The Ring program

offrecord-ring is the one program that governs every note of the Ring. It verifies the Ring’s proofs, then signs the Solana Privacy Program’s instructions.

Ids

Read from the Ring as this loads.

Reading the Ring

Ring program
Reading the Ring
Ring account
Reading the Ring
Fee vault
Reading the Ring
Relayer
Reading the Ring

The same values come from ring() in the SDK.

Accounts

AccountOwned byHolds
Ring accountThe Ring programThe auditor key, the policy hash, the four role keys, the exit fee rate and the pause flag. It binds the addresses of the two registries.
Enrollment registryThe storage programOne row per account: a wallet’s shielded keys, written once. Its root is what a spend proves ownership against.
Block list registryThe storage programThe block list entries under one root. Every transfer proves against it.
Fee vaultThe Ring programA program address no key signs for. It collects the exit fee, with one token account per mint, created on first use.
Ring authorityThe Ring programThe program address that signs the Solana Privacy Program’s ring instructions.

Instructions

InstructionSigned byWhat it does
initializeThe upgrade authorityCreates the Ring account with the role keys, fixes the auditor key and the policy for the Ring’s life, and registers the Ring with the Solana Privacy Program.
enrollThe enrollment writerWrites a batch of accounts’ shielded keys to the enrollment registry. Each owner’s signature is checked.
depositThe funding walletMoves an asset from a public wallet into the Ring’s notes.
transactThe fee payerVerifies the Ring proof, checks the exit fee leg on withdrawals, then signs the Solana Privacy Program’s ring_transact. The owner’s signature is proven inside the proof.
mergeThe fee payerCombines one owner’s notes of one asset into a single note.
set_block_listThe policy authorityAdds and removes block list entries.
set_exit_feeThe adminSets the exit fee rate, up to the cap fixed in the program.
pauseThe pauserPauses or resumes the Ring. A paused Ring moves no note.

Roles

Four role keys sit on the Ring account. No key holds two roles.

RoleCan
AdminHand a role to a new key, which also signs, and set the exit fee rate.
Policy authorityWrite block list entries. This is the list keeper’s key.
PauserPause and resume the Ring.
Enrollment writerSubmit batches of enrollments.

No role reads a transfer. The key that could is the empty seat.

Composes with

ProgramIts partId
Solana Privacy ProgramHolds the notes, vaults, trees and nullifiers, and verifies the Owned and conserved proof.ring1GaLCuJnkUMVkX2JeZLTTX17wKsV4fZmPVzXANW
User registryMaps a Solana address to an account’s shielded keys.ring().userRegistryProgramId
Storage programKeeps the enrollment and block list trees and their roots.ring().storageProgramId
SPL Token and Token-2022Move the assets that back the notes.The standard token programs

The Solana Privacy Program and its registry run unmodified at their upstream ids. Sources: helius-labs/privacy-rings and helius-labs/zolana-custom-rings, which holds the reference custom ring this program is built from.

The exit fee and the fee vault

The exit fee is the share of a withdrawal the Ring keeps, in the asset withdrawn. Its rate is a field of the Ring account, set by set_exit_fee. The Ring shows the current rate.

transact enforces it. On any transfer with a public withdrawal, the program requires a leg to the fee vault that covers the rate on what is withdrawn, or the transfer does not settle. Transfers that stay inside the Ring carry no exit fee.

The fee vault receives SOL at its own address and each token at a token account of that address.

TypeScript
const { exitFeeBps, feeVault } = await offrecord.ring()

feeVault.address
feeVault.balances // one holding per asset collected

Token says what the exit fee is for.