Skip to content

Surface relayer sponsorship signal end-to-end (additive, non-breaking)#1007

Merged
taylanpince merged 3 commits into
masterfrom
matt416/surface-sponsorship-signal
May 29, 2026
Merged

Surface relayer sponsorship signal end-to-end (additive, non-breaking)#1007
taylanpince merged 3 commits into
masterfrom
matt416/surface-sponsorship-signal

Conversation

@matt416
Copy link
Copy Markdown
Contributor

@matt416 matt416 commented May 28, 2026

Summary

Fixes the /FeeOptions misclassification described in our internal bug report: a real subsidy and a swallowed /FeeOptions error currently produce byte-identical option shapes, so any consumer using !feeOption as the sponsorship discriminator labels failed quotes as "free gas". This PR makes the two cases distinguishable end-to-end without breaking any existing consumer.

  • @0xsequence/relayerfeeOptions now forwards the server's sponsored: boolean; both feeOptions and feeTokens mark swallowed errors with failed: true. The Relayer interface and all impls (Rpc, Sequence, Local, EIP6963, Pk) are widened to match.
  • @0xsequence/wallet-wdkStandardRelayerOption gains optional sponsored / failed, populated on both construction branches in transactions.ts; isStandardRelayerOption / isERC4337RelayerOption are now re-exported.
  • @0xsequence/dapp-client — adds DappClient.isSponsored(chainId, txs) (and ChainSessionManager.isSponsored(calls)), which returns true only when the relayer explicitly reports sponsorship.

Downstream consumers should switch sponsorship classification from !feeOption inference to sponsored === true (or isSponsored()) so a real subsidy is no longer indistinguishable from a swallowed error. All three packages get minor changesets — additive types, no behavior change for unchanged code paths.

(Supersedes #1006, which was closed when the branch was renamed.)

Test plan

  • Relayer unit tests: sponsored:true / sponsored:false propagation + failed:true on feeOptions and feeTokens error paths (124/124 vitest passing)
  • WDK integration test: asserts sponsored === false and failed === undefined on the LocalRelayer/PkRelayer path
  • Monorepo typecheck + lint + prettier (pre-commit hook ran clean on every commit)
  • CI: full monorepo test suite incl. anvil-fork-based wallet-core tests (skipped locally — needs pnpm test:anvil)
  • Manual smoke against a consumer app: confirm option.sponsored === true for a genuinely sponsored tx and option.failed === true for a forced /FeeOptions 400 (e.g. Polygon Morpho capped vault, Aave insufficient-balance deposit)

🤖 Generated with Claude Code

matt416 and others added 3 commits May 28, 2026 14:03
`RpcRelayer.feeOptions` now forwards the server's `sponsored: boolean` to
callers, and both `feeOptions` and `feeTokens` mark their swallowed-error
returns with `failed: true`. The `Relayer` interface and all bundled
implementations (Rpc, Sequence, Local, EIP6963, Pk) are widened to match.

Additive change: existing consumers ignoring the new fields are unaffected.
Downstream sponsorship classifiers should switch from `!feeOption` inference
to `sponsored === true` so a real subsidy is no longer indistinguishable
from a swallowed `/FeeOptions` error.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
`StandardRelayerOption` gains optional `sponsored` and `failed` fields,
populated on both construction branches in `transactions.ts` from the
relayer SDK's new `feeOptions` return. `isStandardRelayerOption` /
`isERC4337RelayerOption` are re-exported so consumers can narrow before
reading the new fields.

UI consumers that classified sponsorship by "no fee option attached"
should switch to `sponsored === true` to distinguish a real subsidy from
a swallowed `/FeeOptions` error.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
`DappClient.isSponsored(chainId, transactions)` and
`ChainSessionManager.isSponsored(calls)` return true only when the
relayer's `/FeeOptions` endpoint explicitly reports sponsorship; any
error, network failure, or absence of sponsorship returns false. A true
result is always safe to surface as "free gas" in UI.

Prefer this over inferring sponsorship from an empty `getFeeOptions`
array — a swallowed `/FeeOptions` error produces the same empty shape as
a real subsidy. `getFeeOptions` is unchanged.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@matt416 matt416 requested a review from a team May 28, 2026 19:10
@matt416 matt416 requested a review from a team as a code owner May 28, 2026 19:10
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: 7e34cf7d09

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread packages/wallet/dapp-client/src/DappClient.ts
@taylanpince taylanpince merged commit 55121af into master May 29, 2026
16 checks passed
@taylanpince taylanpince deleted the matt416/surface-sponsorship-signal branch May 29, 2026 07:50
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