Skip to content

fix(audit): lock header v1 layout (MULT-4)#31

Merged
dev-jodee merged 10 commits into
audit/ai-scanner/01-rotate-program-keypairfrom
audit/ai-scanner/02-lock-header-v1
Apr 28, 2026
Merged

fix(audit): lock header v1 layout (MULT-4)#31
dev-jodee merged 10 commits into
audit/ai-scanner/01-rotate-program-keypairfrom
audit/ai-scanner/02-lock-header-v1

Conversation

@dev-jodee
Copy link
Copy Markdown
Collaborator

Audit finding: MULT-4

Lock the current delegation Header layout as the canonical v1 baseline and gate future growth.

Changes

  • Compile-time assert! for Header::LEN == 107 and every header offset (DISCRIMINATOR_OFFSET, VERSION_OFFSET, BUMP_OFFSET, DELEGATOR_OFFSET, DELEGATEE_OFFSET, PAYER_OFFSET, INIT_ID_OFFSET)
  • Compile-time assert! for FixedDelegation::LEN == 123, RecurringDelegation::LEN == 147, SubscriptionDelegation::LEN == 155
  • New "Pre-mainnet baseline (v1 lock)" section in docs/003-versioning-migration-architecture.md documenting the release-gate: any future layout change MUST bump CURRENT_VERSION and ship a v1 -> v2 migrate
  • CURRENT_VERSION doc-comment updated to reference the lock + release-gate

CURRENT_VERSION stays at 1. No migration code added.

Test plan

  • cargo build -p subscriptions (compile-time assertions enforced)
  • cargo test -p subscriptions --lib (210/210 pass)
  • Manual: changing any locked LEN value should fail cargo build with the asserted error message

Stack

Stacked on top of #30 (MULT-19).

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 28, 2026

Compute Unit Report

Instruction Samples Min CUs Max CUs Avg CUs Est Cost (Low) [SOL] Est Cost (Med) [SOL] Est Cost (High) [SOL]
cancel_subscription 11 1774 2098 1982 0.000005000 0.000005079 0.000005991
close_subscription_authority 7 1866 1901 1871 0.000005000 0.000005074 0.000005935
create_fixed_delegation 36 3566 18566 5180 0.000005001 0.000005207 0.000007590
create_plan 84 3525 11038 5331 0.000005001 0.000005213 0.000007665
create_recurring_delegation 25 3587 9592 4434 0.000005001 0.000005177 0.000007217
delete_plan 8 401 401 401 0.000005000 0.000005016 0.000005200
init_subscription_authority 136 5805 21274 9200 0.000005002 0.000005368 0.000009600
revoke_delegation 19 303 570 405 0.000005000 0.000005016 0.000005202
subscribe 21 6639 14163 8220 0.000005002 0.000005328 0.000009110
transfer_fixed 6 8478 8481 8480 0.000005002 0.000005339 0.000009240
transfer_recurring 17 8566 8651 8594 0.000005002 0.000005343 0.000009297
transfer_subscription 10 8862 8985 8901 0.000005002 0.000005356 0.000009450
update_plan 21 409 488 461 0.000005000 0.000005018 0.000005230

Generated: 2026-04-28

@dev-jodee dev-jodee force-pushed the audit/ai-scanner/01-rotate-program-keypair branch from 3ddc3cb to 6155c84 Compare April 28, 2026 13:09
@dev-jodee dev-jodee force-pushed the audit/ai-scanner/02-lock-header-v1 branch from 76ac33e to 6ecb3eb Compare April 28, 2026 13:12
@dev-jodee dev-jodee force-pushed the audit/ai-scanner/01-rotate-program-keypair branch from 6155c84 to 40be1d2 Compare April 28, 2026 13:27
@dev-jodee dev-jodee force-pushed the audit/ai-scanner/02-lock-header-v1 branch from 6ecb3eb to c2a2733 Compare April 28, 2026 13:29
- Compile-time assertions for Header::LEN, header field offsets, and
  FixedDelegation / RecurringDelegation / SubscriptionDelegation LEN
- Document release-gate in docs/003: future layout changes must bump
  CURRENT_VERSION and ship a migrate IX
- Annotate CURRENT_VERSION with the v1 lock note

CURRENT_VERSION stays at 1.
@dev-jodee dev-jodee force-pushed the audit/ai-scanner/02-lock-header-v1 branch from c2a2733 to 18f489c Compare April 28, 2026 13:36
@dev-jodee dev-jodee marked this pull request as ready for review April 28, 2026 16:24
- PLAN_LEN_V1 + assert in plan.rs
- PLAN_DATA_LEN_V1 + assert in create_plan.rs
Skip rollover when candidate_start >= expiry_ts. Pulls within drift
window remain valid in the final authorized period; no fresh allowance
is granted in terminal periods.

Affects validate_recurring_transfer (used by recurring delegations and
subscription transfers).
Extract is_effectively_expired helper. Sponsor revocation now waits the
same TIME_DRIFT_ALLOWED_SECS past expiry that transfers tolerate, so
sponsor cannot close a delegation while the delegatee can still pull.
Extend SubscribeData with expected_mint/amount/period_hours/created_at.
Program rejects with PlanTermsMismatch if the live plan disagrees with
what the subscriber signed. Stale-signed subscribe transactions can no
longer enroll into a recreated plan with different terms.

SDK and webapp callers fetch plan data and pass the snapshot.
Plan::check_destination and Plan::can_pull now filter out zero-padded
slots before membership tests. A plan with fewer than four configured
destinations no longer authorizes a zero-owned receiver, and a plan
with fewer than four pullers no longer authorizes a zero-pubkey caller.
…-10)

Webapp exit flows now pass the on-chain payer as receiver when it
differs from the connected signer, so sponsor-funded delegations and
SubscriptionAuthority accounts can actually be closed.

Also migrates revokeSubscription and cancelAndRevokeSubscription from
buildRevokeDelegation to buildRevokeSubscription with planPda + receiver,
fixing subscription revoke for both sponsor and non-sponsor cases.
…(MULT-9)

Stale-delegation cleanup no longer appends a close on the current
SubscriptionAuthority. Revoking stale delegations is now scoped to the
supplied delegation accounts; the SA stays open and current grants
remain valid.
@dev-jodee dev-jodee merged commit 8fe83b6 into audit/ai-scanner/01-rotate-program-keypair Apr 28, 2026
4 checks passed
@dev-jodee dev-jodee deleted the audit/ai-scanner/02-lock-header-v1 branch April 28, 2026 19:41
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