fix(stake,v17): pause junior deposits while insurance loss outstanding (#149) — rebased from #150 - #153
Conversation
…tanding (#149) effective_junior_balance() applies the pool's CURRENT net_loss to the junior tranche with no baseline for when the cohort began. So a junior depositing into a pool that already has an outstanding loss (total_flushed > total_returned) — borne by the global/senior cohort — instantly inherits that pre-existing loss, making the incumbents whole at the new junior's expense (PoC: Greg deposits 3M, admin flushes 600k; Jane deposits 1M as first junior and is immediately worth 400k; Greg recovers his full 3M). Gate process_deposit_junior to reject (StakeError::InsuranceLossOutstanding) while total_flushed > total_returned. Both this loss-inheritance AND the mirror recovery-snipe (#145) require a junior deposit during an outstanding loss, so this one gate closes both. Junior-only: a senior deposit prices against the current marked-down senior_balance and never perturbs effective_junior_balance, so it neither inherits a loss nor needs gating. Mode-1 is unaffected (flush is mode-0 only, so the condition is never true there). Deposits resume once insurance is returned (total_flushed/returned move only via admin Flush/Return, so no unprivileged DoS). Considered but rejected for THIS fix: a per-cohort loss-baseline snapshot (keeps the junior tranche open + fairly priced during a loss). More flexible, but it rewrites the audited effective_junior_balance loss math and adds StakePool state + cohort bookkeeping — wrong risk profile for a security fix. Recommended as a follow-up feature if continuous junior subscriptions during a claim are wanted. Adds tests/poc_junior_preexisting_loss.rs: documents the loss-reassignment math and pins the gate condition (fires while outstanding, lifts on full return). The handler revert is covered by the v17 LiteSVM e2e. cargo build --lib + cargo build-sbf clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…23) for #150 rebase Adds StakeError::InsuranceLossOutstanding (24) to both error_codes test arrays. Also backfills ZeroSharesMinted (22) + NoPendingAdmin (23), which were already missing from the enumeration on main, and bumps the sequential check to 0..24 so test_all_error_codes_unique stays complete. Rebase-completion for #150 (authored by 0x-SquidSol): the gate was re-applied AFTER pre_accrue_mode1 (PR #148) so the JIT fee-snipe guard stays intact. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Warning Review limit reached
More reviews will be available in 4 minutes and 55 seconds. Learn how PR review limits work. Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file). ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits. 🚦 How do rate limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan refill rate. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, the refill rate gradually slows as usage increases. The highest same-day bursts are limited more strictly. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (4)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
Rebased + verified version of #150 (authored by @0x-SquidSol — commit authorship preserved in history; finding/reporting credit for #149 stands). Opened fresh because #150's fork branch couldn't be force-updated from here.
Verified real on v17
mainprocess_deposit_juniorhas no guard againsttotal_flushed > total_returned.effective_junior_balance()applies the pool's currentnet_lossto the junior tranche with no cohort baseline, so the first junior depositor inherits a pre-existing insurance loss (deterministic value transfer to incumbents). Conservation holds globally, so no runtime check fires. Gate condition is unprivileged-DoS-safe (only admin Flush/Return move those counters).Conflict resolution (the important bit)
#150 was branched before #148 merged. #148 added
pre_accrue_mode1(pool, vault)?(the JIT fee-snipe guard) in the same region. This rebase keepspre_accrue_mode1and inserts theInsuranceLossOutstandinggate immediately AFTER it — so #148's guard stays intact (a naive resolve that dropped it would re-open #146/#148).Also
InsuranceLossOutstanding = 24(no collision; last wasNoPendingAdmin = 23).0..24.Verified locally (against the v17 engine)
cargo test: lib 120,poc_junior_preexisting_loss2,error_codes3, unit 59 — all pass.cargo build-sbfclean.Supersedes #150. Closes #149.