feat: V2 RPC primitives + on-device prepare/sign design doc#348
feat: V2 RPC primitives + on-device prepare/sign design doc#348eldenpark wants to merge 14 commits into
Conversation
There was a problem hiding this comment.
Pull request overview
Adds Bedrock support for the temporal-apps V2 sponsorship RPC (pm_sponsorUserOperation) and introduces an opt-in V2 execution path for 4337 transactions, while leaving the existing V1 path intact for current UniFFI consumers.
Changes:
- Add
PmSponsorUserOperationRPC method + response type, with conversion into the existingSponsorUserOperationResponseflow. - Route
pm_sponsorUserOperationandeth_sendUserOperationthrough/v2/rpc. - Add
sign_and_execute_v2()alongside the existing V1sign_and_execute()path.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
bedrock/src/transactions/rpc.rs |
Introduces V2 sponsorship RPC method/response and updates method→endpoint version routing. |
bedrock/src/test_utils.rs |
Extends the mocked RPC client to return a V2 pm_sponsorUserOperation-shaped response. |
bedrock/src/smart_account/transaction_4337.rs |
Adds an opt-in sign_and_execute_v2() execution path that uses the V2 sponsorship + send endpoints. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 889cf04c4c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Adds the Bedrock-side plumbing needed to call the new pm_sponsorUserOperation endpoint on temporal-apps (V2) instead of wa_sponsorUserOperation on app-backend-main (V1). New in rpc.rs: - PmSponsorUserOperation RpcMethod variant, routed to /v2/rpc - SendUserOperation also routed to /v2/rpc - PmSponsorUserOperationResponse struct matching the temporal-apps response - From<PmSponsorUserOperationResponse> for SponsorUserOperationResponse to reuse the existing with_paymaster_data() path - pm_sponsor_user_operation() method on RpcClient New in transaction_4337.rs: - sign_and_execute_v2() trait method alongside the existing sign_and_execute() V1 path; callers in mod.rs are untouched so each transaction type can opt in to V2 one at a time in its own PR sign_and_execute() is left unchanged so all existing UniFFI-exported methods continue to use the V1 path until explicitly migrated.
Adds an Anvil-backed integration test that exercises the full V2 execution path: pm_sponsorUserOperation → gas/paymaster merge → sign → eth_sendUserOperation. Asserts a non-zero userOpHash is returned and that the on-chain ERC-20 balance changes, proving the operation actually executed via EntryPoint. Uses the existing AnvilBackedHttpClient mock, which already handles both pm_sponsorUserOperation and eth_sendUserOperation.
Covers that SendUserOperation, PmSponsorUserOperation, and EthCall
resolve to /v2/rpc/{network}, while SponsorUserOperation,
WaGetUserOperationReceipt, and SupportedEntryPoints stay on /v1.
A third test pins the full URL shape to catch network_name regressions.
Covers JSON deserialization of the pm_sponsorUserOperation response shape (both bundler-sponsored and paymaster-sponsored variants) and verifies the From<PmSponsorUserOperationResponse> for SponsorUserOperationResponse mapping — including that paymaster gas limits are wrapped in Some and provider_name is always RpcProviderName::Any.
Routing eth_sendUserOperation to /v2/ broke the staged migration guarantee: sign_and_execute() callers were silently put on a mixed V1-sponsor/V2-submit path. Fix by reverting SendUserOperation to /v1/ and introducing a separate SendUserOperationV2 variant (same wire name, /v2/ routing) used exclusively by send_user_operation_v2() and sign_and_execute_v2().
9e64d91 to
34de181
Compare
* docs: describe the on-device prepare-and-sign flow Add docs/architecture/transactions/prepare_sign_tx.md — a public-facing description of how Bedrock turns a user intent into a signed ERC-4337 UserOperation, intended for external auditors of the wallet's self-custody guarantees. Sections: - Trust model: calldata is constructed locally; the user signs only payloads the device can independently verify. - What this design replaces: a sequenceDiagram of the legacy prepare/send flow where the server encoded calldata and the device signed an opaque hash — the two trust gaps that motivated the redesign. - High-level flow: build callData → wrap in Safe execTransaction → compute userOpHash → sponsor → sign → submit → poll. - Sponsored path and decline → self-sponsored retry, each with a sequenceDiagram and the JSON-RPC wire shapes. - Sponsorship decline payload contract: required token / paymasterAddress fields, optional advisory cost fields the wallet tolerates as absent. - Per-step details and observable error categories. - Versioning and compatibility: path-versioned endpoint, the non-breaking / breaking change distinction, and how Bedrock's FFI versioning decouples consumers from server version changes. The file is intended to be kept up to date as the on-device flow evolves; it documents the wire contract, not internal infrastructure. * Replace ';' w/ ',' as Mermaid treats it as separator
Park the V2 orchestration (sign_and_execute_v2 + integration test) for a follow-up PR. This PR now ships only the V2 RPC primitives in rpc.rs: endpoint routing, pm_sponsorUserOperation types + client method, eth_sendUserOperation V2 variant, unit tests, conversion tests. The orchestration commit and integration test remain on local branch elden/redesign-transfer-2-full for the follow-up.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 93470134b4
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
The v2 endpoint server strictly requires three params for
pm_sponsorUserOperation: [userOperation, entryPoint, context]. The
client was sending only the first two, so every V2 sponsorship call
against the server would return -32602 "Invalid params".
- Add SponsorshipContext enum with Bundler ({}) and
SelfSponsoredToken(Address) ({ "token": "0x..." }) variants,
matching the two-mode protocol documented in
docs/architecture/transactions/prepare_sign_tx.md.
- Pass &SponsorshipContext through pm_sponsor_user_operation and
serialize it as the third params element.
- Unit test asserts both variants serialize to the expected JSON.
The parked sign_and_execute_v2 follow-up will pass Bundler on the
initial attempt and SelfSponsoredToken on the decline retry.
The bundler-sponsored pm_sponsorUserOperation response omits paymaster fields entirely (not present-with-zero), and the server recently removed the `mode` field. PmSponsorUserOperationResponse required both, so wallet-sponsored V2 responses fail to deserialize with JsonError and the V2 path is unusable end-to-end. - paymaster_verification_gas_limit / paymaster_post_op_gas_limit are now Option<U128>; None on bundler-sponsored, Some on self-sponsored. - `mode` removed from PmSponsorUserOperationResponse — server no longer sends it. - From<PmSponsorUserOperationResponse> for SponsorUserOperationResponse passes the Option through instead of wrapping in Some. - test_pm_sponsor_response_parsing rewritten with realistic fixtures for both response shapes; new conversion test asserts None-in → None-out so future code can't silently regress to wrapping.
Adds the client-side surface for the V2 RPC endpoints (path prefix
/v2/rpc/) and a public-facing description of how Bedrock
turns a user intent into a signed ERC-4337 UserOperation.
Both pieces are additive: no existing caller is migrated, no V1
behaviour changes. V2 plumbing and docs land first so subsequent
PRs can wire V2 into the on-device transaction flow and individual
transaction types one at a time.
RPC primitives (bedrock/src/transactions/rpc.rs)
per RpcMethod; existing methods stay on /v1 unchanged.
plus a From<...> for SponsorUserOperationResponse so V2 results
can be merged into a UserOperation through the existing signing
path without duplicating downstream code.
send_user_operation_v2.
No RpcClient consumer changes here. sign_and_execute_v2 orchestration
and per-transaction-type opt-in are intentionally left for follow-up
PRs.
Architecture doc (docs/architecture/transactions/prepare_sign_tx.md)
Public-facing description of the on-device prepare-and-sign flow,
intended for external auditors of the wallet's self-custody guarantees:
payloads the device can independently verify.
server encoded calldata and the device signed an opaque hash — the
two trust gaps that motivated the redesign.
compute userOpHash -> sponsor -> sign -> submit -> poll.
Mermaid sequence diagram and the JSON-RPC wire shapes.
required; costNative, costToken advisory and may be absent).
Bedrock's independently versioned FFI surface lets the server roll
forward without breaking already-installed devices.
The doc is a living document — it tracks the wire contract, not
internal infrastructure, so server-side iteration on triggers /
cost advisory / sponsorship policy is expected to refine it over
time without churning the client.