feat: store labeled silent addresses and restore from snapshot

This commit is contained in:
Rafael Saes 2023-12-06 11:47:14 -03:00
parent 5939b310a0
commit b04b262761
5 changed files with 61 additions and 23 deletions

View file

@ -26,9 +26,11 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
bitcoin.NetworkType? networkType,
required Uint8List seedBytes,
List<BitcoinAddressRecord>? initialAddresses,
List<BitcoinAddressRecord>? 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<BitcoinWallet> create(
{required String mnemonic,
static Future<BitcoinWallet> create({
required String mnemonic,
required String password,
required WalletInfo walletInfo,
required Box<UnspentCoinsInfo> unspentCoinsInfo,
bitcoin.NetworkType? networkType,
List<BitcoinAddressRecord>? initialAddresses,
List<BitcoinAddressRecord>? initialSilentAddresses,
ElectrumBalance? initialBalance,
int initialRegularAddressIndex = 0,
int initialChangeAddressIndex = 0}) async {
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'));
}

View file

@ -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);

View file

@ -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',
});

View file

@ -19,8 +19,10 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
required this.transactionHistory,
required this.networkType,
List<BitcoinAddressRecord>? initialAddresses,
List<BitcoinAddressRecord>? initialSilentAddresses,
int initialRegularAddressIndex = 0,
int initialChangeAddressIndex = 0,
int initialSilentAddressIndex = 0,
bitcoin.SilentPaymentReceiver? silentAddress,
}) : addresses = ObservableList<BitcoinAddressRecord>.of((initialAddresses ?? []).toSet()),
primarySilentAddress = silentAddress,
@ -30,11 +32,14 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
changeAddresses = ObservableList<BitcoinAddressRecord>.of((initialAddresses ?? [])
.where((addressRecord) => addressRecord.isHidden && !addressRecord.isUsed)
.toSet()),
silentAddresses = ObservableList<BitcoinAddressRecord>.of((initialAddresses ?? [])
.where((addressRecord) => addressRecord.silentAddressLabel != null)
silentAddresses = ObservableList<BitcoinAddressRecord>.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) {

View file

@ -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,30 +27,43 @@ class ElectrumWalletSnapshot {
String mnemonic;
List<BitcoinAddressRecord> addresses;
List<BitcoinAddressRecord> silentAddresses;
ElectrumBalance balance;
bitcoin.NetworkType networkType;
int regularAddressIndex;
int changeAddressIndex;
int silentAddressIndex;
static Future<ElectrumWalletSnapshot> 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? ?? <Object>[];
final mnemonic = data['mnemonic'] as String;
final addressesTmp = data['addresses'] as List? ?? <Object>[];
final addresses = addressesTmp
.whereType<String>()
.map((addr) => BitcoinAddressRecord.fromJSON(addr))
.toList();
final silentAddressesTmp = data['silent_addresses'] as List? ?? <Object>[];
final silentAddresses = silentAddressesTmp
.whereType<String>()
.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(
@ -57,9 +72,12 @@ class ElectrumWalletSnapshot {
password: password,
mnemonic: mnemonic,
addresses: addresses,
silentAddresses: silentAddresses,
balance: balance,
networkType: networkType,
regularAddressIndex: regularAddressIndex,
changeAddressIndex: changeAddressIndex);
changeAddressIndex: changeAddressIndex,
silentAddressIndex: silentAddressIndex,
);
}
}