From afcfab9796a33a895f1aafea7401340fb7366a30 Mon Sep 17 00:00:00 2001 From: Serhii Date: Mon, 14 Aug 2023 13:36:25 +0300 Subject: [PATCH] creating and restoring a wallet --- assets/bitcoin_cash_electrum_server_list.yml | 3 + cw_bitcoin/lib/electrum_wallet.dart | 270 +++++++++--------- cw_core/lib/node.dart | 4 + cw_core/lib/wallet_type.dart | 2 +- cw_haven/pubspec.lock | 2 +- lib/bitcoin_cash/cw_bitcoin_cash.dart | 158 +--------- lib/core/seed_validator.dart | 2 + lib/di.dart | 3 + lib/entities/default_settings_migration.dart | 43 +++ lib/entities/node_list.dart | 24 +- lib/entities/preferences_key.dart | 1 + lib/main.dart | 2 +- .../dashboard/widgets/menu_widget.dart | 6 +- .../screens/wallet_list/wallet_list_page.dart | 39 +-- lib/store/settings_store.dart | 39 ++- .../node_list/node_list_view_model.dart | 3 + .../wallet_address_list_view_model.dart | 22 ++ lib/view_model/wallet_keys_view_model.dart | 2 + lib/view_model/wallet_new_vm.dart | 5 +- lib/view_model/wallet_restore_view_model.dart | 6 + pubspec_base.yaml | 1 + tool/configure.dart | 18 +- 22 files changed, 332 insertions(+), 323 deletions(-) create mode 100644 assets/bitcoin_cash_electrum_server_list.yml diff --git a/assets/bitcoin_cash_electrum_server_list.yml b/assets/bitcoin_cash_electrum_server_list.yml new file mode 100644 index 000000000..d76668169 --- /dev/null +++ b/assets/bitcoin_cash_electrum_server_list.yml @@ -0,0 +1,3 @@ +- + uri: bitcoincash.stackwallet.com:50002 + is_default: true \ No newline at end of file diff --git a/cw_bitcoin/lib/electrum_wallet.dart b/cw_bitcoin/lib/electrum_wallet.dart index f9437e668..ad998c724 100644 --- a/cw_bitcoin/lib/electrum_wallet.dart +++ b/cw_bitcoin/lib/electrum_wallet.dart @@ -2,7 +2,9 @@ import 'dart:async'; import 'dart:convert'; import 'dart:io'; import 'dart:math'; +import 'package:bitcoin_flutter/bitcoin_flutter.dart'; import 'package:cw_core/unspent_coins_info.dart'; +import 'package:cw_core/wallet_type.dart'; import 'package:hive/hive.dart'; import 'package:cw_bitcoin/electrum_wallet_addresses.dart'; import 'package:mobx/mobx.dart'; @@ -34,45 +36,63 @@ import 'package:cw_bitcoin/electrum.dart'; import 'package:hex/hex.dart'; import 'package:cw_core/crypto_currency.dart'; import 'package:collection/collection.dart'; +import 'package:bip32/bip32.dart'; part 'electrum_wallet.g.dart'; class ElectrumWallet = ElectrumWalletBase with _$ElectrumWallet; -abstract class ElectrumWalletBase extends WalletBase with Store { +abstract class ElectrumWalletBase + extends WalletBase + with Store { ElectrumWalletBase( {required String password, - required WalletInfo walletInfo, - required Box unspentCoinsInfo, - required this.networkType, - required this.mnemonic, - required Uint8List seedBytes, - List? initialAddresses, - ElectrumClient? electrumClient, - ElectrumBalance? initialBalance, - CryptoCurrency? currency}) - : hd = bitcoin.HDWallet.fromSeed(seedBytes, network: networkType) - .derivePath("m/0'/0"), + required WalletInfo walletInfo, + required Box unspentCoinsInfo, + required this.networkType, + required this.mnemonic, + required Uint8List seedBytes, + List? initialAddresses, + ElectrumClient? electrumClient, + ElectrumBalance? initialBalance, + CryptoCurrency? currency}) + : hd = currency == CryptoCurrency.bch + ? bitcoinCashHDWallet(seedBytes) + : bitcoin.HDWallet.fromSeed(seedBytes, network: networkType).derivePath("m/0'/0"), syncStatus = NotConnectedSyncStatus(), _password = password, _feeRates = [], _isTransactionUpdating = false, unspentCoins = [], _scripthashesUpdateSubject = {}, - balance = ObservableMap.of( - currency != null - ? {currency: initialBalance ?? const ElectrumBalance(confirmed: 0, unconfirmed: 0, - frozen: 0)} - : {}), + balance = ObservableMap.of(currency != null + ? { + currency: + initialBalance ?? const ElectrumBalance(confirmed: 0, unconfirmed: 0, frozen: 0) + } + : {}), this.unspentCoinsInfo = unspentCoinsInfo, super(walletInfo) { this.electrumClient = electrumClient ?? ElectrumClient(); this.walletInfo = walletInfo; - transactionHistory = - ElectrumTransactionHistory(walletInfo: walletInfo, password: password); + transactionHistory = ElectrumTransactionHistory(walletInfo: walletInfo, password: password); } + static bitcoin.NetworkType bitcoinCashNetworkType = bitcoin.NetworkType( + messagePrefix: '\x18Bitcoin Signed Message:\n', + bech32: 'bc', + bip32: bitcoin.Bip32Type( + public: 0x0488b21e, + private: 0x0488ade4, + ), + pubKeyHash: 0x00, + scriptHash: 0x05, + wif: 0x80); + + static HDWallet bitcoinCashHDWallet(Uint8List seedBytes) => + bitcoin.HDWallet.fromSeed(seedBytes, network: bitcoinCashNetworkType) + .derivePath("m/44'/145'/0'/0/0"); + static int estimatedTransactionSize(int inputsCount, int outputsCounts) => inputsCount * 146 + outputsCounts * 33 + 8; @@ -98,9 +118,9 @@ abstract class ElectrumWalletBase extends WalletBase get publicScriptHashes => walletAddresses.addresses - .where((addr) => !addr.isHidden) - .map((addr) => scriptHash(addr.address, networkType: networkType)) - .toList(); + .where((addr) => !addr.isHidden) + .map((addr) => scriptHash(addr.address, networkType: networkType)) + .toList(); String get xpub => hd.base58!; @@ -110,8 +130,8 @@ abstract class ElectrumWalletBase extends WalletBase BitcoinWalletKeys( - wif: hd.wif!, privateKey: hd.privKey!, publicKey: hd.pubKey!); + BitcoinWalletKeys get keys => + BitcoinWalletKeys(wif: hd.wif!, privateKey: hd.privKey!, publicKey: hd.pubKey!); String _password; List unspentCoins; @@ -132,15 +152,17 @@ abstract class ElectrumWalletBase extends WalletBase startSync() async { try { syncStatus = AttemptingSyncStatus(); - await walletAddresses.discoverAddresses(); + if (walletInfo.type != WalletType.bitcoinCash) { //TODO: BCH: remove this check when supported + await walletAddresses.discoverAddresses(); + } await updateTransactions(); _subscribeForUpdates(); await updateUnspent(); await updateBalance(); _feeRates = await electrumClient.feeRates(); - Timer.periodic(const Duration(minutes: 1), - (timer) async => _feeRates = await electrumClient.feeRates()); + Timer.periodic( + const Duration(minutes: 1), (timer) async => _feeRates = await electrumClient.feeRates()); syncStatus = SyncedSyncStatus(); } catch (e, stacktrace) { @@ -169,8 +191,7 @@ abstract class ElectrumWalletBase extends WalletBase createTransaction( - Object credentials) async { + Future createTransaction(Object credentials) async { const minAmount = 546; final transactionCredentials = credentials as BitcoinTransactionCredentials; final inputs = []; @@ -204,13 +225,11 @@ abstract class ElectrumWalletBase extends WalletBase item.sendAll - || item.formattedCryptoAmount! <= 0)) { + if (outputs.any((item) => item.sendAll || item.formattedCryptoAmount! <= 0)) { throw BitcoinTransactionWrongBalanceException(currency); } - credentialsAmount = outputs.fold(0, (acc, value) => - acc + value.formattedCryptoAmount!); + credentialsAmount = outputs.fold(0, (acc, value) => acc + value.formattedCryptoAmount!); if (allAmount - credentialsAmount < minAmount) { throw BitcoinTransactionWrongBalanceException(currency); @@ -227,9 +246,7 @@ abstract class ElectrumWalletBase extends WalletBase allAmount) { throw BitcoinTransactionWrongBalanceException(currency); @@ -291,8 +308,8 @@ abstract class ElectrumWalletBase extends WalletBase json.encode({ - 'mnemonic': mnemonic, - 'account_index': walletAddresses.currentReceiveAddressIndex.toString(), - 'change_address_index': walletAddresses.currentChangeAddressIndex.toString(), - 'addresses': walletAddresses.addresses.map((addr) => addr.toJSON()).toList(), - 'balance': balance[currency]?.toJSON() - }); + 'mnemonic': mnemonic, + 'account_index': walletAddresses.currentReceiveAddressIndex.toString(), + 'change_address_index': walletAddresses.currentChangeAddressIndex.toString(), + 'addresses': walletAddresses.addresses.map((addr) => addr.toJSON()).toList(), + 'balance': balance[currency]?.toJSON() + }); int feeRate(TransactionPriority priority) { try { @@ -364,34 +374,29 @@ abstract class ElectrumWalletBase extends WalletBase + int feeAmountForPriority( + BitcoinTransactionPriority priority, int inputsCount, int outputsCount) => feeRate(priority) * estimatedTransactionSize(inputsCount, outputsCount); - int feeAmountWithFeeRate(int feeRate, int inputsCount, - int outputsCount) => + int feeAmountWithFeeRate(int feeRate, int inputsCount, int outputsCount) => feeRate * estimatedTransactionSize(inputsCount, outputsCount); @override - int calculateEstimatedFee(TransactionPriority? priority, int? amount, - {int? outputsCount}) { + int calculateEstimatedFee(TransactionPriority? priority, int? amount, {int? outputsCount}) { if (priority is BitcoinTransactionPriority) { - return calculateEstimatedFeeWithFeeRate( - feeRate(priority), - amount, - outputsCount: outputsCount); + return calculateEstimatedFeeWithFeeRate(feeRate(priority), amount, + outputsCount: outputsCount); } return 0; } - int calculateEstimatedFeeWithFeeRate(int feeRate, int? amount, - {int? outputsCount}) { + int calculateEstimatedFeeWithFeeRate(int feeRate, int? amount, {int? outputsCount}) { int inputsCount = 0; if (amount != null) { @@ -420,8 +425,7 @@ abstract class ElectrumWalletBase extends WalletBase makePath() async => - pathForWallet(name: walletInfo.name, type: walletInfo.type); + Future makePath() async => pathForWallet(name: walletInfo.name, type: walletInfo.type); Future updateUnspent() async { - final unspent = await Future.wait(walletAddresses - .addresses.map((address) => electrumClient + final unspent = await Future.wait(walletAddresses.addresses.map((address) => electrumClient .getListUnspentWithAddress(address.address, networkType) - .then((unspent) => unspent - .map((unspent) { - try { - return BitcoinUnspent.fromJSON(address, unspent); - } catch(_) { - return null; - } - }).whereNotNull()))); + .then((unspent) => unspent.map((unspent) { + try { + return BitcoinUnspent.fromJSON(address, unspent); + } catch (_) { + return null; + } + }).whereNotNull()))); unspentCoins = unspent.expand((e) => e).toList(); if (unspentCoinsInfo.isEmpty) { @@ -498,8 +498,8 @@ abstract class ElectrumWalletBase extends WalletBase - element.walletId.contains(id) && element.hash.contains(coin.hash)); + final coinInfoList = unspentCoinsInfo.values + .where((element) => element.walletId.contains(id) && element.hash.contains(coin.hash)); if (coinInfoList.isNotEmpty) { final coinInfo = coinInfoList.first; @@ -518,14 +518,14 @@ abstract class ElectrumWalletBase extends WalletBase _addCoinInfo(BitcoinUnspent coin) async { final newInfo = UnspentCoinsInfo( - walletId: id, - hash: coin.hash, - isFrozen: coin.isFrozen, - isSending: coin.isSending, - noteRaw: coin.note, - address: coin.address.address, - value: coin.value, - vout: coin.vout, + walletId: id, + hash: coin.hash, + isFrozen: coin.isFrozen, + isSending: coin.isSending, + noteRaw: coin.note, + address: coin.address.address, + value: coin.value, + vout: coin.vout, ); await unspentCoinsInfo.add(newInfo); @@ -534,8 +534,8 @@ abstract class ElectrumWalletBase extends WalletBase _refreshUnspentCoinsInfo() async { try { final List keys = []; - final currentWalletUnspentCoins = unspentCoinsInfo.values - .where((element) => element.walletId.contains(id)); + final currentWalletUnspentCoins = + unspentCoinsInfo.values.where((element) => element.walletId.contains(id)); if (currentWalletUnspentCoins.isNotEmpty) { currentWalletUnspentCoins.forEach((element) { @@ -571,27 +571,19 @@ abstract class ElectrumWalletBase extends WalletBase fetchTransactionInfo( {required String hash, required int height}) async { - try { - final tx = await getTransactionExpanded(hash: hash, height: height); - final addresses = walletAddresses.addresses.map((addr) => addr.address).toSet(); - return ElectrumTransactionInfo.fromElectrumBundle( - tx, - walletInfo.type, - networkType, - addresses: addresses, - height: height); - } catch(_) { - return null; - } + try { + final tx = await getTransactionExpanded(hash: hash, height: height); + final addresses = walletAddresses.addresses.map((addr) => addr.address).toSet(); + return ElectrumTransactionInfo.fromElectrumBundle(tx, walletInfo.type, networkType, + addresses: addresses, height: height); + } catch (_) { + return null; + } } @override @@ -602,10 +594,8 @@ abstract class ElectrumWalletBase extends WalletBase electrumClient - .getHistory(scriptHash) - .then((history) => {scriptHash: history})); + final histories = addressHashes.keys.map((scriptHash) => + electrumClient.getHistory(scriptHash).then((history) => {scriptHash: history})); final historyResults = await Future.wait(histories); historyResults.forEach((history) { history.entries.forEach((historyItem) { @@ -616,19 +606,16 @@ abstract class ElectrumWalletBase extends WalletBase>( - {}, (acc, tx) { + final historiesWithDetails = await Future.wait(normalizedHistories.map((transaction) { + try { + return fetchTransactionInfo( + hash: transaction['tx_hash'] as String, height: transaction['height'] as int); + } catch (_) { + return Future.value(null); + } + })); + return historiesWithDetails + .fold>({}, (acc, tx) { if (tx == null) { return acc; } @@ -680,8 +667,11 @@ abstract class ElectrumWalletBase extends WalletBase _fetchBalances() async { final addresses = walletAddresses.addresses.toList(); final balanceFutures = >>[]; + var counter = addresses.length; - for (var i = 0; i < addresses.length; i++) { + if (walletInfo.type == WalletType.bitcoinCash) counter = 1; //TODO: BCH: remove this check when supported + + for (var i = 0; i < counter; i++) { final addressRecord = addresses[i]; final sh = scriptHash(addressRecord.address, networkType: networkType); final balanceFuture = electrumClient.getBalance(sh); @@ -691,8 +681,10 @@ abstract class ElectrumWalletBase extends WalletBase updateBalance() async { @@ -727,9 +719,7 @@ abstract class ElectrumWalletBase extends WalletBase addr.isHidden) - .toList(); + var addresses = walletAddresses.addresses.where((addr) => addr.isHidden).toList(); if (addresses.length < minCountOfHiddenAddresses) { addresses = walletAddresses.addresses.toList(); @@ -740,4 +730,4 @@ abstract class ElectrumWalletBase extends WalletBase _onError = onError; -} +} \ No newline at end of file diff --git a/cw_core/lib/node.dart b/cw_core/lib/node.dart index 59a1450f6..ca42a0c77 100644 --- a/cw_core/lib/node.dart +++ b/cw_core/lib/node.dart @@ -78,6 +78,8 @@ class Node extends HiveObject with Keyable { return Uri.http(uriRaw, ''); case WalletType.ethereum: return Uri.https(uriRaw, ''); + case WalletType.bitcoinCash: + return createUriFromElectrumAddress(uriRaw); default: throw Exception('Unexpected type ${type.toString()} for Node uri'); } @@ -129,6 +131,8 @@ class Node extends HiveObject with Keyable { return requestMoneroNode(); case WalletType.ethereum: return requestElectrumServer(); + case WalletType.bitcoinCash: + return requestElectrumServer(); default: return false; } diff --git a/cw_core/lib/wallet_type.dart b/cw_core/lib/wallet_type.dart index 3555ba2ab..9b5881f87 100644 --- a/cw_core/lib/wallet_type.dart +++ b/cw_core/lib/wallet_type.dart @@ -68,7 +68,7 @@ WalletType deserializeFromInt(int raw) { return WalletType.haven; case 4: return WalletType.ethereum; - case 4: + case 5: return WalletType.bitcoinCash; default: throw Exception('Unexpected token: $raw for WalletType deserializeFromInt'); diff --git a/cw_haven/pubspec.lock b/cw_haven/pubspec.lock index a79d2d3cf..72342d7ef 100644 --- a/cw_haven/pubspec.lock +++ b/cw_haven/pubspec.lock @@ -672,5 +672,5 @@ packages: source: hosted version: "3.1.1" sdks: - dart: ">=2.19.0 <3.0.0" + dart: ">=2.19.0 <4.0.0" flutter: ">=3.0.0" diff --git a/lib/bitcoin_cash/cw_bitcoin_cash.dart b/lib/bitcoin_cash/cw_bitcoin_cash.dart index f098c5234..8d9b014ef 100644 --- a/lib/bitcoin_cash/cw_bitcoin_cash.dart +++ b/lib/bitcoin_cash/cw_bitcoin_cash.dart @@ -20,149 +20,17 @@ class CWBitcoinCash extends BitcoinCash { }) => BitcoinCashNewWalletCredentials(name: name, walletInfo: walletInfo); -// @override -// TransactionPriority getMediumTransactionPriority() => BitcoinTransactionPriority.medium; -// -// @override -// WalletCredentials createBitcoinRestoreWalletFromSeedCredentials({ -// required String name, -// required String mnemonic, -// required String password}) -// => BitcoinRestoreWalletFromSeedCredentials(name: name, mnemonic: mnemonic, password: password); -// -// @override -// WalletCredentials createBitcoinRestoreWalletFromWIFCredentials({ -// required String name, -// required String password, -// required String wif, -// WalletInfo? walletInfo}) -// => BitcoinRestoreWalletFromWIFCredentials(name: name, password: password, wif: wif, walletInfo: walletInfo); -// -// @override -// WalletCredentials createBitcoinNewWalletCredentials({ -// required String name, -// WalletInfo? walletInfo}) -// => BitcoinNewWalletCredentials(name: name, walletInfo: walletInfo); -// -// -// @override -// Map getWalletKeys(Object wallet) { -// final bitcoinWallet = wallet as ElectrumWallet; -// final keys = bitcoinWallet.keys; -// -// return { -// 'wif': keys.wif, -// 'privateKey': keys.privateKey, -// 'publicKey': keys.publicKey -// }; -// } -// -// @override -// List getTransactionPriorities() -// => BitcoinTransactionPriority.all; -// -// List getLitecoinTransactionPriorities() -// => LitecoinTransactionPriority.all; -// -// @override -// TransactionPriority deserializeBitcoinTransactionPriority(int raw) -// => BitcoinTransactionPriority.deserialize(raw: raw); -// -// @override -// TransactionPriority deserializeLitecoinTransactionPriority(int raw) -// => LitecoinTransactionPriority.deserialize(raw: raw); -// -// @override -// int getFeeRate(Object wallet, TransactionPriority priority) { -// final bitcoinWallet = wallet as ElectrumWallet; -// return bitcoinWallet.feeRate(priority); -// } -// -// @override -// Future generateNewAddress(Object wallet) async { -// final bitcoinWallet = wallet as ElectrumWallet; -// await bitcoinWallet.walletAddresses.generateNewAddress(); -// } -// -// @override -// Object createBitcoinTransactionCredentials(List outputs, {required TransactionPriority priority, int? feeRate}) -// => BitcoinTransactionCredentials( -// outputs.map((out) => OutputInfo( -// fiatAmount: out.fiatAmount, -// cryptoAmount: out.cryptoAmount, -// address: out.address, -// note: out.note, -// sendAll: out.sendAll, -// extractedAddress: out.extractedAddress, -// isParsedAddress: out.isParsedAddress, -// formattedCryptoAmount: out.formattedCryptoAmount)) -// .toList(), -// priority: priority as BitcoinTransactionPriority, -// feeRate: feeRate); -// -// @override -// Object createBitcoinTransactionCredentialsRaw(List outputs, {TransactionPriority? priority, required int feeRate}) -// => BitcoinTransactionCredentials( -// outputs, -// priority: priority != null ? priority as BitcoinTransactionPriority : null, -// feeRate: feeRate); -// -// @override -// List getAddresses(Object wallet) { -// final bitcoinWallet = wallet as ElectrumWallet; -// return bitcoinWallet.walletAddresses.addresses -// .map((BitcoinAddressRecord addr) => addr.address) -// .toList(); -// } -// -// @override -// String getAddress(Object wallet) { -// final bitcoinWallet = wallet as ElectrumWallet; -// return bitcoinWallet.walletAddresses.address; -// } -// -// @override -// String formatterBitcoinAmountToString({required int amount}) -// => bitcoinAmountToString(amount: amount); -// -// @override -// double formatterBitcoinAmountToDouble({required int amount}) -// => bitcoinAmountToDouble(amount: amount); -// -// @override -// int formatterStringDoubleToBitcoinAmount(String amount) -// => stringDoubleToBitcoinAmount(amount); -// -// @override -// String bitcoinTransactionPriorityWithLabel(TransactionPriority priority, int rate) -// => (priority as BitcoinTransactionPriority).labelWithRate(rate); -// -// void updateUnspents(Object wallet) async { -// final bitcoinWallet = wallet as ElectrumWallet; -// await bitcoinWallet.updateUnspent(); -// } -// -// WalletService createBitcoinWalletService(Box walletInfoSource, Box unspentCoinSource) { -// return BitcoinWalletService(walletInfoSource, unspentCoinSource); -// } -// -// WalletService createLitecoinWalletService(Box walletInfoSource, Box unspentCoinSource) { -// return LitecoinWalletService(walletInfoSource, unspentCoinSource); -// } -// -// @override -// TransactionPriority getBitcoinTransactionPriorityMedium() -// => BitcoinTransactionPriority.medium; -// -// @override -// TransactionPriority getLitecoinTransactionPriorityMedium() -// => LitecoinTransactionPriority.medium; -// -// @override -// TransactionPriority getBitcoinTransactionPrioritySlow() -// => BitcoinTransactionPriority.slow; -// -// @override -// TransactionPriority getLitecoinTransactionPrioritySlow() -// => LitecoinTransactionPriority.slow; + @override + WalletCredentials createBitcoinCashRestoreWalletFromSeedCredentials( + {required String name, required String mnemonic, required String password}) => + BitcoinCashRestoreWalletFromSeedCredentials( + name: name, mnemonic: mnemonic, password: password); + + @override + TransactionPriority deserializeBitcoinCashTransactionPriority(int raw) => + BitcoinCashTransactionPriority.deserialize(raw: raw); + + @override + TransactionPriority getDefaultTransactionPriority() => + throw UnimplementedError('getDefaultTransactionPriority'); } diff --git a/lib/core/seed_validator.dart b/lib/core/seed_validator.dart index eba1bbda4..9f2ffb0e2 100644 --- a/lib/core/seed_validator.dart +++ b/lib/core/seed_validator.dart @@ -28,6 +28,8 @@ class SeedValidator extends Validator { return haven!.getMoneroWordList(language); case WalletType.ethereum: return ethereum!.getEthereumWordList(language); + case WalletType.bitcoinCash: + return getBitcoinWordList(language); default: return []; } diff --git a/lib/di.dart b/lib/di.dart index 2a54c85a3..0a21a726b 100644 --- a/lib/di.dart +++ b/lib/di.dart @@ -2,6 +2,7 @@ import 'package:cake_wallet/anonpay/anonpay_api.dart'; import 'package:cake_wallet/anonpay/anonpay_info_base.dart'; import 'package:cake_wallet/anonpay/anonpay_invoice_info.dart'; import 'package:cake_wallet/buy/onramper/onramper_buy_provider.dart'; +import 'package:cake_wallet/bitcoin_cash/bitcoin_cash.dart'; import 'package:cake_wallet/buy/payfura/payfura_buy_provider.dart'; import 'package:cake_wallet/core/yat_service.dart'; import 'package:cake_wallet/entities/background_tasks.dart'; @@ -759,6 +760,8 @@ Future setup({ return bitcoin!.createLitecoinWalletService(_walletInfoSource, _unspentCoinsInfoSource!); case WalletType.ethereum: return ethereum!.createEthereumWalletService(_walletInfoSource); + case WalletType.bitcoinCash: + return bitcoinCash!.createBitcoinCashWalletService(_walletInfoSource, _unspentCoinsInfoSource!); default: throw Exception('Unexpected token: ${param1.toString()} for generating of WalletService'); } diff --git a/lib/entities/default_settings_migration.dart b/lib/entities/default_settings_migration.dart index b4cb23131..75248dd14 100644 --- a/lib/entities/default_settings_migration.dart +++ b/lib/entities/default_settings_migration.dart @@ -27,6 +27,7 @@ const cakeWalletBitcoinElectrumUri = 'electrum.cakewallet.com:50002'; const cakeWalletLitecoinElectrumUri = 'ltc-electrum.cakewallet.com:50002'; const havenDefaultNodeUri = 'nodes.havenprotocol.org:443'; const ethereumDefaultNodeUri = 'ethereum.publicnode.com'; +const cakeWalletBitcoinCashDefaultNodeUri = 'bitcoincash.stackwallet.com:50002'; Future defaultSettingsMigration( {required int version, @@ -84,6 +85,8 @@ Future defaultSettingsMigration( sharedPreferences: sharedPreferences, nodes: nodes); await changeHavenCurrentNodeToDefault( sharedPreferences: sharedPreferences, nodes: nodes); + await changeBitcoinCashCurrentNodeToDefault( + sharedPreferences: sharedPreferences, nodes: nodes); break; case 2: @@ -163,6 +166,11 @@ Future defaultSettingsMigration( await changeEthereumCurrentNodeToDefault( sharedPreferences: sharedPreferences, nodes: nodes); break; + case 22: + await addBitcoinCashElectrumServerList(nodes: nodes); + await changeBitcoinCurrentElectrumServerToDefault( + sharedPreferences: sharedPreferences, nodes: nodes); + break; default: break; @@ -255,6 +263,12 @@ Node? getEthereumDefaultNode({required Box nodes}) { ?? nodes.values.firstWhereOrNull((node) => node.type == WalletType.ethereum); } +Node? getBitcoinCashDefaultElectrumServer({required Box nodes}) { + return nodes.values.firstWhereOrNull( + (Node node) => node.uriRaw == cakeWalletBitcoinCashDefaultNodeUri) + ?? nodes.values.firstWhereOrNull((node) => node.type == WalletType.bitcoinCash); +} + Node getMoneroDefaultNode({required Box nodes}) { final timeZone = DateTime.now().timeZoneOffset.inHours; var nodeUri = ''; @@ -293,6 +307,15 @@ Future changeLitecoinCurrentElectrumServerToDefault( await sharedPreferences.setInt(PreferencesKey.currentLitecoinElectrumSererIdKey, serverId); } +Future changeBitcoinCashCurrentNodeToDefault( + {required SharedPreferences sharedPreferences, + required Box nodes}) async { + final server = getBitcoinCashDefaultElectrumServer(nodes: nodes); + final serverId = server?.key as int ?? 0; + + await sharedPreferences.setInt(PreferencesKey.currentBitcoinCashNodeIdKey, serverId); +} + Future changeHavenCurrentNodeToDefault( {required SharedPreferences sharedPreferences, required Box nodes}) async { @@ -351,6 +374,15 @@ Future addLitecoinElectrumServerList({required Box nodes}) async { } } +Future addBitcoinCashElectrumServerList({required Box nodes}) async { + final serverList = await loadBitcoinCashElectrumServerList(); + for (var node in serverList) { + if (nodes.values.firstWhereOrNull((element) => element.uriRaw == node.uriRaw) == null) { + await nodes.add(node); + } + } +} + Future addHavenNodeList({required Box nodes}) async { final nodeList = await loadDefaultHavenNodes(); for (var node in nodeList) { @@ -453,6 +485,8 @@ Future checkCurrentNodes( .getInt(PreferencesKey.currentHavenNodeIdKey); final currentEthereumNodeId = sharedPreferences .getInt(PreferencesKey.currentEthereumNodeIdKey); + final currentBitcoinCashNodeId = sharedPreferences + .getInt(PreferencesKey.currentBitcoinCashNodeIdKey); final currentMoneroNode = nodeSource.values.firstWhereOrNull( (node) => node.key == currentMoneroNodeId); final currentBitcoinElectrumServer = nodeSource.values.firstWhereOrNull( @@ -463,6 +497,8 @@ Future checkCurrentNodes( (node) => node.key == currentHavenNodeId); final currentEthereumNodeServer = nodeSource.values.firstWhereOrNull( (node) => node.key == currentEthereumNodeId); + final currentBitcoinCashNodeServer = nodeSource.values.firstWhereOrNull( + (node) => node.key == currentBitcoinCashNodeId); if (currentMoneroNode == null) { final newCakeWalletNode = @@ -503,6 +539,13 @@ Future checkCurrentNodes( await sharedPreferences.setInt( PreferencesKey.currentEthereumNodeIdKey, node.key as int); } + + if (currentBitcoinCashNodeServer == null) { + final node = Node(uri: cakeWalletBitcoinCashDefaultNodeUri, type: WalletType.bitcoinCash); + await nodeSource.add(node); + await sharedPreferences.setInt( + PreferencesKey.currentBitcoinCashNodeIdKey, node.key as int); + } } Future resetBitcoinElectrumServer( diff --git a/lib/entities/node_list.dart b/lib/entities/node_list.dart index b06351a79..a26a0bac6 100644 --- a/lib/entities/node_list.dart +++ b/lib/entities/node_list.dart @@ -66,7 +66,7 @@ Future> loadDefaultHavenNodes() async { nodes.add(node); } } - + return nodes; } @@ -86,15 +86,33 @@ Future> loadDefaultEthereumNodes() async { return nodes; } +Future> loadBitcoinCashElectrumServerList() async { + final serverListRaw = + await rootBundle.loadString('assets/bitcoin_cash_electrum_server_list.yml'); + final loadedServerList = loadYaml(serverListRaw) as YamlList; + final serverList = []; + + for (final raw in loadedServerList) { + if (raw is Map) { + final node = Node.fromMap(Map.from(raw)); + node.type = WalletType.bitcoinCash; + serverList.add(node); + } + } + + return serverList; +} + Future resetToDefault(Box nodeSource) async { final moneroNodes = await loadDefaultNodes(); final bitcoinElectrumServerList = await loadBitcoinElectrumServerList(); final litecoinElectrumServerList = await loadLitecoinElectrumServerList(); + final bitcoinCashElectrumServerList = await loadBitcoinCashElectrumServerList(); final havenNodes = await loadDefaultHavenNodes(); - final nodes = - moneroNodes + + final nodes = moneroNodes + bitcoinElectrumServerList + litecoinElectrumServerList + + bitcoinCashElectrumServerList + havenNodes; await nodeSource.clear(); diff --git a/lib/entities/preferences_key.dart b/lib/entities/preferences_key.dart index c50629c1b..2025b4356 100644 --- a/lib/entities/preferences_key.dart +++ b/lib/entities/preferences_key.dart @@ -7,6 +7,7 @@ class PreferencesKey { static const currentHavenNodeIdKey = 'current_node_id_xhv'; static const currentEthereumNodeIdKey = 'current_node_id_eth'; static const currentFiatCurrencyKey = 'current_fiat_currency'; + static const currentBitcoinCashNodeIdKey = 'current_node_id_bch'; static const currentTransactionPriorityKeyLegacy = 'current_fee_priority'; static const currentBalanceDisplayModeKey = 'current_balance_display_mode'; static const shouldSaveRecipientAddressKey = 'save_recipient_address'; diff --git a/lib/main.dart b/lib/main.dart index 62a0bfc9c..7265d7803 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -153,7 +153,7 @@ Future initializeAppConfigs() async { transactionDescriptions: transactionDescriptions, secureStorage: secureStorage, anonpayInvoiceInfo: anonpayInvoiceInfo, - initialMigrationVersion: 21); + initialMigrationVersion: 22); } Future initialSetup( diff --git a/lib/src/screens/dashboard/widgets/menu_widget.dart b/lib/src/screens/dashboard/widgets/menu_widget.dart index 9dd08add9..57d320322 100644 --- a/lib/src/screens/dashboard/widgets/menu_widget.dart +++ b/lib/src/screens/dashboard/widgets/menu_widget.dart @@ -30,7 +30,8 @@ class MenuWidgetState extends State { this.bitcoinIcon = Image.asset('assets/images/bitcoin_menu.png'), this.litecoinIcon = Image.asset('assets/images/litecoin_menu.png'), this.havenIcon = Image.asset('assets/images/haven_menu.png'), - this.ethereumIcon = Image.asset('assets/images/eth_icon.png'); + this.ethereumIcon = Image.asset('assets/images/eth_icon.png'), + this.bitcoinCashIcon = Image.asset('assets/images/bch_icon.png'); final largeScreen = 731; @@ -48,6 +49,7 @@ class MenuWidgetState extends State { Image litecoinIcon; Image havenIcon; Image ethereumIcon; + Image bitcoinCashIcon; @override void initState() { @@ -217,6 +219,8 @@ class MenuWidgetState extends State { return havenIcon; case WalletType.ethereum: return ethereumIcon; + case WalletType.bitcoinCash: + return bitcoinCashIcon; default: throw Exception('No icon for ${type.toString()}'); } diff --git a/lib/src/screens/wallet_list/wallet_list_page.dart b/lib/src/screens/wallet_list/wallet_list_page.dart index 81086fac9..177293e8c 100644 --- a/lib/src/screens/wallet_list/wallet_list_page.dart +++ b/lib/src/screens/wallet_list/wallet_list_page.dart @@ -41,16 +41,20 @@ class WalletListBody extends StatefulWidget { } class WalletListBodyState extends State { - final moneroIcon = Image.asset('assets/images/monero_logo.png', height: 24, width: 24); - final bitcoinIcon = Image.asset('assets/images/bitcoin.png', height: 24, width: 24); - final litecoinIcon = Image.asset('assets/images/litecoin_icon.png', height: 24, width: 24); - final nonWalletTypeIcon = Image.asset('assets/images/close.png', height: 24, width: 24); - final havenIcon = Image.asset('assets/images/haven_logo.png', height: 24, width: 24); - final ethereumIcon = Image.asset('assets/images/eth_icon.png', height: 24, width: 24); - final scrollController = ScrollController(); + final nonWalletTypeIconPath = 'assets/images/close.png'; final double tileHeight = 60; Flushbar? _progressBar; + Image getIconByWalletType(WalletType type, bool isEnabled) { + if (!isEnabled) { + return Image.asset(nonWalletTypeIconPath, height: 24, width: 24); + } + + final path = walletTypeToCryptoCurrency(type).iconPath ?? nonWalletTypeIconPath; + print('path: $path type: $type'); + return Image.asset(path, height: 24, width: 24); + } + @override Widget build(BuildContext context) { final newWalletImage = @@ -100,9 +104,7 @@ class WalletListBodyState extends State { child: Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ - wallet.isEnabled - ? _imageFor(type: wallet.type) - : nonWalletTypeIcon, + getIconByWalletType(wallet.type, wallet.isEnabled), SizedBox(width: 10), Flexible( child: Text( @@ -221,23 +223,6 @@ class WalletListBodyState extends State { ); } - Image _imageFor({required WalletType type}) { - switch (type) { - case WalletType.bitcoin: - return bitcoinIcon; - case WalletType.monero: - return moneroIcon; - case WalletType.litecoin: - return litecoinIcon; - case WalletType.haven: - return havenIcon; - case WalletType.ethereum: - return ethereumIcon; - default: - return nonWalletTypeIcon; - } - } - Future _loadWallet(WalletListItem wallet) async { await widget.authService.authenticateAction( context, diff --git a/lib/store/settings_store.dart b/lib/store/settings_store.dart index 703c7d73e..93eeab1d0 100644 --- a/lib/store/settings_store.dart +++ b/lib/store/settings_store.dart @@ -1,6 +1,7 @@ import 'dart:io'; import 'package:cake_wallet/bitcoin/bitcoin.dart'; +import 'package:cake_wallet/bitcoin_cash/bitcoin_cash.dart'; import 'package:cake_wallet/entities/cake_2fa_preset_options.dart'; import 'package:cake_wallet/entities/background_tasks.dart'; import 'package:cake_wallet/entities/exchange_api_mode.dart'; @@ -80,7 +81,8 @@ abstract class SettingsStoreBase with Store { TransactionPriority? initialMoneroTransactionPriority, TransactionPriority? initialHavenTransactionPriority, TransactionPriority? initialLitecoinTransactionPriority, - TransactionPriority? initialEthereumTransactionPriority}) + TransactionPriority? initialEthereumTransactionPriority, + TransactionPriority? initialBitcoinCashTransactionPriority}) : nodes = ObservableMap.of(nodes), _sharedPreferences = sharedPreferences, _backgroundTasks = backgroundTasks, @@ -138,6 +140,10 @@ abstract class SettingsStoreBase with Store { priority[WalletType.ethereum] = initialEthereumTransactionPriority; } + if (initialBitcoinTransactionPriority != null) { + priority[WalletType.bitcoinCash] = initialBitcoinTransactionPriority; + } + reaction( (_) => fiatCurrency, (FiatCurrency fiatCurrency) => sharedPreferences.setString( @@ -166,6 +172,9 @@ abstract class SettingsStoreBase with Store { case WalletType.ethereum: key = PreferencesKey.ethereumTransactionPriority; break; + case WalletType.bitcoinCash: + key = PreferencesKey.bitcoinTransactionPriority; + break; default: key = null; } @@ -495,6 +504,7 @@ abstract class SettingsStoreBase with Store { TransactionPriority? havenTransactionPriority; TransactionPriority? litecoinTransactionPriority; TransactionPriority? ethereumTransactionPriority; + TransactionPriority? bitcoinCashTransactionPriority; if (sharedPreferences.getInt(PreferencesKey.havenTransactionPriority) != null) { havenTransactionPriority = monero?.deserializeMoneroTransactionPriority( @@ -508,12 +518,17 @@ abstract class SettingsStoreBase with Store { ethereumTransactionPriority = bitcoin?.deserializeLitecoinTransactionPriority( sharedPreferences.getInt(PreferencesKey.ethereumTransactionPriority)!); } + if (sharedPreferences.getInt(PreferencesKey.bitcoinTransactionPriority) != null) { + bitcoinCashTransactionPriority = bitcoin?.deserializeLitecoinTransactionPriority( + sharedPreferences.getInt(PreferencesKey.bitcoinTransactionPriority)!); + } moneroTransactionPriority ??= monero?.getDefaultTransactionPriority(); bitcoinTransactionPriority ??= bitcoin?.getMediumTransactionPriority(); havenTransactionPriority ??= monero?.getDefaultTransactionPriority(); litecoinTransactionPriority ??= bitcoin?.getLitecoinTransactionPriorityMedium(); ethereumTransactionPriority ??= ethereum?.getDefaultTransactionPriority(); + bitcoinCashTransactionPriority ??= bitcoinCash?.getDefaultTransactionPriority(); final currentBalanceDisplayMode = BalanceDisplayMode.deserialize( raw: sharedPreferences.getInt(PreferencesKey.currentBalanceDisplayModeKey)!); @@ -592,6 +607,8 @@ abstract class SettingsStoreBase with Store { sharedPreferences.getInt(PreferencesKey.currentBitcoinElectrumSererIdKey); final litecoinElectrumServerId = sharedPreferences.getInt(PreferencesKey.currentLitecoinElectrumSererIdKey); + final bitcoinCashElectrumServerId = + sharedPreferences.getInt(PreferencesKey.currentBitcoinCashNodeIdKey); final havenNodeId = sharedPreferences.getInt(PreferencesKey.currentHavenNodeIdKey); final ethereumNodeId = sharedPreferences.getInt(PreferencesKey.currentEthereumNodeIdKey); final moneroNode = nodeSource.get(nodeId); @@ -599,6 +616,7 @@ abstract class SettingsStoreBase with Store { final litecoinElectrumServer = nodeSource.get(litecoinElectrumServerId); final havenNode = nodeSource.get(havenNodeId); final ethereumNode = nodeSource.get(ethereumNodeId); + final bitcoinCashElectrumServer = nodeSource.get(bitcoinCashElectrumServerId); final packageInfo = await PackageInfo.fromPlatform(); final deviceName = await _getDeviceName() ?? ''; final shouldShowYatPopup = sharedPreferences.getBool(PreferencesKey.shouldShowYatPopup) ?? true; @@ -625,6 +643,10 @@ abstract class SettingsStoreBase with Store { nodes[WalletType.ethereum] = ethereumNode; } + if (bitcoinCashElectrumServer != null) { + nodes[WalletType.bitcoinCash] = bitcoinCashElectrumServer; + } + final savedSyncMode = SyncMode.all.firstWhere((element) { return element.type.index == (sharedPreferences.getInt(PreferencesKey.syncModeKey) ?? 1); }); @@ -708,6 +730,11 @@ abstract class SettingsStoreBase with Store { sharedPreferences.getInt(PreferencesKey.ethereumTransactionPriority)!) ?? priority[WalletType.ethereum]!; } + if (sharedPreferences.getInt(PreferencesKey.bitcoinTransactionPriority) != null) { + priority[WalletType.bitcoinCash] = bitcoinCash?.deserializeBitcoinCashTransactionPriority( + sharedPreferences.getInt(PreferencesKey.bitcoinTransactionPriority)!) ?? + priority[WalletType.bitcoinCash]!; + } balanceDisplayMode = BalanceDisplayMode.deserialize( raw: sharedPreferences.getInt(PreferencesKey.currentBalanceDisplayModeKey)!); @@ -787,6 +814,8 @@ abstract class SettingsStoreBase with Store { sharedPreferences.getInt(PreferencesKey.currentBitcoinElectrumSererIdKey); final litecoinElectrumServerId = sharedPreferences.getInt(PreferencesKey.currentLitecoinElectrumSererIdKey); + final bitcoinCashElectrumServerId = + sharedPreferences.getInt(PreferencesKey.currentBitcoinCashNodeIdKey); final havenNodeId = sharedPreferences.getInt(PreferencesKey.currentHavenNodeIdKey); final ethereumNodeId = sharedPreferences.getInt(PreferencesKey.currentEthereumNodeIdKey); final moneroNode = nodeSource.get(nodeId); @@ -794,6 +823,7 @@ abstract class SettingsStoreBase with Store { final litecoinElectrumServer = nodeSource.get(litecoinElectrumServerId); final havenNode = nodeSource.get(havenNodeId); final ethereumNode = nodeSource.get(ethereumNodeId); + final bitcoinCashNode = nodeSource.get(bitcoinCashElectrumServerId); if (moneroNode != null) { nodes[WalletType.monero] = moneroNode; @@ -814,6 +844,10 @@ abstract class SettingsStoreBase with Store { if (ethereumNode != null) { nodes[WalletType.ethereum] = ethereumNode; } + + if (bitcoinCashNode != null) { + nodes[WalletType.bitcoinCash] = bitcoinCashNode; + } } Future _saveCurrentNode(Node node, WalletType walletType) async { @@ -835,6 +869,9 @@ abstract class SettingsStoreBase with Store { case WalletType.ethereum: await _sharedPreferences.setInt(PreferencesKey.currentEthereumNodeIdKey, node.key as int); break; + case WalletType.bitcoinCash: + await _sharedPreferences.setInt(PreferencesKey.currentBitcoinCashNodeIdKey, node.key as int); + break; default: break; } diff --git a/lib/view_model/node_list/node_list_view_model.dart b/lib/view_model/node_list/node_list_view_model.dart index 1c81c255b..6b34eabd2 100644 --- a/lib/view_model/node_list/node_list_view_model.dart +++ b/lib/view_model/node_list/node_list_view_model.dart @@ -66,6 +66,9 @@ abstract class NodeListViewModelBase with Store { case WalletType.ethereum: node = getEthereumDefaultNode(nodes: _nodeSource)!; break; + case WalletType.bitcoinCash: + node = getBitcoinCashDefaultElectrumServer(nodes: _nodeSource)!; + break; default: throw Exception('Unexpected wallet type: ${_appStore.wallet!.type}'); } diff --git a/lib/view_model/wallet_address_list/wallet_address_list_view_model.dart b/lib/view_model/wallet_address_list/wallet_address_list_view_model.dart index d692b4ea8..546970e37 100644 --- a/lib/view_model/wallet_address_list/wallet_address_list_view_model.dart +++ b/lib/view_model/wallet_address_list/wallet_address_list_view_model.dart @@ -110,6 +110,24 @@ class EthereumURI extends PaymentURI { } } +class BitcoinCashURI extends PaymentURI { + BitcoinCashURI({ + required String amount, + required String address}) + : super(amount: amount, address: address); + + @override + String toString() { + var base = address; + + if (amount.isNotEmpty) { + base += '?amount=${amount.replaceAll(',', '.')}'; + } + + return base; + } +} + abstract class WalletAddressListViewModelBase with Store { WalletAddressListViewModelBase({ required AppStore appStore, @@ -172,6 +190,10 @@ abstract class WalletAddressListViewModelBase with Store { return EthereumURI(amount: amount, address: address.address); } + if (_wallet.type == WalletType.bitcoinCash) { + return BitcoinCashURI(amount: amount, address: address.address); + } + throw Exception('Unexpected type: ${type.toString()}'); } diff --git a/lib/view_model/wallet_keys_view_model.dart b/lib/view_model/wallet_keys_view_model.dart index 0a758ccfb..e9799e4f0 100644 --- a/lib/view_model/wallet_keys_view_model.dart +++ b/lib/view_model/wallet_keys_view_model.dart @@ -120,6 +120,8 @@ abstract class WalletKeysViewModelBase with Store { return 'haven-wallet'; case WalletType.ethereum: return 'ethereum-wallet'; + case WalletType.bitcoinCash: + return 'bitcoinCash-wallet'; default: throw Exception('Unexpected wallet type: ${_appStore.wallet!.toString()}'); } diff --git a/lib/view_model/wallet_new_vm.dart b/lib/view_model/wallet_new_vm.dart index dcb9785e7..98c337e45 100644 --- a/lib/view_model/wallet_new_vm.dart +++ b/lib/view_model/wallet_new_vm.dart @@ -1,6 +1,7 @@ import 'package:cake_wallet/view_model/restore/restore_wallet.dart'; import 'package:cake_wallet/ethereum/ethereum.dart'; import 'package:flutter/foundation.dart'; +import 'package:cake_wallet/bitcoin_cash/bitcoin_cash.dart'; import 'package:hive/hive.dart'; import 'package:mobx/mobx.dart'; import 'package:cake_wallet/monero/monero.dart'; @@ -45,8 +46,10 @@ abstract class WalletNewVMBase extends WalletCreationVM with Store { name: name, language: options as String); case WalletType.ethereum: return ethereum!.createEthereumNewWalletCredentials(name: name); + case WalletType.bitcoinCash: + return bitcoinCash!.createBitcoinCashNewWalletCredentials(name: name); default: - throw Exception('Unexpected type: ${type.toString()}');; + throw Exception('Unexpected type: ${type.toString()}'); } } diff --git a/lib/view_model/wallet_restore_view_model.dart b/lib/view_model/wallet_restore_view_model.dart index 6bf87f22c..cbadb2f91 100644 --- a/lib/view_model/wallet_restore_view_model.dart +++ b/lib/view_model/wallet_restore_view_model.dart @@ -3,6 +3,7 @@ import 'package:cake_wallet/core/mnemonic_length.dart'; import 'package:cake_wallet/view_model/restore/restore_wallet.dart'; import 'package:flutter/foundation.dart'; import 'package:cake_wallet/ethereum/ethereum.dart'; +import 'package:cake_wallet/bitcoin_cash/bitcoin_cash.dart'; import 'package:hive/hive.dart'; import 'package:mobx/mobx.dart'; import 'package:cake_wallet/store/app_store.dart'; @@ -91,6 +92,11 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store { name: name, mnemonic: seed, password: password); + case WalletType.bitcoinCash: + return bitcoinCash!.createBitcoinCashRestoreWalletFromSeedCredentials( + name: name, + mnemonic: seed, + password: password); default: break; } diff --git a/pubspec_base.yaml b/pubspec_base.yaml index ce7d04b3f..8db69522e 100644 --- a/pubspec_base.yaml +++ b/pubspec_base.yaml @@ -121,6 +121,7 @@ flutter: - assets/bitcoin_electrum_server_list.yml - assets/litecoin_electrum_server_list.yml - assets/ethereum_server_list.yml + - assets/bitcoin_cash_electrum_server_list.yml - assets/text/ - assets/faq/ - assets/animation/ diff --git a/tool/configure.dart b/tool/configure.dart index 7c151f93e..11f70430d 100644 --- a/tool/configure.dart +++ b/tool/configure.dart @@ -564,6 +564,8 @@ Future generateBitcoinCash(bool hasImplementation) async { const bitcoinCashCommonHeaders = """ import 'dart:typed_data'; +import 'package:cw_bitcoin_cash/cw_bitcoin_cash.dart'; +import 'package:cw_core/transaction_priority.dart'; import 'package:cw_core/unspent_coins_info.dart'; import 'package:cw_core/wallet_credentials.dart'; import 'package:cw_core/wallet_info.dart'; @@ -577,9 +579,21 @@ import 'package:cw_bitcoin_cash/cw_bitcoin_cash.dart'; const bitcoinCashContent = """ abstract class BitcoinCash { String getMnemonic(int? strength); + Uint8List getSeedFromMnemonic(String seed); - WalletService createBitcoinCashWalletService(Box walletInfoSource, Box unspentCoinSource); - WalletCredentials createBitcoinCashNewWalletCredentials({required String name, WalletInfo? walletInfo}); + + WalletService createBitcoinCashWalletService( + Box walletInfoSource, Box unspentCoinSource); + + WalletCredentials createBitcoinCashNewWalletCredentials( + {required String name, WalletInfo? walletInfo}); + + WalletCredentials createBitcoinCashRestoreWalletFromSeedCredentials( + {required String name, required String mnemonic, required String password}); + + TransactionPriority deserializeBitcoinCashTransactionPriority(int raw); + + TransactionPriority getDefaultTransactionPriority(); } """;