Skip to content

feat(grave-vault): m3 salvage_pool pre-flight + cert freshness gates (rebased)#15

Merged
graveyieldprotocol merged 1 commit into
mainfrom
feat/m3-grave-vault-rebased
May 14, 2026
Merged

feat(grave-vault): m3 salvage_pool pre-flight + cert freshness gates (rebased)#15
graveyieldprotocol merged 1 commit into
mainfrom
feat/m3-grave-vault-rebased

Conversation

@graveyieldprotocol

@graveyieldprotocol graveyieldprotocol commented May 14, 2026

Copy link
Copy Markdown
Collaborator

Summary

Supersedes #12. This is PR #12's m3 work rebased onto current main (post-m4 Scanner + post-Anchor 0.32 toolchain bump from PR #14). The original PR #12 was opened on 2026-05-10 and is now 4 commits behind main with conflicts; this is the clean continuation.

Lands milestone 3 of the canonical 10-step GraveYield build sequence: GraveVault salvage_pool pre-flight + PoolRegistry + cert freshness gates. AMM remove_liquidity (m5), Jupiter swap (m6), and 40/40/20 distribution (m7) remain honest-stubbed below the pre-flight section.

What ships

Scanner — cert_ttl_seconds is now governance-configurable

  • state/protocol_config.rs: new cert_ttl_seconds: i64 field (_reserved stays at 64 bytes; INIT_SPACE grows by 8 bytes — pre-mainnet, no migration concern)
  • constants.rs: new MIN_CERT_TTL_SECONDS = 600 (hardcoded floor; raising requires program upgrade) and DEFAULT_CERT_TTL_SECONDS = 3600. Old ELIGIBILITY_CERT_TTL_SECONDS kept as #[deprecated] alias.
  • errors.rs: new error 6019 CertTtlBelowMinimum
  • instructions/initialize.rs: cert_ttl_seconds: i64 with default-handling (0 → DEFAULT) and floor validation
  • instructions/update_protocol_config.rs: cert_ttl_seconds: Option<i64> with floor enforcement
  • instructions/evaluate_pool_phase2.rs: reads cfg.cert_ttl_seconds instead of the const. Preserves all m4 work in this file — adapter wiring with remaining_accounts, locker check using pool_data.lp_mint, criteria_bitmap match.

Vault — salvage_pool pre-flight + 5 gates

  • instructions/salvage_pool.rs (flagship):
    1. !cfg.emergency_pausedProtocolPaused
    2. !cert.is_expired(now)EligibilityCertExpired
    3. cert.criteria_bitmap == 0x3FInvalidEligibilityCert
    4. cert.amm_program_id / pool_address match params → InvalidEligibilityCert
    5. pool.key() == params.pool_addressPreflightFailed
  • eligibility_cert migrated UncheckedAccountAccount<'info, EligibilityCert>. Anchor 0.32 handles the 8-byte discriminator + cross-program owner check (grave_scanner::ID) automatically; manual ownership require! removed as redundant.
  • instructions/claim_lp_proceeds.rs: lp_holder_pool_vault aligned to SystemAccount<'info> for type consistency with salvage_pool. No init constraint here — safe under Anchor 0.32.
  • Cargo.toml: removed unused init-if-needed feature

Anchor 0.32 migration (new work not in original PR #12)

Anchor 0.32 rejects init/init_if_needed on SystemAccount with a deliberate compile error. PR #12's lp_holder_pool_vault: SystemAccount<'info> + init_if_needed was the trigger. Replaced with the canonical Anchor 0.32 pattern:

  • lp_holder_pool_vault: SystemAccount<'info> + init_if_neededUncheckedAccount<'info> + mut, seeds, bump (PDA validation only)
  • Handler issues a manual anchor_lang::system_program::create_account CPI when vault.lamports() == 0 (lazy first-salvage init, signed with the PDA bump)
  • Net result identical to the original design: system-owned, space=0, rent-exempt PDA created on first salvage of each pool

Subsequent salvages of the same pool are still blocked at the pool_registry init constraint, so the lazy-init only matters on the first call.

CHANGELOG.md

Introduced with the v1.0.6 entry naming each change + the honest-stub status.

Verification

Local checks on the official Solana 3.x stack (rust 1.91.1, anchor 0.32.1, solana 3.0.10, platform-tools v1.54):

  • cargo fmt --all -- --check: clean
  • cargo clippy --workspace --all-targets -- -D warnings: clean
  • cargo test --workspace --lib: 20/20 pass (19 grave-scanner + 1 grave-vault)
  • cargo-build-sbf --tools-version v1.54: BPF compile succeeds in 51s
  • CI: verify the same on GitHub Actions runners
  • scripts/terminology-lint.sh: no v3 vocabulary touched, expected pass

Honest-stub status (m4–m7 still pending)

  • AMM remove_liquidity for Raydium V4: tracked as m5
  • Jupiter v6 swap CPI: m6
  • 40/40/20 distribution math: m7 — SalvageReceipt distribution fields are zeroed at init
  • LP-holder Merkle proof verification in claim_lp_proceeds: returns InvalidClaimProof until m6
  • Locker release adapters (UNCX/PinkSale/Team Finance): future milestone
  • LP-holder snapshot Merkle root verification: m6 — today trusts salvor-supplied root, locks it into PoolRegistry

Closing PR #12

Once this PR merges, #12 should be closed as not-planned (superseded by #15). #12's design is preserved 1:1 here, with only the Anchor 0.32 migration delta added.

Refs

Summary by CodeRabbit

Release Notes - v1.0.6

  • New Features

    • Certificate time-to-live is now governance-configurable with enforced minimum thresholds
    • Salvage pool operations include enhanced preflight validation: certificate freshness checks, criteria matching, and binding verification
  • Improvements

    • Added validation enforcement for minimum certificate TTL requirements during initialization and configuration updates

Review Change Stack

…(rebased)

Re-submitting PR #12's m3 work, rebased onto current main (post-m4 Scanner
+ post-Anchor 0.32 toolchain bump). The original PR #12 was opened on
2026-05-10 and is now 4 commits behind main; this branch supersedes it.

What ships:

### Scanner — cert_ttl_seconds governance-configurable
- state/protocol_config.rs: new `cert_ttl_seconds: i64` field
- constants.rs: new MIN_CERT_TTL_SECONDS=600 (hardcoded floor) and
  DEFAULT_CERT_TTL_SECONDS=3600 (default 1h)
- errors.rs: new 6019 CertTtlBelowMinimum
- instructions/initialize.rs: cert_ttl_seconds param with floor validation
- instructions/update_protocol_config.rs: cert_ttl_seconds Option with floor
- instructions/evaluate_pool_phase2.rs: reads cfg.cert_ttl_seconds (preserves
  m4's adapter wiring with remaining_accounts + pool_data.lp_mint)

### Vault — salvage_pool pre-flight + 5 gates
- programs/grave-vault/src/instructions/salvage_pool.rs (flagship):
    1. !cfg.emergency_paused -> ProtocolPaused
    2. !cert.is_expired(now) -> EligibilityCertExpired
    3. cert.criteria_bitmap == 0x3F -> InvalidEligibilityCert
    4. cert.amm_program_id / pool_address match params -> InvalidEligibilityCert
    5. pool.key() == params.pool_address -> PreflightFailed
- eligibility_cert migrated UncheckedAccount -> Account<'info, EligibilityCert>
  for automatic owner-program validation against grave_scanner::ID
- programs/grave-vault/src/instructions/claim_lp_proceeds.rs:
  lp_holder_pool_vault aligned to SystemAccount<'info> for type consistency

### Anchor 0.32 migration (NEW work, not in original PR #12)

Anchor 0.32 rejects `init`/`init_if_needed` on `SystemAccount` with a
deliberate compile error. PR #12's design used init_if_needed for the
lp_holder_pool_vault PDA; this rebase replaces it with the canonical
Anchor 0.32 pattern:

- lp_holder_pool_vault changes from `SystemAccount<'info>` with
  `init_if_needed` to `UncheckedAccount<'info>` with `mut, seeds, bump`
  (PDA validation only; no init constraint)
- Handler issues a manual `anchor_lang::system_program::create_account`
  CPI when `vault.lamports() == 0` (lazy first-salvage init)
- grave-vault/Cargo.toml: removed the now-unused `init-if-needed` feature
- Net result identical to the original design: system-owned, space=0,
  rent-exempt PDA created on first salvage of each pool

CHANGELOG.md introduced with v1.0.6 entry naming each change.

Local verification on the official Solana 3.x stack (rust 1.91.1, anchor
0.32.1, solana 3.0.10, platform-tools v1.54):
- cargo fmt --all -- --check: clean
- cargo clippy --workspace --all-targets -- -D warnings: clean
- cargo test --workspace --lib: 20/20 pass (19 grave-scanner + 1 grave-vault)
- cargo-build-sbf --tools-version v1.54: BPF compile succeeds in 51s

Supersedes #12. Once this PR merges, #12 should be closed as `not-planned`
(superseded by #15).
@coderabbitai

coderabbitai Bot commented May 14, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

This PR implements governance-configurable certificate TTL bounds for GraveScanner and adds comprehensive preflight validation gates to GraveVault's salvage_pool instruction. Changes span protocol configuration, account constraint tightening via Anchor's type system, and enhanced initialization flows with lazy account creation.

Changes

Certificate TTL Governance and Preflight Certification

Layer / File(s) Summary
Certificate TTL configuration foundation
programs/grave-scanner/src/constants.rs, programs/grave-scanner/src/errors.rs, programs/grave-scanner/src/state/protocol_config.rs
Adds DEFAULT_CERT_TTL_SECONDS (3600s) and MIN_CERT_TTL_SECONDS (600s) constants with deprecated alias for backwards compatibility. Introduces CertTtlBelowMinimum error (code 6019). Extends ProtocolConfig with cert_ttl_seconds: i64 field for on-chain governance control.
Certificate TTL initialization and governance updates
programs/grave-scanner/src/instructions/initialize.rs, programs/grave-scanner/src/instructions/update_protocol_config.rs
initialize accepts cert_ttl_seconds, defaults to DEFAULT_CERT_TTL_SECONDS when zero, and validates against MIN_CERT_TTL_SECONDS. update_protocol_config adds optional cert_ttl_seconds parameter with identical minimum enforcement, reverting with CertTtlBelowMinimum if violated.
Phase 2 certificate expiry stamping from ProtocolConfig
programs/grave-scanner/src/instructions/evaluate_pool_phase2.rs
evaluate_pool_phase2 now reads cfg.cert_ttl_seconds to compute EligibilityCert.expires_at via checked_add, replacing the hardcoded constant. Floor enforcement is delegated to update_protocol_config.
GraveVault account type tightening
programs/grave-vault/src/instructions/claim_lp_proceeds.rs
lp_holder_pool_vault tightened from UncheckedAccount<'info> to SystemAccount<'info>, enabling Anchor's owner/discriminator validation while preserving PDA seed/bump constraints.
Salvage pool preflight certification gates and lazy vault initialization
programs/grave-vault/src/instructions/salvage_pool.rs
Comprehensive refactoring: tightens eligibility_cert to typed Account<EligibilityCert> with PDA constraints under grave_scanner::ID. Adds sequential preflight gates: emergency pause, certificate freshness, criteria bitmap validation against ALL_CRITERIA_MASK, AMM/pool binding checks, and pool key consistency. Implements lazy initialization of lp_holder_pool_vault via system_program::create_account CPI when lamports are zero. Post-preflight, updates PoolRegistry with snapshot/identity fields and initializes SalvageReceipt with zeroed distribution metadata.
Release notes documenting v1.0.6 changes
CHANGELOG.md
Documents certificate TTL governance additions, account type migrations, Anchor init_if_needed usage, Phase 2 TTL stamping, and salvage_pool preflight gates with verification status and pre-mainnet checklist.

Possibly related PRs

  • GraveYield-Protocol/protocol#10: Extends Phase 2 certification path by modifying evaluate_pool_phase_2 logic and ProtocolConfig (main PR adds cert_ttl_seconds governance; related PR wires Phase 2 to use protocol config and criteria bitmap validation).

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 A rabbit hops with glee,
TTL bounds now set by decree,
Preflight gates catch the flawed,
Lazy vaults by CPI awed,
Account types prove what they be!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main change: adding pre-flight checks and certificate freshness gates to the salvage_pool instruction, which is the primary focus across multiple file changes.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/m3-grave-vault-rebased

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@CHANGELOG.md`:
- Around line 34-37: Update the CHANGELOG entry that claims an `init_if_needed`
Anchor feature on `SystemAccount` (mentioned around the
`programs/grave-vault/Cargo.toml` note and on lines referencing
`init_if_needed`) to reflect the actual implementation: remove or correct the
assertion that Anchor provided `init_if_needed` for `SystemAccount` and instead
state that the migration uses a manual lazy-creation CPI (post-Anchor 0.32
rejection) to create the 0-data system-owned PDA for `lp_holder_pool_vault`, and
ensure the note still mentions that subsequent salvages are gated by the
`pool_registry` init constraint; apply the same correction to the other
occurrence that currently references `init_if_needed`.
- Around line 80-83: Update the verification status paragraph that currently
claims "`cargo check`: not yet run" to reflect the actual PR verification
results (local fmt/clippy/tests/build and BPF compile passed) by editing the
CHANGELOG entry text so it accurately states which checks have passed and that
cargo check was performed (or remove the "pending" note), and ensure the
phrasing matches the PR's reported checks and version v1.0.7 mention.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 27fa8c03-00fd-4df8-9084-b744fc4fd6fa

📥 Commits

Reviewing files that changed from the base of the PR and between 80ef6af and 6d4caf4.

📒 Files selected for processing (9)
  • CHANGELOG.md
  • programs/grave-scanner/src/constants.rs
  • programs/grave-scanner/src/errors.rs
  • programs/grave-scanner/src/instructions/evaluate_pool_phase2.rs
  • programs/grave-scanner/src/instructions/initialize.rs
  • programs/grave-scanner/src/instructions/update_protocol_config.rs
  • programs/grave-scanner/src/state/protocol_config.rs
  • programs/grave-vault/src/instructions/claim_lp_proceeds.rs
  • programs/grave-vault/src/instructions/salvage_pool.rs

Comment thread CHANGELOG.md
Comment on lines +34 to +37
- **`init_if_needed` Anchor feature** on `programs/grave-vault/Cargo.toml`
for the `lp_holder_pool_vault` SystemAccount. First salvage of a pool
creates the 0-data system-owned PDA; subsequent salvages of the same
pool are gated upstream by the `pool_registry` init constraint.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Fix the init_if_needed release-note claim; it contradicts the implemented Anchor 0.32 migration.

Line 34 and Line 56 document init_if_needed on SystemAccount, but this PR’s migration notes indicate the opposite path (manual lazy creation CPI after Anchor 0.32 rejection). Please update this section to match the actual final implementation.

Proposed changelog edit
-- **`init_if_needed` Anchor feature** on `programs/grave-vault/Cargo.toml`
-  for the `lp_holder_pool_vault` SystemAccount. First salvage of a pool
-  creates the 0-data system-owned PDA; subsequent salvages of the same
-  pool are gated upstream by the `pool_registry` init constraint.
+- **Anchor 0.32-compatible lazy vault init** for `lp_holder_pool_vault`:
+  replaced `init_if_needed` on `SystemAccount` with manual
+  `system_program::create_account` CPI when the PDA has zero lamports.
+  First salvage of a pool creates the 0-data system-owned PDA; subsequent
+  salvages of the same pool are gated upstream by the `pool_registry`
+  init constraint.
...
-- **`lp_holder_pool_vault`** in both `salvage_pool` and `claim_lp_proceeds`
-  migrated from `UncheckedAccount<'info>` to `SystemAccount<'info>`. In
-  `salvage_pool` the constraint adds `init_if_needed` + `space = 0`. The
+- **`lp_holder_pool_vault`** in `claim_lp_proceeds` migrated to
+  `SystemAccount<'info>` for stricter typing. In `salvage_pool`, lazy PDA
+  initialization is handled via manual CPI account creation (no
+  `init_if_needed` on `SystemAccount` under Anchor 0.32). The
   account remains charter-invariant unsweepable; only `claim_lp_proceeds`
   may debit it (against a valid Merkle proof, m6+).

Also applies to: 56-57

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@CHANGELOG.md` around lines 34 - 37, Update the CHANGELOG entry that claims an
`init_if_needed` Anchor feature on `SystemAccount` (mentioned around the
`programs/grave-vault/Cargo.toml` note and on lines referencing
`init_if_needed`) to reflect the actual implementation: remove or correct the
assertion that Anchor provided `init_if_needed` for `SystemAccount` and instead
state that the migration uses a manual lazy-creation CPI (post-Anchor 0.32
rejection) to create the 0-data system-owned PDA for `lp_holder_pool_vault`, and
ensure the note still mentions that subsequent salvages are gated by the
`pool_registry` init constraint; apply the same correction to the other
occurrence that currently references `init_if_needed`.

Comment thread CHANGELOG.md
Comment on lines +80 to +83
- `cargo check`: not yet run in this sandbox — pending Seth's
ship-now-vs-verify-first call. v1.0.7 will be the post-verification
patch with any compile fixes named in the CHANGELOG.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Update verification status to reflect this PR’s stated check results.

Line 80 says cargo check is pending, but the PR notes claim local fmt/clippy/tests/build and BPF compile already passed. This mismatch can mislead release readiness tracking.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@CHANGELOG.md` around lines 80 - 83, Update the verification status paragraph
that currently claims "`cargo check`: not yet run" to reflect the actual PR
verification results (local fmt/clippy/tests/build and BPF compile passed) by
editing the CHANGELOG entry text so it accurately states which checks have
passed and that cargo check was performed (or remove the "pending" note), and
ensure the phrasing matches the PR's reported checks and version v1.0.7 mention.

@graveyieldprotocol graveyieldprotocol merged commit 4cdd1a9 into main May 14, 2026
7 of 8 checks passed
graveyieldprotocol added a commit that referenced this pull request May 14, 2026
)

Two small follow-ups before m5 work begins.

1. CHANGELOG.md (addresses CodeRabbit's 2 minor findings on PR #15):
   - init_if_needed entry rewritten as the Anchor 0.32-compatible manual
     create_account CPI that actually shipped in PR #15.
   - lp_holder_pool_vault entry split: claim_lp_proceeds = SystemAccount
     (read-only, safe under 0.32); salvage_pool = UncheckedAccount + manual CPI.
   - Verification status reflects locally-passed checks plus the known CI
     anchor build failure being tracked.

2. CI workflow: anchor build now tees stdout/stderr to /tmp/anchor-build.log
   and uploads it as a workflow artifact via actions/upload-artifact@v4
   on failure. The Composio integration this repo uses for programmatic CI
   inspection does not expose log download, so this gives us a debuggable
   surface for the post-PR-15 anchor build regression.

No source changes. No on-chain semantics change.

Locally verified on rust 1.91.1 + anchor 0.32.1 + solana 3.0.10 + platform-tools v1.54:
- cargo fmt / clippy / 20/20 tests / cargo-build-sbf: all clean (working
  tree unchanged from main).

CI's anchor build still fails (same root cause as PR #15) — but this PR
adds the diagnostic mechanism we'll use to identify it.
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