mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2025-06-28 12:29:51 +00:00
Cw 939 whitelist known tokens (#2038)
* [skip-ci] init * don't get price data for potential scam tokens * updates * dont fetch fiat price for scam currencies
This commit is contained in:
parent
3a56277c27
commit
57fe3287fa
9 changed files with 97 additions and 11 deletions
|
@ -11,7 +11,8 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> implemen
|
|||
this.iconPath,
|
||||
this.tag,
|
||||
this.enabled = false,
|
||||
})
|
||||
this.isPotentialScam = false,
|
||||
})
|
||||
: super(title: title, raw: raw);
|
||||
|
||||
final String name;
|
||||
|
@ -20,6 +21,7 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> implemen
|
|||
final String? iconPath;
|
||||
final int decimals;
|
||||
final bool enabled;
|
||||
final bool isPotentialScam;
|
||||
|
||||
set enabled(bool value) => this.enabled = value;
|
||||
|
||||
|
|
|
@ -209,4 +209,9 @@ class CWEthereum extends Ethereum {
|
|||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
List<String> getDefaultTokenContractAddresses() {
|
||||
return DefaultEthereumErc20Tokens().initialErc20Tokens.map((e) => e.contractAddress).toList();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -208,4 +208,9 @@ class CWPolygon extends Polygon {
|
|||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
List<String> getDefaultTokenContractAddresses() {
|
||||
return DefaultPolygonErc20Tokens().initialPolygonErc20Tokens.map((e) => e.contractAddress).toList();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -60,9 +60,12 @@ Future<void> startFiatRateUpdate(
|
|||
tron!.getTronTokenCurrencies(appStore.wallet!).where((element) => element.enabled);
|
||||
}
|
||||
|
||||
|
||||
if (currencies != null) {
|
||||
for (final currency in currencies) {
|
||||
// skip potential scams:
|
||||
if (currency.isPotentialScam) {
|
||||
continue;
|
||||
}
|
||||
() async {
|
||||
fiatConversionStore.prices[currency] = await FiatConversionService.fetchPrice(
|
||||
crypto: currency,
|
||||
|
|
|
@ -154,4 +154,9 @@ class CWSolana extends Solana {
|
|||
double? getEstimateFees(WalletBase wallet) {
|
||||
return (wallet as SolanaWallet).estimatedFee;
|
||||
}
|
||||
|
||||
@override
|
||||
List<String> getDefaultTokenContractAddresses() {
|
||||
return DefaultSPLTokens().initialSPLTokens.map((e) => e.mintAddress).toList();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -211,6 +211,21 @@ class _EditTokenPageBodyState extends State<EditTokenPageBody> {
|
|||
.checkIfERC20TokenContractAddressIsAPotentialScamAddress(
|
||||
_contractAddressController.text,
|
||||
);
|
||||
|
||||
final isWhitelisted = await widget.homeSettingsViewModel
|
||||
.checkIfTokenIsWhitelisted(_contractAddressController.text);
|
||||
|
||||
bool isPotentialScam = hasPotentialError;
|
||||
final tokenSymbol = _tokenSymbolController.text.toUpperCase();
|
||||
|
||||
// check if the token symbol is the same as any of the base currencies symbols (ETH, SOL, POL, TRX, etc):
|
||||
// if it is, then it's probably a scam unless it's in the whitelist
|
||||
final baseCurrencySymbols =
|
||||
CryptoCurrency.all.map((e) => e.title.toUpperCase()).toList();
|
||||
if (baseCurrencySymbols.contains(tokenSymbol) && !isWhitelisted) {
|
||||
isPotentialScam = true;
|
||||
}
|
||||
|
||||
final actionCall = () async {
|
||||
try {
|
||||
await widget.homeSettingsViewModel.addToken(
|
||||
|
@ -219,6 +234,7 @@ class _EditTokenPageBodyState extends State<EditTokenPageBody> {
|
|||
title: _tokenSymbolController.text.toUpperCase(),
|
||||
decimals: int.parse(_tokenDecimalController.text),
|
||||
iconPath: _tokenIconPathController.text,
|
||||
isPotentialScam: isPotentialScam,
|
||||
),
|
||||
contractAddress: _contractAddressController.text,
|
||||
);
|
||||
|
@ -226,7 +242,6 @@ class _EditTokenPageBodyState extends State<EditTokenPageBody> {
|
|||
if (mounted) {
|
||||
Navigator.pop(context);
|
||||
}
|
||||
|
||||
} catch (e) {
|
||||
showPopUp<void>(
|
||||
context: context,
|
||||
|
@ -303,7 +318,8 @@ class _EditTokenPageBodyState extends State<EditTokenPageBody> {
|
|||
if (token != null) {
|
||||
final isZano = widget.homeSettingsViewModel.walletType == WalletType.zano;
|
||||
if (_tokenNameController.text.isEmpty || isZano) _tokenNameController.text = token.name;
|
||||
if (_tokenSymbolController.text.isEmpty || isZano) _tokenSymbolController.text = token.title;
|
||||
if (_tokenSymbolController.text.isEmpty || isZano)
|
||||
_tokenSymbolController.text = token.title;
|
||||
if (_tokenIconPathController.text.isEmpty)
|
||||
_tokenIconPathController.text = token.iconPath ?? '';
|
||||
if (_tokenDecimalController.text.isEmpty || isZano)
|
||||
|
@ -338,7 +354,9 @@ class _EditTokenPageBodyState extends State<EditTokenPageBody> {
|
|||
placeholder: S.of(context).token_contract_address,
|
||||
options: [AddressTextFieldOption.paste],
|
||||
buttonColor: Theme.of(context).hintColor,
|
||||
validator: widget.homeSettingsViewModel.walletType == WalletType.zano ? null : AddressValidator(type: widget.homeSettingsViewModel.nativeToken).call,
|
||||
validator: widget.homeSettingsViewModel.walletType == WalletType.zano
|
||||
? null
|
||||
: AddressValidator(type: widget.homeSettingsViewModel.nativeToken).call,
|
||||
onPushPasteButton: (_) {
|
||||
_pasteText();
|
||||
},
|
||||
|
|
|
@ -133,4 +133,9 @@ class CWTron extends Tron {
|
|||
void updateTronGridUsageState(WalletBase wallet, bool isEnabled) {
|
||||
(wallet as TronWallet).updateScanProviderUsageState(isEnabled);
|
||||
}
|
||||
|
||||
@override
|
||||
List<String> getDefaultTokenContractAddresses() {
|
||||
return DefaultTronTokens().initialTronTokens.map((e) => e.contractAddress).toList();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -114,13 +114,12 @@ abstract class HomeSettingsViewModelBase with Store {
|
|||
if (_balanceViewModel.wallet.type == WalletType.zano) {
|
||||
await zano!.addZanoAssetById(_balanceViewModel.wallet, contractAddress);
|
||||
}
|
||||
|
||||
|
||||
_updateTokensList();
|
||||
_updateFiatPrices(token);
|
||||
} catch (e) {
|
||||
throw e;
|
||||
}
|
||||
finally {
|
||||
} finally {
|
||||
isAddingToken = false;
|
||||
}
|
||||
}
|
||||
|
@ -189,6 +188,40 @@ abstract class HomeSettingsViewModelBase with Store {
|
|||
}
|
||||
}
|
||||
|
||||
bool checkIfTokenIsWhitelisted(String contractAddress) {
|
||||
// get the default tokens for each currency type:
|
||||
List<String> defaultTokenAddresses = [];
|
||||
switch (_balanceViewModel.wallet.type) {
|
||||
case WalletType.ethereum:
|
||||
defaultTokenAddresses = ethereum!.getDefaultTokenContractAddresses();
|
||||
break;
|
||||
case WalletType.polygon:
|
||||
defaultTokenAddresses = polygon!.getDefaultTokenContractAddresses();
|
||||
break;
|
||||
case WalletType.solana:
|
||||
defaultTokenAddresses = solana!.getDefaultTokenContractAddresses();
|
||||
break;
|
||||
case WalletType.tron:
|
||||
defaultTokenAddresses = tron!.getDefaultTokenContractAddresses();
|
||||
break;
|
||||
case WalletType.zano:
|
||||
case WalletType.banano:
|
||||
case WalletType.monero:
|
||||
case WalletType.none:
|
||||
case WalletType.bitcoin:
|
||||
case WalletType.litecoin:
|
||||
case WalletType.haven:
|
||||
case WalletType.nano:
|
||||
case WalletType.wownero:
|
||||
case WalletType.bitcoinCash:
|
||||
return false;
|
||||
}
|
||||
|
||||
// check if the contractAddress is in the defaultTokenAddresses
|
||||
bool isInWhitelist = defaultTokenAddresses.any((element) => element == contractAddress);
|
||||
return isInWhitelist;
|
||||
}
|
||||
|
||||
Future<bool> _isPotentialScamTokenViaMoralis(
|
||||
String contractAddress,
|
||||
String chainName,
|
||||
|
@ -363,6 +396,7 @@ abstract class HomeSettingsViewModelBase with Store {
|
|||
CryptoCurrency get nativeToken => _balanceViewModel.wallet.currency;
|
||||
|
||||
void _updateFiatPrices(CryptoCurrency token) async {
|
||||
if (token.isPotentialScam) return; // don't fetch price data for potential scam tokens
|
||||
try {
|
||||
_balanceViewModel.fiatConvertationStore.prices[token] =
|
||||
await FiatConversionService.fetchPrice(
|
||||
|
@ -455,9 +489,10 @@ abstract class HomeSettingsViewModelBase with Store {
|
|||
}
|
||||
|
||||
if (_balanceViewModel.wallet.type == WalletType.zano) {
|
||||
tokens.addAll(zano!.getZanoAssets(_balanceViewModel.wallet)
|
||||
.where((element) => _matchesSearchText(element))
|
||||
.toList()
|
||||
tokens.addAll(zano!
|
||||
.getZanoAssets(_balanceViewModel.wallet)
|
||||
.where((element) => _matchesSearchText(element))
|
||||
.toList()
|
||||
..sort(_sortFunc));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -872,6 +872,7 @@ import 'package:cw_evm/evm_chain_wallet.dart';
|
|||
import 'package:cw_ethereum/ethereum_client.dart';
|
||||
import 'package:cw_ethereum/ethereum_wallet.dart';
|
||||
import 'package:cw_ethereum/ethereum_wallet_service.dart';
|
||||
import 'package:cw_ethereum/default_ethereum_erc20_tokens.dart';
|
||||
|
||||
import 'package:eth_sig_util/util/utils.dart';
|
||||
|
||||
|
@ -922,6 +923,7 @@ abstract class Ethereum {
|
|||
|
||||
void setLedgerConnection(WalletBase wallet, ledger.LedgerConnection connection);
|
||||
Future<List<HardwareAccountData>> getHardwareWalletAccounts(LedgerViewModel ledgerVM, {int index = 0, int limit = 5});
|
||||
List<String> getDefaultTokenContractAddresses();
|
||||
}
|
||||
""";
|
||||
|
||||
|
@ -977,6 +979,7 @@ import 'package:cw_evm/evm_chain_wallet.dart';
|
|||
import 'package:cw_polygon/polygon_client.dart';
|
||||
import 'package:cw_polygon/polygon_wallet.dart';
|
||||
import 'package:cw_polygon/polygon_wallet_service.dart';
|
||||
import 'package:cw_polygon/default_polygon_erc20_tokens.dart';
|
||||
|
||||
import 'package:eth_sig_util/util/utils.dart';
|
||||
|
||||
|
@ -1027,6 +1030,7 @@ abstract class Polygon {
|
|||
|
||||
void setLedgerConnection(WalletBase wallet, ledger.LedgerConnection connection);
|
||||
Future<List<HardwareAccountData>> getHardwareWalletAccounts(LedgerViewModel ledgerVM, {int index = 0, int limit = 5});
|
||||
List<String> getDefaultTokenContractAddresses();
|
||||
}
|
||||
""";
|
||||
|
||||
|
@ -1269,6 +1273,7 @@ import 'package:cw_solana/solana_wallet_service.dart';
|
|||
import 'package:cw_solana/solana_transaction_info.dart';
|
||||
import 'package:cw_solana/solana_transaction_credentials.dart';
|
||||
import 'package:cw_solana/solana_wallet_creation_credentials.dart';
|
||||
import 'package:cw_solana/default_spl_tokens.dart';
|
||||
""";
|
||||
const solanaCwPart = "part 'cw_solana.dart';";
|
||||
const solanaContent = """
|
||||
|
@ -1310,6 +1315,7 @@ abstract class Solana {
|
|||
String getTokenAddress(CryptoCurrency asset);
|
||||
List<int>? getValidationLength(CryptoCurrency type);
|
||||
double? getEstimateFees(WalletBase wallet);
|
||||
List<String> getDefaultTokenContractAddresses();
|
||||
}
|
||||
|
||||
""";
|
||||
|
@ -1355,6 +1361,7 @@ import 'package:cw_tron/tron_client.dart';
|
|||
import 'package:cw_tron/tron_token.dart';
|
||||
import 'package:cw_tron/tron_wallet.dart';
|
||||
import 'package:cw_tron/tron_wallet_service.dart';
|
||||
import 'package:cw_tron/default_tron_tokens.dart';
|
||||
|
||||
""";
|
||||
const tronCwPart = "part 'cw_tron.dart';";
|
||||
|
@ -1386,6 +1393,7 @@ abstract class Tron {
|
|||
String? getTronTRC20EstimatedFee(WalletBase wallet);
|
||||
|
||||
void updateTronGridUsageState(WalletBase wallet, bool isEnabled);
|
||||
List<String> getDefaultTokenContractAddresses();
|
||||
}
|
||||
""";
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue