diff --git a/cw_evm/lib/evm_chain_wallet.dart b/cw_evm/lib/evm_chain_wallet.dart index b9fa6dcd7..c44042077 100644 --- a/cw_evm/lib/evm_chain_wallet.dart +++ b/cw_evm/lib/evm_chain_wallet.dart @@ -509,17 +509,17 @@ abstract class EVMChainWalletBase } } - Future> discoverTokensFromMoralis() async { + Future discoverTokensFromMoralis() async { try { - if (!evmChainErc20TokensBox.isOpen) return []; + if (!evmChainErc20TokensBox.isOpen) return MoralisDiscoveryResult.empty; final address = walletAddresses.address; - if (address.isEmpty) return []; + if (address.isEmpty) return MoralisDiscoveryResult.empty; final chainName = EVMChainUtils.getDefaultTokenSymbol(selectedChainId).toLowerCase(); final walletTokens = await _client.fetchWalletTokensFromMoralis(address, chainName); - if (walletTokens.isEmpty) return []; + if (walletTokens.isEmpty) return MoralisDiscoveryResult.empty; final existingTokenAddresses = { for (final token in evmChainErc20TokensBox.values) @@ -529,7 +529,7 @@ abstract class EVMChainWalletBase final whitelistedTokenAddresses = getDefaultTokenContractAddresses.map((a) => a.toLowerCase()).toSet(); - final List newTokens = []; + final newTokens = []; for (final token in walletTokens) { final addr = token.contractAddress.toLowerCase(); @@ -554,13 +554,18 @@ abstract class EVMChainWalletBase isPotentialScam: token.possibleSpam, ); - newTokens.add(newToken); + newTokens.add( + DiscoveredToken( + token: newToken, + balanceWei: token.balanceWei, + ), + ); } - return newTokens; + return MoralisDiscoveryResult(newTokens: newTokens); } catch (e) { printV('Error discovering tokens from Moralis: ${e.toString()}'); - return []; + return MoralisDiscoveryResult.empty; } } @@ -1535,3 +1540,21 @@ class GasParamsHandler { ); } } + +class DiscoveredToken { + final Erc20Token token; + final BigInt balanceWei; + + const DiscoveredToken({ + required this.token, + required this.balanceWei, + }); +} + +class MoralisDiscoveryResult { + final List newTokens; + + const MoralisDiscoveryResult({required this.newTokens}); + + static const MoralisDiscoveryResult empty = MoralisDiscoveryResult(newTokens: []); +} diff --git a/cw_evm/lib/utils/evm_chain_utils.dart b/cw_evm/lib/utils/evm_chain_utils.dart index 2f882c20f..634d2a1fc 100644 --- a/cw_evm/lib/utils/evm_chain_utils.dart +++ b/cw_evm/lib/utils/evm_chain_utils.dart @@ -86,7 +86,7 @@ class EVMChainUtils { 137 => 'MATIC', 8453 => 'BASE', 42161 => 'ARBITRUM', - 56 => 'BNB', + 56 => 'BSC', _ => 'ETH', }; } diff --git a/lib/evm/cw_evm.dart b/lib/evm/cw_evm.dart index eff7c40ca..1aef384ac 100644 --- a/lib/evm/cw_evm.dart +++ b/lib/evm/cw_evm.dart @@ -514,49 +514,59 @@ class CWEVM extends EVM { @override bool hasPriorityFee(int chainId) => EVMChainUtils.hasPriorityFee(chainId); - @override - Future checkTokenFiatPrice(WalletBase wallet, Erc20Token token) async { + Future<({double usdValue, bool hasValidFiatPrice})> _getTokenUsdValueAndFiatCheck( + Erc20Token token, + BigInt balanceWei, + ) async { try { final settingsStore = getIt.get(); - final fiatCurrency = settingsStore.fiatCurrency; final torOnly = settingsStore.fiatApiMode == FiatApiMode.torOnly; final price = await FiatConversionService.fetchPrice( crypto: token, - fiat: fiatCurrency, + fiat: FiatCurrency.usd, torOnly: torOnly, ); - return price > 0; + final hasValidFiatPrice = price > 0; + + final decimals = token.decimal; + final balance = balanceWei.toDouble() / math.pow(10, decimals); + final usdValue = balance * price; + + return (usdValue: usdValue, hasValidFiatPrice: hasValidFiatPrice); } catch (e) { - return false; + return (usdValue: 0.0, hasValidFiatPrice: false); } } + static const _minTokenUsdValue = 0.1; @override Future discoverAndAddWalletTokens(WalletBase wallet) async { if (wallet is! EVMChainWallet) return; try { - final discoveredTokens = await wallet.discoverTokensFromMoralis(); + final result = await wallet.discoverTokensFromMoralis(); - if (discoveredTokens.isEmpty) return; + if (result.newTokens.isEmpty) return; final List> tokenChecks = []; - for (final token in discoveredTokens) { + for (final item in result.newTokens) { tokenChecks.add((() async { + final token = item.token; + final isPropertiesSuspicious = wallet.isTokenPropertiesSuspicious(token); - bool hasValidFiatPrice = true; - if (!isPropertiesSuspicious) { - hasValidFiatPrice = await checkTokenFiatPrice(wallet, token); - } - - final isSpam = isPropertiesSuspicious || !hasValidFiatPrice; + final fiatResult = await _getTokenUsdValueAndFiatCheck( + token, + item.balanceWei, + ); + final isSpam = isPropertiesSuspicious || !fiatResult.hasValidFiatPrice; token.isPotentialScam = isSpam; - token.enabled = !isSpam; + + token.enabled = (fiatResult.usdValue >= _minTokenUsdValue) && !isSpam; await wallet.addErc20Token(token); })()); diff --git a/tool/configure.dart b/tool/configure.dart index 074c3f1c4..aa43adb90 100644 --- a/tool/configure.dart +++ b/tool/configure.dart @@ -1322,6 +1322,7 @@ abstract class DogeCoin { Future generateEVM(bool hasImplementation) async { final outputFile = File(evmOutputPath); const evmCommonHeaders = """ +import 'dart:math' as math; import 'package:cake_wallet/core/utilities.dart'; import 'package:cake_wallet/view_model/send/output.dart'; import 'package:cw_core/crypto_currency.dart'; @@ -1348,6 +1349,7 @@ import 'package:web3dart/web3dart.dart'; import 'package:cake_wallet/core/fiat_conversion_service.dart'; import 'package:cake_wallet/di.dart'; import 'package:cake_wallet/entities/fiat_api_mode.dart'; +import 'package:cake_wallet/entities/fiat_currency.dart'; import 'package:cake_wallet/store/settings_store.dart'; import 'package:cw_evm/utils/evm_chain_formatter.dart'; import 'package:cw_evm/evm_chain_mnemonics.dart'; @@ -1523,7 +1525,6 @@ abstract class EVM { bool hasPriorityFee(int chainId); - Future checkTokenFiatPrice(WalletBase wallet, Erc20Token token); Future discoverAndAddWalletTokens(WalletBase wallet); } @@ -1792,7 +1793,7 @@ Future generatePubspec({ output += '\n$flutterSecureStorage\n'; } - if (hasEthereum || hasPolygon || hasBase || hasArbitrum) { + if (hasEthereum || hasPolygon || hasBase || hasArbitrum || hasBsc) { output += '\n$cwEVM'; }