mirror of
https://github.com/Such-Software/hash-wallet.git
synced 2026-10-26 06:08:40 +01:00
Migrate EVM/Sol/TRX tokens to SQL (#3450)
* fix android CI * feat: Migrate EVM, Sol and Tron tokens to SQL * handle rename edgecase * refactor: enhance token migration logic and improve database handling
This commit is contained in:
@@ -18,6 +18,9 @@ import 'package:cake_wallet/core/key_service.dart';
|
||||
import 'package:cake_wallet/entities/encrypt.dart';
|
||||
import 'package:cake_wallet/entities/preferences_key.dart';
|
||||
import 'package:cake_wallet/entities/secret_store_key.dart';
|
||||
import 'package:cw_core/erc20_token_legacy.dart' show performErc20TokenHiveMigration;
|
||||
import 'package:cw_core/spl_token_legacy.dart' show performSplTokenHiveMigration;
|
||||
import 'package:cw_core/tron_token_legacy.dart' show performTronTokenHiveMigration;
|
||||
import 'package:cw_core/wallet_info.dart';
|
||||
import 'package:cake_wallet/exchange/trade_legacy.dart';
|
||||
import 'package:cake_wallet/.secrets.g.dart' as secrets;
|
||||
@@ -113,6 +116,10 @@ class $BackupService {
|
||||
Future<void> verifyWallets() async {
|
||||
await performHiveMigration(); // for backups made before sqlite migration
|
||||
await performTradeHiveMigration(_secureStorage);
|
||||
await performErc20TokenHiveMigration();
|
||||
await performSplTokenHiveMigration();
|
||||
await performTronTokenHiveMigration();
|
||||
|
||||
correctWallets = (await WalletInfo.getAll())
|
||||
.where((info) => availableWalletTypes.contains(info.type))
|
||||
.toList();
|
||||
|
||||
@@ -27,7 +27,6 @@ import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:encrypt/encrypt.dart' as encrypt;
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:cw_core/cake_hive.dart';
|
||||
import 'package:cw_core/erc20_token.dart';
|
||||
|
||||
const newCakeWalletMoneroUri = 'xmr-node.cakewallet.com:18081';
|
||||
@@ -1270,22 +1269,22 @@ Future<void> _addXautTokenToExistingEthereumWallets() async {
|
||||
|
||||
final ethereumWallets =
|
||||
allWallets.where((wallet) => wallet.type == WalletType.ethereum).toList();
|
||||
const ethereumChainId = 1;
|
||||
|
||||
for (final walletInfo in ethereumWallets) {
|
||||
final sanitizedName = walletInfo.name.replaceAll(' ', '_');
|
||||
final boxName = '${sanitizedName}_${Erc20Token.ethereumBoxName}';
|
||||
final existingToken = await Erc20Token.getByContract(
|
||||
walletInfo.name,
|
||||
ethereumChainId,
|
||||
xautToken.contractAddress,
|
||||
);
|
||||
|
||||
Box<Erc20Token> tokenBox;
|
||||
if (CakeHive.isBoxOpen(boxName)) {
|
||||
tokenBox = CakeHive.box<Erc20Token>(boxName);
|
||||
} else {
|
||||
tokenBox = await CakeHive.openBox<Erc20Token>(boxName);
|
||||
}
|
||||
if (existingToken != null) continue;
|
||||
|
||||
final xautAddress = xautToken.contractAddress;
|
||||
if (!tokenBox.containsKey(xautAddress)) {
|
||||
await tokenBox.put(xautAddress, xautToken);
|
||||
}
|
||||
await Erc20Token.copyWith(
|
||||
xautToken,
|
||||
walletName: walletInfo.name,
|
||||
chainId: ethereumChainId,
|
||||
).save();
|
||||
}
|
||||
} catch (e) {
|
||||
printV('Error in XAUT migration: $e');
|
||||
@@ -1309,20 +1308,11 @@ Future<void> _addXaut0TokenToExistingSolanaWallets() async {
|
||||
final solanaWallets = allWallets.where((wallet) => wallet.type == WalletType.solana).toList();
|
||||
|
||||
for (final walletInfo in solanaWallets) {
|
||||
final sanitizedName = walletInfo.name.replaceAll(' ', '_');
|
||||
final boxName = '${sanitizedName}_${SPLToken.boxName}';
|
||||
final existingToken = await SPLToken.getByMint(walletInfo.name, xaut0Token.mintAddress);
|
||||
|
||||
Box<SPLToken> tokenBox;
|
||||
if (CakeHive.isBoxOpen(boxName)) {
|
||||
tokenBox = CakeHive.box<SPLToken>(boxName);
|
||||
} else {
|
||||
tokenBox = await CakeHive.openBox<SPLToken>(boxName);
|
||||
}
|
||||
if (existingToken != null) continue;
|
||||
|
||||
final xaut0Address = xaut0Token.mintAddress;
|
||||
if (!tokenBox.containsKey(xaut0Address)) {
|
||||
await tokenBox.put(xaut0Address, xaut0Token);
|
||||
}
|
||||
await SPLToken.copyWith(xaut0Token, walletName: walletInfo.name).save();
|
||||
}
|
||||
} catch (e) {
|
||||
printV('Error in XAUT0 migration: $e');
|
||||
@@ -1346,20 +1336,13 @@ Future<void> _addTbbTokenToExistingSolanaWallets() async {
|
||||
final solanaWallets = allWallets.where((wallet) => wallet.type == WalletType.solana).toList();
|
||||
|
||||
for (final walletInfo in solanaWallets) {
|
||||
final sanitizedName = walletInfo.name.replaceAll(" ", "_");
|
||||
final boxName = "${sanitizedName}_${SPLToken.boxName}";
|
||||
final existingToken = await SPLToken.getByMint(walletInfo.name, tbbToken.mintAddress);
|
||||
|
||||
Box<SPLToken> tokenBox;
|
||||
if (CakeHive.isBoxOpen(boxName)) {
|
||||
tokenBox = CakeHive.box<SPLToken>(boxName);
|
||||
} else {
|
||||
tokenBox = await CakeHive.openBox<SPLToken>(boxName);
|
||||
if (existingToken != null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final tbbAddress = tbbToken.mintAddress;
|
||||
if (!tokenBox.containsKey(tbbAddress)) {
|
||||
await tokenBox.put(tbbAddress, tbbToken);
|
||||
}
|
||||
await SPLToken.copyWith(tbbToken, walletName: walletInfo.name).save();
|
||||
}
|
||||
} catch (e) {
|
||||
printV("Error in TBB migration: $e");
|
||||
|
||||
+6
-14
@@ -43,7 +43,7 @@ import 'package:cake_wallet/zcash/zcash.dart';
|
||||
import 'package:cw_core/address_info.dart';
|
||||
import 'package:cw_core/cake_hive.dart';
|
||||
import 'package:cw_core/db/sqlite.dart';
|
||||
import 'package:cw_core/erc20_token.dart';
|
||||
import 'package:cw_core/erc20_token_legacy.dart' show performErc20TokenHiveMigration;
|
||||
import 'package:cw_core/hive_type_ids.dart';
|
||||
import 'package:cw_core/key.dart';
|
||||
import 'package:cw_core/mweb_utxo.dart';
|
||||
@@ -51,8 +51,8 @@ import 'package:cw_core/node.dart';
|
||||
import 'package:cw_core/node_legacy.dart' show performNodeHiveMigration;
|
||||
import 'package:cw_core/payjoin_session.dart';
|
||||
import 'package:cw_core/root_dir.dart';
|
||||
import 'package:cw_core/spl_token.dart';
|
||||
import 'package:cw_core/tron_token.dart';
|
||||
import 'package:cw_core/spl_token_legacy.dart' show performSplTokenHiveMigration;
|
||||
import 'package:cw_core/tron_token_legacy.dart' show performTronTokenHiveMigration;
|
||||
import 'package:cw_core/unspent_coins_info.dart';
|
||||
import 'package:cw_core/utils/print_verbose.dart';
|
||||
import 'package:cw_core/utils/proxy_logger/memory_proxy_logger.dart';
|
||||
@@ -265,18 +265,10 @@ Future<void> initializeAppConfigs({bool loadWallet = true}) async {
|
||||
CakeHive.registerAdapter(PayjoinSessionAdapter());
|
||||
}
|
||||
|
||||
if (!CakeHive.isAdapterRegistered(Erc20Token.typeId)) {
|
||||
CakeHive.registerAdapter(Erc20TokenAdapter());
|
||||
}
|
||||
|
||||
if (!CakeHive.isAdapterRegistered(SPLToken.typeId)) {
|
||||
CakeHive.registerAdapter(SPLTokenAdapter());
|
||||
}
|
||||
|
||||
if (!CakeHive.isAdapterRegistered(TronToken.typeId)) {
|
||||
CakeHive.registerAdapter(TronTokenAdapter());
|
||||
}
|
||||
await performHiveMigration();
|
||||
await performErc20TokenHiveMigration();
|
||||
await performSplTokenHiveMigration();
|
||||
await performTronTokenHiveMigration();
|
||||
|
||||
final secureStorage = secureStorageShared;
|
||||
final transactionDescriptionsBoxKey =
|
||||
|
||||
@@ -26,10 +26,10 @@ class TokenUtilities {
|
||||
|
||||
for (final wallet in evmWallets) {
|
||||
final chain = getTokenNameBasedOnWalletType(wallet.type);
|
||||
final box = await _openEvmTokensBoxFor(wallet);
|
||||
final tokens = await Erc20Token.getAllForWallet(wallet.name, _getDefaultChainId(wallet.type));
|
||||
|
||||
for (final t in box.values.where((t) => t.enabled)) {
|
||||
final key = '$chain|${t.contractAddress.toLowerCase()}';
|
||||
for (final t in tokens.where((t) => t.enabled)) {
|
||||
final key = "$chain|${t.contractAddress.toLowerCase()}";
|
||||
if (seen.add(key)) {
|
||||
unique.add(t);
|
||||
}
|
||||
@@ -47,15 +47,17 @@ class TokenUtilities {
|
||||
|
||||
final tokens = <SPLToken>[];
|
||||
for (final wallet in solWallets) {
|
||||
final box = await _openSolTokensBoxFor(wallet);
|
||||
tokens.addAll(box.values.where((t) => t.enabled));
|
||||
final walletTokens = await SPLToken.getAllForWallet(wallet.name);
|
||||
tokens.addAll(walletTokens.where((t) => t.enabled));
|
||||
}
|
||||
|
||||
final seen = <String>{};
|
||||
final unique = <SPLToken>[];
|
||||
for (final token in tokens) {
|
||||
final key = token.mintAddress.toLowerCase();
|
||||
if (seen.add(key)) unique.add(token);
|
||||
if (seen.add(key)) {
|
||||
unique.add(token);
|
||||
}
|
||||
}
|
||||
return unique;
|
||||
}
|
||||
@@ -69,25 +71,31 @@ class TokenUtilities {
|
||||
final seen = <String>{};
|
||||
final unique = <TronToken>[];
|
||||
for (final wallet in tronWallets) {
|
||||
final box = await _openTronTokensBoxFor(wallet);
|
||||
for (final t in box.values.where((t) => t.enabled)) {
|
||||
final walletTokens = await TronToken.getAllForWallet(wallet.name);
|
||||
for (final t in walletTokens.where((t) => t.enabled)) {
|
||||
final key = t.contractAddress.toLowerCase();
|
||||
if (seen.add(key)) unique.add(t);
|
||||
if (seen.add(key)) {
|
||||
unique.add(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
return unique;
|
||||
}
|
||||
|
||||
static List<Erc20Token> loadDefaultEvmTokensForSwap() {
|
||||
if (evm == null) return [];
|
||||
if (evm == null) {
|
||||
return [];
|
||||
}
|
||||
|
||||
final tokens = <Erc20Token>[];
|
||||
final seen = <String>{};
|
||||
|
||||
for (final chain in evm!.getAllChains()) {
|
||||
for (final token in evm!.getDefaultTokensByChainId(chain.chainId)) {
|
||||
final key = '${chain.chainId}|${token.contractAddress.toLowerCase()}';
|
||||
if (seen.add(key)) tokens.add(token);
|
||||
final key = "${chain.chainId}|${token.contractAddress.toLowerCase()}";
|
||||
if (seen.add(key)) {
|
||||
tokens.add(token);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,7 +117,9 @@ class TokenUtilities {
|
||||
|
||||
for (final t in [...defaultTokens, ...userTokens]) {
|
||||
final key = '${t.tag ?? 'ETH'}|${t.contractAddress.toLowerCase()}';
|
||||
if (seen.add(key)) result.add(t);
|
||||
if (seen.add(key)) {
|
||||
result.add(t);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -124,7 +134,9 @@ class TokenUtilities {
|
||||
|
||||
for (final t in [...defaultTokens, ...userTokens]) {
|
||||
final key = t.mintAddress.toLowerCase();
|
||||
if (seen.add(key)) result.add(t);
|
||||
if (seen.add(key)) {
|
||||
result.add(t);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -139,7 +151,9 @@ class TokenUtilities {
|
||||
|
||||
for (final t in [...defaultTokens, ...userTokens]) {
|
||||
final key = t.contractAddress.toLowerCase();
|
||||
if (seen.add(key)) result.add(t);
|
||||
if (seen.add(key)) {
|
||||
result.add(t);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -153,17 +167,34 @@ class TokenUtilities {
|
||||
required WalletType walletType,
|
||||
required String address,
|
||||
}) async {
|
||||
if (address.isEmpty) return null;
|
||||
if (address.isEmpty) {
|
||||
return null;
|
||||
}
|
||||
final lower = address.toLowerCase();
|
||||
final tokens = await getAvailableTokensForNetwork(walletType);
|
||||
for (final t in tokens) {
|
||||
if (t is Erc20Token && t.contractAddress.toLowerCase() == lower) return t;
|
||||
if (t is SPLToken && t.mintAddress.toLowerCase() == lower) return t;
|
||||
if (t is TronToken && t.contractAddress.toLowerCase() == lower) return t;
|
||||
if (t is Erc20Token && t.contractAddress.toLowerCase() == lower) {
|
||||
return t;
|
||||
}
|
||||
if (t is SPLToken && t.mintAddress.toLowerCase() == lower) {
|
||||
return t;
|
||||
}
|
||||
if (t is TronToken && t.contractAddress.toLowerCase() == lower) {
|
||||
return t;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static int _getDefaultChainId(WalletType walletType) => switch (walletType) {
|
||||
WalletType.ethereum => 1,
|
||||
WalletType.polygon => 137,
|
||||
WalletType.base => 8453,
|
||||
WalletType.arbitrum => 42161,
|
||||
WalletType.bsc => 56,
|
||||
_ => 1,
|
||||
};
|
||||
|
||||
static Future<int?> findEvmChainIdForContract(
|
||||
String contractAddress, {
|
||||
int? excludingChainId,
|
||||
@@ -195,45 +226,10 @@ class TokenUtilities {
|
||||
return null;
|
||||
}
|
||||
|
||||
static Future<Box<Erc20Token>> _openEvmTokensBoxFor(WalletInfo walletInfo) async {
|
||||
final walletKey = walletInfo.name.replaceAll(' ', '_');
|
||||
final boxName = _getErc20TokensBoxName(walletKey, walletInfo.type);
|
||||
|
||||
if (CakeHive.isBoxOpen(boxName)) {
|
||||
return CakeHive.box<Erc20Token>(boxName);
|
||||
}
|
||||
return CakeHive.openBox<Erc20Token>(boxName);
|
||||
}
|
||||
|
||||
static String _getErc20TokensBoxName(String walletKey, WalletType walletType) {
|
||||
return switch (walletType) {
|
||||
WalletType.ethereum => '${walletKey}_${Erc20Token.ethereumBoxName}',
|
||||
WalletType.polygon => '${walletKey}_${Erc20Token.polygonBoxName}',
|
||||
WalletType.base => '${walletKey}_${Erc20Token.baseBoxName}',
|
||||
WalletType.arbitrum => '${walletKey}_${Erc20Token.arbitrumBoxName}',
|
||||
WalletType.bsc => '${walletKey}_${Erc20Token.bscBoxName}',
|
||||
_ => '${walletKey}_${Erc20Token.ethereumBoxName}',
|
||||
};
|
||||
}
|
||||
|
||||
static Future<Box<SPLToken>> _openSolTokensBoxFor(WalletInfo wallet) async {
|
||||
final boxName = '${wallet.name.replaceAll(' ', '_')}_${SPLToken.boxName}';
|
||||
if (CakeHive.isBoxOpen(boxName)) {
|
||||
return CakeHive.box<SPLToken>(boxName);
|
||||
}
|
||||
return CakeHive.openBox<SPLToken>(boxName);
|
||||
}
|
||||
|
||||
static Future<Box<TronToken>> _openTronTokensBoxFor(WalletInfo walletInfo) async {
|
||||
final boxName = '${walletInfo.name.replaceAll(' ', '_')}_${TronToken.boxName}';
|
||||
if (CakeHive.isBoxOpen(boxName)) {
|
||||
return CakeHive.box<TronToken>(boxName);
|
||||
}
|
||||
return CakeHive.openBox<TronToken>(boxName);
|
||||
}
|
||||
|
||||
static Erc20Token? findErc20Token(CryptoCurrency currency, WalletBase wallet) {
|
||||
if (currency is Erc20Token) return currency;
|
||||
if (currency is Erc20Token) {
|
||||
return currency;
|
||||
}
|
||||
|
||||
// More of a fallback for us
|
||||
for (final balanceCurrency in wallet.balance.keys) {
|
||||
@@ -246,10 +242,14 @@ class TokenUtilities {
|
||||
}
|
||||
|
||||
static Erc20Token? findErc20TokenForSwap(CryptoCurrency currency) {
|
||||
if (currency is Erc20Token) return currency;
|
||||
if (currency is Erc20Token) {
|
||||
return currency;
|
||||
}
|
||||
|
||||
for (final token in loadDefaultEvmTokensForSwap()) {
|
||||
if (_matchesCurrency(token, currency)) return token;
|
||||
if (_matchesCurrency(token, currency)) {
|
||||
return token;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -276,19 +276,19 @@ class TokenUtilities {
|
||||
final title = currency.title.toLowerCase();
|
||||
final tag = currency.tag?.toLowerCase();
|
||||
|
||||
return title == 'eth' ||
|
||||
title == 'ethereum' ||
|
||||
title == 'matic' ||
|
||||
title == 'polygon' ||
|
||||
title == 'base' ||
|
||||
title == 'arbitrum' ||
|
||||
title == 'bnb' ||
|
||||
title == 'bsc' ||
|
||||
title == 'avax' ||
|
||||
title == 'avalanche' ||
|
||||
tag == 'polygon' ||
|
||||
tag == 'bsc' ||
|
||||
tag == 'avalanche';
|
||||
return title == "eth" ||
|
||||
title == "ethereum" ||
|
||||
title == "matic" ||
|
||||
title == "polygon" ||
|
||||
title == "base" ||
|
||||
title == "arbitrum" ||
|
||||
title == "bnb" ||
|
||||
title == "bsc" ||
|
||||
title == "avax" ||
|
||||
title == "avalanche" ||
|
||||
tag == "polygon" ||
|
||||
tag == "bsc" ||
|
||||
tag == "avalanche";
|
||||
}
|
||||
|
||||
static int getChainId(CryptoCurrency currency) {
|
||||
@@ -298,37 +298,37 @@ class TokenUtilities {
|
||||
// Only check EVM registry for currencies that might be EVM-related
|
||||
final isPotentialEVM = isNativeToken(currency) ||
|
||||
(tag != null &&
|
||||
(tag == 'ETH' || tag == 'POL' || tag == 'BASE' || tag == 'ARB' || tag == 'BSC'));
|
||||
(tag == "ETH" || tag == "POL" || tag == "BASE" || tag == "ARB" || tag == "BSC"));
|
||||
|
||||
if (isPotentialEVM) {
|
||||
// Try by tag first if available (e.g., 'POL', 'BASE', 'ARB')
|
||||
if (tag != null) {
|
||||
final chainId = evm?.getChainIdByTag(tag);
|
||||
if (chainId != null) return chainId;
|
||||
if (chainId != null) {
|
||||
return chainId;
|
||||
}
|
||||
}
|
||||
|
||||
// Try by title (case-insensitive)
|
||||
final titleChainId = evm?.getChainIdByTitle(title);
|
||||
if (titleChainId != null) return titleChainId;
|
||||
if (titleChainId != null) {
|
||||
return titleChainId;
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback to hardcoded values for chains not in registry yet
|
||||
// Avalanche C-Chain
|
||||
if (title == 'avalanche' || title == 'avax' || tag == 'AVALANCHE') {
|
||||
if (title == "avalanche" || title == "avax" || tag == "AVALANCHE") {
|
||||
return 43114;
|
||||
}
|
||||
|
||||
// Optimism
|
||||
if (title == 'optimism' || title == 'op' || tag == 'OPTIMISM') {
|
||||
if (title == "optimism" || title == "op" || tag == "OPTIMISM") {
|
||||
return 10;
|
||||
}
|
||||
|
||||
// Fantom Opera
|
||||
if (title == 'fantom' || title == 'ftm' || tag == 'FANTOM') {
|
||||
if (title == "fantom" || title == "ftm" || tag == "FANTOM") {
|
||||
return 250;
|
||||
}
|
||||
|
||||
// Default to Ethereum mainnet
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -395,7 +395,7 @@ class TokenUtilities {
|
||||
}
|
||||
|
||||
for (final currency in CryptoCurrency.all) {
|
||||
if (currency.tag?.toLowerCase() == 'sol') {
|
||||
if (currency.tag?.toLowerCase() == "sol") {
|
||||
if (currency is SPLToken) {
|
||||
final mintAddress = currency.mintAddress.toLowerCase();
|
||||
if (addedAddresses.add(mintAddress)) {
|
||||
@@ -406,10 +406,7 @@ class TokenUtilities {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle Tron network
|
||||
else if (network == WalletType.tron) {
|
||||
} else if (network == WalletType.tron) {
|
||||
final userTronTokens = await loadAllUniqueTronTokens();
|
||||
for (final token in userTronTokens) {
|
||||
final contractAddress = token.contractAddress.toLowerCase();
|
||||
@@ -426,7 +423,7 @@ class TokenUtilities {
|
||||
}
|
||||
|
||||
for (final currency in CryptoCurrency.all) {
|
||||
if (currency.tag?.toLowerCase() == 'trx') {
|
||||
if (currency.tag?.toLowerCase() == "trx") {
|
||||
if (currency is TronToken) {
|
||||
final contractAddress = currency.contractAddress.toLowerCase();
|
||||
if (addedAddresses.add(contractAddress)) {
|
||||
@@ -442,31 +439,34 @@ class TokenUtilities {
|
||||
return allTokens;
|
||||
}
|
||||
|
||||
static bool _matchesCurrency(CryptoCurrency a, CryptoCurrency b) {
|
||||
return a.title.toUpperCase() == b.title.toUpperCase() &&
|
||||
(a.tag?.toUpperCase() == b.tag?.toUpperCase());
|
||||
}
|
||||
static bool _matchesCurrency(CryptoCurrency a, CryptoCurrency b) =>
|
||||
a.title.toUpperCase() == b.title.toUpperCase() &&
|
||||
(a.tag?.toUpperCase() == b.tag?.toUpperCase());
|
||||
|
||||
static Future<List<CryptoCurrency>> _getUserTokensForNetwork(CryptoCurrency baseCurrency) async {
|
||||
final walletType = cryptoCurrencyOrTokenToWalletType(baseCurrency);
|
||||
if (walletType == null) return [];
|
||||
if (walletType == null) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (isEVMCompatibleChain(walletType)) {
|
||||
final tokens = await TokenUtilities.loadAllUniqueEvmTokens();
|
||||
|
||||
return tokens.where((token) {
|
||||
if (baseCurrency.tag == null) return token.tag == baseCurrency.title;
|
||||
if (baseCurrency.tag == null) {
|
||||
return token.tag == baseCurrency.title;
|
||||
}
|
||||
|
||||
return token.tag?.toLowerCase() == baseCurrency.tag?.toLowerCase();
|
||||
}).toList();
|
||||
}
|
||||
|
||||
if (walletType == WalletType.solana) {
|
||||
return await loadAllUniqueSolTokens();
|
||||
return loadAllUniqueSolTokens();
|
||||
}
|
||||
|
||||
if (walletType == WalletType.tron) {
|
||||
return await loadAllUniqueTronTokens();
|
||||
return loadAllUniqueTronTokens();
|
||||
}
|
||||
|
||||
return [];
|
||||
|
||||
Reference in New Issue
Block a user