handleCommand method
Handle commands asynchronously and return events
This method supports async cryptographic operations and secure storage access required for wallet operations. All calling code must await this method.
Implementation
@override
Future<List<Event>> handleCommand(WalletState currentState, Command command) async {
switch (command) {
case final CreateWalletCommand cmd:
return await _handleCreateWallet(currentState, cmd);
case final DeleteWalletCommand cmd:
return WalletLifecycle.delete(currentState, cmd);
case final UpdateWalletConfigurationCommand cmd:
return WalletLifecycle.updateConfiguration(currentState, cmd);
case final GenerateAddressCommand cmd:
return await _keys.generateAddress(currentState, cmd);
case final UpdateAddressLabelCommand cmd:
return AddressBook.updateAddressLabel(currentState, cmd);
case final RegisterDiscoveredAddressCommand cmd:
return AddressBook.registerDiscoveredAddress(currentState, cmd);
case final AddWatchAddressCommand cmd:
return AddressBook.addWatchAddress(currentState, cmd);
case final RecordDelegatedAddressesCommand cmd:
final recorded = await _keys.recordDelegatedAddresses(currentState, cmd);
// Sent once the addresses are journaled, and also when every one
// was recorded already (nothing to journal).
if (_replyTo(cmd) != null) {
_repliesAwaitingPersist[cmd.commandId] = DelegatedAddressesRecordedResponse(
walletId: cmd.walletId,
addresses: recorded.addresses,
journaled: [for (final e in recorded.events.whereType<AddressDiscoveredEvent>()) e.address],
success: true,
);
}
return recorded.events;
case final RecordType42AddressesCommand cmd:
final recorded = await _keys.recordType42Addresses(currentState, cmd);
// Sent once the addresses are journaled, and also when every one
// was recorded already (nothing to journal).
if (_replyTo(cmd) != null) {
_repliesAwaitingPersist[cmd.commandId] = Type42AddressesRecordedResponse(
walletId: cmd.walletId,
addresses: recorded.addresses,
journaled: [for (final e in recorded.events.whereType<Type42AddressRecordedEvent>()) e.address],
success: true,
);
}
return recorded.events;
case final DeriveType42DestinationCommand cmd:
final derived = await _keys.deriveType42Destination(currentState, cmd);
if (_replyTo(cmd) != null) {
_repliesAwaitingPersist[cmd.commandId] = Type42DestinationDerivedResponse(
walletId: cmd.walletId,
destination: derived.destination,
success: true,
);
}
return [derived];
case final IssueAnchorKeyCommand cmd:
final issued = await _keys.issueAnchorKey(currentState, cmd);
// Sent once the anchor is journaled, and also when it was issued
// already (nothing to journal).
if (_replyTo(cmd) != null) {
_repliesAwaitingPersist[cmd.commandId] =
AnchorKeyResponse(walletId: cmd.walletId, publicKeyHex: issued.anchorPublicKey, success: true);
}
return issued.events;
case final SignWithAnchorKeyCommand cmd:
final anchor = await _keys.anchorKey(
cmd.walletId, currentState, Type42Derivation.anchorContextHex(cmd.anchorContext));
final digest = dartsv.sha256(cmd.message);
final signature = await _keys.cryptoService.signData(anchor, Uint8List.fromList(digest));
_replyTo(cmd)?.tell(AnchorKeyResponse(
walletId: cmd.walletId,
publicKeyHex: anchor.publicKey.toHex(),
signatureDerHex: hex.encode(signature.toDER()),
success: true,
));
return const [];
case final LookupType42AddressesCommand cmd:
_replyTo(cmd)?.tell(Type42AddressesResponse(
walletId: cmd.walletId,
derivations: Type42Book.paidBy(currentState, cmd.rawTransaction),
success: true,
));
return const [];
case final ReconcileWatchAddressesCommand cmd:
return AddressBook.reconcileWatchAddresses(currentState, cmd);
case final ReceiveUTXOCommand cmd:
return UtxoLedger.receive(currentState, cmd);
case final MarkUTXOAvailableCommand cmd:
return UtxoLedger.markAvailable(currentState, cmd);
case final RecordImportedTransactionCommand cmd:
return OutgoingTransactions.recordImported(currentState, cmd);
case final RecordOutgoingTransactionCommand cmd:
return _transactions.recordOutgoing(currentState, cmd);
case final ConfirmTransactionCommand cmd:
return OutgoingTransactions.confirm(currentState, cmd);
case final UpdateTransactionStatusCommand cmd:
return OutgoingTransactions.updateStatus(currentState, cmd);
case final RevertTransactionConfirmationCommand cmd:
return OutgoingTransactions.revertConfirmation(currentState, cmd);
case final SpendUTXOCommand cmd:
return UtxoLedger.spend(currentState, cmd);
case final UpdateUTXOConfirmationsCommand cmd:
return UtxoLedger.updateConfirmations(currentState, cmd);
case final SignTransactionCommand cmd:
return await _handleSignTransaction(currentState, cmd);
case final SignMultisigTransactionCommand cmd:
return await _handleSignMultisigTransaction(currentState, cmd);
case final SignInputCommand cmd:
return await _handleSignInput(currentState, cmd);
case final BuildFundingTransactionCommand cmd:
return await _handleBuildFundingTransaction(currentState, cmd);
case final BroadcastTransactionCommand cmd:
return OutgoingTransactions.broadcast(currentState, cmd);
case final ReserveUTXOsCommand cmd:
return _reservations.reserveMany(currentState, cmd);
case final ReleaseUTXOsCommand cmd:
return _reservations.releaseMany(currentState, cmd);
case final ReserveUTXOCommand cmd:
return _reservations.reserve(currentState, cmd);
case final ReleaseUTXOCommand cmd:
return _reservations.release(currentState, cmd);
case final RenewUTXOReservationCommand cmd:
return _reservations.renew(currentState, cmd);
case final CleanupExpiredReservationsCommand cmd:
return _reservations.cleanupExpired(currentState, cmd);
case final ReconcileDeferredSpendsCommand cmd:
return _deferred.reconcile(currentState, cmd);
case final RecordTransactionNetworkStatusCommand cmd:
return _deferred.recordNetworkStatus(currentState, cmd);
case final CancelDeferredSpendCommand cmd:
return _deferred.cancel(currentState, cmd);
case final ReclaimDeferredSpendCommand cmd:
return _deferred.reclaim(currentState, cmd, _transactions);
default:
throw ArgumentError('Unknown command type: ${command.runtimeType}');
}
}