Skip to content

Add STATE_VERSION to all settlement PDA seeds - #89

Open
kaze-cow wants to merge 2 commits into
mainfrom
kaze/sc-287-add-state-version-as-a-seed-to-all-storage
Open

Add STATE_VERSION to all settlement PDA seeds#89
kaze-cow wants to merge 2 commits into
mainfrom
kaze/sc-287-add-state-version-as-a-seed-to-all-storage

Conversation

@kaze-cow

@kaze-cow kaze-cow commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Description

Updates the settlement root PDA seed to correspond to the Major and minor cargo package versions

Contents

Generally speaking the root state PDA is now:

macro_rules! state_version {
    () => { concat!(env!("CARGO_PKG_VERSION_MAJOR"), ".", env!("CARGO_PKG_VERSION_MINOR")) };
}

pub const SETTLEMENT_SEED: &[u8] = concat!("settlement v", state_version!()).as_bytes();

The whole seed is printable ASCII, so it shows up readably in explorers, logs and solana account output instead of trailing a raw byte. At 15 bytes it has ample headroom under the 32-byte MAX_SEED_LEN, which a test now pins.

No CU cost. Everything resolves in rustcstrings on the built .so shows settlement v0.1 baked into rodata — so nothing happens on-chain. The four extra seed bytes are free too: sol_create_program_address and sol_try_find_program_address charge a flat create_program_address_units (1500 CU) per bump attempted, before the seeds are even read out of program memory, so cost never scales with seed length.

Other considerations

  • User delegations stop working. Users delegate their token accounts to the state PDA, and a bump moves that address, so every user has to delegate again.
  • Whatever the buffers still hold is stranded. A buffer's funds are only spendable by the state PDA that is its SPL authority. After a bump the program can no longer sign for the old state PDA, so those funds can never be moved again. Buffers must be drained under the old program version first.

How to test

Check new strategy

🤖 Generated with Claude Code

Every account the settlement program stores lived at a PDA whose first
seed was the bare string `settlement`. A program upgrade that changed the
layout or meaning of stored state would therefore land on exactly the
same addresses as the previous version, so old order and state accounts
would be silently reinterpreted under the new layout.

Fold a `STATE_VERSION` constant into the prefix seed that all three PDA
families share, so bumping it relocates the program's whole address space
at once and accounts written by an older version become unreachable
rather than misread.

The version is formatted as decimal ASCII and concatenated onto the
prefix, giving `settlement1`, so the seed stays legible wherever seeds
surface. It remains a single seed rather than an extra seed slot, which
leaves the seed arity of all three schemes untouched and the compute cost
of every derivation unchanged.

The seed is built in a `const` item rather than a `const fn` because the
workspace denies `clippy::arithmetic_side_effects` and that lint skips
`const` item bodies but not `const fn` bodies.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@kaze-cow
kaze-cow requested a review from a team as a code owner August 4, 2026 08:16
@linear-code

linear-code Bot commented Aug 4, 2026

Copy link
Copy Markdown

SC-287

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant