dev
dart 761 lines 22.4 KB
Raw
1 part of 'evm.dart';
2
3 class CWEVM extends EVM {
4 @override
5 List<String> getEVMWordList(String language) => EVMChainMnemonics.englishWordlist;
6
7 @override
8 WalletService createEVMWalletService(WalletType walletType, bool isDirect) {
9 return EVMChainWalletService(isDirect);
10 }
11
12 @override
13 WalletCredentials createEVMNewWalletCredentials({
14 required String name,
15 WalletInfo? walletInfo,
16 String? password,
17 String? mnemonic,
18 String? passphrase,
19 }) {
20 return EVMChainNewWalletCredentials(
21 name: name,
22 walletInfo: walletInfo,
23 password: password,
24 mnemonic: mnemonic,
25 passphrase: passphrase,
26 );
27 }
28
29 @override
30 WalletCredentials createEVMRestoreWalletFromSeedCredentials({
31 required String name,
32 required String mnemonic,
33 required String password,
34 String? passphrase,
35 }) {
36 return EVMChainRestoreWalletFromSeedCredentials(
37 name: name,
38 password: password,
39 mnemonic: mnemonic,
40 passphrase: passphrase,
41 );
42 }
43
44 @override
45 WalletCredentials createEVMRestoreWalletFromPrivateKey({
46 required String name,
47 required String privateKey,
48 required String password,
49 }) {
50 return EVMChainRestoreWalletFromPrivateKey(
51 name: name,
52 password: password,
53 privateKey: privateKey,
54 );
55 }
56
57 @override
58 WalletCredentials createEVMHardwareWalletCredentials({
59 required String name,
60 required HardwareAccountData hwAccountData,
61 WalletInfo? walletInfo,
62 }) {
63 return EVMChainRestoreWalletFromHardware(
64 name: name,
65 hwAccountData: hwAccountData,
66 walletInfo: walletInfo,
67 );
68 }
69
70 @override
71 String getAddress(WalletBase wallet) => (wallet as EVMChainWallet).walletAddresses.address;
72
73 @override
74 String getPrivateKey(WalletBase wallet) {
75 final privateKeyHolder = (wallet as EVMChainWallet).evmChainPrivateKey;
76 if (privateKeyHolder is EthPrivateKey) {
77 return bytesToHex(privateKeyHolder.privateKey);
78 }
79 return "";
80 }
81
82 @override
83 String getPublicKey(WalletBase wallet) {
84 final privateKeyInUnitInt = (wallet as EVMChainWallet).evmChainPrivateKey;
85 return privateKeyInUnitInt.address.hex;
86 }
87
88 @override
89 TransactionPriority getDefaultTransactionPriority() => EVMChainTransactionPriority.medium;
90
91 @override
92 TransactionPriority getEVMTransactionPrioritySlow() => EVMChainTransactionPriority.slow;
93
94 @override
95 List<TransactionPriority> getTransactionPriorities() => EVMChainTransactionPriority.all;
96
97 @override
98 TransactionPriority deserializeEVMTransactionPriority(int raw) =>
99 EVMChainTransactionPriority.deserialize(raw: raw);
100
101 @override
102 Object createEVMTransactionCredentials(
103 List<Output> outputs, {
104 required CryptoCurrency currency,
105 TransactionPriority? priority,
106 int? feeRate,
107 bool useBlinkProtection = true,
108 }) =>
109 EVMChainTransactionCredentials(
110 outputs
111 .map((out) => OutputInfo(
112 fiatAmount: out.fiatAmount,
113 cryptoAmount: out.cryptoAmountMoney,
114 address: out.address,
115 note: out.note,
116 sendAll: out.sendAll,
117 extractedAddress: out.extractedAddress,
118 isParsedAddress: out.isParsedAddress,
119 memo: out.memo,
120 ))
121 .toList(),
122 priority: priority as EVMChainTransactionPriority?,
123 currency: currency,
124 feeRate: feeRate,
125 useBlinkProtection: useBlinkProtection,
126 );
127
128 @override
129 Object createEVMTransactionCredentialsRaw(
130 List<OutputInfo> outputs, {
131 TransactionPriority? priority,
132 required CryptoCurrency currency,
133 required int feeRate,
134 bool useBlinkProtection = true,
135 }) {
136 return EVMChainTransactionCredentials(
137 outputs,
138 priority: priority as EVMChainTransactionPriority?,
139 currency: currency,
140 feeRate: feeRate,
141 useBlinkProtection: useBlinkProtection,
142 );
143 }
144
145 @override
146 TransactionInfo getTransactionInfo({
147 required String id,
148 required int height,
149 required Money amount,
150 required Money fee,
151 required String tokenSymbol,
152 int exponent = 18,
153 required TransactionDirection direction,
154 required bool isPending,
155 required DateTime date,
156 required int confirmations,
157 String? to,
158 String? from,
159 String? evmSignatureName,
160 String? contractAddress,
161 required int chainId,
162 }) =>
163 EVMChainTransactionInfo(
164 id: id,
165 height: height,
166 amount: amount,
167 fee: fee,
168 tokenSymbol: tokenSymbol,
169 exponent: exponent,
170 direction: direction,
171 isPending: isPending,
172 date: date,
173 confirmations: confirmations,
174 to: to,
175 from: from,
176 evmSignatureName: evmSignatureName,
177 contractAddress: contractAddress,
178 chainId: chainId);
179
180 @override
181 int formatterEVMParseAmount(String amount) => EVMChainFormatter.parseEVMChainAmount(amount);
182
183 @override
184 List<Erc20Token> getERC20Currencies(WalletBase wallet) =>
185 (wallet as EVMChainWallet).erc20Currencies;
186
187 @override
188 Future<void> addErc20Token(WalletBase wallet, CryptoCurrency token) =>
189 (wallet as EVMChainWallet).addErc20Token(token as Erc20Token);
190
191 @override
192 Future<void> deleteErc20Token(WalletBase wallet, CryptoCurrency token) =>
193 (wallet as EVMChainWallet).deleteErc20Token(token as Erc20Token);
194
195 @override
196 Future<void> removeTokenTransactionsInHistory(WalletBase wallet, CryptoCurrency token) =>
197 (wallet as EVMChainWallet).removeTokenTransactionsInHistory(token as Erc20Token);
198
199 @override
200 Future<Erc20Token?> getErc20Token(WalletBase wallet, String contractAddress) {
201 final evmWallet = wallet as EVMChainWallet;
202 final chainName = EVMChainUtils.getDefaultTokenSymbol(evmWallet.selectedChainId).toLowerCase();
203 return evmWallet.getErc20Token(contractAddress, chainName);
204 }
205
206 @override
207 CryptoCurrency assetOfTransaction(WalletBase wallet, TransactionInfo transaction) {
208 transaction as EVMChainTransactionInfo;
209 final evmWallet = wallet as EVMChainWallet;
210
211 final nativeCurrency = evmWallet.currency;
212 final nativeCurrencyTitle = nativeCurrency.title;
213 final currentChainId = evmWallet.selectedChainId;
214
215 // If transaction is from a different chain, we will return native currency as fallback
216 // This can happen during chain switching when old transactions are still visible
217 if (transaction.chainId != currentChainId) {
218 return nativeCurrency;
219 }
220
221 if (transaction.tokenSymbol == CryptoCurrency.maticpoly.title ||
222 transaction.tokenSymbol == "MATIC") {
223 return CryptoCurrency.maticpoly;
224 }
225
226 if (transaction.tokenSymbol == nativeCurrencyTitle) {
227 return nativeCurrency;
228 }
229
230 // Otherwise, it's an ERC20 token
231 // Also using firstWhereOrNull to handle cases where token isn't found (e.g., during chain switch)
232 final erc20Token = evmWallet.erc20Currencies.firstWhereOrNull(
233 (element) =>
234 transaction.contractAddress?.toLowerCase() == element.contractAddress.toLowerCase(),
235 );
236
237 return erc20Token ?? nativeCurrency;
238 }
239
240 @override
241 void updateScanProviderUsageState(WalletBase wallet, bool isEnabled) =>
242 (wallet as EVMChainWallet).updateScanProviderUsageState(isEnabled);
243
244 @override
245 Web3Client? getWeb3Client(WalletBase wallet) => (wallet as EVMChainWallet).getWeb3Client();
246
247 @override
248 Future<bool?> getTransactionReceipt(WalletBase wallet, String txHash) async {
249 final client = getWeb3Client(wallet);
250 if (client == null) return null;
251
252 try {
253 final receipt = await client.getTransactionReceipt(txHash);
254
255 if (receipt == null) return null;
256
257 return receipt.status;
258 } catch (_) {
259 return null;
260 }
261 }
262
263 @override
264 String getTokenAddress(CryptoCurrency asset) => (asset as Erc20Token).contractAddress;
265
266 @override
267 Future<bool> isApprovalRequired(
268 WalletBase wallet,
269 String tokenContract,
270 String spender,
271 BigInt requiredAmount,
272 ) =>
273 (wallet as EVMChainWallet).isApprovalRequired(tokenContract, spender, requiredAmount);
274
275 @override
276 Future<BigInt?> getAllowance(WalletBase wallet, String tokenContract, String spender) =>
277 (wallet as EVMChainWallet).getAllowance(tokenContract, spender);
278
279 @override
280 Future<PendingTransaction> createTokenApproval(
281 WalletBase wallet,
282 Money amount,
283 String spender,
284 TransactionPriority? priority, {
285 bool useBlinkProtection = true,
286 }) {
287 final evmWallet = wallet as EVMChainWallet;
288 return evmWallet.createApprovalTransaction(
289 amount,
290 spender,
291 priority as EVMChainTransactionPriority?,
292 useBlinkProtection: useBlinkProtection,
293 );
294 }
295
296 @override
297 Future<PendingTransaction> createRawCallDataTransaction(
298 WalletBase wallet,
299 String to,
300 String dataHex,
301 Money valueWei,
302 TransactionPriority? priority, {
303 bool useBlinkProtection = true,
304 String? sourceTokenAddress,
305 BigInt? sourceTokenAmount,
306 }) =>
307 (wallet as EVMChainWallet).createCallDataTransaction(
308 to,
309 dataHex,
310 valueWei,
311 priority as EVMChainTransactionPriority?,
312 sourceTokenAddress,
313 sourceTokenAmount,
314 useBlinkProtection: useBlinkProtection,
315 );
316
317 @override
318 Future<void> setHardwareWalletService(
319 WalletBase wallet,
320 HardwareWalletService service,
321 ) async {
322 final evmWallet = wallet as EVMChainWallet;
323 final privateKey = evmWallet.evmChainPrivateKey;
324 final derivationPath = (await wallet.walletInfo.getDerivationInfo()).derivationPath;
325
326 if (service is EVMChainLedgerService) {
327 (privateKey as EvmLedgerCredentials)
328 .setLedgerConnection(service.ledgerConnection, derivationPath);
329 } else if (service is EVMChainBitboxService) {
330 (privateKey as EvmBitboxCredentials).setBitbox(service.manager, derivationPath);
331 } else if (service is EVMChainTrezorService) {
332 (privateKey as EvmTrezorCredentials).setTrezorConnect(service.connect, derivationPath);
333 }
334 }
335
336 @override
337 HardwareWalletService getLedgerHardwareWalletService(ledger.LedgerConnection connection) =>
338 EVMChainLedgerService(connection);
339
340 @override
341 HardwareWalletService getBitboxHardwareWalletService(bitbox.BitboxManager manager) =>
342 EVMChainBitboxService(manager);
343
344 @override
345 HardwareWalletService getTrezorHardwareWalletService(trezor.TrezorConnect connect) =>
346 EVMChainTrezorService(connect);
347
348 @override
349 List<Erc20Token> getDefaultTokensByChainId(int chainId) =>
350 EVMChainDefaultTokens.getDefaultTokensByChainId(chainId);
351
352 @override
353 List<String> getDefaultTokenContractAddresses(WalletBase wallet) {
354 final chainId = getSelectedChainId(wallet);
355 if (chainId == null) return [];
356 return EVMChainDefaultTokens.getDefaultTokenAddresses(chainId);
357 }
358
359 @override
360 List<String> getDefaultTokenSymbols(WalletBase wallet) {
361 final chainId = getSelectedChainId(wallet);
362 if (chainId == null) return [];
363 return EVMChainDefaultTokens.getDefaultTokenSymbols(chainId);
364 }
365
366 @override
367 bool isTokenAlreadyAdded(WalletBase wallet, String contractAddress) {
368 final evmWallet = wallet as EVMChainWallet;
369 return evmWallet.erc20Currencies
370 .any((element) => element.contractAddress.toLowerCase() == contractAddress.toLowerCase());
371 }
372
373 @override
374 String? getEVMNativeEstimatedFee(WalletBase wallet) =>
375 (wallet as EVMChainWallet).nativeTxEstimatedFee;
376
377 @override
378 String? getEVMERC20EstimatedFee(WalletBase wallet) =>
379 (wallet as EVMChainWallet).erc20TxEstimatedFee;
380
381 // Chain-specific integrations (only for Ethereum)
382 @override
383 Future<Money>? getDEuroSavingsBalance(WalletBase wallet) {
384 if (wallet.chainId == 1 && wallet is EVMChainWallet) {
385 return DEuro(wallet).savingsBalance;
386 }
387 return null;
388 }
389
390 @override
391 Future<Money>? getDEuroSavingsV1Balance(WalletBase wallet) {
392 if (wallet.chainId == 1 && wallet is EVMChainWallet) {
393 return DEuro(wallet).savingsBalanceV1;
394 }
395 return null;
396 }
397
398 @override
399 Future<Money>? getDEuroAccruedInterest(WalletBase wallet) {
400 if (wallet.chainId == 1 && wallet is EVMChainWallet) {
401 return DEuro(wallet).accruedInterest;
402 }
403 return null;
404 }
405
406 @override
407 Future<BigInt>? getDEuroInterestRate(WalletBase wallet) {
408 if (wallet.chainId == 1 && wallet is EVMChainWallet) {
409 return DEuro(wallet).interestRate;
410 }
411 return null;
412 }
413
414 @override
415 Future<BigInt>? getDEuroSavingsApproved(WalletBase wallet) {
416 if (wallet.chainId == 1 && wallet is EVMChainWallet) {
417 return DEuro(wallet).approvedBalance;
418 }
419 return null;
420 }
421
422 @override
423 Future<PendingTransaction>? addDEuroSaving(
424 WalletBase wallet, BigInt amount, TransactionPriority priority) {
425 if (wallet.chainId == 1 && wallet is EVMChainWallet) {
426 return DEuro(wallet).depositSavings(amount, priority as EVMChainTransactionPriority);
427 }
428 return null;
429 }
430
431 @override
432 Future<PendingTransaction>? removeDEuroSaving(
433 WalletBase wallet, BigInt amount, TransactionPriority priority) {
434 if (wallet.chainId == 1 && wallet is EVMChainWallet) {
435 return DEuro(wallet).withdrawSavings(amount, priority as EVMChainTransactionPriority);
436 }
437 return null;
438 }
439
440 @override
441 Future<PendingTransaction>? withdrawDEuroSavingV1(
442 WalletBase wallet, TransactionPriority priority) {
443 if (wallet.chainId == 1 && wallet is EVMChainWallet) {
444 return DEuro(wallet).withdrawSavingsV1(priority as EVMChainTransactionPriority);
445 }
446 return null;
447 }
448
449 @override
450 Future<PendingTransaction>? reinvestDEuroInterest(
451 WalletBase wallet, TransactionPriority priority) {
452 if (wallet.chainId == 1 && wallet is EVMChainWallet) {
453 return DEuro(wallet).reinvestInterest(priority as EVMChainTransactionPriority);
454 }
455 return null;
456 }
457
458 @override
459 Future<PendingTransaction>? enableDEuroSaving(WalletBase wallet, TransactionPriority priority) {
460 if (wallet.chainId == 1 && wallet is EVMChainWallet) {
461 return DEuro(wallet).enableSavings(priority as EVMChainTransactionPriority);
462 }
463 return null;
464 }
465
466 // Registry helper methods
467 static final EvmChainRegistry _registry = EvmChainRegistry();
468
469 @override
470 int getChainIdByWalletType(WalletType walletType) {
471 final config = _registry.getChainConfigByWalletType(walletType);
472 return config?.chainId ?? 1; // Default to Ethereum
473 }
474
475 @override
476 String getChainNameByWalletType(WalletType walletType) {
477 final config = _registry.getChainConfigByWalletType(walletType);
478 return config?.shortCode ?? 'eth';
479 }
480
481 @override
482 String getTokenNameByWalletType(WalletType walletType) {
483 final config = _registry.getChainConfigByWalletType(walletType);
484 return config?.nativeCurrency.title ?? 'ETH';
485 }
486
487 @override
488 String getCaip2ByChainId(int chainId) {
489 final config = _registry.getChainConfig(chainId);
490 return config?.caip2 ?? 'eip155:1';
491 }
492
493 @override
494 String getChainNameByChainId(int chainId) {
495 final config = _registry.getChainConfig(chainId);
496 return config?.shortCode ?? 'eth';
497 }
498
499 @override
500 String getTokenNameByChainId(int chainId) {
501 final config = _registry.getChainConfig(chainId);
502 return config?.nativeCurrency.title ?? 'ETH';
503 }
504
505 @override
506 int? getChainIdByTag(String tag) {
507 final config = _registry.getChainConfigByTag(tag);
508 return config?.chainId;
509 }
510
511 @override
512 int? getChainIdByTitle(String title) {
513 // Try as tag first (uppercase)
514 final tagResult = getChainIdByTag(title.toUpperCase());
515 if (tagResult != null) return tagResult;
516
517 // Try as lowercase title
518 return getChainIdByTag(title.toLowerCase());
519 }
520
521 @override
522 WalletType? getWalletTypeByChainId(int chainId) {
523 return _registry.getWalletTypeByChainId(chainId);
524 }
525
526 @override
527 List<ChainInfo> getAllChains() {
528 final allChains = _registry.getAllChains();
529 return allChains
530 .map((config) => ChainInfo(
531 chainId: config.chainId,
532 name: config.name,
533 shortCode: config.shortCode,
534 currency: config.nativeCurrency,
535 ))
536 .toList();
537 }
538
539 @override
540 ChainInfo? getChainInfoByChainId(int chainId) {
541 final config = _registry.getChainConfig(chainId);
542 if (config == null) return null;
543
544 return ChainInfo(
545 chainId: config.chainId,
546 name: config.name,
547 shortCode: config.shortCode,
548 currency: config.nativeCurrency,
549 );
550 }
551
552 @override
553 ChainInfo? getCurrentChain(WalletBase wallet) {
554 if (wallet is EVMChainWallet) {
555 final config = wallet.selectedChainConfig;
556 if (config == null) return null;
557 return ChainInfo(
558 chainId: config.chainId,
559 name: config.name,
560 shortCode: config.shortCode,
561 currency: config.nativeCurrency,
562 );
563 }
564 return null;
565 }
566
567 @override
568 int? getSelectedChainId(WalletBase wallet) {
569 if (wallet is EVMChainWallet) {
570 return wallet.selectedChainId;
571 }
572 return null;
573 }
574
575 @override
576 Future<void> selectChain(WalletBase wallet, int chainId, {required Node node}) async {
577 if (wallet is EVMChainWallet) {
578 await wallet.selectChain(chainId, node: node);
579 }
580 }
581
582 @override
583 String? getExplorerUrlForChainId(int chainId, {bool showProtocol = true}) {
584 final config = _registry.getChainConfig(chainId);
585
586 if (config != null && config.explorerUrls.isNotEmpty) {
587 final url = config.explorerUrls.first;
588 return showProtocol
589 ? url
590 : url.replaceAll('https://', '').replaceAll('http://', '').split('/')[0];
591 }
592 return null;
593 }
594
595 @override
596 bool hasPriorityFee(int chainId) => EVMChainUtils.hasPriorityFee(chainId);
597
598 @override
599 bool isUSDT0Token(WalletBase wallet, CryptoCurrency token) {
600 if (token is! Erc20Token) return false;
601
602 final chainId = getSelectedChainId(wallet);
603 if (chainId == null) return false;
604
605 return USDT0Config.isUSDT0Token(token, chainId);
606 }
607
608 @override
609 List<ChainInfo> getUSDT0DestinationChains(WalletBase wallet) {
610 final currentChainId = getSelectedChainId(wallet);
611 if (currentChainId == null) return [];
612
613 final result = <ChainInfo>[];
614 for (final config in _registry.getAllChains()) {
615 if (USDT0Config.isChainSupported(config.chainId) && config.chainId != currentChainId) {
616 result.add(ChainInfo(
617 chainId: config.chainId,
618 name: config.name,
619 shortCode: config.shortCode,
620 currency: config.nativeCurrency,
621 ));
622 }
623 }
624 return result;
625 }
626
627 @override
628 Future<BridgeQuote> quoteUSDT0Transfer({
629 required WalletBase wallet,
630 required int sourceChainId,
631 required int destinationChainId,
632 required BigInt amount,
633 required String recipientAddress,
634 }) async {
635 final evmWallet = wallet as EVMChainWallet;
636 final client = evmWallet.getWeb3Client();
637 if (client == null) {
638 throw StateError('Wallet not connected');
639 }
640
641 final quote = await USDT0Service.quoteCrossChainTransfer(
642 client: client,
643 sourceChainId: sourceChainId,
644 destinationChainId: destinationChainId,
645 amount: amount,
646 recipientAddress: recipientAddress,
647 );
648 return BridgeQuote(
649 nativeFee: quote.nativeFee,
650 lzTokenFee: quote.lzTokenFee,
651 );
652 }
653
654 @override
655 Future<PendingTransaction> executeUSDT0Transfer({
656 required WalletBase wallet,
657 required CryptoCurrency token,
658 required int sourceChainId,
659 required int destinationChainId,
660 required BigInt amount,
661 required String recipientAddress,
662 required BridgeQuote quote,
663 required TransactionPriority priority,
664 bool useBlinkProtection = true,
665 }) {
666 final evmWallet = wallet as EVMChainWallet;
667 final tokenErc20 = token as Erc20Token;
668
669 return USDT0Service.executeCrossChainTransfer(
670 wallet: evmWallet,
671 sourceChainId: sourceChainId,
672 destinationChainId: destinationChainId,
673 amount: amount,
674 recipientAddress: recipientAddress,
675 quote: USDT0Quote(nativeFee: quote.nativeFee, lzTokenFee: quote.lzTokenFee),
676 token: tokenErc20,
677 priority: priority as EVMChainTransactionPriority,
678 useBlinkProtection: useBlinkProtection,
679 );
680 }
681
682 Future<EvmWalletConnectFeeQuote?> getWCBufferedFeeQuote(
683 WalletBase wallet,
684 TransactionPriority priority,
685 ) async {
686 if (wallet is! EVMChainWallet) return null;
687
688 final data = await wallet.getWCBufferedFeeQuote(priority);
689 if (data == null) return null;
690
691 return EvmWalletConnectFeeQuote(
692 maxFeePerGasWei: data.maxFeePerGasWei,
693 maxPriorityFeePerGasWei: data.maxPriorityFeePerGasWei,
694 latestBaseFeeWei: data.latestBaseFeeWei,
695 );
696 }
697
698 Future<double> _fetchFiatApiPriceForToken(Erc20Token token) async {
699 try {
700 final settingsStore = getIt.get<SettingsStore>();
701 final torOnly = settingsStore.fiatApiMode == FiatApiMode.torOnly;
702
703 return await FiatConversionService.fetchPrice(
704 crypto: token,
705 fiat: FiatCurrency.usd,
706 torOnly: torOnly,
707 );
708 } catch (_) {
709 return 0.0;
710 }
711 }
712
713 static const _minTokenUsdValue = 0.1;
714 @override
715 Future<void> discoverAndAddWalletTokens(WalletBase wallet) async {
716 if (wallet is! EVMChainWallet) return;
717
718 try {
719 final result = await wallet.discoverTokensFromMoralis();
720
721 if (result.newTokens.isEmpty) return;
722
723 final List<Future<void>> tokenChecks = [];
724
725 final whitelistedContracts =
726 wallet.getDefaultTokenContractAddresses.map((a) => a.toLowerCase()).toSet();
727
728 for (final item in result.newTokens) {
729 tokenChecks.add((() async {
730 final token = item.token;
731
732 final isPropertiesSuspicious = wallet.isTokenPropertiesSuspicious(token);
733 final isWhitelisted = whitelistedContracts.contains(token.contractAddress.toLowerCase());
734
735 final moralisPrice = item.moralisUsdPrice;
736 final moralisValue = item.moralisUsdValue ?? 0.0;
737 final hasMoralisPrice = moralisPrice != null && moralisPrice > 0;
738
739 final fiatApiPrice = await _fetchFiatApiPriceForToken(token);
740 final hasFiatApiPrice = fiatApiPrice > 0;
741
742 final isImpersonator =
743 hasFiatApiPrice && !hasMoralisPrice && !isWhitelisted && !item.verifiedContract;
744
745 final isSpam = isPropertiesSuspicious ||
746 token.isPotentialScam ||
747 isImpersonator ||
748 (!hasMoralisPrice && !hasFiatApiPrice);
749
750 token.isPotentialScam = isSpam;
751 token.enabled =
752 hasMoralisPrice && hasFiatApiPrice && (moralisValue >= _minTokenUsdValue) && !isSpam;
753
754 await wallet.addErc20Token(token);
755 })());
756 }
757
758 await Future.wait(tokenChecks);
759 } catch (_) {}
760 }
761 }