Skip to content

chore(e2e): make the harness portable to any EVM chain in DEFAULT_STABLECOINS#2250

Open
ryanRfox wants to merge 1 commit into
x402-foundation:mainfrom
ryanRfox:chore/e2e-portable-default-stablecoins
Open

chore(e2e): make the harness portable to any EVM chain in DEFAULT_STABLECOINS#2250
ryanRfox wants to merge 1 commit into
x402-foundation:mainfrom
ryanRfox:chore/e2e-portable-default-stablecoins

Conversation

@ryanRfox
Copy link
Copy Markdown
Contributor

@ryanRfox ryanRfox commented May 8, 2026

Summary

E2E harness becomes portable to any EVM chain defined within the SDK's DEFAULT_STABLECOINS catalog via new flag --evm-network=<caip2>. EVM_NETWORK_CONFIGS is derived from DEFAULT_STABLECOINS at module load, replacing the hand-curated table. Base Sepolia hardcodes (EIP-712 token names, Permit2 target, mock-facilitator scheme set) move to per-chain lookups. EVM-only runs (--families=evm) no longer require non-EVM credentials.

Component Details

  • CLI + harness wiring--evm-network=<caip2> selects the EVM chain; mode default preserved when omitted. getNetworkSet() accepts the override; resolveViemChain(caip2) replaces the base/baseSepolia ternary in clients and test.ts (e2e/src/cli/args.ts, e2e/test.ts).
  • SDK-imported registryEVM_NETWORK_CONFIGS built from Object.keys(DEFAULT_STABLECOINS) at module load; new SDK chains propagate after pnpm install, no harness edits. permit2Asset flows from DEFAULT_STABLECOINS[caip2].address. resolveViemChain(caip2) + evmRpcUrl(caip2) resolve via viem DB → EVM_RPC_URLdefineChain fallback (e2e/src/networks/networks.ts).
  • Hardcodes removed — Per-server EVM_PERMIT2_ASSET_NAMES lookup keyed by EVM_NETWORK replaces the EIP-712 token-name ternary across four EVM resource servers. Permit2 approval script reads target from resolved NetworkConfig. Mock facilitator advertises full EVM scheme set (exact, upto, batch-settlement) matching the real TS facilitator; non-EVM kinds gated on env presence.
  • Family-conditional gating — Removed unconditional EVM+SVM env check that fired before scenario filtering. requiredEnvByFamily table-driven check handles all five families uniformly (e2e/facilitators/typescript/index.ts lazy-initializes the SVM signer). --families=evm runs no longer require Solana/Aptos/Hedera/Stellar credentials.

Required Migration

CI configs setting per-chain RPC env vars must rename:

BASE_SEPOLIA_RPC_URL=...  →  EVM_RPC_URL=...

--evm-network=<caip2> selects the chain (or the mode default applies); EVM_RPC_URL is the single RPC override. No impact on SDK consumers using published packages.

Tests

  • pnpm install --frozen-lockfile clean across typescript/, examples/typescript/, e2e/.
  • tsc --noEmit from e2e/ (after pnpm -C typescript build): zero new errors vs upstream/main; 51 pre-existing errors unchanged.
  • Module-load introspection: EVM_NETWORK_CONFIGS resolves 12 keys, names sourced from viem DB, RPC URLs populated for every DEFAULT_STABLECOINS chain.
  • Base Sepolia slice (--testnet --families=evm --facilitators=typescript --servers=express --clients=fetch --min): 11/11 scenarios pass, exit 0, 28 settlement tx hashes status=0x1, paced JSON-RPC (1.2 s sleep, sequential). Run with no SVM env vars — confirms requiredEnvByFamily skips SVM credentials.
  • Non-Base EVM slice (--evm-network=<caip2> --families=evm): end-to-end pass with EVM-only credentials; zero Missing required environment errors referencing SVM variables.
  • viem floor ^2.48.11; e2e/ lockfile resolves direct viem to 2.48.11. Monorepo-wide floor bump in chore: bump viem floor to ^2.48.11 across monorepo + refresh lockfiles #2242.

Checklist

  • Code formatted and linted
  • All tests pass
  • Commits signed
  • Changelog fragment — internal harness refactor, no @x402/* runtime API surface change

@vercel
Copy link
Copy Markdown

vercel Bot commented May 8, 2026

@ryanRfox is attempting to deploy a commit to the Coinbase Team on Vercel.

A member of the Team first needs to authorize it.

@ryanRfox ryanRfox force-pushed the chore/e2e-portable-default-stablecoins branch 4 times, most recently from 0387732 to 26c331b Compare May 8, 2026 19:45
@ryanRfox ryanRfox mentioned this pull request May 8, 2026
4 tasks
@ryanRfox ryanRfox force-pushed the chore/e2e-portable-default-stablecoins branch from 26c331b to 72d1195 Compare May 8, 2026 20:02
@phdargen phdargen self-assigned this May 11, 2026
@ryanRfox ryanRfox force-pushed the chore/e2e-portable-default-stablecoins branch from 72d1195 to 985ce68 Compare May 13, 2026 18:59
…BLECOINS

Makes the e2e harness portable to any EVM chain in the SDK's
DEFAULT_STABLECOINS catalog. The visible knob is --evm-network=<caip2>;
the rest is the plumbing that makes the knob actually work.

Four interlocking pieces:

1. CLI override - --evm-network=<caip2> selects the EVM chain for a run.
   Mode-default behavior preserved when the flag is omitted.

2. SDK-imported chain registry - EVM_NETWORK_CONFIGS is derived from
   DEFAULT_STABLECOINS at module load via Object.fromEntries(...), replacing
   the prior 10-entry hand-curated table. New SDK chains propagate after
   pnpm install with no harness edit.

3. Removes Base Sepolia hardcodes - EIP-712 token names in the four EVM
   resource servers (express, fastify, hono, next/proxy) move to a per-server
   EVM_PERMIT2_ASSET_NAMES lookup keyed by EVM_NETWORK. The Permit2 approval
   script reads its target from the resolved network config. The mock
   facilitator advertises the full scheme set (exact, upto, batch-settlement)
   and gates non-EVM kinds on env presence.

4. EVM-only credential gating - an EVM-only run (--families=evm) no longer
   requires Solana, Aptos, Hedera, or Stellar wallets. The harness's
   existing requiredEnvByFamily post-filter check (test.ts line ~660)
   handles this uniformly across all five families; the unconditional
   EVM+SVM gate that fired before scenario filtering and over-required both
   families is removed.

resolveViemChain(caip2) looks up viem's chain database; for chains viem
hasn't packaged it falls through to defineChain({ name: 'EVM <id>',
rpcUrls: { default: { http: [] } } }) and the caller supplies EVM_RPC_URL.
With the viem floor at ^2.48.11, every chain currently in DEFAULT_STABLECOINS
is in viem's catalog, so the fallback is for forward-compatibility with
future SDK chains that out-pace viem.

evmRpcUrl(caip2) resolves in three tiers: EVM_RPC_URL env override -> viem
chain default -> ''. getNetworkSet(mode, evmCaip2?) accepts an optional
CAIP-2 EVM override that overlays the mode default's EVM slot from
EVM_NETWORK_CONFIGS.

Migration: CI configurations that set per-chain RPC URL env vars (e.g.,
BASE_SEPOLIA_RPC_URL) must migrate to the unified EVM_RPC_URL. The harness
selects the chain via --evm-network=<caip2> (or the mode default) and reads
RPC override from EVM_RPC_URL only. No impact on SDK consumers using the
published packages.

The complementary monorepo-wide viem floor bump is in x402-foundation#2242.
@ryanRfox ryanRfox force-pushed the chore/e2e-portable-default-stablecoins branch from 985ce68 to ceb7126 Compare May 16, 2026 19:37
ryanRfox added a commit to ryanRfox/x402 that referenced this pull request May 16, 2026
…_NETWORK

Apply the canonical chain-pluggable pattern established in PR x402-foundation#2250 (e2e/src/networks/networks.ts) to the 11 Tier 1 teachable demos. Each demo now reads an EVM_NETWORK env var (CAIP-2, default `eip155:84532`) instead of hard-coding the Base Sepolia literal in route declarations and resource-server registrations. The 11 facilitator-and-server demos can now be retargeted to any EVM chain in `DEFAULT_STABLECOINS` without code changes — same demo, different chain.

Two demos (`facilitator/basic`, `servers/self-facilitation`) inline a small `resolveViemChain` helper so their viem wallet clients track the configured chain, with `EVM_RPC_URL` overriding viem's default RPC. The helper falls back to `defineChain` for chains viem hasn't packaged yet (e.g. Mezo Testnet).

Scope: 11 .ts files + 7 README updates. Companion clients (`clients/fetch`, `clients/axios`, `clients/custom`, `clients/advanced/*`) already use `eip155:*`/`solana:*` wildcards, so no client-side work was needed.

Three intentional chain literals are preserved unchanged because they teach demo-specific semantics rather than the demo's chain selection:
- `clients/advanced/builder-pattern.ts` — `eip155:1` / `solana:EtWT…` per-network overrides
- `servers/advanced/custom-money-definition.ts:50` — `eip155:100` (Gnosis Chain) for the registerMoneyParser pattern
- `servers/offer-receipt/index.ts:59` — `did:pkh:eip155:1` canonical DID:PKH identifier

SVM accepts (`solana:EtWT…`) in the express/fastify/hono/facilitator-basic demos remain unchanged: Phase 2 scope is EVM-side only. SVM remains single-network at Solana Devnet.

Documented in each modified demo's README: the new `EVM_NETWORK` env var, the default chain, the link to `DEFAULT_STABLECOINS` for the list of chains that "just work", and (for the two demos that need it) the `EVM_RPC_URL` override for chains viem doesn't ship.
@ryanRfox
Copy link
Copy Markdown
Contributor Author

@phdargen — I did some refactoring on this one and feel it is ready for your review now. The PR body mentions related and potentially conflicting areas where I've made opinionated choices, so looking for your guidance there.

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.

Feature: Make the e2e harness portable to any EVM chain in DEFAULT_STABLECOINS

2 participants