diff --git a/bridge_ui/src/contexts/EthereumProviderContext.tsx b/bridge_ui/src/contexts/EthereumProviderContext.tsx index 15eecd3ec..ebc635505 100644 --- a/bridge_ui/src/contexts/EthereumProviderContext.tsx +++ b/bridge_ui/src/contexts/EthereumProviderContext.tsx @@ -112,10 +112,10 @@ export const EthereumProviderProvider = ({ setSigner(undefined); setSignerAddress(undefined); setConnectType(undefined); - if (ethereumProvider && ethereumProvider.removeAllListeners) { + if (ethereumProvider?.removeAllListeners) { ethereumProvider.removeAllListeners(); - setEthereumProvider(undefined); } + setEthereumProvider(undefined); if (walletConnectProvider) { walletConnectProvider .disconnect() diff --git a/bridge_ui/src/hooks/useGetSourceParsedTokenAccounts.ts b/bridge_ui/src/hooks/useGetSourceParsedTokenAccounts.ts index 1c73129e9..70f7227bd 100644 --- a/bridge_ui/src/hooks/useGetSourceParsedTokenAccounts.ts +++ b/bridge_ui/src/hooks/useGetSourceParsedTokenAccounts.ts @@ -84,6 +84,7 @@ import { ALGORAND_HOST, ALGO_DECIMALS, COVALENT_GET_TOKENS_URL, + BLOCKSCOUT_GET_TOKENS_URL, KAR_ADDRESS, KAR_DECIMALS, logoOverrides, @@ -108,6 +109,7 @@ import { WMATIC_DECIMALS, WROSE_ADDRESS, WROSE_DECIMALS, + getDefaultNativeCurrencyAddressEvm, } from "../utils/consts"; import { ExtractedMintInfo, @@ -581,12 +583,10 @@ export type CovalentNFTData = { }; const getEthereumAccountsCovalent = async ( - walletAddress: string, + url: string, nft: boolean, chainId: ChainId ): Promise => { - const url = COVALENT_GET_TOKENS_URL(chainId, walletAddress, nft); - try { const output = [] as CovalentData[]; const response = await axios.get(url); @@ -598,6 +598,8 @@ const getEthereumAccountsCovalent = async ( if ( item.contract_decimals !== undefined && item.contract_address && + item.contract_address.toLowerCase() !== + getDefaultNativeCurrencyAddressEvm(chainId).toLowerCase() && // native balance comes from querying token bridge item.balance && item.balance !== "0" && (nft @@ -615,6 +617,47 @@ const getEthereumAccountsCovalent = async ( } }; +export const getEthereumAccountsBlockscout = async ( + url: string, + nft: boolean, + chainId: ChainId +): Promise => { + try { + const output = [] as CovalentData[]; + const response = await axios.get(url); + const tokens = response.data.result; + + if (tokens instanceof Array && tokens.length) { + for (const item of tokens) { + if ( + item.decimals !== undefined && + item.contractAddress && + item.contractAddress.toLowerCase() !== + getDefaultNativeCurrencyAddressEvm(chainId).toLowerCase() && // native balance comes from querying token bridge + item.balance && + item.balance !== "0" && + (nft ? item.type?.includes("ERC-721") : item.type?.includes("ERC-20")) + ) { + output.push({ + contract_decimals: item.decimals, + contract_address: item.contractAddress, + balance: item.balance, + contract_ticker_symbol: item.symbol, + contract_name: item.name, + logo_url: "", + quote: 0, + quote_rate: 0, + }); + } + } + } + + return output; + } catch (error) { + return Promise.reject("Unable to retrieve your Ethereum Tokens."); + } +}; + const getSolanaParsedTokenAccounts = async ( walletAddress: string, dispatch: Dispatch, @@ -1303,16 +1346,28 @@ function useGetAvailableTokens(nft: boolean = false) { }; }, [lookupChain, provider, signerAddress, nft, ethNativeAccount]); - //Ethereum covalent accounts load + //Ethereum covalent or blockscout accounts load useEffect(() => { //const testWallet = "0xf60c2ea62edbfe808163751dd0d8693dcb30019c"; // const nftTestWallet1 = "0x3f304c6721f35ff9af00fd32650c8e0a982180ab"; // const nftTestWallet2 = "0x98ed231428088eb440e8edb5cc8d66dcf913b86e"; // const nftTestWallet3 = "0xb1fadf677a7e9b90e9d4f31c8ffb3dc18c138c6f"; // const nftBscTestWallet1 = "0x5f464a652bd1991df0be37979b93b3306d64a909"; + let cancelled = false; const walletAddress = signerAddress; if (walletAddress && isEVMChain(lookupChain) && !covalent) { + let url = COVALENT_GET_TOKENS_URL(lookupChain, walletAddress, nft); + let getAccounts; + if (url) { + getAccounts = getEthereumAccountsCovalent; + } else { + url = BLOCKSCOUT_GET_TOKENS_URL(lookupChain, walletAddress); + getAccounts = getEthereumAccountsBlockscout; + } + if (!url) { + return; + } //TODO less cancel !cancelled && setCovalentLoading(true); !cancelled && @@ -1321,7 +1376,7 @@ function useGetAvailableTokens(nft: boolean = false) { ? fetchSourceParsedTokenAccountsNFT() : fetchSourceParsedTokenAccounts() ); - getEthereumAccountsCovalent(walletAddress, nft, lookupChain).then( + getAccounts(url, nft, lookupChain).then( (accounts) => { !cancelled && setCovalentLoading(false); !cancelled && setCovalentError(undefined); diff --git a/bridge_ui/src/utils/consts.ts b/bridge_ui/src/utils/consts.ts index 67ba159f8..e9e63729d 100644 --- a/bridge_ui/src/utils/consts.ts +++ b/bridge_ui/src/utils/consts.ts @@ -271,6 +271,35 @@ export const getDefaultNativeCurrencySymbol = (chainId: ChainId) => : chainId === CHAIN_ID_CELO ? "CELO" : ""; + +export const getDefaultNativeCurrencyAddressEvm = (chainId: ChainId) => { + return chainId === CHAIN_ID_ETH + ? WETH_ADDRESS + : chainId === CHAIN_ID_BSC + ? WBNB_ADDRESS + : chainId === CHAIN_ID_POLYGON + ? WMATIC_ADDRESS + : chainId === CHAIN_ID_ETHEREUM_ROPSTEN + ? ROPSTEN_WETH_ADDRESS + : chainId === CHAIN_ID_AVAX + ? WAVAX_ADDRESS + : chainId === CHAIN_ID_OASIS + ? WROSE_ADDRESS + : chainId === CHAIN_ID_AURORA + ? WETH_AURORA_ADDRESS + : chainId === CHAIN_ID_FANTOM + ? WFTM_ADDRESS + : chainId === CHAIN_ID_KARURA + ? KAR_ADDRESS + : chainId === CHAIN_ID_ACALA + ? ACA_ADDRESS + : chainId === CHAIN_ID_KLAYTN + ? WKLAY_ADDRESS + : chainId === CHAIN_ID_CELO + ? CELO_ADDRESS + : ""; +}; + export const getExplorerName = (chainId: ChainId) => chainId === CHAIN_ID_ETH || chainId === CHAIN_ID_ETHEREUM_ROPSTEN ? "Etherscan" @@ -811,15 +840,10 @@ export const COVALENT_BSC = CLUSTER === "devnet" ? 56 : BSC_NETWORK_CHAIN_ID; export const COVALENT_POLYGON = CLUSTER === "devnet" ? 137 : POLYGON_NETWORK_CHAIN_ID; export const COVALENT_AVAX = CLUSTER === "devnet" ? 137 : AVAX_NETWORK_CHAIN_ID; -export const COVALENT_OASIS = CLUSTER === "devnet" ? null : null; -export const COVALENT_AURORA = CLUSTER === "devnet" ? null : null; export const COVALENT_FANTOM = CLUSTER === "devnet" ? 250 : FANTOM_NETWORK_CHAIN_ID; -export const COVALENT_KARURA = CLUSTER === "devnet" ? null : null; -export const COVALENT_ACALA = CLUSTER === "devnet" ? null : null; export const COVALENT_KLAYTN = CLUSTER === "mainnet" ? KLAYTN_NETWORK_CHAIN_ID : null; // Covalent only support mainnet -export const COVALENT_CELO = CLUSTER === "devnet" ? null : null; export const COVALENT_GET_TOKENS_URL = ( chainId: ChainId, walletAddress: string, @@ -835,26 +859,60 @@ export const COVALENT_GET_TOKENS_URL = ( ? COVALENT_POLYGON : chainId === CHAIN_ID_AVAX ? COVALENT_AVAX - : chainId === CHAIN_ID_OASIS - ? COVALENT_OASIS - : chainId === CHAIN_ID_AURORA - ? COVALENT_AURORA : chainId === CHAIN_ID_FANTOM ? COVALENT_FANTOM - : chainId === CHAIN_ID_KARURA - ? COVALENT_KARURA - : chainId === CHAIN_ID_ACALA - ? COVALENT_ACALA : chainId === CHAIN_ID_KLAYTN ? COVALENT_KLAYTN - : chainId === CHAIN_ID_CELO - ? COVALENT_CELO : ""; // https://www.covalenthq.com/docs/api/#get-/v1/{chain_id}/address/{address}/balances_v2/ - return `https://api.covalenthq.com/v1/${chainNum}/address/${walletAddress}/balances_v2/?key=${COVALENT_API_KEY}${ - nft ? "&nft=true" : "" - }${noNftMetadata ? "&no-nft-fetch=true" : ""}`; + return chainNum + ? `https://api.covalenthq.com/v1/${chainNum}/address/${walletAddress}/balances_v2/?key=${COVALENT_API_KEY}${ + nft ? "&nft=true" : "" + }${noNftMetadata ? "&no-nft-fetch=true" : ""}` + : ""; }; + +export const BLOCKSCOUT_GET_TOKENS_URL = ( + chainId: ChainId, + walletAddress: string +) => { + const baseUrl = + chainId === CHAIN_ID_OASIS + ? CLUSTER === "mainnet" + ? "https://explorer.emerald.oasis.dev" + : CLUSTER === "testnet" + ? "https://testnet.explorer.emerald.oasis.dev" + : "" + : chainId === CHAIN_ID_AURORA + ? CLUSTER === "mainnet" + ? "https://explorer.mainnet.aurora.dev" + : CLUSTER === "testnet" + ? "https://explorer.testnet.aurora.dev" + : "" + : chainId === CHAIN_ID_ACALA + ? CLUSTER === "mainnet" + ? "https://blockscout.acala.network" + : CLUSTER === "testnet" + ? "https://blockscout.acala-dev.aca-dev.network" + : "" + : chainId === CHAIN_ID_KARURA + ? CLUSTER === "mainnet" + ? "https://blockscout.karura.network" + : CLUSTER === "testnet" + ? "https://blockscout.karura-dev.aca-dev.network" + : "" + : chainId === CHAIN_ID_CELO + ? CLUSTER === "mainnet" + ? "https://explorer.celo.org" + : CLUSTER === "testnet" + ? "https://alfajores-blockscout.celo-testnet.org" + : "" + : ""; + return baseUrl + ? `${baseUrl}/api?module=account&action=tokenlist&address=${walletAddress}` + : ""; +}; + export const TVL_URL = "https://europe-west3-wormhole-315720.cloudfunctions.net/mainnet-notionaltvl"; export const TVL_CUMULATIVE_URL = diff --git a/bridge_ui/src/utils/metaMaskChainParameters.ts b/bridge_ui/src/utils/metaMaskChainParameters.ts index 538f65669..9389af283 100644 --- a/bridge_ui/src/utils/metaMaskChainParameters.ts +++ b/bridge_ui/src/utils/metaMaskChainParameters.ts @@ -119,7 +119,7 @@ export const METAMASK_CHAIN_PARAMETERS: { chainId: "0xaef3", chainName: "Celo (Alfajores Testnet)", nativeCurrency: { name: "Celo", symbol: "CELO", decimals: 18 }, - rpcUrls: ["https://forno.celo.org"], + rpcUrls: ["https://alfajores-forno.celo-testnet.org"], blockExplorerUrls: ["https://alfajores-blockscout.celo-testnet.org"], }, 42261: {