How a private action works
A private action (a payment, swap or withdrawal from the private balance) is one call to the STRK20 pool that carries a zero-knowledge proof. The pool checks the proof, not the sender, so Outis's relayer sends it from its own account and the user's account never appears on chain.
Loading diagram...
The steps
- Find the notes. The keychain reads the pool from Outis's indexer, which is given no key, and recognizes the account's notes on the device.
- Check. The action is proven against the chain ten blocks back. The keychain checks that the account and its recipients are set up, and that its notes cover the amount and are unspent.
- Quote. The relayer is paid by a withdrawal inside the action, so its fee is fixed before the proof is made.
- Review. The user sees every action, recipient, amount and fee.
- Sign. The owner key signs the action. The pool checks the signature inside the proof,
through the account's
is_valid_signature. - Prove. The proving service returns a proof in about half a minute. It is given the viewing key, which can read the account's private history but not spend it (see Who sees what).
- Send. The relayer sends
apply_actionsand is paid back in the same transaction. If it can't be reached, the action fails rather than go out from the user's account.
Exceptions
- Setting up and shielding are sent from the user's own account, which pays the fees from its public balance. Anyone can see that the account used the pool, but not what it did.
- Deposits are screened by the pool, and only the Starknet Foundation's prover can get the screening signature. Outis passes deposits to it through Starkscan, on mainnet only.
- Private swaps go through a helper the pool exempts from screening: AVNU's on mainnet, StarkWare's on Sepolia.
Fees
Each action pays the network's fee, mostly for the proof, and the pool's fee. Through the relayer, both come from the private balance as one quote.
From a dApp
wallet_strk20InvokeTransaction goes through all of these steps. wallet_strk20PrepareInvoke
stops after the proof and hands the dApp the call to send itself. See
Private requests.