From 64caf8479ea7bce9ff0bb92bcd3f3648214b7d50 Mon Sep 17 00:00:00 2001 From: Rafael Saes Date: Tue, 29 Oct 2024 20:52:19 -0300 Subject: [PATCH] fix: restore flow slow, checking unspents --- cw_bitcoin/lib/bitcoin_address_record.dart | 12 +- .../lib/bitcoin_hardware_wallet_service.dart | 5 +- cw_bitcoin/lib/bitcoin_unspent.dart | 6 + cw_bitcoin/lib/bitcoin_wallet.dart | 22 +- cw_bitcoin/lib/bitcoin_wallet_addresses.dart | 36 ++- .../bitcoin_wallet_creation_credentials.dart | 17 +- cw_bitcoin/lib/bitcoin_wallet_service.dart | 5 +- cw_bitcoin/lib/electrum_wallet.dart | 257 ++++++++---------- cw_bitcoin/lib/electrum_wallet_addresses.dart | 194 ++++++------- .../lib/litecoin_hardware_wallet_service.dart | 13 +- cw_bitcoin/lib/litecoin_wallet.dart | 52 ++-- cw_bitcoin/lib/litecoin_wallet_addresses.dart | 22 +- cw_bitcoin/lib/litecoin_wallet_service.dart | 1 + cw_bitcoin/pubspec.lock | 4 +- cw_bitcoin/pubspec.yaml | 4 - .../src/bitcoin_cash_wallet_addresses.dart | 6 +- cw_core/lib/wallet_keys_file.dart | 5 +- lib/bitcoin/cw_bitcoin.dart | 127 ++++----- .../screens/restore/wallet_restore_page.dart | 68 ++--- lib/store/settings_store.dart | 1 + .../restore/restore_from_qr_vm.dart | 19 +- lib/view_model/wallet_restore_view_model.dart | 2 - tool/configure.dart | 2 - 23 files changed, 396 insertions(+), 484 deletions(-) diff --git a/cw_bitcoin/lib/bitcoin_address_record.dart b/cw_bitcoin/lib/bitcoin_address_record.dart index 2c3abad0f..43c1d5e14 100644 --- a/cw_bitcoin/lib/bitcoin_address_record.dart +++ b/cw_bitcoin/lib/bitcoin_address_record.dart @@ -12,15 +12,19 @@ abstract class BaseBitcoinAddressRecord { String name = '', bool isUsed = false, required this.type, + bool? isHidden, }) : _txCount = txCount, _balance = balance, _name = name, - _isUsed = isUsed; + _isUsed = isUsed, + _isHidden = isHidden ?? isChange; @override bool operator ==(Object o) => o is BaseBitcoinAddressRecord && address == o.address; final String address; + final bool _isHidden; + bool get isHidden => _isHidden; bool isChange; final int index; int _txCount; @@ -54,6 +58,7 @@ class BitcoinAddressRecord extends BaseBitcoinAddressRecord { BitcoinAddressRecord( super.address, { required super.index, + super.isHidden, super.isChange = false, super.txCount = 0, super.balance = 0, @@ -76,6 +81,7 @@ class BitcoinAddressRecord extends BaseBitcoinAddressRecord { return BitcoinAddressRecord( decoded['address'] as String, index: decoded['index'] as int, + isHidden: decoded['isHidden'] as bool? ?? false, isChange: decoded['isChange'] as bool? ?? false, isUsed: decoded['isUsed'] as bool? ?? false, txCount: decoded['txCount'] as int? ?? 0, @@ -95,6 +101,7 @@ class BitcoinAddressRecord extends BaseBitcoinAddressRecord { String toJSON() => json.encode({ 'address': address, 'index': index, + 'isHidden': isHidden, 'isChange': isChange, 'isUsed': isUsed, 'txCount': txCount, @@ -117,6 +124,7 @@ class BitcoinSilentPaymentAddressRecord extends BaseBitcoinAddressRecord { super.name = '', super.isUsed = false, super.type = SilentPaymentsAddresType.p2sp, + super.isHidden, this.labelHex, }) : super(index: labelIndex, isChange: labelIndex == 0) { if (labelIndex != 1 && labelHex == null) { @@ -165,7 +173,7 @@ class BitcoinReceivedSPAddressRecord extends BitcoinSilentPaymentAddressRecord { required this.spendKey, super.type = SegwitAddresType.p2tr, super.labelHex, - }); + }) : super(isHidden: true); factory BitcoinReceivedSPAddressRecord.fromJSON(String jsonSource, {BasedUtxoNetwork? network}) { final decoded = json.decode(jsonSource) as Map; diff --git a/cw_bitcoin/lib/bitcoin_hardware_wallet_service.dart b/cw_bitcoin/lib/bitcoin_hardware_wallet_service.dart index 582147e3d..c63c1fe3a 100644 --- a/cw_bitcoin/lib/bitcoin_hardware_wallet_service.dart +++ b/cw_bitcoin/lib/bitcoin_hardware_wallet_service.dart @@ -22,11 +22,10 @@ class BitcoinHardwareWalletService { for (final i in indexRange) { final derivationPath = "m/84'/0'/$i'"; final xpub = await bitcoinLedgerApp.getXPubKey(derivationPath: derivationPath); - Bip32Slip10Secp256k1 hd = - Bip32Slip10Secp256k1.fromExtendedKey(xpub).childKey(Bip32KeyIndex(0)); + final bip32 = Bip32Slip10Secp256k1.fromExtendedKey(xpub).childKey(Bip32KeyIndex(0)); accounts.add(HardwareAccountData( - address: P2wpkhAddress.fromBip32(bip32: hd, account: i, index: 0) + address: P2wpkhAddress.fromBip32(bip32: bip32, isChange: false, index: i) .toAddress(BitcoinNetwork.mainnet), accountIndex: i, derivationPath: derivationPath, diff --git a/cw_bitcoin/lib/bitcoin_unspent.dart b/cw_bitcoin/lib/bitcoin_unspent.dart index a57ad9a8b..b10eb47f6 100644 --- a/cw_bitcoin/lib/bitcoin_unspent.dart +++ b/cw_bitcoin/lib/bitcoin_unspent.dart @@ -29,4 +29,10 @@ class BitcoinUnspent extends Unspent { } final BaseBitcoinAddressRecord bitcoinAddressRecord; + + @override + bool operator ==(Object o) { + print('BitcoinUnspent operator =='); + return o is BitcoinUnspent && hash == o.hash && vout == o.vout; + } } diff --git a/cw_bitcoin/lib/bitcoin_wallet.dart b/cw_bitcoin/lib/bitcoin_wallet.dart index b974eeb47..6a0e3f4e7 100644 --- a/cw_bitcoin/lib/bitcoin_wallet.dart +++ b/cw_bitcoin/lib/bitcoin_wallet.dart @@ -7,6 +7,7 @@ import 'package:bitcoin_base/bitcoin_base.dart'; import 'package:blockchain_utils/blockchain_utils.dart'; import 'package:cw_bitcoin/bitcoin_address_record.dart'; import 'package:cw_bitcoin/bitcoin_mnemonic.dart'; +import 'package:cw_bitcoin/psbt_transaction_builder.dart'; import 'package:cw_bitcoin/bitcoin_transaction_priority.dart'; import 'package:cw_bitcoin/bitcoin_unspent.dart'; import 'package:cw_bitcoin/electrum_transaction_info.dart'; @@ -45,7 +46,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store { required WalletInfo walletInfo, required Box unspentCoinsInfo, required EncryptionFileUtils encryptionFileUtils, - Uint8List? seedBytes, + List? seedBytes, String? mnemonic, String? xpub, String? addressPageType, @@ -89,6 +90,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store { initialSilentAddressIndex: initialSilentAddressIndex, bip32: bip32, network: networkParam ?? network, + isHardwareWallet: walletInfo.isHardwareWallet, ); autorun((_) { @@ -113,20 +115,18 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store { int initialSilentAddressIndex = 0, required bool mempoolAPIEnabled, }) async { - late Uint8List seedBytes; + late List seedBytes; switch (walletInfo.derivationInfo?.derivationType) { case DerivationType.bip39: - seedBytes = await bip39.mnemonicToSeed( - mnemonic, - passphrase: passphrase ?? "", - ); + seedBytes = Bip39SeedGenerator.generateFromString(mnemonic, passphrase); break; case DerivationType.electrum: default: - seedBytes = await mnemonicToSeedBytes(mnemonic, passphrase: passphrase ?? ""); + seedBytes = ElectrumV2SeedGenerator.generateFromString(mnemonic, passphrase); break; } + return BitcoinWallet( mnemonic: mnemonic, passphrase: passphrase ?? "", @@ -199,7 +199,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store { walletInfo.derivationInfo!.derivationPath ??= snp?.derivationPath ?? electrum_path; walletInfo.derivationInfo!.derivationType ??= snp?.derivationType ?? DerivationType.electrum; - Uint8List? seedBytes = null; + List? seedBytes = null; final mnemonic = keysData.mnemonic; final passphrase = keysData.passphrase; @@ -360,7 +360,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store { updatedUnspentCoins.addAll(await fetchUnspent(address)); })); - unspentCoins = updatedUnspentCoins; + unspentCoins = updatedUnspentCoins.toSet(); if (unspentCoinsInfo.length != updatedUnspentCoins.length) { unspentCoins.forEach((coin) => addCoinInfo(coin)); @@ -642,8 +642,8 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store { } @action - Future fetchBalances(List addresses) async { - final balance = await super.fetchBalances(addresses); + Future fetchBalances() async { + final balance = await super.fetchBalances(); int totalFrozen = balance.frozen; int totalConfirmed = balance.confirmed; diff --git a/cw_bitcoin/lib/bitcoin_wallet_addresses.dart b/cw_bitcoin/lib/bitcoin_wallet_addresses.dart index 931c58e71..ab7a45d4f 100644 --- a/cw_bitcoin/lib/bitcoin_wallet_addresses.dart +++ b/cw_bitcoin/lib/bitcoin_wallet_addresses.dart @@ -1,5 +1,4 @@ import 'package:bitcoin_base/bitcoin_base.dart'; -import 'package:blockchain_utils/bip/bip/bip32/bip32.dart'; import 'package:cw_bitcoin/electrum_wallet_addresses.dart'; import 'package:cw_core/wallet_info.dart'; import 'package:mobx/mobx.dart'; @@ -21,34 +20,47 @@ abstract class BitcoinWalletAddressesBase extends ElectrumWalletAddresses with S super.initialSilentAddressIndex = 0, }) : super(walletInfo); + @override + Future init() async { + await generateInitialAddresses(type: SegwitAddresType.p2wpkh); + + if (!isHardwareWallet) { + await generateInitialAddresses(type: P2pkhAddressType.p2pkh); + await generateInitialAddresses(type: P2shAddressType.p2wpkhInP2sh); + await generateInitialAddresses(type: SegwitAddresType.p2tr); + await generateInitialAddresses(type: SegwitAddresType.p2wsh); + } + + await updateAddressesInBox(); + } + @override BitcoinBaseAddress generateAddress({ - required int account, + required bool isChange, required int index, - required Bip32Slip10Secp256k1 hd, required BitcoinAddressType addressType, }) { switch (addressType) { case P2pkhAddressType.p2pkh: - return P2pkhAddress.fromBip32(account: account, bip32: hd, index: index); + return P2pkhAddress.fromBip32(bip32: bip32, isChange: isChange, index: index); case SegwitAddresType.p2tr: - return P2trAddress.fromBip32(account: account, bip32: hd, index: index); + return P2trAddress.fromBip32(bip32: bip32, isChange: isChange, index: index); case SegwitAddresType.p2wsh: - return P2wshAddress.fromBip32(account: account, bip32: hd, index: index); + return P2wshAddress.fromBip32(bip32: bip32, isChange: isChange, index: index); case P2shAddressType.p2wpkhInP2sh: return P2shAddress.fromBip32( - account: account, - bip32: hd, + bip32: bip32, + isChange: isChange, index: index, type: P2shAddressType.p2wpkhInP2sh, ); case SegwitAddresType.p2wpkh: return P2wpkhAddress.fromBip32( - account: account, - bip32: hd, + bip32: bip32, + isChange: isChange, index: index, - isElectrum: true, - ); // TODO: + isElectrum: false, // TODO: + ); default: throw ArgumentError('Invalid address type'); } diff --git a/cw_bitcoin/lib/bitcoin_wallet_creation_credentials.dart b/cw_bitcoin/lib/bitcoin_wallet_creation_credentials.dart index a1b1418b8..cd615ad2b 100644 --- a/cw_bitcoin/lib/bitcoin_wallet_creation_credentials.dart +++ b/cw_bitcoin/lib/bitcoin_wallet_creation_credentials.dart @@ -7,8 +7,6 @@ class BitcoinNewWalletCredentials extends WalletCredentials { required String name, WalletInfo? walletInfo, String? password, - DerivationType? derivationType, - String? derivationPath, String? passphrase, this.mnemonic, String? parentAddress, @@ -29,18 +27,13 @@ class BitcoinRestoreWalletFromSeedCredentials extends WalletCredentials { required String password, required this.mnemonic, WalletInfo? walletInfo, - required DerivationType derivationType, - required String derivationPath, String? passphrase, }) : super( - name: name, - password: password, - passphrase: passphrase, - walletInfo: walletInfo, - derivationInfo: DerivationInfo( - derivationType: derivationType, - derivationPath: derivationPath, - )); + name: name, + password: password, + passphrase: passphrase, + walletInfo: walletInfo, + ); final String mnemonic; } diff --git a/cw_bitcoin/lib/bitcoin_wallet_service.dart b/cw_bitcoin/lib/bitcoin_wallet_service.dart index 45ef9b653..a38452329 100644 --- a/cw_bitcoin/lib/bitcoin_wallet_service.dart +++ b/cw_bitcoin/lib/bitcoin_wallet_service.dart @@ -89,7 +89,7 @@ class BitcoinWalletService extends WalletService< unspentCoinsInfo: unspentCoinsInfoSource, alwaysScan: alwaysScan, mempoolAPIEnabled: mempoolAPIEnabled, - encryptionFileUtils: encryptionFileUtilsFor(false), + encryptionFileUtils: encryptionFileUtilsFor(isDirect), ); await wallet.init(); saveBackup(name); @@ -103,7 +103,7 @@ class BitcoinWalletService extends WalletService< unspentCoinsInfo: unspentCoinsInfoSource, alwaysScan: alwaysScan, mempoolAPIEnabled: mempoolAPIEnabled, - encryptionFileUtils: encryptionFileUtilsFor(false), + encryptionFileUtils: encryptionFileUtilsFor(isDirect), ); await wallet.init(); return wallet; @@ -189,7 +189,6 @@ class BitcoinWalletService extends WalletService< encryptionFileUtils: encryptionFileUtilsFor(isDirect), mempoolAPIEnabled: mempoolAPIEnabled, ); - await wallet.save(); await wallet.init(); return wallet; } diff --git a/cw_bitcoin/lib/electrum_wallet.dart b/cw_bitcoin/lib/electrum_wallet.dart index 648104540..373b68085 100644 --- a/cw_bitcoin/lib/electrum_wallet.dart +++ b/cw_bitcoin/lib/electrum_wallet.dart @@ -56,7 +56,7 @@ abstract class ElectrumWalletBase required this.encryptionFileUtils, String? xpub, String? mnemonic, - Uint8List? seedBytes, + List? seedBytes, this.passphrase, List? initialAddresses, ElectrumClient? electrumClient, @@ -69,7 +69,7 @@ abstract class ElectrumWalletBase _password = password, _isTransactionUpdating = false, isEnabledAutoGenerateSubaddress = true, - unspentCoins = [], + unspentCoins = {}, scripthashesListening = {}, balance = ObservableMap.of(currency != null ? { @@ -99,7 +99,7 @@ abstract class ElectrumWalletBase } static Bip32Slip10Secp256k1 getAccountHDWallet(CryptoCurrency? currency, BasedUtxoNetwork network, - Uint8List? seedBytes, String? xpub, DerivationInfo? derivationInfo) { + List? seedBytes, String? xpub, DerivationInfo? derivationInfo) { if (seedBytes == null && xpub == null) { throw Exception( "To create a Wallet you need either a seed or an xpub. This should not happen"); @@ -121,7 +121,7 @@ abstract class ElectrumWalletBase return Bip32Slip10Secp256k1.fromExtendedKey(xpub!, getKeyNetVersion(network)); } - static Bip32Slip10Secp256k1 bitcoinCashHDWallet(Uint8List seedBytes) => + static Bip32Slip10Secp256k1 bitcoinCashHDWallet(List seedBytes) => Bip32Slip10Secp256k1.fromSeed(seedBytes).derivePath("m/44'/145'/0'") as Bip32Slip10Secp256k1; int estimatedTransactionSize(int inputsCount, int outputsCounts) => @@ -221,7 +221,8 @@ abstract class ElectrumWalletBase ); String _password; - List unspentCoins; + @observable + Set unspentCoins; @observable TransactionPriorities? feeRates; @@ -242,7 +243,6 @@ abstract class ElectrumWalletBase Future init() async { await walletAddresses.init(); await transactionHistory.init(); - await save(); _autoSaveTimer = Timer.periodic(Duration(minutes: _autoSaveInterval), (_) async => await save()); @@ -263,13 +263,15 @@ abstract class ElectrumWalletBase // await updateTransactions(); // await updateAllUnspents(); - // await updateBalance(); + await updateBalance(); await updateFeeRates(); _updateFeeRateTimer ??= Timer.periodic(const Duration(seconds: 5), (timer) async => await updateFeeRates()); syncStatus = SyncedSyncStatus(); + + await save(); } catch (e, stacktrace) { print(stacktrace); print("startSync $e"); @@ -459,7 +461,7 @@ abstract class ElectrumWalletBase } else if (!isHardwareWallet) { privkey = ECPrivate.fromBip32( bip32: walletAddresses.bip32, - account: utx.bitcoinAddressRecord.isChange ? 1 : 0, + account: BitcoinAddressUtils.getAccountFromChange(utx.bitcoinAddressRecord.isChange), index: utx.bitcoinAddressRecord.index, ); } @@ -660,11 +662,11 @@ abstract class ElectrumWalletBase isChange: true, )); - // Get Derivation path for change Address since it is needed in Litecoin and BitcoinCash hardware Wallets - final changeDerivationPath = - "${_hardenedDerivationPath(walletInfo.derivationInfo?.derivationPath ?? "m/0'")}" - "/${changeAddress.isHidden ? "1" : "0"}" - "/${changeAddress.index}"; + final changeDerivationPath = BitcoinAddressUtils.getDerivationPath( + type: changeAddress.type, + account: changeAddress.isChange ? 1 : 0, + index: changeAddress.index, + ); utxoDetails.publicKeys[address.pubKeyHash()] = PublicKeyWithDerivationPath('', changeDerivationPath); @@ -1105,12 +1107,12 @@ abstract class ElectrumWalletBase Future save() async { if (!(await WalletKeysFile.hasKeysFile(walletInfo.name, walletInfo.type))) { await saveKeysFile(_password, encryptionFileUtils); - saveKeysFile(_password, encryptionFileUtils, true); + await saveKeysFile(_password, encryptionFileUtils, true); } final path = await makePath(); await encryptionFileUtils.write(path: path, password: _password, data: toJSON()); - await transactionHistory.save(); + // await transactionHistory.save(); } @override @@ -1174,7 +1176,7 @@ abstract class ElectrumWalletBase updatedUnspentCoins.addAll(await fetchUnspent(address)); })); - unspentCoins = updatedUnspentCoins; + unspentCoins = updatedUnspentCoins.toSet(); if (unspentCoinsInfo.length != updatedUnspentCoins.length) { unspentCoins.forEach((coin) => addCoinInfo(coin)); @@ -1182,9 +1184,10 @@ abstract class ElectrumWalletBase } await updateCoins(unspentCoins); - await refreshUnspentCoinsInfo(); + // await refreshUnspentCoinsInfo(); } + @action void updateCoin(BitcoinUnspent coin) { final coinInfoList = unspentCoinsInfo.values.where( (element) => @@ -1204,7 +1207,8 @@ abstract class ElectrumWalletBase } } - Future updateCoins(List newUnspentCoins) async { + @action + Future updateCoins(Set newUnspentCoins) async { if (newUnspentCoins.isEmpty) { return; } @@ -1213,8 +1217,26 @@ abstract class ElectrumWalletBase @action Future updateUnspentsForAddress(BitcoinAddressRecord addressRecord) async { - final newUnspentCoins = await fetchUnspent(addressRecord); + final newUnspentCoins = (await fetchUnspent(addressRecord)).toSet(); await updateCoins(newUnspentCoins); + + print([1, unspentCoins.containsAll(newUnspentCoins)]); + if (!unspentCoins.containsAll(newUnspentCoins)) { + newUnspentCoins.forEach((coin) { + print(unspentCoins.contains(coin)); + print([coin.vout, coin.hash]); + print([unspentCoins.first.vout, unspentCoins.first.hash]); + if (!unspentCoins.contains(coin)) { + unspentCoins.add(coin); + } + }); + } + + // if (unspentCoinsInfo.length != unspentCoins.length) { + // unspentCoins.forEach(addCoinInfo); + // } + + // await refreshUnspentCoinsInfo(); } @action @@ -1231,11 +1253,6 @@ abstract class ElectrumWalletBase final tx = await fetchTransactionInfo(hash: coin.hash); coin.isChange = address.isChange; coin.confirmations = tx?.confirmations; - if (coin.isFrozen) { - balance[currency]!.frozen += coin.value; - } else { - balance[currency]!.confirmed += coin.value; - } updatedUnspentCoins.add(coin); } catch (_) {} @@ -1492,64 +1509,65 @@ abstract class ElectrumWalletBase } } - Future getTransactionExpanded( - {required String hash, int? height}) async { - String transactionHex = ''; + Future getTransactionExpanded({required String hash}) async { int? time; - int? confirmations; + int? height; - try { - final verboseTransaction = await electrumClient2!.request( - ElectrumGetTransactionVerbose(transactionHash: hash), - ); + final transactionHex = await electrumClient2!.request( + ElectrumGetTransactionHex(transactionHash: hash), + ); - transactionHex = verboseTransaction['hex'] as String; - time = verboseTransaction['time'] as int?; - confirmations = verboseTransaction['confirmations'] as int?; - } catch (e) { - if (e is RPCError || e is TimeoutException) { - transactionHex = await electrumClient2!.request( - ElectrumGetTransactionHex(transactionHash: hash), + // TODO: + // if (mempoolAPIEnabled) { + if (true) { + try { + final txVerbose = await http.get( + Uri.parse( + "http://mempool.cakewallet.com:8999/api/v1/tx/$hash/status", + ), ); - if (height != null && height > 0 && mempoolAPIEnabled) { - try { - final blockHash = await http.get( + if (txVerbose.statusCode == 200 && + txVerbose.body.isNotEmpty && + jsonDecode(txVerbose.body) != null) { + height = jsonDecode(txVerbose.body)['block_height'] as int; + + final blockHash = await http.get( + Uri.parse( + "http://mempool.cakewallet.com:8999/api/v1/block-height/$height", + ), + ); + + if (blockHash.statusCode == 200 && + blockHash.body.isNotEmpty && + jsonDecode(blockHash.body) != null) { + final blockResponse = await http.get( Uri.parse( - "http://mempool.cakewallet.com:8999/api/v1/block-height/$height", + "http://mempool.cakewallet.com:8999/api/v1/block/${blockHash.body}", ), ); - if (blockHash.statusCode == 200 && - blockHash.body.isNotEmpty && - jsonDecode(blockHash.body) != null) { - final blockResponse = await http.get( - Uri.parse( - "http://mempool.cakewallet.com:8999/api/v1/block/${blockHash.body}", - ), - ); - if (blockResponse.statusCode == 200 && - blockResponse.body.isNotEmpty && - jsonDecode(blockResponse.body)['timestamp'] != null) { - time = int.parse(jsonDecode(blockResponse.body)['timestamp'].toString()); - } + if (blockResponse.statusCode == 200 && + blockResponse.body.isNotEmpty && + jsonDecode(blockResponse.body)['timestamp'] != null) { + time = int.parse(jsonDecode(blockResponse.body)['timestamp'].toString()); } - } catch (_) {} + } } - } + } catch (_) {} } + int? confirmations; + if (height != null) { if (time == null && height > 0) { time = (getDateByBitcoinHeight(height).millisecondsSinceEpoch / 1000).round(); } - if (confirmations == null) { - final tip = currentChainTip!; - if (tip > 0 && height > 0) { - // Add one because the block itself is the first confirmation - confirmations = tip - height + 1; - } + final tip = currentChainTip!; + if (tip > 0 && height > 0) { + // Add one because the block itself is the first confirmation + confirmations = tip - height + 1; } } @@ -1557,19 +1575,9 @@ abstract class ElectrumWalletBase final ins = []; for (final vin in original.inputs) { - String inputTransactionHex = ""; - try { - final verboseTransaction = await electrumClient2!.request( - ElectrumGetTransactionVerbose(transactionHash: vin.txId), - ); - inputTransactionHex = verboseTransaction['hex'] as String; - } catch (e) { - if (e is RPCError || e is TimeoutException) { - inputTransactionHex = await electrumClient2!.request( - ElectrumGetTransactionHex(transactionHash: vin.txId), - ); - } - } + final inputTransactionHex = await electrumClient2!.request( + ElectrumGetTransactionHex(transactionHash: vin.txId), + ); ins.add(BtcTransaction.fromRaw(inputTransactionHex)); } @@ -1585,7 +1593,7 @@ abstract class ElectrumWalletBase Future fetchTransactionInfo({required String hash, int? height}) async { try { return ElectrumTransactionInfo.fromElectrumBundle( - await getTransactionExpanded(hash: hash, height: height), + await getTransactionExpanded(hash: hash), walletInfo.type, network, addresses: addressesSet, @@ -1674,7 +1682,6 @@ abstract class ElectrumWalletBase // Got a new transaction fetched, add it to the transaction history // instead of waiting all to finish, and next time it will be faster transactionHistory.addOne(tx); - await transactionHistory.save(); } } @@ -1682,34 +1689,26 @@ abstract class ElectrumWalletBase })); final totalAddresses = (addressRecord.isChange - ? walletAddresses.allAddresses - .where((addr) => addr.isChange && addr.type == addressRecord.type) + ? walletAddresses.changeAddresses + .where((addr) => addr.type == addressRecord.type) .length - : walletAddresses.allAddresses - .where((addr) => !addr.isChange && addr.type == addressRecord.type) + : walletAddresses.receiveAddresses + .where((addr) => addr.type == addressRecord.type) .length); final gapLimit = (addressRecord.isChange ? ElectrumWalletAddressesBase.defaultChangeAddressesCount : ElectrumWalletAddressesBase.defaultReceiveAddressesCount); - print("gapLimit: $gapLimit"); - print("index: ${addressRecord.index}"); - final isUsedAddressUnderGap = addressRecord.index >= totalAddresses - gapLimit; - print("isUsedAddressAtGapLimit: $isUsedAddressUnderGap"); - print("total: $totalAddresses"); + final isUsedAddressUnderGap = addressRecord.index < totalAddresses && + (addressRecord.index >= totalAddresses - gapLimit); if (isUsedAddressUnderGap) { // Discover new addresses for the same address type until the gap limit is respected - final newAddresses = await walletAddresses.discoverAddresses( - walletAddresses.allAddresses - .where((addr) => - (addressRecord.isChange ? addr.isChange : !addr.isChange) && - addr.type == addressRecord.type) - .toList(), - addressRecord.isChange, + await walletAddresses.discoverAddresses( + isChange: addressRecord.isChange, + gap: gapLimit, type: addressRecord.type, ); - await subscribeForUpdates(newAddresses); } } @@ -1765,59 +1764,30 @@ abstract class ElectrumWalletBase print("status: $status"); await _fetchAddressHistory(addressRecord); - print("_fetchAddressHistory: ${addressRecord.address}"); await updateUnspentsForAddress(addressRecord); - print("updateUnspentsForAddress: ${addressRecord.address}"); }); } })); } @action - Future fetchBalances(List addresses) async { - final balanceFutures = >>[]; - for (var i = 0; i < addresses.length; i++) { - final addressRecord = addresses[i]; - final balanceFuture = electrumClient2!.request( - ElectrumGetScriptHashBalance(scriptHash: addressRecord.scriptHash), - ); - balanceFutures.add(balanceFuture); - } - + Future fetchBalances() async { var totalFrozen = 0; var totalConfirmed = 0; var totalUnconfirmed = 0; - unspentCoinsInfo.values.forEach((info) { - unspentCoins.forEach((element) { - if (element.hash == info.hash && - element.vout == info.vout && - info.isFrozen && - element.bitcoinAddressRecord.address == info.address && - element.value == info.value) { - totalFrozen += element.value; - } - }); + unspentCoins.forEach((element) { + if (element.isFrozen) { + totalFrozen += element.value; + } + + if (element.confirmations == 0) { + totalUnconfirmed += element.value; + } else { + totalConfirmed += element.value; + } }); - final balances = await Future.wait(balanceFutures); - - for (var i = 0; i < balances.length; i++) { - final addressRecord = addresses[i]; - final balance = balances[i]; - try { - final confirmed = balance['confirmed'] as int? ?? 0; - final unconfirmed = balance['unconfirmed'] as int? ?? 0; - totalConfirmed += confirmed; - totalUnconfirmed += unconfirmed; - - addressRecord.balance = confirmed + unconfirmed; - if (confirmed > 0 || unconfirmed > 0) { - addressRecord.setAsUsed(); - } - } catch (_) {} - } - return ElectrumBalance( confirmed: totalConfirmed, unconfirmed: totalUnconfirmed, @@ -1825,22 +1795,9 @@ abstract class ElectrumWalletBase ); } - @action - Future updateBalanceForAddress(BitcoinAddressRecord addressRecord) async { - final updatedBalance = await fetchBalances([addressRecord]); - if (balance[currency] == null) { - balance[currency] = updatedBalance; - } else { - balance[currency]!.confirmed += updatedBalance.confirmed; - balance[currency]!.unconfirmed += updatedBalance.unconfirmed; - balance[currency]!.frozen += updatedBalance.frozen; - } - } - @action Future updateBalance() async { - balance[currency] = await fetchBalances(walletAddresses.allAddresses); - await save(); + balance[currency] = await fetchBalances(); } @override diff --git a/cw_bitcoin/lib/electrum_wallet_addresses.dart b/cw_bitcoin/lib/electrum_wallet_addresses.dart index 6cc706d02..c6600841b 100644 --- a/cw_bitcoin/lib/electrum_wallet_addresses.dart +++ b/cw_bitcoin/lib/electrum_wallet_addresses.dart @@ -43,15 +43,14 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store { int initialSilentAddressIndex = 0, List? initialMwebAddresses, BitcoinAddressType? initialAddressPageType, - }) : _addresses = ObservableList.of((initialAddresses ?? []).toSet()), + }) : _allAddresses = (initialAddresses ?? []).toSet(), addressesByReceiveType = ObservableList.of(([]).toSet()), - receiveAddresses = ObservableList.of((initialAddresses ?? []) - .where((addressRecord) => !addressRecord.isChange && !addressRecord.isUsed) - .toSet()), - changeAddresses = ObservableList.of((initialAddresses ?? []) - .where((addressRecord) => addressRecord.isChange && !addressRecord.isUsed) - .toSet()), + receiveAddresses = ObservableList.of( + (initialAddresses ?? []).where((addressRecord) => !addressRecord.isChange).toSet()), + // TODO: feature to change change address type. For now fixed to p2wpkh, the cheapest type + changeAddresses = ObservableList.of( + (initialAddresses ?? []).where((addressRecord) => addressRecord.isChange).toSet()), currentReceiveAddressIndexByType = initialRegularAddressIndex ?? {}, currentChangeAddressIndexByType = initialChangeAddressIndex ?? {}, _addressPageType = initialAddressPageType ?? @@ -92,7 +91,8 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store { static const defaultChangeAddressesCount = 17; static const gap = 20; - final ObservableList _addresses; + @observable + final Set _allAddresses; final ObservableList addressesByReceiveType; final ObservableList receiveAddresses; final ObservableList changeAddresses; @@ -102,6 +102,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store { final ObservableList mwebAddresses; final BasedUtxoNetwork network; final Bip32Slip10Secp256k1 bip32; + final bool isHardwareWallet; @observable SilentPaymentOwner? silentAddress; @@ -116,7 +117,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store { String? activeSilentAddress; @computed - List get allAddresses => _addresses; + List get allAddresses => _allAddresses.toList(); @override @computed @@ -177,21 +178,18 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store { return; } try { - final addressRecord = _addresses.firstWhere( + final addressRecord = _allAddresses.firstWhere( (addressRecord) => addressRecord.address == addr, ); previousAddressRecord = addressRecord; - receiveAddresses.remove(addressRecord); - receiveAddresses.insert(0, addressRecord); } catch (e) { print("ElectrumWalletAddressBase: set address ($addr): $e"); } } @override - String get primaryAddress => - getAddress(account: 0, index: 0, hd: bip32, addressType: addressPageType); + String get primaryAddress => getAddress(isChange: false, index: 0, addressType: addressPageType); Map currentReceiveAddressIndexByType; @@ -233,19 +231,19 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store { @override Future init() async { if (walletInfo.type == WalletType.bitcoinCash) { - await _generateInitialAddresses(type: P2pkhAddressType.p2pkh); + await generateInitialAddresses(type: P2pkhAddressType.p2pkh); } else if (walletInfo.type == WalletType.litecoin) { - await _generateInitialAddresses(type: SegwitAddresType.p2wpkh); + await generateInitialAddresses(type: SegwitAddresType.p2wpkh); if ((Platform.isAndroid || Platform.isIOS) && !isHardwareWallet) { - await _generateInitialAddresses(type: SegwitAddresType.mweb); + await generateInitialAddresses(type: SegwitAddresType.mweb); } } else if (walletInfo.type == WalletType.bitcoin) { - await _generateInitialAddresses(); + await generateInitialAddresses(type: SegwitAddresType.p2wpkh); if (!isHardwareWallet) { - await _generateInitialAddresses(type: P2pkhAddressType.p2pkh); - await _generateInitialAddresses(type: P2shAddressType.p2wpkhInP2sh); - await _generateInitialAddresses(type: SegwitAddresType.p2tr); - await _generateInitialAddresses(type: SegwitAddresType.p2wsh); + await generateInitialAddresses(type: P2pkhAddressType.p2pkh); + await generateInitialAddresses(type: P2shAddressType.p2wpkhInP2sh); + await generateInitialAddresses(type: SegwitAddresType.p2tr); + await generateInitialAddresses(type: SegwitAddresType.p2wsh); } } @@ -265,14 +263,12 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store { } @action - Future getChangeAddress( + Future getChangeAddress( {List? inputs, List? outputs, bool isPegIn = false}) async { updateChangeAddresses(); if (changeAddresses.isEmpty) { - final newAddresses = await _createNewAddresses(gap, - startIndex: totalCountOfChangeAddresses > 0 ? totalCountOfChangeAddresses - 1 : 0, - isHidden: true); + final newAddresses = await _createNewAddresses(gap, isChange: true); addAddresses(newAddresses); } @@ -331,47 +327,45 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store { 0, (int acc, addressRecord) => addressRecord.isChange == false ? acc + 1 : acc); final address = BitcoinAddressRecord( - getAddress(account: 0, index: newAddressIndex, hd: bip32, addressType: addressPageType), + getAddress(isChange: false, index: newAddressIndex, addressType: addressPageType), index: newAddressIndex, isChange: false, name: label, type: addressPageType, network: network, ); - _addresses.add(address); + _allAddresses.add(address); Future.delayed(Duration.zero, () => updateAddressesByMatch()); return address; } BitcoinBaseAddress generateAddress({ - required int account, + required bool isChange, required int index, - required Bip32Slip10Secp256k1 hd, required BitcoinAddressType addressType, }) { throw UnimplementedError(); } String getAddress({ - required int account, + required bool isChange, required int index, - required Bip32Slip10Secp256k1 hd, required BitcoinAddressType addressType, }) { - return generateAddress(account: account, index: index, hd: hd, addressType: addressType) + return generateAddress(isChange: isChange, index: index, addressType: addressType) .toAddress(network); } Future getAddressAsync({ - required int account, + required bool isChange, required int index, - required Bip32Slip10Secp256k1 hd, required BitcoinAddressType addressType, }) async => - getAddress(account: account, index: index, hd: hd, addressType: addressType); + getAddress(isChange: isChange, index: index, addressType: addressType); + @action void addBitcoinAddressTypes() { - final lastP2wpkh = _addresses + final lastP2wpkh = _allAddresses .where((addressRecord) => _isUnusedReceiveAddressByType(addressRecord, SegwitAddresType.p2wpkh)) .toList() @@ -382,7 +376,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store { addressesMap[address] = 'Active - P2WPKH'; } - final lastP2pkh = _addresses.firstWhere( + final lastP2pkh = _allAddresses.firstWhere( (addressRecord) => _isUnusedReceiveAddressByType(addressRecord, P2pkhAddressType.p2pkh)); if (lastP2pkh.address != address) { addressesMap[lastP2pkh.address] = 'P2PKH'; @@ -390,7 +384,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store { addressesMap[address] = 'Active - P2PKH'; } - final lastP2sh = _addresses.firstWhere((addressRecord) => + final lastP2sh = _allAddresses.firstWhere((addressRecord) => _isUnusedReceiveAddressByType(addressRecord, P2shAddressType.p2wpkhInP2sh)); if (lastP2sh.address != address) { addressesMap[lastP2sh.address] = 'P2SH'; @@ -398,7 +392,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store { addressesMap[address] = 'Active - P2SH'; } - final lastP2tr = _addresses.firstWhere( + final lastP2tr = _allAddresses.firstWhere( (addressRecord) => _isUnusedReceiveAddressByType(addressRecord, SegwitAddresType.p2tr)); if (lastP2tr.address != address) { addressesMap[lastP2tr.address] = 'P2TR'; @@ -406,7 +400,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store { addressesMap[address] = 'Active - P2TR'; } - final lastP2wsh = _addresses.firstWhere( + final lastP2wsh = _allAddresses.firstWhere( (addressRecord) => _isUnusedReceiveAddressByType(addressRecord, SegwitAddresType.p2wsh)); if (lastP2wsh.address != address) { addressesMap[lastP2wsh.address] = 'P2WSH'; @@ -429,8 +423,9 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store { }); } + @action void addLitecoinAddressTypes() { - final lastP2wpkh = _addresses + final lastP2wpkh = _allAddresses .where((addressRecord) => _isUnusedReceiveAddressByType(addressRecord, SegwitAddresType.p2wpkh)) .toList() @@ -441,7 +436,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store { addressesMap[address] = 'Active - P2WPKH'; } - final lastMweb = _addresses.firstWhere( + final lastMweb = _allAddresses.firstWhere( (addressRecord) => _isUnusedReceiveAddressByType(addressRecord, SegwitAddresType.mweb)); if (lastMweb.address != address) { addressesMap[lastMweb.address] = 'MWEB'; @@ -450,8 +445,9 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store { } } + @action void addBitcoinCashAddressTypes() { - final lastP2pkh = _addresses.firstWhere( + final lastP2pkh = _allAddresses.firstWhere( (addressRecord) => _isUnusedReceiveAddressByType(addressRecord, P2pkhAddressType.p2pkh)); if (lastP2pkh.address != address) { addressesMap[lastP2pkh.address] = 'P2PKH'; @@ -461,13 +457,14 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store { } @override + @action Future updateAddressesInBox() async { try { addressesMap.clear(); addressesMap[address] = 'Active'; allAddressesMap.clear(); - _addresses.forEach((addressRecord) { + _allAddresses.forEach((addressRecord) { allAddressesMap[addressRecord.address] = addressRecord.name; }); @@ -494,7 +491,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store { @action void updateAddress(String address, String label) { BaseBitcoinAddressRecord? foundAddress; - _addresses.forEach((addressRecord) { + _allAddresses.forEach((addressRecord) { if (addressRecord.address == address) { foundAddress = addressRecord; } @@ -513,11 +510,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store { if (foundAddress != null) { foundAddress!.setNewName(label); - if (foundAddress is BitcoinAddressRecord) { - final index = _addresses.indexOf(foundAddress); - _addresses.remove(foundAddress); - _addresses.insert(index, foundAddress as BitcoinAddressRecord); - } else { + if (foundAddress is! BitcoinAddressRecord) { final index = silentAddresses.indexOf(foundAddress as BitcoinSilentPaymentAddressRecord); silentAddresses.remove(foundAddress); silentAddresses.insert(index, foundAddress as BitcoinSilentPaymentAddressRecord); @@ -534,88 +527,62 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store { } addressesByReceiveType.clear(); - addressesByReceiveType.addAll(_addresses.where(_isAddressPageTypeMatch).toList()); + addressesByReceiveType.addAll(_allAddresses.where(_isAddressPageTypeMatch).toList()); } @action void updateReceiveAddresses() { receiveAddresses.removeRange(0, receiveAddresses.length); - final newAddresses = - _addresses.where((addressRecord) => !addressRecord.isChange && !addressRecord.isUsed); + final newAddresses = _allAddresses.where((addressRecord) => !addressRecord.isChange); receiveAddresses.addAll(newAddresses); } @action void updateChangeAddresses() { changeAddresses.removeRange(0, changeAddresses.length); - final newAddresses = _addresses.where((addressRecord) => + final newAddresses = _allAddresses.where((addressRecord) => addressRecord.isChange && - !addressRecord.isUsed && - // TODO: feature to change change address type. For now fixed to p2wpkh, the cheapest type (walletInfo.type != WalletType.bitcoin || addressRecord.type == SegwitAddresType.p2wpkh)); changeAddresses.addAll(newAddresses); } @action - Future> discoverAddresses( - List addressList, - bool isHidden, { - BitcoinAddressType type = SegwitAddresType.p2wpkh, + Future> discoverAddresses({ + required bool isChange, + required int gap, + required BitcoinAddressType type, }) async { - final newAddresses = await _createNewAddresses( - gap, - startIndex: addressList.length, - isHidden: isHidden, - type: type, - ); + print("_allAddresses: ${_allAddresses.length}"); + final newAddresses = await _createNewAddresses(gap, isChange: isChange, type: type); addAddresses(newAddresses); + print("_allAddresses: ${_allAddresses.length}"); return newAddresses; } - Future _generateInitialAddresses( - {BitcoinAddressType type = SegwitAddresType.p2wpkh}) async { - var countOfReceiveAddresses = 0; - var countOfHiddenAddresses = 0; - - _addresses.forEach((addr) { - if (addr.type == type) { - if (addr.isChange) { - countOfHiddenAddresses += 1; - return; - } - - countOfReceiveAddresses += 1; - } - }); - - if (countOfReceiveAddresses < defaultReceiveAddressesCount) { - final addressesCount = defaultReceiveAddressesCount - countOfReceiveAddresses; - final newAddresses = await _createNewAddresses(addressesCount, - startIndex: countOfReceiveAddresses, isHidden: false, type: type); - addAddresses(newAddresses); - } - - if (countOfHiddenAddresses < defaultChangeAddressesCount) { - final addressesCount = defaultChangeAddressesCount - countOfHiddenAddresses; - final newAddresses = await _createNewAddresses(addressesCount, - startIndex: countOfHiddenAddresses, isHidden: true, type: type); - addAddresses(newAddresses); - } + @action + Future generateInitialAddresses({required BitcoinAddressType type}) async { + await discoverAddresses(isChange: false, gap: defaultReceiveAddressesCount, type: type); + await discoverAddresses(isChange: true, gap: defaultChangeAddressesCount, type: type); } - Future> _createNewAddresses(int count, - {int startIndex = 0, bool isHidden = false, BitcoinAddressType? type}) async { + @action + Future> _createNewAddresses( + int count, { + bool isChange = false, + BitcoinAddressType? type, + }) async { final list = []; + final startIndex = isChange ? totalCountOfChangeAddresses : totalCountOfReceiveAddresses; for (var i = startIndex; i < count + startIndex; i++) { final address = BitcoinAddressRecord( await getAddressAsync( - account: _getAccount(isHidden), - index: i, - hd: bip32, - addressType: type ?? addressPageType), + isChange: isChange, + index: i, + addressType: type ?? addressPageType, + ), index: i, - isChange: isHidden, + isChange: isChange, type: type ?? addressPageType, network: network, ); @@ -627,11 +594,10 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store { @action void addAddresses(Iterable addresses) { - final addressesSet = this._addresses.toSet(); - addressesSet.addAll(addresses); - this._addresses.clear(); - this._addresses.addAll(addressesSet); + this._allAddresses.addAll(addresses); updateAddressesByMatch(); + updateReceiveAddresses(); + updateChangeAddresses(); } @action @@ -653,7 +619,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store { } void _validateAddresses() { - _addresses.forEach((element) async { + _allAddresses.forEach((element) async { if (element.type == SegwitAddresType.mweb) { // this would add a ton of startup lag for mweb addresses since we have 1000 of them return; @@ -661,18 +627,16 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store { if (!element.isChange && element.address != await getAddressAsync( - account: 0, + isChange: false, index: element.index, - hd: bip32, addressType: element.type, )) { element.isChange = true; } else if (element.isChange && element.address != await getAddressAsync( - account: 1, + isChange: true, index: element.index, - hd: bip32, addressType: element.type, )) { element.isChange = false; @@ -692,11 +656,11 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store { return _isAddressByType(addressRecord, addressPageType); } - int _getAccount(bool isHidden) => isHidden ? 1 : 0; bool _isAddressByType(BitcoinAddressRecord addr, BitcoinAddressType type) => addr.type == type; - bool _isUnusedReceiveAddressByType(BitcoinAddressRecord addr, BitcoinAddressType type) => - !addr.isChange && !addr.isUsed && addr.type == type; + bool _isUnusedReceiveAddressByType(BitcoinAddressRecord addr, BitcoinAddressType type) { + return !addr.isChange && !addr.isUsed && addr.type == type; + } @action void deleteSilentPaymentAddress(String address) { diff --git a/cw_bitcoin/lib/litecoin_hardware_wallet_service.dart b/cw_bitcoin/lib/litecoin_hardware_wallet_service.dart index 62840933c..c2f2aa22e 100644 --- a/cw_bitcoin/lib/litecoin_hardware_wallet_service.dart +++ b/cw_bitcoin/lib/litecoin_hardware_wallet_service.dart @@ -2,7 +2,6 @@ import 'dart:async'; import 'package:bitcoin_base/bitcoin_base.dart'; import 'package:blockchain_utils/blockchain_utils.dart'; -import 'package:cw_bitcoin/utils.dart'; import 'package:cw_core/hardware/hardware_account_data.dart'; import 'package:ledger_flutter_plus/ledger_flutter_plus.dart'; import 'package:ledger_litecoin/ledger_litecoin.dart'; @@ -12,8 +11,7 @@ class LitecoinHardwareWalletService { final LedgerConnection ledgerConnection; - Future> getAvailableAccounts( - {int index = 0, int limit = 5}) async { + Future> getAvailableAccounts({int index = 0, int limit = 5}) async { final litecoinLedgerApp = LitecoinLedgerApp(ledgerConnection); await litecoinLedgerApp.getVersion(); @@ -27,14 +25,13 @@ class LitecoinHardwareWalletService { final xpub = await litecoinLedgerApp.getXPubKey( accountsDerivationPath: derivationPath, xPubVersion: int.parse(hex.encode(xpubVersion.public), radix: 16)); - final hd = Bip32Slip10Secp256k1.fromExtendedKey(xpub, xpubVersion) - .childKey(Bip32KeyIndex(0)); + final bip32 = + Bip32Slip10Secp256k1.fromExtendedKey(xpub, xpubVersion).childKey(Bip32KeyIndex(0)); - final address = generateP2WPKHAddress( - hd: hd, index: 0, network: LitecoinNetwork.mainnet); + final address = P2wpkhAddress.fromBip32(bip32: bip32, isChange: false, index: 0); accounts.add(HardwareAccountData( - address: address, + address: address.toAddress(LitecoinNetwork.mainnet), accountIndex: i, derivationPath: derivationPath, xpub: xpub, diff --git a/cw_bitcoin/lib/litecoin_wallet.dart b/cw_bitcoin/lib/litecoin_wallet.dart index 45c6d9285..7c581ab4e 100644 --- a/cw_bitcoin/lib/litecoin_wallet.dart +++ b/cw_bitcoin/lib/litecoin_wallet.dart @@ -1,6 +1,5 @@ import 'dart:async'; import 'dart:convert'; -import 'dart:typed_data'; import 'package:convert/convert.dart' as convert; import 'dart:math'; @@ -87,8 +86,8 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store { mempoolAPIEnabled: mempoolAPIEnabled, ) { if (seedBytes != null) { - mwebHd = Bip32Slip10Secp256k1.fromSeed(seedBytes).derivePath( - "m/1000'") as Bip32Slip10Secp256k1; + mwebHd = + Bip32Slip10Secp256k1.fromSeed(seedBytes).derivePath("m/1000'") as Bip32Slip10Secp256k1; mwebEnabled = alwaysScan ?? false; } else { mwebHd = null; @@ -772,7 +771,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store { }); // copy coin control attributes to mwebCoins: - await updateCoins(mwebUnspentCoins); + await updateCoins(mwebUnspentCoins.toSet()); // get regular ltc unspents (this resets unspentCoins): await super.updateAllUnspents(); // add the mwebCoins: @@ -810,11 +809,8 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store { } @override - Future fetchBalances(List addresses) async { - final nonMwebAddresses = walletAddresses.allAddresses - .where((address) => RegexUtils.addressTypeFromStr(address.address, network) is! MwebAddress) - .toList(); - final balance = await super.fetchBalances(nonMwebAddresses); + Future fetchBalances() async { + final balance = await super.fetchBalances(); if (!mwebEnabled) { return balance; @@ -980,8 +976,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store { if (!mwebEnabled) { tx.changeAddressOverride = - (await (walletAddresses as LitecoinWalletAddresses) - .getChangeAddress(isPegIn: false)) + (await (walletAddresses as LitecoinWalletAddresses).getChangeAddress(isPegIn: false)) .address; return tx; } @@ -1021,10 +1016,9 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store { bool isPegIn = !hasMwebInput && hasMwebOutput; bool isRegular = !hasMwebInput && !hasMwebOutput; - tx.changeAddressOverride = - (await (walletAddresses as LitecoinWalletAddresses) - .getChangeAddress(isPegIn: isPegIn || isRegular)) - .address; + tx.changeAddressOverride = (await (walletAddresses as LitecoinWalletAddresses) + .getChangeAddress(isPegIn: isPegIn || isRegular)) + .address; if (!hasMwebInput && !hasMwebOutput) { tx.isMweb = false; return tx; @@ -1058,7 +1052,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store { .firstWhere((utxo) => utxo.hash == e.value.txId && utxo.vout == e.value.txIndex); final key = ECPrivate.fromBip32( bip32: walletAddresses.bip32, - account: utxo.bitcoinAddressRecord.isChange ? 1 : 0, + account: BitcoinAddressUtils.getAccountFromChange(utxo.bitcoinAddressRecord.isChange), index: utxo.bitcoinAddressRecord.index, ); final digest = tx2.getTransactionSegwitDigit( @@ -1277,8 +1271,8 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store { @override void setLedgerConnection(LedgerConnection connection) { _ledgerConnection = connection; - _litecoinLedgerApp = - LitecoinLedgerApp(_ledgerConnection!, derivationPath: walletInfo.derivationInfo!.derivationPath!); + _litecoinLedgerApp = LitecoinLedgerApp(_ledgerConnection!, + derivationPath: walletInfo.derivationInfo!.derivationPath!); } @override @@ -1314,19 +1308,17 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store { if (maybeChangePath != null) changePath ??= maybeChangePath.derivationPath; } - final rawHex = await _litecoinLedgerApp!.createTransaction( - inputs: readyInputs, - outputs: outputs - .map((e) => TransactionOutput.fromBigInt( - (e as BitcoinOutput).value, Uint8List.fromList(e.address.toScriptPubKey().toBytes()))) - .toList(), - changePath: changePath, - sigHashType: 0x01, - additionals: ["bech32"], - isSegWit: true, - useTrustedInputForSegwit: true - ); + inputs: readyInputs, + outputs: outputs + .map((e) => TransactionOutput.fromBigInt((e as BitcoinOutput).value, + Uint8List.fromList(e.address.toScriptPubKey().toBytes()))) + .toList(), + changePath: changePath, + sigHashType: 0x01, + additionals: ["bech32"], + isSegWit: true, + useTrustedInputForSegwit: true); return BtcTransaction.fromRaw(rawHex); } diff --git a/cw_bitcoin/lib/litecoin_wallet_addresses.dart b/cw_bitcoin/lib/litecoin_wallet_addresses.dart index b6e7b4428..7ff87bfd5 100644 --- a/cw_bitcoin/lib/litecoin_wallet_addresses.dart +++ b/cw_bitcoin/lib/litecoin_wallet_addresses.dart @@ -6,7 +6,6 @@ import 'package:bitcoin_base/bitcoin_base.dart'; import 'package:blockchain_utils/blockchain_utils.dart'; import 'package:cw_bitcoin/bitcoin_address_record.dart'; import 'package:cw_bitcoin/bitcoin_unspent.dart'; -import 'package:cw_bitcoin/electrum_wallet.dart'; import 'package:cw_bitcoin/electrum_wallet_addresses.dart'; import 'package:cw_core/wallet_info.dart'; import 'package:cw_mweb/cw_mweb.dart'; @@ -15,11 +14,9 @@ import 'package:mobx/mobx.dart'; part 'litecoin_wallet_addresses.g.dart'; -class LitecoinWalletAddresses = LitecoinWalletAddressesBase - with _$LitecoinWalletAddresses; +class LitecoinWalletAddresses = LitecoinWalletAddressesBase with _$LitecoinWalletAddresses; -abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses - with Store { +abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses with Store { LitecoinWalletAddressesBase( WalletInfo walletInfo, { required super.bip32, @@ -44,14 +41,13 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses List mwebAddrs = []; bool generating = false; - List get scanSecret => - mwebHd!.childKey(Bip32KeyIndex(0x80000000)).privateKey.privKey.raw; + List get scanSecret => mwebHd!.childKey(Bip32KeyIndex(0x80000000)).privateKey.privKey.raw; List get spendPubkey => mwebHd!.childKey(Bip32KeyIndex(0x80000001)).publicKey.pubKey.compressed; @override Future init() async { - if (!isHardwareWallet) await initMwebAddresses(); + if (!super.isHardwareWallet) await initMwebAddresses(); await super.init(); } @@ -122,31 +118,29 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses @override BitcoinBaseAddress generateAddress({ - required int account, + required bool isChange, required int index, - required Bip32Slip10Secp256k1 hd, required BitcoinAddressType addressType, }) { if (addressType == SegwitAddresType.mweb) { return MwebAddress.fromAddress(address: mwebAddrs[0], network: network); } - return P2wpkhAddress.fromBip32(account: account, bip32: hd, index: index); + return P2wpkhAddress.fromBip32(bip32: bip32, isChange: isChange, index: index); } } @override Future getAddressAsync({ - required int account, + required bool isChange, required int index, - required Bip32Slip10Secp256k1 hd, required BitcoinAddressType addressType, }) async { if (addressType == SegwitAddresType.mweb) { await ensureMwebAddressUpToIndexExists(index); } - return getAddress(account: account, index: index, hd: hd, addressType: addressType); + return getAddress(isChange: isChange, index: index, addressType: addressType); } @action diff --git a/cw_bitcoin/lib/litecoin_wallet_service.dart b/cw_bitcoin/lib/litecoin_wallet_service.dart index 2d68a86ad..d13dcc8a4 100644 --- a/cw_bitcoin/lib/litecoin_wallet_service.dart +++ b/cw_bitcoin/lib/litecoin_wallet_service.dart @@ -170,6 +170,7 @@ class LitecoinWalletService extends WalletService< walletInfo: credentials.walletInfo!, unspentCoinsInfo: unspentCoinsInfoSource, encryptionFileUtils: encryptionFileUtilsFor(isDirect), + mempoolAPIEnabled: mempoolAPIEnabled, ); await wallet.save(); await wallet.init(); diff --git a/cw_bitcoin/pubspec.lock b/cw_bitcoin/pubspec.lock index 3ce7a37da..ad03398e3 100644 --- a/cw_bitcoin/pubspec.lock +++ b/cw_bitcoin/pubspec.lock @@ -564,10 +564,10 @@ packages: dependency: "direct main" description: name: ledger_flutter_plus - sha256: ea3ed586e1697776dacf42ac979095f1ca3bd143bf007cbe5c78e09cb6943f42 + sha256: c7b04008553193dbca7e17b430768eecc372a72b0ff3625b5e7fc5e5c8d3231b url: "https://pub.dev" source: hosted - version: "1.2.5" + version: "1.4.1" ledger_litecoin: dependency: "direct main" description: diff --git a/cw_bitcoin/pubspec.yaml b/cw_bitcoin/pubspec.yaml index 821f9b7f3..94ae3e046 100644 --- a/cw_bitcoin/pubspec.yaml +++ b/cw_bitcoin/pubspec.yaml @@ -28,10 +28,6 @@ dependencies: cryptography: ^2.0.5 blockchain_utils: path: /home/rafael/Working/blockchain_utils/ - ledger_flutter: ^1.0.1 - ledger_bitcoin: - git: - url: https://github.com/cake-tech/ledger-bitcoin cw_mweb: path: ../cw_mweb grpc: ^3.2.4 diff --git a/cw_bitcoin_cash/lib/src/bitcoin_cash_wallet_addresses.dart b/cw_bitcoin_cash/lib/src/bitcoin_cash_wallet_addresses.dart index ae195bf6b..704d1e843 100644 --- a/cw_bitcoin_cash/lib/src/bitcoin_cash_wallet_addresses.dart +++ b/cw_bitcoin_cash/lib/src/bitcoin_cash_wallet_addresses.dart @@ -1,5 +1,4 @@ import 'package:bitcoin_base/bitcoin_base.dart'; -import 'package:blockchain_utils/blockchain_utils.dart'; import 'package:cw_bitcoin/electrum_wallet_addresses.dart'; import 'package:cw_core/wallet_info.dart'; import 'package:mobx/mobx.dart'; @@ -22,10 +21,9 @@ abstract class BitcoinCashWalletAddressesBase extends ElectrumWalletAddresses wi @override BitcoinBaseAddress generateAddress({ - required int account, + required bool isChange, required int index, - required Bip32Slip10Secp256k1 hd, required BitcoinAddressType addressType, }) => - P2pkhAddress.fromBip32(account: account, bip32: hd, index: index); + P2pkhAddress.fromBip32(bip32: bip32, isChange: isChange, index: index); } diff --git a/cw_core/lib/wallet_keys_file.dart b/cw_core/lib/wallet_keys_file.dart index 638cdc39d..ff680f9e1 100644 --- a/cw_core/lib/wallet_keys_file.dart +++ b/cw_core/lib/wallet_keys_file.dart @@ -27,7 +27,10 @@ mixin WalletKeysFile BitcoinRestoreWalletFromSeedCredentials( name: name, mnemonic: mnemonic, password: password, - derivationType: derivationType, - derivationPath: derivationPath, passphrase: passphrase, ); @@ -373,66 +369,71 @@ class CWBitcoin extends Bitcoin { } for (DerivationType dType in electrum_derivations.keys) { - late Uint8List seedBytes; - if (dType == DerivationType.electrum) { - seedBytes = await mnemonicToSeedBytes(mnemonic, passphrase: passphrase ?? ""); - } else if (dType == DerivationType.bip39) { - seedBytes = bip39.mnemonicToSeed(mnemonic, passphrase: passphrase ?? ''); - } - - for (DerivationInfo dInfo in electrum_derivations[dType]!) { - try { - DerivationInfo dInfoCopy = DerivationInfo( - derivationType: dInfo.derivationType, - derivationPath: dInfo.derivationPath, - description: dInfo.description, - scriptType: dInfo.scriptType, - ); - - String balancePath = dInfoCopy.derivationPath!; - int derivationDepth = _countCharOccurrences(balancePath, '/'); - - // for BIP44 - if (derivationDepth == 3 || derivationDepth == 1) { - // we add "/0" so that we generate account 0 - balancePath += "/0"; - } - - final hd = Bip32Slip10Secp256k1.fromSeed(seedBytes).derivePath(balancePath) - as Bip32Slip10Secp256k1; - - // derive address at index 0: - String? address; - switch (dInfoCopy.scriptType) { - case "p2wpkh": - address = P2wpkhAddress.fromBip32(bip32: hd, account: 0, index: 0).toAddress(network); - break; - case "p2pkh": - address = P2pkhAddress.fromBip32(bip32: hd, account: 0, index: 0).toAddress(network); - break; - case "p2wpkh-p2sh": - address = P2shAddress.fromBip32(bip32: hd, account: 0, index: 0).toAddress(network); - break; - case "p2tr": - address = P2trAddress.fromBip32(bip32: hd, account: 0, index: 0).toAddress(network); - break; - default: - continue; - } - - final sh = BitcoinAddressUtils.scriptHash(address, network: network); - final history = await electrumClient.getHistory(sh); - - final balance = await electrumClient.getBalance(sh); - dInfoCopy.balance = balance.entries.firstOrNull?.value.toString() ?? "0"; - dInfoCopy.address = address; - dInfoCopy.transactionsCount = history.length; - - list.add(dInfoCopy); - } catch (e, s) { - print("derivationInfoError: $e"); - print("derivationInfoStack: $s"); + try { + late List seedBytes; + if (dType == DerivationType.electrum) { + seedBytes = ElectrumV2SeedGenerator.generateFromString(mnemonic, passphrase); + } else if (dType == DerivationType.bip39) { + seedBytes = Bip39SeedGenerator.generateFromString(mnemonic, passphrase); } + + for (DerivationInfo dInfo in electrum_derivations[dType]!) { + try { + DerivationInfo dInfoCopy = DerivationInfo( + derivationType: dInfo.derivationType, + derivationPath: dInfo.derivationPath, + description: dInfo.description, + scriptType: dInfo.scriptType, + ); + + String balancePath = dInfoCopy.derivationPath!; + int derivationDepth = _countCharOccurrences(balancePath, '/'); + + // for BIP44 + if (derivationDepth == 3 || derivationDepth == 1) { + // we add "/0" so that we generate account 0 + balancePath += "/0"; + } + + final bip32 = Bip32Slip10Secp256k1.fromSeed(seedBytes); + final bip32BalancePath = Bip32PathParser.parse(balancePath); + + // derive address at index 0: + final path = bip32BalancePath.addElem(Bip32KeyIndex(0)); + String? address; + switch (dInfoCopy.scriptType) { + case "p2wpkh": + address = P2wpkhAddress.fromPath(bip32: bip32, path: path).toAddress(network); + break; + case "p2pkh": + address = P2pkhAddress.fromPath(bip32: bip32, path: path).toAddress(network); + break; + case "p2wpkh-p2sh": + address = P2shAddress.fromPath(bip32: bip32, path: path).toAddress(network); + break; + case "p2tr": + address = P2trAddress.fromPath(bip32: bip32, path: path).toAddress(network); + break; + default: + continue; + } + + final sh = BitcoinAddressUtils.scriptHash(address, network: network); + final history = await electrumClient.getHistory(sh); + + final balance = await electrumClient.getBalance(sh); + dInfoCopy.balance = balance.entries.firstOrNull?.value.toString() ?? "0"; + dInfoCopy.address = address; + dInfoCopy.transactionsCount = history.length; + + list.add(dInfoCopy); + } catch (e, s) { + print("derivationInfoError: $e"); + print("derivationInfoStack: $s"); + } + } + } catch (e) { + print("seed error: $e"); } } diff --git a/lib/src/screens/restore/wallet_restore_page.dart b/lib/src/screens/restore/wallet_restore_page.dart index 6215e26c3..97a612d02 100644 --- a/lib/src/screens/restore/wallet_restore_page.dart +++ b/lib/src/screens/restore/wallet_restore_page.dart @@ -54,8 +54,10 @@ class WalletRestorePage extends BasePage { _validateOnChange(isPolyseed: isPolyseed); }, displayWalletPassword: walletRestoreViewModel.hasWalletPassword, - onPasswordChange: (String password) => walletRestoreViewModel.walletPassword = password, - onRepeatedPasswordChange: (String repeatedPassword) => walletRestoreViewModel.repeatedWalletPassword = repeatedPassword)); + onPasswordChange: (String password) => + walletRestoreViewModel.walletPassword = password, + onRepeatedPasswordChange: (String repeatedPassword) => + walletRestoreViewModel.repeatedWalletPassword = repeatedPassword)); break; case WalletRestoreMode.keys: _pages.add(WalletRestoreFromKeysFrom( @@ -69,8 +71,10 @@ class WalletRestorePage extends BasePage { }, displayPrivateKeyField: walletRestoreViewModel.hasRestoreFromPrivateKey, displayWalletPassword: walletRestoreViewModel.hasWalletPassword, - onPasswordChange: (String password) => walletRestoreViewModel.walletPassword = password, - onRepeatedPasswordChange: (String repeatedPassword) => walletRestoreViewModel.repeatedWalletPassword = repeatedPassword, + onPasswordChange: (String password) => + walletRestoreViewModel.walletPassword = password, + onRepeatedPasswordChange: (String repeatedPassword) => + walletRestoreViewModel.repeatedWalletPassword = repeatedPassword, onHeightOrDateEntered: (value) => walletRestoreViewModel.isButtonEnabled = value)); break; default: @@ -379,38 +383,40 @@ class WalletRestorePage extends BasePage { walletRestoreViewModel.state = IsExecutingState(); - DerivationInfo? dInfo; + if (walletRestoreViewModel.type == WalletType.nano) { + DerivationInfo? dInfo; - // get info about the different derivations: - List derivations = - await walletRestoreViewModel.getDerivationInfo(_credentials()); + // get info about the different derivations: + List derivations = + await walletRestoreViewModel.getDerivationInfo(_credentials()); - int derivationsWithHistory = 0; - int derivationWithHistoryIndex = 0; - for (int i = 0; i < derivations.length; i++) { - if (derivations[i].transactionsCount > 0) { - derivationsWithHistory++; - derivationWithHistoryIndex = i; + int derivationsWithHistory = 0; + int derivationWithHistoryIndex = 0; + for (int i = 0; i < derivations.length; i++) { + if (derivations[i].transactionsCount > 0) { + derivationsWithHistory++; + derivationWithHistoryIndex = i; + } } - } - if (derivationsWithHistory > 1) { - dInfo = await Navigator.of(context).pushNamed( - Routes.restoreWalletChooseDerivation, - arguments: derivations, - ) as DerivationInfo?; - } else if (derivationsWithHistory == 1) { - dInfo = derivations[derivationWithHistoryIndex]; - } else if (derivations.length == 1) { - // we only return 1 derivation if we're pretty sure we know which one to use: - dInfo = derivations.first; - } else { - // if we have multiple possible derivations, and none (or multiple) have histories - // we just default to the most common one: - dInfo = walletRestoreViewModel.getCommonRestoreDerivation(); - } + if (derivationsWithHistory > 1) { + dInfo = await Navigator.of(context).pushNamed( + Routes.restoreWalletChooseDerivation, + arguments: derivations, + ) as DerivationInfo?; + } else if (derivationsWithHistory == 1) { + dInfo = derivations[derivationWithHistoryIndex]; + } else if (derivations.length == 1) { + // we only return 1 derivation if we're pretty sure we know which one to use: + dInfo = derivations.first; + } else { + // if we have multiple possible derivations, and none (or multiple) have histories + // we just default to the most common one: + dInfo = walletRestoreViewModel.getCommonRestoreDerivation(); + } - this.derivationInfo = dInfo; + this.derivationInfo = dInfo; + } await walletRestoreViewModel.create(options: _credentials()); seedSettingsViewModel.setPassphrase(null); diff --git a/lib/store/settings_store.dart b/lib/store/settings_store.dart index bc06fbcc4..bcea80a54 100644 --- a/lib/store/settings_store.dart +++ b/lib/store/settings_store.dart @@ -602,6 +602,7 @@ abstract class SettingsStoreBase with Store { static const defaultActionsMode = 11; static const defaultPinCodeTimeOutDuration = PinCodeRequiredDuration.tenMinutes; static const defaultAutoGenerateSubaddressStatus = AutoGenerateSubaddressStatus.initialized; + // static final walletPasswordDirectInput = Platform.isLinux; static final walletPasswordDirectInput = false; static const defaultSeedPhraseLength = SeedPhraseLength.twelveWords; static const defaultMoneroSeedType = MoneroSeedType.defaultSeedType; diff --git a/lib/view_model/restore/restore_from_qr_vm.dart b/lib/view_model/restore/restore_from_qr_vm.dart index cbdad85b8..0a2c04d7f 100644 --- a/lib/view_model/restore/restore_from_qr_vm.dart +++ b/lib/view_model/restore/restore_from_qr_vm.dart @@ -38,7 +38,7 @@ abstract class WalletRestorationFromQRVMBase extends WalletCreationVM with Store wif = '', address = '', super(appStore, walletInfoSource, walletCreationService, seedSettingsViewModel, - type: type, isRecovery: true); + type: type, isRecovery: true); @observable int height; @@ -113,21 +113,11 @@ abstract class WalletRestorationFromQRVMBase extends WalletCreationVM with Store ); case WalletType.bitcoin: case WalletType.litecoin: - - final derivationInfoList = await getDerivationInfoFromQRCredentials(restoreWallet); - DerivationInfo derivationInfo; - if (derivationInfoList.isEmpty) { - derivationInfo = getDefaultCreateDerivation()!; - } else { - derivationInfo = derivationInfoList.first; - } return bitcoin!.createBitcoinRestoreWalletFromSeedCredentials( name: name, mnemonic: restoreWallet.mnemonicSeed ?? '', password: password, passphrase: restoreWallet.passphrase, - derivationType: derivationInfo.derivationType!, - derivationPath: derivationInfo.derivationPath!, ); case WalletType.bitcoinCash: return bitcoinCash!.createBitcoinCashRestoreWalletFromSeedCredentials( @@ -144,8 +134,7 @@ abstract class WalletRestorationFromQRVMBase extends WalletCreationVM with Store passphrase: restoreWallet.passphrase, ); case WalletType.nano: - final derivationInfo = - (await getDerivationInfoFromQRCredentials(restoreWallet)).first; + final derivationInfo = (await getDerivationInfoFromQRCredentials(restoreWallet)).first; return nano!.createNanoRestoreWalletFromSeedCredentials( name: name, mnemonic: restoreWallet.mnemonicSeed ?? '', @@ -190,8 +179,8 @@ abstract class WalletRestorationFromQRVMBase extends WalletCreationVM with Store } @override - Future processFromRestoredWallet(WalletCredentials credentials, - RestoredWallet restoreWallet) async { + Future processFromRestoredWallet( + WalletCredentials credentials, RestoredWallet restoreWallet) async { try { switch (restoreWallet.restoreMode) { case WalletRestoreMode.keys: diff --git a/lib/view_model/wallet_restore_view_model.dart b/lib/view_model/wallet_restore_view_model.dart index d37b69f74..59623057d 100644 --- a/lib/view_model/wallet_restore_view_model.dart +++ b/lib/view_model/wallet_restore_view_model.dart @@ -105,8 +105,6 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store { mnemonic: seed, password: password, passphrase: passphrase, - derivationType: derivationInfo!.derivationType!, - derivationPath: derivationInfo.derivationPath!, ); case WalletType.haven: return haven!.createHavenRestoreWalletFromSeedCredentials( diff --git a/tool/configure.dart b/tool/configure.dart index 68408ee2e..07e523125 100644 --- a/tool/configure.dart +++ b/tool/configure.dart @@ -148,8 +148,6 @@ abstract class Bitcoin { required String name, required String mnemonic, required String password, - required DerivationType derivationType, - required String derivationPath, String? passphrase, }); WalletCredentials createBitcoinRestoreWalletFromWIFCredentials({required String name, required String password, required String wif, WalletInfo? walletInfo});