Skip to content

Commit c35dec0

Browse files
committed
feat: restore & scan imp
1 parent 9bb3d9f commit c35dec0

13 files changed

+450
-174
lines changed

cw_bitcoin/lib/bitcoin_wallet.dart

+109-40
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,53 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
108108
int initialSilentAddressIndex = 0,
109109
required bool mempoolAPIEnabled,
110110
}) async {
111+
List<int>? seedBytes = null;
112+
final Map<CWBitcoinDerivationType, Bip32Slip10Secp256k1> hdWallets = {};
113+
114+
if (walletInfo.isRecovery) {
115+
for (final derivation in walletInfo.derivations ?? <DerivationInfo>[]) {
116+
if (derivation.description?.contains("SP") ?? false) {
117+
continue;
118+
}
119+
120+
if (derivation.derivationType == DerivationType.bip39) {
121+
seedBytes = Bip39SeedGenerator.generateFromString(mnemonic, passphrase);
122+
hdWallets[CWBitcoinDerivationType.bip39] = Bip32Slip10Secp256k1.fromSeed(seedBytes);
123+
124+
break;
125+
} else {
126+
try {
127+
seedBytes = ElectrumV2SeedGenerator.generateFromString(mnemonic, passphrase);
128+
hdWallets[CWBitcoinDerivationType.electrum] = Bip32Slip10Secp256k1.fromSeed(seedBytes);
129+
} catch (e) {
130+
print("electrum_v2 seed error: $e");
131+
132+
try {
133+
seedBytes = ElectrumV1SeedGenerator(mnemonic).generate();
134+
hdWallets[CWBitcoinDerivationType.electrum] =
135+
Bip32Slip10Secp256k1.fromSeed(seedBytes);
136+
} catch (e) {
137+
print("electrum_v1 seed error: $e");
138+
}
139+
}
140+
141+
break;
142+
}
143+
}
144+
145+
if (hdWallets[CWBitcoinDerivationType.bip39] != null) {
146+
hdWallets[CWBitcoinDerivationType.old_bip39] = hdWallets[CWBitcoinDerivationType.bip39]!;
147+
}
148+
if (hdWallets[CWBitcoinDerivationType.electrum] != null) {
149+
hdWallets[CWBitcoinDerivationType.old_electrum] =
150+
hdWallets[CWBitcoinDerivationType.electrum]!;
151+
}
152+
} else {
153+
seedBytes = walletInfo.derivationInfo?.derivationType == DerivationType.electrum
154+
? ElectrumV2SeedGenerator.generateFromString(mnemonic, passphrase)
155+
: Bip39SeedGenerator.generateFromString(mnemonic, passphrase);
156+
}
157+
111158
return BitcoinWallet(
112159
mnemonic: mnemonic,
113160
passphrase: passphrase ?? "",
@@ -119,9 +166,8 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
119166
initialSilentAddressIndex: initialSilentAddressIndex,
120167
initialBalance: initialBalance,
121168
encryptionFileUtils: encryptionFileUtils,
122-
seedBytes: walletInfo.derivationInfo?.derivationType == DerivationType.electrum
123-
? ElectrumV2SeedGenerator.generateFromString(mnemonic, passphrase)
124-
: Bip39SeedGenerator.generateFromString(mnemonic, passphrase),
169+
seedBytes: seedBytes,
170+
hdWallets: hdWallets,
125171
initialRegularAddressIndex: initialRegularAddressIndex,
126172
initialChangeAddressIndex: initialChangeAddressIndex,
127173
addressPageType: addressPageType,
@@ -253,16 +299,24 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
253299
}
254300

255301
Future<bool> getNodeIsElectrs() async {
256-
final version = await sendWorker(ElectrumWorkerGetVersionRequest()) as List<String>;
302+
if (node?.uri.host.contains("electrs") ?? false) {
303+
return true;
304+
}
305+
306+
final version = await sendWorker(ElectrumWorkerGetVersionRequest());
257307

258-
if (version.isNotEmpty) {
308+
if (version is List<String> && version.isNotEmpty) {
259309
final server = version[0];
260310

261311
if (server.toLowerCase().contains('electrs')) {
262312
node!.isElectrs = true;
263313
node!.save();
264314
return node!.isElectrs!;
265315
}
316+
} else if (version is String && version.toLowerCase().contains('electrs')) {
317+
node!.isElectrs = true;
318+
node!.save();
319+
return node!.isElectrs!;
266320
}
267321

268322
node!.isElectrs = false;
@@ -271,33 +325,39 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
271325
}
272326

273327
Future<bool> getNodeSupportsSilentPayments() async {
274-
return true;
328+
// TODO: handle disconnection on check
329+
// TODO: use cached values
330+
if (node == null) {
331+
return false;
332+
}
333+
334+
final isFulcrum = node!.uri.host.contains("fulcrum");
335+
if (isFulcrum) {
336+
return false;
337+
}
338+
275339
// As of today (august 2024), only ElectrumRS supports silent payments
276-
// if (!(await getNodeIsElectrs())) {
277-
// return false;
278-
// }
340+
if (!(await getNodeIsElectrs())) {
341+
return false;
342+
}
279343

280-
// if (node == null) {
281-
// return false;
282-
// }
344+
try {
345+
final workerResponse = (await sendWorker(ElectrumWorkerCheckTweaksRequest())) as String;
346+
final tweaksResponse = ElectrumWorkerCheckTweaksResponse.fromJson(
347+
json.decode(workerResponse) as Map<String, dynamic>,
348+
);
349+
final supportsScanning = tweaksResponse.result == true;
283350

284-
// try {
285-
// final tweaksResponse = await electrumClient.getTweaks(height: 0);
286-
287-
// if (tweaksResponse != null) {
288-
// node!.supportsSilentPayments = true;
289-
// node!.save();
290-
// return node!.supportsSilentPayments!;
291-
// }
292-
// } on RequestFailedTimeoutException catch (_) {
293-
// node!.supportsSilentPayments = false;
294-
// node!.save();
295-
// return node!.supportsSilentPayments!;
296-
// } catch (_) {}
297-
298-
// node!.supportsSilentPayments = false;
299-
// node!.save();
300-
// return node!.supportsSilentPayments!;
351+
if (supportsScanning) {
352+
node!.supportsSilentPayments = true;
353+
node!.save();
354+
return node!.supportsSilentPayments!;
355+
}
356+
} catch (_) {}
357+
358+
node!.supportsSilentPayments = false;
359+
node!.save();
360+
return node!.supportsSilentPayments!;
301361
}
302362

303363
LedgerConnection? _ledgerConnection;
@@ -383,16 +443,9 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
383443
if (tip > walletInfo.restoreHeight) {
384444
_setListeners(walletInfo.restoreHeight);
385445
}
386-
} else {
387-
alwaysScan = false;
388-
389-
// _isolate?.then((value) => value.kill(priority: Isolate.immediate));
390-
391-
// if (rpc!.isConnected) {
392-
// syncStatus = SyncedSyncStatus();
393-
// } else {
394-
// syncStatus = NotConnectedSyncStatus();
395-
// }
446+
} else if (syncStatus is! SyncedSyncStatus) {
447+
await sendWorker(ElectrumWorkerStopScanningRequest());
448+
await startSync();
396449
}
397450
}
398451

@@ -565,9 +618,16 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
565618
messageJson = message as Map<String, dynamic>;
566619
}
567620
final workerMethod = messageJson['method'] as String;
621+
final workerError = messageJson['error'] as String?;
568622

569623
switch (workerMethod) {
570624
case ElectrumRequestMethods.tweaksSubscribeMethod:
625+
if (workerError != null) {
626+
print(messageJson);
627+
// _onConnectionStatusChange(ConnectionStatus.failed);
628+
break;
629+
}
630+
571631
final response = ElectrumWorkerTweaksSubscribeResponse.fromJson(messageJson);
572632
onTweaksSyncResponse(response.result);
573633
break;
@@ -651,9 +711,16 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
651711
syncStatus = SyncingSyncStatus(newSyncStatus.blocksLeft, newSyncStatus.ptc);
652712
} else {
653713
syncStatus = newSyncStatus;
714+
715+
if (newSyncStatus is SyncedSyncStatus) {
716+
silentPaymentsScanningActive = false;
717+
}
654718
}
655719

656-
await walletInfo.updateRestoreHeight(result.height!);
720+
final height = result.height;
721+
if (height != null) {
722+
await walletInfo.updateRestoreHeight(height);
723+
}
657724
}
658725

659726
await save();
@@ -801,6 +868,8 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
801868
case SyncingSyncStatus:
802869
return;
803870
case SyncedTipSyncStatus:
871+
silentPaymentsScanningActive = false;
872+
804873
// Message is shown on the UI for 3 seconds, then reverted to synced
805874
Timer(Duration(seconds: 3), () {
806875
if (this.syncStatus is SyncedTipSyncStatus) this.syncStatus = SyncedSyncStatus();

cw_bitcoin/lib/bitcoin_wallet_addresses.dart

+9
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,15 @@ abstract class BitcoinWalletAddressesBase extends ElectrumWalletAddresses with S
361361
return labels;
362362
}
363363

364+
@override
365+
@action
366+
void updateHiddenAddresses() {
367+
super.updateHiddenAddresses();
368+
this.hiddenAddresses.addAll(silentPaymentAddresses
369+
.where((addressRecord) => addressRecord.isHidden)
370+
.map((addressRecord) => addressRecord.address));
371+
}
372+
364373
Map<String, dynamic> toJson() {
365374
final json = super.toJson();
366375
json['silentPaymentAddresses'] =

0 commit comments

Comments
 (0)