allow fetching multiple pools via usePools.ts

This commit is contained in:
Moody Salem 2021-04-23 17:31:36 -05:00
parent 644ecdbd32
commit b69f08cbe1
No known key found for this signature in database
GPG Key ID: 8CB5CD10385138DB
11 changed files with 97 additions and 112 deletions

@ -1,9 +1,6 @@
import { Interface } from '@ethersproject/abi'
import { abi as STAKING_REWARDS_ABI } from '@uniswap/liquidity-staker/build/StakingRewards.json'
import { abi as STAKING_REWARDS_FACTORY_ABI } from '@uniswap/liquidity-staker/build/StakingRewardsFactory.json'
const STAKING_REWARDS_INTERFACE = new Interface(STAKING_REWARDS_ABI)
const STAKING_REWARDS_FACTORY_INTERFACE = new Interface(STAKING_REWARDS_FACTORY_ABI)
export { STAKING_REWARDS_FACTORY_INTERFACE, STAKING_REWARDS_INTERFACE }
export { STAKING_REWARDS_INTERFACE }

@ -2,7 +2,7 @@ import React, { useMemo } from 'react'
import { Position } from '@uniswap/v3-sdk'
import Badge, { BadgeVariant } from 'components/Badge'
import DoubleCurrencyLogo from 'components/DoubleLogo'
import { PoolState, usePool } from 'data/Pools'
import { PoolState, usePool } from 'hooks/usePools'
import { useToken } from 'hooks/Tokens'
import { AlertTriangle } from 'react-feather'
import { useTranslation } from 'react-i18next'

@ -85,8 +85,8 @@ export const BASES_TO_CHECK_TRADES_AGAINST: ChainTokenList = {
export const ADDITIONAL_BASES: { [chainId in ChainId]?: { [tokenAddress: string]: Token[] } } = {
[ChainId.MAINNET]: {
'0xA948E86885e12Fb09AfEF8C52142EBDbDf73cD18': [new Token(ChainId.MAINNET, UNI_ADDRESS, 18, 'UNI', 'Uniswap')],
'0x561a4717537ff4AF5c687328c0f7E90a319705C0': [new Token(ChainId.MAINNET, UNI_ADDRESS, 18, 'UNI', 'Uniswap')],
'0xA948E86885e12Fb09AfEF8C52142EBDbDf73cD18': [UNI[ChainId.MAINNET]],
'0x561a4717537ff4AF5c687328c0f7E90a319705C0': [UNI[ChainId.MAINNET]],
[FEI.address]: [TRIBE],
[TRIBE.address]: [FEI],
[FRAX.address]: [FXS],

@ -1,97 +0,0 @@
import { computePoolAddress } from '@uniswap/v3-sdk'
import { ZERO_ADDRESS } from './../constants/index'
import { Currency } from '@uniswap/sdk-core'
import { useMemo } from 'react'
import { useActiveWeb3React } from '../hooks'
import { useSingleCallResult } from '../state/multicall/hooks'
import { wrappedCurrency } from '../utils/wrappedCurrency'
import { Pool, FeeAmount } from '@uniswap/v3-sdk'
import { useV3Factory, useV3Pool } from 'hooks/useContract'
import { V3_CORE_FACTORY_ADDRESSES } from 'constants/v3'
export enum PoolState {
LOADING = 'LOADING',
NOT_EXISTS = 'NOT_EXISTS',
EXISTS = 'EXISTS',
INVALID = 'INVALID',
}
export function usePool(currencyA?: Currency, currencyB?: Currency, feeAmount?: FeeAmount): [PoolState, Pool | null] {
const { chainId } = useActiveWeb3React()
const factoryContract = useV3Factory()
const tokenA = wrappedCurrency(currencyA, chainId)
const tokenB = wrappedCurrency(currencyB, chainId)
// sorted version
const [token0, token1] = useMemo(
() =>
tokenA && tokenB && !tokenA.equals(tokenB)
? tokenA.sortsBefore(tokenB)
? [tokenA, tokenB]
: [tokenB, tokenA]
: [undefined, undefined],
[tokenA, tokenB]
)
// fetch all generated addresses for pools
const poolAddress = useMemo(() => {
try {
const addr = chainId && V3_CORE_FACTORY_ADDRESSES[chainId]
return addr && tokenA && tokenB && feeAmount && !tokenA.equals(tokenB)
? computePoolAddress({
factoryAddress: addr,
tokenA,
tokenB,
fee: feeAmount,
})
: undefined
} catch {
return undefined
}
}, [chainId, feeAmount, tokenA, tokenB])
// check factory if pools exists
const addressParams = token0 && token1 && feeAmount ? [token0.address, token1.address, feeAmount] : undefined
const addressFromFactory = useSingleCallResult(addressParams ? factoryContract : undefined, 'getPool', addressParams)
const { result: addressesResult, loading: addressesLoading } = addressFromFactory
const poolAddressFromFactory = addressesResult?.[0]
const poolContract = useV3Pool(poolAddress)
// attempt to fetch pool metadata
const slot0Datas = useSingleCallResult(poolContract, 'slot0')
// fetch additional data to instantiate pools
const liquidityDatas = useSingleCallResult(poolContract, 'liquidity')
const { result: slot0, loading: slot0Loading } = slot0Datas
const { result: liquidityResult, loading: liquidityLoading } = liquidityDatas
const liquidity = liquidityResult?.[0]
return useMemo(() => {
// still loading data
if (slot0Loading || addressesLoading || liquidityLoading) return [PoolState.LOADING, null]
// invalid pool setup
if (!tokenA || !tokenB || !feeAmount || tokenA.equals(tokenB)) return [PoolState.INVALID, null]
// pool has not been created or not initialized yet
if (poolAddressFromFactory === ZERO_ADDRESS || !slot0 || !liquidity || slot0.sqrtPriceX96 === 0) {
return [PoolState.NOT_EXISTS, null]
}
return [PoolState.EXISTS, new Pool(tokenA, tokenB, feeAmount, slot0.sqrtPriceX96, liquidity, slot0.tick)]
}, [
addressesLoading,
feeAmount,
liquidity,
liquidityLoading,
poolAddressFromFactory,
slot0,
slot0Loading,
tokenA,
tokenB,
])
}

@ -1,5 +1,5 @@
import { Pool, Position } from '@uniswap/v3-sdk'
import { usePool } from 'data/Pools'
import { usePool } from 'hooks/usePools'
import { PositionDetails } from 'types/position'
import { useCurrency } from './Tokens'

85
src/hooks/usePools.ts Normal file

@ -0,0 +1,85 @@
import { computePoolAddress } from '@uniswap/v3-sdk'
import { IUniswapV3PoolStateInterface } from '../types/v3/IUniswapV3PoolState'
import { Token, Currency } from '@uniswap/sdk-core'
import { useMemo } from 'react'
import { useActiveWeb3React } from './index'
import { useMultipleContractSingleData } from '../state/multicall/hooks'
import { wrappedCurrency } from '../utils/wrappedCurrency'
import { Pool, FeeAmount } from '@uniswap/v3-sdk'
import { V3_CORE_FACTORY_ADDRESSES } from 'constants/v3'
import { abi as IUniswapV3PoolStateABI } from '@uniswap/v3-core/artifacts/contracts/interfaces/pool/IUniswapV3PoolState.sol/IUniswapV3PoolState.json'
import { Interface } from '@ethersproject/abi'
const POOL_STATE_INTERFACE = new Interface(IUniswapV3PoolStateABI) as IUniswapV3PoolStateInterface
export enum PoolState {
LOADING = 'LOADING',
NOT_EXISTS = 'NOT_EXISTS',
EXISTS = 'EXISTS',
INVALID = 'INVALID',
}
export function usePools(
poolKeys: [Currency | undefined, Currency | undefined, FeeAmount | undefined][]
): [PoolState, Pool | null][] {
const { chainId } = useActiveWeb3React()
const transformed: ([Token, Token, FeeAmount] | null)[] = useMemo(() => {
return poolKeys.map(([currencyA, currencyB, feeAmount]) => {
if (!chainId || !currencyA || !currencyB || !feeAmount) return null
const tokenA = wrappedCurrency(currencyA, chainId)
const tokenB = wrappedCurrency(currencyB, chainId)
if (!tokenA || !tokenB || tokenA.equals(tokenB)) return null
const [token0, token1] = tokenA.sortsBefore(tokenB) ? [tokenA, tokenB] : [tokenB, tokenA]
return [token0, token1, feeAmount]
})
}, [chainId, poolKeys])
const poolAddresses: (string | undefined)[] = useMemo(() => {
const v3CoreFactoryAddress = chainId && V3_CORE_FACTORY_ADDRESSES[chainId]
return transformed.map((value) => {
if (!v3CoreFactoryAddress || !value) return undefined
return computePoolAddress({
factoryAddress: v3CoreFactoryAddress,
tokenA: value[0],
tokenB: value[1],
fee: value[2],
})
})
}, [chainId, transformed])
const slot0s = useMultipleContractSingleData(poolAddresses, POOL_STATE_INTERFACE, 'slot0')
const liquidities = useMultipleContractSingleData(poolAddresses, POOL_STATE_INTERFACE, 'liquidity')
return useMemo(() => {
return poolKeys.map((_key, index) => {
const [token0, token1, fee] = transformed[index] ?? []
if (!token0 || !token1 || !fee) return [PoolState.INVALID, null]
const { result: slot0, loading: slot0Loading, valid: slot0Valid } = slot0s[index]
const { result: liquidity, loading: liquidityLoading, valid: liquidityValid } = liquidities[index]
if (!slot0Valid || !liquidityValid) return [PoolState.INVALID, null]
if (slot0Loading || liquidityLoading) return [PoolState.LOADING, null]
if (!slot0 || !liquidity) return [PoolState.NOT_EXISTS, null]
return [PoolState.EXISTS, new Pool(token0, token1, fee, slot0.sqrtPriceX96, liquidity[0], slot0.tick)]
})
}, [liquidities, poolKeys, slot0s, transformed])
}
export function usePool(
currencyA: Currency | undefined,
currencyB: Currency | undefined,
feeAmount: FeeAmount | undefined
): [PoolState, Pool | null] {
const poolKeys: [Currency | undefined, Currency | undefined, FeeAmount | undefined][] = useMemo(
() => [[currencyA, currencyB, feeAmount]],
[currencyA, currencyB, feeAmount]
)
return usePools(poolKeys)[0]
}

@ -18,7 +18,7 @@ import { BackArrow, ExternalLink, TYPE } from '../../theme'
import { getEtherscanLink, isAddress } from '../../utils'
import { BodyWrapper } from '../AppBody'
import { V2_MIGRATOR_ADDRESSES } from 'constants/v3'
import { PoolState, usePool } from 'data/Pools'
import { PoolState, usePool } from 'hooks/usePools'
import { FeeAmount, Pool, Position, priceToClosestTick, TickMath } from '@uniswap/v3-sdk'
import { LightCard, PinkCard, YellowCard } from 'components/Card'
import { ApprovalState, useApproveCallback } from 'hooks/useApproveCallback'

@ -1,6 +1,6 @@
import React, { useCallback, useMemo, useState } from 'react'
import { Position } from '@uniswap/v3-sdk'
import { PoolState, usePool } from 'data/Pools'
import { PoolState, usePool } from 'hooks/usePools'
import { useToken } from 'hooks/Tokens'
import { useV3PositionFromTokenId } from 'hooks/useV3Positions'
import { Link, RouteComponentProps } from 'react-router-dom'

@ -1,7 +1,7 @@
import { BigNumber } from '@ethersproject/bignumber'
import { TokenAmount } from '@uniswap/sdk-core'
import { Position } from '@uniswap/v3-sdk'
import { usePool } from 'data/Pools'
import { usePool } from 'hooks/usePools'
import { useActiveWeb3React } from 'hooks'
import { useToken } from 'hooks/Tokens'
import { useV3PositionFees } from 'hooks/useV3PositionFees'

@ -97,7 +97,7 @@ export function useClaimCallback(
const claimData = useUserClaimData(account)
// used for popup summary
const unClaimedAmount: TokenAmount | undefined = useUserUnclaimedAmount(account)
const unclaimedAmount: TokenAmount | undefined = useUserUnclaimedAmount(account)
const addTransaction = useTransactionAdder()
const distributorContract = useMerkleDistributorContract()
@ -111,7 +111,7 @@ export function useClaimCallback(
.claim(...args, { value: null, gasLimit: calculateGasMargin(estimatedGasLimit) })
.then((response: TransactionResponse) => {
addTransaction(response, {
summary: `Claimed ${unClaimedAmount?.toSignificant(4)} UNI`,
summary: `Claimed ${unclaimedAmount?.toSignificant(4)} UNI`,
claim: { recipient: account },
})
return response.hash

@ -1,7 +1,7 @@
import { BIG_INT_ZERO } from './../../constants/index'
import { getTickToPrice } from 'utils/getTickToPrice'
import JSBI from 'jsbi'
import { PoolState } from './../../data/Pools'
import { PoolState } from '../../hooks/usePools'
import { Pool, FeeAmount, Position, priceToClosestTick, TickMath } from '@uniswap/v3-sdk/dist/'
import { Currency, CurrencyAmount, ETHER, Price } from '@uniswap/sdk-core'
import { useCallback, useMemo } from 'react'
@ -13,7 +13,7 @@ import { tryParseAmount } from '../swap/hooks'
import { useCurrencyBalances } from '../wallet/hooks'
import { Field, Bound, typeInput, typeLowerRangeInput, typeUpperRangeInput, typeStartPriceInput } from './actions'
import { tryParseTick } from './utils'
import { usePool } from 'data/Pools'
import { usePool } from 'hooks/usePools'
export function useMintState(): AppState['mint'] {
return useSelector<AppState, AppState['mint']>((state) => state.mint)