diff --git a/src/components/MultiHopTrade/hooks/useAllowanceApproval/helpers.ts b/src/components/MultiHopTrade/hooks/useAllowanceApproval/helpers.ts index edb12eb5a18..1d247489a36 100644 --- a/src/components/MultiHopTrade/hooks/useAllowanceApproval/helpers.ts +++ b/src/components/MultiHopTrade/hooks/useAllowanceApproval/helpers.ts @@ -72,6 +72,7 @@ export const getApprovalTxData = async ({ approvalAmountCryptoBaseUnit, spender: tradeQuoteStep.allowanceContract, to: assetReference, + chainId: tradeQuoteStep.sellAsset.chainId, }) const { networkFeeCryptoBaseUnit, ...fees } = await getFees({ diff --git a/src/contracts/contractManager.ts b/src/contracts/contractManager.ts index 92a77953ccd..35519b7fd3b 100644 --- a/src/contracts/contractManager.ts +++ b/src/contracts/contractManager.ts @@ -1,7 +1,10 @@ import type { AssetId, ChainId } from '@shapeshiftoss/caip' import { fromAssetId, toAssetId } from '@shapeshiftoss/caip' +import type { EvmChainId } from '@shapeshiftoss/chain-adapters' +import { KnownChainIds } from '@shapeshiftoss/types' import type { Token } from '@uniswap/sdk' import { Fetcher } from '@uniswap/sdk' +import assert from 'assert' import { erc20ABI } from 'contracts/abis/ERC20ABI' import { FarmingABI } from 'contracts/abis/farmingAbi' import { IUniswapV2Pair } from 'contracts/abis/IUniswapV2Pair' @@ -12,7 +15,7 @@ import memoize from 'lodash/memoize' import type { Address } from 'viem' import { getContract } from 'viem' import { getEthersProvider } from 'lib/ethersProviderSingleton' -import { viemEthMainnetClient } from 'lib/viem-client' +import { viemClientByChainId, viemEthMainnetClient } from 'lib/viem-client' import { ETH_FOX_POOL_CONTRACT_ADDRESS, @@ -78,20 +81,24 @@ export const getOrCreateContractByAddress = ( export const getOrCreateContractByType = ({ address, type, - // TODO(gomes): viem client by ChainId - chainId: _chainId, + chainId, }: { address: string | `0x${string}` type: T - chainId?: ChainId + chainId: ChainId }): KnownContractByType => { const definedContract = definedContracts.find(contract => contract.address === address) if (definedContract && definedContract.contract) return definedContract.contract as unknown as KnownContractByType + + const publicClient = viemClientByChainId[chainId as EvmChainId] + assert(publicClient !== undefined, `no public client found for chainId '${chainId}'`) + const contract = getContract({ abi: CONTRACT_TYPE_TO_ABI[type], address: address as Address, - publicClient: viemEthMainnetClient, + + publicClient, }) definedContracts.push({ contract, @@ -107,6 +114,7 @@ export const fetchUniV2PairData = memoize(async (pairAssetId: AssetId) => { const pair = getOrCreateContractByType({ address: contractAddress, type: ContractType.UniV2Pair, + chainId: KnownChainIds.EthereumMainnet, }) const ethersProvider = getEthersProvider() diff --git a/src/features/defi/providers/thorchain-savers/components/ThorchainSaversManager/Deposit/components/Approve.tsx b/src/features/defi/providers/thorchain-savers/components/ThorchainSaversManager/Deposit/components/Approve.tsx index 59c91e3cfce..2f84183153d 100644 --- a/src/features/defi/providers/thorchain-savers/components/ThorchainSaversManager/Deposit/components/Approve.tsx +++ b/src/features/defi/providers/thorchain-savers/components/ThorchainSaversManager/Deposit/components/Approve.tsx @@ -143,6 +143,7 @@ export const Approve: React.FC = ({ accountId, onNext }) => { const contract = getOrCreateContractByType({ address: fromAssetId(assetId).assetReference, type: ContractType.ERC20, + chainId, }) const amountToApprove = state.isExactAllowance ? amountCryptoBaseUnit : MAX_ALLOWANCE diff --git a/src/features/defi/providers/univ2/hooks/useUniV2LiquidityPool.ts b/src/features/defi/providers/univ2/hooks/useUniV2LiquidityPool.ts index 6472ad4216a..e6380005e4a 100644 --- a/src/features/defi/providers/univ2/hooks/useUniV2LiquidityPool.ts +++ b/src/features/defi/providers/univ2/hooks/useUniV2LiquidityPool.ts @@ -2,6 +2,7 @@ import { MaxUint256 } from '@ethersproject/constants' import type { AccountId, AssetId } from '@shapeshiftoss/caip' import { ethAssetId, ethChainId, fromAccountId, fromAssetId, toAssetId } from '@shapeshiftoss/caip' import type { ethereum } from '@shapeshiftoss/chain-adapters' +import { KnownChainIds } from '@shapeshiftoss/types' import { UNISWAP_V2_ROUTER_02_CONTRACT_ADDRESS, WETH_TOKEN_CONTRACT_ADDRESS, @@ -98,6 +99,7 @@ export const useUniV2LiquidityPool = ({ : getOrCreateContractByType({ address: asset0ContractAddress, type: ContractType.ERC20, + chainId: KnownChainIds.EthereumMainnet, }) }, [asset0ContractAddress, skip]) @@ -107,6 +109,7 @@ export const useUniV2LiquidityPool = ({ : getOrCreateContractByType({ address: asset1ContractAddress, type: ContractType.ERC20, + chainId: KnownChainIds.EthereumMainnet, }) }, [asset1ContractAddress, skip]) @@ -116,6 +119,7 @@ export const useUniV2LiquidityPool = ({ : getOrCreateContractByType({ address: lpContractAddress, type: ContractType.UniV2Pair, + chainId: KnownChainIds.EthereumMainnet, }) }, [lpContractAddress, skip]) @@ -445,6 +449,7 @@ export const useUniV2LiquidityPool = ({ const contract = getOrCreateContractByType({ address: contractAddress, type: ContractType.ERC20, + chainId: KnownChainIds.EthereumMainnet, }) if (!contract) return @@ -606,6 +611,7 @@ export const useUniV2LiquidityPool = ({ const contract = getOrCreateContractByType({ address: contractAddress, type: ContractType.ERC20, + chainId: KnownChainIds.EthereumMainnet, }) if (!contract) return diff --git a/src/lib/utils/evm.ts b/src/lib/utils/evm.ts index 2d4331d42ec..d7f8916eb93 100644 --- a/src/lib/utils/evm.ts +++ b/src/lib/utils/evm.ts @@ -28,6 +28,7 @@ type GetApproveContractDataArgs = { approvalAmountCryptoBaseUnit: string to: string spender: string + chainId: ChainId } type BuildArgs = { @@ -224,9 +225,14 @@ export const getApproveContractData = ({ approvalAmountCryptoBaseUnit, to, spender, + chainId, }: GetApproveContractDataArgs): string => { const address = ethers.utils.getAddress(to) - const contract = getOrCreateContractByType({ address, type: ContractType.ERC20 }) + const contract = getOrCreateContractByType({ + address, + type: ContractType.ERC20, + chainId, + }) const data = encodeFunctionData({ abi: contract.abi, functionName: 'approve', diff --git a/src/lib/viem-client.ts b/src/lib/viem-client.ts index c1956d9dfb0..673508ae5ff 100644 --- a/src/lib/viem-client.ts +++ b/src/lib/viem-client.ts @@ -1,6 +1,9 @@ +import type { EvmChainId } from '@shapeshiftoss/chain-adapters' +import { KnownChainIds } from '@shapeshiftoss/types' import { getConfig } from 'config' +import type { PublicClient } from 'viem' import { createPublicClient, http } from 'viem' -import { arbitrum, avalanche, bsc, gnosis, mainnet, optimism } from 'viem/chains' +import { arbitrum, avalanche, bsc, gnosis, mainnet, optimism, polygon } from 'viem/chains' export const viemEthMainnetClient = createPublicClient({ chain: mainnet, @@ -31,3 +34,20 @@ export const viemGnosisClient = createPublicClient({ chain: gnosis, transport: http(getConfig().REACT_APP_GNOSIS_NODE_URL), }) + +export const viemPolygonClient = createPublicClient({ + chain: polygon, + transport: http(getConfig().REACT_APP_POLYGON_NODE_URL), +}) + +export const viemClientByChainId: Record = { + [KnownChainIds.EthereumMainnet]: viemEthMainnetClient, + [KnownChainIds.BnbSmartChainMainnet]: viemBscClient, + [KnownChainIds.AvalancheMainnet]: viemAvalancheClient, + [KnownChainIds.ArbitrumMainnet]: viemArbitrumClient, + [KnownChainIds.GnosisMainnet]: viemGnosisClient, + [KnownChainIds.PolygonMainnet]: viemPolygonClient, + // cast required due to typescript shenanigans + // https://github.com/wagmi-dev/viem/issues/1018 + [KnownChainIds.OptimismMainnet]: viemOptimismClient as PublicClient, +} diff --git a/src/state/slices/opportunitiesSlice/resolvers/uniV2/index.ts b/src/state/slices/opportunitiesSlice/resolvers/uniV2/index.ts index 7c6fe82b537..ad23ea4c40c 100644 --- a/src/state/slices/opportunitiesSlice/resolvers/uniV2/index.ts +++ b/src/state/slices/opportunitiesSlice/resolvers/uniV2/index.ts @@ -1,5 +1,5 @@ import { ethAssetId, fromAssetId, toAssetId } from '@shapeshiftoss/caip' -import type { MarketData } from '@shapeshiftoss/types' +import { KnownChainIds, type MarketData } from '@shapeshiftoss/types' import type { TokenAmount } from '@uniswap/sdk' import { WETH_TOKEN_CONTRACT_ADDRESS } from 'contracts/constants' import { fetchUniV2PairData, getOrCreateContractByType } from 'contracts/contractManager' @@ -196,6 +196,7 @@ export const uniV2LpOpportunitiesMetadataResolver = async ({ const uniV2LPContract = getOrCreateContractByType({ address: contractAddress, type: ContractType.UniV2Pair, + chainId: KnownChainIds.EthereumMainnet, }) const apy = bnOrZero(apr).div(100).toString() diff --git a/src/state/slices/opportunitiesSlice/resolvers/uniV2/utils.test.ts b/src/state/slices/opportunitiesSlice/resolvers/uniV2/utils.test.ts index cdf9f2ddb2c..457f0adf9a3 100644 --- a/src/state/slices/opportunitiesSlice/resolvers/uniV2/utils.test.ts +++ b/src/state/slices/opportunitiesSlice/resolvers/uniV2/utils.test.ts @@ -18,8 +18,9 @@ const mockAmount0Out = '97000000000000000000000' const mockAmount0In = '23000000000000000000000' const blockNumber = 5000000 -jest.mock('lib/viem-client', () => ({ - viemEthMainnetClient: { +jest.mock('lib/viem-client', () => { + const { KnownChainIds } = require('@shapeshiftoss/types') + const viemEthMainnetClient = { createEventFilter: jest.fn(() => ({})), getFilterLogs: () => new Promise(resolve => { @@ -38,8 +39,14 @@ jest.mock('lib/viem-client', () => ({ }, ]) }), - }, -})) + } + return { + viemEthMainnetClient, + viemClientByChainId: { + [KnownChainIds.EthereumMainnet]: viemEthMainnetClient, + }, + } +}) const mockContract = getContract({ abi: [], diff --git a/src/state/slices/opportunitiesSlice/resolvers/uniV2/utils.ts b/src/state/slices/opportunitiesSlice/resolvers/uniV2/utils.ts index c48b8e1838d..bc809f390d9 100644 --- a/src/state/slices/opportunitiesSlice/resolvers/uniV2/utils.ts +++ b/src/state/slices/opportunitiesSlice/resolvers/uniV2/utils.ts @@ -1,5 +1,6 @@ import type { AssetId } from '@shapeshiftoss/caip' import { fromAssetId } from '@shapeshiftoss/caip' +import { KnownChainIds } from '@shapeshiftoss/types' import type { TokenAmount } from '@uniswap/sdk' import type { IUniswapV2Pair } from 'contracts/abis/IUniswapV2Pair' import { getOrCreateContractByType } from 'contracts/contractManager' @@ -108,6 +109,7 @@ export const calculateAPRFromToken0 = memoize( const pair = getOrCreateContractByType({ address: contractAddress, type: ContractType.UniV2Pair, + chainId: KnownChainIds.EthereumMainnet, }) const token0Volume24Hr = await getToken0Volume24Hr({