CW-1103:Token Validation Issues (#2327)

* feat(token_validation): Improve flow for adding new tokens across wallets

This change:
- Implements check to see if a token is already added, preventing duplicates
- Triggers dialog warning if its a duplicate token
- Takes EVM Chains contract adddress case-insensitivity when making checks for potential scams.

* refactor(token_validation): Modify token management flow

This change:
- Removes duplicate token check during token addition in EVMChainWalletBase.
- Introduces a flag to indicate if a token is being edited
- Adjusts token addition validation to bypass checks when editing an existing token.

* Update lib/src/screens/dashboard/edit_token_page.dart

---------

Co-authored-by: Omar Hatem <omarh.ismail1@gmail.com>
This commit is contained in:
David Adegoke 2025-06-24 03:47:21 +01:00 committed by GitHub
parent 4434ad7363
commit af89603b81
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
37 changed files with 127 additions and 5 deletions

View file

@ -198,8 +198,8 @@ abstract class EVMChainWalletBase
for (var token in erc20Currencies) { for (var token in erc20Currencies) {
bool isPotentialScam = false; bool isPotentialScam = false;
bool isWhitelisted = bool isWhitelisted = getDefaultTokenContractAddresses
getDefaultTokenContractAddresses.any((element) => element == token.contractAddress); .any((element) => element.toLowerCase() == token.contractAddress.toLowerCase());
final tokenSymbol = token.title.toUpperCase(); final tokenSymbol = token.title.toUpperCase();
@ -214,6 +214,16 @@ abstract class EVMChainWalletBase
token.iconPath = null; token.iconPath = null;
await token.save(); await token.save();
} }
// For fixing wrongly classified tokens
if (!isPotentialScam && token.isPotentialScam) {
token.isPotentialScam = false;
final iconPath = CryptoCurrency.all
.firstWhere((element) => element.title.toUpperCase() == token.symbol.toUpperCase())
.iconPath;
token.iconPath = iconPath;
await token.save();
}
} }
} }

View file

@ -199,8 +199,16 @@ class CWEthereum extends Ethereum {
} }
@override @override
List<String> getDefaultTokenContractAddresses() => List<String> getDefaultTokenContractAddresses() {
DefaultEthereumErc20Tokens().initialErc20Tokens.map((e) => e.contractAddress).toList(); return DefaultEthereumErc20Tokens().initialErc20Tokens.map((e) => e.contractAddress).toList();
}
@override
bool isTokenAlreadyAdded(WalletBase wallet, String contractAddress) {
final ethereumWallet = wallet as EthereumWallet;
return ethereumWallet.erc20Currencies.any((element) => element.contractAddress.toLowerCase() == contractAddress.toLowerCase());
}
Future<PendingTransaction> createTokenApproval(WalletBase wallet, BigInt amount, String spender, Future<PendingTransaction> createTokenApproval(WalletBase wallet, BigInt amount, String spender,
CryptoCurrency token, TransactionPriority priority) => CryptoCurrency token, TransactionPriority priority) =>

View file

@ -216,4 +216,10 @@ class CWPolygon extends Polygon {
.initialPolygonErc20Tokens .initialPolygonErc20Tokens
.map((e) => e.contractAddress) .map((e) => e.contractAddress)
.toList(); .toList();
@override
bool isTokenAlreadyAdded(WalletBase wallet, String contractAddress) {
final polygonWallet = wallet as PolygonWallet;
return polygonWallet.erc20Currencies.any((element) => element.contractAddress.toLowerCase() == contractAddress.toLowerCase());
}
} }

View file

@ -155,4 +155,10 @@ class CWSolana extends Solana {
List<String> getDefaultTokenContractAddresses() { List<String> getDefaultTokenContractAddresses() {
return DefaultSPLTokens().initialSPLTokens.map((e) => e.mintAddress).toList(); return DefaultSPLTokens().initialSPLTokens.map((e) => e.mintAddress).toList();
} }
@override
bool isTokenAlreadyAdded(WalletBase wallet, String contractAddress) {
final solanaWallet = wallet as SolanaWallet;
return solanaWallet.splTokenCurrencies.any((element) => element.mintAddress == contractAddress);
}
} }

View file

@ -73,6 +73,7 @@ class _EditTokenPageBodyState extends State<EditTokenPageBody> {
bool _showDisclaimer = false; bool _showDisclaimer = false;
bool _disclaimerChecked = false; bool _disclaimerChecked = false;
bool isEditingToken = false;
@override @override
void initState() { void initState() {
@ -88,6 +89,8 @@ class _EditTokenPageBodyState extends State<EditTokenPageBody> {
_tokenSymbolController.text = widget.token!.title; _tokenSymbolController.text = widget.token!.title;
_tokenDecimalController.text = widget.token!.decimals.toString(); _tokenDecimalController.text = widget.token!.decimals.toString();
_tokenIconPathController.text = widget.token?.iconPath ?? ''; _tokenIconPathController.text = widget.token?.iconPath ?? '';
isEditingToken = true;
} }
if (widget.initialContractAddress != null) { if (widget.initialContractAddress != null) {
@ -200,6 +203,25 @@ class _EditTokenPageBodyState extends State<EditTokenPageBody> {
onPressed: () async { onPressed: () async {
if (_formKey.currentState!.validate() && if (_formKey.currentState!.validate() &&
(!_showDisclaimer || _disclaimerChecked)) { (!_showDisclaimer || _disclaimerChecked)) {
final isTokenAlreadyAdded = isEditingToken
? false
: await widget.homeSettingsViewModel
.checkIfTokenIsAlreadyAdded(_contractAddressController.text);
if (isTokenAlreadyAdded) {
showPopUp<void>(
context: context,
builder: (dialogContext) {
return AlertWithOneAction(
alertTitle: S.current.warning,
alertContent: S.of(context).token_already_exists,
buttonText: S.of(context).ok,
buttonAction: () => Navigator.of(dialogContext).pop(),
);
},
);
return;
}
final isWhitelisted = await widget.homeSettingsViewModel final isWhitelisted = await widget.homeSettingsViewModel
.checkIfTokenIsWhitelisted(_contractAddressController.text); .checkIfTokenIsWhitelisted(_contractAddressController.text);

View file

@ -138,4 +138,10 @@ class CWTron extends Tron {
List<String> getDefaultTokenContractAddresses() { List<String> getDefaultTokenContractAddresses() {
return DefaultTronTokens().initialTronTokens.map((e) => e.contractAddress).toList(); return DefaultTronTokens().initialTronTokens.map((e) => e.contractAddress).toList();
} }
@override
bool isTokenAlreadyAdded(WalletBase wallet, String contractAddress) {
final tronWallet = wallet as TronWallet;
return tronWallet.tronTokenCurrencies.any((element) => element.contractAddress == contractAddress);
}
} }

View file

@ -126,6 +126,31 @@ abstract class HomeSettingsViewModelBase with Store {
} }
} }
@action
bool checkIfTokenIsAlreadyAdded(String contractAddress) {
if (_balanceViewModel.wallet.type == WalletType.ethereum) {
return ethereum!.isTokenAlreadyAdded(_balanceViewModel.wallet, contractAddress);
}
if (_balanceViewModel.wallet.type == WalletType.polygon) {
return polygon!.isTokenAlreadyAdded(_balanceViewModel.wallet, contractAddress);
}
if (_balanceViewModel.wallet.type == WalletType.solana) {
return solana!.isTokenAlreadyAdded(_balanceViewModel.wallet, contractAddress);
}
if (_balanceViewModel.wallet.type == WalletType.tron) {
return tron!.isTokenAlreadyAdded(_balanceViewModel.wallet, contractAddress);
}
if (_balanceViewModel.wallet.type == WalletType.zano) {
return zano!.isTokenAlreadyAdded(_balanceViewModel.wallet, contractAddress);
}
return false;
}
@action @action
Future<void> deleteToken(CryptoCurrency token) async { Future<void> deleteToken(CryptoCurrency token) async {
try { try {

View file

@ -136,4 +136,10 @@ class CWZano extends Zano {
Map<String, List<int>> debugCallLength() { Map<String, List<int>> debugCallLength() {
return api.debugCallLength(); return api.debugCallLength();
} }
@override
bool isTokenAlreadyAdded(WalletBase wallet, String contractAddress) {
final zanoWallet = wallet as ZanoWallet;
return zanoWallet.zanoAssets.values.any((element) => element?.assetId == contractAddress);
}
} }

View file

@ -913,6 +913,7 @@
"tip": "بقشيش:", "tip": "بقشيش:",
"to": "ل", "to": "ل",
"today": "اليوم", "today": "اليوم",
"token_already_exists": "رمز موجود بالفعل",
"token_contract_address": "عنوان عقد الرمز", "token_contract_address": "عنوان عقد الرمز",
"token_decimal": "رمز عشري", "token_decimal": "رمز عشري",
"token_name": "اسم الرمز ، على سبيل المثال: Tether", "token_name": "اسم الرمز ، على سبيل المثال: Tether",

View file

@ -913,6 +913,7 @@
"tip": "Tip:", "tip": "Tip:",
"to": "Да", "to": "Да",
"today": "Днес", "today": "Днес",
"token_already_exists": "Токена вече съществува",
"token_contract_address": "Адрес на токен договор", "token_contract_address": "Адрес на токен договор",
"token_decimal": "Токен десетичен", "token_decimal": "Токен десетичен",
"token_name": "Име на токена, напр.: Tether", "token_name": "Име на токена, напр.: Tether",

View file

@ -913,6 +913,7 @@
"tip": "Spropitné:", "tip": "Spropitné:",
"to": "Na", "to": "Na",
"today": "Dnes", "today": "Dnes",
"token_already_exists": "Token již existuje",
"token_contract_address": "Adresa tokenové smlouvy", "token_contract_address": "Adresa tokenové smlouvy",
"token_decimal": "Token v desítkové soustavě", "token_decimal": "Token v desítkové soustavě",
"token_name": "Název tokenu např.: Tether", "token_name": "Název tokenu např.: Tether",

View file

@ -914,6 +914,7 @@
"tip": "Hinweis:", "tip": "Hinweis:",
"to": "Zu", "to": "Zu",
"today": "Heute", "today": "Heute",
"token_already_exists": "Token existiert bereits",
"token_contract_address": "Token-Contract-Adresse", "token_contract_address": "Token-Contract-Adresse",
"token_decimal": "Token-Dezimalzahl", "token_decimal": "Token-Dezimalzahl",
"token_name": "Token-Name, z. B.: Tether", "token_name": "Token-Name, z. B.: Tether",

View file

@ -914,6 +914,7 @@
"tip": "Tip:", "tip": "Tip:",
"to": "To", "to": "To",
"today": "Today", "today": "Today",
"token_already_exists": "Token already exists",
"token_contract_address": "Token contract address", "token_contract_address": "Token contract address",
"token_decimal": "Token decimal", "token_decimal": "Token decimal",
"token_name": "Token name eg: Tether", "token_name": "Token name eg: Tether",

View file

@ -914,6 +914,7 @@
"tip": "Consejo:", "tip": "Consejo:",
"to": "A", "to": "A",
"today": "Hoy", "today": "Hoy",
"token_already_exists": "Token ya existe",
"token_contract_address": "Dirección de contrato de token", "token_contract_address": "Dirección de contrato de token",
"token_decimal": "Token decimal", "token_decimal": "Token decimal",
"token_name": "Nombre del token, por ejemplo: Tether", "token_name": "Nombre del token, por ejemplo: Tether",

View file

@ -913,6 +913,7 @@
"tip": "Pourboire:", "tip": "Pourboire:",
"to": "À", "to": "À",
"today": "Aujourd'hui", "today": "Aujourd'hui",
"token_already_exists": "Le jeton existe déjà",
"token_contract_address": "Adresse du contrat de token", "token_contract_address": "Adresse du contrat de token",
"token_decimal": "Décimales de token", "token_decimal": "Décimales de token",
"token_name": "Nom du token, par exemple : Tether", "token_name": "Nom du token, par exemple : Tether",

View file

@ -915,6 +915,7 @@
"tip": "Tukwici:", "tip": "Tukwici:",
"to": "Zuwa", "to": "Zuwa",
"today": "Yau", "today": "Yau",
"token_already_exists": "Alama an riga an wanzu",
"token_contract_address": "Adireshin kwangilar Token", "token_contract_address": "Adireshin kwangilar Token",
"token_decimal": "Alamar ƙima", "token_decimal": "Alamar ƙima",
"token_name": "Alamar sunan misali: Tether", "token_name": "Alamar sunan misali: Tether",

View file

@ -915,6 +915,7 @@
"tip": "टिप:", "tip": "टिप:",
"to": "को", "to": "को",
"today": "आज", "today": "आज",
"token_already_exists": "टोकन पहले से मौजूद है",
"token_contract_address": "टोकन अनुबंध पता", "token_contract_address": "टोकन अनुबंध पता",
"token_decimal": "सांकेतिक दशमलव", "token_decimal": "सांकेतिक दशमलव",
"token_name": "टोकन नाम जैसे: टीथर", "token_name": "टोकन नाम जैसे: टीथर",

View file

@ -913,6 +913,7 @@
"tip": "Savjet:", "tip": "Savjet:",
"to": "Do", "to": "Do",
"today": "Danas", "today": "Danas",
"token_already_exists": "Token već postoji",
"token_contract_address": "Adresa ugovora tokena", "token_contract_address": "Adresa ugovora tokena",
"token_decimal": "Token decimalni", "token_decimal": "Token decimalni",
"token_name": "Naziv tokena npr.: Tether", "token_name": "Naziv tokena npr.: Tether",

View file

@ -911,6 +911,7 @@
"tip": "Թեյավճար", "tip": "Թեյավճար",
"to": "Դեպի", "to": "Դեպի",
"today": "Այսօր", "today": "Այսօր",
"token_already_exists": "Նշանն արդեն գոյություն ունի",
"token_contract_address": "Token-ի պայմանագրի հասցե", "token_contract_address": "Token-ի պայմանագրի հասցե",
"token_decimal": "Token-ի տասանիշ", "token_decimal": "Token-ի տասանիշ",
"token_name": "Token-ի անուն, օրինակ՝ Tether", "token_name": "Token-ի անուն, օրինակ՝ Tether",

View file

@ -916,6 +916,7 @@
"tip": "Tip:", "tip": "Tip:",
"to": "Ke", "to": "Ke",
"today": "Hari ini", "today": "Hari ini",
"token_already_exists": "Token sudah ada",
"token_contract_address": "Alamat kontrak token", "token_contract_address": "Alamat kontrak token",
"token_decimal": "Desimal token", "token_decimal": "Desimal token",
"token_name": "Nama token misalnya: Tether", "token_name": "Nama token misalnya: Tether",

View file

@ -914,6 +914,7 @@
"tip": "Suggerimento:", "tip": "Suggerimento:",
"to": "A", "to": "A",
"today": "Oggi", "today": "Oggi",
"token_already_exists": "Il token esiste già",
"token_contract_address": "Indirizzo del contratto token", "token_contract_address": "Indirizzo del contratto token",
"token_decimal": "Decimale del token", "token_decimal": "Decimale del token",
"token_name": "Nome del token, ad esempio: Tether", "token_name": "Nome del token, ad esempio: Tether",

View file

@ -914,6 +914,7 @@
"tip": "ヒント: ", "tip": "ヒント: ",
"to": "に", "to": "に",
"today": "今日", "today": "今日",
"token_already_exists": "トークンはすでに存在します",
"token_contract_address": "トークンコントラクトアドレス", "token_contract_address": "トークンコントラクトアドレス",
"token_decimal": "トークン10進数", "token_decimal": "トークン10進数",
"token_name": "トークン名 例: Tether", "token_name": "トークン名 例: Tether",

View file

@ -914,6 +914,7 @@
"tip": "팁:", "tip": "팁:",
"to": "받는 통화", "to": "받는 통화",
"today": "오늘", "today": "오늘",
"token_already_exists": "토큰이 이미 존재합니다",
"token_contract_address": "토큰 계약 주소", "token_contract_address": "토큰 계약 주소",
"token_decimal": "토큰 소수 자릿수", "token_decimal": "토큰 소수 자릿수",
"token_name": "토큰 이름 (예: Tether)", "token_name": "토큰 이름 (예: Tether)",

View file

@ -913,6 +913,7 @@
"tip": "အကြံပြုချက်-", "tip": "အကြံပြုချက်-",
"to": "သို့", "to": "သို့",
"today": "ဒီနေ့", "today": "ဒီနေ့",
"token_already_exists": "တိုကင်ရှိပြီးသား",
"token_contract_address": "တိုကင်စာချုပ်လိပ်စာ", "token_contract_address": "တိုကင်စာချုပ်လိပ်စာ",
"token_decimal": "တိုကင်ဒဿမ", "token_decimal": "တိုကင်ဒဿမ",
"token_name": "တိုကင်အမည် ဥပမာ- Tether", "token_name": "တိုကင်အမည် ဥပမာ- Tether",

View file

@ -913,6 +913,7 @@
"tip": "Tip:", "tip": "Tip:",
"to": "Naar", "to": "Naar",
"today": "Vandaag", "today": "Vandaag",
"token_already_exists": "Token bestaat al",
"token_contract_address": "Token contractadres", "token_contract_address": "Token contractadres",
"token_decimal": "Token decimaal", "token_decimal": "Token decimaal",
"token_name": "Tokennaam bijv.: Tether", "token_name": "Tokennaam bijv.: Tether",

View file

@ -913,6 +913,7 @@
"tip": "tip:", "tip": "tip:",
"to": "Do", "to": "Do",
"today": "Dzisiaj", "today": "Dzisiaj",
"token_already_exists": "Token już istnieje",
"token_contract_address": "Adres kontraktu tokena", "token_contract_address": "Adres kontraktu tokena",
"token_decimal": "Token dziesiętny", "token_decimal": "Token dziesiętny",
"token_name": "Nazwa tokena, np.: Tether", "token_name": "Nazwa tokena, np.: Tether",

View file

@ -915,6 +915,7 @@
"tip": "Dica:", "tip": "Dica:",
"to": "Para", "to": "Para",
"today": "Hoje", "today": "Hoje",
"token_already_exists": "Token já existe",
"token_contract_address": "Endereço do contrato de token", "token_contract_address": "Endereço do contrato de token",
"token_decimal": "Token decimal", "token_decimal": "Token decimal",
"token_name": "Nome do token, por exemplo: Tether", "token_name": "Nome do token, por exemplo: Tether",

View file

@ -914,6 +914,7 @@
"tip": "Совет:", "tip": "Совет:",
"to": "К", "to": "К",
"today": "Сегодня", "today": "Сегодня",
"token_already_exists": "Токен уже существует",
"token_contract_address": "Адрес контракта токена", "token_contract_address": "Адрес контракта токена",
"token_decimal": "Десятичный токен", "token_decimal": "Десятичный токен",
"token_name": "Имя токена, например: Tether", "token_name": "Имя токена, например: Tether",

View file

@ -913,6 +913,7 @@
"tip": "เพิ่มค่าตอบแทน:", "tip": "เพิ่มค่าตอบแทน:",
"to": "ถึง", "to": "ถึง",
"today": "วันนี้", "today": "วันนี้",
"token_already_exists": "โทเค็นมีอยู่แล้ว",
"token_contract_address": "ที่อยู่สัญญาโทเค็น", "token_contract_address": "ที่อยู่สัญญาโทเค็น",
"token_decimal": "โทเค็นทศนิยม", "token_decimal": "โทเค็นทศนิยม",
"token_name": "ชื่อโทเค็น เช่น Tether", "token_name": "ชื่อโทเค็น เช่น Tether",

View file

@ -913,6 +913,7 @@
"tip": "Tip:", "tip": "Tip:",
"to": "Sa", "to": "Sa",
"today": "Ngayon", "today": "Ngayon",
"token_already_exists": "Mayroon nang token",
"token_contract_address": "Address ng token contract", "token_contract_address": "Address ng token contract",
"token_decimal": "Token decimal", "token_decimal": "Token decimal",
"token_name": "Pangalan ng token, halimbawa: Tether", "token_name": "Pangalan ng token, halimbawa: Tether",

View file

@ -913,6 +913,7 @@
"tip": "Bahşiş:", "tip": "Bahşiş:",
"to": "İle", "to": "İle",
"today": "Bugün", "today": "Bugün",
"token_already_exists": "Token zaten var",
"token_contract_address": "Token sözleşme adresi", "token_contract_address": "Token sözleşme adresi",
"token_decimal": "Belirteç ondalık", "token_decimal": "Belirteç ondalık",
"token_name": "Belirteç adı, örneğin: Tether", "token_name": "Belirteç adı, örneğin: Tether",

View file

@ -914,6 +914,7 @@
"tip": "Порада:", "tip": "Порада:",
"to": "До", "to": "До",
"today": "Сьогодні", "today": "Сьогодні",
"token_already_exists": "Маркер вже існує",
"token_contract_address": "Адреса договору маркера", "token_contract_address": "Адреса договору маркера",
"token_decimal": "Токен десятковий", "token_decimal": "Токен десятковий",
"token_name": "Назва токена, наприклад: Tether", "token_name": "Назва токена, наприклад: Tether",

View file

@ -915,6 +915,7 @@
"tip": "ٹپ:", "tip": "ٹپ:",
"to": "to", "to": "to",
"today": "آج", "today": "آج",
"token_already_exists": "ٹوکن پہلے ہی موجود ہے",
"token_contract_address": "ٹوکن کنٹریکٹ ایڈریس", "token_contract_address": "ٹوکن کنٹریکٹ ایڈریس",
"token_decimal": "ٹوکن اعشاریہ", "token_decimal": "ٹوکن اعشاریہ",
"token_name": "ٹوکن کا نام جیسے: Tether", "token_name": "ٹوکن کا نام جیسے: Tether",

View file

@ -910,6 +910,7 @@
"tip": "Mẹo:", "tip": "Mẹo:",
"to": "ĐẾN", "to": "ĐẾN",
"today": "Hôm nay", "today": "Hôm nay",
"token_already_exists": "Mã thông báo đã tồn tại",
"token_contract_address": "Địa chỉ hợp đồng token", "token_contract_address": "Địa chỉ hợp đồng token",
"token_decimal": "Số thập phân của token", "token_decimal": "Số thập phân của token",
"token_name": "Tên token ví dụ: Tether", "token_name": "Tên token ví dụ: Tether",

View file

@ -914,6 +914,7 @@
"tip": "Owó àfikún:", "tip": "Owó àfikún:",
"to": "Si", "to": "Si",
"today": "Lénìí", "today": "Lénìí",
"token_already_exists": "Token tẹlẹ wa",
"token_contract_address": "Àmi guide adirẹsi", "token_contract_address": "Àmi guide adirẹsi",
"token_decimal": "Àmi eleemewa", "token_decimal": "Àmi eleemewa",
"token_name": "Orukọ àmi fun apẹẹrẹ: Tether", "token_name": "Orukọ àmi fun apẹẹrẹ: Tether",

View file

@ -913,6 +913,7 @@
"tip": "提示:", "tip": "提示:",
"to": "到", "to": "到",
"today": "今天", "today": "今天",
"token_already_exists": "令牌已经存在",
"token_contract_address": "代币合约地址", "token_contract_address": "代币合约地址",
"token_decimal": "令牌十进制", "token_decimal": "令牌十进制",
"token_name": "代币名称例如Tether", "token_name": "代币名称例如Tether",

View file

@ -760,6 +760,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(); List<String> getDefaultTokenContractAddresses();
bool isTokenAlreadyAdded(WalletBase wallet, String contractAddress);
} }
"""; """;
@ -870,6 +871,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(); List<String> getDefaultTokenContractAddresses();
bool isTokenAlreadyAdded(WalletBase wallet, String contractAddress);
} }
"""; """;
@ -1156,6 +1158,7 @@ abstract class Solana {
List<int>? getValidationLength(CryptoCurrency type); List<int>? getValidationLength(CryptoCurrency type);
double? getEstimateFees(WalletBase wallet); double? getEstimateFees(WalletBase wallet);
List<String> getDefaultTokenContractAddresses(); List<String> getDefaultTokenContractAddresses();
bool isTokenAlreadyAdded(WalletBase wallet, String contractAddress);
} }
"""; """;
@ -1234,6 +1237,7 @@ abstract class Tron {
void updateTronGridUsageState(WalletBase wallet, bool isEnabled); void updateTronGridUsageState(WalletBase wallet, bool isEnabled);
List<String> getDefaultTokenContractAddresses(); List<String> getDefaultTokenContractAddresses();
bool isTokenAlreadyAdded(WalletBase wallet, String contractAddress);
} }
"""; """;
@ -1308,6 +1312,7 @@ abstract class Zano {
String getAddress(WalletBase wallet); String getAddress(WalletBase wallet);
bool validateAddress(String address); bool validateAddress(String address);
Map<String, List<int>> debugCallLength(); Map<String, List<int>> debugCallLength();
bool isTokenAlreadyAdded(WalletBase wallet, String contractAddress);
} }
"""; """;
const zanoEmptyDefinition = 'Zano? zano;\n'; const zanoEmptyDefinition = 'Zano? zano;\n';