Skip to content

feat(rpc): sign_and_execute_v2 + typed decline parsing#361

Open
eldenpark wants to merge 4 commits into
mainfrom
elden/sign_execute_1
Open

feat(rpc): sign_and_execute_v2 + typed decline parsing#361
eldenpark wants to merge 4 commits into
mainfrom
elden/sign_execute_1

Conversation

@eldenpark
Copy link
Copy Markdown
Contributor

Wires the V2 RPC primitives from #348 into an end-to-end orchestration that transaction types in transactions/mod.rs will opt into to migrate off the legacy V1 sign_and_execute. Happy path only: pm_sponsorUserOperation with SponsorshipContext::Protocol, merge gas (and any paymaster fields) into the UserOp via the new with_sponsorship_data, sign, submit via send_user_operation_v2. V1 sign_and_execute is untouched; no UniFFI export moves yet.

The JSON-RPC layer now preserves the error data field into RpcError::RpcResponseError (as a raw JSON string, kept UniFFI-liftable), and RpcError::as_sponsorship_decline parses the temporal-apps "sponsorship declined" payload (-32602 with token, paymasterAddress, costNative, costToken) into a typed SponsorshipDecline. The retry path — prepending an ERC-20 approve and re-calling with SponsorshipContext::SelfSponsoredToken — lands in the follow-up.

Wires the V2 RPC primitives from #348 into an end-to-end orchestration
that transaction types in transactions/mod.rs will opt into to migrate
off the legacy V1 sign_and_execute. Happy path only:
pm_sponsorUserOperation with SponsorshipContext::Protocol, merge gas
(and any paymaster fields) into the UserOp via the new
with_sponsorship_data, sign, submit via send_user_operation_v2. V1
sign_and_execute is untouched; no UniFFI export moves yet.

The JSON-RPC layer now preserves the error data field into
RpcError::RpcResponseError (as a raw JSON string, kept UniFFI-liftable),
and RpcError::as_sponsorship_decline parses the temporal-apps
"sponsorship declined" payload (-32602 with token, paymasterAddress,
costNative, costToken) into a typed SponsorshipDecline. The retry path
— prepending an ERC-20 approve and re-calling with
SponsorshipContext::SelfSponsoredToken — lands in the follow-up.
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds an end-to-end V2 UserOperation execution path and preserves/decodes structured JSON-RPC error data so Bedrock can recognize (and later retry) protocol sponsorship declines without changing the legacy V1 flow.

Changes:

  • Extend RpcError::RpcResponseError to retain the JSON-RPC error.data field as raw JSON text and add typed parsing via RpcError::as_sponsorship_decline.
  • Introduce sign_and_execute_v2 (happy-path) to request V2 sponsorship, merge sponsorship data into the UserOperation, sign locally, and submit via the V2 RPC path.
  • Add UserOperation::with_sponsorship_data to merge V2 sponsorship response fields (gas always; paymaster fields conditionally).

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

File Description
bedrock/src/transactions/rpc.rs Preserves JSON-RPC error data as a UniFFI-friendly string and adds typed sponsorship-decline parsing + unit tests.
bedrock/src/transactions/custom_bundler.rs Propagates JSON-RPC error data into RpcError for external bundler calls.
bedrock/src/smart_account/transaction_4337.rs Adds sign_and_execute_v2 orchestration and tests around sponsorship-data merging behavior.
bedrock/src/primitives/contracts.rs Adds UserOperation::with_sponsorship_data to apply V2 sponsorship response fields onto a UserOperation.

Comment thread bedrock/src/primitives/contracts.rs Outdated
with_sponsorship_data previously wrote paymaster fields only when the
response carried Some(...), so pre-existing paymaster data on the
input UserOp would survive a protocol-sponsored merge — contradicting
the method's doc and risking an unintended paymaster-backed op on the
sponsored path. Switch to unconditional overwrite (None clears any
prior Some), matching V1 with_paymaster_data so the response is the
single source of truth. Adds a test that pre-populates all four
paymaster fields and asserts they're cleared.
@eldenpark eldenpark requested a review from Copilot June 2, 2026 20:58
@eldenpark eldenpark marked this pull request as ready for review June 2, 2026 20:58
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated no new comments.

// 3. Merge gas (and paymaster fields if any) into the `UserOp`.
// For SponsorshipContext::Protocol the response carries only
// gas fields; paymaster fields stay None.
user_operation = user_operation.with_sponsorship_data(&sponsor_response);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

here we need to return, so the app can display a consent prompt when they need to self-sponsor

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yeap, I'll handle this in the follow-up PR

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.

3 participants