diff --git a/cw_evm/lib/evm_chain_wallet.dart b/cw_evm/lib/evm_chain_wallet.dart index f064086b0..ad81272f6 100644 --- a/cw_evm/lib/evm_chain_wallet.dart +++ b/cw_evm/lib/evm_chain_wallet.dart @@ -276,6 +276,8 @@ abstract class EVMChainWalletBase evmChainErc20TokensBox = await CakeHive.openBox(boxName); } + await _normalizeEvmChainErc20TokensBoxKeys(); + addInitialTokens(); } @@ -306,6 +308,88 @@ abstract class EVMChainWalletBase String getTransactionHistoryFileName() => EVMChainUtils.getTransactionHistoryFileName(selectedChainId); + /// Ensures all ERC20 token entries use lowercase contract addresses as + /// their Hive keys to avoid duplicates caused by case differences. + Future _normalizeEvmChainErc20TokensBoxKeys() async { + if (!evmChainErc20TokensBox.isOpen) return; + + final prefs = await sharedPrefs.future; + final migrationKey = 'erc20_box_normalized_${walletInfo.name}_$selectedChainId'; + + if (prefs.getBool(migrationKey) ?? false) return; + + final box = evmChainErc20TokensBox; + final keys = box.keys.cast().toList(growable: false); + + if (keys.isEmpty) { + await prefs.setBool(migrationKey, true); + return; + } + + final Map normalizedTokens = {}; + var needsRewrite = false; + + for (final key in keys) { + final token = box.get(key); + + if (token == null) { + needsRewrite = true; + continue; + } + + final lowerKey = key.toLowerCase(); + + final Erc20Token normalizedToken = + token.contractAddress == token.contractAddress.toLowerCase() + ? token + : Erc20Token( + name: token.name, + symbol: token.symbol, + contractAddress: token.contractAddress.toLowerCase(), + decimal: token.decimal, + enabled: token.enabled, + iconPath: token.iconPath, + tag: token.tag, + isPotentialScam: token.isPotentialScam, + ); + + if (!needsRewrite && (lowerKey != key || identical(normalizedToken, token) == false)) { + needsRewrite = true; + } + + final existing = normalizedTokens[lowerKey]; + + if (existing == null) { + normalizedTokens[lowerKey] = normalizedToken; + continue; + } + + final merged = Erc20Token( + name: normalizedToken.name, + symbol: normalizedToken.symbol, + contractAddress: lowerKey, + decimal: normalizedToken.decimal, + enabled: normalizedToken.enabled || existing.enabled, + iconPath: (normalizedToken.iconPath?.isNotEmpty ?? false) + ? normalizedToken.iconPath + : existing.iconPath, + tag: normalizedToken.tag ?? existing.tag, + isPotentialScam: normalizedToken.isPotentialScam || existing.isPotentialScam, + ); + + normalizedTokens[lowerKey] = merged; + } + + if (needsRewrite) { + await box.clear(); + for (final entry in normalizedTokens.entries) { + await box.put(entry.key, entry.value); + } + } + + await prefs.setBool(migrationKey, true); + } + Future checkIfScanProviderIsEnabled() async { final key = EVMChainUtils.getScanProviderPreferenceKey(selectedChainId); return (await sharedPrefs.future).getBool(key) ?? true; diff --git a/cw_evm/lib/tokens/arbitrum_tokens.dart b/cw_evm/lib/tokens/arbitrum_tokens.dart index 34470fdfc..fb6aa7703 100644 --- a/cw_evm/lib/tokens/arbitrum_tokens.dart +++ b/cw_evm/lib/tokens/arbitrum_tokens.dart @@ -8,56 +8,56 @@ class ArbitrumTokens { Erc20Token( name: "Arbitrum", symbol: "ARB", - contractAddress: "0x912CE59144191C1204E64559FE8253a0e49E6548", + contractAddress: "0x912ce59144191c1204e64559fe8253a0e49e6548", decimal: 18, enabled: true, ), Erc20Token( name: "USD Coin", symbol: "USDC", - contractAddress: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831", + contractAddress: "0xaf88d065e77c8cc2239327c5edb3a432268e5831", decimal: 6, enabled: true, ), Erc20Token( name: "USDC.e", symbol: "USDC.e", - contractAddress: "0xFF970A61A04b1cA14834A43f5dE4533eBDDB5CC8", + contractAddress: "0xff970a61a04b1ca14834a43f5de4533ebddb5cc8", decimal: 6, enabled: true, ), Erc20Token( name: "Wrapped BTC", symbol: "WBTC", - contractAddress: "0x2f2a2543B76A4166549F7aaB2e75Bef0aefC5B0f", + contractAddress: "0x2f2a2543b76a4166549f7aab2e75bef0aefc5b0f", decimal: 8, enabled: true, ), Erc20Token( name: "Chainlink Token", symbol: "LINK", - contractAddress: "0xf97f4df75117a78c1A5a0DBb814Af92458539FB4", + contractAddress: "0xf97f4df75117a78c1a5a0dbb814af92458539fb4", decimal: 18, enabled: true, ), Erc20Token( name: "Wrapped liquid staked Ether 2.0", symbol: "wstETH", - contractAddress: "0x0fBcbaEA96Ce0cF7Ee00A8c19c3ab6f5Dc8E1921", + contractAddress: "0x0fbcbaea96ce0cf7ee00a8c19c3ab6f5dc8e1921", decimal: 18, enabled: false, ), Erc20Token( name: "Wrapped Ether", symbol: "WETH", - contractAddress: "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1", + contractAddress: "0x82af49447d8a07e3bd95bd0d56f35241523fbab1", decimal: 18, enabled: false, ), Erc20Token( name: "DAI", symbol: "DAI", - contractAddress: "0xDA10009cBd5D07dd0CeCc66161FC93D7c9000da1", + contractAddress: "0xda10009cbd5d07dd0cecc66161fc93d7c9000da1", decimal: 18, enabled: false, ), diff --git a/cw_evm/lib/tokens/base_tokens.dart b/cw_evm/lib/tokens/base_tokens.dart index 6169bc923..83f7b4080 100644 --- a/cw_evm/lib/tokens/base_tokens.dart +++ b/cw_evm/lib/tokens/base_tokens.dart @@ -15,21 +15,21 @@ class BaseTokens { Erc20Token( name: "USDe", symbol: "USDe", - contractAddress: "0x5d3a1Ff2b6BAb83b63cd9AD0787074081a52ef34", + contractAddress: "0x5d3a1ff2b6bab83b63cd9ad0787074081a52ef34", decimal: 18, enabled: true, ), Erc20Token( name: "Dai", symbol: "DAI", - contractAddress: "0x50c5725949A6F0c72E6C4a641F24049A917DB0Cb", + contractAddress: "0x50c5725949a6f0c72e6c4a641f24049a917db0cb", decimal: 18, enabled: true, ), Erc20Token( name: "Bridged Tether USD", symbol: "USDT", - contractAddress: "0xfde4C96c8593536E31F229EA8f37b2ADa2699bb2", + contractAddress: "0xfde4c96c8593536e31f229ea8f37b2ada2699bb2", decimal: 6, enabled: true, ), @@ -43,14 +43,14 @@ class BaseTokens { Erc20Token( name: "Wrapped BTC", symbol: "WBTC", - contractAddress: "0x0555E30da8f98308EdB960aa94C0Db47230d2B9c", + contractAddress: "0x0555e30da8f98308edb960aa94c0db47230d2b9c", decimal: 8, enabled: false, ), Erc20Token( name: "SPX6900", symbol: "SPX", - contractAddress: "0x50dA645f148798F68EF2d7dB7C1CB22A6819bb2C", + contractAddress: "0x50da645f148798f68ef2d7db7c1cb22a6819bb2c", decimal: 8, enabled: false, ), diff --git a/cw_evm/lib/tokens/bsc_tokens.dart b/cw_evm/lib/tokens/bsc_tokens.dart index 2e003f2fd..67a5078ff 100644 --- a/cw_evm/lib/tokens/bsc_tokens.dart +++ b/cw_evm/lib/tokens/bsc_tokens.dart @@ -8,42 +8,42 @@ class BSCTokens { Erc20Token( name: "USD Coin", symbol: "USDC", - contractAddress: "0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d", + contractAddress: "0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d", decimal: 18, enabled: true, ), Erc20Token( name: "Ethereum", symbol: "ETH", - contractAddress: "0x2170Ed0880ac9A755fd29B2688956BD959F933F8", + contractAddress: "0x2170ed0880ac9a755fd29b2688956bd959f933f8", decimal: 18, enabled: true, ), Erc20Token( name: "Tether USD", symbol: "USDT", - contractAddress: "0x55d398326f99059fF775485246999027B3197955", + contractAddress: "0x55d398326f99059ff775485246999027b3197955", decimal: 18, enabled: true, ), Erc20Token( name: "USDe", symbol: "USDe", - contractAddress: "0x5d3a1Ff2b6BAb83b63cd9AD0787074081a52ef34", + contractAddress: "0x5d3a1ff2b6bab83b63cd9ad0787074081a52ef34", decimal: 18, enabled: true, ), Erc20Token( name: "PancakeSwap Token", symbol: "CAKE", - contractAddress: "0x0E09FaBB73Bd3Ade0a17ECC321fD13a19e81cE82", + contractAddress: "0x0e09fabb73bd3ade0a17ecc321fd13a19e81ce82", decimal: 18, enabled: false, ), Erc20Token( name: "Cardano Token", symbol: "ADA", - contractAddress: "0x3EE2200Efb3400fAbB9AacF31297cBdD1d435D47", + contractAddress: "0x3ee2200efb3400fabb9aacf31297cbdd1d435d47", decimal: 18, enabled: false, ), @@ -57,14 +57,14 @@ class BSCTokens { Erc20Token( name: "Wrapped BTC", symbol: "WBTC", - contractAddress: "0x0555E30da8f98308EdB960aa94C0Db47230d2B9c", + contractAddress: "0x0555e30da8f98308edb960aa94c0db47230d2b9c", decimal: 8, enabled: false, ), Erc20Token( name: "Wrapped BNB", symbol: "WBNB", - contractAddress: "0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c", + contractAddress: "0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c", decimal: 18, enabled: false, ), diff --git a/cw_evm/lib/tokens/ethereum_tokens.dart b/cw_evm/lib/tokens/ethereum_tokens.dart index 33e18ec8f..5f1f4b273 100644 --- a/cw_evm/lib/tokens/ethereum_tokens.dart +++ b/cw_evm/lib/tokens/ethereum_tokens.dart @@ -22,21 +22,21 @@ class EthereumTokens { Erc20Token( name: "Decentralized Euro", symbol: "DEURO", - contractAddress: "0xbA3f535bbCcCcA2A154b573Ca6c5A49BAAE0a3ea", + contractAddress: "0xba3f535bbcccca2a154b573ca6c5a49baae0a3ea", decimal: 18, enabled: true, ), Erc20Token( name: "Dai", symbol: "DAI", - contractAddress: "0x6B175474E89094C44Da98b954EedeAC495271d0F", + contractAddress: "0x6b175474e89094c44da98b954eedeac495271d0f", decimal: 18, enabled: true, ), Erc20Token( name: "Wrapped Ether", symbol: "WETH", - contractAddress: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + contractAddress: "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", decimal: 18, enabled: false, ), @@ -64,7 +64,7 @@ class EthereumTokens { Erc20Token( name: "Matic Token", symbol: "MATIC", - contractAddress: "0x7D1AfA7B718fb893dB30A3aBc0Cfc608AaCfeBB0", + contractAddress: "0x7d1afa7b718fb893db30a3abc0cfc608aacfebb0", decimal: 18, enabled: false, ), @@ -85,7 +85,7 @@ class EthereumTokens { Erc20Token( name: "Tether Gold", symbol: "XAUT", - contractAddress: "0x68749665FF8D2d112Fa859AA293F07A622782F38", + contractAddress: "0x68749665ff8d2d112fa859aa293f07a622782f38", decimal: 6, enabled: false, iconPath: "assets/images/xaut_icon.png", diff --git a/cw_evm/lib/tokens/polygon_tokens.dart b/cw_evm/lib/tokens/polygon_tokens.dart index 24957a17a..c6aa67bee 100644 --- a/cw_evm/lib/tokens/polygon_tokens.dart +++ b/cw_evm/lib/tokens/polygon_tokens.dart @@ -8,63 +8,63 @@ class PolygonTokens { Erc20Token( name: "Wrapped Ether", symbol: "WETH", - contractAddress: "0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619", + contractAddress: "0x7ceb23fd6bc0add59e62ac25578270cff1b9f619", decimal: 18, enabled: false, ), Erc20Token( name: "Tether USD (PoS)", symbol: "USDT", - contractAddress: "0xc2132D05D31c914a87C6611C10748AEb04B58e8F", + contractAddress: "0xc2132d05d31c914a87c6611c10748aeb04b58e8f", decimal: 6, enabled: true, ), Erc20Token( name: "USD Coin", symbol: "USDC", - contractAddress: "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359", + contractAddress: "0x3c499c542cef5e3811e1192ce70d8cc03d5c3359", decimal: 6, enabled: true, ), Erc20Token( name: "USD Coin (POS)", symbol: "USDC.e", - contractAddress: "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174", + contractAddress: "0x2791bca1f2de4661ed88a30c99a7a9449aa84174", decimal: 6, enabled: true, ), Erc20Token( name: "Decentralized Euro", symbol: "DEURO", - contractAddress: "0xC2ff25dD99e467d2589b2c26EDd270F220F14E47", + contractAddress: "0xc2ff25dd99e467d2589b2c26edd270f220f14e47", decimal: 18, enabled: true, ), Erc20Token( name: "Avalanche Token", symbol: "AVAX", - contractAddress: "0x2C89bbc92BD86F8075d1DEcc58C7F4E0107f286b", + contractAddress: "0x2c89bbc92bd86f8075d1decc58c7f4e0107f286b", decimal: 18, enabled: false, ), Erc20Token( name: "Wrapped BTC (PoS)", symbol: "WBTC", - contractAddress: "0x1BFD67037B42Cf73acF2047067bd4F2C47D9BfD6", + contractAddress: "0x1bfd67037b42cf73acf2047067bd4f2c47d9bfd6", decimal: 8, enabled: false, ), Erc20Token( name: "Dai (PoS)", symbol: "DAI", - contractAddress: "0x8f3Cf7ad23Cd3CaDbD9735AFf958023239c6A063", + contractAddress: "0x8f3cf7ad23cd3cadbd9735aff958023239c6a063", decimal: 18, enabled: true, ), Erc20Token( name: "SHIBA INU (PoS)", symbol: "SHIB", - contractAddress: "0x6f8a06447Ff6FcF75d803135a7de15CE88C1d4ec", + contractAddress: "0x6f8a06447ff6fcf75d803135a7de15ce88c1d4ec", decimal: 18, enabled: false, ),