Skip to content

Events

This page lists every event the wallet coordinator emits in libspiffy 5.0.0: its fields, when it is emitted, and whether it is a reply to a request. Events are defined in lib/src/actors/coordinator_messages.dart and exported by package:libspiffy/coordinator.dart. The requests that cause them are on Commands and Queries.

All events extend CoordinatorEvent, which has two members:

  • walletId (String?): the wallet the event is about, or null when it is not about one wallet.
  • eventTimestamp (DateTime): when the event was made. Since 5.0.0 it is taken when the event is constructed.

You can read events three ways:

  • libspiffy.coordinator.ask(request) completes with one request’s reply. See Commands.
  • libspiffy.coordinator.on<E>({walletId}) is a Stream<E> of the events of one type, of one wallet when you give walletId. Use it for what happens without a request: a balance change, a confirmation, an incoming channel request.
  • libspiffy.coordinatorEvents is the whole stream (a broadcast Stream<CoordinatorEvent>?, null before the system is initialized). Replies are published on it too.
// Sketch: assumes an initialized LibSpiffyActorSystem named `libspiffy`.
import 'package:libspiffy/coordinator.dart';
void follow() {
libspiffy.coordinator
.on<BalanceUpdatedEvent>(walletId: 'alice')
.listen((e) => print('alice: ${e.totalBalance} sats spendable'));
libspiffy.coordinatorEvents?.listen((event) {
switch (event) {
case TransactionConfirmedEvent e:
print('${e.txid} mined at ${e.blockHeight}');
case ErrorEvent e:
print('${e.source} (${e.walletId}): ${e.message}');
default:
break;
}
});
}

Events emitted before anything listens (for example UnfinishedChannelsFoundEvent at startup) are held and delivered to the first listener, up to 256 of them; beyond that the oldest are dropped with a warning. After the first listener, a broadcast stream delivers only what happens while you listen, so subscribe as soon as the system is initialized.

A reply is an event that extends CoordinatorReply, a subclass of CoordinatorEvent. Each request names its reply type, and the coordinator answers each request with exactly one reply, on success and on failure. A reply adds two members:

  • requestId (String?): the requestId of the request it answers. It is null when no request caused the event: the same types are also emitted for what nobody asked, such as a payment that waited for its block header, a peer’s batch of headers, or a channel the counterparty opened.
  • failure (String?): why the request failed, or null when it succeeded. ask() throws CoordinatorFailure carrying the reply when failure is not null.

For most replies failure is error (or a fixed message) when success is false. Some replies never report a failure themselves, and a failure to answer them arrives as an ErrorEvent naming the request: BalanceResponse, TransactionsResponse, DeferredPaymentsResponse, HeaderSyncStatusResponse, ChannelOpenedEvent, ChannelPaymentEvent, ChannelClosedEvent and ChannelRejectedEvent.

A reclaim the wallet starts itself when a payment’s deadline passes is reported with a DeferredPaymentReclaimedEvent whose requestId is deadline-<txid>.

Event Reply to Also emitted without a request
WalletCreatedEvent CreateWalletCommand
WalletDeletedEvent DeleteWalletCommand
ImportCompleteEvent ImportWalletCommand
ImportProgressEvent not a reply while an import runs
ImportUTXOConfirmedEvent not a reply while an import runs
ImportTransactionConfirmedEvent not a reply while an import runs
WalletStatusEvent not a reply when the coordinator shuts down
BalanceUpdatedEvent not a reply when a wallet’s balance changes
TransactionRecordedEvent RecordOutgoingCommand
TransactionConfirmedEvent not a reply when a proof confirms a transaction
TransactionConfirmationRevertedEvent not a reply when a confirmation is taken back
TransactionImportedEvent ImportTransactionCommand yes
SPVValidationResultEvent not a reply when SPV validation of an import has a verdict
AddressGeneratedEvent GenerateAddressCommand
WatchAddressRegisteredEvent RegisterWatchAddressCommand
UTXOsReleasedEvent ReleaseUTXOsCommand
InvoiceCreatedEvent CreateInvoiceCommand
InvoicePaidEvent not a reply when an invoice is paid
PaymentReadyEvent PayInvoiceCommand
BEEFValidationResultEvent ValidateBEEFCommand yes
BEEFSettledEvent SettleBEEFCommand
BroadcastFailureEvent not a reply when an ARC broadcast fails
ProvisioningCompleteEvent ProvisionFundingCommand
TimestampCompleteEvent TimestampCommand
UTXOSplitStartedEvent not a reply when a split starts
UTXOSplitCompleteEvent SplitUTXOsCommand
ForeignSpendsCheckedEvent CheckForeignSpendsCommand
DeferredPaymentBroadcastEvent BroadcastDeferredPaymentCommand
DeferredPaymentStatusEvent CheckDeferredPaymentStatusCommand
DeferredPaymentCancelledEvent CancelDeferredPaymentCommand
DeferredPaymentReclaimedEvent ReclaimDeferredPaymentCommand at a payment’s deadline
DeferredPaymentCompletedEvent CompleteDeferredPaymentCommand
ChannelRequestReceivedEvent not a reply when a peer asks to open a channel
ChannelOpenedEvent OpenChannelCommand yes
ChannelAcceptedEvent AcceptChannelCommand
ChannelRejectedEvent RejectChannelCommand
ChannelPaymentEvent ChannelPayCommand yes
ChannelClosedEvent CloseChannelCommand yes
ChannelExpiredEvent ExpireChannelCommand
ChannelRefundClaimedEvent ClaimChannelRefundCommand
ChannelFundingRetriedEvent RetryChannelFundingCommand
ChannelOpenResentEvent ResendChannelOpenCommand
UnfinishedChannelsFoundEvent not a reply once at startup
P2PMessageToSendEvent not a reply when a peer must be sent a message
ChannelP2PMessageToSendEvent not a reply when a channel peer must be sent a message
AncestorProofRequestedEvent RequestAncestorProofCommand
AncestorProofResponseEvent not a reply when a peer’s proof response is processed
AncestorProofRequestReceivedEvent not a reply when a peer asks for a proof
AnchorPublicKeyEvent IssueAnchorKeyCommand
AnchorSignedEvent SignWithAnchorKeyCommand
Brc100KeyOperationEvent Brc100KeyOperationCommand
Type42DestinationEvent DeriveType42DestinationCommand
BlockHeadersStoredEvent StoreHeadersCommand for peers’ batches
HeaderSyncStatusEvent not a reply when header sync catches up or falls behind
BalanceResponse GetBalanceQuery
TransactionsResponse GetTransactionsQuery
TransactionDetailResponse GetTransactionDetailQuery
TransactionExportedEvent ExportTransactionQuery
DeferredPaymentsResponse GetDeferredPaymentsQuery
HeaderSyncStatusResponse GetHeaderSyncStatusQuery
ErrorEvent not a reply; names the request that caused it yes

Reply to CreateWalletCommand. On success it is emitted once the read model holds the wallet. failure: error when success is false.

Field Type
walletId String
requestId String?
rootAddress String?
success bool
error String?

Reply to DeleteWalletCommand, once the deletion is journaled and the read model no longer holds the wallet. failure: error when success is false, including a refusal by the wallet.

Field Type
walletId String
requestId String?
success bool
error String?

Reply to ImportWalletCommand, when the import ends. transactionCount is what this run recorded, transactionsSkipped what the wallet already held, and transactionsFailed what could not be fetched or proven. A successful import with transactionsFailed above zero is incomplete: send ImportWalletCommand again with resume: true. failure: error when success is false, for example an import with no key or no blockchain data source.

Field Type
walletId String
requestId String?
success bool
error String?
addressCount int
transactionCount int
transactionsSkipped int
transactionsFailed int

Emitted repeatedly while ImportWalletCommand runs. phase names the step and progress is the fraction done, from 0.0 to 1.0.

Field Type
walletId String
phase String
progress double
message String
addressesFound int
totalAddresses int
transactionsProcessed int
totalTransactions int

Emitted during an import when the wallet aggregate records an imported UTXO.

Field Type
walletId String
txid String
vout int
success bool
error String?

Emitted during an import when the wallet aggregate records an imported transaction.

Field Type
walletId String
txid String
success bool
error String?

Emitted when the coordinator shuts down (status shutdown).

Field Type
walletId String?
status String
message String

Emitted when the read model applies an event that changes a wallet’s balance, and only when a number differs from the last one announced for that wallet. The numbers are computed by the same code as BalanceResponse. totalBalance is confirmedBalance + unconfirmedBalance; pendingBalance, watchOnlyBalance and reservedBalance are not part of it.

Field Type
walletId String
confirmedBalance BigInt
unconfirmedBalance BigInt
totalBalance BigInt
pendingBalance BigInt
watchOnlyBalance BigInt
reservedBalance BigInt

Reply to RecordOutgoingCommand, once the transaction is journaled and the read model holds it. amountSatoshis is null when the wallet had recorded the transaction already. failure: error when success is false.

Field Type
walletId String
requestId String?
txid String
amountSatoshis BigInt?
success bool
error String?

Emitted when a merkle proof places the transaction in a block whose header is on the local active chain. It carries no confirmation count: compute tip height - blockHeight + 1 if you need a depth.

Field Type
walletId String
txid String
blockHeight int

Emitted when a confirmation is taken back: the block left the active chain in a reorg, or the header at the proof’s height contradicts the proof. The transaction is unconfirmed again until a fresh proof arrives, and TransactionConfirmedEvent is then emitted again.

Field Type
walletId String
txid String
blockHeight int?
blockHash String?
reason String

Reply to ImportTransactionCommand, once the read model holds the transaction. Also emitted, with a null requestId, for transactions received that nobody requested, such as a proven foreign spender or a peer’s proof response. totalValueReceived is a decimal string of satoshis. failure: error when success is false, for example a BEEF without the proof of its last transaction.

Field Type
walletId String
requestId String?
transactionId String
success bool
utxosCreated int?
totalValueReceived String?
error String?

Emitted for an imported transaction once SPV validation has a verdict (not for a payment received with ValidateBEEFCommand, which gets BEEFValidationResultEvent).

Field Type
walletId String?
txid String
isValid bool
validationError String?
spendableUTXOs List<Map<String, dynamic>>
spentUTXOs List<Map<String, dynamic>>
unreadableOutputs List<Map<String, dynamic>>

Reply to GenerateAddressCommand, once the read model holds the address. chain is AddressChain.receive, .change or .delegated. publicKeyHex is set only when the command asked for it. failure: error when success is false.

Field Type
walletId String
requestId String?
success bool
address String?
derivationIndex int?
chain AddressChain?
publicKeyHex String?
error String?

Reply to RegisterWatchAddressCommand. failure: error when success is false.

Field Type
walletId String
requestId String?
address String
success bool
error String?

Reply to ReleaseUTXOsCommand, once the read model shows the release. releasedUtxoKeys is empty when the reservation held none (already released, or expired). failure: error when success is false.

Field Type
walletId String
requestId String?
reservationId String
releasedUtxoKeys List<String>
success bool
error String?

Reply to CreateInvoiceCommand. issuedAddresses lists the addresses the wallet issued, each with its address, chain and derivationIndex; an address you supplied in an output is not among them. failure: error when success is false.

Field Type
walletId String
requestId String?
invoiceId String
addresses List<String>
amount BigInt
outputs List<InvoiceOutputSpec>?
issuedAddresses List<IssuedAddress>
description String?
expiresAt DateTime?
success bool
error String?

Emitted when the invoice read model records a payment of the invoice.

Field Type
walletId String
invoiceId String
txid String
amountReceived BigInt

Reply to PayInvoiceCommand. beefBytes is the payment to hand to the recipient; it has not been broadcast. witnessTxid and witnessBeefBytes are set only for a payment with a paired witness transaction. failure: error when success is false.

Field Type
walletId String?
requestId String?
invoiceId String
beefBytes Uint8List
txid String
amountPaid BigInt
changeAmount BigInt
ancestorCount int
success bool
error String?
witnessTxid String?
witnessBeefBytes Uint8List?

Reply to ValidateBEEFCommand, after the payment is validated, recorded and, if it carries no proof of its own, submitted to ARC. valid means it is recorded and queryable; broadcasted means ARC accepted it, with ARC’s status in networkStatus. With awaitingHeader: true the reply is not a verdict: a second event follows when the block header arrives, also after a restart. failure: error when valid is false.

Field Type
walletId String?
requestId String?
invoiceId String?
txid String?
valid bool
error String?
broadcasted bool
networkStatus String?
broadcastError String?
awaitingHeader bool
spendableUTXOs List<Map<String, dynamic>>?
unreadableOutputs List<Map<String, dynamic>>

Reply to SettleBEEFCommand. failedTxids and failureErrors have the same length and order. failure: error when success is false.

Field Type
walletId String?
requestId String?
txid String
success bool
error String?
submittedCount int
skippedCount int
failedCount int
failedTxids List<String>
failureErrors List<String>

Emitted when an ARC broadcast fails outside a SettleBEEFCommand. The coordinator sets willRetry to true: the broadcast is handed to the durable retry queue.

Field Type
walletId String?
txid String
error String
willRetry bool

Reply to ProvisionFundingCommand. failure: error when success is false.

Field Type
walletId String?
requestId String?
transactionCount int
earmarkCount int
success bool
error String?

Reply to TimestampCommand, after ARC answers the broadcast. transactionId is the transaction carrying the hashes. failure: error when success is false.

Field Type
walletId String?
requestId String?
archiveId String
transactionId String?
success bool
error String?

Emitted when a SplitUTXOsCommand can start: the UTXOs are chosen and the first split transaction is about to be built. Not emitted when the split cannot start; the reply then reports the error.

Field Type
walletId String
utxoCount int
targetOutputsPerUtxo int

Reply to SplitUTXOsCommand. transactionCount is the number of split transactions ARC accepted or queued (the length of txids); newUtxoCount is the outputs they create. splits has one SplitTransactionOutcome per source UTXO, in order. failure: error when success is false.

Field Type
walletId String
requestId String?
transactionCount int
newUtxoCount int
totalFeePaid BigInt
success bool
error String?
txids List<String>
splits List<SplitTransactionOutcome>

SplitTransactionOutcome has txid (String?, null when no transaction was built), sourceUtxoKey (String), status (SplitTransactionStatus), networkStatus (String?), error (String?), feePaid (BigInt?) and isSuccess (true for accepted and queued). SplitTransactionStatus is one of accepted, queued, contested, rejected, notBroadcast, unanswered, notRecorded and notBuilt.

Reply to CheckForeignSpendsCommand, once the read model shows what was recorded. spends lists the outputs another transaction spent; unchecked maps each output whose check failed to the reason. failure: error when success is false.

Field Type
walletId String
requestId String?
success bool
checked List<String>
spends List<ForeignSpend>
unchecked Map<String, String>
error String?

Reply to BroadcastDeferredPaymentCommand. success means the network holds the transaction (SEEN_ON_NETWORK or MINED). source is arc or dataSource. confirmed means a MINED answer’s proof matched the local headers. competingTxids is set for a DOUBLE_SPEND_ATTEMPTED answer. failure: error when success is false.

Field Type
walletId String
txid String
requestId String?
success bool
networkStatus String?
source String?
confirmed bool
willRetry bool
error String?
competingTxids List<String>

Reply to CheckDeferredPaymentStatusCommand. success means a source answered. proofStatus is verified, headerUnknown, rootMismatch, malformed, or null without a proof. failure: error when success is false.

Field Type
walletId String
txid String
requestId String?
success bool
networkStatus String?
source String?
blockHeight int?
proofStatus String?
confirmed bool
error String?
competingTxids List<String>

Reply to CancelDeferredPaymentCommand. networkStatus is what the network check before the cancellation answered; releasedUtxoKeys are the inputs released. failure: error when success is false.

Field Type
walletId String
txid String
requestId String?
success bool
networkStatus String?
releasedUtxoKeys List<String>
error String?

Reply to ReclaimDeferredPaymentCommand. Also emitted, with requestId deadline-<txid>, for a reclaim the wallet starts itself when a payment’s deadline passes. success means the self-spend is journaled and the network holds it. Otherwise the payment stays outstanding and resolves as reclaimed if the network reports the self-spend later. failure: error when success is false.

Field Type
walletId String
txid String
reclaimTxid String?
requestId String?
success bool
reclaimedUtxoKeys List<String>
reclaimedSatoshis BigInt?
fee BigInt?
toAddress String?
networkStatus String?
source String?
competingTxids List<String>
error String?

Reply to CompleteDeferredPaymentCommand. On success the completed transaction completedTxid is recorded and holds the half-signed payment’s inputs. failure: error when success is false.

Field Type
walletId String
txid String
completedTxid String?
requestId String?
success bool
error String?

Emitted when a peer asks to open a channel with you. Answer with AcceptChannelCommand or RejectChannelCommand.

Field Type
channelId String
clientPeerId String
clientPubKey String
clientAddress String
fundingAmountSats int
lockTimeUnix int
context String?

walletId is always null.

Reply to OpenChannelCommand, once the server accepted the channel and its funding is on the network. Also emitted, with a null requestId, when a channel this node serves opens. failure is always null: a failed open is an ErrorEvent naming the request.

Field Type
walletId String
requestId String?
channelId String
fundingTxId String?
fundingAmountSats int

Reply to AcceptChannelCommand, once the acceptance is journaled and channel_accept is handed to your transport. The channel opens when the client funds it (ChannelOpenedEvent). failure: error when success is false.

Field Type
walletId String
requestId String?
channelId String
success bool
error String?

Reply to RejectChannelCommand. clientTold is true when a request from the client was held and channel_reject was handed to your transport. failure is always null.

Field Type
requestId String?
channelId String
clientTold bool

walletId is always null.

Reply to ChannelPayCommand, once the channel journals the payment and payment_update is handed to your transport. Also emitted, with a null requestId, for a payment received on a channel this node serves. failure is always null: a refused payment is an ErrorEvent naming the request.

Field Type
walletId String?
requestId String?
channelId String
amountSats int
sequence int
clientBalance int
serverBalance int

Reply to CloseChannelCommand. Also emitted, with a null requestId, for a channel closed by the counterparty or by a server’s settlement timer. failure is always null: a failed close is an ErrorEvent naming the request.

Field Type
walletId String?
requestId String?
channelId String
reason String?
settlementTxId String?

Reply to ExpireChannelCommand, once the expiry is journaled. failure: error when success is false.

Field Type
walletId String?
requestId String?
channelId String
success bool
error String?

Reply to ClaimChannelRefundCommand, on success and failure. refundTxId is null when the claim failed before a refund was read from the channel’s state. failure: error when success is false.

Field Type
walletId String?
requestId String?
channelId String
refundTxId String?
success bool
error String?

Reply to RetryChannelFundingCommand, on success and failure. On success ChannelOpenedEvent follows. failure: error when success is false.

Field Type
walletId String?
requestId String?
channelId String
fundingTxId String?
success bool
error String?

Reply to ResendChannelOpenCommand, on success and failure. toPeerId names the peer channel_open was re-sent to. failure: error when success is false.

Field Type
walletId String?
requestId String?
channelId String
toPeerId String?
fundingTxId String?
success bool
error String?

Emitted once at startup for each wallet with channels that started opening and never reached open. It only reports: nothing is retried. Not emitted when there is nothing to report.

Field Type
walletId String?
channels List<UnfinishedChannel>

UnfinishedChannel has channelId (String), state (String, opening or funding), counterpartyPeerId (String?), fundingAmountSats (BigInt) and lockTimeUnix (int). Carry on with RetryChannelFundingCommand or ResendChannelOpenCommand, or take the funding inputs back with CancelDeferredPaymentCommand.

Emitted when the library has a message for a peer. Your app sends payload to toPeerId on its own transport. The merkle-proof protocol emits this class with messageType proof_request or proof_response, so listen for this class, not only the channel subclass, if you want proof recovery.

Field Type
toPeerId String
messageType String
payload Map<String, dynamic>

walletId is always null.

A P2PMessageToSendEvent for the channel protocol (messageType channel_request, channel_accept, channel_reject, refund_sign_request, refund_signed, channel_open, payment_update, payment_ack, channel_close, channel_closed or channel_error). Same fields as P2PMessageToSendEvent.

Reply to RequestAncestorProofCommand. success only says the request went out to toPeerId; the answer arrives later as AncestorProofResponseEvent. success is false, with toPeerId null, when nobody can be asked: the transaction is not stored or has no counterparty marker. failure: error when success is false.

Field Type
walletId String
txid String
toPeerId String?
ancestorTxids List<String>
requestId String?
success bool
error String?

Emitted when a peer’s proof_response has been through the ordinary receive path. success is true only when the BEEF verified and the fresh proof was stored. requestId is the id the proof request named on the wire, when it named one. This is not a CoordinatorReply.

Field Type
walletId String?
txid String
fromPeerId String
requestId String?
success bool
error String?

Emitted on the responder when a peer sends a proof_request. answered is false when the request was refused; reason says why, for your logs only. requestId is the id the request named on the wire. This is not a CoordinatorReply.

Field Type
fromPeerId String
txid String
requestId String?
answered bool
reason String?

walletId is always null.

Reply to IssueAnchorKeyCommand. publicKey is compressed hex. failure: error when success is false, for example for an xpub or WIF wallet, which has no anchor key.

Field Type
walletId String
requestId String?
publicKey String?
success bool
error String?

Reply to SignWithAnchorKeyCommand. signatureDer is a hex DER signature of SHA-256 of the message (deterministic, RFC 6979, low S). failure: error when success is false.

Field Type
walletId String
requestId String?
publicKey String?
signatureDer String?
success bool
error String?

Reply to Brc100KeyOperationCommand. failure: error when success is false.

Field Type
walletId String
requestId String?
result Brc100KeyResult?
success bool
error String?

Reply to DeriveType42DestinationCommand. destination.address is what the payer pays; destination.derivation is the hand-off the payee imports the payment with. failure: error when success is false.

Field Type
walletId String
requestId String?
destination Type42Destination?
success bool
error String?

Reply to StoreHeadersCommand (source from the command); every StoreHeadersCommand is answered. Also emitted, with a null requestId and source p2p (the constant BlockHeadersStoredEvent.peerSource), for each batch a peer sent that stored or rejected a header. success is false when a header was rejected; error says why the first one was. The initial CDN download reports progress through LibSpiffyActorSystem.initialize(onHeaderSyncProgress:) instead. failure: error when success is false.

Field Type
requestId String?
headersStored int
startHeight int
endHeight int
success bool
error String?
source String

walletId is always null.

Emitted when header sync catches up with its peers or falls behind them (when HeaderSyncStatus.synced changes).

Field Type
status HeaderSyncStatus

HeaderSyncStatus has height (the active chain’s tip), networkHeight (the higher of height and the heights peers reported when they connected; 0 while none did), synced (the last peer answer held fewer than 2,000 headers) and peerCount.

These answer the queries on Queries. Each is a CoordinatorReply carrying the query’s requestId.

Reply to GetBalanceQuery. failure is always null: a failure to answer is an ErrorEvent with source getBalance.

Field Type
walletId String
requestId String?
confirmedBalance BigInt
unconfirmedBalance BigInt
totalBalance BigInt
pendingBalance BigInt
watchOnlyBalance BigInt
reservedBalance BigInt

Reply to GetTransactionsQuery. failure is always null: a failure to answer is an ErrorEvent with source getTransactions.

Field Type
walletId String
requestId String?
transactions List<BitcoinTransaction>

Reply to GetTransactionDetailQuery. found is false when the wallet has no such transaction. failure: error.

Field Type
walletId String
requestId String?
transaction BitcoinTransaction?
found bool
error String?

Reply to ExportTransactionQuery. failure: error when success is false.

Field Type
walletId String
txid String
requestId String?
success bool
beef List<int>?
delegatedIndices List<int>
type42Derivations List<Type42Derivation>
error String?

Reply to GetDeferredPaymentsQuery. failure is always null: a failure to answer is an ErrorEvent with source getDeferredPayments.

Field Type
walletId String
requestId String?
payments List<DeferredPaymentDetail>
nextCursor String?

Reply to GetHeaderSyncStatusQuery. failure is always null.

Field Type
requestId String?
status HeaderSyncStatus

walletId is always null.

Emitted for a failure that has no reply of its own to report it in. When a request caused it, requestId names that request and ask() throws CoordinatorFailure with this event; otherwise requestId is null. ErrorEvent is not a CoordinatorReply.

Field Type
walletId String?
source String
message String
stackTrace String?
requestId String?

source names what failed. The values in 5.0.0 are getBalance, getTransactions, getTransactionDetail and getDeferredPayments (a query that could not be answered), ChannelP2PAdapter (a channel request failed, or a peer rejected or errored a channel during an open), WalletCoordinatorActor (a channel command on a coordinator built without channel events, or an unexpected exception while handling a message), and WalletManagerActor and BitcoinWalletAggregate (the wallet gave up on a message that has no reply of its own).