Skip to content

Commands

This page lists every command you can send to the wallet coordinator in libspiffy 5.0.0: the fields each one takes, the reply that answers it, and how long ask() waits for that reply by default. Queries (…Query classes) are on Queries, and every event’s fields are on Events.

All commands are defined in lib/src/actors/coordinator_messages.dart and exported by package:libspiffy/coordinator.dart. The replies come from WalletCoordinatorActor (lib/src/actors/wallet_coordinator_actor.dart) and, for channels and proofs, from ChannelP2PAdapter and ProofP2PAdapter.

LibSpiffyActorSystem.coordinator is a WalletCoordinator. Every command with an answer is a CoordinatorRequest<R>, where R is its reply type. ask() sends the command and completes with that reply:

// Sketch: assumes an initialized LibSpiffyActorSystem named `libspiffy`
// and a mnemonic your app generated and backed up.
import 'dart:async';
import 'package:libspiffy/coordinator.dart';
Future<void> createAlice(String mnemonic) async {
try {
final created = await libspiffy.coordinator.ask(
CreateWalletCommand(walletId: 'alice', name: 'Alice', mnemonic: mnemonic),
);
print('created ${created.walletId}, root address ${created.rootAddress}');
} on CoordinatorFailure catch (failure) {
print('not created: ${failure.message}');
} on TimeoutException {
print('no reply yet; it may still arrive on coordinatorEvents');
}
}

How a request is answered:

  • requestId. Every request takes an optional requestId (String?). When you leave it out, one is generated when the command is made. The reply carries it back, and so does an ErrorEvent the request causes, so two requests of the same kind running at once each get their own answer. The field tables below leave requestId out.
  • A returned reply is a success. ask() throws CoordinatorFailure when the reply reports a failure, when an ErrorEvent names the request, or when the coordinator stops first (CoordinatorFailure.closed). CoordinatorFailure.event holds the failed reply or the ErrorEvent.
  • Timeouts. ask() throws TimeoutException when no reply arrives within the request’s replyTimeout, the default timeout listed for each command below. Pass timeout: to override it. A timeout does not cancel the request: it may still finish, and its reply then arrives on the event stream only.
  • tell() sends a command without waiting. Its reply is still published on libspiffy.coordinatorEvents. Use tell() for the commands marked “none — tell only”.

Field types such as InvoiceOutputSpec, PaymentPrivacy, Type42Derivation, Brc100KeyRequest and DeferredPaymentNetworkSource are exported by package:libspiffy/libspiffy.dart. See the API reference for their members.

The defaults are constants on CoordinatorRequest:

Constant Value Used by
defaultTimeout 1 minute Requests answered from the coordinator’s own state or one wallet round trip
paymentTimeout 3 minutes PayInvoiceCommand, ProvisionFundingCommand
networkTimeout 3 minutes Requests that wait on one ARC answer
receiveTimeout 5 minutes ValidateBEEFCommand, ImportTransactionCommand
channelTimeout 5 minutes OpenChannelCommand, CloseChannelCommand
reclaimTimeout 6 minutes ReclaimDeferredPaymentCommand
splitTimeout 15 minutes SplitUTXOsCommand
foreignSpendsTimeout 15 minutes CheckForeignSpendsCommand
importTimeout 1 hour ImportWalletCommand

TimestampCommand waits paymentTimeout + networkTimeout, 6 minutes.

Creates a wallet from one of mnemonic (HD wallet), wif, xpriv or xpub (watch-only). libspiffy generates no keys: a wallet with no key material is refused, and your app generates and backs up the mnemonic.

Field Type Required
walletId String yes
name String yes
mnemonic String? no
wif String? no
xpriv String? no
xpub String? no
walletMetadata Map<String, dynamic>? no

Reply: WalletCreatedEvent, once the read model holds the wallet. Default timeout: 1 minute.

Deletes a wallet. The deletion is journaled as an event.

Field Type Required
walletId String yes
reason String? no

Reply: WalletDeletedEvent, once the read model no longer holds the wallet. A refusal is the reply’s failure. Default timeout: 1 minute.

Imports a wallet’s history from the network. With a mnemonic, the wallet is created from it and its import run as a resume, which derives its keys from the stored mnemonic. With resume: true the wallet must already exist and you give no key: the import reads the key from secure storage, skips what the wallet already holds and imports the rest. Use resume to continue an import after the app was killed, to retry one that ended with transactionsFailed above zero, or to rescan.

Field Type Required
walletId String yes
walletName String yes
xpriv String? no
mnemonic String? no
wif String? no
gapLimit int no (default 20)
networkType String no (default 'test')
resume bool no (default false)

Reply: ImportCompleteEvent. ImportProgressEvent, ImportUTXOConfirmedEvent and ImportTransactionConfirmedEvent are emitted while it runs. With no key and no resume, or without a blockchain data source, the reply is a failed ImportCompleteEvent. Default timeout: 1 hour.

networkType defaults to 'test': set it to match your network.

Derives a fresh address no payment has used yet, on the receive chain (purpose 'receive', the default) or the change chain ('change'). With includePublicKey: true the reply carries the key’s public key, which a counterparty needs for P2PK outputs or a multisig.

Field Type Required
walletId String yes
label String? no
purpose String? no
includePublicKey bool no (default false)

Reply: AddressGeneratedEvent, once the read model holds the address, so a payment to it validates at once. Default timeout: 1 minute.

Adds an address the wallet watches but holds no key for. Funds at it count in watchOnlyBalance, not in the spendable balance.

Field Type Required
walletId String yes
address String yes
scriptType String yes
label String? no

Reply: WatchAddressRegisteredEvent. Default timeout: 1 minute.

Creates an invoice and issues its receive addresses. Give amount for a simple invoice, or outputs for a multi-output one. expiresIn wins over expiresInSeconds.

Field Type Required
walletId String yes
amount BigInt? no
outputs List<InvoiceOutputSpec>? no
description String? no
expiresIn Duration? no
expiresInSeconds int? no
invoiceMetadata Map<String, dynamic>? no
numberOfAddresses int no (default 1)

Reply: InvoiceCreatedEvent. Default timeout: 1 minute.

Builds and signs a payment for an invoice and returns it as BEEF. It does not broadcast: you hand the BEEF to the recipient, who normally broadcasts it. Until the network has it, the payment is a deferred payment and its inputs stay held. deadline makes the wallet reclaim the payment by itself if it is still outstanding then.

Field Type Required
walletId String yes
invoiceId String yes
addresses List<String> yes
amount BigInt yes
outputs List<InvoiceOutputSpec>? no
changeAddress String? no
paymentMetadata Map<String, dynamic>? no
counterpartyMarker String? no
memo String? no
deadline DateTime? no
privacy PaymentPrivacy? no

Reply: PaymentReadyEvent with beefBytes, txid, amountPaid and changeAmount. Default timeout: 3 minutes.

Receives a counterparty’s payment: checks the BEEF structurally and with SPV against the local headers, records it, and submits a transaction that carries no proof of its own to ARC. type42Derivations is the payer’s hand-off for a payment to one of this wallet’s anchor keys.

Field Type Required
walletId String yes
beefHex String yes
invoiceId String? no
fromCounterparty String? no
memo String? no
type42Derivations List<Type42Derivation> no (default const [])

Reply: BEEFValidationResultEvent. If the proofs name a block header the wallet has not synced, the reply has awaitingHeader: true and a second event follows when the header arrives, after a restart too. If the payment pays an invoice, InvoicePaidEvent follows. Default timeout: 5 minutes.

Records an outgoing transaction you built and broadcast outside the coordinator, and marks the inputs in spentUtxoKeys (txid:vout) spent.

Field Type Required
walletId String yes
txid String yes
rawHex String yes
totalInputSats int yes
totalOutputSats int yes
fee int yes
numInputs int yes
numOutputs int yes
txVersion int yes
txLockTime int yes
spentUtxoKeys List<String> yes
recipientAddresses List<String> yes
paymentAmount int yes
changeAddress String? no
changeAmount int? no
counterpartyMarker String? no
memo String? no

Reply: TransactionRecordedEvent, once the read model holds the transaction. A refusal is the reply’s failure. Default timeout: 1 minute.

Imports a transaction that is already mined. The BEEF must carry the merkle proof of its last transaction; one without is refused. Use delegatedIndices or type42Derivations to take over a payment that a service or a payer received for this wallet and handed over with ExportTransactionQuery. A counterparty’s unmined payment goes through ValidateBEEFCommand instead.

Field Type Required
walletId String yes
beef List<int> yes
fromCounterparty String? no
memo String? no
delegatedIndices List<int> no (default const [])
type42Derivations List<Type42Derivation> no (default const [])

Reply: TransactionImportedEvent, once the read model holds the transaction. SPVValidationResultEvent is emitted on the way. Default timeout: 5 minutes.

Broadcasts every transaction in a BEEF that has no merkle proof yet to ARC, in dependency order. You need it for self-payments (token issuance, an identity anchor) where no counterparty will broadcast for you.

Field Type Required
walletId String yes
beefHex String yes
txid String yes

Reply: BEEFSettledEvent with submittedCount, skippedCount, failedCount and the failed txids. Default timeout: 3 minutes.

Releases the UTXOs held by a reservation, so they can be spent again.

Field Type Required
walletId String yes
reservationId String yes

Reply: UTXOsReleasedEvent, once the read model shows the release. releasedUtxoKeys is empty when the reservation held none. A refusal is the reply’s failure. Default timeout: 1 minute.

Splits spendable UTXOs into smaller ones whose values follow Benford’s law, for privacy. utxoKeys picks the UTXOs (txid:vout); null takes any, largest first. targetUtxoCount defaults to 5 pieces per UTXO when null.

Field Type Required
walletId String yes
targetUtxoCount int? no
maxUtxosToSplit int? no
utxoKeys List<String>? no
partSats BigInt? no
minPartSats BigInt? no

Reply: UTXOSplitCompleteEvent with one SplitTransactionOutcome per split transaction. UTXOSplitStartedEvent is emitted first when the split can start. Default timeout: 15 minutes.

Runs a script plugin’s funding provisioning: it builds a tree of transactions (a split and earmarks) from one large UTXO, and the coordinator records each transaction and registers the earmarked UTXOs.

Field Type Required
walletId String yes
pluginId String yes
pluginParams Map<String, dynamic> yes

Reply: ProvisioningCompleteEvent. Default timeout: 3 minutes.

Pays a transaction with one OP_RETURN output per file hash, to timestamp the hashes on chain.

Field Type Required
archiveId String yes
walletId String yes
fileHashes List<String> yes
archiveTitle String? no

Reply: TimestampCompleteEvent with the archiveId and the transactionId, after ARC answers the broadcast. A timestamp ARC refused records nothing. Default timeout: 6 minutes.

Asks the configured data source whether outputs the wallet holds were spent by someone else; by default every unspent plugin output (token). A spender that is mined and proven against the local headers is recorded in the wallet.

Field Type Required
walletId String yes
utxoKeys List<String>? no

Reply: ForeignSpendsCheckedEvent, once the read model shows what was recorded. Default timeout: 15 minutes.

A payment built by PayInvoiceCommand is a deferred payment until the network has it: the wallet holds its inputs, and no other payment can take them. List them with GetDeferredPaymentsQuery. via chooses where a network call goes: DeferredPaymentNetworkSource.arc (default), .dataSource or .arcThenDataSource.

Broadcasts a deferred payment yourself, for example when the recipient is slow to. Its unconfirmed ancestors are submitted first. Safe to repeat: a transaction the network already has is reported as such.

Field Type Required
walletId String yes
txid String yes
via DeferredPaymentNetworkSource no (default DeferredPaymentNetworkSource.arc)

Reply: DeferredPaymentBroadcastEvent. Default timeout: 3 minutes.

Asks the network about a deferred payment now instead of waiting for the periodic scan. A MINED answer confirms the payment only when its merkle proof matches the local headers.

Field Type Required
walletId String yes
txid String yes
via DeferredPaymentNetworkSource no (default DeferredPaymentNetworkSource.arc)

Reply: DeferredPaymentStatusEvent. Default timeout: 3 minutes.

Cancels an outstanding deferred payment and releases its inputs. The network is checked first; the cancellation is refused when the network knows the transaction, or when the check fails unless force is true. Cancelling does not revoke the signed transaction the recipient holds: use ReclaimDeferredPaymentCommand for that.

Field Type Required
walletId String yes
txid String yes
reason String? no
via DeferredPaymentNetworkSource no (default DeferredPaymentNetworkSource.arc)
force bool no (default false)

Reply: DeferredPaymentCancelledEvent with the releasedUtxoKeys. Default timeout: 3 minutes.

Spends the inputs a deferred payment holds back to this wallet and broadcasts that transaction, which makes the recipient’s copy unspendable. It is immediate and irreversible, and first seen wins: if the recipient’s copy reached the network first, the reclaim is rejected.

Field Type Required
walletId String yes
txid String yes
via DeferredPaymentNetworkSource no (default DeferredPaymentNetworkSource.arc)
reason String? no

Reply: DeferredPaymentReclaimedEvent. Default timeout: 6 minutes.

Replaces a deferred payment the wallet signed only in part with rawHex, the same transaction carrying the counterparty’s signatures. Nothing is broadcast.

Field Type Required
walletId String yes
txid String yes
rawHex String yes

Reply: DeferredPaymentCompletedEvent with the completedTxid. Default timeout: 1 minute.

Channel commands are handled by ChannelP2PAdapter, which answers a channel’s requests of one kind in the order they were made. Messages for the peer arrive as ChannelP2PMessageToSendEvent, which your app delivers on its own transport. A step of an open or close that fails, and the counterparty’s channel_reject or channel_error during an open, is an ErrorEvent with source ChannelP2PAdapter that names the request, so ask() throws CoordinatorFailure. A coordinator built without channel events answers every channel command with an ErrorEvent.

Opens a payment channel to serverPeerId, funded with fundingAmountSats and refundable after lockTimeDurationSeconds.

Field Type Required
walletId String yes
serverPeerId String yes
fundingAmountSats int yes
lockTimeDurationSeconds int yes
context String? no
counterpartyMarker String? no

Reply: the channel’s ChannelOpenedEvent, once the server accepted it and its funding is on the network. A ChannelP2PMessageToSendEvent (channel_request) for the peer is emitted on the way. Default timeout: 5 minutes.

Accepts a channel request you received as ChannelRequestReceivedEvent; copy its fields.

Field Type Required
channelId String yes
walletId String yes
clientPeerId String yes
clientPubKey String yes
clientAddress String yes
fundingAmountSats int yes
lockTimeUnix int yes
counterpartyMarker String? no

Reply: ChannelAcceptedEvent, once the acceptance is journaled and channel_accept is handed to your transport. The channel opens later, when the client funds it (ChannelOpenedEvent). Default timeout: 1 minute.

Rejects a channel request.

Field Type Required
channelId String yes
reason String? no

Reply: ChannelRejectedEvent. clientTold is true when the request was held and channel_reject was handed to your transport. Default timeout: 1 minute.

Pays amountSats over an open channel.

Field Type Required
channelId String yes
walletId String yes
amountSats int yes
purpose String? no
invoiceId String? no

Reply: the payment’s ChannelPaymentEvent, with the new sequence and balances, once the channel journals it and payment_update is handed to your transport. A refused payment (for example more than the client’s balance) is an ErrorEvent. Default timeout: 1 minute.

Closes a channel cooperatively.

Field Type Required
channelId String yes
reason String? no

Reply: ChannelClosedEvent. A close that fails (for example a settlement ARC did not take) is an ErrorEvent. Default timeout: 5 minutes.

Records that a channel’s lock time has passed. observedBy is 'client' or 'server'. It records the refund without broadcasting it.

Field Type Required
channelId String yes
observedBy String yes
settlementOrRefundTxId String? no

Reply: ChannelExpiredEvent. A failed expiry is the reply’s failure. Default timeout: 3 minutes.

Broadcasts the refund of an expired channel through ARC (non-cooperative close) and records the money back in the wallet. Leave refundTxHex null to use the signed refund the channel holds.

Field Type Required
channelId String yes
refundTxHex String? no

Reply: ChannelRefundClaimedEvent. Default timeout: 3 minutes.

Broadcasts again the funding transaction of a channel whose funding broadcast failed. The transaction is read from the channel’s journal; it is safe to repeat.

Field Type Required
channelId String yes

Reply: ChannelFundingRetriedEvent; ChannelOpenedEvent follows on success. Default timeout: 3 minutes.

Sends channel_open again for a channel that is open on this side but whose peer never got the message. Nothing is journaled.

Field Type Required
channelId String yes

Reply: ChannelOpenResentEvent. Default timeout: 1 minute.

libspiffy owns no transport. Your app carries bytes between peers, hands what arrives to the coordinator, and sends what the coordinator emits as P2PMessageToSendEvent.

Hands an inbound peer message to the coordinator. proof_request and proof_response go to the merkle-proof protocol; every other messageType goes to the channel protocol. ChannelP2PReceived is the same class under its older name, with the same fields and routing.

Field Type Required
fromPeerId String yes
messageType String yes
payload Map<String, dynamic> yes

Reply: none — tell only. What follows depends on the message: channel events, AncestorProofResponseEvent or AncestorProofRequestReceivedEvent.

Asks the counterparty who sent you txid for a fresh BEEF, when a reorg took an ancestor’s block off the active chain and the outputs can no longer be spent. The peer asked is the counterparty marker recorded on the transaction.

Field Type Required
walletId String yes
txid String yes
ancestorTxids List<String> no (default const [])

Reply: AncestorProofRequestedEvent. A P2PMessageToSendEvent with messageType proof_request goes out for your transport. The peer’s answer arrives later as AncestorProofResponseEvent. Default timeout: 1 minute.

These commands use the wallet’s anchor keys. An anchor key is issued per anchorContext (opaque bytes, for example an identity key followed by a rotation epoch). A wallet created from an xpub or a WIF has no anchor key.

Returns the wallet’s anchor public key for a context. Payers derive type-42 destinations from it to pay the wallet while it is offline. An empty context is refused.

Field Type Required
walletId String yes
anchorContext List<int> yes

Reply: AnchorPublicKeyEvent with publicKey (compressed, hex). Default timeout: 1 minute.

Signs SHA-256 of message with the anchor key for a context, to bind that anchor to an identity. The wallet hashes the message itself.

Field Type Required
walletId String yes
anchorContext List<int> yes
message List<int> yes

Reply: AnchorSignedEvent with signatureDer (hex, RFC 6979, low S). Default timeout: 1 minute.

Runs a BRC-100 key operation (request) with a BRC-42 child of the anchor key for a context. The private keys stay in the wallet.

Field Type Required
walletId String yes
anchorContext List<int> yes
request Brc100KeyRequest yes

Reply: Brc100KeyOperationEvent with the result. Default timeout: 1 minute.

Derives a type-42 address for paying the holder of anchorPublicKey. Pass the recipient’s anchorContext when it published one. Without invoiceNumber the wallet makes up a BRC-29 one.

Field Type Required
walletId String yes
anchorPublicKey String yes
anchorContext List<int>? no
invoiceNumber String? no
payerAnchorContext List<int>? no

Reply: Type42DestinationEvent with the destination (the address and the hand-off the payee imports the payment with). Default timeout: 1 minute.

Stores block headers from a source of your own. They are validated and placed on the header chain like headers from a peer.

Field Type Required
headers List<Map<String, dynamic>> yes
source String no (default 'external')

Reply: BlockHeadersStoredEvent with source set to the command’s source. Every StoreHeadersCommand is answered, also when its batch fails, with nothing stored. Default timeout: 1 minute.

Shuts the coordinator down: it cancels its subscriptions and closes the event stream. To stop the whole system, call LibSpiffyActorSystem.shutdown() instead.

No fields.

Reply: none — tell only. A WalletStatusEvent with status shutdown is emitted, then the event stream closes.

RefreshWalletCommand is gone: it refreshed nothing. To read a wallet’s current state, send the queries, or follow BalanceUpdatedEvent with libspiffy.coordinator.on<BalanceUpdatedEvent>(walletId: ...).