Skip to main content

Transaction Lifecycle

Privacy Boost transactions don’t settle the instant you submit them. Settlement takes several seconds in the steady state and longer under congestion, so the SDK surfaces intermediate states you can drive UI and dependent actions from. This page explains what each state means and how to use preconfirmation — the intermediate state that lets you chain private actions before on-chain finality.

The state machine

Every transaction carries a raw lifecycle status and a derived consumer-facing phase. Use phase for UI and business logic; use status only for debugging, audit, or history views.
enum TransactionStatus {
  pending = 'pending',
  preconfirmed = 'preconfirmed',
  completed = 'completed',
  failed = 'failed',
  blocked = 'blocked',
}

enum TransactionPhase {
  inFlight = 'inFlight',
  spendable = 'spendable',
  final = 'final',
  failed = 'failed',
}
StatusPhaseMeaning
pendinginFlightAccepted by the SDK but not yet preconfirmed.
preconfirmed (transfer)spendableThe output note can be selected as input for the next private action.
preconfirmed (shield, unshield)inFlightProgress only — no spendable output is produced.
completedfinalSettled on-chain. Terminal success.
failedfailedTerminal failure — validation reject, revert, or unrecoverable reorg.
blockedinFlightHeld by compliance review. See complianceStatus for the verdict.
phase is recomputed automatically whenever status or type changes — you don’t need to derive it yourself.

What preconfirmation guarantees

When a transfer reaches preconfirmed, its output note is spendable: getNotes, getBalance, and prepareTransfer will select it as input for a chained operation, and the input notes it consumed are locked from reuse. It does not mean the transaction is on-chain. A reorg can still force a re-batch or transition the transaction to failed, in which case any chained spend against the preconfirmed output also unwinds. The practical rule: chain against spendable, but keep polling the originating request until it reaches final. Shields and unshields also pass through preconfirmed, but neither produces a spendable output — treat their preconfirmed state as progress UI only.

Polling

The SDK polls in-flight transactions for you:
sdk.transactions.poll(); // returns { pending, resolved, preconfirmed }
  • pending — still in flight (pending or preconfirmed).
  • resolved — newly reached completed or failed since the previous poll.
  • preconfirmed — newly transitioned into preconfirmed since the previous poll. Fires once per transaction.
The React SDK exposes the same signals through useTransactions({ onPreconfirmed, onAllResolved }). See the React and TypeScript guides for usage.
  • Show two distinct states, not one. “Submitted” (inFlight) and “Ready to use” (transfer-only spendable) communicate progress meaningfully; collapsing them into “pending” hides the preconfirmation win.
  • Gate chained actions on phase === 'spendable', not on status === 'completed'. The whole point of preconfirmation is to unblock the next action a few seconds earlier.
  • Mark preconfirmed transfers as not-yet-final in history. A dim row or “finalizing” badge keeps the distinction visible until polling reports completed.
  • Treat shield preconfirmed as progress only. Don’t let the user spend against a shielded amount until it reaches completed.
  • Handle blocked explicitly via complianceStatus rather than treating it as a generic failure.

State transitions

pending ─► preconfirmed ─► completed     (happy path)
   │            │
   │            └─► pending ─► …         (reorg: re-batch into a later epoch)
   │            │
   │            └─► failed               (revert / unrecoverable reorg)

   ├─► blocked ─► pending ─► …           (compliance clears)
   │       └────► failed                 (compliance rejects)

   └─► failed                            (validation reject)
phase is authoritative — UI should react to transitions rather than caching past states. Input notes consumed by a transaction become spendable again whenever it lands in failed.

See also