From 56a7042c76bd440182c3acd6e753873a8d74f703 Mon Sep 17 00:00:00 2001 From: Karelian Pie Date: Wed, 21 Jun 2023 16:44:49 +0300 Subject: [PATCH] feat: Migrate useGauge to wagmi --- apps/veyfi/contexts/useGauge.tsx | 113 ++++++++++++++++++++----------- 1 file changed, 75 insertions(+), 38 deletions(-) diff --git a/apps/veyfi/contexts/useGauge.tsx b/apps/veyfi/contexts/useGauge.tsx index a6f8078ad..e88501f2e 100644 --- a/apps/veyfi/contexts/useGauge.tsx +++ b/apps/veyfi/contexts/useGauge.tsx @@ -1,17 +1,19 @@ import React, {createContext, memo, useCallback, useContext, useMemo} from 'react'; -import {Contract} from 'ethcall'; +import {Contract} from 'ethcall'; // TODO: Remove this import import {FixedNumber} from 'ethers'; +import {useContractRead} from 'wagmi'; import useSWR from 'swr'; import {keyBy} from '@veYFI/utils'; import VEYFI_GAUGE_ABI from '@veYFI/utils/abi/veYFIGauge.abi'; import VEYFI_REGISTRY_ABI from '@veYFI/utils/abi/veYFIRegistry.abi'; import {VEYFI_REGISTRY_ADDRESS} from '@veYFI/utils/constants'; +import {getContract, multicall} from '@wagmi/core'; import {useWeb3} from '@yearn-finance/web-lib/contexts/useWeb3'; +import {useChainID} from '@yearn-finance/web-lib/hooks/useChainID'; import ERC20_ABI from '@yearn-finance/web-lib/utils/abi/erc20.abi'; import {allowanceKey} from '@yearn-finance/web-lib/utils/address'; -import {getProvider, newEthCallProvider} from '@yearn-finance/web-lib/utils/web3/providers'; -import type {Call} from 'ethcall'; +import type {Call} from 'ethcall'; // TODO: Remove this import import type {ReactElement} from 'react'; import type {TAddress, TDict} from '@yearn-finance/web-lib/types'; @@ -56,30 +58,57 @@ const defaultProps: TGaugeContext = { const GaugeContext = createContext(defaultProps); export const GaugeContextApp = memo(function GaugeContextApp({children}: {children: ReactElement}): ReactElement { - const {provider, address: userAddress, isActive} = useWeb3(); + const {address: userAddress, isActive} = useWeb3(); + const {chainID} = useChainID(); + const veYFIRegistryContract = useMemo((): {address: TAddress, abi: typeof VEYFI_REGISTRY_ABI} => ({ + address: VEYFI_REGISTRY_ADDRESS, + abi: VEYFI_REGISTRY_ABI + }), []); + const {data: vaultAddresses} = useContractRead({ + ...veYFIRegistryContract, + functionName: 'getVaults', + chainId: chainID + }); const gaugesFetcher = useCallback(async (): Promise => { - const currentProvider = getProvider(1); - const ethcallProvider = await newEthCallProvider(currentProvider); - const veYFIRegistryContract = new Contract(VEYFI_REGISTRY_ADDRESS, VEYFI_REGISTRY_ABI); // todo: update once abi is available - const [vaultAddresses] = await ethcallProvider.tryAll([veYFIRegistryContract.getVaults()]) as [TAddress[]]; - const gaugeAddressCalls = vaultAddresses.map((address): Call => veYFIRegistryContract.gauges(address)); - const gaugeAddresses = await ethcallProvider.tryAll(gaugeAddressCalls) as TAddress[]; + if (!isActive || !userAddress) { + return []; + } + + const gaugeAddressCalls = []; + for (const vaultAddress of vaultAddresses as TAddress[]) { + gaugeAddressCalls.push({ + ...veYFIRegistryContract, + functionName: 'gauges', + args: [vaultAddress] + }); + } + + // TODO: Types of property 'abi' are incompatible. + const gaugeAddressesResults = await multicall({contracts: gaugeAddressCalls, chainId: chainID}); + + const gaugeAddresses = gaugeAddressesResults.map(({result}): unknown => result) as TAddress[]; const gaugePromises = gaugeAddresses.map(async (address): Promise => { - const veYFIGaugeContract = new Contract(address, VEYFI_GAUGE_ABI); // todo: update once abi is available - const [ - asset, - name, - symbol, - decimals, - totalAssets - ] = await ethcallProvider.tryAll([ - veYFIGaugeContract.asset(), - veYFIGaugeContract.name(), - veYFIGaugeContract.symbol(), - veYFIGaugeContract.decimals(), - veYFIGaugeContract.totalAssets() - ]) as [TAddress, string, string, number, bigint]; + // todo: update once abi is available + const veYFIGaugeContract = getContract({ + address, + abi: VEYFI_GAUGE_ABI + }); + + + // TODO: These should be migrated to wagmi + const results = await multicall({ + contracts: [ + veYFIGaugeContract.asset(), + veYFIGaugeContract.name(), + veYFIGaugeContract.symbol(), + veYFIGaugeContract.decimals(), + veYFIGaugeContract.totalAssets() + ], + chainId: chainID + }); + + const [asset, name, symbol, decimals, totalAssets] = results.map(({result}): unknown => result) as [TAddress, string, string, number, bigint]; return ({ address, @@ -98,16 +127,20 @@ export const GaugeContextApp = memo(function GaugeContextApp({children}: {childr if (!gauges|| !isActive|| !userAddress) { return []; } - const currentProvider = getProvider(1); - const ethcallProvider = await newEthCallProvider(currentProvider); const positionPromises = gauges.map(async ({address}): Promise => { const veYFIGaugeContract = new Contract(address, VEYFI_GAUGE_ABI); // todo: update once abi is available - const [balance, earned, boostedBalance] = await ethcallProvider.tryAll([ - veYFIGaugeContract.balanceOf(userAddress), - veYFIGaugeContract.earned(userAddress), - veYFIGaugeContract.nextBoostedBalanceOf(userAddress) - ]) as bigint[]; + + const results = await multicall({ + contracts: [ + veYFIGaugeContract.balanceOf(userAddress), + veYFIGaugeContract.earned(userAddress), + veYFIGaugeContract.nextBoostedBalanceOf(userAddress) + ], + chainId: chainID + }); + + const [balance, earned, boostedBalance] = results.map(({result}): unknown => result) as bigint[]; const depositPosition: TPosition = { balance, @@ -132,29 +165,33 @@ export const GaugeContextApp = memo(function GaugeContextApp({children}: {childr }; }); return Promise.all(positionPromises); - }, [gauges, isActive, userAddress]); - const {data: positions, mutate: refreshPositions, isLoading: isLoadingPositions} = useSWR(gauges && isActive && provider ? 'gaugePositions' : null, positionsFetcher, {shouldRetryOnError: false}); + }, [chainID, gauges, isActive, userAddress]); + const {data: positions, mutate: refreshPositions, isLoading: isLoadingPositions} = useSWR(gauges && isActive ? 'gaugePositions' : null, positionsFetcher, {shouldRetryOnError: false}); const allowancesFetcher = useCallback(async (): Promise> => { if (!gauges || !isActive || !userAddress) { return {}; } - const currentProvider = getProvider(1); - const ethcallProvider = await newEthCallProvider(currentProvider); const allowanceCalls = gauges.map(({address, vaultAddress}): Call => { const erc20Contract = new Contract(vaultAddress, ERC20_ABI); return erc20Contract.allowance(userAddress, address); }); - const allowances = await ethcallProvider.tryAll(allowanceCalls) as bigint[]; + + const results = await multicall({ + contracts: allowanceCalls, + chainId: chainID + }); + const allowances = results.map(({result}): unknown => result) as bigint[]; + const allowancesMap: TDict = {}; gauges.forEach(({address, vaultAddress}, index): void => { allowancesMap[allowanceKey(1, vaultAddress, address, userAddress)] = allowances[index]; }); return allowancesMap; - }, [gauges, isActive, userAddress]); - const {data: allowancesMap, mutate: refreshAllowances, isLoading: isLoadingAllowances} = useSWR(gauges && isActive && provider ? 'gaugeAllowances' : null, allowancesFetcher, {shouldRetryOnError: false}); + }, [chainID, gauges, isActive, userAddress]); + const {data: allowancesMap, mutate: refreshAllowances, isLoading: isLoadingAllowances} = useSWR(gauges && isActive ? 'gaugeAllowances' : null, allowancesFetcher, {shouldRetryOnError: false}); const refresh = useCallback((): void => { refreshVotingEscrow();