Skip to content

feat: auto-undelegate owner-program requests during finalize#184

Closed
snawaz wants to merge 7 commits into
snawaz/request-undelegationfrom
snawaz/auto-undelegate
Closed

feat: auto-undelegate owner-program requests during finalize#184
snawaz wants to merge 7 commits into
snawaz/request-undelegationfrom
snawaz/auto-undelegate

Conversation

@snawaz

@snawaz snawaz commented Jun 29, 2026

Copy link
Copy Markdown
Collaborator
  • added owner-program requested undelegation with auto-undelegation during finalize/commit-finalize using DelegationMetadata::undelegation_requester to trigger the flow and close the request/delegation PDAs.

  • enforced (and documented) the shared rent payer invariant for owner-program requests so validators can fetch one account only (metadata) instead of two accounts, derive the request PDA, and avoid fetching UndelegationRequest (which wont exist for 99.999% cases) during every finalize.

Summary by CodeRabbit

  • New Features

    • Added support for automatic undelegation during finalize and commit-finalize flows.
    • Finalize and undelegation requests now work with additional account handling for rent reimbursement and owner-program paths.
  • Bug Fixes

    • Improved undelegation request validation and rejection behavior for conflicting requests.
    • Finalize/undelegate flows now handle previously pending undelegation requests more reliably.
  • Tests

    • Updated and expanded coverage for finalize, commit-finalize, undelegation, and lamport settlement scenarios.
    • Adjusted compute-unit expectations to match the new behavior.

snawaz commented Jun 29, 2026

Copy link
Copy Markdown
Collaborator Author

@coderabbitai

coderabbitai Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@snawaz, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 59 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

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 reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

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, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 16319fd5-6031-445d-85f4-4b654adcf280

📥 Commits

Reviewing files that changed from the base of the PR and between 7b7c5b0 and 72af1c7.

📒 Files selected for processing (25)
  • dlp-api/src/instruction_builder/commit_finalize.rs
  • dlp-api/src/instruction_builder/commit_finalize_from_buffer.rs
  • dlp-api/src/instruction_builder/finalize.rs
  • dlp-api/src/state/undelegation_request.rs
  • src/processor/fast/commit_finalize.rs
  • src/processor/fast/commit_finalize_from_buffer.rs
  • src/processor/fast/commit_state.rs
  • src/processor/fast/finalize.rs
  • src/processor/fast/internal/commit_finalize_internal.rs
  • src/processor/fast/internal/mod.rs
  • src/processor/fast/internal/undelegate_internal.rs
  • src/processor/fast/request_undelegation.rs
  • src/processor/fast/undelegate.rs
  • src/processor/fast/undelegate_confined_account.rs
  • tests/integration/tests/test-delegation.ts
  • tests/test_call_handler.rs
  • tests/test_call_handler_v2.rs
  • tests/test_commit_finalize.rs
  • tests/test_commit_finalize_from_buffer.rs
  • tests/test_commit_undelegate_zero_lamports_system_owned.rs
  • tests/test_finalize.rs
  • tests/test_lamports_settlement.rs
  • tests/test_request_undelegation.rs
  • tests/test_undelegate.rs
  • tests/test_undelegate_with_rollback_after_timeout.rs
📝 Walkthrough

Walkthrough

This PR adds auto-undelegation support to finalize and commit_finalize, including optional auto-undelegation account parsing in the fast-path processors and a shared undelegation implementation. The finalize, commit_finalize, and commit_finalize_from_buffer instruction builders now accept owner_program and rent_reimbursement and derive additional undelegation-related PDAs. request_undelegation now uses DelegationMetadata directly and writes back undelegation_requester state with rent-payer validation. Tests were updated for the new instruction signatures and the auto-undelegation flows.

Suggested reviewers

  • GabrielePicco
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch snawaz/auto-undelegate

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
tests/test_lamports_settlement.rs (1)

1043-1057: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Thread the actual rent reimbursement account through these finalize helpers.

Line 1056 and Line 1284 still hardcode args.authority.pubkey() into the new rent_reimbursement slot. In the same file, the direct commit_finalize calls pass payer.pubkey() as reimbursement, and the undelegation path validates that this account matches delegation_metadata.rent_payer. These helpers will build the wrong finalize instruction for any path that exercises auto-undelegation or reimbursement validation.

Suggested fix
 struct FinalizeNewStateArgs<'a> {
     banks: &'a mut BanksClient,
     authority: &'a Keypair,
     blockhash: Hash,
     delegated_account: Pubkey,
     owner_program: Pubkey,
+    rent_reimbursement: Pubkey,
 }
 
 async fn finalize_new_state(args: FinalizeNewStateArgs<'_>) {
     let ix = dlp_api::instruction_builder::finalize(
         args.authority.pubkey(),
         args.delegated_account,
         args.owner_program,
-        args.authority.pubkey(),
+        args.rent_reimbursement,
     );
     // ...
 }
 
 struct FinalizeWithFeePayerArgs<'a> {
     banks: &'a mut BanksClient,
     authority: &'a Keypair,
     fee_payer: &'a Keypair,
     label: &'a str,
     delegated_account: Pubkey,
     owner_program: Pubkey,
+    rent_reimbursement: Pubkey,
 }
 
 async fn finalize_with_fee_payer(args: FinalizeWithFeePayerArgs<'_>) {
     let ix = dlp_api::instruction_builder::finalize(
         args.authority.pubkey(),
         args.delegated_account,
         args.owner_program,
-        args.authority.pubkey(),
+        args.rent_reimbursement,
     );
     // ...
 }

Also applies to: 1270-1286

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_lamports_settlement.rs` around lines 1043 - 1057, The finalize
helper paths are still hardcoding the reimbursement account to the authority
key, which breaks auto-undelegation and rent_payer validation. Update the
finalize instruction construction in finalize_new_state and the related helper
used by commit_finalize so the actual rent reimbursement account is threaded
through as an argument, and use that value instead of args.authority.pubkey()
when populating the rent_reimbursement slot.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/processor/fast/internal/undelegate_internal.rs`:
- Around line 461-467: Use checked arithmetic for the cleanup fee calculation in
undelegate_internal::undelegate_internal. `commit_fee` is already guarded with
`checked_mul`, but the later `commit_fee + SESSION_FEE_LAMPORTS` and the
combined lamport total can still overflow before the `min(...)` logic, so
replace those additions with checked/saturating handling that returns
`DlpError::Overflow` on failure. Keep the fix localized around
`total_fee_requested` and `total_lamports` so the fee/reimbursement split
remains correct.

In `@src/processor/fast/undelegate.rs`:
- Around line 100-105: The idempotent fast-path in undelegate_account is too
broad because it returns Ok(()) whenever delegated_account.owner() matches
owner_program.address(), which can incorrectly treat a still-delegated account
owned by crate::fast::ID as already undelegated. Update the check in
undelegate_account so it only short-circuits after confirming the current owner
is not the DLP program, keeping the existing validation path for accounts still
owned by crate::fast::ID.

---

Outside diff comments:
In `@tests/test_lamports_settlement.rs`:
- Around line 1043-1057: The finalize helper paths are still hardcoding the
reimbursement account to the authority key, which breaks auto-undelegation and
rent_payer validation. Update the finalize instruction construction in
finalize_new_state and the related helper used by commit_finalize so the actual
rent reimbursement account is threaded through as an argument, and use that
value instead of args.authority.pubkey() when populating the rent_reimbursement
slot.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: b565f45f-962f-4564-a6a7-9825ec228013

📥 Commits

Reviewing files that changed from the base of the PR and between ac3af3b and c393b6f.

📒 Files selected for processing (23)
  • dlp-api/src/instruction_builder/commit_finalize.rs
  • dlp-api/src/instruction_builder/commit_finalize_from_buffer.rs
  • dlp-api/src/instruction_builder/finalize.rs
  • src/processor/fast/commit_finalize.rs
  • src/processor/fast/commit_finalize_from_buffer.rs
  • src/processor/fast/commit_state.rs
  • src/processor/fast/finalize.rs
  • src/processor/fast/internal/commit_finalize_internal.rs
  • src/processor/fast/internal/mod.rs
  • src/processor/fast/internal/undelegate_internal.rs
  • src/processor/fast/request_undelegation.rs
  • src/processor/fast/undelegate.rs
  • src/processor/fast/undelegate_confined_account.rs
  • tests/test_call_handler.rs
  • tests/test_call_handler_v2.rs
  • tests/test_commit_finalize.rs
  • tests/test_commit_finalize_from_buffer.rs
  • tests/test_commit_undelegate_zero_lamports_system_owned.rs
  • tests/test_finalize.rs
  • tests/test_lamports_settlement.rs
  • tests/test_request_undelegation.rs
  • tests/test_undelegate.rs
  • tests/test_undelegate_with_rollback_after_timeout.rs

Comment thread src/processor/fast/internal/undelegate_internal.rs
Comment thread src/processor/fast/undelegate.rs Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/processor/fast/request_undelegation.rs (1)

93-105: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Backfill undelegation_requester when reusing an existing request.

Lines 158-198 only revalidate the existing PDA; they never mirror the creation-path write from Lines 137-142. That leaves preexisting requests with DelegationMetadata.undelegation_requester == None, and process_auto_undelegation_if_requested() in src/processor/fast/internal/undelegate_internal.rs exits early unless the requester is OwnerProgram, so finalize will never auto-undelegate those already-open requests even after a retry. Lines 100-105 also pin retries to DelegationMetadata::rent_payer, so some legacy requests cannot use this path to repair themselves. Please persist OwnerProgram here too, or add an explicit migration/compatibility path for existing requests.

Also applies to: 158-198

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/processor/fast/request_undelegation.rs` around lines 93 - 105, Backfill
the missing undelegation requester when reusing an existing request: the retry
path in request_undelegation should mirror the creation-path write to
DelegationMetadata.undelegation_requester instead of only revalidating the PDA.
Update the existing-request branch in request_undelegation to persist
OwnerProgram on the loaded DelegationMetadata (the same symbol used in the
create flow), or add a compatibility/migration branch for legacy records so
process_auto_undelegation_if_requested can proceed for preexisting requests.
Ensure the rent_payer revalidation stays intact while allowing old requests to
be repaired.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@src/processor/fast/request_undelegation.rs`:
- Around line 93-105: Backfill the missing undelegation requester when reusing
an existing request: the retry path in request_undelegation should mirror the
creation-path write to DelegationMetadata.undelegation_requester instead of only
revalidating the PDA. Update the existing-request branch in request_undelegation
to persist OwnerProgram on the loaded DelegationMetadata (the same symbol used
in the create flow), or add a compatibility/migration branch for legacy records
so process_auto_undelegation_if_requested can proceed for preexisting requests.
Ensure the rent_payer revalidation stays intact while allowing old requests to
be repaired.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: a6f63787-378f-4bc7-8494-c10b60c65e18

📥 Commits

Reviewing files that changed from the base of the PR and between c393b6f and 5894b5e.

📒 Files selected for processing (3)
  • dlp-api/src/state/undelegation_request.rs
  • src/processor/fast/internal/undelegate_internal.rs
  • src/processor/fast/request_undelegation.rs

@snawaz snawaz requested a review from GabrielePicco June 30, 2026 07:54
@snawaz snawaz marked this pull request as ready for review June 30, 2026 07:55

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tests/integration/tests/test-delegation.ts`:
- Line 368: The delegation threshold assertion and its failure message are out
of sync: the test currently uses the new 55000 limit but the adjacent
expect/assert message still mentions 18500. Update the message to match the
actual threshold, or better, extract the limit into a shared constant and reuse
it in both the assertion and the message in test-delegation.ts so the check
stays consistent.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 74a19563-70ef-498d-aed0-6e872f149b08

📥 Commits

Reviewing files that changed from the base of the PR and between 5894b5e and 7b7c5b0.

📒 Files selected for processing (2)
  • src/processor/fast/undelegate.rs
  • tests/integration/tests/test-delegation.ts

Comment thread tests/integration/tests/test-delegation.ts
@snawaz snawaz force-pushed the snawaz/auto-undelegate branch from 756805e to 72af1c7 Compare July 3, 2026 10:58
@snawaz

snawaz commented Jul 6, 2026

Copy link
Copy Markdown
Collaborator Author

discarded because the idea of undelegation in finalize step is discarded.

@snawaz snawaz closed this Jul 6, 2026
@snawaz snawaz deleted the snawaz/auto-undelegate branch July 8, 2026 14:12
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