Skip to content

fix: 9 HIGH-severity tranche/insurance security fixes - #98

Merged
dcccrypto merged 1 commit into
masterfrom
fix/stake-security-batch-2
Apr 5, 2026
Merged

fix: 9 HIGH-severity tranche/insurance security fixes#98
dcccrypto merged 1 commit into
masterfrom
fix/stake-security-batch-2

Conversation

@dcccrypto

@dcccrypto dcccrypto commented Apr 5, 2026

Copy link
Copy Markdown
Owner

Summary

Implements 9 HIGH-severity security fixes identified during comprehensive PR review. These address vulnerabilities in the tranche system, insurance accounting, and admin withdrawal paths.

Fixes included:

Test results

  • cargo check: clean
  • cargo test: 57 passed, 0 failed
  • No IDL changes

Security review

All fixes passed two rounds of security review. Original PRs from 0x-SquidSol — reimplemented here to resolve merge conflicts.

Closes #46, #58, #69, #70, #73, #77, #85, #86, #92

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Enhanced deposit security by strengthening tranche-mixing prevention
    • Improved withdrawal valuation accuracy for junior and senior tranches
    • Fixed insurance balance accounting and added pool mode validation
    • Added vault address verification for insurance operations
    • Refined fee accrual logic with LP supply guards and improved tranche fee distribution
    • Corrected junior deposit LP pricing calculations

…PR#85)

PR#46 (CVSS 7.5) — Tranche anti-mixing bypass: remove lp_amount > 0 from
  senior guard (deposit._reserved[8] == 1 check now unconditional) and
  switch junior guard to use is_initialized instead of lp_amount > 0.
  Attacker could: deposit junior -> withdraw all -> deposit senior into
  same PDA -> withdraw at junior rates. Now blocked regardless of LP balance.

PR#70 (CVSS 8.1) — Senior withdrawal wrong formula: when tranche_enabled()
  and !is_junior, now calls calc_senior_collateral_for_withdraw against
  senior sub-pool (senior_lp, senior_bal) instead of the global pool formula.
  Prevents senior holders extracting junior-backed collateral.

PR#73 (CVSS 6.5) — Junior fee multiplier non-functional: AccrueFees now
  calls distribute_fees() when tranche_enabled() and junior_total_lp() > 0,
  crediting junior_balance with its weighted share of fee_delta. Previously
  all fees went to senior because distribute_fees was never invoked.

PR#85 (CVSS 7.5) — Pre-deposit dust attack bricks pool: add
  pool.total_lp_supply > 0 guard to the fee accrual condition. Without it,
  sending 1 token to the vault before the first deposit sets total_fees_earned
  > 0 while total_lp_supply == 0, permanently blocking all future deposits.

PR#77 (CVSS 7.5) — Junior withdrawal missing loss absorption: add
  effective_junior_balance() to state.rs (applies distribute_loss against
  outstanding net_loss = total_flushed - total_returned) and use it in
  the withdrawal path instead of raw junior_balance(). Also fixes
  senior_balance() to derive from effective_junior_balance(). Junior holders
  now receive reduced payout that correctly reflects absorbed insurance losses.

Fixes: CVSS 8.1, 7.5, 7.5, 7.5, 6.5 — all HIGH severity.
Tests: 57 passed, 0 failed. Cargo check: clean.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@dcccrypto
dcccrypto merged commit b1f14d2 into master Apr 5, 2026
@coderabbitai

coderabbitai Bot commented Apr 5, 2026

Copy link
Copy Markdown

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ce0dad37-6b16-4c30-8927-27edc352bf1a

📥 Commits

Reviewing files that changed from the base of the PR and between c4b6852 and ef30f81.

📒 Files selected for processing (2)
  • src/processor.rs
  • src/state.rs

📝 Walkthrough

Walkthrough

This pull request modifies deposit, withdrawal, insurance, and fee-handling instruction processors in src/processor.rs and introduces a loss-adjusted junior balance calculation in src/state.rs. Changes include deposit PDA tranche-mixing prevention, withdrawal valuation using loss-adjusted balances, insurance accounting updates, fee accrual guards, and a new pool state method to compute junior balance net of unreturned insurance losses.

Changes

Cohort / File(s) Summary
Deposit PDA Tranche-Mixing Prevention & LP Pricing
src/processor.rs (process_deposit, process_deposit_junior)
process_deposit now rejects all senior deposits into junior-flagged PDAs unconditionally. process_deposit_junior rejects senior deposits into already-initialized PDAs. Both changes remove reliance on LP balance checks. process_deposit_junior also switches to effective_junior_balance() for LP-to-mint calculation.
Withdrawal Valuation
src/processor.rs (process_withdraw)
Junior withdrawals now use effective_junior_balance() instead of raw junior balance. Senior withdrawals when tranches are enabled are valued against senior sub-pool only via calc_senior_collateral_for_withdraw(). Non-tranche withdrawals remain valued against global pool.
Insurance & Vault Management
src/processor.rs (process_flush_to_insurance, process_admin_withdraw_insurance)
process_flush_to_insurance adds pool-mode validation and updates available vault balance computation to include total_returned. process_admin_withdraw_insurance validates that provided vault key matches the pool's stored vault address.
Fee Accrual & Tranche Distribution
src/processor.rs (process_accrue_fees)
Accrual now requires both current_balance > pool_value and pool.total_lp_supply > 0. When tranches are active and junior LP exists, fees are distributed between junior and senior sub-pools via distribute_fees(), with junior balance share adjusted accordingly.
Pool State Loss Adjustment
src/state.rs
New public method effective_junior_balance() computes junior balance net of unreturned insurance losses using distribute_loss(). Updated senior_balance() uses effective_junior_balance() instead of raw junior_balance() when subtracting from total pool value.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 Deposits now stand proud, each in their rightful lane,
No mixing tranches, no clever bypass game!
With losses dispersed and fees justly shared,
The pool runs truer, with safeguards prepared.

✨ 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 fix/stake-security-batch-2

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.

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