@piprail/sdk 1.15.1 → 1.18.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/dist/index.d.ts CHANGED
@@ -82,8 +82,12 @@ interface X402ExactAcceptEntry {
82
82
  payTo: AddressId;
83
83
  maxTimeoutSeconds: number;
84
84
  extra: {
85
- /** The exact-EVM transfer method. PipRail self-settles EIP-3009 today. */
86
- assetTransferMethod: 'eip3009';
85
+ /** The exact-EVM transfer method, per the x402 `exact` EVM scheme: `'eip3009'`
86
+ * for tokens with native `transferWithAuthorization`, or `'permit2'` for tokens
87
+ * WITHOUT it (e.g. Binance-Peg USDC on BNB) — the payer signs a Permit2 witness
88
+ * transfer whose `spender` is the canonical x402ExactPermit2Proxy and whose
89
+ * `witness.to` binds the recipient. PipRail self-settles BOTH. */
90
+ assetTransferMethod: 'eip3009' | 'permit2';
87
91
  /** EIP-712 domain name of the token. OPTIONAL per the exact-EVM scheme (only
88
92
  * `assetTransferMethod` is required) — a foreign rail may omit it. NEVER assumed
89
93
  * from the symbol (USDC's on-chain name() is "USD Coin", not "USDC"); a PipRail gate
@@ -154,22 +158,65 @@ interface ExactPaymentPayload {
154
158
  authorization: ExactAuthorizationWire;
155
159
  }
156
160
  /**
157
- * What {@link parseExactPaymentHeader} extracts from an inbound `exact` payment,
158
- * normalised across the v1 (`X-PAYMENT`, flat `{scheme,network,payload}`, network
159
- * slug) and v2 (`PAYMENT-SIGNATURE`, `{accepted,payload}`, CAIP-2 network) wire
160
- * shapes. `network`/`asset` are the CLIENT's claim used only to MATCH an offered
161
- * rail; the gate re-derives every verified field from its own trusted rail.
161
+ * The `permit2Authorization` a payer signs for the `permit2` variant of the x402
162
+ * `exact` EVM scheme (tokens without EIP-3009 e.g. Binance-Peg USDC on BNB). It is
163
+ * an EIP-712 `PermitWitnessTransferFrom` over the canonical Permit2 contract, whose
164
+ * `spender` is the canonical **x402ExactPermit2Proxy** and whose **witness** binds the
165
+ * recipient (`to`) + an activation time (`validAfter`). All numeric fields are DECIMAL
166
+ * strings on the wire (`permitted.amount`, `nonce`, `deadline`, `witness.validAfter`).
162
167
  */
163
- interface ParsedExactPayment {
168
+ interface Permit2Authorization {
169
+ /** What may be pulled: the ERC-20 token + the exact base-unit amount. */
170
+ permitted: {
171
+ token: string;
172
+ amount: string;
173
+ };
174
+ /** The payer (token owner). */
175
+ from: string;
176
+ /** The signature's allowed spender — the canonical x402ExactPermit2Proxy. */
177
+ spender: string;
178
+ /** Permit2 unordered nonce (a uint256, decimal string). Single-use via its bitmap. */
179
+ nonce: string;
180
+ /** Unix-seconds signature expiry. */
181
+ deadline: string;
182
+ /** The proxy-enforced witness: funds go ONLY to `to`, and not before `validAfter`. */
183
+ witness: {
184
+ to: string;
185
+ validAfter: string;
186
+ };
187
+ }
188
+ /** The `payload` a client sends for the `permit2` exact variant: a signature + its Permit2 authorization. */
189
+ interface Permit2PaymentPayload {
190
+ signature: string;
191
+ permit2Authorization: Permit2Authorization;
192
+ }
193
+ /** Either `exact`-rail payload shape — EIP-3009 (`authorization`) or Permit2 (`permit2Authorization`). */
194
+ type ExactPaymentPayloadAny = ExactPaymentPayload | Permit2PaymentPayload;
195
+ interface ParsedExactBase {
164
196
  x402Version: number;
165
197
  /** The client's claimed network (slug or CAIP-2) — for matching, not trust. */
166
198
  network: string;
167
199
  /** The client's claimed asset, if present (v2 `accepted.asset`). */
168
200
  asset?: string;
169
- payload: ExactPaymentPayload;
170
201
  /** The full decoded PaymentPayload, for verbatim forwarding to a facilitator (Mode B). */
171
202
  raw: Record<string, unknown>;
172
203
  }
204
+ /**
205
+ * What {@link parseExactPaymentHeader} extracts from an inbound `exact` payment,
206
+ * normalised across the v1 (`X-PAYMENT`, flat `{scheme,network,payload}`, network slug)
207
+ * and v2 (`PAYMENT-SIGNATURE`, `{accepted,payload}`, CAIP-2 network) wire shapes.
208
+ * `network`/`asset` are the CLIENT's claim — used only to MATCH an offered rail; the gate
209
+ * re-derives every verified field from its own trusted rail. A discriminated union on
210
+ * `method`, so narrowing on `method` narrows `payload`: `'eip3009'` → {@link ExactPaymentPayload}
211
+ * (`authorization`), `'permit2'` → {@link Permit2PaymentPayload} (`permit2Authorization`).
212
+ */
213
+ type ParsedExactPayment = (ParsedExactBase & {
214
+ method: 'eip3009';
215
+ payload: ExactPaymentPayload;
216
+ }) | (ParsedExactBase & {
217
+ method: 'permit2';
218
+ payload: Permit2PaymentPayload;
219
+ });
173
220
  interface X402Receipt {
174
221
  scheme: 'onchain-proof' | 'exact';
175
222
  /**
@@ -192,6 +239,37 @@ interface X402Receipt {
192
239
  payTo: AddressId;
193
240
  verifiedAt: string;
194
241
  }
242
+ /**
243
+ * The settled-payment record handed to a gate's `onPaid` hook — the wire
244
+ * {@link X402Receipt} plus the merchant-facing extras the gate already computed
245
+ * for the challenge, so a receipt handler never needs a second lookup to display
246
+ * or reconcile it: the token's `decimals`/`symbol`, the human `amountFormatted`
247
+ * (derived from the SETTLED base-unit `amount`, not the requested price), and a
248
+ * stable `idempotencyKey`.
249
+ *
250
+ * **Delivery contract — read this before persisting receipts.** `onPaid` is
251
+ * **at-least-once**: with a single in-memory replay store it fires exactly once
252
+ * per proof, but across instances sharing a custom `isUsed`/`markUsed` store two
253
+ * nodes can settle the same proof in a race and each fire once. Always **dedupe on
254
+ * `idempotencyKey`** (a unique index / upsert). It is also fire-and-forget by
255
+ * default — the gate does not block the response on it and a process crash between
256
+ * settlement and your side-effect drops that receipt. For durability either set
257
+ * `awaitOnPaid` (record before the 200) or push to a durable queue inside the hook;
258
+ * for a webhook, use {@link deliverReceipt} (signed, retried, idempotent).
259
+ */
260
+ interface PaidReceipt extends X402Receipt {
261
+ /** The token's on-chain decimals — pairs with `amount` so you can format without a lookup. */
262
+ decimals: number;
263
+ /** The token symbol when the gate knows it (e.g. `USDC`, `FDUSD`). */
264
+ symbol?: string;
265
+ /** Human-readable settled amount, e.g. `"0.05"` — `amount` / 10**`decimals`. */
266
+ amountFormatted: string;
267
+ /**
268
+ * A stable, unique key for this settlement (the settled `transaction` id). `onPaid`
269
+ * is at-least-once across instances — dedupe persistence and webhook delivery on this.
270
+ */
271
+ idempotencyKey: string;
272
+ }
195
273
  /**
196
274
  * Why a verification failed — a closed, chain-agnostic vocabulary. Every code a
197
275
  * driver returns is in this union; a client/agent branches on it rather than
@@ -236,7 +314,7 @@ declare function buildSignatureHeader(signature: X402PaymentSignature): string;
236
314
  */
237
315
  declare function buildExactSignatureHeader(input: {
238
316
  accepted: X402ExactAcceptEntry;
239
- payload: ExactPaymentPayload;
317
+ payload: ExactPaymentPayloadAny;
240
318
  }): string;
241
319
  /**
242
320
  * Parse the PAYMENT-REQUIRED challenge from a 402 response. Prefers the
@@ -610,7 +688,7 @@ declare const CHAINS: {
610
688
  value: bigint;
611
689
  yParity: number;
612
690
  accessList: viem.AccessList;
613
- authorizationList? /** EVM chain id, e.g. 5000 for Mantle. */: undefined | undefined;
691
+ authorizationList?: undefined | undefined;
614
692
  blobVersionedHashes?: undefined | undefined;
615
693
  chainId: number;
616
694
  type: "eip1559";
@@ -619,7 +697,7 @@ declare const CHAINS: {
619
697
  maxFeePerGas: bigint;
620
698
  maxPriorityFeePerGas: bigint;
621
699
  isSystemTx?: undefined | undefined;
622
- mint? /** Known tokens on this chain (empty for unknown custom chains). */: undefined | undefined;
700
+ mint?: undefined | undefined;
623
701
  sourceHash?: undefined | undefined;
624
702
  } | {
625
703
  blockHash: `0x${string}` | null;
@@ -1019,11 +1097,13 @@ declare const CHAINS: {
1019
1097
  maxPriorityFeePerGas: bigint;
1020
1098
  isSystemTx?: undefined | undefined;
1021
1099
  mint?: undefined | undefined;
1022
- sourceHash? /** Known tokens on this chain (empty for unknown custom chains). */: undefined | undefined;
1100
+ sourceHash?: undefined | undefined;
1023
1101
  } | {
1024
1102
  blockHash: `0x${string}` | null;
1025
1103
  blockNumber: bigint | null;
1026
- blockTimestamp?: bigint | undefined;
1104
+ blockTimestamp
1105
+ /** EVM chain id, e.g. 5000 for Mantle. */
1106
+ ? /** EVM chain id, e.g. 5000 for Mantle. */: bigint | undefined;
1027
1107
  from: abitype.Address;
1028
1108
  gas: bigint;
1029
1109
  hash: viem.Hash;
@@ -1257,6 +1337,16 @@ declare const CHAINS: {
1257
1337
  decimals: number;
1258
1338
  symbol: string;
1259
1339
  };
1340
+ FDUSD: {
1341
+ address: "0xc5f0f7b66764F6ec8C8Dff7BA683102295E16409";
1342
+ decimals: number;
1343
+ symbol: string;
1344
+ };
1345
+ USD1: {
1346
+ address: "0x8d0D000Ee44948FC98c9B98A4FA4921476f08B0d";
1347
+ decimals: number;
1348
+ symbol: string;
1349
+ };
1260
1350
  };
1261
1351
  };
1262
1352
  avalanche: {
@@ -2725,7 +2815,9 @@ declare const CHAINS: {
2725
2815
  chainId: number;
2726
2816
  type: "eip7702";
2727
2817
  gasPrice?: undefined | undefined;
2728
- maxFeePerBlobGas?: undefined | undefined;
2818
+ maxFeePerBlobGas
2819
+ /** JSON-RPC endpoint. */
2820
+ ? /** JSON-RPC endpoint. */: undefined | undefined;
2729
2821
  maxFeePerGas: bigint;
2730
2822
  maxPriorityFeePerGas: bigint;
2731
2823
  l1BatchNumber: bigint | null;
@@ -4230,7 +4322,7 @@ interface ResolvedNetwork {
4230
4322
  * and the nonce (for the client's spend record + a re-present-the-same-auth retry).
4231
4323
  */
4232
4324
  payExact?(wallet: WalletHandle, accept: X402ExactAcceptEntry): Promise<{
4233
- payload: ExactPaymentPayload;
4325
+ payload: ExactPaymentPayloadAny;
4234
4326
  accepted: X402ExactAcceptEntry;
4235
4327
  payerFrom: string;
4236
4328
  nonce: string;
@@ -4265,6 +4357,15 @@ interface ResolvedNetwork {
4265
4357
  name: string;
4266
4358
  version: string;
4267
4359
  } | null>;
4360
+ /**
4361
+ * OPTIONAL (EVM-only) — whether this chain can carry the **Permit2** transfer method
4362
+ * of the `exact` scheme: i.e. the canonical Permit2 **and** the `x402ExactPermit2Proxy`
4363
+ * are deployed here. The gate calls it to AVOID advertising a Permit2 `exact` rail it
4364
+ * could never settle (a non-EIP-3009 token on a proxy-less chain — e.g. Binance-Peg
4365
+ * USDC on a chain without the proxy). EIP-3009 needs no proxy, so this gates ONLY the
4366
+ * Permit2 fallback. Omitted (or `false`) ⇒ treat Permit2 as unavailable on this chain.
4367
+ */
4368
+ exactPermit2Supported?(): boolean;
4268
4369
  /**
4269
4370
  * OPTIONAL (EVM-only today) — verify a standard x402 `exact` (EIP-3009) payment
4270
4371
  * locally, then SELF-SETTLE it by broadcasting `transferWithAuthorization` from the
@@ -4280,7 +4381,7 @@ interface ResolvedNetwork {
4280
4381
  */
4281
4382
  settleExactSelf?(input: {
4282
4383
  relayer: WalletHandle;
4283
- payload: ExactPaymentPayload;
4384
+ payload: ExactPaymentPayloadAny;
4284
4385
  accept: X402ExactAcceptEntry;
4285
4386
  }): Promise<VerifyResult>;
4286
4387
  }
@@ -5627,16 +5728,18 @@ interface AcceptOption {
5627
5728
  rpcUrl?: string;
5628
5729
  }
5629
5730
  /**
5630
- * Opt into ALSO advertising a standard x402 `exact` rail (EIP-3009) beside the
5631
- * default `onchain-proof` rail, so ANY standard x402 client can pay this gate
5632
- * (dual-advertise). EVM + EIP-3009 tokens only (USDC, EURC NOT USDT, NOT native).
5633
- * Omitting `exact` leaves the gate byte-identical to today (onchain-proof only).
5731
+ * Opt into ALSO advertising a standard x402 `exact` rail beside the default
5732
+ * `onchain-proof` rail, so ANY standard x402 client can pay this gate (dual-advertise).
5733
+ * EVM ERC-20 only **EIP-3009** (USDC, EURC) or, for tokens without it, **Permit2**
5734
+ * (any ERC-20 e.g. Binance-Peg USDC on BNB, settled via the canonical
5735
+ * x402ExactPermit2Proxy). NOT native coins, NOT non-EVM chains. Omitting `exact` leaves
5736
+ * the gate byte-identical to today (onchain-proof only).
5634
5737
  *
5635
5738
  * Two settlement modes, both backendless (PipRail hosts nothing):
5636
- * - `settle: 'self'` — your own `relayer` key broadcasts `transferWithAuthorization`.
5637
- * You pay gas to RECEIVE (the inverse of onchain-proof, where the payer pays gas)
5638
- * and must keep the relayer funded. The signature binds `to`, so there's no
5639
- * redirect risk. This is the on-brand default for the rail.
5739
+ * - `settle: 'self'` — your own `relayer` key broadcasts the settle (EIP-3009's
5740
+ * `transferWithAuthorization`, or the proxy's `settle` for Permit2). You pay gas to
5741
+ * RECEIVE (the inverse of onchain-proof) and keep the relayer funded. The signature
5742
+ * binds the recipient, so there's no redirect risk. The on-brand default for the rail.
5640
5743
  * - `settle: { facilitator }` — delegate verify+settle to a third-party x402
5641
5744
  * facilitator YOU choose (Coinbase CDP, x402.org, …). No relayer key needed; the
5642
5745
  * facilitator pays gas. Also the only path onto Coinbase's Bazaar directory.
@@ -5649,6 +5752,10 @@ interface ExactRailOption {
5649
5752
  /** Required for `settle: 'self'` — the gas-paying relayer wallet: EVM `{ privateKey }`
5650
5753
  * or a bring-your-own `{ walletClient }`. (Distinct from `payTo`, the receive address.) */
5651
5754
  relayer?: unknown;
5755
+ /** Which exact-EVM transfer method to advertise. `'auto'` (default) uses EIP-3009 when the
5756
+ * token supports it, else Permit2 — so a non-EIP-3009 token like Binance-Peg USDC on BNB
5757
+ * "just works". Force `'eip3009'` or `'permit2'` to pin one. */
5758
+ method?: 'eip3009' | 'permit2' | 'auto';
5652
5759
  }
5653
5760
  interface RequirePaymentOptions {
5654
5761
  /**
@@ -5696,8 +5803,28 @@ interface RequirePaymentOptions {
5696
5803
  isUsed?: (ref: string) => boolean | Promise<boolean>;
5697
5804
  /** Replay hook — record a redeemed proof. */
5698
5805
  markUsed?: (ref: string) => void | Promise<void>;
5699
- /** Fired when a payment verifies successfully. */
5700
- onPaid?: (receipt: X402Receipt) => void;
5806
+ /**
5807
+ * Fired when a payment verifies successfully, with the enriched {@link PaidReceipt}.
5808
+ * May be **sync or async** — a throw OR a rejected promise is isolated (routed to
5809
+ * `onPaidError`), so the hook can never break the request or crash the process.
5810
+ * Fire-and-forget by default (the response is not blocked on it); set `awaitOnPaid`
5811
+ * to record the receipt before the resource is served. `onPaid` is **at-least-once**
5812
+ * across instances — dedupe on `receipt.idempotencyKey`. See {@link PaidReceipt}.
5813
+ */
5814
+ onPaid?: (receipt: PaidReceipt) => void | Promise<void>;
5815
+ /**
5816
+ * Observe a failure inside `onPaid` (sync throw or async rejection). Without it,
5817
+ * a failing receipt hook is swallowed silently — set this to log/alert/queue the
5818
+ * dropped receipt. Its own throws are also swallowed (it can never break a request).
5819
+ */
5820
+ onPaidError?: (error: unknown, receipt: PaidReceipt) => void;
5821
+ /**
5822
+ * Await `onPaid` before returning the paid result (and thus before the gated
5823
+ * resource is served), so "receipt recorded" is guaranteed on the happy path.
5824
+ * Default `false` (fire-and-forget — lower latency). A rejection is still isolated
5825
+ * via `onPaidError`; it never turns a settled payment into a 402.
5826
+ */
5827
+ awaitOnPaid?: boolean;
5701
5828
  /**
5702
5829
  * ALSO advertise a standard x402 `exact` rail (EIP-3009) so any standard x402
5703
5830
  * client can pay this gate — opt-in, EVM/EIP-3009 only. See {@link ExactRailOption}.
@@ -5867,6 +5994,85 @@ interface SettleViaFacilitatorInput extends FacilitatorConfig {
5867
5994
  */
5868
5995
  declare function settleViaFacilitator(input: SettleViaFacilitatorInput): Promise<VerifyResult>;
5869
5996
 
5997
+ /**
5998
+ * Reliable receipt delivery — the durable webhook a stateless gate can't be.
5999
+ *
6000
+ * `deliverReceipt(receipt, { url, secret })` POSTs a settled {@link PaidReceipt} to
6001
+ * YOUR OWN endpoint, with retries + exponential backoff, an HMAC-SHA256 signature,
6002
+ * and an idempotency key. It is the recommended body of an `onPaid` hook when you
6003
+ * want at-least-once delivery to a webhook instead of a fire-and-forget callback:
6004
+ *
6005
+ * createPaymentGate({
6006
+ * chain, token, amount, payTo,
6007
+ * awaitOnPaid: true, // record before serving
6008
+ * onPaid: (r) => deliverReceipt(r, {
6009
+ * url: process.env.RECEIPTS_WEBHOOK,
6010
+ * secret: process.env.RECEIPTS_SECRET, // signs the body
6011
+ * }),
6012
+ * })
6013
+ *
6014
+ * Charter note: PipRail hosts nothing — `url` is **your** endpoint. This is a pure
6015
+ * transport primitive (no chain libraries), isomorphic (global `fetch` + Web Crypto),
6016
+ * and it **never throws**: failures come back as `{ delivered: false, … }`, because a
6017
+ * delivery helper that threw would reintroduce the very crash `onPaid` isolation
6018
+ * prevents. The receiver verifies the signature and dedupes on the idempotency key.
6019
+ */
6020
+
6021
+ interface DeliverReceiptOptions {
6022
+ /** Your receiving endpoint. PipRail hosts nothing — this is your server. */
6023
+ url: string;
6024
+ /**
6025
+ * Shared secret. When set, the raw JSON body is signed HMAC-SHA256 and sent as
6026
+ * `<signatureHeader>: sha256=<hex>` so the receiver can verify authenticity.
6027
+ */
6028
+ secret?: string;
6029
+ /** Extra retry attempts after the first send (default 5 → up to 6 POSTs total). */
6030
+ retries?: number;
6031
+ /** Per-attempt timeout in ms (default 10000). An attempt that exceeds it is aborted + retried. */
6032
+ timeoutMs?: number;
6033
+ /** Extra request headers (merged; never override the signature/idempotency headers). */
6034
+ headers?: Record<string, string>;
6035
+ /** Header carrying the signature. Default `piprail-signature`. */
6036
+ signatureHeader?: string;
6037
+ /** Header carrying the dedupe key (= `receipt.idempotencyKey`). Default `idempotency-key`. */
6038
+ idempotencyHeader?: string;
6039
+ /** Backoff before retry N (1-based) in ms. Default jittered exponential (cap 30s). */
6040
+ backoff?: (attempt: number) => number;
6041
+ /** Injected `fetch` (tests / non-global-fetch runtimes). Defaults to the global. */
6042
+ fetchImpl?: typeof fetch;
6043
+ /** Observe each attempt (logging/metrics). Its own throws are ignored. */
6044
+ onAttempt?: (info: DeliverAttempt) => void;
6045
+ }
6046
+ /** One delivery attempt's outcome (passed to `onAttempt`). */
6047
+ interface DeliverAttempt {
6048
+ /** 1-based attempt number. */
6049
+ attempt: number;
6050
+ /** Did the endpoint return a 2xx? */
6051
+ ok: boolean;
6052
+ /** HTTP status, when a response was received. */
6053
+ status?: number;
6054
+ /** Transport/abort error message, when no response was received. */
6055
+ error?: string;
6056
+ /** Will another attempt follow? */
6057
+ willRetry: boolean;
6058
+ }
6059
+ /** The terminal result of `deliverReceipt` — it never throws, so always inspect this. */
6060
+ interface DeliverResult {
6061
+ /** True iff the endpoint returned a 2xx within the attempt budget. */
6062
+ delivered: boolean;
6063
+ /** Total POSTs made (1 + retries used). */
6064
+ attempts: number;
6065
+ /** Final HTTP status, when the last attempt got a response. */
6066
+ status?: number;
6067
+ /** Final error, when delivery failed (last transport error or a non-2xx summary). */
6068
+ error?: string;
6069
+ }
6070
+ /**
6071
+ * POST a settled receipt to your endpoint with retries, a timeout, an HMAC signature,
6072
+ * and an idempotency key. Never throws — returns a {@link DeliverResult}.
6073
+ */
6074
+ declare function deliverReceipt(receipt: PaidReceipt, options: DeliverReceiptOptions): Promise<DeliverResult>;
6075
+
5870
6076
  /**
5871
6077
  * The driver registry — the ONLY place the families meet. Routing decides a
5872
6078
  * family from the `chain` value (synchronously), then asks that family's
@@ -6157,8 +6363,13 @@ declare class UnsupportedNetworkError extends PipRailError {
6157
6363
  * the same funds to the same payTo and waste their own gas — no redirect risk.
6158
6364
  */
6159
6365
 
6160
- /** x402 network slug → EVM chain id, for the chains PipRail ships with EIP-3009
6161
- * USDC. Extend as needed; an unknown slug just won't be selected. */
6366
+ /** x402 network slug → EVM chain id, for the chains PipRail ships an exact-payable
6367
+ * stablecoin on EIP-3009 USDC/EURC on most, and **Permit2** on BNB (Binance-Peg
6368
+ * USDC isn't EIP-3009). This is a public REFERENCE/helper, NOT the runtime gate: the
6369
+ * gate offers `exact` on ANY EVM chain whose token is EIP-3009 (detected live via
6370
+ * `exactDomain`) or whose chain has the Permit2 proxy — so keep this list in sync with
6371
+ * what we've VERIFIED, but the rail isn't limited to it. An unknown slug → `null`.
6372
+ * (Matching uses CAIP-2 via `net.supports`.) */
6162
6373
  declare const EXACT_NETWORK_SLUGS: Readonly<Record<string, number>>;
6163
6374
  /** Resolve an x402 `exact` network slug (e.g. "base") to its EVM chain id. */
6164
6375
  declare function chainIdForExactNetwork(slug: string): number | null;
@@ -6359,22 +6570,119 @@ declare const eip3009Abi: readonly [{
6359
6570
  readonly outputs: readonly [{
6360
6571
  readonly type: "string";
6361
6572
  }];
6573
+ }, {
6574
+ readonly type: "function";
6575
+ readonly name: "DOMAIN_SEPARATOR";
6576
+ readonly stateMutability: "view";
6577
+ readonly inputs: readonly [];
6578
+ readonly outputs: readonly [{
6579
+ readonly type: "bytes32";
6580
+ }];
6362
6581
  }];
6363
6582
  /**
6364
- * Read an EIP-3009 token's true EIP-712 domain `{ name, version }` from the
6365
- * contract — what a payer must sign over. Returns `null` if the asset is NOT an
6366
- * EIP-3009 token (no `authorizationState`/`version` — e.g. USDT, native coin, a
6367
- * plain ERC-20), so the gate refuses to advertise a standard `exact` rail for it.
6583
+ * Read an EIP-3009 token's true EIP-712 domain `{ name, version }` from the contract — what a
6584
+ * payer must sign over. Returns `null` if the asset is NOT an EIP-3009 token (no
6585
+ * `authorizationState` — e.g. USDT, native coin, a plain ERC-20), so the caller falls back to
6586
+ * permit2 / onchain-proof.
6368
6587
  *
6369
- * The name is NEVER assumed from the symbol: canonical USDC's domain name is
6370
- * "USD Coin" (not "USDC"), and EURC's is "Euro Coin" on Ethereum/Avalanche but "EURC"
6371
- * on Base — proof that only the on-chain read is authoritative. `eip712Domain()`
6372
- * (EIP-5267) reverts on these proxies, so we read `name()`+`version()` and probe
6373
- * `authorizationState` to confirm EIP-3009 support.
6588
+ * The name is NEVER assumed from the symbol: canonical USDC's domain name is "USD Coin" (not
6589
+ * "USDC"), and EURC's is "Euro Coin" on Ethereum/Avalanche but "EURC" on Base — only the on-chain
6590
+ * read is authoritative.
6591
+ *
6592
+ * The version comes from `version()` when the token exposes it (canonical FiatToken — USDC is
6593
+ * "2"). Many EIP-3009 tokens HARDCODE the domain version and DON'T expose `version()` — e.g.
6594
+ * **FDUSD and USD1 on BNB Chain** (both "1"). For those we DERIVE the version by matching the
6595
+ * token's on-chain `DOMAIN_SEPARATOR()` against the standard 4-field domain for a small set of
6596
+ * common versions; a token with a non-standard / salted domain returns `null` (→ permit2 fallback).
6374
6597
  */
6375
6598
  declare function readExactDomain(publicClient: PublicClient, asset: string): Promise<{
6376
6599
  name: string;
6377
6600
  version: string;
6378
6601
  } | null>;
6379
6602
 
6380
- export { type AcceptOption, type AddressId, type AgentTool, type AlgorandToken, type AptosToken, type AssetId, type BazaarExtension, type BuildExactParams, CHAINS, type Caip2, type ChainFamily, type ChainInput, type ChainName, type ChainPreset, type ChainSelector, type ChallengeTriage, type ChallengeVerdict, type ConfirmInfo, ConfirmationTimeoutError, type CostEstimate, DIRECTORY_INFO, type DeclineReasonCode, type DirectoryInfo, type DiscoverOptions, type DiscoveredRail, type DiscoveredResource, type DiscoveryDescriptor, type DiscoverySigner, type DiscoverySource, type DomainClaim, type DomainVerification, EIP3009_TYPES, EXACT_NETWORK_SLUGS, type EvmToken, type ExactAccept, type ExactAuthorization, type ExactAuthorizationWire, type ExactPaymentPayload, type ExactRailOption, type ExpressLikeMiddleware, type ExpressLikeNext, type ExpressLikeRequest, type ExpressLikeResponse, type FacilitatorConfig, type FacilitatorPaymentRequirements, GENERATOR, HEADER_REQUIRED, HEADER_RESPONSE, HEADER_RESPONSE_V1, HEADER_SIGNATURE, HEADER_SIGNATURE_V1, InsufficientFundsError, InvalidEnvelopeError, type ListingVisibility, type ManifestInput, MaxRetriesExceededError, MissingDriverError, type NearToken, NoCompatibleAcceptError, NonReplayableBodyError, type OpenApiDocument, type OpenApiOperation, PIPRAIL_AGENT_GUIDE, type ParsedExactPayment, type PayBlocker, type PayOption, type PayWarning, PaymentDeclinedError, type PaymentDriver, type PaymentGate, type PaymentIntent, type PaymentPlan, type PaymentPolicy, type PaymentRail, type PaymentScheme, PaymentTimeoutError, PipRailClient, type PipRailClientOptions, type PipRailCostQuote, PipRailError, type PipRailEvent, type PipRailQuote, type PolicyDecision, type PolicyDenyCode, RecipientNotReadyError, type RecipientReason, type RegisterInput, type RegisterOptions, type RegisterOutcome, type RequirePaymentOptions, type ResolveOptions, type ResolvedChain, type ResolvedNetwork, type ResolvedToken, type ResourceDescription, type SearchOpenIndexesOptions, type SessionBudget, type SettleOutcome, type SettleViaFacilitatorInput, SettlementError, type SolanaToken, type SpendAssetTotal, type SpendRecord, type SpendRemaining, type SpendSummary, type StellarToken, type SuiToken, type TokenInfo, type TokenInput, type TonToken, type ToolAnnotations, type TronToken, UnknownTokenError, UnsupportedNetworkError, UnsupportedSchemeError, type VerifyErrorCode, type VerifyPaymentResult, type VerifyResult, type WalletBalance, type WalletHandle, type WalletInput, type WellKnownX402, WrongChainError, WrongFamilyError, type X402AcceptEntry, type X402AnyAccept, type X402Challenge, type X402DnsRecord, type X402ExactAcceptEntry, type X402InvalidBody, type X402PaymentSignature, type X402Receipt, type X402ResourceObject, type XrplToken, agentGuide, buildBazaarExtension, buildChallengeHeader, buildExactAuthorization, buildExactSignatureHeader, buildOpenApi, buildReceiptHeader, buildSignatureHeader, buildWellKnownX402, buildX402DnsTxt, chainIdForExactNetwork, claim402IndexDomain, classifyChallenge, createPaymentGate, decorateOutcome, eip3009Abi, encodeXPaymentHeader, evaluatePolicy, explainDecline, formatSpendReport, getDirectoryInfo, normalizeNetwork, parseChallenge, parseExactPaymentHeader, parseExactRequirements, parseReceipt, parseSettleResponse, parseSignatureHeader, paymentTools, pickAccept, planAcross, readExactDomain, register402Index, registerDriver, registerX402Scan, requirePayment, resolveChain, searchOpenIndexes, settleViaFacilitator, summarizePlan, toInsufficientFundsError, toInvalidBody, verify402IndexDomain };
6603
+ /**
6604
+ * ── EVM SECTION: x402 `exact` scheme, `permit2` variant — BUYER + SELLER ──────
6605
+ *
6606
+ * The companion to `exact.ts` for ERC-20 tokens that do NOT implement EIP-3009
6607
+ * `transferWithAuthorization` — most notably **Binance-Peg USDC/USDT on BNB Chain**
6608
+ * (no native Circle USDC exists on BNB). The x402 `exact` EVM scheme defines a second
6609
+ * `assetTransferMethod`, `"permit2"`, for exactly these tokens:
6610
+ *
6611
+ * • The payer signs an EIP-712 **`PermitWitnessTransferFrom`** over the canonical
6612
+ * **Permit2** contract, with `spender` = the canonical **x402ExactPermit2Proxy**
6613
+ * and a **witness** that binds the recipient (`to`) + an activation time
6614
+ * (`validAfter`). The buyer never broadcasts (and, after a one-time Permit2 approval,
6615
+ * spends ~0 gas) — the merchant/facilitator broadcasts.
6616
+ * • The merchant/facilitator settles by calling the **proxy's `settle(...)`**, which
6617
+ * calls `Permit2.permitWitnessTransferFrom`. Because the signed `spender` is the
6618
+ * proxy and the proxy forces `transferDetails.to == witness.to`, a relayer can only
6619
+ * push the signed funds to the signed recipient — no redirect risk (same guarantee
6620
+ * EIP-3009's `to`-binding gives us).
6621
+ *
6622
+ * Spec: github.com/coinbase/x402 `specs/schemes/exact/scheme_exact_evm.md` (the Permit2
6623
+ * method). Both contracts are canonical CREATE2 deployments (same address every EVM
6624
+ * chain) and are verified deployed on BNB. This module mirrors `exact.ts` file-for-file
6625
+ * (buyer {@link payPermit2Evm}; seller {@link verifyAndSettlePermit2Evm}); the EVM
6626
+ * driver routes to it on `accept.extra.assetTransferMethod === 'permit2'`.
6627
+ *
6628
+ * One-time setup: the payer must `approve(Permit2, max)` on the token ONCE
6629
+ * ({@link ensurePermit2Allowance} does this lazily) — after that, every payment is a
6630
+ * gasless signature. This is the only way `permit2` differs operationally from EIP-3009.
6631
+ */
6632
+
6633
+ /** Canonical Permit2 (Uniswap), same address on every EVM chain incl. BNB. */
6634
+ declare const PERMIT2_ADDRESS: "0x000000000022D473030F116dDEE9F6B43aC78BA3";
6635
+ /** Canonical x402ExactPermit2Proxy — the SAME CREATE2 address on every chain where it's been
6636
+ * deployed (see {@link PERMIT2_PROXY_CHAIN_IDS}; it is NOT on every EVM chain). It is the
6637
+ * `spender` the buyer signs over, and the contract the seller settles through; it enforces
6638
+ * `transferDetails.to == witness.to`, so funds can only reach the signed payTo. */
6639
+ declare const X402_EXACT_PERMIT2_PROXY: "0x402085c248EeA27D92E8b30b2C58ed07f9E20001";
6640
+ /** EVM chain ids where BOTH the canonical Permit2 AND the x402ExactPermit2Proxy are deployed —
6641
+ * i.e. where the **Permit2** transfer method of `exact` can actually settle. Verified on-chain
6642
+ * (`eth_getCode`, 2026-06-11). EIP-3009 needs NO proxy, so this gates only the Permit2 fallback;
6643
+ * on a non-EIP-3009 token on a chain absent here, the gate offers `onchain-proof` only rather
6644
+ * than an unsettleable Permit2 rail. The proxy is a permissionless CREATE2 deploy, so extend
6645
+ * this as it lands on more chains (re-verify before adding). */
6646
+ declare const PERMIT2_PROXY_CHAIN_IDS: ReadonlySet<number>;
6647
+ /** Whether a chain has the x402 Permit2 proxy deployed (→ can settle the Permit2 exact method). */
6648
+ declare function isPermit2ProxyChain(chainId: number): boolean;
6649
+ /**
6650
+ * EIP-712 type set for the x402 `permit2` exact method. MUST encode to exactly the type
6651
+ * string Permit2 reconstructs for `permitWitnessTransferFrom`:
6652
+ * `PermitWitnessTransferFrom(TokenPermissions permitted,address spender,uint256 nonce,uint256 deadline,Witness witness)TokenPermissions(address token,uint256 amount)Witness(address to,uint256 validAfter)`
6653
+ * (viem orders referenced structs alphabetically → TokenPermissions before Witness ✓.)
6654
+ */
6655
+ declare const PERMIT2_WITNESS_TYPES: {
6656
+ readonly PermitWitnessTransferFrom: readonly [{
6657
+ readonly name: "permitted";
6658
+ readonly type: "TokenPermissions";
6659
+ }, {
6660
+ readonly name: "spender";
6661
+ readonly type: "address";
6662
+ }, {
6663
+ readonly name: "nonce";
6664
+ readonly type: "uint256";
6665
+ }, {
6666
+ readonly name: "deadline";
6667
+ readonly type: "uint256";
6668
+ }, {
6669
+ readonly name: "witness";
6670
+ readonly type: "Witness";
6671
+ }];
6672
+ readonly TokenPermissions: readonly [{
6673
+ readonly name: "token";
6674
+ readonly type: "address";
6675
+ }, {
6676
+ readonly name: "amount";
6677
+ readonly type: "uint256";
6678
+ }];
6679
+ readonly Witness: readonly [{
6680
+ readonly name: "to";
6681
+ readonly type: "address";
6682
+ }, {
6683
+ readonly name: "validAfter";
6684
+ readonly type: "uint256";
6685
+ }];
6686
+ };
6687
+
6688
+ export { type AcceptOption, type AddressId, type AgentTool, type AlgorandToken, type AptosToken, type AssetId, type BazaarExtension, type BuildExactParams, CHAINS, type Caip2, type ChainFamily, type ChainInput, type ChainName, type ChainPreset, type ChainSelector, type ChallengeTriage, type ChallengeVerdict, type ConfirmInfo, ConfirmationTimeoutError, type CostEstimate, DIRECTORY_INFO, type DeclineReasonCode, type DeliverAttempt, type DeliverReceiptOptions, type DeliverResult, type DirectoryInfo, type DiscoverOptions, type DiscoveredRail, type DiscoveredResource, type DiscoveryDescriptor, type DiscoverySigner, type DiscoverySource, type DomainClaim, type DomainVerification, EIP3009_TYPES, EXACT_NETWORK_SLUGS, type EvmToken, type ExactAccept, type ExactAuthorization, type ExactAuthorizationWire, type ExactPaymentPayload, type ExactPaymentPayloadAny, type ExactRailOption, type ExpressLikeMiddleware, type ExpressLikeNext, type ExpressLikeRequest, type ExpressLikeResponse, type FacilitatorConfig, type FacilitatorPaymentRequirements, GENERATOR, HEADER_REQUIRED, HEADER_RESPONSE, HEADER_RESPONSE_V1, HEADER_SIGNATURE, HEADER_SIGNATURE_V1, InsufficientFundsError, InvalidEnvelopeError, type ListingVisibility, type ManifestInput, MaxRetriesExceededError, MissingDriverError, type NearToken, NoCompatibleAcceptError, NonReplayableBodyError, type OpenApiDocument, type OpenApiOperation, PERMIT2_ADDRESS, PERMIT2_PROXY_CHAIN_IDS, PERMIT2_WITNESS_TYPES, PIPRAIL_AGENT_GUIDE, type PaidReceipt, type ParsedExactPayment, type PayBlocker, type PayOption, type PayWarning, PaymentDeclinedError, type PaymentDriver, type PaymentGate, type PaymentIntent, type PaymentPlan, type PaymentPolicy, type PaymentRail, type PaymentScheme, PaymentTimeoutError, type Permit2Authorization, type Permit2PaymentPayload, PipRailClient, type PipRailClientOptions, type PipRailCostQuote, PipRailError, type PipRailEvent, type PipRailQuote, type PolicyDecision, type PolicyDenyCode, RecipientNotReadyError, type RecipientReason, type RegisterInput, type RegisterOptions, type RegisterOutcome, type RequirePaymentOptions, type ResolveOptions, type ResolvedChain, type ResolvedNetwork, type ResolvedToken, type ResourceDescription, type SearchOpenIndexesOptions, type SessionBudget, type SettleOutcome, type SettleViaFacilitatorInput, SettlementError, type SolanaToken, type SpendAssetTotal, type SpendRecord, type SpendRemaining, type SpendSummary, type StellarToken, type SuiToken, type TokenInfo, type TokenInput, type TonToken, type ToolAnnotations, type TronToken, UnknownTokenError, UnsupportedNetworkError, UnsupportedSchemeError, type VerifyErrorCode, type VerifyPaymentResult, type VerifyResult, type WalletBalance, type WalletHandle, type WalletInput, type WellKnownX402, WrongChainError, WrongFamilyError, type X402AcceptEntry, type X402AnyAccept, type X402Challenge, type X402DnsRecord, type X402ExactAcceptEntry, type X402InvalidBody, type X402PaymentSignature, type X402Receipt, type X402ResourceObject, X402_EXACT_PERMIT2_PROXY, type XrplToken, agentGuide, buildBazaarExtension, buildChallengeHeader, buildExactAuthorization, buildExactSignatureHeader, buildOpenApi, buildReceiptHeader, buildSignatureHeader, buildWellKnownX402, buildX402DnsTxt, chainIdForExactNetwork, claim402IndexDomain, classifyChallenge, createPaymentGate, decorateOutcome, deliverReceipt, eip3009Abi, encodeXPaymentHeader, evaluatePolicy, explainDecline, formatSpendReport, getDirectoryInfo, isPermit2ProxyChain, normalizeNetwork, parseChallenge, parseExactPaymentHeader, parseExactRequirements, parseReceipt, parseSettleResponse, parseSignatureHeader, paymentTools, pickAccept, planAcross, readExactDomain, register402Index, registerDriver, registerX402Scan, requirePayment, resolveChain, searchOpenIndexes, settleViaFacilitator, summarizePlan, toInsufficientFundsError, toInvalidBody, verify402IndexDomain };