Skip to content

feat: V2 RPC primitives + on-device prepare/sign design doc#348

Open
eldenpark wants to merge 14 commits into
mainfrom
elden/redesign-transfer-2
Open

feat: V2 RPC primitives + on-device prepare/sign design doc#348
eldenpark wants to merge 14 commits into
mainfrom
elden/redesign-transfer-2

Conversation

@eldenpark
Copy link
Copy Markdown
Contributor

@eldenpark eldenpark commented Apr 29, 2026

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)

  • Path-versioned endpoint routing. rpc_endpoint now picks /v1 or /v2
    per RpcMethod; existing methods stay on /v1 unchanged.
  • New RpcMethod variants:
    • PmSponsorUserOperation -> pm_sponsorUserOperation on /v2
    • SendUserOperationV2 -> eth_sendUserOperation on /v2
  • New PmSponsorUserOperationResponse type matching the V2 wire shape,
    plus a From<...> for SponsorUserOperationResponse so V2 results
    can be merged into a UserOperation through the existing signing
    path without duplicating downstream code.
  • New RpcClient methods: pm_sponsor_user_operation and
    send_user_operation_v2.
  • Unit tests for V1/V2 routing and for the response conversion.

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:

  • Trust model: calldata is constructed locally; the user signs only
    payloads the device can independently verify.
  • What this design replaces: 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
    Mermaid sequence diagram and the JSON-RPC wire shapes.
  • Sponsorship decline payload contract (token, paymasterAddress
    required; costNative, costToken advisory and may be absent).
  • Observable error categories and how Bedrock surfaces each.
  • Versioning and compatibility: how the path-versioned endpoint plus
    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.

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 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 PmSponsorUserOperation RPC method + response type, with conversion into the existing SponsorUserOperationResponse flow.
  • Route pm_sponsorUserOperation and eth_sendUserOperation through /v2/rpc.
  • Add sign_and_execute_v2() alongside the existing V1 sign_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.

Comment thread bedrock/src/smart_account/transaction_4337.rs Outdated
Comment thread bedrock/src/transactions/rpc.rs Outdated
Comment thread bedrock/src/transactions/rpc.rs Outdated
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 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".

Comment thread bedrock/src/transactions/rpc.rs Outdated
@eldenpark eldenpark marked this pull request as draft April 30, 2026 19:06
eldenpark added 9 commits May 26, 2026 17:22
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().
@eldenpark eldenpark force-pushed the elden/redesign-transfer-2 branch from 9e64d91 to 34de181 Compare May 27, 2026 00:23
eldenpark added 2 commits May 27, 2026 14:22
* 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.
@eldenpark eldenpark changed the title feat(rpc): add sign_and_execute_v2 for V2 RPC feat: V2 RPC primitives + on-device prepare/sign design doc May 27, 2026
@eldenpark eldenpark requested a review from Copilot May 27, 2026 21:48
@eldenpark eldenpark marked this pull request as ready for review May 27, 2026 21:48
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 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".

Comment thread bedrock/src/transactions/rpc.rs
Comment thread bedrock/src/transactions/rpc.rs Outdated
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 2 out of 2 changed files in this pull request and generated 2 comments.

Comment thread bedrock/src/transactions/rpc.rs Outdated
Comment thread bedrock/src/transactions/rpc.rs
eldenpark added 3 commits May 27, 2026 14:59
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.
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