Skip to main content

Transaction Lifecycle

Platus has exactly two ways to change state on-chain:

  1. deposit: public tokens enter the pool and become a private note. Permissionless, no proof.
  2. transact: a proven batch spends notes, creates notes, settles public value, and optionally runs on-chain actions.

Everything a user does: internal transfer, withdrawal, swap, consolidation — is a transact.


Deposit

A deposit converts public ERC-20 into a single private note owned by a stealth address. It carries no ZK proof: the depositor reveals the asset and amount publicly, and the note's secrets are derived deterministically from a ledger nonce so the recipient can recover them by scanning events.

Key points:

  • Custody. Tokens land in the Vault, never in the Orchestrator. The Vault is a pure pass-through custodian that never calls untrusted code. See Vault.
  • The fee. Vault.pull skims a fixed 10 bps (FEE_BPS = 10) protocol fee to the fee collector; only the net is committed to the tree, so the note is spendable for exactly what backs it.

Because the secrets are public-derivable, anyone scanning sees a deposit's amount and asset. Privacy begins the moment that note is spent in a transact.


Transact

transact is the heart of the protocol. It is split across three environments: the client builds and proves, the bundler validates and aggregates, and the contract verifies and settles.

Stage 1 — Client: build, prove, sign

The SDK turns an intent (ActionOperationRequest) into a submittable operation through four pure phases.

Each Action then becomes a witness for the action circuit, which proves all the per-note constraints and emits a single Poseidon2 digest as its public output.

Stage 2 — Bundler: validate and aggregate

The bundler runs every cheap check before the expensive one: an op that would revert on-chain is rejected at ingress and never poisons a cross-user batch. It then builds the binary recursion treerecursive_2_leaf verifies pairs of Action proofs, recursive_2_inner folds pairs of subtrees, and finalize wraps the root into an EVM-verifiable proof. See Aggregation.

Stage 3 — Contract: verify and settle

Orchestrator.transact runs a strict checks-then-effects pipeline. Every check passes before any state changes (CEI). See State Transitions for the slot-level detail.


Public route: shielded value driving an on-chain call

A withdrawal-with-action (e.g. a private swap) uses the same transact but attaches an actionPayload to an Action. The settled public value is routed to a per-user AppAccount (an EIP-7702-delegated EOA), which executes the call; any leftover is re-shielded as a fresh note to the user's refundTarget.

The safety net: one user's failed action can never revert another user's bundle. See AppAccount and Orchestrator.