feat: add CloseLamportsPda recovery for stranded sponsored transfers - #139
Conversation
When the post-delegation actions of a SponsoredLamportsTransfer fail on the ER (e.g. a rent-parameter mismatch after a SIMD-0437 step), the validator rescue-undelegates the lamports PDA with the principal still inside and there was no base-layer path to recover it. Add public instruction 33, CloseLamportsPda: a permissionless base-only recovery that refunds everything above the sponsored rent to the payer from the PDA derivation, returns the rent share to the global rent PDA and closes the PDA. Delegated (in-flight) PDAs are rejected by the owner check, and the recipients are bound to the derivation so a caller cannot redirect funds.
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Advanced Run ID: 📒 Files selected for processing (5)
Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review. WalkthroughAdds the ChangesLamports PDA recovery
Priority: ⬇️ Low Estimated code review effort: 3 (Moderate) | ~25 minutes Change: Feature Suggested reviewers: Merge Risk: ⚪ Minimal · up to The recovery instruction validates its canonical accounts and closes the stranded PDA as intended. No actionable merge-blocking risk remains. 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 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 |
Why
When the post-delegation actions of a
SponsoredLamportsTransferfail on the ER (for example when ER and base disagree on rent parameters), the validator rescue-undelegates the lamports PDA on base with the principal still inside. The program had no way to return it: the only close path is the post-undelegate Magic intent, which needs the DLP escrow signer, so the funds stayed locked in the PDA.What
New public instruction 33
CloseLamportsPda, permissionless, base-layer only:payer(w, receives principal),rent_pda(w),lamports_pda(w),destination(derivation only)salt: [u8; 32]balance - min_balance(0)to the payer from the[b"lamports", payer, destination, salt]derivation, returns the rent share to the global rent PDA, closes the accountSafety properties:
validate_rent_pda), so the caller cannot redirect fundspayer == rent_pda(queue-refill PDAs) works: the two credits are applied sequentially on the aliased accountTests: refund + close, delegated PDA rejected, substituted payer rejected. Full
cargo test-sbfsuite passes.Out of scope / follow-ups
close_lamports_pda_intent.rsdoes not bind the escrow authority to the PDA payer, so a foreign program's Magic action could push a rescued PDA's balance into the rent PDA (griefing, not theft). Suggested fix isescrow_authority == payer; separate PR.transfer_lamports_pda.rs:51still requires the ER's own rent minimum; dropping the rent term would prevent the failure mode entirely. Separate PR.