use multicall2
This commit is contained in:
parent
60d1f8743f
commit
bff3811faf
@ -10,7 +10,7 @@ import COINBASE_ICON_URL from '../assets/images/coinbaseWalletIcon.svg'
|
|||||||
import FORTMATIC_ICON_URL from '../assets/images/fortmaticIcon.png'
|
import FORTMATIC_ICON_URL from '../assets/images/fortmaticIcon.png'
|
||||||
import PORTIS_ICON_URL from '../assets/images/portisIcon.png'
|
import PORTIS_ICON_URL from '../assets/images/portisIcon.png'
|
||||||
|
|
||||||
export const MULTICALL_ADDRESSES: { [chainId in ChainId]: string } = {
|
export const MULTICALL2_ADDRESSES: { [chainId in ChainId]: string } = {
|
||||||
[ChainId.MAINNET]: '',
|
[ChainId.MAINNET]: '',
|
||||||
[ChainId.ROPSTEN]: '0x5BA1e12693Dc8F9c48aAD8770482f4739bEeD696',
|
[ChainId.ROPSTEN]: '0x5BA1e12693Dc8F9c48aAD8770482f4739bEeD696',
|
||||||
[ChainId.KOVAN]: '0x5BA1e12693Dc8F9c48aAD8770482f4739bEeD696',
|
[ChainId.KOVAN]: '0x5BA1e12693Dc8F9c48aAD8770482f4739bEeD696',
|
||||||
|
@ -26,7 +26,7 @@ import {
|
|||||||
MERKLE_DISTRIBUTOR_ADDRESS,
|
MERKLE_DISTRIBUTOR_ADDRESS,
|
||||||
V1_MIGRATOR_ADDRESS,
|
V1_MIGRATOR_ADDRESS,
|
||||||
UNI,
|
UNI,
|
||||||
MULTICALL_ADDRESSES,
|
MULTICALL2_ADDRESSES,
|
||||||
} from 'constants/index'
|
} from 'constants/index'
|
||||||
import { abi as NFTPositionManagerABI } from '@uniswap/v3-periphery/artifacts/contracts/NonfungiblePositionManager.sol/NonfungiblePositionManager.json'
|
import { abi as NFTPositionManagerABI } from '@uniswap/v3-periphery/artifacts/contracts/NonfungiblePositionManager.sol/NonfungiblePositionManager.json'
|
||||||
import {
|
import {
|
||||||
@ -40,6 +40,7 @@ import { TickLens, UniswapV3Factory, UniswapV3Pool } from 'types/v3'
|
|||||||
import { NonfungiblePositionManager } from 'types/v3/NonfungiblePositionManager'
|
import { NonfungiblePositionManager } from 'types/v3/NonfungiblePositionManager'
|
||||||
import { V3Migrator } from 'types/v3/V3Migrator'
|
import { V3Migrator } from 'types/v3/V3Migrator'
|
||||||
import { getContract } from 'utils'
|
import { getContract } from 'utils'
|
||||||
|
import { Multicall2 } from '../abis/types'
|
||||||
import { useActiveWeb3React } from './index'
|
import { useActiveWeb3React } from './index'
|
||||||
|
|
||||||
// returns null on errors
|
// returns null on errors
|
||||||
@ -113,9 +114,9 @@ export function usePairContract(pairAddress?: string, withSignerIfPossible?: boo
|
|||||||
return useContract(pairAddress, IUniswapV2PairABI, withSignerIfPossible)
|
return useContract(pairAddress, IUniswapV2PairABI, withSignerIfPossible)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useMulticallContract(): Contract | null {
|
export function useMulticall2Contract(): Multicall2 | null {
|
||||||
const { chainId } = useActiveWeb3React()
|
const { chainId } = useActiveWeb3React()
|
||||||
return useContract(chainId && MULTICALL_ADDRESSES[chainId], MULTICALL_ABI, false)
|
return useContract(chainId && MULTICALL2_ADDRESSES[chainId], MULTICALL_ABI, false) as Multicall2
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useMerkleDistributorContract(): Contract | null {
|
export function useMerkleDistributorContract(): Contract | null {
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import { BigNumber } from 'ethers'
|
import { BigNumber } from 'ethers'
|
||||||
import { useSingleCallResult } from '../state/multicall/hooks'
|
import { useSingleCallResult } from '../state/multicall/hooks'
|
||||||
import { useMulticallContract } from './useContract'
|
import { useMulticall2Contract } from './useContract'
|
||||||
|
|
||||||
// gets the current timestamp from the blockchain
|
// gets the current timestamp from the blockchain
|
||||||
export default function useCurrentBlockTimestamp(): BigNumber | undefined {
|
export default function useCurrentBlockTimestamp(): BigNumber | undefined {
|
||||||
const multicall = useMulticallContract()
|
const multicall = useMulticall2Contract()
|
||||||
return useSingleCallResult(multicall, 'getCurrentBlockTimestamp')?.result?.[0]
|
return useSingleCallResult(multicall, 'getCurrentBlockTimestamp')?.result?.[0]
|
||||||
}
|
}
|
||||||
|
@ -69,13 +69,13 @@ export function useV3Positions(account: string | null | undefined): UseV3Positio
|
|||||||
const positionManager = useV3NFTPositionManagerContract()
|
const positionManager = useV3NFTPositionManagerContract()
|
||||||
|
|
||||||
const { loading: balanceLoading, error: balanceError, result: balanceResult } = useSingleCallResult(
|
const { loading: balanceLoading, error: balanceError, result: balanceResult } = useSingleCallResult(
|
||||||
positionManager ?? undefined,
|
positionManager,
|
||||||
'balanceOf',
|
'balanceOf',
|
||||||
[account ?? undefined]
|
[account ?? undefined]
|
||||||
)
|
)
|
||||||
|
|
||||||
// we don't expect any account balance to ever exceed the bounds of max safe int
|
// we don't expect any account balance to ever exceed the bounds of max safe int
|
||||||
const accountBalance: number | undefined = balanceResult?.[0] ? Number.parseInt(balanceResult[0]) : undefined
|
const accountBalance: number | undefined = balanceResult?.[0]?.toNumber()
|
||||||
|
|
||||||
const tokenIdsArgs = useMemo(() => {
|
const tokenIdsArgs = useMemo(() => {
|
||||||
if (accountBalance && account) {
|
if (accountBalance && account) {
|
||||||
@ -88,11 +88,7 @@ export function useV3Positions(account: string | null | undefined): UseV3Positio
|
|||||||
return []
|
return []
|
||||||
}, [account, accountBalance])
|
}, [account, accountBalance])
|
||||||
|
|
||||||
const tokenIdResults = useSingleContractMultipleData(
|
const tokenIdResults = useSingleContractMultipleData(positionManager, 'tokenOfOwnerByIndex', tokenIdsArgs)
|
||||||
positionManager ?? undefined,
|
|
||||||
'tokenOfOwnerByIndex',
|
|
||||||
tokenIdsArgs
|
|
||||||
)
|
|
||||||
|
|
||||||
const tokenIds = useMemo(() => {
|
const tokenIds = useMemo(() => {
|
||||||
if (account) {
|
if (account) {
|
||||||
|
@ -73,6 +73,7 @@ const ResponsiveButtonPrimary = styled(ButtonPrimary)`
|
|||||||
width: 49%;
|
width: 49%;
|
||||||
`};
|
`};
|
||||||
`
|
`
|
||||||
|
|
||||||
const MainContentWrapper = styled.main`
|
const MainContentWrapper = styled.main`
|
||||||
background-color: ${({ theme }) => theme.bg0};
|
background-color: ${({ theme }) => theme.bg0};
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
@ -80,17 +81,14 @@ const MainContentWrapper = styled.main`
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
`
|
`
|
||||||
|
|
||||||
export default function Pool() {
|
export default function Pool() {
|
||||||
const { account } = useActiveWeb3React()
|
const { account } = useActiveWeb3React()
|
||||||
const toggleWalletModal = useWalletModalToggle()
|
const toggleWalletModal = useWalletModalToggle()
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const theme = useContext(ThemeContext)
|
const theme = useContext(ThemeContext)
|
||||||
|
|
||||||
const { error, positions } = useV3Positions(account)
|
const { positions } = useV3Positions(account)
|
||||||
|
|
||||||
if (error) {
|
|
||||||
console.error('error fetching v3 positions', error)
|
|
||||||
}
|
|
||||||
|
|
||||||
const hasPositions = useMemo(() => Boolean(positions && positions.length > 0), [positions])
|
const hasPositions = useMemo(() => Boolean(positions && positions.length > 0), [positions])
|
||||||
|
|
||||||
@ -131,6 +129,7 @@ export default function Pool() {
|
|||||||
external: false,
|
external: false,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<PageWrapper>
|
<PageWrapper>
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import { Contract } from '@ethersproject/contracts'
|
import { BigNumber } from 'ethers'
|
||||||
import { useEffect, useMemo, useRef } from 'react'
|
import { useEffect, useMemo, useRef } from 'react'
|
||||||
import { useDispatch, useSelector } from 'react-redux'
|
import { useDispatch, useSelector } from 'react-redux'
|
||||||
|
import { Multicall2 } from '../../abis/types'
|
||||||
import { useActiveWeb3React } from '../../hooks'
|
import { useActiveWeb3React } from '../../hooks'
|
||||||
import { useMulticallContract } from '../../hooks/useContract'
|
import { useMulticall2Contract } from '../../hooks/useContract'
|
||||||
import useDebounce from '../../hooks/useDebounce'
|
import useDebounce from '../../hooks/useDebounce'
|
||||||
import chunkArray from '../../utils/chunkArray'
|
import chunkArray from '../../utils/chunkArray'
|
||||||
import { CancelledError, retry, RetryableError } from '../../utils/retry'
|
import { CancelledError, retry, RetryableError } from '../../utils/retry'
|
||||||
@ -18,20 +19,24 @@ import {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetches a chunk of calls, enforcing a minimum block number constraint
|
* Fetches a chunk of calls, enforcing a minimum block number constraint
|
||||||
* @param multicallContract multicall contract to fetch against
|
* @param multicall2Contract multicall contract to fetch against
|
||||||
* @param chunk chunk of calls to make
|
* @param chunk chunk of calls to make
|
||||||
* @param minBlockNumber minimum block number of the result set
|
* @param minBlockNumber minimum block number of the result set
|
||||||
*/
|
*/
|
||||||
async function fetchChunk(
|
async function fetchChunk(
|
||||||
multicallContract: Contract,
|
multicall2Contract: Multicall2,
|
||||||
chunk: Call[],
|
chunk: Call[],
|
||||||
minBlockNumber: number
|
minBlockNumber: number
|
||||||
): Promise<{ results: string[]; blockNumber: number }> {
|
): Promise<{
|
||||||
console.debug('Fetching chunk', multicallContract, chunk, minBlockNumber)
|
results: { success: boolean; returnData: string }[]
|
||||||
let resultsBlockNumber, returnData
|
blockNumber: number
|
||||||
|
}> {
|
||||||
|
console.debug('Fetching chunk', multicall2Contract, chunk, minBlockNumber)
|
||||||
|
let resultsBlockNumber: BigNumber
|
||||||
|
let results: { success: boolean; returnData: string }[]
|
||||||
try {
|
try {
|
||||||
;[resultsBlockNumber, returnData] = await multicallContract.callStatic.aggregate(
|
;[resultsBlockNumber, , results] = await multicall2Contract.callStatic.blockAndAggregate(
|
||||||
chunk.map((obj) => [obj.address, obj.callData])
|
chunk.map((obj) => ({ target: obj.address, callData: obj.callData }))
|
||||||
)
|
)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.debug('Failed to fetch chunk inside retry', error)
|
console.debug('Failed to fetch chunk inside retry', error)
|
||||||
@ -41,7 +46,7 @@ async function fetchChunk(
|
|||||||
console.debug(`Fetched results for old block number: ${resultsBlockNumber.toString()} vs. ${minBlockNumber}`)
|
console.debug(`Fetched results for old block number: ${resultsBlockNumber.toString()} vs. ${minBlockNumber}`)
|
||||||
throw new RetryableError('Fetched for old block number')
|
throw new RetryableError('Fetched for old block number')
|
||||||
}
|
}
|
||||||
return { results: returnData, blockNumber: resultsBlockNumber.toNumber() }
|
return { results, blockNumber: resultsBlockNumber.toNumber() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -116,7 +121,7 @@ export default function Updater(): null {
|
|||||||
const debouncedListeners = useDebounce(state.callListeners, 100)
|
const debouncedListeners = useDebounce(state.callListeners, 100)
|
||||||
const latestBlockNumber = useBlockNumber()
|
const latestBlockNumber = useBlockNumber()
|
||||||
const { chainId } = useActiveWeb3React()
|
const { chainId } = useActiveWeb3React()
|
||||||
const multicallContract = useMulticallContract()
|
const multicall2Contract = useMulticall2Contract()
|
||||||
const cancellations = useRef<{ blockNumber: number; cancellations: (() => void)[] }>()
|
const cancellations = useRef<{ blockNumber: number; cancellations: (() => void)[] }>()
|
||||||
|
|
||||||
const listeningKeys: { [callKey: string]: number } = useMemo(() => {
|
const listeningKeys: { [callKey: string]: number } = useMemo(() => {
|
||||||
@ -132,7 +137,7 @@ export default function Updater(): null {
|
|||||||
])
|
])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!latestBlockNumber || !chainId || !multicallContract) return
|
if (!latestBlockNumber || !chainId || !multicall2Contract) return
|
||||||
|
|
||||||
const outdatedCallKeys: string[] = JSON.parse(serializedOutdatedCallKeys)
|
const outdatedCallKeys: string[] = JSON.parse(serializedOutdatedCallKeys)
|
||||||
if (outdatedCallKeys.length === 0) return
|
if (outdatedCallKeys.length === 0) return
|
||||||
@ -155,7 +160,7 @@ export default function Updater(): null {
|
|||||||
cancellations.current = {
|
cancellations.current = {
|
||||||
blockNumber: latestBlockNumber,
|
blockNumber: latestBlockNumber,
|
||||||
cancellations: chunkedCalls.map((chunk, index) => {
|
cancellations: chunkedCalls.map((chunk, index) => {
|
||||||
const { cancel, promise } = retry(() => fetchChunk(multicallContract, chunk, latestBlockNumber), {
|
const { cancel, promise } = retry(() => fetchChunk(multicall2Contract, chunk, latestBlockNumber), {
|
||||||
n: Infinity,
|
n: Infinity,
|
||||||
minWait: 2500,
|
minWait: 2500,
|
||||||
maxWait: 3500,
|
maxWait: 3500,
|
||||||
@ -168,18 +173,29 @@ export default function Updater(): null {
|
|||||||
const firstCallKeyIndex = chunkedCalls.slice(0, index).reduce<number>((memo, curr) => memo + curr.length, 0)
|
const firstCallKeyIndex = chunkedCalls.slice(0, index).reduce<number>((memo, curr) => memo + curr.length, 0)
|
||||||
const lastCallKeyIndex = firstCallKeyIndex + returnData.length
|
const lastCallKeyIndex = firstCallKeyIndex + returnData.length
|
||||||
|
|
||||||
|
const slice = outdatedCallKeys.slice(firstCallKeyIndex, lastCallKeyIndex)
|
||||||
|
|
||||||
dispatch(
|
dispatch(
|
||||||
updateMulticallResults({
|
updateMulticallResults({
|
||||||
chainId,
|
chainId,
|
||||||
results: outdatedCallKeys
|
results: slice.reduce<{ [callKey: string]: string | null }>((memo, callKey, i) => {
|
||||||
.slice(firstCallKeyIndex, lastCallKeyIndex)
|
if (returnData[i].success) {
|
||||||
.reduce<{ [callKey: string]: string | null }>((memo, callKey, i) => {
|
memo[callKey] = returnData[i].returnData ?? null
|
||||||
memo[callKey] = returnData[i] ?? null
|
}
|
||||||
return memo
|
return memo
|
||||||
}, {}),
|
}, {}),
|
||||||
blockNumber: fetchBlockNumber,
|
blockNumber: fetchBlockNumber,
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// todo: dispatch an error for each call that failed, i.e. returnData[i].success === false
|
||||||
|
// dispatch(
|
||||||
|
// errorFetchingMulticallResults({
|
||||||
|
// calls: // todo: compute this,
|
||||||
|
// chainId,
|
||||||
|
// fetchingBlockNumber: latestBlockNumber,
|
||||||
|
// })
|
||||||
|
// )
|
||||||
})
|
})
|
||||||
.catch((error: any) => {
|
.catch((error: any) => {
|
||||||
if (error instanceof CancelledError) {
|
if (error instanceof CancelledError) {
|
||||||
@ -198,7 +214,7 @@ export default function Updater(): null {
|
|||||||
return cancel
|
return cancel
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}, [chainId, multicallContract, dispatch, serializedOutdatedCallKeys, latestBlockNumber])
|
}, [chainId, multicall2Contract, dispatch, serializedOutdatedCallKeys, latestBlockNumber])
|
||||||
|
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ import { JSBI } from '@uniswap/v2-sdk'
|
|||||||
import { useMemo } from 'react'
|
import { useMemo } from 'react'
|
||||||
import { useActiveWeb3React } from '../../hooks'
|
import { useActiveWeb3React } from '../../hooks'
|
||||||
import { useAllTokens } from '../../hooks/Tokens'
|
import { useAllTokens } from '../../hooks/Tokens'
|
||||||
import { useMulticallContract } from '../../hooks/useContract'
|
import { useMulticall2Contract } from '../../hooks/useContract'
|
||||||
import { isAddress } from '../../utils'
|
import { isAddress } from '../../utils'
|
||||||
import { useUserUnclaimedAmount } from '../claim/hooks'
|
import { useUserUnclaimedAmount } from '../claim/hooks'
|
||||||
import { useMultipleContractSingleData, useSingleContractMultipleData } from '../multicall/hooks'
|
import { useMultipleContractSingleData, useSingleContractMultipleData } from '../multicall/hooks'
|
||||||
@ -18,7 +18,7 @@ import { Erc20Interface } from 'abis/types/Erc20'
|
|||||||
export function useETHBalances(
|
export function useETHBalances(
|
||||||
uncheckedAddresses?: (string | undefined)[]
|
uncheckedAddresses?: (string | undefined)[]
|
||||||
): { [address: string]: CurrencyAmount | undefined } {
|
): { [address: string]: CurrencyAmount | undefined } {
|
||||||
const multicallContract = useMulticallContract()
|
const multicallContract = useMulticall2Contract()
|
||||||
|
|
||||||
const addresses: string[] = useMemo(
|
const addresses: string[] = useMemo(
|
||||||
() =>
|
() =>
|
||||||
|
Loading…
Reference in New Issue
Block a user