Skip to content

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

Closed
graveyieldprotocol wants to merge 1 commit into
mainfrom
feat/grave-vault-m3-salvage-pool-preflight
Closed

feat(grave-vault): m3 salvage_pool pre-flight + cert freshness gates#12
graveyieldprotocol wants to merge 1 commit into
mainfrom
feat/grave-vault-m3-salvage-pool-preflight

Conversation

@graveyieldprotocol

@graveyieldprotocol graveyieldprotocol commented May 10, 2026

Copy link
Copy Markdown
Collaborator

Summary

Lands milestone 3 of the canonical 10-step GraveYield build sequence: GraveVault salvage_pool pre-flight + PoolRegistry. The instruction now opens with all the right gates wired; AMM remove_liquidity (m5), Jupiter swap (m6), and 40/40/20 distribution (m7) remain honest-stubbed below the pre-flight section.

Resolves Seth's Telegram lock from 2026-05-10:

  • MIN_CERT_TTL_SECONDS = 600 (10 min)
  • Doc patch deferred — code first, docs document what the code actually does.

Changes

Scanner (cert_ttl_seconds migration to governance-configurable + floor)

  • programs/grave-scanner/src/state/protocol_config.rs — added cert_ttl_seconds: i64 field. _reserved stays at 64 bytes; INIT_SPACE grows by 8 bytes (pre-mainnet, no migration concern).
  • programs/grave-scanner/src/constants.rs — added MIN_CERT_TTL_SECONDS: i64 = 600 (hardcoded floor; raising requires program upgrade) and DEFAULT_CERT_TTL_SECONDS: i64 = 3600. Old ELIGIBILITY_CERT_TTL_SECONDS const kept as #[deprecated] alias for backwards-compatible test fixtures.
  • programs/grave-scanner/src/errors.rs — added error 6019 CertTtlBelowMinimum.
  • programs/grave-scanner/src/instructions/initialize.rsInitializeParams.cert_ttl_seconds: i64 field with default-handling (0 → DEFAULT_CERT_TTL_SECONDS) and floor validation.
  • programs/grave-scanner/src/instructions/update_protocol_config.rsUpdateProtocolConfigParams.cert_ttl_seconds: Option<i64> with floor validation. Reverts CertTtlBelowMinimum for any value < 600s.
  • programs/grave-scanner/src/instructions/evaluate_pool_phase2.rs — reads cfg.cert_ttl_seconds instead of the hardcoded const when stamping cert.expires_at.

Vault (salvage_pool full pre-flight)

  • programs/grave-vault/src/instructions/salvage_pool.rs — flagship change. Five gates wired:
    1. !cfg.emergency_pausedProtocolPaused (existing).
    2. !cert.is_expired(now)EligibilityCertExpired (NEW). TTL window comes from Scanner ProtocolConfig, floored at 600s.
    3. cert.criteria_bitmap == 0x3FInvalidEligibilityCert (NEW). All six derelict-pool criteria must have passed at Phase 2.
    4. cert.amm_program_id == params.amm_program_id AND cert.pool_address == params.pool_addressInvalidEligibilityCert (NEW). Defense in depth against forged seed match.
    5. pool.key() == params.pool_addressPreflightFailed (existing).
    • eligibility_cert migrated UncheckedAccountAccount<'info, EligibilityCert>. Anchor now handles 8-byte discriminator + owner-program (grave_scanner::ID) automatically; manual ownership require! removed as redundant.
    • lp_holder_pool_vault migrated UncheckedAccountSystemAccount<'info> with init_if_needed + space = 0. First salvage of a pool creates the system-owned 0-data PDA; subsequent salvages of the same pool blocked upstream by pool_registry init constraint, so the init_if_needed footgun does not apply.
    • Inline TODOs name m4–m7 deliverables and explicitly capture min_quote_output_lamports to keep the unused-variable lint quiet through m6.
  • programs/grave-vault/src/instructions/claim_lp_proceeds.rslp_holder_pool_vault aligned to SystemAccount<'info> for type consistency with salvage_pool.
  • programs/grave-vault/Cargo.toml — added init-if-needed feature to anchor-lang dependency.
  • CHANGELOG.md — created with v1.0.6 entry naming each change + honest-stub status.

Verification status

  • All 10 files written and committed atomically (commit 35afe30).
  • Cross-program type binding: Account<'info, EligibilityCert> works because grave-scanner = { features = ["cpi"] } and #[account] macro generates a stable Owner impl that resolves to grave_scanner::ID regardless of consuming crate.
  • cargo check / cargo clippy -D warnings not yet run. Pending Seth's ship-now-vs-verify-first call. v1.0.7 will be the post-verification patch with any compile fixes named in CHANGELOG (per established cadence).
  • No localnet tests in this PR. m3 test plan (8 cases — happy path → AmmAdapterUnimplemented revert; pause; missing cert; stale cert; double salvage; cert criteria mismatch; cert pool mismatch; pool address mismatch) is a follow-up PR once Anchor.toml localnet validator setup lands.

Honest-stub status (m4–m7 still pending)

  • AMM remove_liquidity Raydium V4: wired in v1.0.5 background work; not yet integration-tested against seeded localnet pool (OpenBook seed harness is v1.1).
  • AMM adapters Raydium CLMM / Orca / PumpSwap: revert AmmAdapterUnimplemented.
  • Locker release adapters UNCX / PinkSale / Team Finance: revert LockerAdapterUnimplemented.
  • Jupiter v6 swap CPI: not wired; m6 deliverable.
  • 40/40/20 distribution math: not wired; m7 deliverable. SalvageReceipt distribution fields are zeroed at init.
  • LP-holder Merkle proof verification in claim_lp_proceeds: returns InvalidClaimProof until m6.

Pre-mainnet checklist additions

  • Re-deploy ProtocolConfig PDAs on devnet — adding cert_ttl_seconds changes INIT_SPACE. Existing config accounts will fail realloc unless rotated through a fresh initialize. (No-op on the canonical pre-mainnet deploy path since no live config exists.)
  • Replace placeholder program IDs in both crates' declare_id! and Anchor.toml via anchor keys list && anchor keys sync before any audit submission.

Test plan

  • Pull this branch and run cargo check from repo root (Rust 1.85, Solana 2.0.21, Anchor 0.31.1).
  • Run cargo clippy --all-targets -- -D warnings.
  • Run pnpm -r typecheck to verify SDK types still resolve against the new IDL.
  • CI workflow: terminology-lint.sh should pass (no rescue / RescueReceipt introduced — all canonical v4.0 terms).
  • (Followup PR) Localnet test suite for the 8 m3 revert cases.

Summary by CodeRabbit

Release Notes

  • New Features

    • Certificate Time-To-Live (TTL) is now governance-configurable with enforced minimum duration
    • Added certificate freshness validation and enhanced protocol state checks during pool salvage operations
    • Improved account type safety for LP holder vault operations
  • Chores

    • Updated v1.0.6 changelog documenting milestone-3 implementation
    • Enhanced Anchor framework dependency configuration for vault initialization

Review Change Stack

- scanner: ProtocolConfig.cert_ttl_seconds field (governance-configurable)
- scanner: MIN_CERT_TTL_SECONDS=600 hardcoded floor + error 6019
- scanner: phase2 reads cfg.cert_ttl_seconds (was hardcoded const)
- vault:   salvage_pool full pre-flight (pause, freshness, criteria, bind)
- vault:   typed Account<EligibilityCert> cross-program account binding
- vault:   lp_holder_pool_vault as SystemAccount + init_if_needed
- vault:   claim_lp_proceeds aligned to SystemAccount type
- vault:   Cargo.toml +init-if-needed feature on anchor-lang

Lands milestone 3 of canonical 10-step build sequence. AMM remove,
Jupiter swap, and 40/40/20 distribution remain honest-stubbed (m5-m7).
@coderabbitai

coderabbitai Bot commented May 10, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

The PR implements governance-configurable certificate TTL validation with minimum enforcement and strengthens GraveVault account type safety by migrating from unchecked accounts to typed PDAs, adding pre-flight gating logic for protocol pause, certificate freshness, criteria enforcement, and parameter binding verification in salvage_pool.

Changes

TTL Configuration and Account Type Strengthening

Layer / File(s) Summary
TTL Constants and Error Definitions
programs/grave-scanner/src/constants.rs, programs/grave-scanner/src/errors.rs
Introduces DEFAULT_CERT_TTL_SECONDS (3600s), MIN_CERT_TTL_SECONDS (600s), deprecated alias for backward compatibility, and CertTtlBelowMinimum error variant.
ProtocolConfig State Schema
programs/grave-scanner/src/state/protocol_config.rs
Adds cert_ttl_seconds: i64 field documenting governance update constraints and phase-2 usage.
Initialize TTL Validation
programs/grave-scanner/src/instructions/initialize.rs
InitializeParams gains cert_ttl_seconds; handler defaults to DEFAULT_CERT_TTL_SECONDS, validates minimum floor, and stores in config.
Update TTL Validation
programs/grave-scanner/src/instructions/update_protocol_config.rs
UpdateProtocolConfigParams adds optional cert_ttl_seconds; handler validates and updates config with minimum floor enforcement.
Phase-2 Certificate Issuance
programs/grave-scanner/src/instructions/evaluate_pool_phase2.rs
Uses governance-configurable cfg.cert_ttl_seconds instead of fixed constant to stamp cert.expires_at with overflow checking.
Account Type Wiring
programs/grave-vault/Cargo.toml, programs/grave-vault/src/instructions/salvage_pool.rs, programs/grave-vault/src/instructions/claim_lp_proceeds.rs
Enables init-if-needed feature; defines ALL_CRITERIA_MASK constant; wires eligibility_cert as typed Account<EligibilityCert> PDA; migrates lp_holder_pool_vault from UncheckedAccount to SystemAccount with init_if_needed in both instructions.
Salvage Pool Pre-flight Gating
programs/grave-vault/src/instructions/salvage_pool.rs
Adds sequential validation gates: protocol pause check, certificate freshness via is_expired, criteria bitmap enforcement against ALL_CRITERIA_MASK, and binding verification of amm_program_id and pool_address. Moves Clock::get() earlier, adds pool address consistency check, and explicitly captures min_quote_output_lamports for future steps.
Documentation
CHANGELOG.md
Documents v1.0.6 release with milestone-3 scope, added/changed items, verification status, audit-pending stubs, and pre-mainnet deployment checklist including ProtocolConfig PDA redeployment necessity.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

The PR introduces coordinated changes across TTL configuration and account type safety with clear validation logic and pre-flight gating, but requires careful review of the handler's gating sequence and state schema impact on serialization size.

Possibly related PRs

  • graveyieldprotocol/protocol#10: Prior PR making overlapping changes to grave-scanner (evaluate_pool_phase2, ProtocolConfig state, and error definitions) that this PR builds upon or extends.

Poem

🐰 With TTL floors and account types now strong,
The vaults shall gating-check all day long!
Freshness confirmed, criteria aligned bright—
Salvage pools now guard with pre-flight!

🚥 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 accurately describes the main change: implementing milestone 3 salvage_pool pre-flight gates and certificate freshness validation, which aligns with the primary changes across grave-scanner and grave-vault.
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/grave-vault-m3-salvage-pool-preflight

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.

🧹 Nitpick comments (1)
programs/grave-vault/src/instructions/salvage_pool.rs (1)

29-35: ⚡ Quick win

Consider adding a test assertion to verify mask synchronization.

The intentional duplication is reasonable for compile-time safety, but without an automated check, the two constants could silently drift during refactoring. A simple test assertion would catch this:

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn all_criteria_mask_matches_scanner() {
        assert_eq!(
            ALL_CRITERIA_MASK,
            grave_scanner::criteria::ALL_CRITERIA_MASK,
            "ALL_CRITERIA_MASK drifted from grave_scanner"
        );
    }
}
🤖 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 `@programs/grave-vault/src/instructions/salvage_pool.rs` around lines 29 - 35,
Add a unit test that asserts the local ALL_CRITERIA_MASK equals
grave_scanner::criteria::ALL_CRITERIA_MASK to prevent drift; create a
#[cfg(test)] mod tests with a #[test] fn (e.g.
all_criteria_mask_matches_scanner) that calls assert_eq!(ALL_CRITERIA_MASK,
grave_scanner::criteria::ALL_CRITERIA_MASK, "...") so CI fails if the two
constants diverge.
🤖 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.

Nitpick comments:
In `@programs/grave-vault/src/instructions/salvage_pool.rs`:
- Around line 29-35: Add a unit test that asserts the local ALL_CRITERIA_MASK
equals grave_scanner::criteria::ALL_CRITERIA_MASK to prevent drift; create a
#[cfg(test)] mod tests with a #[test] fn (e.g.
all_criteria_mask_matches_scanner) that calls assert_eq!(ALL_CRITERIA_MASK,
grave_scanner::criteria::ALL_CRITERIA_MASK, "...") so CI fails if the two
constants diverge.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 9db1dbe3-f121-4414-aa2a-cc48198856ac

📥 Commits

Reviewing files that changed from the base of the PR and between 4a4aa6c and 35afe30.

📒 Files selected for processing (10)
  • 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/Cargo.toml
  • programs/grave-vault/src/instructions/claim_lp_proceeds.rs
  • programs/grave-vault/src/instructions/salvage_pool.rs

graveyieldprotocol added a commit that referenced this pull request May 12, 2026
Implements Raydium V4 AmmInfo (752-byte) pool account parsing. Reads
coin_vault, pc_vault, coin_vault_mint, pc_vault_mint, lp_mint at the
documented byte offsets (336/368/400/432/464); resolves the actual vault
token accounts and lp_mint via remaining_accounts; returns PoolData with
real reserves and LP supply.

Defense in depth: vault accounts' mint fields are verified against
AmmInfo's claimed mints (PoolDataParseError on mismatch), so an attacker
who supplies the genuine pool account but forged vault accounts (e.g.
vaults pointing to a different mint) is rejected.

Architectural changes (touch all 5 adapters + 2 handlers):
- adapters::extract_pool_data takes a third arg: remaining_accounts
- All AMM adapter parse() signatures accept remaining_accounts: &[AccountInfo]
- PoolData gains lp_mint: Pubkey (no longer aliased to base_mint)
- Phase 1 and Phase 2 handlers pass ctx.remaining_accounts through
- Locker check fix: now receives true lp_mint (was using base_mint placeholder
  per inaugural-commit comment)

Other AMM adapters (raydium_clmm, orca_whirlpool, pumpswap, meteora) keep
the new signature but continue to revert AmmAdapterUnimplemented — honest-
stub pattern unchanged.

Retires PRE-MAINNET-TODO CPI-001 (raydium_v4 layout). Adds a "Retired"
section to docs/PRE_MAINNET_CHECKLIST.md tracking the row with a post-
merge SHA pointer (filled by a tiny follow-up commit after merge).

Tests: 4 pure-Rust unit tests for AMM_INFO_SIZE constant, read_pubkey
byte offset extraction, out-of-bounds rejection, and synthetic 752-byte
fixture roundtrip across all five Pubkey offsets. Full parse() integration
test against a real mainnet pool (requires solana-program-test) is flagged
as m4.1 follow-up — not in this PR.

last_swap_unix_ts handling: Raydium V4 AmmInfo has no last-swap-timestamp
field; adapter returns 0 as sentinel. Handler continues to read
last_swap_unix_ts from instruction params until ORACLE-002 retires with
indexer-signed attestation. ORACLE-002 row updated to note this.

CHANGELOG.md not touched — that file is introduced by PR #12 (GraveVault
m3). After #12 merges, m4 work gets a CHANGELOG entry in a small follow-up.

Refs:
- Whitepaper v4.0.1 §3 (Six derelict-pool criteria)
- Combined Tech Doc v3.0.1 §3.5 (sweep_stale_anchor + criteria)
- v4.0 canonical build sequence step 5 (AMM remove_liquidity precondition
  is the GraveVault m5 deliverable; Scanner-side layout parse is m4)
graveyieldprotocol added a commit that referenced this pull request May 14, 2026
Aligns the toolchain to https://solana.com/docs/intro/installation:

  Solana CLI:   2.2.18  -> 3.0.10
  Anchor CLI:   0.31.1  -> 0.32.1
  Rust (host):  1.85.0  -> 1.91.1
  Node.js:      20      -> 24
  rust-version: 1.79    -> 1.91

platform-tools v1.54 pin retained in Cargo.toml [workspace.metadata.solana] — Solana 3.0.10's default platform-tools (v1.52, cargo 1.84) still cannot parse edition2024 manifests; v1.54 (cargo 1.85) is required.

Anchor 0.32 migration:
- 5 adapter files: removed unused `use anchor_lang::solana_program::pubkey;` (macro now resolves via prelude after 0.32's `solana-program → smaller crates` refactor)
- No other source changes required

Cargo.toml repository URL also corrected from stale lowercase graveyieldprotocol/protocol to org-canonical GraveYield-Protocol/protocol.

Verification:
- cargo fmt --all -- --check: clean
- cargo clippy --workspace --all-targets -- -D warnings: clean on Rust 1.91.1 + Anchor 0.32.1 (locally verified)
- cargo test -p grave-scanner --lib: 19/19 pass
- pnpm typecheck: clean on Node 24
- anchor build: BPF compile succeeds via Solana 3.0.10 + platform-tools v1.54 (CI verified, 338s)
- terminology-lint.sh: clean

All 5 CI jobs green on commit 78dbce1.

Follow-up not in this PR: PR #12 (GraveVault m3) will rebase against new main and inherit this toolchain. Any Anchor 0.32 surface that touches GraveVault's `init_if_needed` on SystemAccount will be handled at that rebase.
graveyieldprotocol added a commit that referenced this pull request May 14, 2026
…(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).
@graveyieldprotocol

Copy link
Copy Markdown
Collaborator Author

Superseded by #15.

The rebased version against current main (post-m4, post-Solana 3.x toolchain bump) is now open at #15 and is fully verified locally:

  • cargo fmt + clippy: clean on Rust 1.91.1 + Anchor 0.32.1
  • 20/20 tests pass
  • cargo-build-sbf --tools-version v1.54: BPF compile succeeds in 51s

Migration delta vs this PR: Anchor 0.32 rejects init/init_if_needed on SystemAccount (per the 0.32.0 release notes — lang: Add custom error when using init on SystemAccount). PR #15 replaces the lp_holder_pool_vault: SystemAccount<'info> + init_if_needed pattern with UncheckedAccount<'info> + a manual system_program::create_account CPI in the handler. Net behaviour is identical — system-owned, space=0, rent-exempt PDA created on first salvage of each pool — but compatible with the new Anchor major.

Closing this PR as not-planned. Original design is preserved 1:1 in #15.

graveyieldprotocol added a commit that referenced this pull request May 14, 2026
…15)

Lands milestone 3 of the canonical 10-step GraveYield build sequence:
GraveVault salvage_pool pre-flight + PoolRegistry init + 5 cert/pool gates.
Supersedes PR #12 (rebased onto current main with Anchor 0.32 migration).

## Scanner: cert_ttl_seconds governance-configurable

- state/protocol_config.rs: new cert_ttl_seconds: i64 field
- constants.rs: MIN_CERT_TTL_SECONDS=600 floor, DEFAULT_CERT_TTL_SECONDS=3600;
  old ELIGIBILITY_CERT_TTL_SECONDS kept as #[deprecated] alias
- errors.rs: new 6019 CertTtlBelowMinimum
- instructions/initialize.rs + update_protocol_config.rs: cert_ttl_seconds
  with floor validation
- instructions/evaluate_pool_phase2.rs: reads cfg.cert_ttl_seconds; preserves
  all m4 adapter wiring (remaining_accounts, lp_mint, criteria bitmap match)

## Vault: salvage_pool pre-flight + 5 gates

- instructions/salvage_pool.rs:
    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: UncheckedAccount -> Account<'info, EligibilityCert>
  (Anchor 0.32 handles discriminator + cross-program owner check)
- instructions/claim_lp_proceeds.rs: lp_holder_pool_vault as SystemAccount
- 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. Replaced:
- lp_holder_pool_vault: SystemAccount + init_if_needed -> UncheckedAccount
  + mut/seeds/bump (PDA validation only)
- Handler issues manual anchor_lang::system_program::create_account CPI when
  vault.lamports() == 0 (lazy first-salvage init, signed with PDA bump)
- Net result identical to original design: system-owned, space=0,
  rent-exempt PDA created on first salvage

## CHANGELOG.md

Introduced with v1.0.6 entry. Note: CodeRabbit flagged 2 minor wording
inaccuracies in the CHANGELOG (describes the init_if_needed approach we
replaced) — addressed in a follow-up fix-up commit.

## Verification

Local on 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
- cargo-build-sbf --tools-version v1.54: BPF compile clean in 51s

CodeRabbit reviewed: 2 minor 🟡 nits, both CHANGELOG.md wording (no code
findings). Honest stubs: m5 (Raydium V4 remove_liquidity CPI), m6 (Jupiter
swap + Merkle proof), m7 (40/40/20 distribution) remain pending.
@graveyieldprotocol

Copy link
Copy Markdown
Collaborator Author

Superseded by #15, which has now merged to main as 4cdd1a9d.

#15 contains this PR's full diff plus the Anchor 0.32 migration delta required by the toolchain bump in #14 (replacing init_if_needed on SystemAccount with a manual system_program::create_account CPI). The intent and on-chain semantics are preserved 1:1.

Please close this PR as not planned.

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