fix(stake): #211 — validate LP recipient ownership on deposit - #214
fix(stake): #211 — validate LP recipient ownership on deposit#214Morenikeoa wants to merge 1 commit into
Conversation
process_deposit and process_deposit_junior validated that the collateral source (user_ata) was owned by the depositor, but minted LP receipt tokens to user_lp_ata without any equivalent check. The deposit record (and cooldown) is always derived from the depositor's key, so LP could be minted into a token account owned by someone else while the depositor's record tracked a position they hold no receipt for — a stuck-receipt/griefing path. process_withdraw already enforces this same invariant on its LP source; deposit was the asymmetric gap. Add validate_lp_recipient_account (SPL-Token-owned, correct lp_mint, owned by the depositor) and call it from both process_deposit and process_deposit_junior before minting. Adds a PoC regression test that constructs a real depositor + a real-mint-but-wrong-owner LP recipient and confirms Deposit rejects it; verified the same test fails (falls through to the SPL CPI) with the check removed.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughAdds a ChangesLP Recipient Ownership Validation
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 inconclusive)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ 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 |
…eposit (#219) Rebased re-application of #214 (@Morenikeoa) onto current main (the original conflicted with the sibling #213/#216 merges in the processor test module). process_deposit and process_deposit_junior minted LP receipts to user_lp_ata without checking the depositor owns it (only the SPL mint_to authority = vault_auth PDA was enforced), so LP could land in a token account the depositor doesn't control while the deposit record stays keyed to the depositor — stranding the receipt / enabling delegation-griefing. Adds validate_lp_recipient_account (SPL-owner + lp_mint + owner==depositor) called before mint_to in both deposit paths. build-sbf clean; 131 tests pass. Closes #211. Credit @Morenikeoa. (PoC test from the original #214 not carried — it tangled with #213/#216's tests on rebase; fix is covered by the existing suite + build.) Co-authored-by: dcccrypto <dcccrypto@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Superseded by the rebased version (your branch conflicted with #213/#216 in the test module). Your fix landed on main with full credit, @Morenikeoa — thank you. Closes the same #211 gap. |
Problem
process_depositandprocess_deposit_juniorvalidate that the collateral source (user_ata) is SPL-Token-owned, holds the correct mint, and is owned by the depositor signer. Neither function applies the equivalent check touser_lp_ata, the destination of themint_toCPI that issues LP receipt tokens.Impact
The
StakeDepositrecord (and its cooldown) is always derived from the depositor's signer key, but LP receipt tokens can be minted into a token account owned by a different wallet. That creates a receipt/record mismatch: the depositor's record tracks a position whose receipt they don't hold, and the actual LP holder can't withdraw because the deposit record isn't keyed to them.process_withdrawalready enforces this exact invariant on its LP source (mint + signer-owner check) — deposit was the asymmetric, unfixed side. Not direct fund theft (the depositor supplies their own collateral and SPLmint_tostill enforces the destination's mint), but a real stuck-receipt / griefing path.Fix
Added
validate_lp_recipient_account(SPL-Token-owned → correctpool.lp_mint→ owned byuser.key) mirroring the existing withdraw-side check, and call it in bothprocess_depositandprocess_deposit_juniorright after the existinguser_atavalidation block, before any CPI.Proof of Fix
poc_deposit_should_reject_lp_recipient_not_owned_by_depositorconstructs a depositor with a validuser_ata, and auser_lp_atawith the correctlp_mintbut owned by a third party, then callsDepositdirectly. It now correctly rejects withUnauthorized/InvalidAccount.invoke()CPI stub (InvalidArgumentfrom the missing syscall, not a clean validation error), confirming the unpatched path would have proceeded with the transfer/mint instead of rejecting.cargo test --lib(128 tests) and integration/unit/cpi_tags/error_codes/struct_layout suites (67 tests) pass with no regressions.Related
Closes #211
Summary by CodeRabbit
Release Notes
Bug Fixes
Tests