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 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.ROPSTEN]: '0x5BA1e12693Dc8F9c48aAD8770482f4739bEeD696',
|
||||
[ChainId.KOVAN]: '0x5BA1e12693Dc8F9c48aAD8770482f4739bEeD696',
|
||||
|
@ -26,7 +26,7 @@ import {
|
||||
MERKLE_DISTRIBUTOR_ADDRESS,
|
||||
V1_MIGRATOR_ADDRESS,
|
||||
UNI,
|
||||
MULTICALL_ADDRESSES,
|
||||
MULTICALL2_ADDRESSES,
|
||||
} from 'constants/index'
|
||||
import { abi as NFTPositionManagerABI } from '@uniswap/v3-periphery/artifacts/contracts/NonfungiblePositionManager.sol/NonfungiblePositionManager.json'
|
||||
import {
|
||||
@ -40,6 +40,7 @@ import { TickLens, UniswapV3Factory, UniswapV3Pool } from 'types/v3'
|
||||
import { NonfungiblePositionManager } from 'types/v3/NonfungiblePositionManager'
|
||||
import { V3Migrator } from 'types/v3/V3Migrator'
|
||||
import { getContract } from 'utils'
|
||||
import { Multicall2 } from '../abis/types'
|
||||
import { useActiveWeb3React } from './index'
|
||||
|
||||
// returns null on errors
|
||||
@ -113,9 +114,9 @@ export function usePairContract(pairAddress?: string, withSignerIfPossible?: boo
|
||||
return useContract(pairAddress, IUniswapV2PairABI, withSignerIfPossible)
|
||||
}
|
||||
|
||||
export function useMulticallContract(): Contract | null {
|
||||
export function useMulticall2Contract(): Multicall2 | null {
|
||||
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 {
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { BigNumber } from 'ethers'
|
||||
import { useSingleCallResult } from '../state/multicall/hooks'
|
||||
import { useMulticallContract } from './useContract'
|
||||
import { useMulticall2Contract } from './useContract'
|
||||
|
||||
// gets the current timestamp from the blockchain
|
||||
export default function useCurrentBlockTimestamp(): BigNumber | undefined {
|
||||
const multicall = useMulticallContract()
|
||||
const multicall = useMulticall2Contract()
|
||||
return useSingleCallResult(multicall, 'getCurrentBlockTimestamp')?.result?.[0]
|
||||
}
|
||||
|
@ -69,13 +69,13 @@ export function useV3Positions(account: string | null | undefined): UseV3Positio
|
||||
const positionManager = useV3NFTPositionManagerContract()
|
||||
|
||||
const { loading: balanceLoading, error: balanceError, result: balanceResult } = useSingleCallResult(
|
||||
positionManager ?? undefined,
|
||||
positionManager,
|
||||
'balanceOf',
|
||||
[account ?? undefined]
|
||||
)
|
||||
|
||||
// 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(() => {
|
||||
if (accountBalance && account) {
|
||||
@ -88,11 +88,7 @@ export function useV3Positions(account: string | null | undefined): UseV3Positio
|
||||
return []
|
||||
}, [account, accountBalance])
|
||||
|
||||
const tokenIdResults = useSingleContractMultipleData(
|
||||
positionManager ?? undefined,
|
||||
'tokenOfOwnerByIndex',
|
||||
tokenIdsArgs
|
||||
)
|
||||
const tokenIdResults = useSingleContractMultipleData(positionManager, 'tokenOfOwnerByIndex', tokenIdsArgs)
|
||||
|
||||
const tokenIds = useMemo(() => {
|
||||
if (account) {
|
||||
|
@ -73,6 +73,7 @@ const ResponsiveButtonPrimary = styled(ButtonPrimary)`
|
||||
width: 49%;
|
||||
`};
|
||||
`
|
||||
|
||||
const MainContentWrapper = styled.main`
|
||||
background-color: ${({ theme }) => theme.bg0};
|
||||
padding: 16px;
|
||||
@ -80,17 +81,14 @@ const MainContentWrapper = styled.main`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
`
|
||||
|
||||
export default function Pool() {
|
||||
const { account } = useActiveWeb3React()
|
||||
const toggleWalletModal = useWalletModalToggle()
|
||||
const { t } = useTranslation()
|
||||
const theme = useContext(ThemeContext)
|
||||
|
||||
const { error, positions } = useV3Positions(account)
|
||||
|
||||
if (error) {
|
||||
console.error('error fetching v3 positions', error)
|
||||
}
|
||||
const { positions } = useV3Positions(account)
|
||||
|
||||
const hasPositions = useMemo(() => Boolean(positions && positions.length > 0), [positions])
|
||||
|
||||
@ -131,6 +129,7 @@ export default function Pool() {
|
||||
external: false,
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<PageWrapper>
|
||||
|
@ -1,8 +1,9 @@
|
||||
import { Contract } from '@ethersproject/contracts'
|
||||
import { BigNumber } from 'ethers'
|
||||
import { useEffect, useMemo, useRef } from 'react'
|
||||
import { useDispatch, useSelector } from 'react-redux'
|
||||
import { Multicall2 } from '../../abis/types'
|
||||
import { useActiveWeb3React } from '../../hooks'
|
||||
import { useMulticallContract } from '../../hooks/useContract'
|
||||
import { useMulticall2Contract } from '../../hooks/useContract'
|
||||
import useDebounce from '../../hooks/useDebounce'
|
||||
import chunkArray from '../../utils/chunkArray'
|
||||
import { CancelledError, retry, RetryableError } from '../../utils/retry'
|
||||
@ -18,20 +19,24 @@ import {
|
||||
|
||||
/**
|
||||
* 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 minBlockNumber minimum block number of the result set
|
||||
*/
|
||||
async function fetchChunk(
|
||||
multicallContract: Contract,
|
||||
multicall2Contract: Multicall2,
|
||||
chunk: Call[],
|
||||
minBlockNumber: number
|
||||
): Promise<{ results: string[]; blockNumber: number }> {
|
||||
console.debug('Fetching chunk', multicallContract, chunk, minBlockNumber)
|
||||
let resultsBlockNumber, returnData
|
||||
): Promise<{
|
||||
results: { success: boolean; returnData: string }[]
|
||||
blockNumber: number
|
||||
}> {
|
||||
console.debug('Fetching chunk', multicall2Contract, chunk, minBlockNumber)
|
||||
let resultsBlockNumber: BigNumber
|
||||
let results: { success: boolean; returnData: string }[]
|
||||
try {
|
||||
;[resultsBlockNumber, returnData] = await multicallContract.callStatic.aggregate(
|
||||
chunk.map((obj) => [obj.address, obj.callData])
|
||||
;[resultsBlockNumber, , results] = await multicall2Contract.callStatic.blockAndAggregate(
|
||||
chunk.map((obj) => ({ target: obj.address, callData: obj.callData }))
|
||||
)
|
||||
} catch (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}`)
|
||||
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 latestBlockNumber = useBlockNumber()
|
||||
const { chainId } = useActiveWeb3React()
|
||||
const multicallContract = useMulticallContract()
|
||||
const multicall2Contract = useMulticall2Contract()
|
||||
const cancellations = useRef<{ blockNumber: number; cancellations: (() => void)[] }>()
|
||||
|
||||
const listeningKeys: { [callKey: string]: number } = useMemo(() => {
|
||||
@ -132,7 +137,7 @@ export default function Updater(): null {
|
||||
])
|
||||
|
||||
useEffect(() => {
|
||||
if (!latestBlockNumber || !chainId || !multicallContract) return
|
||||
if (!latestBlockNumber || !chainId || !multicall2Contract) return
|
||||
|
||||
const outdatedCallKeys: string[] = JSON.parse(serializedOutdatedCallKeys)
|
||||
if (outdatedCallKeys.length === 0) return
|
||||
@ -155,7 +160,7 @@ export default function Updater(): null {
|
||||
cancellations.current = {
|
||||
blockNumber: latestBlockNumber,
|
||||
cancellations: chunkedCalls.map((chunk, index) => {
|
||||
const { cancel, promise } = retry(() => fetchChunk(multicallContract, chunk, latestBlockNumber), {
|
||||
const { cancel, promise } = retry(() => fetchChunk(multicall2Contract, chunk, latestBlockNumber), {
|
||||
n: Infinity,
|
||||
minWait: 2500,
|
||||
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 lastCallKeyIndex = firstCallKeyIndex + returnData.length
|
||||
|
||||
const slice = outdatedCallKeys.slice(firstCallKeyIndex, lastCallKeyIndex)
|
||||
|
||||
dispatch(
|
||||
updateMulticallResults({
|
||||
chainId,
|
||||
results: outdatedCallKeys
|
||||
.slice(firstCallKeyIndex, lastCallKeyIndex)
|
||||
.reduce<{ [callKey: string]: string | null }>((memo, callKey, i) => {
|
||||
memo[callKey] = returnData[i] ?? null
|
||||
return memo
|
||||
}, {}),
|
||||
results: slice.reduce<{ [callKey: string]: string | null }>((memo, callKey, i) => {
|
||||
if (returnData[i].success) {
|
||||
memo[callKey] = returnData[i].returnData ?? null
|
||||
}
|
||||
return memo
|
||||
}, {}),
|
||||
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) => {
|
||||
if (error instanceof CancelledError) {
|
||||
@ -198,7 +214,7 @@ export default function Updater(): null {
|
||||
return cancel
|
||||
}),
|
||||
}
|
||||
}, [chainId, multicallContract, dispatch, serializedOutdatedCallKeys, latestBlockNumber])
|
||||
}, [chainId, multicall2Contract, dispatch, serializedOutdatedCallKeys, latestBlockNumber])
|
||||
|
||||
return null
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ import { JSBI } from '@uniswap/v2-sdk'
|
||||
import { useMemo } from 'react'
|
||||
import { useActiveWeb3React } from '../../hooks'
|
||||
import { useAllTokens } from '../../hooks/Tokens'
|
||||
import { useMulticallContract } from '../../hooks/useContract'
|
||||
import { useMulticall2Contract } from '../../hooks/useContract'
|
||||
import { isAddress } from '../../utils'
|
||||
import { useUserUnclaimedAmount } from '../claim/hooks'
|
||||
import { useMultipleContractSingleData, useSingleContractMultipleData } from '../multicall/hooks'
|
||||
@ -18,7 +18,7 @@ import { Erc20Interface } from 'abis/types/Erc20'
|
||||
export function useETHBalances(
|
||||
uncheckedAddresses?: (string | undefined)[]
|
||||
): { [address: string]: CurrencyAmount | undefined } {
|
||||
const multicallContract = useMulticallContract()
|
||||
const multicallContract = useMulticall2Contract()
|
||||
|
||||
const addresses: string[] = useMemo(
|
||||
() =>
|
||||
|
Loading…
Reference in New Issue
Block a user