Skip to content

feat: magic fee vault as vault on ER for receiving payments#149

Merged
taco-paco merged 8 commits intomainfrom
feat/magic-fee-vault
Mar 16, 2026
Merged

feat: magic fee vault as vault on ER for receiving payments#149
taco-paco merged 8 commits intomainfrom
feat/magic-fee-vault

Conversation

@taco-paco
Copy link
Contributor

@taco-paco taco-paco commented Mar 12, 2026

⚠️ NOTE: Use notes like this to emphasize something important about the PR.

This could include other PRs this PR is built on top of; API breaking changes; reasons for why the PR is on hold; or anything else you would like to draw attention to.

Status Type ⚠️ Core Change Issue
Ready Feature Yes Link

Problem

What problem are you trying to solve?

Solution

How did you solve the problem?
On ER we need to receive payments for Intent scheduling. With this on startup validator needs to make sure that vault exists and delegated, otherwise do it. If that is not done commits and undelegations would get rejected

Before & After Screenshots

Insert screenshots of example code output

BEFORE:
[insert screenshot here]

AFTER:
[insert screenshot here]

Other changes (e.g. bug fixes, small refactors)

Deploy Notes

Notes regarding deployment of the contained body of work. These should note any
new dependencies, new scripts, etc.

New scripts:

  • script : script details

New dependencies:

  • dependency : dependency details

Summary by CodeRabbit

  • New Features

    • Added Magic Fee Vault initialization and delegation flows for validators (on-chain support for creating and delegating vaults).
  • API

    • Added client-side instructions and PDA utilities to initialize and delegate Magic Fee Vaults.
  • Tests

    • Added comprehensive Rust and JS integration tests covering init and delegation flows.
    • Adjusted compute unit expectation in an existing test.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 12, 2026

📝 Walkthrough

Walkthrough

Adds Magic Fee Vault support across the codebase: two new DlpDiscriminator variants (InitMagicFeeVault = 24, DelegateMagicFeeVault = 25); new processor handlers process_init_magic_fee_vault and process_delegate_magic_fee_vault with corresponding modules; PDA helpers (constant tag, macro, PDA function) for magic fee vaults; dlp-api instruction builders for init and delegate flows; Rust unit tests and TypeScript integration tests exercising init/delegate success and failure cases. One test's compute-unit expectation was increased.

Suggested reviewers

  • snawaz
  • GabrielePicco
🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main feature: introducing a magic fee vault for receiving payments on ER (likely Execution Runtime).
Description check ✅ Passed The description provides the Problem (payments needed for Intent scheduling), Solution (vault creation and delegation), and Status table, though some template sections remain as placeholders.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/magic-fee-vault
📝 Coding Plan
  • Generate coding plan for human review comments

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.

Tip

You can validate your CodeRabbit configuration file in your editor.

If your editor has YAML language server, you can enable auto-completion and validation by adding # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json at the top of your CodeRabbit configuration file.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@tests/test_delegate_magic_fee_vault.rs`:
- Around line 84-156: The wrong-validator test creates new PDAs for the wrong
validator instead of calling delegate_magic_fee_vault against the
already-initialized vault, and it only asserts "any error"; update
test_delegate_magic_fee_vault_fails_with_wrong_validator to reuse the existing
vault/accounts created by setup_vault (i.e., pass the same validator-owned
PDA/account pubkeys that setup_vault initialized) but sign the tx with
wrong_validator, then assert the specific InstructionError/program error
returned (unwrap_err and match the InstructionError or program-specific custom
error you expect) rather than assert!(res.is_err()).

In `@tests/test_init_magic_fee_vault.rs`:
- Around line 57-75: Update the assertion in
test_init_magic_fee_vault_fails_without_validator_fees_vault to verify the
specific program error instead of just assert!(res.is_err()); after
banks.process_transaction(tx).await unwrap the Err to an InstructionError (or to
a TransportError then downcast) and assert it equals the expected custom program
error returned by your program (use the error enum/variant from your crate, e.g.
compare to dlp::error::YourProgramError::MissingValidatorFeesVault or the
corresponding InstructionError::Custom(code)); locate the test function and the
init_magic_fee_vault call to change the assertion accordingly and replace the
placeholder variant with the actual error variant/code from your program.
🪄 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: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 166d9e24-a260-42d1-bc0a-52d03974c9dd

📥 Commits

Reviewing files that changed from the base of the PR and between 95ca88d and cd494df.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (13)
  • Cargo.toml
  • src/discriminator.rs
  • src/instruction_builder/delegate_magic_fee_vault.rs
  • src/instruction_builder/init_magic_fee_vault.rs
  • src/instruction_builder/mod.rs
  • src/lib.rs
  • src/pda.rs
  • src/processor/delegate_magic_fee_vault.rs
  • src/processor/init_magic_fee_vault.rs
  • src/processor/mod.rs
  • tests/test_commit_finalize.rs
  • tests/test_delegate_magic_fee_vault.rs
  • tests/test_init_magic_fee_vault.rs

Copy link
Contributor

@GabrielePicco GabrielePicco left a comment

Choose a reason for hiding this comment

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

LGTM!
Please let's also add an integration tests, so that we can use it to intialize/delegate the vaults for the existing validators

# Conflicts:
#	Cargo.toml
#	dlp-api/src/instruction_builder/delegate_magic_fee_vault.rs
#	dlp-api/src/instruction_builder/init_magic_fee_vault.rs
#	dlp-api/src/instruction_builder/mod.rs
#	src/discriminator.rs
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
tests/test_init_magic_fee_vault.rs (1)

57-75: ⚠️ Potential issue | 🟡 Minor

Assert the exact program error, not just is_err().

Line 74 currently passes on any transaction failure, so unrelated regressions can be misclassified as the expected guard failure.

Suggested tightening
-    let res = banks.process_transaction(tx).await;
-    assert!(res.is_err());
+    let err = banks.process_transaction(tx).await.unwrap_err();
+    // Assert the precise custom error returned when validator fees vault is missing.
+    // Replace `EXPECTED_ERROR_CODE` with the actual program error code/variant.
+    assert!(matches!(
+        err,
+        solana_sdk::transport::TransportError::TransactionError(
+            solana_sdk::transaction::TransactionError::InstructionError(
+                _,
+                solana_sdk::instruction::InstructionError::Custom(code)
+            )
+        ) if code == EXPECTED_ERROR_CODE
+    ));
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/test_init_magic_fee_vault.rs` around lines 57 - 75, The test
test_init_magic_fee_vault_fails_without_validator_fees_vault should assert the
exact program error instead of just res.is_err(); update the assertion to unwrap
the transaction error and match it against the specific program error returned
by your program (e.g., convert your custom error enum variant like
dlp_api::error::DlpError::MissingValidatorFeesVault to the program error code
and assert TransactionError::InstructionError(_, InstructionError::Custom(code))
or use assert_matches! to compare to that exact variant); modify the assertion
in the test to check for that specific error rather than a general is_err().
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@tests/test_delegate_magic_fee_vault.rs`:
- Around line 83-101: The tests
test_delegate_magic_fee_vault_fails_without_fees_vault and
test_delegate_magic_fee_vault_fails_without_magic_fee_vault should assert the
specific transaction/InstructionError rather than only checking is_err(); update
each to call let err = res.unwrap_err() and assert that err matches
solana_sdk::transaction::TransactionError::InstructionError(0,
solana_program::instruction::InstructionError::InvalidAccountData) (or the
correct InstructionError your program returns) using matches! with a clear
failure message so the test verifies the exact expected rejection for the
dlp_api::instruction_builder::delegate_magic_fee_vault invocation.

---

Duplicate comments:
In `@tests/test_init_magic_fee_vault.rs`:
- Around line 57-75: The test
test_init_magic_fee_vault_fails_without_validator_fees_vault should assert the
exact program error instead of just res.is_err(); update the assertion to unwrap
the transaction error and match it against the specific program error returned
by your program (e.g., convert your custom error enum variant like
dlp_api::error::DlpError::MissingValidatorFeesVault to the program error code
and assert TransactionError::InstructionError(_, InstructionError::Custom(code))
or use assert_matches! to compare to that exact variant); modify the assertion
in the test to check for that specific error rather than a general is_err().
🪄 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: 3e651b27-df2d-4515-ae92-7050ebd9b017

📥 Commits

Reviewing files that changed from the base of the PR and between cd494df and b8bc15c.

📒 Files selected for processing (9)
  • dlp-api/src/instruction_builder/delegate_magic_fee_vault.rs
  • dlp-api/src/instruction_builder/init_magic_fee_vault.rs
  • dlp-api/src/instruction_builder/mod.rs
  • src/discriminator.rs
  • src/lib.rs
  • src/processor/delegate_magic_fee_vault.rs
  • tests/test_commit_finalize.rs
  • tests/test_delegate_magic_fee_vault.rs
  • tests/test_init_magic_fee_vault.rs

@taco-paco
Copy link
Contributor Author

LGTM! Please let's also add an integration tests, so that we can use it to intialize/delegate the vaults for the existing validators

Added. Right now validator checks for vault and tries to create + delegate vault, otherwise we crash

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@tests/integration/tests/test-delegation.ts`:
- Around line 418-423: Replace the manual PDA derivation for delegation metadata
with the SDK helper: instead of calling
web3.PublicKey.findProgramAddressSync(...) to compute delegationMetadata, call
delegationMetadataPdaFromDelegatedAccount(magicFeeVault) (matching how
delegationRecordPdaFromDelegatedAccount(magicFeeVault) is used) and use its
returned public key; update any variable name if needed to delegationMetadata to
keep usages consistent.

In `@tests/test_init_magic_fee_vault.rs`:
- Around line 50-56: The test currently only checks existence of
magic_fee_vault_account; add a stronger assertion that the account's owner
equals the delegation program ID by unwrapping the Option returned by
banks.get_account and asserting its owner field equals DELEGATION_PROGRAM_ID
(use the existing magic_fee_vault_pda_from_validator and magic_fee_vault_account
variables to locate the check and reference the DELEGATION_PROGRAM_ID constant).
🪄 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: 020b06b7-029b-42ff-a698-ed0f71d19318

📥 Commits

Reviewing files that changed from the base of the PR and between b8bc15c and 7315879.

📒 Files selected for processing (2)
  • tests/integration/tests/test-delegation.ts
  • tests/test_init_magic_fee_vault.rs

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
tests/test_delegate_magic_fee_vault.rs (1)

160-191: ⚠️ Potential issue | 🟡 Minor

This still doesn't test “wrong validator against the existing vault.”

delegate_magic_fee_vault(payer, wrong_validator.pubkey()) derives a brand-new fees vault and magic-fee vault from wrong_validator, so this is just another uninitialized-vault failure. If you want the authorization path, build the instruction against the already-initialized PDAs for validator and only swap the validator signer/account to wrong_validator, then assert the specific error.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/test_delegate_magic_fee_vault.rs` around lines 160 - 191, The test
test_delegate_magic_fee_vault_fails_with_wrong_validator is currently deriving
PDAs for wrong_validator (so it tests an uninitialized-vault failure) instead of
exercising the authorization path; change the test to build the
delegate_magic_fee_vault instruction using the already-initialized PDAs created
by setup_vault (derive the fees vault and magic-fee vault from the original
validator/keypair used in setup_vault) but sign/submit the transaction with
wrong_validator as the signer/account, then assert the expected
authorization-specific error (not InvalidAccountOwner) to verify wrong_validator
is rejected when operating on an existing vault.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@tests/integration/tests/test-delegation.ts`:
- Around line 380-454: The tests use payer as the validator which masks bugs;
create a distinct validator Keypair (e.g., const validatorKeypair =
web3.Keypair.generate(); const validator = validatorKeypair.publicKey) and fund
it (airdrop or transfer) before these cases, update references in the
"Initialize magic fee vault" and "Delegate magic fee vault" tests to use that
validator public key (retain magicFeeVaultPda,
validatorFeesVaultPdaFromValidator, delegationRecordPdaFromDelegatedAccount,
etc.), ensure the validator keypair is marked as a signer in the transaction
submission (pass validatorKeypair to the routine that submits signatures via
processInstruction or equivalent) so the tests exercise a real distinct
validator signature rather than relying on payer === validator.

---

Duplicate comments:
In `@tests/test_delegate_magic_fee_vault.rs`:
- Around line 160-191: The test
test_delegate_magic_fee_vault_fails_with_wrong_validator is currently deriving
PDAs for wrong_validator (so it tests an uninitialized-vault failure) instead of
exercising the authorization path; change the test to build the
delegate_magic_fee_vault instruction using the already-initialized PDAs created
by setup_vault (derive the fees vault and magic-fee vault from the original
validator/keypair used in setup_vault) but sign/submit the transaction with
wrong_validator as the signer/account, then assert the expected
authorization-specific error (not InvalidAccountOwner) to verify wrong_validator
is rejected when operating on an existing vault.
🪄 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: 7670cc55-b5f5-4081-9e10-7429d0fa4925

📥 Commits

Reviewing files that changed from the base of the PR and between 7315879 and 2504724.

📒 Files selected for processing (2)
  • tests/integration/tests/test-delegation.ts
  • tests/test_delegate_magic_fee_vault.rs

@taco-paco taco-paco merged commit 293e922 into main Mar 16, 2026
4 checks passed
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.

2 participants