Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cw 939 whitelist known tokens #2038

Merged
merged 7 commits into from
Feb 27, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion cw_core/lib/crypto_currency.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;

Expand Down
5 changes: 5 additions & 0 deletions lib/ethereum/cw_ethereum.dart
Original file line number Diff line number Diff line change
Expand Up @@ -209,4 +209,9 @@ class CWEthereum extends Ethereum {
throw err;
}
}

@override
List<String> getDefaultTokenContractAddresses() {
return DefaultEthereumErc20Tokens().initialErc20Tokens.map((e) => e.contractAddress).toList();
}
}
5 changes: 5 additions & 0 deletions lib/polygon/cw_polygon.dart
Original file line number Diff line number Diff line change
Expand Up @@ -208,4 +208,9 @@ class CWPolygon extends Polygon {
throw err;
}
}

@override
List<String> getDefaultTokenContractAddresses() {
return DefaultPolygonErc20Tokens().initialPolygonErc20Tokens.map((e) => e.contractAddress).toList();
}
}
5 changes: 4 additions & 1 deletion lib/reactions/fiat_rate_update.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
5 changes: 5 additions & 0 deletions lib/solana/cw_solana.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
}
24 changes: 21 additions & 3 deletions lib/src/screens/dashboard/edit_token_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -219,14 +234,14 @@ class _EditTokenPageBodyState extends State<EditTokenPageBody> {
title: _tokenSymbolController.text.toUpperCase(),
decimals: int.parse(_tokenDecimalController.text),
iconPath: _tokenIconPathController.text,
isPotentialScam: isPotentialScam,
),
contractAddress: _contractAddressController.text,
);

if (mounted) {
Navigator.pop(context);
}

} catch (e) {
showPopUp<void>(
context: context,
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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();
},
Expand Down
5 changes: 5 additions & 0 deletions lib/tron/cw_tron.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
}
47 changes: 41 additions & 6 deletions lib/view_model/dashboard/home_settings_view_model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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));
}
}
Expand Down
8 changes: 8 additions & 0 deletions tool/configure.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down Expand Up @@ -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();
}
""";

Expand Down Expand Up @@ -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';

Expand Down Expand Up @@ -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();
}
""";

Expand Down Expand Up @@ -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 = """
Expand Down Expand Up @@ -1310,6 +1315,7 @@ abstract class Solana {
String getTokenAddress(CryptoCurrency asset);
List<int>? getValidationLength(CryptoCurrency type);
double? getEstimateFees(WalletBase wallet);
List<String> getDefaultTokenContractAddresses();
}

""";
Expand Down Expand Up @@ -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';";
Expand Down Expand Up @@ -1386,6 +1393,7 @@ abstract class Tron {
String? getTronTRC20EstimatedFee(WalletBase wallet);

void updateTronGridUsageState(WalletBase wallet, bool isEnabled);
List<String> getDefaultTokenContractAddresses();
}
""";

Expand Down
Loading