GlobalConfig
Singleton account holding protocol-wide configuration. Seeds:["global-config"]
| Field | Type | Notes |
|---|---|---|
authority | Pubkey | Active config authority |
fee_recipient | Pubkey | Receives withdrawal fees and registration fees |
fee_bps | u16 | Withdrawal fee in basis points (3–30) |
withdrawal_timelock_seconds | i64 | Fixed at initialize time by chain ID |
registration_fee_lamports | u64 | Flat SOL fee charged at initialize_participant |
next_participant_id | u32 | Monotonic counter for new participants |
bump | u8 | PDA bump |
chain_id | u16 | Deployment chain ID, fixed at initialize |
message_domain | [u8; 16] | Deployment-scoped signing domain |
pending_authority | Pubkey | Nominated successor (two-step handoff) |
_reserved | [u8; 14] | Future expansion |
chain_id and message_domain are immutable after initialize. Updating them would require a fresh deployment.
TokenRegistry
Singleton account holding the allowlist of supported settlement tokens. Seeds:["token-registry"]
| Field | Type | Notes |
|---|---|---|
authority | Pubkey | Registry authority - can register new tokens |
tokens | Vec<TokenEntry> | Up to 198 entries |
bump | u8 | PDA bump |
pending_authority | Pubkey | Nominated successor (two-step handoff) |
TokenEntry (51 bytes):
| Field | Type | Notes |
|---|---|---|
id | u16 | Unique token_id used in signed messages |
mint | Pubkey | SPL token mint |
decimals | u8 | Token decimals (≤ 20) |
symbol | [u8; 8] | ASCII symbol, null-terminated |
registered_at | i64 | Unix timestamp of registration (immutable) |
(id, mint) mapping is immutable. The registry authority cannot swap which mint a token_id refers to.
Participant buckets
Participant state is bucketed. A participant ID maps to one slot inside oneParticipantBucket.
Seeds: ["participant-bucket-v2", bucket_id (LE u32)]
Live sizing constants:
PARTICIPANT_BUCKET_SLOT_COUNT = 9MAX_BUCKET_TOKEN_BALANCES = 16
participant_id:
bucket_id = participant_id / 9slot_index = participant_id % 9
ownerparticipant_idinbound_channel_policy- BLS registration fields (
bls_scheme_version,bls_pubkey_compressed) - up to 16 token-balance entries (
available_balance,withdrawing_balance,withdrawal_unlock_at,withdrawal_destination)
Owner index buckets
Owner lookup is bucketed separately soowner -> participant_id resolution stays deterministic.
Seeds: ["owner-index-bucket-v2", bucket_id (LE u32)]
Live sizing constants:
OWNER_INDEX_BUCKET_COUNT = 1024OWNER_INDEX_BUCKET_SLOT_COUNT = 32
owner:
bucket_id = sha256(owner)[0..4] % 1024
Channel buckets
Channel state is also bucketed by token and participant pair ordinal. Seeds:["channel-bucket-v2", token_id (LE u16), bucket_id (LE u32)]
Live sizing constants:
CHANNEL_BUCKET_SLOT_COUNT = 46
lower_participant_id, higher_participant_id) and two directional lanes:
lower_to_higherhigher_to_lower
settled_cumulativelocked_balanceauthorized_signer- pending unlock fields
- pending signer-rotation fields
(payer_id, payee_id) ordering, so settlement always writes one deterministic lane per direction.
Protocol vault
Tokens deposited into Ryvo live in per-token vault token accounts derived from the program. They are SPL Token accounts owned by the program, not participant balances. Participantavailable_balance and channel locked_balance are ledger positions against this vault, the vault is the single source of truth for tokens actually held by the program.
See Balances and withdrawals for how the vault relates to participant state.
