[skip ci] Merge branch 'main' of https://github.com/cake-tech/cake_wallet into breez

This commit is contained in:
Matthew Fosse 2024-06-21 14:12:45 -07:00
commit 45e1a4d223
58 changed files with 255 additions and 103 deletions

View file

@ -6,6 +6,7 @@ import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
import 'package:convert/convert.dart'; import 'package:convert/convert.dart';
import 'package:cw_bitcoin/bitcoin_address_record.dart'; import 'package:cw_bitcoin/bitcoin_address_record.dart';
import 'package:cw_bitcoin/bitcoin_mnemonic.dart'; import 'package:cw_bitcoin/bitcoin_mnemonic.dart';
import 'package:cw_bitcoin/electrum_derivations.dart';
import 'package:cw_bitcoin/bitcoin_wallet_addresses.dart'; import 'package:cw_bitcoin/bitcoin_wallet_addresses.dart';
import 'package:cw_bitcoin/electrum_balance.dart'; import 'package:cw_bitcoin/electrum_balance.dart';
import 'package:cw_bitcoin/electrum_wallet.dart'; import 'package:cw_bitcoin/electrum_wallet.dart';
@ -150,7 +151,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
); );
// set the default if not present: // set the default if not present:
walletInfo.derivationInfo!.derivationPath = snp.derivationPath ?? "m/0'/0"; walletInfo.derivationInfo!.derivationPath = snp.derivationPath ?? electrum_path;
walletInfo.derivationInfo!.derivationType = snp.derivationType ?? DerivationType.electrum; walletInfo.derivationInfo!.derivationType = snp.derivationType ?? DerivationType.electrum;
Uint8List? seedBytes = null; Uint8List? seedBytes = null;

View file

@ -108,3 +108,6 @@ Map<DerivationType, List<DerivationInfo>> electrum_derivations = {
), ),
], ],
}; };
String electrum_path = electrum_derivations[DerivationType.electrum]!.first.derivationPath!;

View file

@ -17,6 +17,7 @@ import 'package:cw_bitcoin/bitcoin_unspent.dart';
import 'package:cw_bitcoin/bitcoin_wallet_keys.dart'; import 'package:cw_bitcoin/bitcoin_wallet_keys.dart';
import 'package:cw_bitcoin/electrum.dart'; import 'package:cw_bitcoin/electrum.dart';
import 'package:cw_bitcoin/electrum_balance.dart'; import 'package:cw_bitcoin/electrum_balance.dart';
import 'package:cw_bitcoin/electrum_derivations.dart';
import 'package:cw_bitcoin/electrum_transaction_history.dart'; import 'package:cw_bitcoin/electrum_transaction_history.dart';
import 'package:cw_bitcoin/electrum_transaction_info.dart'; import 'package:cw_bitcoin/electrum_transaction_info.dart';
import 'package:cw_bitcoin/electrum_wallet_addresses.dart'; import 'package:cw_bitcoin/electrum_wallet_addresses.dart';
@ -133,7 +134,7 @@ abstract class ElectrumWalletBase
return currency == CryptoCurrency.bch return currency == CryptoCurrency.bch
? bitcoinCashHDWallet(seedBytes) ? bitcoinCashHDWallet(seedBytes)
: bitcoin.HDWallet.fromSeed(seedBytes, network: networkType) : bitcoin.HDWallet.fromSeed(seedBytes, network: networkType)
.derivePath(_hardenedDerivationPath(derivationInfo?.derivationPath ?? "m/0'")); .derivePath(_hardenedDerivationPath(derivationInfo?.derivationPath ?? electrum_path));
} }
return bitcoin.HDWallet.fromBase58(xpub!); return bitcoin.HDWallet.fromBase58(xpub!);

View file

@ -2,6 +2,7 @@ import 'dart:convert';
import 'package:bitcoin_base/bitcoin_base.dart'; import 'package:bitcoin_base/bitcoin_base.dart';
import 'package:cw_bitcoin/bitcoin_address_record.dart'; import 'package:cw_bitcoin/bitcoin_address_record.dart';
import 'package:cw_bitcoin/electrum_balance.dart'; import 'package:cw_bitcoin/electrum_balance.dart';
import 'package:cw_bitcoin/electrum_derivations.dart';
import 'package:cw_core/pathForWallet.dart'; import 'package:cw_core/pathForWallet.dart';
import 'package:cw_core/wallet_info.dart'; import 'package:cw_core/wallet_info.dart';
import 'package:cw_core/utils/file.dart'; import 'package:cw_core/utils/file.dart';
@ -71,7 +72,7 @@ class ElectrumWalletSnapshot {
final derivationType = DerivationType final derivationType = DerivationType
.values[(data['derivationTypeIndex'] as int?) ?? DerivationType.electrum.index]; .values[(data['derivationTypeIndex'] as int?) ?? DerivationType.electrum.index];
final derivationPath = data['derivationPath'] as String? ?? "m/0'/0"; final derivationPath = data['derivationPath'] as String? ?? electrum_path;
try { try {
regularAddressIndexByType = { regularAddressIndexByType = {

View file

@ -5,58 +5,64 @@ import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
import 'package:bitcoin_flutter/src/payments/index.dart' show PaymentData; import 'package:bitcoin_flutter/src/payments/index.dart' show PaymentData;
import 'package:hex/hex.dart'; import 'package:hex/hex.dart';
bitcoin.PaymentData generatePaymentData({required bitcoin.HDWallet hd, int? index}) { bitcoin.PaymentData generatePaymentData({
final pubKey = index != null ? hd.derive(index).pubKey! : hd.pubKey!; required bitcoin.HDWallet hd,
required int index,
}) {
final pubKey = hd.derive(index).pubKey!;
return PaymentData(pubkey: Uint8List.fromList(HEX.decode(pubKey))); return PaymentData(pubkey: Uint8List.fromList(HEX.decode(pubKey)));
} }
ECPrivate generateECPrivate( ECPrivate generateECPrivate({
{required bitcoin.HDWallet hd, required BasedUtxoNetwork network, int? index}) { required bitcoin.HDWallet hd,
final wif = index != null ? hd.derive(index).wif! : hd.wif!; required BasedUtxoNetwork network,
required int index,
}) {
final wif = hd.derive(index).wif!;
return ECPrivate.fromWif(wif, netVersion: network.wifNetVer); return ECPrivate.fromWif(wif, netVersion: network.wifNetVer);
} }
String generateP2WPKHAddress({ String generateP2WPKHAddress({
required bitcoin.HDWallet hd, required bitcoin.HDWallet hd,
required BasedUtxoNetwork network, required BasedUtxoNetwork network,
int? index, required int index,
}) { }) {
final pubKey = index != null ? hd.derive(index).pubKey! : hd.pubKey!; final pubKey = hd.derive(index).pubKey!;
return ECPublic.fromHex(pubKey).toP2wpkhAddress().toAddress(network); return ECPublic.fromHex(pubKey).toP2wpkhAddress().toAddress(network);
} }
String generateP2SHAddress({ String generateP2SHAddress({
required bitcoin.HDWallet hd, required bitcoin.HDWallet hd,
required BasedUtxoNetwork network, required BasedUtxoNetwork network,
int? index, required int index,
}) { }) {
final pubKey = index != null ? hd.derive(index).pubKey! : hd.pubKey!; final pubKey = hd.derive(index).pubKey!;
return ECPublic.fromHex(pubKey).toP2wpkhInP2sh().toAddress(network); return ECPublic.fromHex(pubKey).toP2wpkhInP2sh().toAddress(network);
} }
String generateP2WSHAddress({ String generateP2WSHAddress({
required bitcoin.HDWallet hd, required bitcoin.HDWallet hd,
required BasedUtxoNetwork network, required BasedUtxoNetwork network,
int? index, required int index,
}) { }) {
final pubKey = index != null ? hd.derive(index).pubKey! : hd.pubKey!; final pubKey = hd.derive(index).pubKey!;
return ECPublic.fromHex(pubKey).toP2wshAddress().toAddress(network); return ECPublic.fromHex(pubKey).toP2wshAddress().toAddress(network);
} }
String generateP2PKHAddress({ String generateP2PKHAddress({
required bitcoin.HDWallet hd, required bitcoin.HDWallet hd,
required BasedUtxoNetwork network, required BasedUtxoNetwork network,
int? index, required int index,
}) { }) {
final pubKey = index != null ? hd.derive(index).pubKey! : hd.pubKey!; final pubKey = hd.derive(index).pubKey!;
return ECPublic.fromHex(pubKey).toP2pkhAddress().toAddress(network); return ECPublic.fromHex(pubKey).toP2pkhAddress().toAddress(network);
} }
String generateP2TRAddress({ String generateP2TRAddress({
required bitcoin.HDWallet hd, required bitcoin.HDWallet hd,
required BasedUtxoNetwork network, required BasedUtxoNetwork network,
int? index, required int index,
}) { }) {
final pubKey = index != null ? hd.derive(index).pubKey! : hd.pubKey!; final pubKey = hd.derive(index).pubKey!;
return ECPublic.fromHex(pubKey).toTaprootAddress().toAddress(network); return ECPublic.fromHex(pubKey).toTaprootAddress().toAddress(network);
} }

View file

@ -16,6 +16,7 @@ abstract class TransactionInfo extends Object with Keyable {
void changeFiatAmount(String amount); void changeFiatAmount(String amount);
String? to; String? to;
String? from; String? from;
String? evmSignatureName;
List<String>? inputAddresses; List<String>? inputAddresses;
List<String>? outputAddresses; List<String>? outputAddresses;

View file

@ -29,6 +29,11 @@ class EthereumClient extends EVMChainClient {
final jsonResponse = json.decode(response.body) as Map<String, dynamic>; final jsonResponse = json.decode(response.body) as Map<String, dynamic>;
if (jsonResponse['result'] is String) {
log(jsonResponse['result']);
return [];
}
if (response.statusCode >= 200 && response.statusCode < 300 && jsonResponse['status'] != 0) { if (response.statusCode >= 200 && response.statusCode < 300 && jsonResponse['status'] != 0) {
return (jsonResponse['result'] as List) return (jsonResponse['result'] as List)
.map((e) => EVMChainTransactionModel.fromJson(e as Map<String, dynamic>, 'ETH')) .map((e) => EVMChainTransactionModel.fromJson(e as Map<String, dynamic>, 'ETH'))

View file

@ -14,6 +14,7 @@ class EthereumTransactionInfo extends EVMChainTransactionInfo {
required super.confirmations, required super.confirmations,
required super.to, required super.to,
required super.from, required super.from,
super.evmSignatureName,
super.exponent, super.exponent,
}); });
@ -31,6 +32,7 @@ class EthereumTransactionInfo extends EVMChainTransactionInfo {
tokenSymbol: data['tokenSymbol'] as String, tokenSymbol: data['tokenSymbol'] as String,
to: data['to'], to: data['to'],
from: data['from'], from: data['from'],
evmSignatureName: data['evmSignatureName'],
); );
} }

View file

@ -94,6 +94,7 @@ class EthereumWallet extends EVMChainWallet {
tokenSymbol: transactionModel.tokenSymbol ?? "ETH", tokenSymbol: transactionModel.tokenSymbol ?? "ETH",
to: transactionModel.to, to: transactionModel.to,
from: transactionModel.from, from: transactionModel.from,
evmSignatureName: transactionModel.evmSignatureName,
); );
return model; return model;
} }

View file

@ -20,6 +20,7 @@ abstract class EVMChainTransactionInfo extends TransactionInfo {
required this.confirmations, required this.confirmations,
required this.to, required this.to,
required this.from, required this.from,
this.evmSignatureName,
}) : amount = ethAmount.toInt(), }) : amount = ethAmount.toInt(),
fee = ethFee.toInt(); fee = ethFee.toInt();
@ -38,6 +39,7 @@ abstract class EVMChainTransactionInfo extends TransactionInfo {
String? _fiatAmount; String? _fiatAmount;
final String? to; final String? to;
final String? from; final String? from;
final String? evmSignatureName;
//! Getter to be overridden in child classes //! Getter to be overridden in child classes
String get feeCurrency; String get feeCurrency;
@ -73,5 +75,6 @@ abstract class EVMChainTransactionInfo extends TransactionInfo {
'tokenSymbol': tokenSymbol, 'tokenSymbol': tokenSymbol,
'to': to, 'to': to,
'from': from, 'from': from,
'evmSignatureName': evmSignatureName,
}; };
} }

View file

@ -12,6 +12,8 @@ class EVMChainTransactionModel {
final String? tokenSymbol; final String? tokenSymbol;
final int? tokenDecimal; final int? tokenDecimal;
final bool isError; final bool isError;
final String input;
String? evmSignatureName;
EVMChainTransactionModel({ EVMChainTransactionModel({
required this.date, required this.date,
@ -27,6 +29,8 @@ class EVMChainTransactionModel {
required this.tokenSymbol, required this.tokenSymbol,
required this.tokenDecimal, required this.tokenDecimal,
required this.isError, required this.isError,
required this.input,
this.evmSignatureName,
}); });
factory EVMChainTransactionModel.fromJson(Map<String, dynamic> json, String defaultSymbol) => factory EVMChainTransactionModel.fromJson(Map<String, dynamic> json, String defaultSymbol) =>
@ -44,5 +48,7 @@ class EVMChainTransactionModel {
tokenSymbol: json["tokenSymbol"] ?? defaultSymbol, tokenSymbol: json["tokenSymbol"] ?? defaultSymbol,
tokenDecimal: int.tryParse(json["tokenDecimal"] ?? ""), tokenDecimal: int.tryParse(json["tokenDecimal"] ?? ""),
isError: json["isError"] == "1", isError: json["isError"] == "1",
input: json["input"] ?? "",
evmSignatureName: json["evmSignatureName"],
); );
} }

View file

@ -39,6 +39,20 @@ import 'evm_erc20_balance.dart';
part 'evm_chain_wallet.g.dart'; part 'evm_chain_wallet.g.dart';
const Map<String, String> methodSignatureToType = {
'0x095ea7b3': 'approval',
'0xa9059cbb': 'transfer',
'0x23b872dd': 'transferFrom',
'0x574da717': 'transferOut',
'0x2e1a7d4d': 'withdraw',
'0x7ff36ab5': 'swapExactETHForTokens',
'0x40c10f19': 'mint',
'0x44bc937b': 'depositWithExpiry',
'0xd0e30db0': 'deposit',
'0xe8e33700': 'addLiquidity',
'0xd505accf': 'permit',
};
abstract class EVMChainWallet = EVMChainWalletBase with _$EVMChainWallet; abstract class EVMChainWallet = EVMChainWalletBase with _$EVMChainWallet;
abstract class EVMChainWalletBase abstract class EVMChainWalletBase
@ -235,7 +249,8 @@ abstract class EVMChainWalletBase
String? hexOpReturnMemo; String? hexOpReturnMemo;
if (opReturnMemo != null) { if (opReturnMemo != null) {
hexOpReturnMemo = '0x${opReturnMemo.codeUnits.map((char) => char.toRadixString(16).padLeft(2, '0')).join()}'; hexOpReturnMemo =
'0x${opReturnMemo.codeUnits.map((char) => char.toRadixString(16).padLeft(2, '0')).join()}';
} }
final CryptoCurrency transactionCurrency = final CryptoCurrency transactionCurrency =
@ -337,11 +352,21 @@ abstract class EVMChainWalletBase
@override @override
Future<Map<String, EVMChainTransactionInfo>> fetchTransactions() async { Future<Map<String, EVMChainTransactionInfo>> fetchTransactions() async {
final List<EVMChainTransactionModel> transactions = [];
final List<Future<List<EVMChainTransactionModel>>> erc20TokensTransactions = [];
final address = _evmChainPrivateKey.address.hex; final address = _evmChainPrivateKey.address.hex;
final transactions = await _client.fetchTransactions(address); final externalTransactions = await _client.fetchTransactions(address);
final internalTransactions = await _client.fetchInternalTransactions(address); final internalTransactions = await _client.fetchInternalTransactions(address);
final List<Future<List<EVMChainTransactionModel>>> erc20TokensTransactions = []; for (var transaction in externalTransactions) {
final evmSignatureName = analyzeTransaction(transaction.input);
if (evmSignatureName != 'depositWithExpiry' && evmSignatureName != 'transfer') {
transaction.evmSignatureName = evmSignatureName;
transactions.add(transaction);
}
}
for (var token in balance.keys) { for (var token in balance.keys) {
if (token is Erc20Token) { if (token is Erc20Token) {
@ -369,6 +394,17 @@ abstract class EVMChainWalletBase
return result; return result;
} }
String? analyzeTransaction(String? transactionInput) {
if (transactionInput == '0x' || transactionInput == null || transactionInput.isEmpty) {
return 'simpleTransfer';
}
final methodSignature =
transactionInput.length >= 10 ? transactionInput.substring(0, 10) : null;
return methodSignatureToType[methodSignature];
}
@override @override
Object get keys => throw UnimplementedError("keys"); Object get keys => throw UnimplementedError("keys");
@ -482,11 +518,11 @@ abstract class EVMChainWalletBase
await token.delete(); await token.delete();
balance.remove(token); balance.remove(token);
await _removeTokenTransactionsInHistory(token); await removeTokenTransactionsInHistory(token);
_updateBalance(); _updateBalance();
} }
Future<void> _removeTokenTransactionsInHistory(Erc20Token token) async { Future<void> removeTokenTransactionsInHistory(Erc20Token token) async {
transactionHistory.transactions.removeWhere((key, value) => value.tokenSymbol == token.title); transactionHistory.transactions.removeWhere((key, value) => value.tokenSymbol == token.title);
await transactionHistory.save(); await transactionHistory.save();
} }

View file

@ -108,6 +108,8 @@ abstract class MoneroWalletBase
publicSpendKey: monero_wallet.getPublicSpendKey(), publicSpendKey: monero_wallet.getPublicSpendKey(),
publicViewKey: monero_wallet.getPublicViewKey()); publicViewKey: monero_wallet.getPublicViewKey());
int? get restoreHeight => transactionHistory.transactions.values.firstOrNull?.height;
monero_wallet.SyncListener? _listener; monero_wallet.SyncListener? _listener;
ReactionDisposer? _onAccountChangeReaction; ReactionDisposer? _onAccountChangeReaction;
bool _isTransactionUpdating; bool _isTransactionUpdating;

View file

@ -456,7 +456,7 @@ class SolanaWalletClient {
funder: ownerKeypair, funder: ownerKeypair,
); );
} catch (e) { } catch (e) {
throw Exception('Insufficient lamports balance to complete this transaction'); throw Exception('Insufficient SOL balance to complete this transaction');
} }
// Input by the user // Input by the user

View file

@ -295,14 +295,7 @@ class CWBitcoin extends Bitcoin {
List<DerivationType> types = await compareDerivationMethods(mnemonic: mnemonic, node: node); List<DerivationType> types = await compareDerivationMethods(mnemonic: mnemonic, node: node);
if (types.length == 1 && types.first == DerivationType.electrum) { if (types.length == 1 && types.first == DerivationType.electrum) {
return [ return [getElectrumDerivations()[DerivationType.electrum]!.first];
DerivationInfo(
derivationType: DerivationType.electrum,
derivationPath: "m/0'",
description: "Electrum",
scriptType: "p2wpkh",
)
];
} }
final electrumClient = ElectrumClient(); final electrumClient = ElectrumClient();
@ -339,38 +332,34 @@ class CWBitcoin extends Bitcoin {
scriptType: dInfo.scriptType, scriptType: dInfo.scriptType,
); );
String derivationPath = dInfoCopy.derivationPath!; String balancePath = dInfoCopy.derivationPath!;
int derivationDepth = _countOccurrences(derivationPath, "/"); int derivationDepth = _countOccurrences(balancePath, "/");
// the correct derivation depth is dependant on the derivation type:
// the derivation paths defined in electrum_derivations are at the ROOT level, i.e.:
// electrum's format doesn't specify subaddresses, just subaccounts:
// for BIP44 // for BIP44
if (derivationDepth == 3) { if (derivationDepth == 3 || derivationDepth == 1) {
// we add "/0/0" so that we generate account 0, index 0 and correctly get balance // we add "/0" so that we generate account 0
derivationPath += "/0/0"; balancePath += "/0";
} }
// var hd = bip32.BIP32.fromSeed(seedBytes).derivePath(derivationPath);
final hd = btc.HDWallet.fromSeed( final hd = btc.HDWallet.fromSeed(
seedBytes, seedBytes,
network: networkType, network: networkType,
).derivePath(derivationPath); ).derivePath(balancePath);
// derive address at index 0:
String? address; String? address;
switch (dInfoCopy.scriptType) { switch (dInfoCopy.scriptType) {
case "p2wpkh": case "p2wpkh":
address = generateP2WPKHAddress(hd: hd, network: network); address = generateP2WPKHAddress(hd: hd, network: network, index: 0);
break; break;
case "p2pkh": case "p2pkh":
address = generateP2PKHAddress(hd: hd, network: network); address = generateP2PKHAddress(hd: hd, network: network, index: 0);
break; break;
case "p2wpkh-p2sh": case "p2wpkh-p2sh":
address = generateP2SHAddress(hd: hd, network: network); address = generateP2SHAddress(hd: hd, network: network, index: 0);
break; break;
case "p2tr": case "p2tr":
address = generateP2TRAddress(hd: hd, network: network); address = generateP2TRAddress(hd: hd, network: network, index: 0);
break; break;
default: default:
continue; continue;
@ -396,6 +385,11 @@ class CWBitcoin extends Bitcoin {
return list; return list;
} }
@override
Map<DerivationType, List<DerivationInfo>> getElectrumDerivations() {
return electrum_derivations;
}
@override @override
bool hasTaprootInput(PendingTransaction pendingTransaction) { bool hasTaprootInput(PendingTransaction pendingTransaction) {
return (pendingTransaction as PendingBitcoinTransaction).hasTaprootInputs; return (pendingTransaction as PendingBitcoinTransaction).hasTaprootInputs;

View file

@ -233,6 +233,8 @@ Future<void> defaultSettingsMigration(
case 36: case 36:
await changeTronCurrentNodeToDefault(sharedPreferences: sharedPreferences, nodes: nodes); await changeTronCurrentNodeToDefault(sharedPreferences: sharedPreferences, nodes: nodes);
break; break;
case 37:
await fixBtcDerivationPaths(walletInfoSource);
default: default:
break; break;
} }
@ -775,6 +777,19 @@ Future<void> changeDefaultMoneroNode(
} }
} }
Future<void> fixBtcDerivationPaths(Box<WalletInfo> walletsInfoSource) async {
for (WalletInfo walletInfo in walletsInfoSource.values) {
if (walletInfo.type == WalletType.bitcoin ||
walletInfo.type == WalletType.bitcoinCash ||
walletInfo.type == WalletType.litecoin) {
if (walletInfo.derivationInfo?.derivationPath == "m/0'/0") {
walletInfo.derivationInfo!.derivationPath = "m/0'";
await walletInfo.save();
}
}
}
}
Future<void> updateBtcNanoWalletInfos(Box<WalletInfo> walletsInfoSource) async { Future<void> updateBtcNanoWalletInfos(Box<WalletInfo> walletsInfoSource) async {
for (WalletInfo walletInfo in walletsInfoSource.values) { for (WalletInfo walletInfo in walletsInfoSource.values) {
if (walletInfo.type == WalletType.nano || walletInfo.type == WalletType.bitcoin) { if (walletInfo.type == WalletType.nano || walletInfo.type == WalletType.bitcoin) {

View file

@ -77,6 +77,7 @@ class PreferencesKey {
static const moneroSeedType = 'monero_seed_type'; static const moneroSeedType = 'monero_seed_type';
static const clearnetDonationLink = 'clearnet_donation_link'; static const clearnetDonationLink = 'clearnet_donation_link';
static const onionDonationLink = 'onion_donation_link'; static const onionDonationLink = 'onion_donation_link';
static const donationLinkWalletName = 'donation_link_wallet_name';
static const lastSeenAppVersion = 'last_seen_app_version'; static const lastSeenAppVersion = 'last_seen_app_version';
static const shouldShowMarketPlaceInDashboard = 'should_show_marketplace_in_dashboard'; static const shouldShowMarketPlaceInDashboard = 'should_show_marketplace_in_dashboard';
static const isNewInstall = 'is_new_install'; static const isNewInstall = 'is_new_install';

View file

@ -137,6 +137,10 @@ class CWEthereum extends Ethereum {
Future<void> deleteErc20Token(WalletBase wallet, CryptoCurrency token) async => Future<void> deleteErc20Token(WalletBase wallet, CryptoCurrency token) async =>
await (wallet as EthereumWallet).deleteErc20Token(token as Erc20Token); await (wallet as EthereumWallet).deleteErc20Token(token as Erc20Token);
@override
Future<void> removeTokenTransactionsInHistory(WalletBase wallet, CryptoCurrency token) async =>
await (wallet as EthereumWallet).removeTokenTransactionsInHistory(token as Erc20Token);
@override @override
Future<Erc20Token?> getErc20Token(WalletBase wallet, String contractAddress) async { Future<Erc20Token?> getErc20Token(WalletBase wallet, String contractAddress) async {
final ethereumWallet = wallet as EthereumWallet; final ethereumWallet = wallet as EthereumWallet;

View file

@ -202,7 +202,7 @@ Future<void> initializeAppConfigs() async {
transactionDescriptions: transactionDescriptions, transactionDescriptions: transactionDescriptions,
secureStorage: secureStorage, secureStorage: secureStorage,
anonpayInvoiceInfo: anonpayInvoiceInfo, anonpayInvoiceInfo: anonpayInvoiceInfo,
initialMigrationVersion: 36, initialMigrationVersion: 37,
); );
} }

View file

@ -244,6 +244,12 @@ class CWMonero extends Monero {
}; };
} }
@override
int? getRestoreHeight(Object wallet) {
final moneroWallet = wallet as MoneroWallet;
return moneroWallet.restoreHeight;
}
@override @override
Object createMoneroTransactionCreationCredentials( Object createMoneroTransactionCreationCredentials(
{required List<Output> outputs, required TransactionPriority priority}) => {required List<Output> outputs, required TransactionPriority priority}) =>

View file

@ -135,6 +135,10 @@ class CWPolygon extends Polygon {
Future<void> deleteErc20Token(WalletBase wallet, CryptoCurrency token) async => Future<void> deleteErc20Token(WalletBase wallet, CryptoCurrency token) async =>
await (wallet as PolygonWallet).deleteErc20Token(token as Erc20Token); await (wallet as PolygonWallet).deleteErc20Token(token as Erc20Token);
@override
Future<void> removeTokenTransactionsInHistory(WalletBase wallet, CryptoCurrency token) async =>
await (wallet as PolygonWallet).removeTokenTransactionsInHistory(token as Erc20Token);
@override @override
Future<Erc20Token?> getErc20Token(WalletBase wallet, String contractAddress) async { Future<Erc20Token?> getErc20Token(WalletBase wallet, String contractAddress) async {
final polygonWallet = wallet as PolygonWallet; final polygonWallet = wallet as PolygonWallet;

View file

@ -3,7 +3,6 @@ import 'package:cake_wallet/src/screens/new_wallet/widgets/select_button.dart';
import 'package:cake_wallet/themes/extensions/keyboard_theme.dart'; import 'package:cake_wallet/themes/extensions/keyboard_theme.dart';
import 'package:cake_wallet/di.dart'; import 'package:cake_wallet/di.dart';
import 'package:cake_wallet/src/screens/base_page.dart'; import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/src/screens/monero_accounts/monero_account_list_page.dart';
import 'package:cake_wallet/anonpay/anonpay_donation_link_info.dart'; import 'package:cake_wallet/anonpay/anonpay_donation_link_info.dart';
import 'package:cake_wallet/entities/preferences_key.dart'; import 'package:cake_wallet/entities/preferences_key.dart';
import 'package:cw_core/receive_page_option.dart'; import 'package:cw_core/receive_page_option.dart';
@ -14,7 +13,6 @@ import 'package:cake_wallet/themes/extensions/sync_indicator_theme.dart';
import 'package:cake_wallet/themes/theme_base.dart'; import 'package:cake_wallet/themes/theme_base.dart';
import 'package:cake_wallet/utils/responsive_layout_util.dart'; import 'package:cake_wallet/utils/responsive_layout_util.dart';
import 'package:cake_wallet/utils/share_util.dart'; import 'package:cake_wallet/utils/share_util.dart';
import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:cake_wallet/view_model/dashboard/receive_option_view_model.dart'; import 'package:cake_wallet/view_model/dashboard/receive_option_view_model.dart';
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart'; import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
import 'package:cw_core/wallet_type.dart'; import 'package:cw_core/wallet_type.dart';
@ -171,8 +169,7 @@ class AddressPage extends BasePage {
textSize: 14, textSize: 14,
height: 50, height: 50,
); );
} } else {
else {
return const SizedBox(); return const SizedBox();
} }
}), }),
@ -204,8 +201,12 @@ class AddressPage extends BasePage {
final sharedPreferences = getIt.get<SharedPreferences>(); final sharedPreferences = getIt.get<SharedPreferences>();
final clearnetUrl = sharedPreferences.getString(PreferencesKey.clearnetDonationLink); final clearnetUrl = sharedPreferences.getString(PreferencesKey.clearnetDonationLink);
final onionUrl = sharedPreferences.getString(PreferencesKey.onionDonationLink); final onionUrl = sharedPreferences.getString(PreferencesKey.onionDonationLink);
final donationWalletName =
sharedPreferences.getString(PreferencesKey.donationLinkWalletName);
if (clearnetUrl != null && onionUrl != null) { if (clearnetUrl != null &&
onionUrl != null &&
addressListViewModel.wallet.name == donationWalletName) {
Navigator.pushNamed( Navigator.pushNamed(
context, context,
Routes.anonPayReceivePage, Routes.anonPayReceivePage,

View file

@ -8,6 +8,7 @@ import 'package:cake_wallet/view_model/dashboard/anonpay_transaction_list_item.d
import 'package:cake_wallet/view_model/dashboard/order_list_item.dart'; import 'package:cake_wallet/view_model/dashboard/order_list_item.dart';
import 'package:cw_core/crypto_currency.dart'; import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/sync_status.dart'; import 'package:cw_core/sync_status.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart'; import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:flutter_mobx/flutter_mobx.dart';
@ -87,6 +88,10 @@ class TransactionsPage extends StatelessWidget {
} }
final transaction = item.transaction; final transaction = item.transaction;
final transactionType = dashboardViewModel.type == WalletType.ethereum &&
transaction.evmSignatureName == 'approval'
? ' (${transaction.evmSignatureName})'
: '';
return Observer( return Observer(
builder: (_) => TransactionRow( builder: (_) => TransactionRow(
@ -100,7 +105,8 @@ class TransactionsPage extends StatelessWidget {
? '' ? ''
: item.formattedFiatAmount, : item.formattedFiatAmount,
isPending: transaction.isPending, isPending: transaction.isPending,
title: item.formattedTitle + item.formattedStatus, title: item.formattedTitle +
item.formattedStatus + ' $transactionType',
), ),
); );
} }

View file

@ -60,8 +60,7 @@ class AnonPayInvoicePage extends BasePage {
@override @override
Widget middle(BuildContext context) => PresentReceiveOptionPicker( Widget middle(BuildContext context) => PresentReceiveOptionPicker(
receiveOptionViewModel: receiveOptionViewModel, receiveOptionViewModel: receiveOptionViewModel, color: titleColor(context));
color: titleColor(context));
@override @override
Widget trailing(BuildContext context) => TrailButton( Widget trailing(BuildContext context) => TrailButton(
@ -87,30 +86,36 @@ class AnonPayInvoicePage extends BasePage {
config: KeyboardActionsConfig( config: KeyboardActionsConfig(
keyboardActionsPlatform: KeyboardActionsPlatform.IOS, keyboardActionsPlatform: KeyboardActionsPlatform.IOS,
keyboardBarColor: Theme.of(context).extension<KeyboardTheme>()!.keyboardBarColor, keyboardBarColor: Theme.of(context).extension<KeyboardTheme>()!.keyboardBarColor,
nextFocus: false, nextFocus: false,
actions: [ actions: [
KeyboardActionsItem( KeyboardActionsItem(
focusNode: _amountFocusNode, focusNode: _amountFocusNode,
toolbarButtons: [(_) => KeyboardDoneButton()], toolbarButtons: [(_) => KeyboardDoneButton()],
),
]),
child: Container(
color: Theme.of(context).colorScheme.background,
child: ScrollableWithBottomSection(
contentPadding: EdgeInsets.only(bottom: 24),
content: Container(
decoration: responsiveLayoutUtil.shouldRenderMobileUI ? BoxDecoration(
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(24), bottomRight: Radius.circular(24)),
gradient: LinearGradient(
colors: [
Theme.of(context).extension<ExchangePageTheme>()!.firstGradientTopPanelColor,
Theme.of(context).extension<ExchangePageTheme>()!.secondGradientTopPanelColor,
],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
), ),
) : null, ]),
child: Container(
color: Theme.of(context).colorScheme.background,
child: ScrollableWithBottomSection(
contentPadding: EdgeInsets.only(bottom: 24),
content: Container(
decoration: responsiveLayoutUtil.shouldRenderMobileUI
? BoxDecoration(
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(24), bottomRight: Radius.circular(24)),
gradient: LinearGradient(
colors: [
Theme.of(context)
.extension<ExchangePageTheme>()!
.firstGradientTopPanelColor,
Theme.of(context)
.extension<ExchangePageTheme>()!
.secondGradientTopPanelColor,
],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
)
: null,
child: Observer(builder: (_) { child: Observer(builder: (_) {
return Padding( return Padding(
padding: EdgeInsets.fromLTRB(24, 120, 24, 0), padding: EdgeInsets.fromLTRB(24, 120, 24, 0),
@ -143,9 +148,11 @@ class AnonPayInvoicePage extends BasePage {
: S.of(context).anonpay_description("a donation link", "donate"), : S.of(context).anonpay_description("a donation link", "donate"),
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: TextStyle( style: TextStyle(
color: Theme.of(context).extension<ExchangePageTheme>()!.receiveAmountColor, color: Theme.of(context)
fontWeight: FontWeight.w500, .extension<ExchangePageTheme>()!
fontSize: 12), .receiveAmountColor,
fontWeight: FontWeight.w500,
fontSize: 12),
), ),
), ),
), ),
@ -172,7 +179,7 @@ class AnonPayInvoicePage extends BasePage {
anonInvoicePageViewModel.generateDonationLink(); anonInvoicePageViewModel.generateDonationLink();
} }
}, },
color: Theme.of(context).primaryColor, color: Theme.of(context).primaryColor,
textColor: Colors.white, textColor: Colors.white,
isLoading: anonInvoicePageViewModel.state is IsExecutingState, isLoading: anonInvoicePageViewModel.state is IsExecutingState,
), ),
@ -199,8 +206,12 @@ class AnonPayInvoicePage extends BasePage {
final sharedPreferences = getIt.get<SharedPreferences>(); final sharedPreferences = getIt.get<SharedPreferences>();
final clearnetUrl = sharedPreferences.getString(PreferencesKey.clearnetDonationLink); final clearnetUrl = sharedPreferences.getString(PreferencesKey.clearnetDonationLink);
final onionUrl = sharedPreferences.getString(PreferencesKey.onionDonationLink); final onionUrl = sharedPreferences.getString(PreferencesKey.onionDonationLink);
final donationWalletName =
sharedPreferences.getString(PreferencesKey.donationLinkWalletName);
if (clearnetUrl != null && onionUrl != null) { if (clearnetUrl != null &&
onionUrl != null &&
anonInvoicePageViewModel.currentWalletName == donationWalletName) {
Navigator.pushReplacementNamed(context, Routes.anonPayReceivePage, Navigator.pushReplacementNamed(context, Routes.anonPayReceivePage,
arguments: AnonpayDonationLinkInfo( arguments: AnonpayDonationLinkInfo(
clearnetUrl: clearnetUrl, clearnetUrl: clearnetUrl,

View file

@ -150,6 +150,7 @@ abstract class AnonInvoicePageViewModelBase with Store {
await sharedPreferences.setString(PreferencesKey.clearnetDonationLink, result.clearnetUrl); await sharedPreferences.setString(PreferencesKey.clearnetDonationLink, result.clearnetUrl);
await sharedPreferences.setString(PreferencesKey.onionDonationLink, result.onionUrl); await sharedPreferences.setString(PreferencesKey.onionDonationLink, result.onionUrl);
await sharedPreferences.setString(PreferencesKey.donationLinkWalletName, _wallet.name);
state = ExecutedSuccessfullyState(payload: result); state = ExecutedSuccessfullyState(payload: result);
} }
@ -163,10 +164,13 @@ abstract class AnonInvoicePageViewModelBase with Store {
maximum = limit.max != null ? limit.max! / 4 : null; maximum = limit.max != null ? limit.max! / 4 : null;
} }
@computed
String get currentWalletName => _wallet.name;
@action @action
void reset() { void reset() {
selectedCurrency = walletTypeToCryptoCurrency(_wallet.type); selectedCurrency = walletTypeToCryptoCurrency(_wallet.type);
cryptoCurrency = walletTypeToCryptoCurrency(_wallet.type); cryptoCurrency = walletTypeToCryptoCurrency(_wallet.type);
receipientEmail = ''; receipientEmail = '';
receipientName = ''; receipientName = '';
description = ''; description = '';
@ -177,7 +181,10 @@ abstract class AnonInvoicePageViewModelBase with Store {
Future<void> _getPreviousDonationLink() async { Future<void> _getPreviousDonationLink() async {
if (pageOption == ReceivePageOption.anonPayDonationLink) { if (pageOption == ReceivePageOption.anonPayDonationLink) {
final donationLink = sharedPreferences.getString(PreferencesKey.clearnetDonationLink); final donationLink = sharedPreferences.getString(PreferencesKey.clearnetDonationLink);
if (donationLink != null) { final donationLinkWalletName =
sharedPreferences.getString(PreferencesKey.donationLinkWalletName);
if (donationLink != null && currentWalletName == donationLinkWalletName) {
final url = Uri.parse(donationLink); final url = Uri.parse(donationLink);
url.queryParameters.forEach((key, value) { url.queryParameters.forEach((key, value) {
if (key == 'name') receipientName = value; if (key == 'name') receipientName = value;

View file

@ -39,7 +39,7 @@ abstract class ContactListViewModelBase with Store {
)); ));
} }
}); });
} else if (info.addresses?.isNotEmpty == true) { } else if (info.addresses?.isNotEmpty == true && info.addresses!.length > 1) {
info.addresses!.forEach((address, label) { info.addresses!.forEach((address, label) {
if (label.isEmpty) { if (label.isEmpty) {
return; return;

View file

@ -144,10 +144,12 @@ abstract class HomeSettingsViewModelBase with Store {
if (_balanceViewModel.wallet.type == WalletType.ethereum) { if (_balanceViewModel.wallet.type == WalletType.ethereum) {
ethereum!.addErc20Token(_balanceViewModel.wallet, token as Erc20Token); ethereum!.addErc20Token(_balanceViewModel.wallet, token as Erc20Token);
if (!value) ethereum!.removeTokenTransactionsInHistory(_balanceViewModel.wallet, token);
} }
if (_balanceViewModel.wallet.type == WalletType.polygon) { if (_balanceViewModel.wallet.type == WalletType.polygon) {
polygon!.addErc20Token(_balanceViewModel.wallet, token as Erc20Token); polygon!.addErc20Token(_balanceViewModel.wallet, token as Erc20Token);
if (!value) polygon!.removeTokenTransactionsInHistory(_balanceViewModel.wallet, token);
} }
if (_balanceViewModel.wallet.type == WalletType.solana) { if (_balanceViewModel.wallet.type == WalletType.solana) {

View file

@ -1,3 +1,4 @@
import 'package:cake_wallet/bitcoin/bitcoin.dart';
import 'package:cake_wallet/core/wallet_creation_service.dart'; import 'package:cake_wallet/core/wallet_creation_service.dart';
import 'package:cake_wallet/di.dart'; import 'package:cake_wallet/di.dart';
import 'package:cake_wallet/entities/background_tasks.dart'; import 'package:cake_wallet/entities/background_tasks.dart';
@ -99,10 +100,7 @@ abstract class WalletCreationVMBase with Store {
case WalletType.bitcoin: case WalletType.bitcoin:
case WalletType.lightning: case WalletType.lightning:
case WalletType.litecoin: case WalletType.litecoin:
return DerivationInfo( return bitcoin!.getElectrumDerivations()[DerivationType.electrum]!.first;
derivationType: DerivationType.electrum,
derivationPath: "m/0'",
);
default: default:
return null; return null;
} }

View file

@ -1,16 +1,15 @@
import 'package:cake_wallet/bitcoin/bitcoin.dart'; import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/haven/haven.dart';
import 'package:cake_wallet/monero/monero.dart';
import 'package:cake_wallet/reactions/wallet_connect.dart'; import 'package:cake_wallet/reactions/wallet_connect.dart';
import 'package:cake_wallet/src/screens/transaction_details/standart_list_item.dart';
import 'package:cake_wallet/store/app_store.dart'; import 'package:cake_wallet/store/app_store.dart';
import 'package:cw_core/transaction_direction.dart'; import 'package:cw_core/transaction_direction.dart';
import 'package:cw_core/transaction_info.dart'; import 'package:cw_core/transaction_info.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:mobx/mobx.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cw_core/wallet_base.dart'; import 'package:cw_core/wallet_base.dart';
import 'package:cake_wallet/src/screens/transaction_details/standart_list_item.dart'; import 'package:cw_core/wallet_type.dart';
import 'package:cake_wallet/monero/monero.dart';
import 'package:cake_wallet/haven/haven.dart';
import 'package:cw_monero/api/wallet.dart' as monero_wallet; import 'package:cw_monero/api/wallet.dart' as monero_wallet;
import 'package:mobx/mobx.dart';
import 'package:polyseed/polyseed.dart'; import 'package:polyseed/polyseed.dart';
part 'wallet_keys_view_model.g.dart'; part 'wallet_keys_view_model.g.dart';
@ -84,6 +83,12 @@ abstract class WalletKeysViewModelBase with Store {
.toLegacySeed(legacyLang); .toLegacySeed(legacyLang);
items.add(StandartListItem(title: S.current.wallet_seed_legacy, value: legacySeed)); items.add(StandartListItem(title: S.current.wallet_seed_legacy, value: legacySeed));
} }
final restoreHeight = monero!.getRestoreHeight(_appStore.wallet!);
if (restoreHeight != null) {
items.add(StandartListItem(
title: S.current.wallet_recovery_height, value: restoreHeight.toString()));
}
} }
if (_appStore.wallet!.type == WalletType.haven) { if (_appStore.wallet!.type == WalletType.haven) {

View file

@ -843,6 +843,7 @@
"wallet_menu": "قائمة", "wallet_menu": "قائمة",
"wallet_name": "اسم المحفظة", "wallet_name": "اسم المحفظة",
"wallet_name_exists": "توجد بالفعل محفظة بهذا الاسم. الرجاء اختيار اسم مختلف أو إعادة تسمية المحفظة الأخرى أولاً.", "wallet_name_exists": "توجد بالفعل محفظة بهذا الاسم. الرجاء اختيار اسم مختلف أو إعادة تسمية المحفظة الأخرى أولاً.",
"wallet_recovery_height": "ارتفاع الاسترداد",
"wallet_restoration_store_incorrect_seed_length": "طول السييد غير صحيح", "wallet_restoration_store_incorrect_seed_length": "طول السييد غير صحيح",
"wallet_seed": "سييد المحفظة", "wallet_seed": "سييد المحفظة",
"wallet_seed_legacy": "بذرة محفظة قديمة", "wallet_seed_legacy": "بذرة محفظة قديمة",

View file

@ -843,6 +843,7 @@
"wallet_menu": "Меню", "wallet_menu": "Меню",
"wallet_name": "Име на портфейл", "wallet_name": "Име на портфейл",
"wallet_name_exists": "Вече има портфейл с това име. Моля, изберете друго име или преименувайте другия портфейл.", "wallet_name_exists": "Вече има портфейл с това име. Моля, изберете друго име или преименувайте другия портфейл.",
"wallet_recovery_height": "Височина на възстановяване",
"wallet_restoration_store_incorrect_seed_length": "Грешна дължина на seed-а", "wallet_restoration_store_incorrect_seed_length": "Грешна дължина на seed-а",
"wallet_seed": "Seed на портфейла", "wallet_seed": "Seed на портфейла",
"wallet_seed_legacy": "Наследено портфейл семе", "wallet_seed_legacy": "Наследено портфейл семе",

View file

@ -843,6 +843,7 @@
"wallet_menu": "Menu", "wallet_menu": "Menu",
"wallet_name": "Název peněženky", "wallet_name": "Název peněženky",
"wallet_name_exists": "Peněženka s tímto názvem už existuje. Prosím zvolte si jiný název, nebo nejprve přejmenujte nejprve druhou peněženku.", "wallet_name_exists": "Peněženka s tímto názvem už existuje. Prosím zvolte si jiný název, nebo nejprve přejmenujte nejprve druhou peněženku.",
"wallet_recovery_height": "Výška zotavení",
"wallet_restoration_store_incorrect_seed_length": "Nesprávná délka seedu", "wallet_restoration_store_incorrect_seed_length": "Nesprávná délka seedu",
"wallet_seed": "Seed peněženky", "wallet_seed": "Seed peněženky",
"wallet_seed_legacy": "Starší semeno peněženky", "wallet_seed_legacy": "Starší semeno peněženky",

View file

@ -846,6 +846,7 @@
"wallet_menu": "Wallet-Menü", "wallet_menu": "Wallet-Menü",
"wallet_name": "Walletname", "wallet_name": "Walletname",
"wallet_name_exists": "Wallet mit diesem Namen existiert bereits", "wallet_name_exists": "Wallet mit diesem Namen existiert bereits",
"wallet_recovery_height": "Erstellungshöhe",
"wallet_restoration_store_incorrect_seed_length": "Falsche Seed-Länge", "wallet_restoration_store_incorrect_seed_length": "Falsche Seed-Länge",
"wallet_seed": "Wallet-Seed", "wallet_seed": "Wallet-Seed",
"wallet_seed_legacy": "Legacy Wallet Seed", "wallet_seed_legacy": "Legacy Wallet Seed",

View file

@ -843,6 +843,7 @@
"wallet_menu": "Menu", "wallet_menu": "Menu",
"wallet_name": "Wallet name", "wallet_name": "Wallet name",
"wallet_name_exists": "A wallet with that name already exists. Please choose a different name or rename the other wallet first.", "wallet_name_exists": "A wallet with that name already exists. Please choose a different name or rename the other wallet first.",
"wallet_recovery_height": "Recovery Height",
"wallet_restoration_store_incorrect_seed_length": "Incorrect seed length", "wallet_restoration_store_incorrect_seed_length": "Incorrect seed length",
"wallet_seed": "Wallet seed", "wallet_seed": "Wallet seed",
"wallet_seed_legacy": "Legacy wallet seed", "wallet_seed_legacy": "Legacy wallet seed",

View file

@ -844,6 +844,7 @@
"wallet_menu": "Menú de billetera", "wallet_menu": "Menú de billetera",
"wallet_name": "Nombre de la billetera", "wallet_name": "Nombre de la billetera",
"wallet_name_exists": "Wallet con ese nombre ya ha existido", "wallet_name_exists": "Wallet con ese nombre ya ha existido",
"wallet_recovery_height": "Altura de recuperación",
"wallet_restoration_store_incorrect_seed_length": "Longitud de semilla incorrecta", "wallet_restoration_store_incorrect_seed_length": "Longitud de semilla incorrecta",
"wallet_seed": "Semilla de billetera", "wallet_seed": "Semilla de billetera",
"wallet_seed_legacy": "Semilla de billetera heredada", "wallet_seed_legacy": "Semilla de billetera heredada",

View file

@ -268,7 +268,7 @@
"errorSigningTransaction": "Une erreur s'est produite lors de la signature de la transaction", "errorSigningTransaction": "Une erreur s'est produite lors de la signature de la transaction",
"estimated": "Estimé", "estimated": "Estimé",
"estimated_new_fee": "De nouveaux frais estimés", "estimated_new_fee": "De nouveaux frais estimés",
"etherscan_history": "Historique d'Etherscan", "etherscan_history": "Historique Etherscan",
"event": "Événement", "event": "Événement",
"events": "Événements", "events": "Événements",
"exchange": "Échanger", "exchange": "Échanger",
@ -413,7 +413,7 @@
"node_test": "Tester", "node_test": "Tester",
"nodes": "Nœuds", "nodes": "Nœuds",
"nodes_list_reset_to_default_message": "Êtes vous certain de vouloir revenir aux réglages par défaut ?", "nodes_list_reset_to_default_message": "Êtes vous certain de vouloir revenir aux réglages par défaut ?",
"none_of_selected_providers_can_exchange": "Aucun des prestataires sélectionnés ne peut effectuer cet échange", "none_of_selected_providers_can_exchange": "Aucun des fournisseurs sélectionnés ne peut effectuer cet échange",
"noNFTYet": "Pas encore de NFT", "noNFTYet": "Pas encore de NFT",
"normal": "Normal", "normal": "Normal",
"note_optional": "Note (optionnelle)", "note_optional": "Note (optionnelle)",
@ -803,7 +803,7 @@
"unconfirmed": "Solde non confirmé", "unconfirmed": "Solde non confirmé",
"understand": "J'ai compris", "understand": "J'ai compris",
"unmatched_currencies": "La devise de votre portefeuille (wallet) actuel ne correspond pas à celle du QR code scanné", "unmatched_currencies": "La devise de votre portefeuille (wallet) actuel ne correspond pas à celle du QR code scanné",
"unspent_change": "Changement", "unspent_change": "Monnaie",
"unspent_coins_details_title": "Détails des pièces (coins) non dépensées", "unspent_coins_details_title": "Détails des pièces (coins) non dépensées",
"unspent_coins_title": "Pièces (coins) non dépensées", "unspent_coins_title": "Pièces (coins) non dépensées",
"unsupported_asset": "Nous ne prenons pas en charge cette action pour cet élément. Veuillez créer ou passer à un portefeuille d'un type d'actif pris en charge.", "unsupported_asset": "Nous ne prenons pas en charge cette action pour cet élément. Veuillez créer ou passer à un portefeuille d'un type d'actif pris en charge.",
@ -843,6 +843,7 @@
"wallet_menu": "Menu", "wallet_menu": "Menu",
"wallet_name": "Nom du Portefeuille (Wallet)", "wallet_name": "Nom du Portefeuille (Wallet)",
"wallet_name_exists": "Un portefeuille (wallet) portant ce nom existe déjà", "wallet_name_exists": "Un portefeuille (wallet) portant ce nom existe déjà",
"wallet_recovery_height": "Hauteur de récupération",
"wallet_restoration_store_incorrect_seed_length": "Longueur de phrase secrète (seed) incorrecte", "wallet_restoration_store_incorrect_seed_length": "Longueur de phrase secrète (seed) incorrecte",
"wallet_seed": "Phrase secrète (seed) du portefeuille (wallet)", "wallet_seed": "Phrase secrète (seed) du portefeuille (wallet)",
"wallet_seed_legacy": "Graine de portefeuille hérité", "wallet_seed_legacy": "Graine de portefeuille hérité",

View file

@ -845,6 +845,7 @@
"wallet_menu": "Menu", "wallet_menu": "Menu",
"wallet_name": "Sunan walat", "wallet_name": "Sunan walat",
"wallet_name_exists": "Wallet mai wannan sunan ya riga ya wanzu. Da fatan za a zaɓi wani suna daban ko sake suna ɗayan walat tukuna.", "wallet_name_exists": "Wallet mai wannan sunan ya riga ya wanzu. Da fatan za a zaɓi wani suna daban ko sake suna ɗayan walat tukuna.",
"wallet_recovery_height": "Mai Tsaro",
"wallet_restoration_store_incorrect_seed_length": "kalmar sirrin iri ba daidai ba", "wallet_restoration_store_incorrect_seed_length": "kalmar sirrin iri ba daidai ba",
"wallet_seed": "kalmar sirri na walat", "wallet_seed": "kalmar sirri na walat",
"wallet_seed_legacy": "Tallarin walat walat", "wallet_seed_legacy": "Tallarin walat walat",

View file

@ -845,6 +845,7 @@
"wallet_menu": "बटुआ मेनू", "wallet_menu": "बटुआ मेनू",
"wallet_name": "बटुए का नाम", "wallet_name": "बटुए का नाम",
"wallet_name_exists": "उस नाम वाला वॉलेट पहले से मौजूद है", "wallet_name_exists": "उस नाम वाला वॉलेट पहले से मौजूद है",
"wallet_recovery_height": "वसूली ऊंचाई",
"wallet_restoration_store_incorrect_seed_length": "गलत बीज की लंबाई", "wallet_restoration_store_incorrect_seed_length": "गलत बीज की लंबाई",
"wallet_seed": "बटुआ का बीज", "wallet_seed": "बटुआ का बीज",
"wallet_seed_legacy": "विरासत बटुए बीज", "wallet_seed_legacy": "विरासत बटुए बीज",

View file

@ -843,6 +843,7 @@
"wallet_menu": "Izbornik", "wallet_menu": "Izbornik",
"wallet_name": "Ime novčanika", "wallet_name": "Ime novčanika",
"wallet_name_exists": "Novčanik s tim nazivom već postoji", "wallet_name_exists": "Novčanik s tim nazivom već postoji",
"wallet_recovery_height": "Visina oporavka",
"wallet_restoration_store_incorrect_seed_length": "Netočna dužina pristupnog izraza", "wallet_restoration_store_incorrect_seed_length": "Netočna dužina pristupnog izraza",
"wallet_seed": "Pristupni izraz novčanika", "wallet_seed": "Pristupni izraz novčanika",
"wallet_seed_legacy": "Sjeme naslijeđenog novčanika", "wallet_seed_legacy": "Sjeme naslijeđenog novčanika",

View file

@ -846,6 +846,7 @@
"wallet_menu": "Menu", "wallet_menu": "Menu",
"wallet_name": "Nama Dompet", "wallet_name": "Nama Dompet",
"wallet_name_exists": "Nama dompet sudah ada. Silakan pilih nama yang berbeda atau ganti nama dompet yang lain terlebih dahulu.", "wallet_name_exists": "Nama dompet sudah ada. Silakan pilih nama yang berbeda atau ganti nama dompet yang lain terlebih dahulu.",
"wallet_recovery_height": "Tinggi pemulihan",
"wallet_restoration_store_incorrect_seed_length": "Panjang seed yang salah", "wallet_restoration_store_incorrect_seed_length": "Panjang seed yang salah",
"wallet_seed": "Seed dompet", "wallet_seed": "Seed dompet",
"wallet_seed_legacy": "Biji dompet warisan", "wallet_seed_legacy": "Biji dompet warisan",

View file

@ -846,6 +846,7 @@
"wallet_menu": "Menù", "wallet_menu": "Menù",
"wallet_name": "Nome del Portafoglio", "wallet_name": "Nome del Portafoglio",
"wallet_name_exists": "Il portafoglio con quel nome è già esistito", "wallet_name_exists": "Il portafoglio con quel nome è già esistito",
"wallet_recovery_height": "Altezza di recupero",
"wallet_restoration_store_incorrect_seed_length": "Lunghezza seme non corretta", "wallet_restoration_store_incorrect_seed_length": "Lunghezza seme non corretta",
"wallet_seed": "Seme Portafoglio", "wallet_seed": "Seme Portafoglio",
"wallet_seed_legacy": "Seme di portafoglio legacy", "wallet_seed_legacy": "Seme di portafoglio legacy",

View file

@ -844,6 +844,7 @@
"wallet_menu": "ウォレットメニュー", "wallet_menu": "ウォレットメニュー",
"wallet_name": "ウォレット名", "wallet_name": "ウォレット名",
"wallet_name_exists": "その名前のウォレットはすでに存在しています", "wallet_name_exists": "その名前のウォレットはすでに存在しています",
"wallet_recovery_height": "回復の高さ",
"wallet_restoration_store_incorrect_seed_length": "誤ったシード長s", "wallet_restoration_store_incorrect_seed_length": "誤ったシード長s",
"wallet_seed": "ウォレットシード", "wallet_seed": "ウォレットシード",
"wallet_seed_legacy": "レガシーウォレットシード", "wallet_seed_legacy": "レガシーウォレットシード",

View file

@ -844,6 +844,7 @@
"wallet_menu": "월렛 메뉴", "wallet_menu": "월렛 메뉴",
"wallet_name": "지갑 이름", "wallet_name": "지갑 이름",
"wallet_name_exists": "해당 이름의 지갑이 이미 존재합니다.", "wallet_name_exists": "해당 이름의 지갑이 이미 존재합니다.",
"wallet_recovery_height": "복구 높이",
"wallet_restoration_store_incorrect_seed_length": "시드 길이가 잘못되었습니다", "wallet_restoration_store_incorrect_seed_length": "시드 길이가 잘못되었습니다",
"wallet_seed": "지갑 시드", "wallet_seed": "지갑 시드",
"wallet_seed_legacy": "레거시 지갑 시드", "wallet_seed_legacy": "레거시 지갑 시드",

View file

@ -843,6 +843,7 @@
"wallet_menu": "မီနူး", "wallet_menu": "မီနူး",
"wallet_name": "ပိုက်ဆံအိတ်နာမည", "wallet_name": "ပိုက်ဆံအိတ်နာမည",
"wallet_name_exists": "ထိုအမည်ဖြင့် ပိုက်ဆံအိတ်တစ်ခု ရှိနှင့်ပြီးဖြစ်သည်။ အခြားအမည်တစ်ခုကို ရွေးပါ သို့မဟုတ် အခြားပိုက်ဆံအိတ်ကို ဦးစွာ အမည်ပြောင်းပါ။", "wallet_name_exists": "ထိုအမည်ဖြင့် ပိုက်ဆံအိတ်တစ်ခု ရှိနှင့်ပြီးဖြစ်သည်။ အခြားအမည်တစ်ခုကို ရွေးပါ သို့မဟုတ် အခြားပိုက်ဆံအိတ်ကို ဦးစွာ အမည်ပြောင်းပါ။",
"wallet_recovery_height": "ပြန်လည်ထူထောင်ရေးအမြင့်",
"wallet_restoration_store_incorrect_seed_length": "မျိုးစေ့အရှည် မမှန်ပါ။", "wallet_restoration_store_incorrect_seed_length": "မျိုးစေ့အရှည် မမှန်ပါ။",
"wallet_seed": "ပိုက်ဆံအိတ်စေ့", "wallet_seed": "ပိုက်ဆံအိတ်စေ့",
"wallet_seed_legacy": "အမွေအနှစ်ပိုက်ဆံအိတ်မျိုးစေ့", "wallet_seed_legacy": "အမွေအနှစ်ပိုက်ဆံအိတ်မျိုးစေ့",

View file

@ -844,6 +844,7 @@
"wallet_menu": "Portemonnee-menu", "wallet_menu": "Portemonnee-menu",
"wallet_name": "Portemonnee naam", "wallet_name": "Portemonnee naam",
"wallet_name_exists": "Portemonnee met die naam bestaat al", "wallet_name_exists": "Portemonnee met die naam bestaat al",
"wallet_recovery_height": "Herstelhoogte",
"wallet_restoration_store_incorrect_seed_length": "Onjuiste zaadlengte", "wallet_restoration_store_incorrect_seed_length": "Onjuiste zaadlengte",
"wallet_seed": "Portemonnee zaad", "wallet_seed": "Portemonnee zaad",
"wallet_seed_legacy": "Legacy portemonnee zaad", "wallet_seed_legacy": "Legacy portemonnee zaad",

View file

@ -843,6 +843,7 @@
"wallet_menu": "Menu portfela", "wallet_menu": "Menu portfela",
"wallet_name": "Nazwa portfela", "wallet_name": "Nazwa portfela",
"wallet_name_exists": "Portfel o tej nazwie już istnieje", "wallet_name_exists": "Portfel o tej nazwie już istnieje",
"wallet_recovery_height": "Wysokość odzysku",
"wallet_restoration_store_incorrect_seed_length": "Nieprawidłowa długość frazy seed", "wallet_restoration_store_incorrect_seed_length": "Nieprawidłowa długość frazy seed",
"wallet_seed": "Seed portfela", "wallet_seed": "Seed portfela",
"wallet_seed_legacy": "Dziedziczne ziarno portfela", "wallet_seed_legacy": "Dziedziczne ziarno portfela",

View file

@ -846,6 +846,7 @@
"wallet_menu": "Menu", "wallet_menu": "Menu",
"wallet_name": "Nome da carteira", "wallet_name": "Nome da carteira",
"wallet_name_exists": "A carteira com esse nome já existe", "wallet_name_exists": "A carteira com esse nome já existe",
"wallet_recovery_height": "Altura de recuperação",
"wallet_restoration_store_incorrect_seed_length": "Comprimento de semente incorreto", "wallet_restoration_store_incorrect_seed_length": "Comprimento de semente incorreto",
"wallet_seed": "Semente de carteira", "wallet_seed": "Semente de carteira",
"wallet_seed_legacy": "Semente de carteira herdada", "wallet_seed_legacy": "Semente de carteira herdada",

View file

@ -844,6 +844,7 @@
"wallet_menu": "Меню кошелька", "wallet_menu": "Меню кошелька",
"wallet_name": "Имя кошелька", "wallet_name": "Имя кошелька",
"wallet_name_exists": "Кошелек с таким именем уже существует", "wallet_name_exists": "Кошелек с таким именем уже существует",
"wallet_recovery_height": "Высота восстановления",
"wallet_restoration_store_incorrect_seed_length": "Неверная длина мнемонической фразы", "wallet_restoration_store_incorrect_seed_length": "Неверная длина мнемонической фразы",
"wallet_seed": "Мнемоническая фраза кошелька", "wallet_seed": "Мнемоническая фраза кошелька",
"wallet_seed_legacy": "Наследие семя кошелька", "wallet_seed_legacy": "Наследие семя кошелька",

View file

@ -843,6 +843,7 @@
"wallet_menu": "เมนู", "wallet_menu": "เมนู",
"wallet_name": "ชื่อกระเป๋า", "wallet_name": "ชื่อกระเป๋า",
"wallet_name_exists": "กระเป๋าที่มีชื่อนี้มีอยู่แล้ว โปรดเลือกชื่ออื่นหรือเปลี่ยนชื่อกระเป๋าอื่นก่อน", "wallet_name_exists": "กระเป๋าที่มีชื่อนี้มีอยู่แล้ว โปรดเลือกชื่ออื่นหรือเปลี่ยนชื่อกระเป๋าอื่นก่อน",
"wallet_recovery_height": "ความสูงของการกู้คืน",
"wallet_restoration_store_incorrect_seed_length": "ความยาวของซีดไม่ถูกต้อง", "wallet_restoration_store_incorrect_seed_length": "ความยาวของซีดไม่ถูกต้อง",
"wallet_seed": "ซีดของกระเป๋า", "wallet_seed": "ซีดของกระเป๋า",
"wallet_seed_legacy": "เมล็ดกระเป๋าเงินมรดก", "wallet_seed_legacy": "เมล็ดกระเป๋าเงินมรดก",

View file

@ -843,6 +843,7 @@
"wallet_menu": "Menu", "wallet_menu": "Menu",
"wallet_name": "Pangalan ng Wallet", "wallet_name": "Pangalan ng Wallet",
"wallet_name_exists": "Ang isang pitaka na may pangalang iyon ay mayroon na. Mangyaring pumili ng ibang pangalan o palitan muna ang iba pang pitaka.", "wallet_name_exists": "Ang isang pitaka na may pangalang iyon ay mayroon na. Mangyaring pumili ng ibang pangalan o palitan muna ang iba pang pitaka.",
"wallet_recovery_height": "Taas ng pagbawi",
"wallet_restoration_store_incorrect_seed_length": "Maling haba ng binhi", "wallet_restoration_store_incorrect_seed_length": "Maling haba ng binhi",
"wallet_seed": "SEED ng Wallet", "wallet_seed": "SEED ng Wallet",
"wallet_seed_legacy": "Legacy wallet seed", "wallet_seed_legacy": "Legacy wallet seed",

View file

@ -843,6 +843,7 @@
"wallet_menu": "Menü", "wallet_menu": "Menü",
"wallet_name": "Cüzdan ismi", "wallet_name": "Cüzdan ismi",
"wallet_name_exists": "Bu isimde bir cüzdan zaten mevcut. Lütfen farklı bir isim seç veya önce diğer cüzdanı yeniden adlandır.", "wallet_name_exists": "Bu isimde bir cüzdan zaten mevcut. Lütfen farklı bir isim seç veya önce diğer cüzdanı yeniden adlandır.",
"wallet_recovery_height": "Kurtarma Yüksekliği",
"wallet_restoration_store_incorrect_seed_length": "Yanlış tohum uzunluğu", "wallet_restoration_store_incorrect_seed_length": "Yanlış tohum uzunluğu",
"wallet_seed": "Cüzdan tohumu", "wallet_seed": "Cüzdan tohumu",
"wallet_seed_legacy": "Eski cüzdan tohumu", "wallet_seed_legacy": "Eski cüzdan tohumu",

View file

@ -844,6 +844,7 @@
"wallet_menu": "Меню гаманця", "wallet_menu": "Меню гаманця",
"wallet_name": "Ім'я гаманця", "wallet_name": "Ім'я гаманця",
"wallet_name_exists": "Гаманець з такою назвою вже існує", "wallet_name_exists": "Гаманець з такою назвою вже існує",
"wallet_recovery_height": "Висота відновлення",
"wallet_restoration_store_incorrect_seed_length": "Невірна довжина мнемонічної фрази", "wallet_restoration_store_incorrect_seed_length": "Невірна довжина мнемонічної фрази",
"wallet_seed": "Мнемонічна фраза гаманця", "wallet_seed": "Мнемонічна фраза гаманця",
"wallet_seed_legacy": "Спадець насіння гаманця", "wallet_seed_legacy": "Спадець насіння гаманця",

View file

@ -845,6 +845,7 @@
"wallet_menu": "مینو", "wallet_menu": "مینو",
"wallet_name": "بٹوے کا نام", "wallet_name": "بٹوے کا نام",
"wallet_name_exists": "اس نام کا پرس پہلے سے موجود ہے۔ براہ کرم ایک مختلف نام منتخب کریں یا پہلے دوسرے بٹوے کا نام تبدیل کریں۔", "wallet_name_exists": "اس نام کا پرس پہلے سے موجود ہے۔ براہ کرم ایک مختلف نام منتخب کریں یا پہلے دوسرے بٹوے کا نام تبدیل کریں۔",
"wallet_recovery_height": "بحالی کی اونچائی",
"wallet_restoration_store_incorrect_seed_length": "غلط بیج کی لمبائی", "wallet_restoration_store_incorrect_seed_length": "غلط بیج کی لمبائی",
"wallet_seed": "بٹوے کا بیج", "wallet_seed": "بٹوے کا بیج",
"wallet_seed_legacy": "میراثی پرس کا بیج", "wallet_seed_legacy": "میراثی پرس کا بیج",

View file

@ -844,6 +844,7 @@
"wallet_menu": "Mẹ́nù", "wallet_menu": "Mẹ́nù",
"wallet_name": "Orúkọ àpamọ́wọ́", "wallet_name": "Orúkọ àpamọ́wọ́",
"wallet_name_exists": "Ẹ ti ní àpamọ́wọ́ pẹ̀lú orúkọ̀ yẹn. Ẹ jọ̀wọ́ yàn orúkọ̀ tó yàtọ̀ tàbí pààrọ̀ orúkọ ti àpamọ́wọ́ tẹ́lẹ̀.", "wallet_name_exists": "Ẹ ti ní àpamọ́wọ́ pẹ̀lú orúkọ̀ yẹn. Ẹ jọ̀wọ́ yàn orúkọ̀ tó yàtọ̀ tàbí pààrọ̀ orúkọ ti àpamọ́wọ́ tẹ́lẹ̀.",
"wallet_recovery_height": "Iga Imularada",
"wallet_restoration_store_incorrect_seed_length": "Gígùn hóró tí a máa ń lò kọ́ ni èyí", "wallet_restoration_store_incorrect_seed_length": "Gígùn hóró tí a máa ń lò kọ́ ni èyí",
"wallet_seed": "Hóró àpamọ́wọ́", "wallet_seed": "Hóró àpamọ́wọ́",
"wallet_seed_legacy": "Irugbin akole", "wallet_seed_legacy": "Irugbin akole",

View file

@ -843,6 +843,7 @@
"wallet_menu": "钱包菜单", "wallet_menu": "钱包菜单",
"wallet_name": "钱包名称", "wallet_name": "钱包名称",
"wallet_name_exists": "同名的钱包已经存在", "wallet_name_exists": "同名的钱包已经存在",
"wallet_recovery_height": "恢复高度",
"wallet_restoration_store_incorrect_seed_length": "种子长度错误", "wallet_restoration_store_incorrect_seed_length": "种子长度错误",
"wallet_seed": "钱包种子", "wallet_seed": "钱包种子",
"wallet_seed_legacy": "旧的钱包种子", "wallet_seed_legacy": "旧的钱包种子",

View file

@ -191,6 +191,7 @@ abstract class Bitcoin {
{required String mnemonic, required Node node}); {required String mnemonic, required Node node});
Future<List<DerivationInfo>> getDerivationsFromMnemonic( Future<List<DerivationInfo>> getDerivationsFromMnemonic(
{required String mnemonic, required Node node, String? passphrase}); {required String mnemonic, required Node node, String? passphrase});
Map<DerivationType, List<DerivationInfo>> getElectrumDerivations();
Future<void> setAddressType(Object wallet, dynamic option); Future<void> setAddressType(Object wallet, dynamic option);
ReceivePageOption getSelectedAddressType(Object wallet); ReceivePageOption getSelectedAddressType(Object wallet);
List<ReceivePageOption> getBitcoinReceivePageOptions(); List<ReceivePageOption> getBitcoinReceivePageOptions();
@ -367,6 +368,7 @@ abstract class Monero {
WalletCredentials createMoneroRestoreWalletFromSeedCredentials({required String name, required String password, required int height, required String mnemonic}); WalletCredentials createMoneroRestoreWalletFromSeedCredentials({required String name, required String password, required int height, required String mnemonic});
WalletCredentials createMoneroNewWalletCredentials({required String name, required String language, required bool isPolyseed, String password}); WalletCredentials createMoneroNewWalletCredentials({required String name, required String language, required bool isPolyseed, String password});
Map<String, String> getKeys(Object wallet); Map<String, String> getKeys(Object wallet);
int? getRestoreHeight(Object wallet);
Object createMoneroTransactionCreationCredentials({required List<Output> outputs, required TransactionPriority priority}); Object createMoneroTransactionCreationCredentials({required List<Output> outputs, required TransactionPriority priority});
Object createMoneroTransactionCreationCredentialsRaw({required List<OutputInfo> outputs, required TransactionPriority priority}); Object createMoneroTransactionCreationCredentialsRaw({required List<OutputInfo> outputs, required TransactionPriority priority});
String formatterMoneroAmountToString({required int amount}); String formatterMoneroAmountToString({required int amount});
@ -670,6 +672,7 @@ abstract class Ethereum {
List<Erc20Token> getERC20Currencies(WalletBase wallet); List<Erc20Token> getERC20Currencies(WalletBase wallet);
Future<void> addErc20Token(WalletBase wallet, CryptoCurrency token); Future<void> addErc20Token(WalletBase wallet, CryptoCurrency token);
Future<void> deleteErc20Token(WalletBase wallet, CryptoCurrency token); Future<void> deleteErc20Token(WalletBase wallet, CryptoCurrency token);
Future<void> removeTokenTransactionsInHistory(WalletBase wallet, CryptoCurrency token);
Future<Erc20Token?> getErc20Token(WalletBase wallet, String contractAddress); Future<Erc20Token?> getErc20Token(WalletBase wallet, String contractAddress);
CryptoCurrency assetOfTransaction(WalletBase wallet, TransactionInfo transaction); CryptoCurrency assetOfTransaction(WalletBase wallet, TransactionInfo transaction);
@ -773,6 +776,7 @@ abstract class Polygon {
List<Erc20Token> getERC20Currencies(WalletBase wallet); List<Erc20Token> getERC20Currencies(WalletBase wallet);
Future<void> addErc20Token(WalletBase wallet, CryptoCurrency token); Future<void> addErc20Token(WalletBase wallet, CryptoCurrency token);
Future<void> deleteErc20Token(WalletBase wallet, CryptoCurrency token); Future<void> deleteErc20Token(WalletBase wallet, CryptoCurrency token);
Future<void> removeTokenTransactionsInHistory(WalletBase wallet, CryptoCurrency token);
Future<Erc20Token?> getErc20Token(WalletBase wallet, String contractAddress); Future<Erc20Token?> getErc20Token(WalletBase wallet, String contractAddress);
CryptoCurrency assetOfTransaction(WalletBase wallet, TransactionInfo transaction); CryptoCurrency assetOfTransaction(WalletBase wallet, TransactionInfo transaction);