0xsequence#1008#653
Conversation
Bumps [next](https://github.com/vercel/next.js) from 15.5.14 to 15.5.15. - [Release notes](https://github.com/vercel/next.js/releases) - [Changelog](https://github.com/vercel/next.js/blob/canary/release.js) - [Commits](vercel/next.js@v15.5.14...v15.5.15) --- updated-dependencies: - dependency-name: next dependency-version: 15.5.15 dependency-type: direct:production ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
#1007) * feat(relayer): propagate sponsored signal and mark swallowed errors `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> * feat(wallet-wdk): carry sponsored/failed on StandardRelayerOption `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> * feat(dapp-client): add isSponsored for explicit sponsorship checks `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> --------- Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Bumps [turbo](https://github.com/vercel/turborepo) from 2.9.8 to 2.9.14. - [Release notes](https://github.com/vercel/turborepo/releases) - [Changelog](https://github.com/vercel/turborepo/blob/main/RELEASE.md) - [Commits](vercel/turborepo@v2.9.8...v2.9.14) --- updated-dependencies: - dependency-name: turbo dependency-version: 2.9.14 dependency-type: direct:development ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
|
|
Review or Edit in CodeSandboxOpen the branch in Web Editor • VS Code • Insiders |
Reviewer's GuideIntroduces explicit sponsorship and failure signalling throughout the relayer fee-options pipeline, adds a dedicated sponsorship check API for dapps, updates wallet fee-option transaction building (including undeployed wallets), extends userdata with active device management, removes several unsupported networks, tightens relayer tests, and bumps various package/tooling versions. Sequence diagram for dapp sponsorship check via relayer feeOptionssequenceDiagram
actor User
participant DappClient
participant ChainSessionManager
participant Wallet
participant Relayer
participant RpcRelayer
participant RelayerClient
User->>DappClient: isSponsored(chainId, transactions)
DappClient->>ChainSessionManager: isSponsored(calls)
ChainSessionManager->>ChainSessionManager: _buildAndSignCalls(callsToSend)
ChainSessionManager->>Wallet: buildFeeOptionsTransaction(provider, payload)
Wallet-->>ChainSessionManager: { to, data }
ChainSessionManager->>Relayer: feeOptions(walletAddress, chainId, to, callsToSend, data)
Relayer->>RpcRelayer: feeOptions(wallet, chainId, to, calls, data)
RpcRelayer->>RelayerClient: feeOptions({ wallet, to, data })
RelayerClient-->>RpcRelayer: FeeOptionsReturn(sponsored, options, quote)
RpcRelayer-->>Relayer: { options, quote, sponsored, failed? }
Relayer-->>ChainSessionManager: { options, quote, sponsored, failed? }
ChainSessionManager-->>DappClient: sponsored === true && !failed
DappClient-->>User: boolean isSponsored
File-Level Changes
Possibly linked issues
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
✅ Snyk checks have passed. No issues have been found so far.
💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse. |
There was a problem hiding this comment.
Hey - I've found 3 issues, and left some high level feedback:
- In
wallet-fee-options.test.ts, consider derivingFEE_OPTIONS_STUB_SIGNATUREvia the samebuildFeeOptionsStubSignaturelogic or a shared helper instead of hardcoding the hex literal, so the test stays aligned if the stub signature encoding ever changes. ChainSessionManager.getFeeOptionsandChainSessionManager.isSponsoredduplicate the same call mapping and_buildAndSignCallslogic; extracting a shared helper for buildingcallsToSendandsignedCallwould reduce drift and make future changes to the signing flow easier to keep consistent.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- In `wallet-fee-options.test.ts`, consider deriving `FEE_OPTIONS_STUB_SIGNATURE` via the same `buildFeeOptionsStubSignature` logic or a shared helper instead of hardcoding the hex literal, so the test stays aligned if the stub signature encoding ever changes.
- `ChainSessionManager.getFeeOptions` and `ChainSessionManager.isSponsored` duplicate the same call mapping and `_buildAndSignCalls` logic; extracting a shared helper for building `callsToSend` and `signedCall` would reduce drift and make future changes to the signing flow easier to keep consistent.
## Individual Comments
### Comment 1
<location path="packages/services/relayer/src/relayer/standard/eip6963.ts" line_range="40" />
<code_context>
calls: Payload.Call[],
- ): Promise<{ options: FeeOption[]; quote?: FeeQuote }> {
+ data?: Hex.Hex,
+ ): Promise<{ options: FeeOption[]; quote?: FeeQuote; sponsored: boolean; failed?: boolean }> {
// IMPORTANT:
// The relayer FeeOptions endpoint simulates `eth_call(to, data)`.
</code_context>
<issue_to_address>
**issue (bug_risk):** Forward the new optional `data` argument through the EIP6963 relayer adapter.
`Relayer.feeOptions` now accepts `data?: Hex.Hex`, but `EIP6963Relayer.feeOptions` still calls `this.relayer.feeOptions(wallet, chainId, to, calls)` and drops `data`. This will break callers that rely on a fully-built transaction (e.g. undeployed wallets where `to`/`data` are significant). Please update the adapter signature to include `data?: Hex.Hex` and forward it to the inner relayer to preserve behavior.
</issue_to_address>
### Comment 2
<location path="packages/services/relayer/src/relayer/standard/pk-relayer.ts" line_range="124" />
<code_context>
calls: Payload.Call[],
- ): Promise<{ options: FeeOption[]; quote?: FeeQuote }> {
+ data?: Hex.Hex,
+ ): Promise<{ options: FeeOption[]; quote?: FeeQuote; sponsored: boolean; failed?: boolean }> {
// IMPORTANT:
// The relayer FeeOptions endpoint simulates `eth_call(to, data)`.
</code_context>
<issue_to_address>
**issue (bug_risk):** Propagate the optional `transactionData`/`data` argument in the PK relayer wrapper.
`PkRelayer.feeOptions` still doesn’t accept or forward the new `data?: Hex.Hex` argument to the inner relayer. If a caller supplies a pre-built transaction payload, this wrapper will ignore it and force the inner relayer to reconstruct `data`, which can change the intended behavior. Please add `data?: Hex.Hex` to the method signature and pass it through to `this.relayer.feeOptions(...)` to match the `Relayer` interface and the other adapters.
</issue_to_address>
### Comment 3
<location path="packages/wallet/dapp-client/src/ChainSessionManager.ts" line_range="890" />
<code_context>
+ * sponsorship all return `false`, so a `true` result is always safe to
+ * surface as "free gas" in UI.
+ */
+ async isSponsored(calls: Transaction[]): Promise<boolean> {
+ const callsToSend = calls.map((tx) => ({
+ to: tx.to,
</code_context>
<issue_to_address>
**issue (complexity):** Consider extracting the common build/sign/cache/relayer-call logic into a shared private helper used by both getFeeOptions and isSponsored.
You can reduce duplication by extracting the shared “build → sign → cache → call relayer” flow into a private helper and reusing it from both `getFeeOptions` and `isSponsored`.
For example:
```ts
private async _fetchFeeOptions(
calls: Transaction[],
): Promise<Awaited<ReturnType<typeof this.relayer.feeOptions>>> {
const callsToSend = calls.map((tx) => ({
to: tx.to,
value: tx.value,
data: tx.data,
gasLimit: tx.gasLimit ?? BigInt(0),
delegateCall: tx.delegateCall ?? false,
onlyFallback: tx.onlyFallback ?? false,
behaviorOnError: tx.behaviorOnError ?? ('revert' as const),
}))
const signedCall = await this._buildAndSignCalls(callsToSend)
const fingerprint = this._fingerprintCalls(callsToSend)
if (fingerprint) {
this.lastSignedCallCache = {
fingerprint,
signedCall,
createdAtMs: Date.now(),
}
}
const walletAddress = this.walletAddress
if (!walletAddress) throw new InitializationError('Wallet is not initialized.')
return this.relayer.feeOptions(
walletAddress,
this.chainId,
signedCall.to,
callsToSend,
signedCall.data,
)
}
```
Then `getFeeOptions` and `isSponsored` become thin wrappers:
```ts
async getFeeOptions(calls: Transaction[]) {
try {
const feeOptions = await this._fetchFeeOptions(calls)
return feeOptions.options
} catch (err) {
throw new FeeOptionError(
`Failed to get fee options: ${err instanceof Error ? err.message : String(err)}`,
)
}
}
```
```ts
async isSponsored(calls: Transaction[]): Promise<boolean> {
try {
const feeOptions = await this._fetchFeeOptions(calls)
return feeOptions.sponsored === true && !feeOptions.failed
} catch (err) {
console.warn(
`isSponsored check failed for chain ${this.chainId}:`,
err instanceof Error ? err.message : String(err),
)
return false
}
}
```
This keeps all existing behavior (including caching and the extra `signedCall.data` argument) in one place, avoids divergence between `getFeeOptions` and `isSponsored`, and reduces cognitive load.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
There was a problem hiding this comment.
Code Review
This pull request upgrades TypeScript to version 6.0.3 and updates various tooling dependencies across the workspace. It introduces explicit sponsorship and error-tracking fields (sponsored and failed) to the relayer and wallet SDKs, alongside a new buildFeeOptionsTransaction helper to handle fee options simulations for both deployed and undeployed wallets. A critical piece of feedback highlights that the removal of multiple supported network configurations (such as Polygon zkEVM, Xai, and Blast) from the primitives package is a breaking change that should either be reverted or accompanied by a major version bump and proper documentation.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
Summary by Sourcery
Propagate explicit relayer sponsorship and failure signals through wallet, dapp client, and relayer APIs while updating fee option handling, adding active device userdata APIs, pruning unused networks, tightening tests, and refreshing tooling and TypeScript/Next configurations.
New Features:
Bug Fixes:
Enhancements:
Build:
CI:
Documentation:
Tests: