feat(x402-e2e): post-commit lifecycle scenarios + PR6 cleanups#76
Conversation
Adds the B1-B4, B6, B7 post-commit lifecycle scenarios (redeem,
complete, raiseDispute, mutual resolveDispute, retractDispute,
cancelVoucher) and A2 (atomic commit-and-redeem) to the e2e suite.
Harness extensions:
- SellerActor.signResolutionProposal — produces the counterpartySig
the buyer needs for mutual resolveDispute, routed through
coreSdk.signDisputeResolutionProposal with a forwarding adapter.
- performBuyerPostCommitAction — wraps signAction + POST to the
/x402B/{redeem,complete,dispute/*} routes mounted by server-express.
- performCancelVoucher — reaches the facilitator's /perform-action
directly, since server-express does not mount /cancel.
- BuyerActor accepts an optional policy override (needed by A2's
redeemMode: "commit-and-redeem").
PR6 cleanups:
- Subgraph reader now takes a viem PublicClient and waits on
coreSdk.waitForGraphNodeIndexing(blockNumber) when getExchangeById
returns null, instead of relying solely on the outer poll loop.
- Resource-server offer.ts tightens feeLimit against
ConfigHandlerFacet.getMaxTotalOfferFeePercentage() and floors
disputePeriodDurationInMS against getMinDisputePeriod(). Fetched
once at boot via fetchProtocolConfig and threaded as an optional
protocolConfig arg, keeping the example's unit tests stable.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughAdds action-aware meta-tx typed-data/recovery, fetches on-chain protocol config and threads it into offer construction, replaces global cached offers with session-scoped caching keyed by session header, stamps client session IDs, uses viem nonceManager for the relayer, centralizes token-auth deadline logic, and expands E2E seed-wallets, harnesses, readiness gating, and tests. ChangesAction-aware EIP-712 meta-transaction infrastructure
Resource server protocol configuration
Session tracking & payment flow control
Client token-auth deadline
Core header and package exports
E2E test infrastructure
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
✨ Finishing Touches🧪 Generate unit tests (beta)
|
…rio context handling
…nts and enhance fetch wrapper with session ID
…nd typed-data builders
…ng for improved state accuracy
…ction dispatching based on X-PAYMENT header
…nd enhance boot sequence handling
There was a problem hiding this comment.
Pull request overview
This PR expands the @bosonprotocol/x402-e2e suite with runnable commit/post-commit lifecycle scenarios and strengthens determinism/robustness in the local-stack harness by isolating chain-touching tests and tightening offer/config handling across the example resource server and facilitator.
Changes:
- Adds runnable e2e scenarios for atomic commit-and-redeem (A2) and buyer-driven post-commit lifecycle transitions (B1–B4, B6, B7).
- Introduces per-test-file seed-wallet slots + multi-seller seeding to make cross-file parallelism safer (plus an
E2E_SEQUENTIAL=1escape hatch). - Improves robustness of on-chain/subgraph interactions and meta-tx signature recovery (subgraph indexing waits, typed-data variant dispatch, relayer nonce management, and example-server protocol-config + offer caching updates).
Reviewed changes
Copilot reviewed 29 out of 30 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| typescript/packages/x402-e2e/vitest.config.ts | Adds E2E_SEQUENTIAL option to disable cross-file parallelism for debugging. |
| typescript/packages/x402-e2e/test/setup/globalSetup.ts | Seeds one seller per seed-wallet slot and resets the stack defensively before boot. |
| typescript/packages/x402-e2e/test/scenarios/post-commit.test.ts | New runnable post-commit lifecycle scenarios (B1–B4, B6, B7). |
| typescript/packages/x402-e2e/test/scenarios/commit.test.ts | Promotes A2 to runnable (atomic commit-and-redeem) and switches to per-file seed wallet + funded random buyer. |
| typescript/packages/x402-e2e/test/scenarios/_skeletons.test.ts | Removes moved post-commit todos and leaves remaining follow-ups parked. |
| typescript/packages/x402-e2e/test/scenarios/_setup.ts | Requires per-file slot + buyer account; fetches on-chain protocol config for in-process resource server. |
| typescript/packages/x402-e2e/test/scenarios/_seed-wallets.ts | Introduces named per-file seed-wallet slots and seller-info lookup via env JSON map. |
| typescript/packages/x402-e2e/test/scenarios/_buyer-setup.ts | Adds createFundedBuyer helper for per-describe isolated buyer EOAs. |
| typescript/packages/x402-e2e/test/harness/actors.test.ts | Adds unit coverage for SellerActor.signResolutionProposal. |
| typescript/packages/x402-e2e/src/harness/seller-actor.ts | Adds signResolutionProposal via core-sdk typed-data signing path. |
| typescript/packages/x402-e2e/src/harness/post-commit-http.ts | Adds helper to sign+POST buyer post-commit actions to resource server routes. |
| typescript/packages/x402-e2e/src/harness/index.ts | Re-exports new post-commit and facilitator-perform helpers. |
| typescript/packages/x402-e2e/src/harness/facilitator-perform-action.ts | Adds facilitator-direct cancelVoucher helper (and placeholder revoke). |
| typescript/packages/x402-e2e/src/harness/exchange-reader.ts | Adds optional PublicClient and waits for subgraph indexing vs chain head before reads. |
| typescript/packages/x402-e2e/src/harness/buyer-actor.ts | Adds optional policy override to drive atomic commit-and-redeem. |
| typescript/packages/x402-e2e/src/config/accounts.ts | Adds additional test accounts (ACCOUNT_10–ACCOUNT_15). |
| typescript/packages/x402-e2e/src/bin/resource-server.ts | Hardens boot: waits for Diamond code + ConfigHandlerFacet init; passes protocolConfig into app. |
| typescript/packages/x402-e2e/README.md | Documents seed-wallet slots + sequential fallback and updates account range. |
| typescript/packages/server-express/src/middleware.ts | Auto-detects commit flow from X-PAYMENT action when flow isn’t pinned. |
| typescript/packages/facilitator/test/perform-action.test.ts | Updates test signing fixture to mirror typed-data variants per action family. |
| typescript/packages/facilitator/src/verify/meta-tx-signature.ts | Adds action-aware typed-data reconstruction and signature recovery for post-commit actions. |
| typescript/packages/facilitator/src/perform-action/index.ts | Switches perform-action signature recovery to the new action-aware recovery function. |
| typescript/packages/core/src/eip712/meta-transaction.ts | Adds typed-data builders for action-specific meta-tx primary types (exchange/dispute/fund). |
| typescript/packages/client-fetch/src/wrap.ts | Adds per-flow session header to scope resource-server FullOffer caching across 402+retry. |
| typescript/packages/client-fetch/src/index.ts | Exports SESSION_ID_HEADER. |
| examples/resource-server/src/protocol-config.ts | Adds fetchProtocolConfig to read on-chain fee/dispute-period bounds. |
| examples/resource-server/src/offer.ts | Uses optional protocolConfig to tighten feeLimit and floor dispute period. |
| examples/resource-server/src/index.ts | Re-exports fetchProtocolConfig (+ type) for integrators. |
| examples/resource-server/src/app.ts | Switches requirements cache from time-based singleton to per-session keyed cache. |
| examples/facilitator-http/src/config.ts | Wraps relayer account with viem nonceManager to serialize concurrent submissions. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Actionable comments posted: 7
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@examples/resource-server/src/app.ts`:
- Around line 106-112: SESSION_ID_HEADER ("x-x402-boson-session-id") is
duplicated elsewhere and sessionCache (Map with SESSION_CACHE_TTL_MS and
FALLBACK_KEY) can grow unbounded; extract the header constant into a shared
module (e.g., x402-core) and import it into this file instead of redefining
SESSION_ID_HEADER, and either implement periodic cleanup for sessionCache (a
timer that scans and deletes expired entries) or swap the Map for an LRU cache
implementation so expired entries are evicted automatically; update references
to SESSION_ID_HEADER, SESSION_CACHE_TTL_MS, sessionCache, and FALLBACK_KEY
accordingly.
In `@typescript/packages/facilitator/src/verify/meta-tx-signature.ts`:
- Around line 243-270: decodeExchangeIdArg currently decodes the calldata but
doesn't verify decoded.functionName, allowing mismatched calldata (e.g.,
withdrawFunds) that still has a uint256 first arg; update decodeExchangeIdArg to
check decoded.functionName is one of the expected exchange-keyed function names
(same whitelist used by decodeResolveDisputeArgs / decodeWithdrawFundsArgs), and
return a DecodeFailure (code "BAD_META_TX_SIGNATURE") if it is not, before
validating the first arg type and returning { ok: true, value }. Ensure you
reference decoded.functionName and ACTION_ARGS_ABI within decodeExchangeIdArg
when adding this validation.
In `@typescript/packages/x402-e2e/src/harness/facilitator-perform-action.ts`:
- Around line 24-25: The type FacilitatorOnlyActionId currently advertises
"boson-revokeVoucher" as supported but the exported facilitator handler (the
exported function in the file that always throws around lines 95-101) is not
implemented; remove "boson-revokeVoucher" from FacilitatorOnlyActionId (and any
related export lists) or delete its entry from the exported actions surface, and
either remove the exported throwing handler or implement it before re-adding the
action; ensure only implemented actions are listed so callers cannot select the
unwired "boson-revokeVoucher".
In `@typescript/packages/x402-e2e/src/harness/post-commit-http.ts`:
- Around line 192-198: The safeStringify function is duplicated; extract the
function into a shared harness module (e.g., http-error-utils) and export it,
then replace the local safeStringify implementations in both modules with an
import of the shared function; update references to safeStringify in the modules
that currently define it (the post-commit-http and facilitator-perform-action
modules) to import from the new shared harness module and remove the duplicated
local definitions.
In `@typescript/packages/x402-e2e/test/scenarios/_seed-wallets.ts`:
- Around line 93-108: The JSON.parse call in getSellerInfo can throw a
SyntaxError with little context; wrap the JSON.parse(raw) into a try/catch
inside getSellerInfo (when reading process.env[SELLERS_ENV_KEY]) and on catch
throw a new Error that includes SELLERS_ENV_KEY, the raw value length/preview if
helpful, and the original error.message (or error.stack) so diagnostics clearly
indicate malformed JSON and where it came from; keep parsing into SellerInfoMap
and then proceed with the existing lookup of all[slot].
In `@typescript/packages/x402-e2e/test/scenarios/commit.test.ts`:
- Around line 119-131: The test uses duplicated literals (the txHash regex and
the price "1000000") in multiple scenarios; create a shared module (e.g.,
_assertion-constants.ts) that exports TX_HASH_REGEX and EXPECTED_PRICE, update
this test to import TX_HASH_REGEX and EXPECTED_PRICE and replace the inline
/^0x[0-9a-fA-F]+$/ and "1000000" occurrences in the assertions (the
readXPaymentResponse check and the ctx.asserter.expect call for exchangeId /
price), and update other scenario tests to import the same constants so the
regex and price are centralized.
In `@typescript/packages/x402-e2e/test/scenarios/post-commit.test.ts`:
- Around line 21-23: Update the high-level test description text that currently
reads "local stack (Diamond, subgraph, facilitator)" to use the user-facing term
"escrow" instead of "Diamond" (e.g., "local stack (escrow, subgraph,
facilitator)") so the scenario description uses escrow terminology; leave
internal/deep-link references alone if they specifically target Boson
facets/contracts.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 99f71f13-9af1-4a1c-87e9-573273b0f19c
📒 Files selected for processing (30)
examples/facilitator-http/src/config.tsexamples/resource-server/src/app.tsexamples/resource-server/src/index.tsexamples/resource-server/src/offer.tsexamples/resource-server/src/protocol-config.tstypescript/packages/client-fetch/src/index.tstypescript/packages/client-fetch/src/wrap.tstypescript/packages/core/src/eip712/meta-transaction.tstypescript/packages/facilitator/src/perform-action/index.tstypescript/packages/facilitator/src/verify/meta-tx-signature.tstypescript/packages/facilitator/test/perform-action.test.tstypescript/packages/server-express/src/middleware.tstypescript/packages/x402-e2e/README.mdtypescript/packages/x402-e2e/src/bin/resource-server.tstypescript/packages/x402-e2e/src/config/accounts.tstypescript/packages/x402-e2e/src/harness/buyer-actor.tstypescript/packages/x402-e2e/src/harness/exchange-reader.tstypescript/packages/x402-e2e/src/harness/facilitator-perform-action.tstypescript/packages/x402-e2e/src/harness/index.tstypescript/packages/x402-e2e/src/harness/post-commit-http.tstypescript/packages/x402-e2e/src/harness/seller-actor.tstypescript/packages/x402-e2e/test/harness/actors.test.tstypescript/packages/x402-e2e/test/scenarios/_buyer-setup.tstypescript/packages/x402-e2e/test/scenarios/_seed-wallets.tstypescript/packages/x402-e2e/test/scenarios/_setup.tstypescript/packages/x402-e2e/test/scenarios/_skeletons.test.tstypescript/packages/x402-e2e/test/scenarios/commit.test.tstypescript/packages/x402-e2e/test/scenarios/post-commit.test.tstypescript/packages/x402-e2e/test/setup/globalSetup.tstypescript/packages/x402-e2e/vitest.config.ts
…-auth signature deadlines
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@typescript/packages/client/src/token-auth/deadline.ts`:
- Around line 19-24: computeTokenAuthDeadline currently always subtracts
TOKEN_AUTH_DELINE_SAFETY_MARGIN_SECONDS which can make the deadline be in the
past when maxTimeoutSeconds is smaller than the margin; modify
computeTokenAuthDeadline to clamp the safety margin to at most maxTimeoutSeconds
- 1 (and never below 0) before subtracting so very short timeouts still produce
a future expiry. Update the function computeTokenAuthDeadline to compute an
effectiveMargin = Math.min(TOKEN_AUTH_DEADLINE_SAFETY_MARGIN_SECONDS,
Math.max(0, maxTimeoutSeconds - 1)) and subtract effectiveMargin instead of the
raw TOKEN_AUTH_DEADLINE_SAFETY_MARGIN_SECONDS.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: e2bea324-c168-478f-8462-36d0237bc7e9
📒 Files selected for processing (7)
examples/resource-server/src/app.tstypescript/packages/client/src/token-auth/deadline.tstypescript/packages/client/src/token-auth/erc3009.tstypescript/packages/client/src/token-auth/permit.tstypescript/packages/client/src/token-auth/permit2.tstypescript/packages/x402-e2e/README.mdtypescript/packages/x402-e2e/vitest.config.ts
The fixed 60s subtraction in `computeTokenAuthDeadline` could push the returned deadline into the past when `maxTimeoutSeconds < 60`, causing token-auth signatures to expire before they reach the facilitator. Clamp the effective margin to `Math.min(60, max(0, timeoutSeconds - 1))` so short timeouts still produce a strictly-future deadline. Addresses PR #76 review comment r3279645435. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
`getMinDisputePeriod()` returns a `uint256` in seconds; converting straight through `Number(...) * 1000` could silently lose precision or overflow past `MAX_SAFE_INTEGER / 1000`. Range-check the `bigint` against `MAX_SAFE_INTEGER / 1000` before converting, and throw a clear `RangeError` rather than emitting a wrong `minDisputePeriodMs`. `maxFeeBps` stays a plain `Number` — it's a `uint16` (max 65535), always safe. Addresses PR #76 review comment r3276008292. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
`WalletClient` doesn't require `account` / `chain` at the type level, so the previous non-null assertions would crash with an opaque viem error if a caller passed a bare client. Replace the assertions with an explicit guard that throws a clear harness-side message pointing at the right helper (`buildWalletClient(SEED_WALLETS.<slot>.account)`). Addresses PR #76 review comment r3276008400. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
`SESSION_ID_HEADER` was declared in both `@bosonprotocol/x402-client-fetch` (canonical mixed case) and the example resource server (lowercase), so the wire contract for per-buyer-flow offer caching was double-sourced. Move the canonical declaration into `@bosonprotocol/x402-core` (the package both buyer-side and server-side packages already orbit around), re-export it from `client-fetch` for backwards compatibility, and have the example resource server import the same constant. Express's `req.header()` is case-insensitive, so the canonical mixed-case value works for the server-side lookup. Addresses PR #76 review comment r3276010028 (header-duplication half). The unbounded-cache half called out by the same comment was already addressed earlier on this branch via the 256-entry LRU cap + per-call expired-entry pruning. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
`decodeExchangeIdArg` decoded calldata against the full `ACTION_ARGS_ABI` but didn't check which function the calldata actually encoded. A malformed `metaTx.functionSignature` encoding e.g. `withdrawFunds` would decode successfully as long as the first argument happened to be a `uint256` — leading to subtle mismatches when the reconstructed typed-data didn't reflect the action the signer actually approved. Whitelist the six exchange-keyed function names (`redeemVoucher`, `cancelVoucher`, `completeExchange`, `raiseDispute`, `retractDispute`, `escalateDispute`) and reject anything else with the existing `BAD_META_TX_SIGNATURE` envelope. Mirrors the validation already done by sibling `decodeResolveDisputeArgs` / `decodeWithdrawFundsArgs`. Addresses PR #76 review comment r3276010031. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
`safeStringify` was duplicated between `post-commit-http.ts` and `facilitator-perform-action.ts`. Move it into a shared `harness/http-error-utils.ts` and import from both call sites so the two implementations can't drift. Addresses PR #76 review comment r3276010036. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…tants The tx-hash regex (`/^0x[0-9a-fA-F]+$/`) and the default commit price (`"1000000"`) were repeated across `commit.test.ts` and `post-commit.test.ts` (and elsewhere). Pull them into `test/scenarios/_assertion-constants.ts` and import from both scenario files so they can't drift independently. Harness-level callers (`asserters.test.ts`, `_setup.ts`) keep their literals — the comment scope was the scenario files. Addresses PR #76 review comment r3276010052. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@typescript/packages/x402-e2e/src/harness/http-error-utils.ts`:
- Around line 11-15: The safeStringify function can return undefined because
JSON.stringify can return undefined for top-level undefined; update
safeStringify so it always returns a string by capturing the result of
JSON.stringify(value) into a variable, checking for undefined (or falsy) and
returning a fallback string (e.g., "undefined" or String(value)) if
JSON.stringify returns undefined, while keeping the existing catch branch that
returns String(value); reference: safeStringify function in http-error-utils.ts.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: dfac60aa-6640-4dae-b944-5a5391471f87
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (12)
examples/resource-server/src/app.tstypescript/packages/client-fetch/package.jsontypescript/packages/client-fetch/src/wrap.tstypescript/packages/core/src/headers.tstypescript/packages/core/src/index.tstypescript/packages/facilitator/src/verify/meta-tx-signature.tstypescript/packages/x402-e2e/src/harness/facilitator-perform-action.tstypescript/packages/x402-e2e/src/harness/http-error-utils.tstypescript/packages/x402-e2e/src/harness/post-commit-http.tstypescript/packages/x402-e2e/test/scenarios/_assertion-constants.tstypescript/packages/x402-e2e/test/scenarios/commit.test.tstypescript/packages/x402-e2e/test/scenarios/post-commit.test.ts
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
`JSON.stringify(value)` returns `undefined` (not a string) for top-level `undefined`, function, and symbol values without throwing, so the success branch could silently violate the declared `: string` return type and propagate `undefined` into error messages. Capture the call's result and fall back to `String(value)` on `null` / `undefined` so every code path returns a real string. Addresses PR #76 review comment r3279980090. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Restructure the three locally-built stack Dockerfiles (facilitator-http, webhook-sink, resource-server) so `pnpm install` runs in a separate stage keyed only on the lockfile + workspace manifests, with a shared BuildKit pnpm-store cache mount for tarball reuse. Source-only edits now skip the install layer entirely, and `--build` with no changes is a near-instant all-cache-hit. Also document a "When to rebuild" table in the x402-e2e README so the flag's effect on each service is explicit. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Without it, `pnpm install` inside the image ignores the repo-wide settings (`auto-install-peers`, `strict-peer-dependencies`, `shared-workspace-lockfile`) and can resolve a different dependency graph than a local install. Including `.npmrc` in the same COPY as the lockfile also makes the install layer correctly invalidate when the config changes. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…l buyers) E0 — 20 fresh EOAs fire `fetch(/resource)` concurrently against an in-process resource server, each going through atomic commit-and-redeem. Surfaces concurrency regressions the existing single-buyer scenarios can't catch (relayer nonceManager, offer template signing, subgraph indexer under load). Three upstream tweaks were needed to land the test green: - example-resource-server: fold the per-request session id into `metadataUri` / `metadataHash` so concurrent buyers each get a distinct `predictedOfferId`. Without it, two requests within the same millisecond produce byte-identical `UnsignedFullOffer` structs and the second commit reverts `OfferSoldOut` on the single-quantity template. - example-resource-server: widen offer + voucher validity windows from 1 h to 30 d (with 1 d backdate) so they tolerate Hardhat's ~20x chain-time acceleration under interval mining. - x402-e2e/globalSetup: switch Hardhat to 50 ms interval mining right after `[stack] ready`. The default automine rejects concurrent meta-tx submissions from a single relayer with "transactions can't be queued when automining"; interval mining lets them queue and mine in batches. Also adds an `E2E_DOCKER_KEEP_STACK=1` escape hatch on globalSetup so individual scenario files can be re-run repeatedly against a stack the maintainer brought up via `pnpm stack:up` — useful for iterating without paying the full cold-start cost each run. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…mit-redeem feat(x402-e2e): concurrent commit-and-redeem scenario (20 parallel buyers)
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@typescript/packages/x402-e2e/test/setup/globalSetup.ts`:
- Around line 136-138: The call to enableIntervalMining() is outside the guarded
setup block so if it throws the outer catch won't run and the non-KEEP_STACK
cleanup path can be skipped; move the console.log and await
enableIntervalMining() into the same try/guarded block where the rest of the
setup occurs (the block that checks KEEP_STACK and performs cleanup) so any
failure triggers the existing catch handling and cleanup logic; ensure you
reference and preserve the KEEP_STACK conditional and existing cleanup calls
while relocating enableIntervalMining() into the guarded setup in globalSetup.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 4bade2f9-2a9a-453f-81bf-1ffa703c3e77
📒 Files selected for processing (6)
CLAUDE.mdexamples/resource-server/src/app.tsexamples/resource-server/src/offer.tstypescript/packages/x402-e2e/test/scenarios/_seed-wallets.tstypescript/packages/x402-e2e/test/scenarios/concurrent.test.tstypescript/packages/x402-e2e/test/setup/globalSetup.ts
perf(x402-e2e): cache pnpm install layer in stack Dockerfiles
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@typescript/packages/x402-e2e/README.md`:
- Around line 101-107: The table row that reads "Only docs, CI, or
`.dockerignore` | nothing" is incorrect because changing `.dockerignore` can
change Docker build context and often requires rebuilding images; update the
README table entry (the row containing `.dockerignore`) to state that
`.dockerignore` changes should trigger a `--build` and/or rebuilding of the
relevant local images (e.g., the three images referenced by
`x402b-facilitator-http`, `x402b-resource-server`, and `x402b-webhook-sink`)
instead of "nothing", and add a short note that changes to `.dockerignore`
commonly require rebuilding when Dockerfiles use `COPY . .`.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 117de05d-937a-4e35-a943-41859c064a68
📒 Files selected for processing (4)
examples/facilitator-http/Dockerfileexamples/webhook-sink/Dockerfiletypescript/packages/x402-e2e/README.mdtypescript/packages/x402-e2e/src/bin/resource-server.Dockerfile
`.dockerignore` shapes the build context, and all three local Dockerfiles copy the full repo via `COPY . .`, so changes to it commonly require a `--build` of `x402b-facilitator-http`, `x402b-resource-server`, and `x402b-webhook-sink`. Split the row out of the "rebuild nothing" bucket and add a note explaining the `COPY . .` interaction. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Summary
Picks up the e2e suite where #74 left off (A1 only). Adds the @p0/@p1 buyer-driven post-commit lifecycle scenarios and applies the two robustness cleanups carried over from PR6.
New scenarios in
typescript/packages/x402-e2e/test/scenarios/:commit.test.ts— promotes A2 (atomic commit-and-redeem viaPolicy.redeemMode: \"commit-and-redeem\") fromit.todoto runnable.post-commit.test.ts:REDEEMEDCOMPLETEDDISPUTED+RESOLVINGRESOLVEDRETRACTEDCANCELLED(driven via the facilitator since server-express doesn't mount a/cancelroute)Each post-commit test starts from a fresh commit driven through the same 402 retry A1 uses, then drives the transition under test.
Harness extensions:
SellerActor.signResolutionProposal— produces thecounterpartySigthe buyer needs for mutual resolveDispute. Routes throughcoreSdk.signDisputeResolutionProposalso the EIP-712 typed-data stays in lock-step with the deployed protocol.post-commit-http.ts—performBuyerPostCommitActionwrapsbuyer.client.signAction(...)+ POST to/x402B/{redeem,complete,dispute/{raise,resolve,retract,escalate}}.facilitator-perform-action.ts—performCancelVoucherreaches the facilitator'sPOST /perform-actiondirectly.BuyerActornow accepts an optionalpolicyoverride (needed by A2).PR6 cleanups (the two robustness items the A1 PR called out as follow-ups):
exchange-reader.tsnow accepts a viemPublicClient; on anullgetExchangeByIdit fetches the chain head and callscoreSdk.waitForGraphNodeIndexing(blockNumber)before forwardingnull— the canonical "indexer caught up" wait, replacing reliance on the outer poll loop alone.examples/resource-server/src/protocol-config.ts—fetchProtocolConfigreadsConfigHandlerFacet.getMaxTotalOfferFeePercentage()+getMinDisputePeriod().offer.tstightensfeeLimit = price * maxFeeBps / 10000and floorsdisputePeriodDurationInMSagainst the on-chain minimum. Backwards-compatible:protocolConfigis an optional arg, so the example's existing unit tests still pass without changes.Out of scope (deferred to follow-up PRs)
erc3009/permit/permit2token-auth)Test plan
pnpm build— workspace builds cleanpnpm test— offline unit tests pass; scenario tests skip cleanly withoutE2E_DOCKER=1pnpm lint+pnpm format:check— cleanE2E_DOCKER=1 pnpm --filter @bosonprotocol/x402-e2e test— all enabled scenarios green end-to-end against the local Boson stack🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Bug Fixes
Tests