Transaction Lifecycle
Platus has exactly two ways to change state on-chain:
deposit: public tokens enter the pool and become a private note. Permissionless, no proof.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 theOrchestrator. The Vault is a pure pass-through custodian that never calls untrusted code. See Vault. - The fee.
Vault.pullskims 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 tree — recursive_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.