@piprail/sdk 2.11.0 → 2.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,65 @@ All notable changes to `@piprail/sdk` are documented here. The format
4
4
  follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the
5
5
  versions follow [Semantic Versioning](https://semver.org/).
6
6
 
7
+ ## [2.13.0] — 2026-06-21 — A2A hardening: spec-correct `payment-failed`, schema-contract precision + exhaustive edge-case coverage
8
+
9
+ An extreme-hardening pass on the **x402-over-A2A seller transport**, audited against the **real
10
+ `@a2a-js/sdk` 0.3.13 types**, the **a2a-x402 spec (v0.1+v0.2)**, Google's **reference `x402_a2a`
11
+ executor**, and the canonical **x402 V2** lib. Net: **zero runtime defects found** — the wire is
12
+ schema-perfect. This ships the two correctness fixes plus a comprehensive test + doc-precision pass.
13
+ HTTP and every other rail are byte-identical to 2.12.0; additive, defaults unchanged.
14
+
15
+ - **fix(a2a): a rejected (failed-verification) proof now emits `x402.payment.status: payment-failed`,
16
+ not `payment-required`.** a2a.md §9 is a MUST — *"If a payment fails, the server MUST set
17
+ x402.payment.status to payment-failed"* — and its worked **expired-signature** example (a
18
+ verification failure) emits `payment-failed`. Google's reference executor matches it verbatim
19
+ (`verify_response.is_valid == false → record_payment_failure → PAYMENT_FAILED`). **Retryability is
20
+ unchanged** — it rides on the A2A Task `state` (`input-required`), with a fresh challenge re-issued in
21
+ `x402.payment.required` + the failure receipt + the `x402.payment.error` code. (2.11.0 correctly
22
+ removed the client-only `payment-rejected` but landed on `payment-required`; this is the final notch.)
23
+ A genuine first/no-proof challenge is still `payment-required`.
24
+ - **fix(a2a): a tx-suppressed success receipt (`receipts.includeTxHash:false`) is no longer dropped**
25
+ when an earlier failed attempt on the same task shares the empty `transaction`. The `receipts[]`
26
+ dedupe now skips the empty-string transaction (an empty tx is not an idempotency key), so a
27
+ `payment-completed` task always carries its success receipt. Default (`includeTxHash:true`) unaffected.
28
+ - **fix(a2a): `wrong_recipient` / `transfer_not_found` map to the spec's `SETTLEMENT_FAILED`, not
29
+ `INVALID_AMOUNT`.** Neither is an amount mismatch; the a2a.md §9.1 enum has no recipient/not-found
30
+ member, so its catch-all `SETTLEMENT_FAILED` is the correct nearest fit — a buyer is no longer told to
31
+ retry with a "corrected amount" when the real issue is a recipient/asset. The raw PipRail code still
32
+ rides in `extensions.piprail`. `INVALID_AMOUNT` is now reserved for genuine amount errors.
33
+ - **test: +24 A2A coverage cases** (the suite is now exhaustive) — the `payment-failed` rejection
34
+ contract; standard **`exact` (EIP-3009) happy-path settle over A2A** (the scheme a real Google client
35
+ sends); the **`upto` metered rail over A2A** incl. a `$0` settle; **multi-chain CAIP-2 rail selection**;
36
+ the **forged-`accepted` guard** (an unoffered network/asset can't redirect funds); the
37
+ tx-suppressed-dedupe regression; `fulfill` throwing a non-Error / returning `undefined`; `newTaskId`
38
+ minting; TTL-eviction + receipts-cap **boundary** (tail-preserving) cases; the host-adapter
39
+ required-field-set contract; and the **error-enum codomain guard** (every emitted code is one of the 7
40
+ canonical `x402ErrorCode` members).
41
+ - **docs: the A2A guide is corrected + sharpened** — the lifecycle table/prose pair a rejection with
42
+ `payment-failed` (retry via `input-required`); a new **"Which A2A package?"** note (A2A is a Linux
43
+ Foundation project, official runtime `@a2a-js/sdk`); a **transport-metadata** note (PipRail emits x402
44
+ payment state; the host adapter stamps the SDK-required `contextId`/`messageId`/`artifactId`);
45
+ `receipt.amount` clarified as base units; the buyer-payload snippet made internally consistent.
46
+
47
+ ## [2.12.0] — 2026-06-21 — BNB: the `U` (United Stables) token + Binance `permit2-exact` interop
48
+
49
+ BNB Chain max-out — full token parity with Binance's own x402 set, plus tolerance for Binance's
50
+ Permit2 dialect. Additive; no default changes, every other chain/rail byte-identical to 2.11.0.
51
+
52
+ - **feat(bnb): add `U` (United Stables) as a built-in BNB token.** `0xcE24439F2D9C6a2289F741120FE202248B666666`
53
+ (18dp) — the **first-listed token in Binance's own x402 set** (U/USD1/USDT/USDC) and the BNB Agent
54
+ Survival Pack settlement unit. Native **EIP-3009** (domain name `"United Stables"`, version `"1"`
55
+ derived from `DOMAIN_SEPARATOR`, no `version()`), so it routes onto the existing gasless
56
+ `transferWithAuthorization` rail with **no new protocol code** — like FDUSD/USD1. On-chain-verified,
57
+ and **live-proven on BNB mainnet**: a keyless facilitator (Pieverse) sponsored the gas — buyer AND
58
+ merchant paid **zero BNB** (settle tx `0x2b3b8c51ae81df441551301c44a64652c84c796af3b9d03ec58ea38f1cb013d5`).
59
+ Dexter + Pieverse both accept `U`; self-settle gasless also works. Grouped as `USD` for budget policy.
60
+ - **feat(x402): the buyer tolerates the `permit2-exact` `assetTransferMethod` label.** Binance's x402
61
+ facilitator ("b402") labels its EVM-Permit2 exact rail `permit2-exact` (the coinbase/x402 spec uses
62
+ bare `permit2`). PipRail still **emits** `permit2`; the buyer now treats `permit2-exact` as the same
63
+ Permit2 rail, so it can pay a Binance-issued 402. The gate/seller side already discriminates on
64
+ payload shape, so it was unaffected. Additive — no existing `permit2`/`eip3009` rail changes.
65
+
7
66
  ## [2.11.0] — 2026-06-21 — A2A interop hardening: spec-correct merchant status + verified x402-V2 conformance
8
67
 
9
68
  A2A transport correctness, after a **live cross-check against Google's official `x402` / `x402_a2a`
@@ -1610,6 +1669,10 @@ straight into your wallet. The API is small and self-contained.
1610
1669
  to your wallet; PipRail never holds funds.
1611
1670
  - `viem ^2.21` is a peer dependency. Node 20+ or a modern browser.
1612
1671
 
1672
+ [2.12.0]: https://www.npmjs.com/package/@piprail/sdk
1673
+ [2.11.0]: https://www.npmjs.com/package/@piprail/sdk
1674
+ [2.10.0]: https://www.npmjs.com/package/@piprail/sdk
1675
+ [2.9.0]: https://www.npmjs.com/package/@piprail/sdk
1613
1676
  [2.8.0]: https://www.npmjs.com/package/@piprail/sdk
1614
1677
  [2.7.0]: https://www.npmjs.com/package/@piprail/sdk
1615
1678
  [2.6.0]: https://www.npmjs.com/package/@piprail/sdk
package/dist/index.cjs CHANGED
@@ -149,11 +149,15 @@ var CHAINS = {
149
149
  // Binance-Peg (NOT EIP-3009) → the `exact` rail uses Permit2.
150
150
  USDC: { address: "0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d", decimals: 18, symbol: "USDC" },
151
151
  USDT: { address: "0x55d398326f99059fF775485246999027B3197955", decimals: 18, symbol: "USDT" },
152
- // FDUSD + USD1 ARE EIP-3009 (transferWithAuthorization) → the `exact` rail uses the gasless,
153
- // no-Permit2-approve path. Both hardcode EIP-712 domain version "1" (no version() — the SDK
154
- // derives it from DOMAIN_SEPARATOR). Verified on-chain (symbol/decimals/domain match).
152
+ // FDUSD, USD1 + U ARE EIP-3009 (transferWithAuthorization) → the `exact` rail uses the gasless,
153
+ // no-Permit2-approve path. All three hardcode EIP-712 domain version "1" (no version() — the
154
+ // SDK derives it from DOMAIN_SEPARATOR). Verified on-chain (symbol/decimals/domain match).
155
155
  FDUSD: { address: "0xc5f0f7b66764F6ec8C8Dff7BA683102295E16409", decimals: 18, symbol: "FDUSD" },
156
- USD1: { address: "0x8d0D000Ee44948FC98c9B98A4FA4921476f08B0d", decimals: 18, symbol: "USD1" }
156
+ USD1: { address: "0x8d0D000Ee44948FC98c9B98A4FA4921476f08B0d", decimals: 18, symbol: "USD1" },
157
+ // U (United Stables) — the first-listed token in Binance's own x402 set (U/USD1/USDT/USDC) and
158
+ // the BNB Agent Survival Pack settlement unit. EIP-3009 (domain name "United Stables",
159
+ // version "1" derived from DOMAIN_SEPARATOR 0x358738…1679b6). On-chain-verified 2026-06-21.
160
+ U: { address: "0xcE24439F2D9C6a2289F741120FE202248B666666", decimals: 18, symbol: "U" }
157
161
  }
158
162
  },
159
163
  avalanche: {
@@ -2118,7 +2122,8 @@ function makeEvmNetwork(resolved) {
2118
2122
  async estimateCost(accept) {
2119
2123
  const { decimals, symbol } = resolved.chain.nativeCurrency;
2120
2124
  if (accept.scheme === "exact") {
2121
- const permit2 = accept.extra.assetTransferMethod === "permit2";
2125
+ const m = accept.extra.assetTransferMethod;
2126
+ const permit2 = m === "permit2" || m === "permit2-exact";
2122
2127
  return _chunkMWBT7MCEcjs.nativeCost.call(void 0, {
2123
2128
  symbol,
2124
2129
  decimals,
@@ -2198,10 +2203,12 @@ function makeEvmNetwork(resolved) {
2198
2203
  // `assetTransferMethod`: `permit2` (any ERC-20 — e.g. Binance-Peg USDC on BNB, signs a
2199
2204
  // Permit2 witness transfer + lazily does the one-time approval) or `eip3009` (re-derives
2200
2205
  // the token's EIP-712 domain on-chain + signs transferWithAuthorization). Never broadcasts.
2206
+ // `permit2-exact` is Binance b402's foreign-dialect alias for `permit2` — treated identically.
2201
2207
  // Throws UnsupportedSchemeError for a contract signer (or a non-EIP-3009 token on the eip3009 path).
2202
2208
  async payExact(wallet, accept) {
2203
2209
  const a = wallet._native;
2204
- if (accept.extra.assetTransferMethod === "permit2") {
2210
+ const method = accept.extra.assetTransferMethod;
2211
+ if (method === "permit2" || method === "permit2-exact") {
2205
2212
  const { payload: payload2, payerFrom: payerFrom2, nonce: nonce2 } = await payPermit2Evm({
2206
2213
  publicClient,
2207
2214
  walletClient: a.walletClient,
@@ -3070,6 +3077,8 @@ var BUILTIN_DENOMS = {
3070
3077
  USDT: "USD",
3071
3078
  USD1: "USD",
3072
3079
  FDUSD: "USD",
3080
+ U: "USD",
3081
+ // United Stables — BNB EIP-3009 stablecoin (1:1 USDC/USDT/USD1-backed)
3073
3082
  RLUSD: "USD",
3074
3083
  EURC: "EUR"
3075
3084
  };
@@ -6332,25 +6341,25 @@ var KNOWN_FACILITATORS = {
6332
6341
  note: "Pieverse \u2014 keyless, sponsors gas (Monad USDC EIP-3009). LIVE-settled on Monad 2026-06-17 (tx 0x00cfeb93876e5ef57dcb002510038b7304913233ca286d7ab33c72a8b119eb0d)."
6333
6342
  }
6334
6343
  ],
6335
- // BNB Chain (eip155:56). Dexter keyless-settles the EVM EIP-3009 exact rail — but ONLY for BNB's
6336
- // EIP-3009 tokens (FDUSD / USD1); BNB's USDC/USDT are Binance-Peg (Permit2), which no facilitator
6344
+ // BNB Chain (eip155:56). Dexter + Pieverse keyless-settle the EVM EIP-3009 exact rail for BNB's
6345
+ // EIP-3009 tokens (FDUSD / USD1 / U); BNB's USDC/USDT are Binance-Peg (Permit2), which no facilitator
6337
6346
  // settles. Dexter also enforces a ~$0.003 dynamic settlement floor on BNB, so a sub-$0.003 payment
6338
6347
  // is rejected (amount_too_low) — fine for real prices, but the floor is real. LIVE-settled with
6339
- // FDUSD, buyer paid zero BNB — this beats the BNB token-overlap wall that blocked AEON/Pieverse.
6348
+ // FDUSD + U, buyer paid zero BNB — this beats the BNB token-overlap wall that blocked AEON/Pieverse.
6340
6349
  "eip155:56": [
6341
6350
  {
6342
6351
  url: "https://x402.dexter.cash",
6343
6352
  keyless: true,
6344
6353
  schemes: ["exact"],
6345
6354
  settles: ["eip3009"],
6346
- note: "Dexter \u2014 keyless, gas-sponsored. BNB EIP-3009 tokens FDUSD/USD1 ONLY (Binance-Peg USDC/USDT are Permit2 \u2192 not facilitator-settleable); ~$0.003 dynamic floor. LIVE-settled on BNB 2026-06-17 with FDUSD (tx 0x6d9eb4e4939f3f3c74cb19424cc7822d66ec8ed5c5c7c330d9f88a5f9ad59e9e)."
6355
+ note: "Dexter \u2014 keyless, gas-sponsored. BNB EIP-3009 tokens FDUSD/USD1/U (Binance-Peg USDC/USDT are Permit2 \u2192 not facilitator-settleable); ~$0.003 dynamic floor. LIVE-settled on BNB 2026-06-17 with FDUSD (tx 0x6d9eb4e4939f3f3c74cb19424cc7822d66ec8ed5c5c7c330d9f88a5f9ad59e9e); accepts U (verify confirmed 2026-06-21)."
6347
6356
  },
6348
6357
  {
6349
6358
  url: "https://facilitator.pieverse.io",
6350
6359
  keyless: true,
6351
6360
  schemes: ["exact"],
6352
6361
  settles: ["eip3009"],
6353
- note: "Pieverse \u2014 keyless, sponsors gas. BNB EIP-3009 tokens FDUSD/USD1 (same Binance-Peg caveat as Dexter). LIVE-settled on BNB 2026-06-17 with FDUSD (tx 0xb9c76affc45bd07a51559efd813ca71516fc30625478724476c2cf42fc2203d3) \u2014 a 2nd keyless BNB facilitator (failover for Dexter)."
6362
+ note: "Pieverse \u2014 keyless, sponsors gas. BNB EIP-3009 tokens FDUSD/USD1/U (same Binance-Peg caveat as Dexter). LIVE-settled on BNB with FDUSD 2026-06-17 (tx 0xb9c76affc45bd07a51559efd813ca71516fc30625478724476c2cf42fc2203d3) AND with the U / United Stables token 2026-06-21 (tx 0x2b3b8c51ae81df441551301c44a64652c84c796af3b9d03ec58ea38f1cb013d5, buyer 0 BNB) \u2014 a 2nd keyless BNB facilitator (failover for Dexter)."
6354
6363
  }
6355
6364
  ],
6356
6365
  // HyperEVM (eip155:999). Ultravioleta DAO keyless-settles the EVM EIP-3009 exact rail (HyperEVM's
@@ -7469,11 +7478,18 @@ var MAX_TASK_RECEIPTS = 64;
7469
7478
  var VERIFY_CODE_TO_A2A_ERROR = {
7470
7479
  payment_expired: "EXPIRED_PAYMENT",
7471
7480
  tx_already_used: "DUPLICATE_NONCE",
7481
+ // Genuine amount mismatches only — the spec defines INVALID_AMOUNT as "the payment amount does
7482
+ // not match the required amount" (a2a.md §9.1), so keep it strictly for amount errors.
7472
7483
  amount_too_low: "INVALID_AMOUNT",
7473
7484
  upto_settle_exceeds_max: "INVALID_AMOUNT",
7474
7485
  signature_invalid: "INVALID_SIGNATURE",
7475
- transfer_not_found: "INVALID_AMOUNT",
7476
- wrong_recipient: "INVALID_AMOUNT",
7486
+ // NOT amount mismatches — a proof for an unoffered asset/network, or paid to the wrong recipient.
7487
+ // The spec's 7-member enum (errors.py x402ErrorCode) has no WRONG_RECIPIENT/TRANSFER_NOT_FOUND, so
7488
+ // these map to SETTLEMENT_FAILED — its explicit catch-all "the transaction failed on-chain for a
7489
+ // reason other than the above" (a2a.md §9.1) — never INVALID_AMOUNT, which would mislead a buyer
7490
+ // into retrying with a corrected amount. The raw PipRail code still rides in extensions.piprail.
7491
+ transfer_not_found: "SETTLEMENT_FAILED",
7492
+ wrong_recipient: "SETTLEMENT_FAILED",
7477
7493
  tx_reverted: "SETTLEMENT_FAILED",
7478
7494
  tx_not_found: "EXPIRED_PAYMENT",
7479
7495
  insufficient_confirmations: "EXPIRED_PAYMENT",
@@ -7556,7 +7572,7 @@ function createA2APaymentHandler(options) {
7556
7572
  const store = _nullishCoalesce(options.taskStore, () => ( defaultTaskStore()));
7557
7573
  function appendReceipt(taskId, entry) {
7558
7574
  const prior = _nullishCoalesce(_optionalChain([store, 'access', _138 => _138.get, 'call', _139 => _139(taskId), 'optionalAccess', _140 => _140.receipts]), () => ( []));
7559
- const isDup = "success" in entry && entry.success === true && prior.some((r) => "transaction" in r && r.transaction === entry.transaction);
7575
+ const isDup = "success" in entry && entry.success === true && entry.transaction !== "" && prior.some((r) => "transaction" in r && r.transaction === entry.transaction);
7560
7576
  const next = isDup ? prior : [...prior, entry];
7561
7577
  const receipts = next.length > MAX_TASK_RECEIPTS ? next.slice(-MAX_TASK_RECEIPTS) : next;
7562
7578
  store.set(taskId, { receipts }, ttlMs);
@@ -7586,7 +7602,7 @@ function createA2APaymentHandler(options) {
7586
7602
  const network = _nullishCoalesce(attempted, () => ( singleNetworkOf(result.challenge)));
7587
7603
  const receipts = appendReceiptFailed(taskId, result.error, result.detail, network);
7588
7604
  const metadata = {
7589
- [A2A_STATUS_KEY]: "payment-required",
7605
+ [A2A_STATUS_KEY]: "payment-failed",
7590
7606
  [A2A_ERROR_KEY]: toA2AErrorCode(result.error),
7591
7607
  [A2A_REQUIRED_KEY]: result.challenge,
7592
7608
  ...toA2APaymentReceipts(receipts)
package/dist/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
- import { C as Caip2, X as X402AcceptEntry, x as X402AnyAccept, z as X402ExactAcceptEntry, d as ExactPaymentPayloadAny, p as SignedReceipt, w as VerifyResult, G as X402UptoAcceptEntry, n as Permit2UptoPaymentPayload, v as SpendSummary, y as X402Challenge, D as X402Receipt, S as SettleOutcome, u as SpendStore, s as SpendLedger, t as SpendRecord, o as PipRailReceipt, V as VerifyErrorCode, a as AssetId, A as AddressId, P as PaidReceipt } from './ledger-OQos-tmj.cjs';
2
- export { E as EXT_OFFER_RECEIPT, b as ExactAuthorizationWire, c as ExactPaymentPayload, H as HEADER_REQUIRED, e as HEADER_RESPONSE, f as HEADER_RESPONSE_V1, g as HEADER_SIGNATURE, h as HEADER_SIGNATURE_V1, i as ParsedExactPayment, j as ParsedUptoPayment, k as Permit2Authorization, l as Permit2PaymentPayload, m as Permit2UptoAuthorization, q as SpendAssetTotal, r as SpendDenomTotal, B as X402PaymentSignature, F as X402ResourceObject, I as buildChallengeHeader, J as buildExactSignatureHeader, K as buildReceiptExtension, L as buildReceiptHeader, M as buildSignatureHeader, N as buildUptoSignatureHeader, O as decodeBase64Json, Q as memorySpendStore, R as parseChallenge, T as parseExactObject, U as parseExactPaymentHeader, W as parseReceipt, Y as parseReceiptExtension, Z as parseSettleResponse, _ as parseSignatureHeader, $ as parseSignatureObject, a0 as parseUptoObject, a1 as parseUptoPaymentHeader, a2 as pickAccept } from './ledger-OQos-tmj.cjs';
1
+ import { C as Caip2, X as X402AcceptEntry, x as X402AnyAccept, z as X402ExactAcceptEntry, d as ExactPaymentPayloadAny, p as SignedReceipt, w as VerifyResult, G as X402UptoAcceptEntry, n as Permit2UptoPaymentPayload, v as SpendSummary, y as X402Challenge, D as X402Receipt, S as SettleOutcome, u as SpendStore, s as SpendLedger, t as SpendRecord, o as PipRailReceipt, V as VerifyErrorCode, a as AssetId, A as AddressId, P as PaidReceipt } from './ledger-mF_SoiDB.cjs';
2
+ export { E as EXT_OFFER_RECEIPT, b as ExactAuthorizationWire, c as ExactPaymentPayload, H as HEADER_REQUIRED, e as HEADER_RESPONSE, f as HEADER_RESPONSE_V1, g as HEADER_SIGNATURE, h as HEADER_SIGNATURE_V1, i as ParsedExactPayment, j as ParsedUptoPayment, k as Permit2Authorization, l as Permit2PaymentPayload, m as Permit2UptoAuthorization, q as SpendAssetTotal, r as SpendDenomTotal, B as X402PaymentSignature, F as X402ResourceObject, I as buildChallengeHeader, J as buildExactSignatureHeader, K as buildReceiptExtension, L as buildReceiptHeader, M as buildSignatureHeader, N as buildUptoSignatureHeader, O as decodeBase64Json, Q as memorySpendStore, R as parseChallenge, T as parseExactObject, U as parseExactPaymentHeader, W as parseReceipt, Y as parseReceiptExtension, Z as parseSettleResponse, _ as parseSignatureHeader, $ as parseSignatureObject, a0 as parseUptoObject, a1 as parseUptoPaymentHeader, a2 as pickAccept } from './ledger-mF_SoiDB.cjs';
3
3
  import * as viem_zksync from 'viem/zksync';
4
4
  import * as abitype from 'abitype';
5
5
  import * as viem_chains from 'viem/chains';
@@ -740,9 +740,7 @@ declare const CHAINS: {
740
740
  } | {
741
741
  blockHash: `0x${string}` | null;
742
742
  blockNumber: bigint | null;
743
- blockTimestamp
744
- /** EVM chain id, e.g. 5000 for Mantle. */
745
- ? /** EVM chain id, e.g. 5000 for Mantle. */: bigint | undefined;
743
+ blockTimestamp?: bigint | undefined;
746
744
  from: abitype.Address;
747
745
  gas: bigint;
748
746
  hash: viem.Hash;
@@ -986,6 +984,11 @@ declare const CHAINS: {
986
984
  decimals: number;
987
985
  symbol: string;
988
986
  };
987
+ U: {
988
+ address: "0xcE24439F2D9C6a2289F741120FE202248B666666";
989
+ decimals: number;
990
+ symbol: string;
991
+ };
989
992
  };
990
993
  };
991
994
  avalanche: {
@@ -2454,9 +2457,7 @@ declare const CHAINS: {
2454
2457
  chainId: number;
2455
2458
  type: "eip7702";
2456
2459
  gasPrice?: undefined | undefined;
2457
- maxFeePerBlobGas
2458
- /** JSON-RPC endpoint. */
2459
- ? /** JSON-RPC endpoint. */: undefined | undefined;
2460
+ maxFeePerBlobGas?: undefined | undefined;
2460
2461
  maxFeePerGas: bigint;
2461
2462
  maxPriorityFeePerGas: bigint;
2462
2463
  l1BatchNumber: bigint | null;
@@ -3293,7 +3294,15 @@ declare const CHAINS: {
3293
3294
  maxPriorityFeePerGas: bigint;
3294
3295
  isSystemTx?: undefined | undefined;
3295
3296
  mint?: undefined | undefined;
3296
- sourceHash?: undefined | undefined;
3297
+ sourceHash
3298
+ /**
3299
+ * Normalise a `ChainInput` (+ optional rpc override) into the
3300
+ * `{ chain, chainId, rpcUrl, tokens }` the wallet and verifier need.
3301
+ */
3302
+ ? /**
3303
+ * Normalise a `ChainInput` (+ optional rpc override) into the
3304
+ * `{ chain, chainId, rpcUrl, tokens }` the wallet and verifier need.
3305
+ */: undefined | undefined;
3297
3306
  } | {
3298
3307
  blockHash: `0x${string}` | null;
3299
3308
  blockNumber: bigint | null;
@@ -7825,11 +7834,11 @@ declare const PERMIT2_UPTO_WITNESS_TYPES: {
7825
7834
  declare function renderLandingPage(sd: SelfDescription): string;
7826
7835
 
7827
7836
  /**
7828
- * Minimal, DUCK-TYPED Google Agent2Agent (A2A) shapes — the structural surface the
7829
- * PipRail A2A transport reads/writes, and NOTHING more. Like `ExpressLikeRequest` in
7830
- * `server.ts`, these declare only the fields the adapter touches, so any A2A runtime's
7831
- * objects (the official `@a2a-js/sdk`, ADK, or a hand-rolled JSON-RPC handler) satisfy
7832
- * them structurally — **with ZERO `@a2a` dependency**.
7837
+ * Minimal, DUCK-TYPED Agent2Agent (A2A) shapes — the structural surface the PipRail A2A
7838
+ * transport reads/writes, and NOTHING more. Like `ExpressLikeRequest` in `server.ts`, these
7839
+ * declare only the fields the adapter touches, so any A2A runtime's objects (the official
7840
+ * `@a2a-js/sdk` — `a2aproject` org, the Linux Foundation A2A project — ADK, or a hand-rolled
7841
+ * JSON-RPC handler) satisfy them structurally — **with ZERO `@a2a` dependency**.
7833
7842
  *
7834
7843
  * x402-over-A2A carries PipRail's existing `PaymentRequired`/`PaymentPayload`/
7835
7844
  * `SettlementResponse` envelopes inside A2A `Task`/`Message` `metadata`, keyed off five
@@ -7939,9 +7948,11 @@ interface A2ATaskRecord {
7939
7948
  }
7940
7949
 
7941
7950
  /**
7942
- * x402-over-A2A — the SELLER-side transport adapter (Google Agent2Agent).
7951
+ * x402-over-A2A — the SELLER-side transport adapter for the Agent2Agent (A2A) protocol.
7943
7952
  *
7944
- * A2A is x402's third official transport (alongside HTTP and MCP). It carries PipRail's
7953
+ * A2A is an open protocol (created by Google, now a Linux Foundation project — a2a-protocol.org;
7954
+ * official JS runtime `@a2a-js/sdk` from the `a2aproject` org). It is x402's third official transport
7955
+ * (alongside HTTP and MCP). It carries PipRail's
7945
7956
  * BYTE-IDENTICAL `PaymentRequired`/`PaymentPayload`/`SettlementResponse` envelopes inside
7946
7957
  * A2A `Task`/`Message` JSON-RPC `metadata` (five namespaced `x402.payment.*` keys) keyed
7947
7958
  * off a coarse A2A Task state — instead of base64 HTTP headers. It is a thin codec + adapter
@@ -7970,9 +7981,15 @@ interface A2ATaskRecord {
7970
7981
  * PaymentPayload byte-identically, while the legacy v0.1 `x402_a2a` package (x402Version 1,
7971
7982
  * `maxAmountRequired`, chain slugs) is bitrotted. Inbound v1 object-cores are absorbed for the
7972
7983
  * standard `exact` scheme; PipRail-native `onchain-proof` is always v2 (never sent v1-flat).
7973
- * • Merchant statuses are spec-bounded: `payment-required` (incl. a retryable re-challenge of a
7974
- * rejected proof) / `payment-completed` / `payment-failed`. `payment-rejected` + `payment-submitted`
7975
- * are CLIENT→merchant statuses we never emit.
7984
+ * • Merchant statuses are spec-bounded: `payment-required` (a genuine first/no-proof challenge) /
7985
+ * `payment-completed` / `payment-failed`. A SUBMITTED proof that fails verification (expired /
7986
+ * wrong-amount / replayed) emits `payment-failed` — the a2a.md §9 rule ("If a payment fails, the
7987
+ * server MUST set x402.payment.status to payment-failed") and its EXPIRED-signature example, which
7988
+ * Google's reference executor matches verbatim (`is_valid == false → record_payment_failure →
7989
+ * PAYMENT_FAILED`). Retryability rides on the A2A Task `state` (`input-required`), NOT the status —
7990
+ * so a rejection is `payment-failed` + `input-required` (retry) while a terminal settlement error is
7991
+ * `payment-failed` + `failed`. `payment-rejected` + `payment-submitted` are CLIENT→merchant statuses
7992
+ * we never emit.
7976
7993
  *
7977
7994
  * ── DEFERRED (NOT built here — see the x402-parity/03-a2a-transport plan) ──────
7978
7995
  * • Phase 4 — the A2A BUYER (`A2APayer`): the HTTP buyer mints the payload that rides A2A today.
@@ -8008,6 +8025,12 @@ declare function toA2AErrorCode(code: string): string;
8008
8025
  * Build the `input-required` payment-request Task carrying the challenge as RAW JSON
8009
8026
  * (NOT base64) in `x402.payment.required` + `x402.payment.status = 'payment-required'`.
8010
8027
  * `parts` are any human-readable message parts the merchant wants alongside it.
8028
+ *
8029
+ * Returns a **transport-metadata** Task: it carries the x402 `payment` state, NOT the host-owned
8030
+ * ids the `@a2a-js/sdk` runtime requires (`Task.contextId`, `status.message.messageId`/`parts`,
8031
+ * `artifacts[].artifactId` are all REQUIRED in the SDK's types). The host adapter stamps those
8032
+ * before publishing — see the `@a2a-js/sdk` mount in the docs / `examples/a2a-server/lib.mjs`.
8033
+ * This keeps the protocol layer chain- and runtime-agnostic (zero `@a2a` dependency).
8011
8034
  */
8012
8035
  declare function toA2APaymentRequired(taskId: string, challenge: X402Challenge, parts?: A2APart[]): A2ATask;
8013
8036
  /** Build the `x402.payment.receipts` metadata block (an ARRAY, append-only, B7 union). */
@@ -8069,9 +8092,15 @@ interface A2APaymentHandler {
8069
8092
  * `gate.verify()`'s `VerifyPaymentResult` exactly:
8070
8093
  * - no payload yet → Task `input-required` + `x402.payment.required`
8071
8094
  * - payload, verified+settled → Task `completed` + `x402.payment.receipts` + artifacts
8072
- * - payload, rejected → Task `input-required` re-challenge (RETRYABLE)
8095
+ * - payload, rejected → Task `input-required` re-challenge, status `payment-failed` (RETRYABLE)
8073
8096
  * - settle threw (relayer) → Task `failed` + `x402.payment.error` (NOT retryable)
8074
8097
  * - settle OK but fulfill threw → Task `completed` + receipt + error annotation (B7)
8098
+ *
8099
+ * The returned Task is **transport metadata only** — it carries the x402 `payment.*` state but NOT
8100
+ * the host-owned ids the `@a2a-js/sdk` runtime requires (`Task.contextId`, `status.message.messageId`
8101
+ * /`parts`, `artifacts[].artifactId`). The host adapter (the `AgentExecutor`) stamps those before
8102
+ * `bus.publish` — see the mount in the docs / `examples/a2a-server/lib.mjs`. This keeps the protocol
8103
+ * layer free of any `@a2a` dependency.
8075
8104
  */
8076
8105
  handleMessage(message: A2AMessage, taskId?: string): Promise<A2ATask>;
8077
8106
  /** Stamp the x402 extension into an AgentCard's `capabilities.extensions` (§2.4). */
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { C as Caip2, X as X402AcceptEntry, x as X402AnyAccept, z as X402ExactAcceptEntry, d as ExactPaymentPayloadAny, p as SignedReceipt, w as VerifyResult, G as X402UptoAcceptEntry, n as Permit2UptoPaymentPayload, v as SpendSummary, y as X402Challenge, D as X402Receipt, S as SettleOutcome, u as SpendStore, s as SpendLedger, t as SpendRecord, o as PipRailReceipt, V as VerifyErrorCode, a as AssetId, A as AddressId, P as PaidReceipt } from './ledger-OQos-tmj.js';
2
- export { E as EXT_OFFER_RECEIPT, b as ExactAuthorizationWire, c as ExactPaymentPayload, H as HEADER_REQUIRED, e as HEADER_RESPONSE, f as HEADER_RESPONSE_V1, g as HEADER_SIGNATURE, h as HEADER_SIGNATURE_V1, i as ParsedExactPayment, j as ParsedUptoPayment, k as Permit2Authorization, l as Permit2PaymentPayload, m as Permit2UptoAuthorization, q as SpendAssetTotal, r as SpendDenomTotal, B as X402PaymentSignature, F as X402ResourceObject, I as buildChallengeHeader, J as buildExactSignatureHeader, K as buildReceiptExtension, L as buildReceiptHeader, M as buildSignatureHeader, N as buildUptoSignatureHeader, O as decodeBase64Json, Q as memorySpendStore, R as parseChallenge, T as parseExactObject, U as parseExactPaymentHeader, W as parseReceipt, Y as parseReceiptExtension, Z as parseSettleResponse, _ as parseSignatureHeader, $ as parseSignatureObject, a0 as parseUptoObject, a1 as parseUptoPaymentHeader, a2 as pickAccept } from './ledger-OQos-tmj.js';
1
+ import { C as Caip2, X as X402AcceptEntry, x as X402AnyAccept, z as X402ExactAcceptEntry, d as ExactPaymentPayloadAny, p as SignedReceipt, w as VerifyResult, G as X402UptoAcceptEntry, n as Permit2UptoPaymentPayload, v as SpendSummary, y as X402Challenge, D as X402Receipt, S as SettleOutcome, u as SpendStore, s as SpendLedger, t as SpendRecord, o as PipRailReceipt, V as VerifyErrorCode, a as AssetId, A as AddressId, P as PaidReceipt } from './ledger-mF_SoiDB.js';
2
+ export { E as EXT_OFFER_RECEIPT, b as ExactAuthorizationWire, c as ExactPaymentPayload, H as HEADER_REQUIRED, e as HEADER_RESPONSE, f as HEADER_RESPONSE_V1, g as HEADER_SIGNATURE, h as HEADER_SIGNATURE_V1, i as ParsedExactPayment, j as ParsedUptoPayment, k as Permit2Authorization, l as Permit2PaymentPayload, m as Permit2UptoAuthorization, q as SpendAssetTotal, r as SpendDenomTotal, B as X402PaymentSignature, F as X402ResourceObject, I as buildChallengeHeader, J as buildExactSignatureHeader, K as buildReceiptExtension, L as buildReceiptHeader, M as buildSignatureHeader, N as buildUptoSignatureHeader, O as decodeBase64Json, Q as memorySpendStore, R as parseChallenge, T as parseExactObject, U as parseExactPaymentHeader, W as parseReceipt, Y as parseReceiptExtension, Z as parseSettleResponse, _ as parseSignatureHeader, $ as parseSignatureObject, a0 as parseUptoObject, a1 as parseUptoPaymentHeader, a2 as pickAccept } from './ledger-mF_SoiDB.js';
3
3
  import * as viem_zksync from 'viem/zksync';
4
4
  import * as abitype from 'abitype';
5
5
  import * as viem_chains from 'viem/chains';
@@ -740,9 +740,7 @@ declare const CHAINS: {
740
740
  } | {
741
741
  blockHash: `0x${string}` | null;
742
742
  blockNumber: bigint | null;
743
- blockTimestamp
744
- /** EVM chain id, e.g. 5000 for Mantle. */
745
- ? /** EVM chain id, e.g. 5000 for Mantle. */: bigint | undefined;
743
+ blockTimestamp?: bigint | undefined;
746
744
  from: abitype.Address;
747
745
  gas: bigint;
748
746
  hash: viem.Hash;
@@ -986,6 +984,11 @@ declare const CHAINS: {
986
984
  decimals: number;
987
985
  symbol: string;
988
986
  };
987
+ U: {
988
+ address: "0xcE24439F2D9C6a2289F741120FE202248B666666";
989
+ decimals: number;
990
+ symbol: string;
991
+ };
989
992
  };
990
993
  };
991
994
  avalanche: {
@@ -2454,9 +2457,7 @@ declare const CHAINS: {
2454
2457
  chainId: number;
2455
2458
  type: "eip7702";
2456
2459
  gasPrice?: undefined | undefined;
2457
- maxFeePerBlobGas
2458
- /** JSON-RPC endpoint. */
2459
- ? /** JSON-RPC endpoint. */: undefined | undefined;
2460
+ maxFeePerBlobGas?: undefined | undefined;
2460
2461
  maxFeePerGas: bigint;
2461
2462
  maxPriorityFeePerGas: bigint;
2462
2463
  l1BatchNumber: bigint | null;
@@ -3293,7 +3294,15 @@ declare const CHAINS: {
3293
3294
  maxPriorityFeePerGas: bigint;
3294
3295
  isSystemTx?: undefined | undefined;
3295
3296
  mint?: undefined | undefined;
3296
- sourceHash?: undefined | undefined;
3297
+ sourceHash
3298
+ /**
3299
+ * Normalise a `ChainInput` (+ optional rpc override) into the
3300
+ * `{ chain, chainId, rpcUrl, tokens }` the wallet and verifier need.
3301
+ */
3302
+ ? /**
3303
+ * Normalise a `ChainInput` (+ optional rpc override) into the
3304
+ * `{ chain, chainId, rpcUrl, tokens }` the wallet and verifier need.
3305
+ */: undefined | undefined;
3297
3306
  } | {
3298
3307
  blockHash: `0x${string}` | null;
3299
3308
  blockNumber: bigint | null;
@@ -7825,11 +7834,11 @@ declare const PERMIT2_UPTO_WITNESS_TYPES: {
7825
7834
  declare function renderLandingPage(sd: SelfDescription): string;
7826
7835
 
7827
7836
  /**
7828
- * Minimal, DUCK-TYPED Google Agent2Agent (A2A) shapes — the structural surface the
7829
- * PipRail A2A transport reads/writes, and NOTHING more. Like `ExpressLikeRequest` in
7830
- * `server.ts`, these declare only the fields the adapter touches, so any A2A runtime's
7831
- * objects (the official `@a2a-js/sdk`, ADK, or a hand-rolled JSON-RPC handler) satisfy
7832
- * them structurally — **with ZERO `@a2a` dependency**.
7837
+ * Minimal, DUCK-TYPED Agent2Agent (A2A) shapes — the structural surface the PipRail A2A
7838
+ * transport reads/writes, and NOTHING more. Like `ExpressLikeRequest` in `server.ts`, these
7839
+ * declare only the fields the adapter touches, so any A2A runtime's objects (the official
7840
+ * `@a2a-js/sdk` — `a2aproject` org, the Linux Foundation A2A project — ADK, or a hand-rolled
7841
+ * JSON-RPC handler) satisfy them structurally — **with ZERO `@a2a` dependency**.
7833
7842
  *
7834
7843
  * x402-over-A2A carries PipRail's existing `PaymentRequired`/`PaymentPayload`/
7835
7844
  * `SettlementResponse` envelopes inside A2A `Task`/`Message` `metadata`, keyed off five
@@ -7939,9 +7948,11 @@ interface A2ATaskRecord {
7939
7948
  }
7940
7949
 
7941
7950
  /**
7942
- * x402-over-A2A — the SELLER-side transport adapter (Google Agent2Agent).
7951
+ * x402-over-A2A — the SELLER-side transport adapter for the Agent2Agent (A2A) protocol.
7943
7952
  *
7944
- * A2A is x402's third official transport (alongside HTTP and MCP). It carries PipRail's
7953
+ * A2A is an open protocol (created by Google, now a Linux Foundation project — a2a-protocol.org;
7954
+ * official JS runtime `@a2a-js/sdk` from the `a2aproject` org). It is x402's third official transport
7955
+ * (alongside HTTP and MCP). It carries PipRail's
7945
7956
  * BYTE-IDENTICAL `PaymentRequired`/`PaymentPayload`/`SettlementResponse` envelopes inside
7946
7957
  * A2A `Task`/`Message` JSON-RPC `metadata` (five namespaced `x402.payment.*` keys) keyed
7947
7958
  * off a coarse A2A Task state — instead of base64 HTTP headers. It is a thin codec + adapter
@@ -7970,9 +7981,15 @@ interface A2ATaskRecord {
7970
7981
  * PaymentPayload byte-identically, while the legacy v0.1 `x402_a2a` package (x402Version 1,
7971
7982
  * `maxAmountRequired`, chain slugs) is bitrotted. Inbound v1 object-cores are absorbed for the
7972
7983
  * standard `exact` scheme; PipRail-native `onchain-proof` is always v2 (never sent v1-flat).
7973
- * • Merchant statuses are spec-bounded: `payment-required` (incl. a retryable re-challenge of a
7974
- * rejected proof) / `payment-completed` / `payment-failed`. `payment-rejected` + `payment-submitted`
7975
- * are CLIENT→merchant statuses we never emit.
7984
+ * • Merchant statuses are spec-bounded: `payment-required` (a genuine first/no-proof challenge) /
7985
+ * `payment-completed` / `payment-failed`. A SUBMITTED proof that fails verification (expired /
7986
+ * wrong-amount / replayed) emits `payment-failed` — the a2a.md §9 rule ("If a payment fails, the
7987
+ * server MUST set x402.payment.status to payment-failed") and its EXPIRED-signature example, which
7988
+ * Google's reference executor matches verbatim (`is_valid == false → record_payment_failure →
7989
+ * PAYMENT_FAILED`). Retryability rides on the A2A Task `state` (`input-required`), NOT the status —
7990
+ * so a rejection is `payment-failed` + `input-required` (retry) while a terminal settlement error is
7991
+ * `payment-failed` + `failed`. `payment-rejected` + `payment-submitted` are CLIENT→merchant statuses
7992
+ * we never emit.
7976
7993
  *
7977
7994
  * ── DEFERRED (NOT built here — see the x402-parity/03-a2a-transport plan) ──────
7978
7995
  * • Phase 4 — the A2A BUYER (`A2APayer`): the HTTP buyer mints the payload that rides A2A today.
@@ -8008,6 +8025,12 @@ declare function toA2AErrorCode(code: string): string;
8008
8025
  * Build the `input-required` payment-request Task carrying the challenge as RAW JSON
8009
8026
  * (NOT base64) in `x402.payment.required` + `x402.payment.status = 'payment-required'`.
8010
8027
  * `parts` are any human-readable message parts the merchant wants alongside it.
8028
+ *
8029
+ * Returns a **transport-metadata** Task: it carries the x402 `payment` state, NOT the host-owned
8030
+ * ids the `@a2a-js/sdk` runtime requires (`Task.contextId`, `status.message.messageId`/`parts`,
8031
+ * `artifacts[].artifactId` are all REQUIRED in the SDK's types). The host adapter stamps those
8032
+ * before publishing — see the `@a2a-js/sdk` mount in the docs / `examples/a2a-server/lib.mjs`.
8033
+ * This keeps the protocol layer chain- and runtime-agnostic (zero `@a2a` dependency).
8011
8034
  */
8012
8035
  declare function toA2APaymentRequired(taskId: string, challenge: X402Challenge, parts?: A2APart[]): A2ATask;
8013
8036
  /** Build the `x402.payment.receipts` metadata block (an ARRAY, append-only, B7 union). */
@@ -8069,9 +8092,15 @@ interface A2APaymentHandler {
8069
8092
  * `gate.verify()`'s `VerifyPaymentResult` exactly:
8070
8093
  * - no payload yet → Task `input-required` + `x402.payment.required`
8071
8094
  * - payload, verified+settled → Task `completed` + `x402.payment.receipts` + artifacts
8072
- * - payload, rejected → Task `input-required` re-challenge (RETRYABLE)
8095
+ * - payload, rejected → Task `input-required` re-challenge, status `payment-failed` (RETRYABLE)
8073
8096
  * - settle threw (relayer) → Task `failed` + `x402.payment.error` (NOT retryable)
8074
8097
  * - settle OK but fulfill threw → Task `completed` + receipt + error annotation (B7)
8098
+ *
8099
+ * The returned Task is **transport metadata only** — it carries the x402 `payment.*` state but NOT
8100
+ * the host-owned ids the `@a2a-js/sdk` runtime requires (`Task.contextId`, `status.message.messageId`
8101
+ * /`parts`, `artifacts[].artifactId`). The host adapter (the `AgentExecutor`) stamps those before
8102
+ * `bus.publish` — see the mount in the docs / `examples/a2a-server/lib.mjs`. This keeps the protocol
8103
+ * layer free of any `@a2a` dependency.
8075
8104
  */
8076
8105
  handleMessage(message: A2AMessage, taskId?: string): Promise<A2ATask>;
8077
8106
  /** Stamp the x402 extension into an AgentCard's `capabilities.extensions` (§2.4). */
package/dist/index.js CHANGED
@@ -149,11 +149,15 @@ var CHAINS = {
149
149
  // Binance-Peg (NOT EIP-3009) → the `exact` rail uses Permit2.
150
150
  USDC: { address: "0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d", decimals: 18, symbol: "USDC" },
151
151
  USDT: { address: "0x55d398326f99059fF775485246999027B3197955", decimals: 18, symbol: "USDT" },
152
- // FDUSD + USD1 ARE EIP-3009 (transferWithAuthorization) → the `exact` rail uses the gasless,
153
- // no-Permit2-approve path. Both hardcode EIP-712 domain version "1" (no version() — the SDK
154
- // derives it from DOMAIN_SEPARATOR). Verified on-chain (symbol/decimals/domain match).
152
+ // FDUSD, USD1 + U ARE EIP-3009 (transferWithAuthorization) → the `exact` rail uses the gasless,
153
+ // no-Permit2-approve path. All three hardcode EIP-712 domain version "1" (no version() — the
154
+ // SDK derives it from DOMAIN_SEPARATOR). Verified on-chain (symbol/decimals/domain match).
155
155
  FDUSD: { address: "0xc5f0f7b66764F6ec8C8Dff7BA683102295E16409", decimals: 18, symbol: "FDUSD" },
156
- USD1: { address: "0x8d0D000Ee44948FC98c9B98A4FA4921476f08B0d", decimals: 18, symbol: "USD1" }
156
+ USD1: { address: "0x8d0D000Ee44948FC98c9B98A4FA4921476f08B0d", decimals: 18, symbol: "USD1" },
157
+ // U (United Stables) — the first-listed token in Binance's own x402 set (U/USD1/USDT/USDC) and
158
+ // the BNB Agent Survival Pack settlement unit. EIP-3009 (domain name "United Stables",
159
+ // version "1" derived from DOMAIN_SEPARATOR 0x358738…1679b6). On-chain-verified 2026-06-21.
160
+ U: { address: "0xcE24439F2D9C6a2289F741120FE202248B666666", decimals: 18, symbol: "U" }
157
161
  }
158
162
  },
159
163
  avalanche: {
@@ -2118,7 +2122,8 @@ function makeEvmNetwork(resolved) {
2118
2122
  async estimateCost(accept) {
2119
2123
  const { decimals, symbol } = resolved.chain.nativeCurrency;
2120
2124
  if (accept.scheme === "exact") {
2121
- const permit2 = accept.extra.assetTransferMethod === "permit2";
2125
+ const m = accept.extra.assetTransferMethod;
2126
+ const permit2 = m === "permit2" || m === "permit2-exact";
2122
2127
  return nativeCost({
2123
2128
  symbol,
2124
2129
  decimals,
@@ -2198,10 +2203,12 @@ function makeEvmNetwork(resolved) {
2198
2203
  // `assetTransferMethod`: `permit2` (any ERC-20 — e.g. Binance-Peg USDC on BNB, signs a
2199
2204
  // Permit2 witness transfer + lazily does the one-time approval) or `eip3009` (re-derives
2200
2205
  // the token's EIP-712 domain on-chain + signs transferWithAuthorization). Never broadcasts.
2206
+ // `permit2-exact` is Binance b402's foreign-dialect alias for `permit2` — treated identically.
2201
2207
  // Throws UnsupportedSchemeError for a contract signer (or a non-EIP-3009 token on the eip3009 path).
2202
2208
  async payExact(wallet, accept) {
2203
2209
  const a = wallet._native;
2204
- if (accept.extra.assetTransferMethod === "permit2") {
2210
+ const method = accept.extra.assetTransferMethod;
2211
+ if (method === "permit2" || method === "permit2-exact") {
2205
2212
  const { payload: payload2, payerFrom: payerFrom2, nonce: nonce2 } = await payPermit2Evm({
2206
2213
  publicClient,
2207
2214
  walletClient: a.walletClient,
@@ -3070,6 +3077,8 @@ var BUILTIN_DENOMS = {
3070
3077
  USDT: "USD",
3071
3078
  USD1: "USD",
3072
3079
  FDUSD: "USD",
3080
+ U: "USD",
3081
+ // United Stables — BNB EIP-3009 stablecoin (1:1 USDC/USDT/USD1-backed)
3073
3082
  RLUSD: "USD",
3074
3083
  EURC: "EUR"
3075
3084
  };
@@ -6332,25 +6341,25 @@ var KNOWN_FACILITATORS = {
6332
6341
  note: "Pieverse \u2014 keyless, sponsors gas (Monad USDC EIP-3009). LIVE-settled on Monad 2026-06-17 (tx 0x00cfeb93876e5ef57dcb002510038b7304913233ca286d7ab33c72a8b119eb0d)."
6333
6342
  }
6334
6343
  ],
6335
- // BNB Chain (eip155:56). Dexter keyless-settles the EVM EIP-3009 exact rail — but ONLY for BNB's
6336
- // EIP-3009 tokens (FDUSD / USD1); BNB's USDC/USDT are Binance-Peg (Permit2), which no facilitator
6344
+ // BNB Chain (eip155:56). Dexter + Pieverse keyless-settle the EVM EIP-3009 exact rail for BNB's
6345
+ // EIP-3009 tokens (FDUSD / USD1 / U); BNB's USDC/USDT are Binance-Peg (Permit2), which no facilitator
6337
6346
  // settles. Dexter also enforces a ~$0.003 dynamic settlement floor on BNB, so a sub-$0.003 payment
6338
6347
  // is rejected (amount_too_low) — fine for real prices, but the floor is real. LIVE-settled with
6339
- // FDUSD, buyer paid zero BNB — this beats the BNB token-overlap wall that blocked AEON/Pieverse.
6348
+ // FDUSD + U, buyer paid zero BNB — this beats the BNB token-overlap wall that blocked AEON/Pieverse.
6340
6349
  "eip155:56": [
6341
6350
  {
6342
6351
  url: "https://x402.dexter.cash",
6343
6352
  keyless: true,
6344
6353
  schemes: ["exact"],
6345
6354
  settles: ["eip3009"],
6346
- note: "Dexter \u2014 keyless, gas-sponsored. BNB EIP-3009 tokens FDUSD/USD1 ONLY (Binance-Peg USDC/USDT are Permit2 \u2192 not facilitator-settleable); ~$0.003 dynamic floor. LIVE-settled on BNB 2026-06-17 with FDUSD (tx 0x6d9eb4e4939f3f3c74cb19424cc7822d66ec8ed5c5c7c330d9f88a5f9ad59e9e)."
6355
+ note: "Dexter \u2014 keyless, gas-sponsored. BNB EIP-3009 tokens FDUSD/USD1/U (Binance-Peg USDC/USDT are Permit2 \u2192 not facilitator-settleable); ~$0.003 dynamic floor. LIVE-settled on BNB 2026-06-17 with FDUSD (tx 0x6d9eb4e4939f3f3c74cb19424cc7822d66ec8ed5c5c7c330d9f88a5f9ad59e9e); accepts U (verify confirmed 2026-06-21)."
6347
6356
  },
6348
6357
  {
6349
6358
  url: "https://facilitator.pieverse.io",
6350
6359
  keyless: true,
6351
6360
  schemes: ["exact"],
6352
6361
  settles: ["eip3009"],
6353
- note: "Pieverse \u2014 keyless, sponsors gas. BNB EIP-3009 tokens FDUSD/USD1 (same Binance-Peg caveat as Dexter). LIVE-settled on BNB 2026-06-17 with FDUSD (tx 0xb9c76affc45bd07a51559efd813ca71516fc30625478724476c2cf42fc2203d3) \u2014 a 2nd keyless BNB facilitator (failover for Dexter)."
6362
+ note: "Pieverse \u2014 keyless, sponsors gas. BNB EIP-3009 tokens FDUSD/USD1/U (same Binance-Peg caveat as Dexter). LIVE-settled on BNB with FDUSD 2026-06-17 (tx 0xb9c76affc45bd07a51559efd813ca71516fc30625478724476c2cf42fc2203d3) AND with the U / United Stables token 2026-06-21 (tx 0x2b3b8c51ae81df441551301c44a64652c84c796af3b9d03ec58ea38f1cb013d5, buyer 0 BNB) \u2014 a 2nd keyless BNB facilitator (failover for Dexter)."
6354
6363
  }
6355
6364
  ],
6356
6365
  // HyperEVM (eip155:999). Ultravioleta DAO keyless-settles the EVM EIP-3009 exact rail (HyperEVM's
@@ -7469,11 +7478,18 @@ var MAX_TASK_RECEIPTS = 64;
7469
7478
  var VERIFY_CODE_TO_A2A_ERROR = {
7470
7479
  payment_expired: "EXPIRED_PAYMENT",
7471
7480
  tx_already_used: "DUPLICATE_NONCE",
7481
+ // Genuine amount mismatches only — the spec defines INVALID_AMOUNT as "the payment amount does
7482
+ // not match the required amount" (a2a.md §9.1), so keep it strictly for amount errors.
7472
7483
  amount_too_low: "INVALID_AMOUNT",
7473
7484
  upto_settle_exceeds_max: "INVALID_AMOUNT",
7474
7485
  signature_invalid: "INVALID_SIGNATURE",
7475
- transfer_not_found: "INVALID_AMOUNT",
7476
- wrong_recipient: "INVALID_AMOUNT",
7486
+ // NOT amount mismatches — a proof for an unoffered asset/network, or paid to the wrong recipient.
7487
+ // The spec's 7-member enum (errors.py x402ErrorCode) has no WRONG_RECIPIENT/TRANSFER_NOT_FOUND, so
7488
+ // these map to SETTLEMENT_FAILED — its explicit catch-all "the transaction failed on-chain for a
7489
+ // reason other than the above" (a2a.md §9.1) — never INVALID_AMOUNT, which would mislead a buyer
7490
+ // into retrying with a corrected amount. The raw PipRail code still rides in extensions.piprail.
7491
+ transfer_not_found: "SETTLEMENT_FAILED",
7492
+ wrong_recipient: "SETTLEMENT_FAILED",
7477
7493
  tx_reverted: "SETTLEMENT_FAILED",
7478
7494
  tx_not_found: "EXPIRED_PAYMENT",
7479
7495
  insufficient_confirmations: "EXPIRED_PAYMENT",
@@ -7556,7 +7572,7 @@ function createA2APaymentHandler(options) {
7556
7572
  const store = options.taskStore ?? defaultTaskStore();
7557
7573
  function appendReceipt(taskId, entry) {
7558
7574
  const prior = store.get(taskId)?.receipts ?? [];
7559
- const isDup = "success" in entry && entry.success === true && prior.some((r) => "transaction" in r && r.transaction === entry.transaction);
7575
+ const isDup = "success" in entry && entry.success === true && entry.transaction !== "" && prior.some((r) => "transaction" in r && r.transaction === entry.transaction);
7560
7576
  const next = isDup ? prior : [...prior, entry];
7561
7577
  const receipts = next.length > MAX_TASK_RECEIPTS ? next.slice(-MAX_TASK_RECEIPTS) : next;
7562
7578
  store.set(taskId, { receipts }, ttlMs);
@@ -7586,7 +7602,7 @@ function createA2APaymentHandler(options) {
7586
7602
  const network = attempted ?? singleNetworkOf(result.challenge);
7587
7603
  const receipts = appendReceiptFailed(taskId, result.error, result.detail, network);
7588
7604
  const metadata = {
7589
- [A2A_STATUS_KEY]: "payment-required",
7605
+ [A2A_STATUS_KEY]: "payment-failed",
7590
7606
  [A2A_ERROR_KEY]: toA2AErrorCode(result.error),
7591
7607
  [A2A_REQUIRED_KEY]: result.challenge,
7592
7608
  ...toA2APaymentReceipts(receipts)
@@ -92,7 +92,13 @@ interface X402ExactAcceptEntry {
92
92
  * authorizing exactly one NEP-141 `ft_transfer` to `payTo` (per `scheme_exact_near.md`); a
93
93
  * facilitator-selected relayer (`feePayer` below) prepays gas + the 1 yoctoNEAR and submits, so
94
94
  * the buyer holds zero NEAR. PipRail self-settles ALL. */
95
- assetTransferMethod: 'eip3009' | 'permit2' | 'svm' | 'algorand' | 'aptos' | 'near';
95
+ assetTransferMethod: 'eip3009' | 'permit2'
96
+ /** A FOREIGN-dialect alias for `'permit2'` — Binance's x402 ("b402") facilitator labels its
97
+ * EVM-Permit2 exact rail `'permit2-exact'` (the coinbase/x402 spec uses bare `'permit2'`).
98
+ * PipRail EMITS only `'permit2'`; it TOLERATES `'permit2-exact'` inbound so the buyer pays a
99
+ * Binance-issued 402 (the buyer treats the two as one rail). NB: settlement still requires the
100
+ * rail to bind PipRail's canonical x402ExactPermit2Proxy — see the buyer in drivers/evm. */
101
+ | 'permit2-exact' | 'svm' | 'algorand' | 'aptos' | 'near';
96
102
  /** EIP-712 domain name of the token. OPTIONAL per the exact-EVM scheme (only
97
103
  * `assetTransferMethod` is required) — a foreign rail may omit it. NEVER assumed
98
104
  * from the symbol (USDC's on-chain name() is "USD Coin", not "USDC"); a PipRail gate
@@ -92,7 +92,13 @@ interface X402ExactAcceptEntry {
92
92
  * authorizing exactly one NEP-141 `ft_transfer` to `payTo` (per `scheme_exact_near.md`); a
93
93
  * facilitator-selected relayer (`feePayer` below) prepays gas + the 1 yoctoNEAR and submits, so
94
94
  * the buyer holds zero NEAR. PipRail self-settles ALL. */
95
- assetTransferMethod: 'eip3009' | 'permit2' | 'svm' | 'algorand' | 'aptos' | 'near';
95
+ assetTransferMethod: 'eip3009' | 'permit2'
96
+ /** A FOREIGN-dialect alias for `'permit2'` — Binance's x402 ("b402") facilitator labels its
97
+ * EVM-Permit2 exact rail `'permit2-exact'` (the coinbase/x402 spec uses bare `'permit2'`).
98
+ * PipRail EMITS only `'permit2'`; it TOLERATES `'permit2-exact'` inbound so the buyer pays a
99
+ * Binance-issued 402 (the buyer treats the two as one rail). NB: settlement still requires the
100
+ * rail to bind PipRail's canonical x402ExactPermit2Proxy — see the buyer in drivers/evm. */
101
+ | 'permit2-exact' | 'svm' | 'algorand' | 'aptos' | 'near';
96
102
  /** EIP-712 domain name of the token. OPTIONAL per the exact-EVM scheme (only
97
103
  * `assetTransferMethod` is required) — a foreign rail may omit it. NEVER assumed
98
104
  * from the symbol (USDC's on-chain name() is "USD Coin", not "USDC"); a PipRail gate
package/dist/node.d.cts CHANGED
@@ -1,5 +1,5 @@
1
- import { u as SpendStore } from './ledger-OQos-tmj.cjs';
2
- export { Q as memorySpendStore } from './ledger-OQos-tmj.cjs';
1
+ import { u as SpendStore } from './ledger-mF_SoiDB.cjs';
2
+ export { Q as memorySpendStore } from './ledger-mF_SoiDB.cjs';
3
3
 
4
4
  /**
5
5
  * A durable {@link SpendStore} backed by a local JSONL file (one settled payment per
package/dist/node.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { u as SpendStore } from './ledger-OQos-tmj.js';
2
- export { Q as memorySpendStore } from './ledger-OQos-tmj.js';
1
+ import { u as SpendStore } from './ledger-mF_SoiDB.js';
2
+ export { Q as memorySpendStore } from './ledger-mF_SoiDB.js';
3
3
 
4
4
  /**
5
5
  * A durable {@link SpendStore} backed by a local JSONL file (one settled payment per
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@piprail/sdk",
3
- "version": "2.11.0",
3
+ "version": "2.13.0",
4
4
  "description": "Accept x402 crypto payments across 29 chains — every major EVM chain plus Solana, TON, Tron, NEAR, Sui, Aptos, Algorand, Stellar & XRPL — in a couple of lines. No backend, no database, no fee; payments settle straight to your wallet.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",