mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2025-06-28 20:39: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,6 +11,7 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> implemen
|
||||||
this.iconPath,
|
this.iconPath,
|
||||||
this.tag,
|
this.tag,
|
||||||
this.enabled = false,
|
this.enabled = false,
|
||||||
|
this.isPotentialScam = false,
|
||||||
})
|
})
|
||||||
: super(title: title, raw: raw);
|
: super(title: title, raw: raw);
|
||||||
|
|
||||||
|
@ -20,6 +21,7 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> implemen
|
||||||
final String? iconPath;
|
final String? iconPath;
|
||||||
final int decimals;
|
final int decimals;
|
||||||
final bool enabled;
|
final bool enabled;
|
||||||
|
final bool isPotentialScam;
|
||||||
|
|
||||||
set enabled(bool value) => this.enabled = value;
|
set enabled(bool value) => this.enabled = value;
|
||||||
|
|
||||||
|
|
|
@ -209,4 +209,9 @@ class CWEthereum extends Ethereum {
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<String> getDefaultTokenContractAddresses() {
|
||||||
|
return DefaultEthereumErc20Tokens().initialErc20Tokens.map((e) => e.contractAddress).toList();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -208,4 +208,9 @@ class CWPolygon extends Polygon {
|
||||||
throw err;
|
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);
|
tron!.getTronTokenCurrencies(appStore.wallet!).where((element) => element.enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (currencies != null) {
|
if (currencies != null) {
|
||||||
for (final currency in currencies) {
|
for (final currency in currencies) {
|
||||||
|
// skip potential scams:
|
||||||
|
if (currency.isPotentialScam) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
() async {
|
() async {
|
||||||
fiatConversionStore.prices[currency] = await FiatConversionService.fetchPrice(
|
fiatConversionStore.prices[currency] = await FiatConversionService.fetchPrice(
|
||||||
crypto: currency,
|
crypto: currency,
|
||||||
|
|
|
@ -154,4 +154,9 @@ class CWSolana extends Solana {
|
||||||
double? getEstimateFees(WalletBase wallet) {
|
double? getEstimateFees(WalletBase wallet) {
|
||||||
return (wallet as SolanaWallet).estimatedFee;
|
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(
|
.checkIfERC20TokenContractAddressIsAPotentialScamAddress(
|
||||||
_contractAddressController.text,
|
_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 {
|
final actionCall = () async {
|
||||||
try {
|
try {
|
||||||
await widget.homeSettingsViewModel.addToken(
|
await widget.homeSettingsViewModel.addToken(
|
||||||
|
@ -219,6 +234,7 @@ class _EditTokenPageBodyState extends State<EditTokenPageBody> {
|
||||||
title: _tokenSymbolController.text.toUpperCase(),
|
title: _tokenSymbolController.text.toUpperCase(),
|
||||||
decimals: int.parse(_tokenDecimalController.text),
|
decimals: int.parse(_tokenDecimalController.text),
|
||||||
iconPath: _tokenIconPathController.text,
|
iconPath: _tokenIconPathController.text,
|
||||||
|
isPotentialScam: isPotentialScam,
|
||||||
),
|
),
|
||||||
contractAddress: _contractAddressController.text,
|
contractAddress: _contractAddressController.text,
|
||||||
);
|
);
|
||||||
|
@ -226,7 +242,6 @@ class _EditTokenPageBodyState extends State<EditTokenPageBody> {
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
showPopUp<void>(
|
showPopUp<void>(
|
||||||
context: context,
|
context: context,
|
||||||
|
@ -303,7 +318,8 @@ class _EditTokenPageBodyState extends State<EditTokenPageBody> {
|
||||||
if (token != null) {
|
if (token != null) {
|
||||||
final isZano = widget.homeSettingsViewModel.walletType == WalletType.zano;
|
final isZano = widget.homeSettingsViewModel.walletType == WalletType.zano;
|
||||||
if (_tokenNameController.text.isEmpty || isZano) _tokenNameController.text = token.name;
|
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)
|
if (_tokenIconPathController.text.isEmpty)
|
||||||
_tokenIconPathController.text = token.iconPath ?? '';
|
_tokenIconPathController.text = token.iconPath ?? '';
|
||||||
if (_tokenDecimalController.text.isEmpty || isZano)
|
if (_tokenDecimalController.text.isEmpty || isZano)
|
||||||
|
@ -338,7 +354,9 @@ class _EditTokenPageBodyState extends State<EditTokenPageBody> {
|
||||||
placeholder: S.of(context).token_contract_address,
|
placeholder: S.of(context).token_contract_address,
|
||||||
options: [AddressTextFieldOption.paste],
|
options: [AddressTextFieldOption.paste],
|
||||||
buttonColor: Theme.of(context).hintColor,
|
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: (_) {
|
onPushPasteButton: (_) {
|
||||||
_pasteText();
|
_pasteText();
|
||||||
},
|
},
|
||||||
|
|
|
@ -133,4 +133,9 @@ class CWTron extends Tron {
|
||||||
void updateTronGridUsageState(WalletBase wallet, bool isEnabled) {
|
void updateTronGridUsageState(WalletBase wallet, bool isEnabled) {
|
||||||
(wallet as TronWallet).updateScanProviderUsageState(isEnabled);
|
(wallet as TronWallet).updateScanProviderUsageState(isEnabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<String> getDefaultTokenContractAddresses() {
|
||||||
|
return DefaultTronTokens().initialTronTokens.map((e) => e.contractAddress).toList();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -119,8 +119,7 @@ abstract class HomeSettingsViewModelBase with Store {
|
||||||
_updateFiatPrices(token);
|
_updateFiatPrices(token);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw e;
|
throw e;
|
||||||
}
|
} finally {
|
||||||
finally {
|
|
||||||
isAddingToken = false;
|
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(
|
Future<bool> _isPotentialScamTokenViaMoralis(
|
||||||
String contractAddress,
|
String contractAddress,
|
||||||
String chainName,
|
String chainName,
|
||||||
|
@ -363,6 +396,7 @@ abstract class HomeSettingsViewModelBase with Store {
|
||||||
CryptoCurrency get nativeToken => _balanceViewModel.wallet.currency;
|
CryptoCurrency get nativeToken => _balanceViewModel.wallet.currency;
|
||||||
|
|
||||||
void _updateFiatPrices(CryptoCurrency token) async {
|
void _updateFiatPrices(CryptoCurrency token) async {
|
||||||
|
if (token.isPotentialScam) return; // don't fetch price data for potential scam tokens
|
||||||
try {
|
try {
|
||||||
_balanceViewModel.fiatConvertationStore.prices[token] =
|
_balanceViewModel.fiatConvertationStore.prices[token] =
|
||||||
await FiatConversionService.fetchPrice(
|
await FiatConversionService.fetchPrice(
|
||||||
|
@ -455,7 +489,8 @@ abstract class HomeSettingsViewModelBase with Store {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_balanceViewModel.wallet.type == WalletType.zano) {
|
if (_balanceViewModel.wallet.type == WalletType.zano) {
|
||||||
tokens.addAll(zano!.getZanoAssets(_balanceViewModel.wallet)
|
tokens.addAll(zano!
|
||||||
|
.getZanoAssets(_balanceViewModel.wallet)
|
||||||
.where((element) => _matchesSearchText(element))
|
.where((element) => _matchesSearchText(element))
|
||||||
.toList()
|
.toList()
|
||||||
..sort(_sortFunc));
|
..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_client.dart';
|
||||||
import 'package:cw_ethereum/ethereum_wallet.dart';
|
import 'package:cw_ethereum/ethereum_wallet.dart';
|
||||||
import 'package:cw_ethereum/ethereum_wallet_service.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';
|
import 'package:eth_sig_util/util/utils.dart';
|
||||||
|
|
||||||
|
@ -922,6 +923,7 @@ abstract class Ethereum {
|
||||||
|
|
||||||
void setLedgerConnection(WalletBase wallet, ledger.LedgerConnection connection);
|
void setLedgerConnection(WalletBase wallet, ledger.LedgerConnection connection);
|
||||||
Future<List<HardwareAccountData>> getHardwareWalletAccounts(LedgerViewModel ledgerVM, {int index = 0, int limit = 5});
|
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_client.dart';
|
||||||
import 'package:cw_polygon/polygon_wallet.dart';
|
import 'package:cw_polygon/polygon_wallet.dart';
|
||||||
import 'package:cw_polygon/polygon_wallet_service.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';
|
import 'package:eth_sig_util/util/utils.dart';
|
||||||
|
|
||||||
|
@ -1027,6 +1030,7 @@ abstract class Polygon {
|
||||||
|
|
||||||
void setLedgerConnection(WalletBase wallet, ledger.LedgerConnection connection);
|
void setLedgerConnection(WalletBase wallet, ledger.LedgerConnection connection);
|
||||||
Future<List<HardwareAccountData>> getHardwareWalletAccounts(LedgerViewModel ledgerVM, {int index = 0, int limit = 5});
|
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_info.dart';
|
||||||
import 'package:cw_solana/solana_transaction_credentials.dart';
|
import 'package:cw_solana/solana_transaction_credentials.dart';
|
||||||
import 'package:cw_solana/solana_wallet_creation_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 solanaCwPart = "part 'cw_solana.dart';";
|
||||||
const solanaContent = """
|
const solanaContent = """
|
||||||
|
@ -1310,6 +1315,7 @@ abstract class Solana {
|
||||||
String getTokenAddress(CryptoCurrency asset);
|
String getTokenAddress(CryptoCurrency asset);
|
||||||
List<int>? getValidationLength(CryptoCurrency type);
|
List<int>? getValidationLength(CryptoCurrency type);
|
||||||
double? getEstimateFees(WalletBase wallet);
|
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_token.dart';
|
||||||
import 'package:cw_tron/tron_wallet.dart';
|
import 'package:cw_tron/tron_wallet.dart';
|
||||||
import 'package:cw_tron/tron_wallet_service.dart';
|
import 'package:cw_tron/tron_wallet_service.dart';
|
||||||
|
import 'package:cw_tron/default_tron_tokens.dart';
|
||||||
|
|
||||||
""";
|
""";
|
||||||
const tronCwPart = "part 'cw_tron.dart';";
|
const tronCwPart = "part 'cw_tron.dart';";
|
||||||
|
@ -1386,6 +1393,7 @@ abstract class Tron {
|
||||||
String? getTronTRC20EstimatedFee(WalletBase wallet);
|
String? getTronTRC20EstimatedFee(WalletBase wallet);
|
||||||
|
|
||||||
void updateTronGridUsageState(WalletBase wallet, bool isEnabled);
|
void updateTronGridUsageState(WalletBase wallet, bool isEnabled);
|
||||||
|
List<String> getDefaultTokenContractAddresses();
|
||||||
}
|
}
|
||||||
""";
|
""";
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue