-
Notifications
You must be signed in to change notification settings - Fork 15
Add receive address generation for bdk_demo #79
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
7018941
b8d875b
2c47504
62b8a59
960989e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,117 @@ | ||
| import 'package:bdk_demo/models/wallet_record.dart'; | ||
| import 'package:bdk_demo/providers/wallet_providers.dart'; | ||
| import 'package:flutter_riverpod/flutter_riverpod.dart'; | ||
|
|
||
| class ReceiveAddressState { | ||
| const ReceiveAddressState({ | ||
| this.walletId, | ||
| this.address, | ||
| this.index, | ||
| this.isGenerating = false, | ||
| this.errorMessage, | ||
| }); | ||
|
|
||
| static const empty = ReceiveAddressState(); | ||
|
|
||
| final String? walletId; | ||
| final String? address; | ||
| final int? index; | ||
| final bool isGenerating; | ||
| final String? errorMessage; | ||
|
|
||
| ReceiveAddressState copyWith({ | ||
| String? walletId, | ||
| String? address, | ||
| int? index, | ||
| bool? isGenerating, | ||
| String? errorMessage, | ||
| bool clearAddress = false, | ||
| bool clearIndex = false, | ||
| bool clearErrorMessage = false, | ||
| }) { | ||
| return ReceiveAddressState( | ||
| walletId: walletId ?? this.walletId, | ||
| address: clearAddress ? null : (address ?? this.address), | ||
| index: clearIndex ? null : (index ?? this.index), | ||
| isGenerating: isGenerating ?? this.isGenerating, | ||
| errorMessage: clearErrorMessage | ||
| ? null | ||
| : (errorMessage ?? this.errorMessage), | ||
| ); | ||
| } | ||
| } | ||
|
|
||
| final currentReceiveAddressProvider = | ||
| NotifierProvider<CurrentReceiveAddressNotifier, ReceiveAddressState>( | ||
| CurrentReceiveAddressNotifier.new, | ||
| ); | ||
|
|
||
| class CurrentReceiveAddressNotifier extends Notifier<ReceiveAddressState> { | ||
| bool _inFlight = false; | ||
|
|
||
| @override | ||
| ReceiveAddressState build() { | ||
| ref.listen<WalletRecord?>(activeWalletRecordProvider, (previous, next) { | ||
| final current = state; | ||
| if (current.walletId == null && !current.isGenerating) return; | ||
| if (next == null || current.walletId != next.id) { | ||
| state = ReceiveAddressState.empty; | ||
| } | ||
| }); | ||
| return ReceiveAddressState.empty; | ||
| } | ||
|
|
||
| Future<void> generateForActiveWallet() async { | ||
| if (_inFlight) return; | ||
|
|
||
| final record = ref.read(activeWalletRecordProvider); | ||
| if (record == null) { | ||
| state = const ReceiveAddressState(errorMessage: 'No active wallet.'); | ||
| return; | ||
| } | ||
|
|
||
| final walletId = record.id; | ||
| _inFlight = true; | ||
| state = ReceiveAddressState.empty.copyWith( | ||
| walletId: walletId, | ||
| isGenerating: true, | ||
| clearAddress: true, | ||
| clearIndex: true, | ||
| clearErrorMessage: true, | ||
| ); | ||
|
|
||
| try { | ||
| final walletService = ref.read(walletServiceProvider); | ||
| final (addressInfo, updatedWallet) = await walletService.generateAddress( | ||
| record, | ||
| ); | ||
|
|
||
| if (!_stillActive(walletId)) { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This stale branch runs after generateAddress() has already revealed and persisted the address for the old wallet. Could we either avoid committing when _stillActive(walletId) is false, or cache the generated address by wallet id so it is shown when that wallet becomes active again? Otherwise switching wallets during generation advances the old wallet’s receive index without ever surfacing the address.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree, what I want to do here is keep the generated receive address keyed by walletId instead of dropping it when the user switches wallets mid-generation... that way we still avoid showing stale state on the newly active wallet, but when the original wallet becomes active again we can show the address that was already revealed and persisted. I’ll also add a test for that path so the behavior is locked in.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yep, that behavior makes sense to me. Since the address has already been revealed and persisted by the time the stale completion returns, we shouldn’t drop it. Caching the result by walletId seems right. One thing to tighten before resolving: the cached wallet ownership path looks fragile, and CI is currently panicking in the reactivation test, so I’d either cache just the receive-address state and reload the wallet from SQLite, or make the cached-wallet handoff explicit and covered by the test.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yep, agreed. I’m going to cache only the receive address state by walletId, and dispose the stale returned wallet. |
||
| updatedWallet.dispose(); | ||
| state = ReceiveAddressState.empty; | ||
| return; | ||
| } | ||
|
|
||
| ref.read(activeWalletProvider.notifier).replaceWallet(updatedWallet); | ||
| state = ReceiveAddressState( | ||
| walletId: walletId, | ||
| address: addressInfo.address.toString(), | ||
| index: addressInfo.index, | ||
| ); | ||
| } catch (error) { | ||
| if (_stillActive(walletId)) { | ||
| state = ReceiveAddressState( | ||
| walletId: walletId, | ||
| errorMessage: error.toString(), | ||
| ); | ||
| } else { | ||
| state = ReceiveAddressState.empty; | ||
| } | ||
| } finally { | ||
| _inFlight = false; | ||
| } | ||
| } | ||
|
|
||
| bool _stillActive(String walletId) => | ||
| ref.read(activeWalletRecordProvider)?.id == walletId; | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.