Add "Enable/Disable" feature for ERC20 tokens

This commit is contained in:
OmarHatem 2023-06-23 20:21:28 +03:00
parent e715162294
commit 342174325b
32 changed files with 186 additions and 63 deletions

View file

@ -1,11 +1,10 @@
import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/keyable.dart';
import 'package:hive/hive.dart';
part 'erc20_token.g.dart';
@HiveType(typeId: Erc20Token.typeId)
class Erc20Token extends CryptoCurrency with Keyable, HiveObjectMixin {
class Erc20Token extends CryptoCurrency with HiveObjectMixin {
@HiveField(0)
final String name;
@HiveField(1)
@ -16,6 +15,8 @@ class Erc20Token extends CryptoCurrency with Keyable, HiveObjectMixin {
final int decimal;
@HiveField(4, defaultValue: false)
bool _enabled;
@HiveField(5)
final String? iconPath;
bool get enabled => _enabled;
@ -30,7 +31,7 @@ class Erc20Token extends CryptoCurrency with Keyable, HiveObjectMixin {
required this.contractAddress,
required this.decimal,
bool enabled = false,
String? iconPath,
this.iconPath,
}) : _enabled = enabled,
super(
name: symbol.toLowerCase(),
@ -48,12 +49,4 @@ class Erc20Token extends CryptoCurrency with Keyable, HiveObjectMixin {
@override
int get hashCode => contractAddress.hashCode;
@override
dynamic get keyIndex {
_keyIndex ??= key;
return _keyIndex;
}
dynamic _keyIndex;
}

View file

@ -255,25 +255,32 @@ abstract class EthereumWalletBase
}
Future<void> _updateBalance() async {
balance[currency] = await _fetchBalances();
balance[currency] = await _fetchEthBalance();
/// Get Erc20 Tokens balances
for (var token in erc20TokensBox.values) {
try {
balance[token] = await _client.fetchERC20Balances(
_privateKey.address,
token.contractAddress,
);
} catch (_) {}
}
await _fetchErc20Balances();
await save();
}
Future<ERC20Balance> _fetchBalances() async {
Future<ERC20Balance> _fetchEthBalance() async {
final balance = await _client.getBalance(_privateKey.address);
return ERC20Balance(balance.getInWei);
}
Future<void> _fetchErc20Balances() async {
for (var token in erc20TokensBox.values) {
try {
if (token.enabled) {
balance[token] = await _client.fetchERC20Balances(
_privateKey.address,
token.contractAddress,
);
} else {
balance.remove(token);
}
} catch (_) {}
}
}
Future<EthPrivateKey> getPrivateKey(String mnemonic, String password) async {
final seed = bip39.mnemonicToSeed(mnemonic);

View file

@ -5,21 +5,20 @@ import 'package:flutter/foundation.dart';
import 'package:http/http.dart';
import 'package:cake_wallet/.secrets.g.dart' as secrets;
const _fiatApiClearNetAuthority = 'fiat-api.cakewallet.com';
const _fiatApiOnionAuthority = 'n4z7bdcmwk2oyddxvzaap3x2peqcplh3pzdy7tpkk5ejz5n4mhfvoxqd.onion';
const _fiatApiPath = '/v2/rates';
Future<double> _fetchPrice(Map<String, dynamic> args) async {
final crypto = args['crypto'] as CryptoCurrency;
final fiat = args['fiat'] as FiatCurrency;
final crypto = args['crypto'] as String;
final fiat = args['fiat'] as String;
final torOnly = args['torOnly'] as bool;
final Map<String, String> queryParams = {
'interval_count': '1',
'base': crypto.toString(),
'quote': fiat.toString(),
'key' : secrets.fiatApiKey,
'base': crypto,
'quote': fiat,
'key': secrets.fiatApiKey,
};
double price = 0.0;
@ -52,7 +51,11 @@ Future<double> _fetchPrice(Map<String, dynamic> args) async {
}
Future<double> _fetchPriceAsync(CryptoCurrency crypto, FiatCurrency fiat, bool torOnly) async =>
compute(_fetchPrice, {'fiat': fiat, 'crypto': crypto, 'torOnly': torOnly});
compute(_fetchPrice, {
'fiat': fiat.toString(),
'crypto': crypto.toString(),
'torOnly': torOnly,
});
class FiatConversionService {
static Future<double> fetchPrice({

View file

@ -1,17 +1,19 @@
import 'package:cake_wallet/generated/i18n.dart';
enum SortBalanceBy {
FiatBalance,
Gross,
GrossBalance,
Alphabetical;
@override
String toString() {
switch (this) {
case SortBalanceBy.FiatBalance:
return "S.current.fiat_balance";
case SortBalanceBy.Gross:
return "S.current.gross";
return S.current.fiat_balance;
case SortBalanceBy.GrossBalance:
return S.current.gross_balance;
case SortBalanceBy.Alphabetical:
return "S.current.alphabetical";
return S.current.alphabetical;
}
}
}

View file

@ -235,7 +235,7 @@ class _EditTokenPageBodyState extends State<EditTokenPageBody> {
return null;
}
return 'S.of(context).field_required';
return S.of(context).field_required;
},
onPushPasteButton: (_) {
_pasteText();
@ -282,8 +282,7 @@ class _EditTokenPageBodyState extends State<EditTokenPageBody> {
return S.of(context).field_required;
}
if (int.tryParse(text!) == null) {
// TODO: add localization
return 'S.of(context).invalid_input';
return S.of(context).invalid_input;
}
return null;

View file

@ -106,7 +106,7 @@ class HomeSettingsPage extends BasePage {
"(${token.symbol})",
value: token.enabled,
onValueChange: (_, bool value) {
token.enabled = value;
_homeSettingsViewModel.changeTokenAvailability(index, value);
},
onTap: (_) {
Navigator.pushNamed(context, Routes.editToken, arguments: {

View file

@ -1,3 +1,5 @@
import 'package:cake_wallet/core/fiat_conversion_service.dart';
import 'package:cake_wallet/entities/fiat_api_mode.dart';
import 'package:cake_wallet/entities/sort_balance_types.dart';
import 'package:cake_wallet/ethereum/ethereum.dart';
import 'package:cake_wallet/store/settings_store.dart';
@ -41,6 +43,7 @@ abstract class HomeSettingsViewModelBase with Store {
Future<void> addErc20Token(Erc20Token token) async {
await ethereum!.addErc20Token(_balanceViewModel.wallet, token);
_updateTokensList();
_updateFiatPrices(token);
}
Future<void> deleteErc20Token(Erc20Token token) async {
@ -52,4 +55,20 @@ abstract class HomeSettingsViewModelBase with Store {
await ethereum!.getErc20Token(_balanceViewModel.wallet, contractAddress);
String get nativeToken => _balanceViewModel.wallet.currency.title;
void _updateFiatPrices(Erc20Token token) async {
try {
_balanceViewModel.fiatConvertationStore.prices[token] =
await FiatConversionService.fetchPrice(
crypto: token,
fiat: _settingsStore.fiatCurrency,
torOnly: _settingsStore.fiatApiMode == FiatApiMode.torOnly);
} catch (_) {}
}
void changeTokenAvailability(int index, bool value) async {
tokens[index].enabled = value;
_balanceViewModel.wallet.updateBalance();
_updateTokensList();
}
}

View file

@ -738,5 +738,9 @@
"token_symbol": "رمز العملة ، على سبيل المثال: USDT",
"token_decimal": "رمز عشري",
"field_required": "هذه الخانة مطلوبه",
"pin_at_top": "تثبيت ${token} في الأعلى"
"pin_at_top": "تثبيت ${token} في الأعلى",
"invalid_input": "مدخل غير صالح",
"fiat_balance": "الرصيد فيات",
"gross_balance": "إجمالي الرصيد",
"alphabetical": "مرتب حسب الحروف الأبجدية"
}

View file

@ -734,5 +734,9 @@
"token_symbol": "Символ на токена, напр.: USDT",
"token_decimal": "Токен десетичен",
"field_required": "Това поле е задължително",
"pin_at_top": "закачете ${token} отгоре"
"pin_at_top": "закачете ${token} отгоре",
"invalid_input": "Невалиден вход",
"fiat_balance": "Фиат Баланс",
"gross_balance": "Брутен баланс",
"alphabetical": "Азбучен ред"
}

View file

@ -734,5 +734,9 @@
"token_symbol": "Symbol tokenu, např.: USDT",
"token_decimal": "Token v desítkové soustavě",
"field_required": "Toto pole je povinné",
"pin_at_top": "špendlík ${token} nahoře"
"pin_at_top": "špendlík ${token} nahoře",
"invalid_input": "Neplatný vstup",
"fiat_balance": "Fiat Balance",
"gross_balance": "Hrubý zůstatek",
"alphabetical": "Abecední"
}

View file

@ -740,5 +740,9 @@
"token_symbol": "Token-Symbol, z. B.: USDT",
"token_decimal": "Token-Dezimalzahl",
"field_required": "Dieses Feld ist erforderlich",
"pin_at_top": "Stecken Sie ${token} oben fest"
"pin_at_top": "Stecken Sie ${token} oben fest",
"invalid_input": "Ungültige Eingabe",
"fiat_balance": "Fiat Balance",
"gross_balance": "Bruttosaldo",
"alphabetical": "Alphabetisch"
}

View file

@ -740,5 +740,9 @@
"token_symbol": "Token symbol eg: USDT",
"token_decimal": "Token decimal",
"field_required": "This field is required",
"pin_at_top": "Pin ${token} at top"
"pin_at_top": "Pin ${token} at top",
"invalid_input": "Invalid input",
"fiat_balance": "Fiat Balance",
"gross_balance": "Gross Balance",
"alphabetical": "Alphabetical"
}

View file

@ -740,5 +740,9 @@
"token_symbol": "Símbolo de token, por ejemplo: USDT",
"token_decimal": "Token decimal",
"field_required": "Este campo es obligatorio",
"pin_at_top": "pin ${token} en la parte superior"
"pin_at_top": "pin ${token} en la parte superior",
"invalid_input": "Entrada inválida",
"fiat_balance": "Equilibrio Fiat",
"gross_balance": "Saldo bruto",
"alphabetical": "Alfabético"
}

View file

@ -740,5 +740,9 @@
"token_symbol": "Symbole de jeton, par exemple : USDT",
"token_decimal": "Décimal de jeton",
"field_required": "Ce champ est obligatoire",
"pin_at_top": "épingler ${token} en haut"
"pin_at_top": "épingler ${token} en haut",
"invalid_input": "Entrée invalide",
"fiat_balance": "Fiat Balance",
"gross_balance": "Solde brut",
"alphabetical": "Alphabétique"
}

View file

@ -723,5 +723,9 @@
"token_symbol": "Alamar alama misali: USDT",
"token_decimal": "Alamar ƙima",
"field_required": "wannan fillin ana bukatansa",
"pin_at_top": "pin ${token} a sama"
"pin_at_top": "pin ${token} a sama",
"invalid_input": "Shigar da ba daidai ba",
"fiat_balance": "Fiat Balance",
"gross_balance": "Babban Ma'auni",
"alphabetical": "Harafi"
}

View file

@ -740,5 +740,9 @@
"token_symbol": "टोकन प्रतीक जैसे: यूएसडीटी",
"token_decimal": "सांकेतिक दशमलव",
"field_required": "यह फ़ील्ड आवश्यक है",
"pin_at_top": "शीर्ष पर ${token} पिन करें"
"pin_at_top": "शीर्ष पर ${token} पिन करें",
"invalid_input": "अमान्य निवेश",
"fiat_balance": "फिएट बैलेंस",
"gross_balance": "सकल संतुलन",
"alphabetical": "वर्णमाला"
}

View file

@ -740,5 +740,9 @@
"token_symbol": "Simbol tokena npr.: USDT",
"token_decimal": "Token decimalni",
"field_required": "ovo polje je obavezno",
"pin_at_top": "prikvači ${token} na vrh"
"pin_at_top": "prikvači ${token} na vrh",
"invalid_input": "Pogrešan unos",
"fiat_balance": "Fiat Bilans",
"gross_balance": "Bruto bilanca",
"alphabetical": "Abecedno"
}

View file

@ -716,5 +716,9 @@
"token_symbol": "Simbol token misalnya: USDT",
"token_decimal": "Desimal token",
"field_required": "Bagian ini diperlukan",
"pin_at_top": "sematkan ${token} di atas"
"pin_at_top": "sematkan ${token} di atas",
"invalid_input": "Masukan tidak valid",
"fiat_balance": "Saldo Fiat",
"gross_balance": "Saldo Kotor",
"alphabetical": "Alfabetis"
}

View file

@ -740,5 +740,9 @@
"token_symbol": "Simbolo del token, ad esempio: USDT",
"token_decimal": "Decimale del token",
"field_required": "Questo campo è obbligatorio",
"pin_at_top": "fissa ${token} in alto"
"pin_at_top": "fissa ${token} in alto",
"invalid_input": "Inserimento non valido",
"fiat_balance": "Equilibrio fiat",
"gross_balance": "Saldo lordo",
"alphabetical": "Alfabetico"
}

View file

@ -740,5 +740,9 @@
"token_symbol": "トークンシンボル 例: USDT",
"token_decimal": "トークン10進数",
"field_required": "この項目は必須です",
"pin_at_top": "${token} を上部に固定します"
"pin_at_top": "${token} を上部に固定します",
"invalid_input": "無効入力",
"fiat_balance": "フィアットバランス",
"gross_balance": "グロス残高",
"alphabetical": "アルファベット順"
}

View file

@ -740,5 +740,9 @@
"token_symbol": "토큰 기호 예: USDT",
"token_decimal": "토큰 십진수",
"field_required": "이 필드는 필수입니다",
"pin_at_top": "상단에 ${token} 고정"
"pin_at_top": "상단에 ${token} 고정",
"invalid_input": "잘못된 입력",
"fiat_balance": "피아트 잔액",
"gross_balance": "총 잔액",
"alphabetical": "알파벳순"
}

View file

@ -740,5 +740,9 @@
"token_symbol": "တိုကင်သင်္ကေတ ဥပမာ- USDT",
"token_decimal": "တိုကင်ဒဿမ",
"field_required": "ဤစာကွက်လပ်မှာဖြည့်ရန်လိုအပ်ပါသည်",
"pin_at_top": "အပေါ်တွင် ${token} ပင်ထိုးပါ။"
"pin_at_top": "အပေါ်တွင် ${token} ပင်ထိုးပါ။",
"invalid_input": "ထည့်သွင်းမှု မမှန်ကန်ပါ။",
"fiat_balance": "Fiat Balance",
"gross_balance": "စုစုပေါင်းလက်ကျန်ငွေ",
"alphabetical": "အက္ခရာစဉ်"
}

View file

@ -740,5 +740,9 @@
"token_symbol": "Tokensymbool bijv.: USDT",
"token_decimal": "Token decimaal",
"field_required": "dit veld is verplicht",
"pin_at_top": "speld ${token} bovenaan"
"pin_at_top": "speld ${token} bovenaan",
"invalid_input": "Ongeldige invoer",
"fiat_balance": "Fiat Balans",
"gross_balance": "Bruto saldo",
"alphabetical": "Alfabetisch"
}

View file

@ -740,5 +740,9 @@
"token_symbol": "Symbol tokena np.: USDT",
"token_decimal": "Token dziesiętny",
"field_required": "To pole jest wymagane",
"pin_at_top": "przypnij ${token} na górze"
"pin_at_top": "przypnij ${token} na górze",
"invalid_input": "Nieprawidłowe dane wejściowe",
"fiat_balance": "Bilans Fiata",
"gross_balance": "Saldo brutto",
"alphabetical": "Alfabetyczny"
}

View file

@ -739,5 +739,9 @@
"token_symbol": "Símbolo de token, por exemplo: USDT",
"token_decimal": "Token decimal",
"field_required": "Este campo é obrigatório",
"pin_at_top": "fixe ${token} no topo"
"pin_at_top": "fixe ${token} no topo",
"invalid_input": "Entrada inválida",
"fiat_balance": "Equilíbrio Fiat",
"gross_balance": "Saldo Bruto",
"alphabetical": "alfabética"
}

View file

@ -740,5 +740,9 @@
"token_symbol": "Символ токена, например: USDT",
"token_decimal": "Десятичный токен",
"field_required": "Это поле обязательно к заполнению",
"pin_at_top": "закрепить ${token} вверху"
"pin_at_top": "закрепить ${token} вверху",
"invalid_input": "Неверный Ввод",
"fiat_balance": "Фиатный баланс",
"gross_balance": "Валовой баланс",
"alphabetical": "Алфавитный"
}

View file

@ -738,5 +738,9 @@
"token_symbol": "สัญลักษณ์โทเค็น เช่น USDT",
"token_decimal": "โทเค็นทศนิยม",
"field_required": "ช่องนี้จำเป็น",
"pin_at_top": "ปักหมุด ${token} ที่ด้านบน"
"pin_at_top": "ปักหมุด ${token} ที่ด้านบน",
"invalid_input": "อินพุตไม่ถูกต้อง",
"fiat_balance": "เฟียต บาลานซ์",
"gross_balance": "ยอดคงเหลือ",
"alphabetical": "ตามตัวอักษร"
}

View file

@ -740,5 +740,9 @@
"token_symbol": "Jeton sembolü, örneğin: USDT",
"token_decimal": "Belirteç ondalık",
"field_required": "Bu alan gereklidir",
"pin_at_top": "${token} üstte sabitle"
"pin_at_top": "${token} üstte sabitle",
"invalid_input": "Geçersiz Giriş",
"fiat_balance": "Fiat Bakiyesi",
"gross_balance": "Brüt Bakiye",
"alphabetical": "Alfabetik"
}

View file

@ -739,5 +739,9 @@
"token_symbol": "Символ маркера, наприклад: USDT",
"token_decimal": "Токен десятковий",
"field_required": "Це поле є обов'язковим",
"pin_at_top": "закріпити ${token} зверху"
"pin_at_top": "закріпити ${token} зверху",
"invalid_input": "Неправильні дані",
"fiat_balance": "Фіат Баланс",
"gross_balance": "Валовий баланс",
"alphabetical": "Алфавітний"
}

View file

@ -735,5 +735,9 @@
"token_symbol": "ٹوکن کی علامت جیسے: USDT",
"token_decimal": "ٹوکن اعشاریہ",
"field_required": "اس کو پر کرنا ضروری ہے",
"pin_at_top": "اوپر ${token} کو پن کریں۔"
"pin_at_top": "اوپر ${token} کو پن کریں۔",
"invalid_input": "غلط ان پٹ",
"fiat_balance": "فیاٹ بیلنس",
"gross_balance": "مجموعی بیلنس",
"alphabetical": "حروف تہجی کے مطابق"
}

View file

@ -735,5 +735,9 @@
"token_symbol": "Aami aami fun apẹẹrẹ: USDT",
"token_decimal": "Àmi eleemewa",
"field_required": "E ni lati se nkan si aye yi",
"pin_at_top": "pin ${tokini} ni oke"
"pin_at_top": "pin ${tokini} ni oke",
"invalid_input": "Iṣawọle ti ko tọ",
"fiat_balance": "Fiat Iwontunws.funfun",
"gross_balance": "Iwontunws.funfun apapọ",
"alphabetical": "Labidibi"
}

View file

@ -739,5 +739,9 @@
"token_symbol": "代币符号例如USDT",
"token_decimal": "令牌十进制",
"field_required": "此字段是必需的",
"pin_at_top": "将 ${token} 固定在顶部"
"pin_at_top": "将 ${token} 固定在顶部",
"invalid_input": "输入无效",
"fiat_balance": "法币余额",
"gross_balance": "毛余额",
"alphabetical": "按字母顺序"
}