Lifecycle: the hold state machine
shield ──▶ [note in tree]
initiate (sender wallet proof + sender-FI policy proof, phase 0)
──▶ nullifiers[2] published, change commitment appended,
Hold { payment_root, sender_fi_index, recipient_fi_index,
deadline_bucket, attestation, envelope, status = open }
resolve (main proof with witness-selected branch + recipient-FI policy
proof at phase 1 or 2, class 1)
──▶ one output commitment appended, status = closed
accept branch: output is the recipient note
reject branch: output is the sender's refund note
(identical records; see [§4.13](/protocol/leakage))
reclaim (sender wallet proof, after deadline_bucket, no FI proof)
──▶ refund commitment appended, status = closed
unshield (wallet proof) ──▶ value exits
The three proving phases are the policy lifecycle. Reclaim is the
fail-closed default and needs no consent. A hold's value is fixed at
initiate; the resolve and reclaim circuits prove the single output carries
exactly (asset, amount) from the shared region.
Consent model:
- Accept requires the recipient's spend authorization (a Schnorr
signature under
akoverpayment_root) inside the resolve circuit, so an FI cannot credit a user who has not agreed to receive. - Reject requires only the envelope plaintext and the bound FI's wrapper proof. The output is the sender's own value returning to the sender, so no user authorization is needed. The recipient FI can reject alone, which keeps the sender's funds liquid without waiting for the recipient to come online.
- Reclaim requires the sender's
aksignature andtime_bucket > deadline_bucket.