Skip to content

feat(paywall): chain-aware faucetUrl resolution across TS/Python/Go SDKs#2160

Merged
phdargen merged 1 commit into
x402-foundation:mainfrom
ryanRfox:feat/paywall-faucet-url-registry-upstream
May 16, 2026
Merged

feat(paywall): chain-aware faucetUrl resolution across TS/Python/Go SDKs#2160
phdargen merged 1 commit into
x402-foundation:mainfrom
ryanRfox:feat/paywall-faucet-url-registry-upstream

Conversation

@ryanRfox
Copy link
Copy Markdown
Contributor

@ryanRfox ryanRfox commented Apr 29, 2026

Summary

Re-scopes #2160 to address @phdargen's review feedback: faucet links are a paywall UX concern and don't belong in the SDK chain catalog. Replaces the prior 4-layer fallback chain with a single-layer resolution path inside @x402/paywall.

Resolution path (single layer)

PaywallConfig.faucetUrls[caip2]   →  curated FAUCET_URLS[caip2]   →  "No faucet configured."
  1. Server override (PaywallConfig.faucetUrls) wins for any chain it covers.
  2. Curated map in @x402/paywall/src/faucetUrls.ts provides defaults for known testnets (Base Sepolia, Arbitrum Sepolia, Mezo Testnet, Stable Testnet, Radius Testnet, Solana Devnet, Algorand Testnet).
  3. No fallback URL. Unmapped chains render <span>No faucet configured.</span> instead of a wrong link (e.g. faucet.circle.com for non-Circle chains).

What changed vs the previous PR head

  • Dropped from SDK chain catalogs. @x402/evm, @x402/avm, go/mechanisms/{evm,svm}, python/x402/mechanisms/{evm,svm} revert to their original chain-identity-only contract — no faucetUrl / FaucetURL / faucet_url fields.
  • Dropped global override. PaywallConfig.faucetUrl (single URL applied to every chain) is gone; only the per-chain faucetUrls map remains.
  • Replaced gen/ codegen with hand-curated source. Three gen/faucetUrls.ts files removed; a single src/faucetUrls.ts now hosts the testnet map plus a resolveFaucetUrl(network, x402) helper.
  • Bundled the SolanaPaywall devnet-gate fix flagged in the prior PR body's "Pre-existing follow-up" — all three paywall components now use the shared isTestnetNetwork() helper, replacing divergent String(network).includes("devnet") (SVM) and network.includes(ALGORAND_NETWORK_REFS.TESTNET) (AVM) substring checks. SVM recognition matches upstream/main: Mainnet + Devnet only (no Solana Testnet — Circle's faucet doesn't drop USDC there and no SVM dev expects paywall Testnet support).
  • Unified copy. All three paywalls render the same "Need {tokenName} on {chainName}?" text; the hardcoded "Need Solana Devnet USDC?" / "Need Algorand Testnet USDC?" strings are gone. SolanaPaywall and AvmPaywall payment-required headers now use {tokenName} instead of hardcoded "USDC", matching EvmPaywall.

Boundary alignment

This aligns with #2250's "consume from DEFAULT_STABLECOINS, don't extend it" principle. The same canon, defended from the other side: paywall UX concerns stay in @x402/paywall; chain catalogs stay focused on chain identity.

Onboarding

DEFAULT_ASSETS.md gains a "Paywall faucet link (recommended for testnets)" section. Adding a faucet for your testnet is a one-line edit to typescript/packages/http/paywall/src/faucetUrls.ts. No cross-SDK lockstep — the map is bundled exclusively by the TypeScript paywall and read by the Python and Go handlers through the rendered template.

Closes

Closes #2159.

@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 29, 2026

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

A member of the Team first needs to authorize it.

@github-actions github-actions Bot added typescript go sdk Changes to core v2 packages python labels Apr 29, 2026
ryanRfox added a commit to ryanRfox/x402 that referenced this pull request Apr 29, 2026
Per upstream Python Towncrier convention, fragment files are named
after the PR number they describe. The PR_TBD placeholder was used
during local CI verification before the upstream PR was filed.

This commit only renames; content is unchanged.
@ryanRfox ryanRfox force-pushed the feat/paywall-faucet-url-registry-upstream branch from 765aa35 to d2ddab4 Compare April 29, 2026 15:19
@ryanRfox ryanRfox force-pushed the feat/paywall-faucet-url-registry-upstream branch from d2ddab4 to 19e7865 Compare May 4, 2026 21:16
@phdargen phdargen self-assigned this May 7, 2026
@ryanRfox ryanRfox force-pushed the feat/paywall-faucet-url-registry-upstream branch 3 times, most recently from 1f023ef to a88cac3 Compare May 13, 2026 19:04
@phdargen
Copy link
Copy Markdown
Collaborator

Hi @ryanRfox, as faucet links are a paywall UX concern only, I think they should not be added to the @x402/evm etc packages. Also feel there are too many layers of fallbacks in your solution.

I'd suggest the following:

  • curated defaults live only in @x402/paywall: a single map Record<network, string>, with per mechanism fallback
  • then have one faucetUrls?.[network] server override

@phdargen
Copy link
Copy Markdown
Collaborator

Would be great if you could also include a fix for the solana devnet bug you mentioned above

ryanRfox added a commit to ryanRfox/x402 that referenced this pull request May 16, 2026
Per x402-foundation#2160 review: faucet links are a paywall UX concern. Curated defaults
live in @x402/paywall/src/faucetUrls.ts (single Record<network, string>),
with PaywallConfig.faucetUrls?.[network] as the sole server override.
Unmapped chains render "No faucet configured." rather than a wrong link.

- Drop SDK-catalog faucetUrl/FaucetURL/faucet_url additions; @x402/evm,
  @x402/avm, go/mechanisms/{evm,svm}, python/x402/mechanisms/{evm,svm}
  retain their original chain-identity-only contract.
- Drop PaywallConfig.faucetUrl (global override); keep faucetUrls (per-chain).
- Replace 3 gen/faucetUrls.ts codegen files with a single hand-curated source.
- Add SOLANA_NETWORK_REFS.TESTNET; extend isTestnetNetwork() to cover it.
- Unify testnet gate via isTestnetNetwork() in {Solana,Avm}Paywall.
- Normalize "Need {tokenName} on {chainName}?" copy across all 3 paywalls.

Closes x402-foundation#2159
@ryanRfox ryanRfox force-pushed the feat/paywall-faucet-url-registry-upstream branch from a88cac3 to fc1f3fe Compare May 16, 2026 00:09
ryanRfox added a commit to ryanRfox/x402 that referenced this pull request May 16, 2026
Per x402-foundation#2160 review: faucet links are a paywall UX concern. Curated defaults
live in @x402/paywall/src/faucetUrls.ts (single Record<network, string>),
with PaywallConfig.faucetUrls?.[network] as the sole server override.
Unmapped chains render "No faucet configured." rather than a wrong link.

- Drop SDK-catalog faucetUrl/FaucetURL/faucet_url additions; @x402/evm,
  @x402/avm, go/mechanisms/{evm,svm}, python/x402/mechanisms/{evm,svm}
  retain their original chain-identity-only contract.
- Drop PaywallConfig.faucetUrl (global override); keep faucetUrls (per-chain).
- Replace 3 gen/faucetUrls.ts codegen files with a single hand-curated source.
- Add SOLANA_NETWORK_REFS.TESTNET; extend isTestnetNetwork() to cover it.
- Unify testnet gate via isTestnetNetwork() in {Solana,Avm}Paywall.
- Normalize "Need {tokenName} on {chainName}?" copy across all 3 paywalls.

Closes x402-foundation#2159
@ryanRfox ryanRfox force-pushed the feat/paywall-faucet-url-registry-upstream branch from fc1f3fe to dc7fa5e Compare May 16, 2026 00:37
ryanRfox added a commit to ryanRfox/x402 that referenced this pull request May 16, 2026
Per x402-foundation#2160 review: faucet links are a paywall UX concern. Curated defaults
live in @x402/paywall/src/faucetUrls.ts (single Record<network, string>),
with PaywallConfig.faucetUrls?.[network] as the sole server override.
Unmapped chains render "No faucet configured." rather than a wrong link.

- Drop SDK-catalog faucetUrl/FaucetURL/faucet_url additions; @x402/evm,
  @x402/avm, go/mechanisms/{evm,svm}, python/x402/mechanisms/{evm,svm}
  retain their original chain-identity-only contract.
- Drop PaywallConfig.faucetUrl (global override); keep faucetUrls (per-chain).
- Replace 3 gen/faucetUrls.ts codegen files with a single hand-curated source.
- Add SOLANA_NETWORK_REFS.TESTNET; extend isTestnetNetwork() to cover it.
- Unify testnet gate via isTestnetNetwork() in {Solana,Avm}Paywall.
- Normalize "Need {tokenName} on {chainName}?" copy across all 3 paywalls.

Closes x402-foundation#2159
@ryanRfox ryanRfox force-pushed the feat/paywall-faucet-url-registry-upstream branch from dc7fa5e to 67ffe7d Compare May 16, 2026 00:47
…dev framing

Address forensic review-quorum findings and conform SVM paywall to upstream pattern:

- Drop dead solana:TESTNET FAUCET_URLS entry (Circle faucet does not
  dispense USDC on Solana Testnet; Option B renders "No faucet configured."
  for any unmapped chain).
- Revert all Solana Testnet recognition added by prior refactor pass
  (SOLANA_NETWORK_REFS.TESTNET constant, getNetworkDisplayName branch,
  isTestnetNetwork OR-branch). The paywall now recognizes one non-mainnet
  SVM network — Devnet — matching upstream/main. No SVM dev expects
  paywall Testnet support; upstream doesn't provide it.
- Unify "Need {tokenName} on {chainName}?" copy in SolanaPaywall and
  AvmPaywall payment-required headers (were hardcoded "USDC"; matches
  EvmPaywall).

Closes x402-foundation#2159
@ryanRfox ryanRfox force-pushed the feat/paywall-faucet-url-registry-upstream branch from 67ffe7d to 7ca399b Compare May 16, 2026 13:17
@ryanRfox
Copy link
Copy Markdown
Contributor Author

@phdargen ready for re-review. Addressed your three asks:

  • Faucet URL data out of SDK packages. Removed from DefaultAssetInfo (TS @x402/evm), USDC_CONFIG (TS @x402/avm), and AssetInfo (Go evm+svm, Python evm+svm). Curated testnet map lives only in @x402/paywall/src/faucetUrls.ts.

  • Collapsed fallback layers. Single server override: PaywallConfig.faucetUrls?.[network]. Resolution = server override → curated map; unmapped chains render No faucet configured. (no wrong-URL fallback). PaywallConfig.faucetUrl (global) dropped across TS/Python/Go.

  • Solana devnet gate. String(network).includes("devnet") replaced with the shared isTestnetNetwork() helper across all three paywall components. SVM recognition matches upstream/main: Mainnet + Devnet.

Copy link
Copy Markdown
Collaborator

@phdargen phdargen left a comment

Choose a reason for hiding this comment

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

Looks good, thank you @ryanRfox

@phdargen phdargen merged commit e35becf into x402-foundation:main May 16, 2026
14 of 15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

go python sdk Changes to core v2 packages typescript

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature: Multi-SDK chain-aware faucetUrl resolution for the testnet paywall

2 participants