BitcoinWalletAggregate class

Bitcoin wallet aggregate root implementing event sourcing

This aggregate manages all wallet state changes through events, ensuring consistency and providing full audit trail for all operations. Follows the Eventador AggregateRoot pattern with functional state management.

One aggregate (persistence id BitcoinWallet_<walletId>) holds the whole wallet, so a command's checks (a spend checks the UTXO, its reservation and deferred holds) see one consistent state. The aggregate itself is the actor plumbing: command and event dispatch, replies, persistence callbacks and queries. The wallet's rules live in collaborators under wallet/ (bead libspiffy-dp4), which work on the state they are given and know nothing of actors or the journal:

  • WalletLifecycle: creation, configuration, deletion.
  • AddressBook: addresses, derivation records, watch addresses.
  • WalletKeys: key material, root and address derivation, private keys.
  • UtxoLedger: receiving, confirming and spending UTXOs, availability, selection, the Benford split initiation.
  • UtxoReservations: reserve, release, renew, expire.
  • DeferredPayments: deferred payments and the holds on their inputs.
  • OutgoingTransactions: imported and outgoing transaction records, the wallet outputs they create, confirmations.
  • WalletTransactionSigner: signing P2PKH, P2PK and multisig inputs.
  • ChannelFunding: payment channel funding transactions.
  • WalletBalances (models): the balance rule.

Constructors

BitcoinWalletAggregate({required String aggregateId, required String aggregateType, required EventStore eventStore, required CryptoService cryptoService, required SecureStorage secureStorage})

Properties

aggregateId → String
The aggregate ID for this aggregate root
no setterinherited
aggregateType → String
The aggregate type for this aggregate root
no setterinherited
commandHandlers → CommandHandlerRegistry<WalletState>
Command handler registry for this aggregate
no setterinherited
cryptoService → CryptoService
final
currentState → WalletState
Current state of the aggregate (non-nullable) Throws if the aggregate hasn't been initialized
no setterinherited
eventHandlers → EventHandlerRegistry<WalletState>
Event handler registry for this aggregate
no setterinherited
eventStore → EventStore
Current event store instance
no setterinherited
hashCode → int
The hash code for this object.
no setterinherited
isInitialized → bool
Whether the aggregate has been initialized with state
no setterinherited
isOutOfService → bool
True once an infrastructure failure has taken this incarnation out of service.
no setterinherited
isRecovered → bool
Whether this actor has completed recovery
no setterinherited
isRecovering → bool
Whether this actor is currently recovering from events
no setterinherited
persistenceId → String
Unique identifier for this persistent actor Used to store and retrieve events from the event store
no setterinherited
recoveryComplete → Future<void>
Future that completes when recovery finishes.
no setterinherited
runtimeType → Type
A representation of the runtime type of the object.
no setterinherited
secureStorage → SecureStorage
final
sequenceNumber → int
Current sequence number for this actor Incremented with each persisted event
no setterinherited
state → WalletState?
Current state of the aggregate Returns null if the aggregate hasn't been initialized yet
no setterinherited

Methods

applyEvent(WalletState current, Event event) → WalletState
Applies event to current and returns the next state (Eventador pattern; bead libspiffy-mmb).
canApplyEvent(Event event) → bool
Check if the aggregate can apply a specific event Override in subclasses for custom event routing
inherited
canHandleCommand(Command command) → bool
Check if the aggregate can handle a specific command Override in subclasses for custom command routing
inherited
canReserveUTXO(WalletState state, String utxoKey) → bool
Check if UTXO can be reserved (business rules)
canSpendUTXO(WalletState state, String utxoKey) → bool
Check if UTXO can be spent (business rules)
checkConcurrency(int expectedVersion) → Future<void>
Check optimistic concurrency control with expected version Public method for explicit concurrency checking
inherited
commandHandler(Command command) → Future<void>
Process a command through the full pipeline This is the main entry point for command processing.
inherited
createInitialState() → WalletState
Create initial empty wallet state
createSnapshot() → Future<void>
Create a snapshot of current state Override to provide custom snapshot logic
inherited
ensureStateInitialized() → void
Initialize the aggregate state This is a protected method that subclasses can use when overriding eventHandler to ensure state is initialized before processing events (replicating base class behavior)
inherited
eventHandler(Event event) → void
Apply an event to update the aggregate state This is called during both command processing and recovery
inherited
getAggregateInfo() → AggregateInfo
Get aggregate information for debugging and monitoring
inherited
getAvailableUTXOs(WalletState state) → List<BitcoinUtxo>
Get available UTXOs for spending (excludes plugin-managed UTXOs like tokens, and watch-only UTXOs at watch addresses, bead libspiffy-87a2)
getBusinessRuleViolations(WalletState state) → List<String>
Get business rule violations for the current state Override in subclasses to provide specific violation messages
inherited
getReservedUTXOs(WalletState state, String reservationId) → List<BitcoinUtxo>
Get UTXOs with specific reservation
getSnapshotState() → Future
Get the current state for snapshot creation
inherited
handleCommand(WalletState currentState, Command command) → Future<List<Event>>
Handle commands asynchronously and return events
hasSufficientBalance(WalletState state, BigInt requiredAmount) → bool
Whether selectUTXOsForAmount can cover requiredAmount: WalletState.availableBalance, the total of the UTXOs it may select, is at least requiredAmount. Fees are the caller's to add.
isInfrastructureFailure(Object? error) → bool
Whether error, raised while processing the current command, is an infrastructure failure (see the mixin documentation) rather than a rejection of the command.
inherited
noSuchMethod(Invocation invocation) → dynamic
Invoked when a nonexistent method or property is accessed.
inherited
onCommandFailure(Command command, dynamic error) → Future<void>
Send error responses when command processing fails Only active when aggregate is used as an actor in the actor system
onCommandProcessed(Command command, List<Event> events) → Future<void>
Send response messages after successful command processing Only active when aggregate is used as an actor in the actor system
onError(Object error, StackTrace stackTrace) → void
Called when an error occurs.
inherited
onEventApplicationFailure(Event event, dynamic error) → void
Logged instead of eventador's print; the error is rethrown.
onEventApplied(Event event, WalletState newState) → void
Called after an event has been applied to the state Override to perform post-event application actions
inherited
onMessage(dynamic message) → Future<void>
Handle incoming messages with command/event routing
onMessageDropped(dynamic message) → Future<void>
Called when a message is dropped because recovery timed out or failed. Override to send error responses, log, or enqueue for retry.
inherited
onPersist(Event event) → Future<void>
Called after successful event persistence Override to perform post-persistence actions
inherited
onPersistBatch(List<Event> events) → Future<void>
Called after successful batch event persistence Override to perform post-persistence actions for batches
inherited
onPersistBatchFailure(List<Event> events, dynamic error) → Future<void>
Called when batch event persistence fails Override to handle batch persistence failures
inherited
onPersistFailure(Event event, dynamic error) → Future<void>
Called when event persistence fails Override to handle persistence failures
inherited
onRecover() → Future<void>
Called at the start of recovery process Override to perform custom recovery initialization
inherited
onRecoveryComplete() → Future<void>
Called when recovery is complete Override to perform post-recovery initialization
onRecoveryFailure(dynamic error) → Future<void>
Called when recovery fails Override to handle recovery failures
inherited
onReplay(Event event) → Future<void>
Called for each event during replay Override to perform custom replay logic
inherited
onSnapshot(dynamic snapshotState, int sequenceNumber) → Future<void>
Restore state from snapshot during recovery
inherited
onSnapshotCreated(dynamic state, int sequenceNumber) → Future<void>
Called when a snapshot is created Override to perform post-snapshot actions
inherited
onSnapshotRestorationFailure(dynamic snapshotData, int sequenceNumber, dynamic error) → Future<void>
A snapshot that cannot be restored must fail recovery. Eventador's default falls back to the empty state and then replays only the events after the snapshot, silently dropping the wallet's history.
onSnapshotRestored(WalletState state, int sequenceNumber) → Future<void>
Called after state has been restored from a snapshot Override to perform post-snapshot restoration actions
inherited
persistEvent(Event event) → Future<void>
Persist an event to the event store Events are immutable and stored permanently
inherited
persistEvents(List<Event> events) → Future<void>
Persist multiple events atomically All events succeed or all fail together
inherited
postStop() → void
Called when the actor is stopped.
inherited
preStart() → Future<void>
Registers with the snapshot manager and recovers state.
queryHandler(dynamic message) → Future<void>
Non-command messages. WalletOwnershipQuery is answered from this aggregate's state (bead libspiffy-29t): the mailbox is FIFO, so the answer reflects every command handled before it, including an address generation already acknowledged to its caller.
registerHandlers() → void
Register command and event handlers
replay(List<Event> events) → void
Replay events to rebuild aggregate state Used during recovery and testing
inherited
restoreFromSnapshot(dynamic snapshotData, int sequenceNumber) → Future<WalletState>
Restore state from snapshot data Override in subclasses to provide custom restoration logic
inherited
restoreStateFromMap(Map<String, dynamic> map, int sequenceNumber) → Future<WalletState>
Rebuilds the wallet state from a snapshot written by getSnapshotState (after the event store's CBOR round trip).
selectUTXOsForAmount(WalletState state, BigInt amount) → List<BitcoinUtxo>
Select UTXOs for a specific amount (simple first-fit algorithm)
toString() → String
A string representation of this object.
inherited
validateBusinessRules(WalletState state) → bool
Validate business rules for the current state Override in subclasses to implement domain-specific validation
inherited

Operators

operator ==(Object other) → bool
The equality operator.
inherited

Constants

changePurpose → const String
Chain discriminator on AddressGeneratedEvent.purpose / GenerateAddressCommand.purpose.
deferredHoldPriority → const int
reservationPriority of a held input. Informational: a hold is refused to every reservation by rule, not by priority.
deferredHoldReason → const String
reservationReason of a held input.