Skip to content

Mini instruction fixes - #486

Open
metapileks wants to merge 13 commits into
pileks/met-543-mini-instructionsfrom
pileks/mini-instructions-fixes
Open

Mini instruction fixes#486
metapileks wants to merge 13 commits into
pileks/met-543-mini-instructionsfrom
pileks/mini-instructions-fixes

Conversation

@metapileks

@metapileks metapileks commented Aug 17, 2026

Copy link
Copy Markdown
Collaborator

Greptile Summary

This PR tightens mini-instruction validation, updates DAO and proposal migration behavior, changes buyback scheduling to use a cycle count, and moves hostile-liquidation state changes into proposal finalization.

  • Adds migration guards and reconstructs DAO spending-limit state from the canonical Squads account.
  • Revalidates large-spend caps and team recipients at launch.
  • Adds stricter spending-limit validation and revised buyback treasury valuation.
  • Removes the dedicated liquidation payload and introduces a replay issue when multiple liquidation proposals pass.

Confidence Score: 3/5

The PR should not merge until hostile-liquidation finalization preserves the first terminal liquidator instead of allowing later proposals to replace it.

Multiple liquidation proposals can coexist before liquidation, and the new finalization path unconditionally writes each passing proposal's liquidator into the DAO; the resulting identity controls who may enqueue estate transactions.

Files Needing Attention: programs/futarchy/src/instructions/finalize_proposal.rs

Security Review

A later hostile-liquidation proposal can overwrite the terminal liquidator identity established by an earlier passed proposal, transferring estate-management authority. How this was verified: The new finalization branch assigns dao.liquidator without the replay guard present in the removed liquidation instruction, and that field authorizes estate proposal enqueueing.

Important Files Changed

Filename Overview
programs/futarchy/src/instructions/finalize_proposal.rs Moves liquidation state changes into finalization but permits a later passed liquidation proposal to replace the active liquidator.
programs/futarchy/src/instructions/initialize_hostile_liquidate_proposal.rs Removes the program callback from the Squads payload and leaves only the legal-layer memo.
programs/futarchy/src/instructions/resize_dao.rs Migrates the DAO layout and reconstructs its spending-limit record from the canonical Squads PDA.
programs/futarchy/src/instructions/resize_proposal.rs Migrates legacy proposals to the typed ExecuteArbitrary representation while preserving launched timing and threshold snapshots.
programs/futarchy/src/state/proposal_action.rs Adds large-spend launch revalidation and revises buyback action fields and treasury-cap valuation.
programs/futarchy/src/state/dao.rs Adds exact migration-size metadata and centralized validation for spending-limit records.
sdk/src/futarchy/v0.6/FutarchyClient.ts Updates buyback APIs for cycle counts and derives the spending-limit account required by DAO migration.

Reviews (1): Last reviewed commit: "adjust buyback for jup trigger order" | Re-trigger Greptile

Greptile also left 1 inline comment on this PR.

@metapileks metapileks self-assigned this Aug 17, 2026
@metapileks
metapileks requested a review from metanallok as a code owner August 17, 2026 00:56
@github-actions

Copy link
Copy Markdown
Contributor

Repository Guard

  • Cargo.lock: pass
  • yarn.lock (root): pass
  • yarn.lock (sdk): pass
  • Repo guard: pass

Repository Guard

Cargo dependency pinning

  • Status: pass
  • Every programs/*/Cargo.toml dep uses =x.y.z, a path = .. workspace ref, or a git dep with a 40-char rev.

Cross-program Anchor/Solana version consistency

  • Status: pass
  • anchor-lang and anchor-spl are pinned to the version declared in repo-guard.toml across every program.

solana-program crate pin

  • Status: pass
  • Every solana-program = "=X" declaration is =1.17.14 (locked to match Cargo.lock).

Anchor.toml solana_version

  • Status: pass
  • Anchor.toml declares solana_version = "1.17.34" (local-dev install for anchor test).

Crate minimum age

  • Status: pass
  • All Cargo deps changed by this PR are at least 14 days old on crates.io.

Yarn package.json pinning

  • Status: pass
  • All package.json deps use exact versions (no ^, ~, ranges).

npm minimum age

  • Status: pass
  • All npm deps changed by this PR are at least 14 days old.

Workflow toolchain consistency

  • Status: pass
  • Every workflow declares anchor-version: 0.29.0.
  • Per-file solana-cli-version values match [toolchain.workflow_solana_cli] in repo-guard.toml.

GitHub Action SHA pinning

  • Status: pass
  • Every third-party action is pinned to a SHA in [actions.sha_allowlist].

Sensitive program / config changes

  • Status: warn
  • Review hint only (CODEOWNERS is the merge gate). Lines below match heuristics for security-sensitive changes:
  • High-sensitivity files touched: Anchor.toml, Cargo.lock
  • programs/futarchy/src/instructions/admin_update_proposal_params.rs:7 declare_id! literal change; Hardcoded Solana address literal -> + declare_id!("6awyHMshBGVjJ3ozdSJdyyDE1CTAXUwrpNMaRGMsb4sf");
  • programs/futarchy/src/instructions/initialize_hostile_takeover_proposal.rs:36 Program ID constant or variable change -> + program_id: crate::ID,
  • programs/futarchy/src/instructions/initialize_hostile_takeover_proposal.rs:76 Program ID constant or variable change -> + program_id: crate::ID,
  • programs/futarchy/src/instructions/initialize_mint_tokens_proposal.rs:99 Program ID constant or variable change -> + program_id: mint_governor::ID,
  • programs/futarchy/src/instructions/initialize_spending_limit_change_proposal.rs:39 Program ID constant or variable change -> + program_id: crate::ID,
  • tests/futarchy/integration/gatedLiquidationUnwind.test.ts:303 Program ID constant or variable change -> + squadsMultisigProgram: multisig.PROGRAM_ID,
  • tests/futarchy/integration/gatedLiquidationUnwind.test.ts:526 Program ID constant or variable change -> + squadsMultisigProgram: multisig.PROGRAM_ID,
  • tests/futarchy/integration/liquidationEndToEnd.test.ts:251 Program ID constant or variable change -> + squadsMultisigProgram: multisig.PROGRAM_ID,
  • tests/futarchy/unit/initializeBuybackTokenProposal.test.ts:27 Hardcoded Solana address literal -> + "MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr",
  • tests/futarchy/unit/initializeHostileLiquidateProposal.test.ts:66 Hardcoded Solana address literal -> + programId: new PublicKey("MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr"),
  • tests/futarchy/unit/liquidatorPath.test.ts:278 Program ID constant or variable change -> + squadsMultisigProgram: multisig.PROGRAM_ID,
  • tests/futarchy/unit/setSpendingLimit.test.ts:90 Program ID constant or variable change -> + squadsMultisigProgram: multisig.PROGRAM_ID,
  • tests/futarchy/unit/syncSpendingLimit.test.ts:128 Program ID constant or variable change -> + squadsMultisigProgram: multisig.PROGRAM_ID,

Overall status: pass

Lockfile freshness (Cargo.lock + yarn.lock) is checked by the workflow directly and cannot be bypassed. The sensitive-diff section is a review hint - CODEOWNERS handles the actual merge gate.

Comment on lines +184 to +185
dao.liquidator = Some(*liquidator);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 security Later liquidation replaces estate authority

When two hostile-liquidation proposals are launched before either finishes and both pass, each finalization unconditionally assigns its proposed liquidator, causing the second proposal to replace the first estate administrator with a different key. How this was verified: The new finalization branch assigns dao.liquidator without the replay guard present in the removed liquidation instruction, and this field authorizes estate proposal enqueueing.

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