Skip to content

Conversation

@0xFirekeeper
Copy link
Member

@0xFirekeeper 0xFirekeeper commented Oct 27, 2025

Allows for systems with retries to process at their own pace, and guards against slightly descynced block.timestamp


PR-Codex overview

This PR updates the maxTimeoutSeconds for the x402 transfer process to allow for a longer authorization timeout, changing it from 300 seconds to 86400 seconds (24 hours). This adjustment aims to accommodate potential issues with block timestamp behavior.

Detailed summary

  • Updated maxTimeoutSeconds from 300 to 86400 in packages/thirdweb/src/x402/common.ts.
  • Adjusted the calculation for validAfter in packages/thirdweb/src/x402/sign.ts to allow for a 24-hour buffer instead of 10 minutes.

✨ Ask PR-Codex anything about this PR by commenting with /codex {your question}

Summary by CodeRabbit

  • Enhancements
    • Increased payment request timeout to 24 hours when no timeout is specified, allowing longer-lived authorization requests.
    • Widened the validity window used during payment validation to better accommodate timing or block-timestamp discrepancies.

Allows for systems with retries to process at their own pace, and guards against slightly descynced block.timestamp
@0xFirekeeper 0xFirekeeper requested review from a team as code owners October 27, 2025 15:11
@changeset-bot
Copy link

changeset-bot bot commented Oct 27, 2025

🦋 Changeset detected

Latest commit: 445e77e

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 4 packages
Name Type
thirdweb Patch
@thirdweb-dev/nebula Patch
@thirdweb-dev/wagmi-adapter Patch
wagmi-inapp Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel
Copy link

vercel bot commented Oct 27, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
docs-v2 Ready Ready Preview Comment Oct 27, 2025 3:27pm
nebula Ready Ready Preview Comment Oct 27, 2025 3:27pm
thirdweb_playground Ready Ready Preview Comment Oct 27, 2025 3:27pm
thirdweb-www Ready Ready Preview Comment Oct 27, 2025 3:27pm
wallet-ui Ready Ready Preview Comment Oct 27, 2025 3:27pm

@github-actions github-actions bot added packages SDK Involves changes to the thirdweb SDK labels Oct 27, 2025
@0xFirekeeper 0xFirekeeper added the DO NOT MERGE This pull request is still in progress and is not ready to be merged. label Oct 27, 2025
@graphite-app
Copy link
Contributor

graphite-app bot commented Oct 27, 2025

How to use the Graphite Merge Queue

Add either label to this PR to merge it via the merge queue:

  • merge-queue - adds this PR to the back of the merge queue
  • hotfix - for urgent hot fixes, skip the queue and merge this PR next

You must have a Graphite account in order to use the merge queue. Sign up using this link.

An organization admin has enabled the Graphite Merge Queue in this repository.

Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 27, 2025

Walkthrough

The changes increase timeout and validity window durations in the x402 payment request flow. Default maxTimeoutSeconds is increased from 300 to 86400 seconds, and the validAfter calculation now subtracts 86400 seconds instead of 600 seconds, widening the validity window.

Changes

Cohort / File(s) Summary
x402 payment request timeout and validity updates
packages/thirdweb/src/x402/common.ts, packages/thirdweb/src/x402/sign.ts
Default maxTimeoutSeconds changed from 300 to 86400 seconds (24 hours); validAfter computation changed to subtract 86400 seconds instead of 600 seconds to account for block timestamp anomalies

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

  • Timeout security implications: Verify that increasing the default timeout from 10 minutes to 24 hours aligns with payment protocol security requirements and doesn't introduce unintended acceptance windows.
  • Validity window expansion: Confirm that the 24-hour lookback window for validAfter is intentional and doesn't conflict with block timestamp assumptions or other protocol constraints.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Description Check ⚠️ Warning The PR description provides a clear, on-topic statement about the changes and includes a PR-Codex generated summary explaining the specific modifications to the x402 timeout and validAfter calculations. However, the description does not follow the required template structure. It is missing the properly formatted title (should follow "[SDK/Dashboard/Portal] Feature/Fix: Concise title"), lacks a dedicated "Notes for the reviewer" section, does not include a "How to test" section, and does not reference an issue tag (TEAM-0000 format). While the content itself is substantive and describes the changes clearly, the lack of adherence to the required template structure and the absence of key sections makes the description incomplete against the specified requirements. To meet the template requirements, please add a proper title in the format "[SDK/Dashboard/Portal] Feature/Fix: Update x402 default payment validity window" at the top, include the Linear issue tag if available, add a "Notes for the reviewer" section highlighting any important considerations (such as the rationale for the 24-hour window and potential impacts), and add a "How to test" section describing how reviewers and QA can verify these changes work correctly (such as relevant unit tests or integration test scenarios).
✅ Passed checks (2 passed)
Check name Status Explanation
Title Check ✅ Passed The PR title "Update x402 default payment validity window" directly and clearly summarizes the main changes in the pull request. The title is specific and refers to the actual modifications across both modified files (common.ts and sign.ts), which both involve updating timeout and validity window parameters for x402 payment processing. The title is concise, avoids vague terminology, and provides enough context for a developer scanning the commit history to understand the primary change.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch firekeeper/timeout

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between dcef3f4 and d84c7c1.

📒 Files selected for processing (2)
  • packages/thirdweb/src/x402/common.ts (1 hunks)
  • packages/thirdweb/src/x402/sign.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each file to one stateless, single-responsibility function for clarity
Re-use shared types from @/types or local types.ts barrels
Prefer type aliases over interface except for nominal shapes
Avoid any and unknown unless unavoidable; narrow generics when possible
Choose composition over inheritance; leverage utility types (Partial, Pick, etc.)
Comment only ambiguous logic; avoid restating TypeScript in prose

**/*.{ts,tsx}: Use explicit function declarations and explicit return types in TypeScript
Limit each file to one stateless, single‑responsibility function
Re‑use shared types from @/types where applicable
Prefer type aliases over interface except for nominal shapes
Avoid any and unknown unless unavoidable; narrow generics when possible
Prefer composition over inheritance; use utility types (Partial, Pick, etc.)
Lazy‑import optional features and avoid top‑level side‑effects to reduce bundle size

Files:

  • packages/thirdweb/src/x402/sign.ts
  • packages/thirdweb/src/x402/common.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Load heavy dependencies inside async paths to keep initial bundle lean (lazy loading)

Files:

  • packages/thirdweb/src/x402/sign.ts
  • packages/thirdweb/src/x402/common.ts
packages/thirdweb/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

packages/thirdweb/**/*.{ts,tsx}: Every public symbol must have comprehensive TSDoc with at least one compiling @example and a custom tag (@beta, @internal, @experimental, etc.)
Comment only ambiguous logic; avoid restating TypeScript in prose
Lazy‑load heavy dependencies inside async paths (e.g., const { jsPDF } = await import("jspdf"))

Files:

  • packages/thirdweb/src/x402/sign.ts
  • packages/thirdweb/src/x402/common.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
  • GitHub Check: E2E Tests (pnpm, vite)
  • GitHub Check: E2E Tests (pnpm, esbuild)
  • GitHub Check: E2E Tests (pnpm, webpack)
  • GitHub Check: Size
  • GitHub Check: Unit Tests
  • GitHub Check: Lint Packages
  • GitHub Check: Build Packages
  • GitHub Check: Analyze (javascript)

mimeType: mimeType ?? "application/json",
payTo: getAddress(facilitator.address), // always pay to the facilitator address first
maxTimeoutSeconds: maxTimeoutSeconds ?? 300,
maxTimeoutSeconds: maxTimeoutSeconds ?? 86400,
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Verify that 24-hour timeout aligns with security and UX requirements.

The default maxTimeoutSeconds has been increased from 300 seconds (5 minutes) to 86400 seconds (24 hours). While this supports retry scenarios as mentioned in the PR description, consider the following:

  1. Security: A 24-hour validity window for payment authorizations significantly increases the window for potential replay attacks or misuse of stale authorizations.
  2. User Experience: Users expecting near-instant responses may experience confusion with such a long timeout.
  3. Breaking Change: Existing integrations may have assumptions about the 5-minute default that could affect timeout handling, monitoring, or user flows.

Verify that this timeout duration is appropriate for your payment flow. Consider whether a more granular approach (e.g., different defaults for different scenarios) would be more suitable. You may also want to search for best practices around EIP-2612 and EIP-3009 authorization validity windows:


🌐 Web query:

What are the recommended validity window durations for EIP-2612 Permit and EIP-3009 TransferWithAuthorization signatures?

💡 Result:

Short answer

  • EIP‑2612 (permit): the spec leaves deadline to the signer; common practice is to use short expiries (minutes→hours). Example usages and docs commonly show deadline = now + 3600s (1 hour) or shorter (e.g., 5–20 minutes) as best practice. [EIP‑2612][1][2][3]

  • EIP‑3009 (transferWithAuthorization): the spec provides validAfter/validBefore and recommends bounding authorizations; common examples use validBefore = now + 3600s (1 hour) and validAfter = now (or a short delay), i.e. a validity window (minutes→hours) chosen by the app. [EIP‑3009][4][5][6]

Notes

  • Neither standard mandates a specific duration — choose based on UX/risk (short windows reduce misuse but increase fragility for relayers). See the EIPs and implementation examples. [1][4][5]

Sources

  1. EIP‑2612 specification (permit, deadline discussion). [EIP‑2612]. [2]
  2. OpenZeppelin / ERC20Permit implementation notes (deadline requirement). [3]
  3. Developer examples showing common deadline usage (now + 3600s). [7]
  4. EIP‑3009 specification (validAfter/validBefore fields and rationale). [4]
  5. EIP‑3009 examples and implementations using validBefore = now + 3600s. [5][6]

References
[1] https://eips.ethereum.org/EIPS/eip-2612
[2] https://eips-wg.github.io/EIPs/2612/
[3] https://docs.openzeppelin.com/contracts/ (ERC20Permit)
[4] https://eips.ethereum.org/EIPS/eip-3009
[5] https://eips-wg.github.io/EIPs/3009/
[6] example usages (libraries/docs showing validBefore/deadline = now + 3600s).


🏁 Script executed:

#!/bin/bash
# Inspect the file context to understand maxTimeoutSeconds purpose
cat packages/thirdweb/src/x402/common.ts

Length of output: 10404


🏁 Script executed:

#!/bin/bash
# Search for references to maxTimeoutSeconds to understand its use case
rg -n "maxTimeoutSeconds" --type ts -C 3

Length of output: 3838


🏁 Script executed:

#!/bin/bash
# Check for any comments or documentation about timeout durations
rg -n "timeout|Timeout" packages/thirdweb/src/x402/ --type ts -C 2

Length of output: 1850


Reduce maxTimeoutSeconds default from 86400 to align with EIP-2612/EIP-3009 best practices.

The default timeout was increased from 300 seconds (5 minutes) to 86400 seconds (24 hours). This contradicts established standards:

  • EIP-2612 and EIP-3009 best practice is short expiries of minutes→hours, commonly 1 hour or 5-20 minutes
  • Your documentation examples in verify-payment.ts and settle-payment.ts use maxTimeoutSeconds: 300 (5 minutes)
  • The code sets validBefore for signature validity (line 38 in sign.ts), directly affecting authorization window length

A 24-hour validity window creates a significant security gap: signatures remain valid for an entire day, increasing exposure to replay attacks or misuse of stale authorizations. Reduce the default to 3600 (1 hour) or provide documented security justification for the 24-hour window.

🤖 Prompt for AI Agents
In packages/thirdweb/src/x402/common.ts around line 110, the default
maxTimeoutSeconds is set to 86400 (24h) which is inconsistent with
EIP-2612/EIP-3009 best practices and existing examples; change the default to
3600 (1 hour) (or 300 if you prefer 5 minutes) to reduce the authorization
window, and ensure any related logic (e.g., the validBefore calculation in
sign.ts line 38) and documentation/examples (verify-payment.ts and
settle-payment.ts) are updated to reflect the new default so defaults remain
consistent across the codebase.

Comment on lines 34 to 36
const validAfter = BigInt(
Math.floor(Date.now() / 1000) - 600, // 10 minutes before
Math.floor(Date.now() / 1000) - 86400, // 24h before in case weird block timestamp behavior
).toString();
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Reconsider the 24-hour validAfter window for authorization signatures.

Setting validAfter to 24 hours in the past is excessive for handling blockchain timestamp desynchronization. Typical blockchain timestamp drift is measured in seconds or minutes, not hours. This creates significant security concerns:

  1. Stale Authorization Risk: A signed authorization remains valid for 24 hours after creation, even if conditions have changed (account balance, user intent, etc.).
  2. Replay Attack Surface: The extended validity window increases opportunities for replay attacks if authorizations are intercepted or leaked.
  3. Non-standard Practice: EIP-2612 and EIP-3009 implementations typically use much shorter validity windows (often 10-30 minutes maximum) to limit exposure.

The comment "weird block timestamp behavior" is vague. If this addresses a specific blockchain issue, it should be documented with details about which chains and what specific behavior is being mitigated.

Consider reducing this to a more conservative value (e.g., 600-1800 seconds) that still handles reasonable clock skew while limiting security exposure. Run the following to check for any documented requirements:


🏁 Script executed:

#!/bin/bash
# Search for documentation or comments about timestamp handling in x402 module
rg -n -C3 -g '*.{ts,md}' 'timestamp|validAfter|block.timestamp' packages/thirdweb/src/x402/

Length of output: 3504


I'll verify the EIP-3009 specification and search for additional context in the codebase.

Now let me search for tests and related documentation in the x402 module to understand if there's a specific reason for this 24-hour window:

Let me search the codebase for tests and any specific rationale for the 24-hour window:Based on my thorough verification, I can now provide the rewritten review comment. The web search results confirm:

  1. Ethereum clients reject blocks with timestamps more than 15 seconds in the future
  2. Ethereum timestamp accuracy can vary up to a few tens of seconds
  3. Standard EIP-3009 implementations use validBefore with a 1-hour window and typically set validAfter to 0

The 24-hour (86400 seconds) backward window is significantly excessive for handling blockchain timestamp drift and introduces unnecessary security risks. The original review comment's concerns are valid and substantiated by industry standards.


Reduce the 24-hour validAfter window to a more reasonable value consistent with blockchain standards.

Ethereum clients only allow block timestamps up to 15 seconds in the future, and actual timestamp accuracy varies only up to a few tens of seconds. Setting validAfter to 24 hours in the past creates security risks:

  1. Extended Authorization Validity: Allows signed authorizations from 24 hours ago to remain valid, even if account conditions or user intent have changed.
  2. Increased Replay Surface: The wide validity window significantly increases exposure to replay attacks if authorizations are leaked or intercepted.
  3. Deviation from Standards: Standard EIP-3009 implementations use 1-hour validity windows and commonly set validAfter to 0, not 24 hours backward.

Consider reducing validAfter to a conservative value like 600-1800 seconds to handle reasonable clock skew while limiting security exposure. Update the comment to explain the specific blockchain issue being addressed, if applicable.

🤖 Prompt for AI Agents
packages/thirdweb/src/x402/sign.ts lines 34-36: the code sets validAfter to 24
hours in the past which is excessive and increases replay/authorization risk;
change the logic to use a much smaller backward skew (e.g., 600–1800 seconds) or
set validAfter to 0 per common EIP-3009 practice, update the numeric value and
accompanying comment to reflect the new conservative skew, and adjust any tests
or docs that assume the 24-hour window.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
.changeset/good-ducks-eat.md (1)

1-5: Changeset structure and versioning look good.

The changeset properly documents the patch bump for the thirdweb package, and the patch version level is appropriate for default parameter value changes that don't modify the public API surface.

Consider enhancing the description to be more specific about the business rationale—e.g., "increases x402 payment timeout from 5 to 1440 minutes to allow retries to complete and guard against block.timestamp desyncs" would give future maintainers clearer context than the current description.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between d84c7c1 and 445e77e.

📒 Files selected for processing (1)
  • .changeset/good-ducks-eat.md (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
.changeset/*.md

📄 CodeRabbit inference engine (AGENTS.md)

.changeset/*.md: Each change in packages/* must include a changeset for the appropriate package
Version bump rules: patch for non‑API changes; minor for new/modified public API

Files:

  • .changeset/good-ducks-eat.md
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Size
  • GitHub Check: Unit Tests
  • GitHub Check: Analyze (javascript)

@codecov
Copy link

codecov bot commented Oct 27, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 54.89%. Comparing base (dcef3f4) to head (445e77e).
⚠️ Report is 2 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #8317   +/-   ##
=======================================
  Coverage   54.89%   54.89%           
=======================================
  Files         919      919           
  Lines       60697    60697           
  Branches     4129     4129           
=======================================
  Hits        33318    33318           
  Misses      27277    27277           
  Partials      102      102           
Flag Coverage Δ
packages 54.89% <ø> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@joaquim-verges joaquim-verges merged commit abf0bba into main Oct 27, 2025
22 of 23 checks passed
@joaquim-verges joaquim-verges deleted the firekeeper/timeout branch October 27, 2025 16:56
@joaquim-verges joaquim-verges mentioned this pull request Oct 27, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

DO NOT MERGE This pull request is still in progress and is not ready to be merged. packages SDK Involves changes to the thirdweb SDK

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants