Every deposit, transfer, and withdraw call follows the same lifecycle. Understanding the two phases helps you build UI that fails fast and shows meaningful progress.

Two-phase model

Prepare runs before the wallet prompt so validation errors (insufficient_state, unsupported_disclosure) surface without a signature request. Execute is one-shot — calling execute() twice on the same prepared operation throws an execution error.

Prepare outcomes

Rejected

Do not call execute() when status === 'rejected'. Inspect operation.errors — an array of structured PrivacySdkError values.

Prepared

When status === 'prepared', the operation includes: The prepared payload is useful for advanced UI (showing change amounts) but you can treat it as opaque for basic integrations.

Execute flow and progress events

Pass onEvent to receive stage updates during execute:
You can also pass signal: AbortSignal to cancel long-running execute work.

Error model

Prepare-time errors appear in operation.errors when status === 'rejected'. Execute-time errors arrive through progress events (status: 'error') or as thrown/rejected promises from execute().

Persisted state after success

On the storageCommit stage the SDK updates local domain state:
  • mark spent private records as consumed
  • insert new output records (recipient note, change note)
  • refresh pool commitment snapshot
  • append delivery metadata when configured
If you use a Redux adapter with localStorage hydration, persist the SDK state branch per wallet owner so records survive reloads — see State integration and Setup.

Operations

Domain semantics for each operation kind.

State integration

Why prepare reads SDK state.

Disclosure policy

Policy errors during prepare and execute.