From b04b262761de2609fb56f3c586e3260d0375876d Mon Sep 17 00:00:00 2001 From: Rafael Saes Date: Wed, 6 Dec 2023 11:47:14 -0300 Subject: [PATCH] feat: store labeled silent addresses and restore from snapshot --- cw_bitcoin/lib/bitcoin_wallet.dart | 31 ++++++++++----- cw_bitcoin/lib/bitcoin_wallet_addresses.dart | 2 + cw_bitcoin/lib/electrum_wallet.dart | 2 + cw_bitcoin/lib/electrum_wallet_addresses.dart | 11 ++++-- cw_bitcoin/lib/electrum_wallet_snapshot.dart | 38 ++++++++++++++----- 5 files changed, 61 insertions(+), 23 deletions(-) diff --git a/cw_bitcoin/lib/bitcoin_wallet.dart b/cw_bitcoin/lib/bitcoin_wallet.dart index 09dc852a8..b17a780f4 100644 --- a/cw_bitcoin/lib/bitcoin_wallet.dart +++ b/cw_bitcoin/lib/bitcoin_wallet.dart @@ -26,9 +26,11 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store { bitcoin.NetworkType? networkType, required Uint8List seedBytes, List? initialAddresses, + List? initialSilentAddresses, ElectrumBalance? initialBalance, int initialRegularAddressIndex = 0, int initialChangeAddressIndex = 0, + int initialSilentAddressIndex = 0, bitcoin.SilentPaymentReceiver? silentAddress}) : super( networkType: networkType ?? bitcoin.bitcoin, @@ -41,24 +43,29 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store { walletAddresses = BitcoinWalletAddresses(walletInfo, transactionHistory: super.transactionHistory, initialAddresses: initialAddresses, + initialSilentAddresses: initialSilentAddresses, initialRegularAddressIndex: initialRegularAddressIndex, initialChangeAddressIndex: initialChangeAddressIndex, + initialSilentAddressIndex: initialSilentAddressIndex, mainHd: hd, sideHd: bitcoin.HDWallet.fromSeed(seedBytes, network: networkType).derivePath("m/0'/1"), networkType: networkType ?? bitcoin.bitcoin, silentAddress: silentAddress); } - static Future create( - {required String mnemonic, - required String password, - required WalletInfo walletInfo, - required Box unspentCoinsInfo, - bitcoin.NetworkType? networkType, - List? initialAddresses, - ElectrumBalance? initialBalance, - int initialRegularAddressIndex = 0, - int initialChangeAddressIndex = 0}) async { + static Future create({ + required String mnemonic, + required String password, + required WalletInfo walletInfo, + required Box unspentCoinsInfo, + bitcoin.NetworkType? networkType, + List? initialAddresses, + List? initialSilentAddresses, + ElectrumBalance? initialBalance, + int initialRegularAddressIndex = 0, + int initialChangeAddressIndex = 0, + int initialSilentAddressIndex = 0, + }) async { return BitcoinWallet( mnemonic: mnemonic, password: password, @@ -66,10 +73,12 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store { unspentCoinsInfo: unspentCoinsInfo, networkType: networkType, initialAddresses: initialAddresses, + initialSilentAddresses: initialSilentAddresses, initialBalance: initialBalance, seedBytes: await mnemonicToSeedBytes(mnemonic), initialRegularAddressIndex: initialRegularAddressIndex, initialChangeAddressIndex: initialChangeAddressIndex, + initialSilentAddressIndex: initialSilentAddressIndex, silentAddress: await bitcoin.SilentPaymentReceiver.fromMnemonic(mnemonic, hrp: networkType == bitcoin.bitcoin ? 'sp' : 'tsp')); } @@ -88,10 +97,12 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store { unspentCoinsInfo: unspentCoinsInfo, networkType: snp.networkType, initialAddresses: snp.addresses, + initialSilentAddresses: snp.silentAddresses, initialBalance: snp.balance, seedBytes: await mnemonicToSeedBytes(snp.mnemonic), initialRegularAddressIndex: snp.regularAddressIndex, initialChangeAddressIndex: snp.changeAddressIndex, + initialSilentAddressIndex: snp.silentAddressIndex, silentAddress: await bitcoin.SilentPaymentReceiver.fromMnemonic(snp.mnemonic, hrp: snp.networkType == bitcoin.bitcoin ? 'sp' : 'tsp')); } diff --git a/cw_bitcoin/lib/bitcoin_wallet_addresses.dart b/cw_bitcoin/lib/bitcoin_wallet_addresses.dart index 11c532ba4..78520a033 100644 --- a/cw_bitcoin/lib/bitcoin_wallet_addresses.dart +++ b/cw_bitcoin/lib/bitcoin_wallet_addresses.dart @@ -16,8 +16,10 @@ abstract class BitcoinWalletAddressesBase extends ElectrumWalletAddresses with S required super.networkType, required super.transactionHistory, super.initialAddresses, + super.initialSilentAddresses, super.initialRegularAddressIndex = 0, super.initialChangeAddressIndex = 0, + super.initialSilentAddressIndex = 0, super.silentAddress, }) : super(walletInfo); diff --git a/cw_bitcoin/lib/electrum_wallet.dart b/cw_bitcoin/lib/electrum_wallet.dart index 001d21f51..1b45fb4ef 100644 --- a/cw_bitcoin/lib/electrum_wallet.dart +++ b/cw_bitcoin/lib/electrum_wallet.dart @@ -533,7 +533,9 @@ abstract class ElectrumWalletBase 'mnemonic': mnemonic, 'account_index': walletAddresses.currentReceiveAddressIndex.toString(), 'change_address_index': walletAddresses.currentChangeAddressIndex.toString(), + 'silent_address_index': walletAddresses.currentSilentAddressIndex.toString(), 'addresses': walletAddresses.addresses.map((addr) => addr.toJSON()).toList(), + 'silent_addresses': walletAddresses.silentAddresses.map((addr) => addr.toJSON()).toList(), 'balance': balance[currency]?.toJSON(), 'network_type': networkType == bitcoin.bitcoin ? 'mainnet' : 'testnet', }); diff --git a/cw_bitcoin/lib/electrum_wallet_addresses.dart b/cw_bitcoin/lib/electrum_wallet_addresses.dart index b072f46b4..00b38cb8e 100644 --- a/cw_bitcoin/lib/electrum_wallet_addresses.dart +++ b/cw_bitcoin/lib/electrum_wallet_addresses.dart @@ -19,8 +19,10 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store { required this.transactionHistory, required this.networkType, List? initialAddresses, + List? initialSilentAddresses, int initialRegularAddressIndex = 0, int initialChangeAddressIndex = 0, + int initialSilentAddressIndex = 0, bitcoin.SilentPaymentReceiver? silentAddress, }) : addresses = ObservableList.of((initialAddresses ?? []).toSet()), primarySilentAddress = silentAddress, @@ -30,11 +32,14 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store { changeAddresses = ObservableList.of((initialAddresses ?? []) .where((addressRecord) => addressRecord.isHidden && !addressRecord.isUsed) .toSet()), - silentAddresses = ObservableList.of((initialAddresses ?? []) - .where((addressRecord) => addressRecord.silentAddressLabel != null) + silentAddresses = ObservableList.of((initialSilentAddresses ?? []) + .where((addressRecord) => + addressRecord.silentAddressLabel != null && + addressRecord.silentPaymentTweak != null) .toSet()), currentReceiveAddressIndex = initialRegularAddressIndex, currentChangeAddressIndex = initialChangeAddressIndex, + currentSilentAddressIndex = initialSilentAddressIndex, super(walletInfo); static const defaultReceiveAddressesCount = 22; @@ -106,7 +111,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store { int currentReceiveAddressIndex; int currentChangeAddressIndex; - int currentSilentAddressIndex = 0; + int currentSilentAddressIndex; @computed int get totalCountOfReceiveAddresses => addresses.fold(0, (acc, addressRecord) { diff --git a/cw_bitcoin/lib/electrum_wallet_snapshot.dart b/cw_bitcoin/lib/electrum_wallet_snapshot.dart index e05e09674..dc30e04ab 100644 --- a/cw_bitcoin/lib/electrum_wallet_snapshot.dart +++ b/cw_bitcoin/lib/electrum_wallet_snapshot.dart @@ -13,10 +13,12 @@ class ElectrumWalletSnapshot { required this.password, required this.mnemonic, required this.addresses, + required this.silentAddresses, required this.balance, required this.networkType, required this.regularAddressIndex, required this.changeAddressIndex, + required this.silentAddressIndex, }); final String name; @@ -25,41 +27,57 @@ class ElectrumWalletSnapshot { String mnemonic; List addresses; + List silentAddresses; ElectrumBalance balance; bitcoin.NetworkType networkType; int regularAddressIndex; int changeAddressIndex; + int silentAddressIndex; static Future load(String name, WalletType type, String password) async { final path = await pathForWallet(name: name, type: type); final jsonSource = await read(path: path, password: password); final data = json.decode(jsonSource) as Map; - final addressesTmp = data['addresses'] as List? ?? []; final mnemonic = data['mnemonic'] as String; + + final addressesTmp = data['addresses'] as List? ?? []; final addresses = addressesTmp .whereType() .map((addr) => BitcoinAddressRecord.fromJSON(addr)) .toList(); + + final silentAddressesTmp = data['silent_addresses'] as List? ?? []; + final silentAddresses = silentAddressesTmp + .whereType() + .map((addr) => BitcoinAddressRecord.fromJSON(addr)) + .toList(); + final balance = ElectrumBalance.fromJSON(data['balance'] as String) ?? ElectrumBalance(confirmed: 0, unconfirmed: 0, frozen: 0); final networkType = data['network_type'] == 'testnet' ? bitcoin.testnet : bitcoin.bitcoin; + var regularAddressIndex = 0; var changeAddressIndex = 0; + var silentAddressIndex = 0; try { regularAddressIndex = int.parse(data['account_index'] as String? ?? '0'); changeAddressIndex = int.parse(data['change_address_index'] as String? ?? '0'); + silentAddressIndex = int.parse(data['silent_address_index'] as String? ?? '0'); } catch (_) {} return ElectrumWalletSnapshot( - name: name, - type: type, - password: password, - mnemonic: mnemonic, - addresses: addresses, - balance: balance, - networkType: networkType, - regularAddressIndex: regularAddressIndex, - changeAddressIndex: changeAddressIndex); + name: name, + type: type, + password: password, + mnemonic: mnemonic, + addresses: addresses, + silentAddresses: silentAddresses, + balance: balance, + networkType: networkType, + regularAddressIndex: regularAddressIndex, + changeAddressIndex: changeAddressIndex, + silentAddressIndex: silentAddressIndex, + ); } }