Skip to content

fix(stake,v17): pause junior deposits while insurance loss outstanding (#149) — rebased from #150 - #153

Merged
dcccrypto merged 2 commits into
mainfrom
fix/v17-junior-preexisting-loss-rebased
Jun 18, 2026
Merged

fix(stake,v17): pause junior deposits while insurance loss outstanding (#149) — rebased from #150#153
dcccrypto merged 2 commits into
mainfrom
fix/v17-junior-preexisting-loss-rebased

Conversation

@dcccrypto

Copy link
Copy Markdown
Owner

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 main

process_deposit_junior has no guard against total_flushed > total_returned. effective_junior_balance() applies the pool's current net_loss to 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 keeps pre_accrue_mode1 and inserts the InsuranceLossOutstanding gate 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 was NoPendingAdmin = 23).
  • Backfilled the error-codes test to enumerate 22/23/24 (22/23 were already missing on main) and bumped the sequential check to 0..24.

Verified locally (against the v17 engine)

cargo test: lib 120, poc_junior_preexisting_loss 2, error_codes 3, unit 59 — all pass. cargo build-sbf clean.

Supersedes #150. Closes #149.

0x-SquidSol and others added 2 commits June 18, 2026 20:58
…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>
@coderabbitai

coderabbitai Bot commented Jun 18, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@dcccrypto, we couldn't start this review because you've reached your PR review rate limit.

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 @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

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 configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f562aef1-9706-4181-9471-5363bab50b40

📥 Commits

Reviewing files that changed from the base of the PR and between 4a2fa7e and faa88b5.

📒 Files selected for processing (4)
  • src/error.rs
  • src/processor.rs
  • tests/error_codes.rs
  • tests/poc_junior_preexisting_loss.rs
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/v17-junior-preexisting-loss-rebased

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.

First junior depositor inherits a pre-existing insurance loss (loss-inheritance side of #145; deterministic loss to honest depositors)

2 participants