Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.ryvo.network/llms.txt

Use this file to discover all available pages before exploring further.

Ryvo enforces strict checks around permanent identities, bucketed channels, and off-chain signed settlement. This page covers the checks builders care about most.

Deployment-scoped signing domain

Every signed message includes a 16-byte message_domain. message_domain is derived inside the program from:
  1. a fixed Ryvo domain tag
  2. the program ID
  3. the chain ID
This means the signing domain is bound to the exact deployment. It cannot be set incorrectly by off-chain tooling, and a message signed for one environment will not verify on another.

Distinct chain IDs per environment

Mainnet, devnet, testnet, and localnet use distinct chain IDs. Because message_domain depends on chain_id, the derived domain differs across environments by construction. The practical consequence: a commitment signed for devnet cannot be replayed on mainnet, and vice versa, even if the program ID were otherwise identical. See Deployment for the specific chain IDs and message domains.

Permanent participants and permanent channels

The protocol removed participant recycling and channel close-and-reopen flows. This eliminates a whole class of replay complexity:
  • participant_id values do not get reused.
  • There is no reopened payment channel for an old signed message to target.
  • Off-chain services can rely on stable channel identities.

Canonical PDA checks

Settlement paths do not trust arbitrary program-owned accounts just because they deserialize correctly. The program re-derives and verifies canonical bucket PDAs for every participant and channel account passed in, including accounts that arrive through remaining_accounts. This matters most in settle_commitment_bundle and settle_clearing_round, where many accounts are passed dynamically. Concretely, the program checks:
  • participant bucket / owner-index bucket addresses against their seed rules
  • channel bucket addresses against ["channel-bucket-v2", token_id, bucket_id] and canonical lane mapping
A passed account that is not the canonical PDA is rejected with ChannelNotInitialized or ParticipantNotFound.

Monotonic cumulative settlement

Both unilateral commitments and cooperative rounds must move channel state strictly forward. If a signed message tries to settle to a cumulative amount that is less than or equal to the current settled_cumulative, the program rejects it with CommitmentAmountMustIncrease. This is both the replay-protection mechanism for off-chain commitments and the rule that makes “keep only the newest commitment” a safe strategy off-chain.

Balanced clearing rounds

settle_clearing_round requires that the net flow sums across the included participants balance correctly. Rounds with inconsistent deltas are rejected with NetFlowImbalance. Participants whose final net position is negative must hold enough total balance to cover it; the program uses saturating checks and returns InsufficientBalance or NetPositionOverflow on failure.

Signature verification integrity

Settlement instructions verify signatures and message structure before state writes:
  1. Commitment signatures are validated against the exact ryvo-cmt-v5 body.
  2. Clearing-round aggregate signatures are validated against the exact round body.
  3. Each signed message parses as a structurally valid protocol message.
  4. Settlement instructions are not called via CPI (CpiNotAllowed).
This prevents transaction-composition attacks that rely on passing pre-verified but unrelated signatures.

Timelocked channel maintenance

The protocol places a timelock in front of actions that would otherwise surprise the other side of the relationship:
  1. unlocking channel-specific locked funds
  2. rotating the channel signing key
  3. withdrawing protocol balance to an external token account
Each of these requires a request step and an execution step separated by the configured timelock. The exact durations per environment are on the Deployment page.

Self-channel rejection

The protocol explicitly rejects self-channels. This prevents a payer from creating a channel to itself and using settlement to bypass the unlock timing model. A violation returns SelfChannelNotAllowed.

Token-registration safety

Adding a token is an authority-gated instruction. The program rejects:
  • duplicate token IDs (TokenIdAlreadyInUse)
  • duplicate mints (TokenAlreadyRegistered)
  • zero token IDs (InvalidTokenId)
  • invalid ASCII symbols (InvalidTokenSymbol)
  • token decimals above the protocol’s supported range (InvalidTokenDecimals)
  • settlement against token accounts whose mint does not match the registered token (InvalidTokenMint)
This prevents most classes of token-confusion attacks where a look-alike mint could be substituted at settlement time.

Summary

Taken together, these checks mean:
  1. Signed messages are bound to one deployment.
  2. Account lookups are bound to canonical state.
  3. Settlement only moves forward.
  4. Channel maintenance cannot surprise the other side instantly.
  5. Submission is front-run resistant.
  6. Cross-token confusion is caught at registration.

See also