> ## Documentation Index
> Fetch the complete documentation index at: https://docs.privacyboost.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Transaction Lifecycle

> How Privacy Boost transactions progress from submission to finality, and how to use preconfirmation to chain actions before on-chain settlement

# 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.

```typescript theme={null}
enum TransactionStatus {
  pending = 'pending',
  preconfirmed = 'preconfirmed',
  completed = 'completed',
  failed = 'failed',
  blocked = 'blocked',
}

enum TransactionPhase {
  inFlight = 'inFlight',
  spendable = 'spendable',
  final = 'final',
  failed = 'failed',
}
```

| Status                            | Phase       | Meaning                                                               |
| --------------------------------- | ----------- | --------------------------------------------------------------------- |
| `pending`                         | `inFlight`  | Accepted by the SDK but not yet preconfirmed.                         |
| `preconfirmed` (transfer)         | `spendable` | The output note can be selected as input for the next private action. |
| `preconfirmed` (shield, unshield) | `inFlight`  | Progress only — no spendable output is produced.                      |
| `completed`                       | `final`     | Settled on-chain. Terminal success.                                   |
| `failed`                          | `failed`    | Terminal failure — validation reject, revert, or unrecoverable reorg. |
| `blocked`                         | `inFlight`  | Held 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:

```typescript theme={null}
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](/sdk/react/guides/transactions) and [TypeScript](/sdk/typescript/guides/transactions) guides for usage.

## Recommended UX patterns

* **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

* [TypeScript: Transactions](/sdk/typescript/guides/transactions)
* [React: Transactions](/sdk/react/guides/transactions)
* [Protocol Deep Dive](/technical-explainer/protocol)
* [Glossary: Preconfirmation](/technical-explainer/glossary#preconfirmation)
