@piprail/sdk 2.4.0 → 2.5.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,40 @@ 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.5.0] — 2026-06-18 — gasless NEAR `exact` rail (NEP-366 meta-transactions)
8
+
9
+ Additive and backward-compatible — defaults and the zero-config 402 stay byte-identical; pure-EVM
10
+ installs still never download a non-EVM library (NEAR + its borsh decoder stay lazy-loaded — verified:
11
+ the built EVM bundle has zero static non-EVM imports, only lazy chunks).
12
+
13
+ ### Added
14
+
15
+ - **NEAR `exact` rail — gasless for the buyer on a fifth family.** PipRail's `exact` scheme now covers
16
+ NEAR (NEP-141 tokens — USDC / USDT) via the ratified
17
+ [`scheme_exact_near`](https://github.com/x402-foundation/x402/blob/main/specs/schemes/exact/scheme_exact_near.md)
18
+ (x402 v2). The buyer signs a **NEP-366 `SignedDelegateAction`** authorizing exactly one `ft_transfer`
19
+ with a **full-access key** and never broadcasts it or holds any NEAR; a relayer wraps it, prepays the
20
+ gas + the 1 yoctoNEAR, and submits — the agent is **completely gasless**. Opt-in
21
+ (`schemes: ['onchain-proof', 'exact']`); native NEAR is **not** exact-payable (the scheme is over
22
+ `ft_transfer`) and stays `onchain-proof`. Proven on NEAR mainnet for both USDC and USDT.
23
+ - New `payExactNear` (buyer build/sign) and `verifyAndSettleExactNear` (seller verify + relay) driver
24
+ functions; `resolveExactRail` / `payExact` / `settleExactSelf` are now implemented for NEAR.
25
+ - **Self-settle today** (`exact: { settle: 'self', relayer: { accountId, key } }`): the merchant runs
26
+ a small funded relayer that pays the sub-cent settle gas — the buyer stays gasless, exactly like the
27
+ Solana / Algorand / Aptos self-settle. The **facilitator** path (`settle: { facilitator }`) is wired
28
+ and will work the moment a real NEAR x402 facilitator ships; **none does yet** (some advertise
29
+ `near:mainnet` in `/supported` without settling it), so `exact: true` deliberately excludes NEAR and
30
+ self-settle is the supported gasless-for-buyer config. See the NEAR chain doc for the caveat.
31
+ - **Sponsor fee-drain guard**: the relayer prepays both the gas and the attached deposit, so the gate
32
+ rejects any delegate whose attached `deposit` ≠ exactly 1 yoctoNEAR or whose `gas` exceeds the
33
+ 300 TGas cap (re-derived from the trusted rail) **before** the relayer signs.
34
+
35
+ ### Dependencies
36
+
37
+ - Added **`borsh` (`>=2 <3`) as an OPTIONAL peer dependency** — used only to decode the inbound NEAR
38
+ `SignedDelegateAction` during self-settle, lazy-loaded inside the NEAR driver. NEAR users already have
39
+ it via `near-api-js`; pure-EVM (and non-NEAR) installs never load it.
40
+
7
41
  ## [2.4.0] — 2026-06-17 — gasless Algorand & Aptos rails + keyless gasless on SIX chains (incl. Algorand & BNB)
8
42
 
9
43
  Additive and backward-compatible — defaults and the zero-config 402 stay byte-identical; pure-EVM
@@ -1347,6 +1381,7 @@ straight into your wallet. The API is small and self-contained.
1347
1381
  to your wallet; PipRail never holds funds.
1348
1382
  - `viem ^2.21` is a peer dependency. Node 20+ or a modern browser.
1349
1383
 
1384
+ [2.5.0]: https://www.npmjs.com/package/@piprail/sdk
1350
1385
  [2.4.0]: https://www.npmjs.com/package/@piprail/sdk
1351
1386
  [2.3.0]: https://www.npmjs.com/package/@piprail/sdk
1352
1387
  [2.2.0]: https://www.npmjs.com/package/@piprail/sdk
package/dist/index.cjs CHANGED
@@ -1396,7 +1396,7 @@ function chainIdFromNetwork(network) {
1396
1396
  const match = /^eip155:(\d+)$/.exec(network);
1397
1397
  if (!match || !match[1]) return null;
1398
1398
  const n = Number(match[1]);
1399
- return Number.isSafeInteger(n) ? n : null;
1399
+ return Number.isSafeInteger(n) && n > 0 ? n : null;
1400
1400
  }
1401
1401
  function buildChallengeHeader(challenge) {
1402
1402
  return toBase64Json(challenge);
@@ -1469,6 +1469,9 @@ function parseExactPaymentHeader(value) {
1469
1469
  const x402Version = typeof v.x402Version === "number" ? v.x402Version : 2;
1470
1470
  const asset = accepted && typeof accepted.asset === "string" ? accepted.asset : void 0;
1471
1471
  const base2 = { x402Version, network, ...asset ? { asset } : {}, raw: v };
1472
+ if (typeof payload.signedDelegateAction === "string") {
1473
+ return { ...base2, method: "near", payload: { signedDelegateAction: payload.signedDelegateAction } };
1474
+ }
1472
1475
  if (typeof payload.transaction === "string" && typeof payload.senderAuth === "string") {
1473
1476
  return { ...base2, method: "aptos", payload: { transaction: payload.transaction, senderAuth: payload.senderAuth } };
1474
1477
  }
@@ -1810,6 +1813,9 @@ function makeEvmNetwork(resolved) {
1810
1813
  if ("paymentGroup" in payload) {
1811
1814
  return { ok: false, error: "signature_invalid", detail: "An Algorand payload was submitted to an EVM exact rail." };
1812
1815
  }
1816
+ if ("signedDelegateAction" in payload) {
1817
+ return { ok: false, error: "signature_invalid", detail: "A NEAR payload was submitted to an EVM exact rail." };
1818
+ }
1813
1819
  return verifyAndSettleExactEvm({
1814
1820
  publicClient,
1815
1821
  walletClient: a.walletClient,
@@ -1906,7 +1912,7 @@ var loaders = {
1906
1912
  near: async () => {
1907
1913
  let mod;
1908
1914
  try {
1909
- mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./near-DI2I3MAV.cjs")));
1915
+ mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./near-H5AQ253I.cjs")));
1910
1916
  } catch (cause) {
1911
1917
  throw new (0, _chunkJG6KRAW6cjs.MissingDriverError)(
1912
1918
  `NEAR selected, but its package isn't installed. Run: npm install near-api-js`,
@@ -3242,7 +3248,7 @@ var PipRailClient = (_class2 = class {
3242
3248
  );
3243
3249
  if (schemes.includes("exact") && exactOnNet && typeof net.payExact !== "function") {
3244
3250
  throw new (0, _chunkJG6KRAW6cjs.UnsupportedSchemeError)(
3245
- `This 402 offers a standard 'exact' rail on ${net.network}, but the ${net.family} family can't pay 'exact' (supported on EVM, Solana + Algorand today), and no 'onchain-proof' rail was offered.`
3251
+ `This 402 offers a standard 'exact' rail on ${net.network}, but the ${net.family} family can't pay 'exact' (supported on EVM, Solana, Algorand + NEAR today), and no 'onchain-proof' rail was offered.`
3246
3252
  );
3247
3253
  }
3248
3254
  if (!schemes.includes("exact") && exactOnNet && typeof net.payExact === "function") {
@@ -3638,7 +3644,7 @@ var PipRailClient = (_class2 = class {
3638
3644
  async payExactRail(net, wallet, accept, url, init, quote) {
3639
3645
  if (!net.payExact) {
3640
3646
  throw new (0, _chunkJG6KRAW6cjs.UnsupportedSchemeError)(
3641
- `the ${net.family} family can't pay a standard 'exact' rail (supported on EVM, Solana + Algorand today).`
3647
+ `the ${net.family} family can't pay a standard 'exact' rail (supported on EVM, Solana, Algorand + NEAR today).`
3642
3648
  );
3643
3649
  }
3644
3650
  throwIfAborted(_optionalChain([init, 'optionalAccess', _48 => _48.signal]));
@@ -5061,6 +5067,17 @@ var KNOWN_FACILITATORS = {
5061
5067
  note: "Corbits \u2014 keyless, Solana-first fee-payer sponsor. LIVE-settled on Solana 2026-06-15 (tx BCreYer\u2026)."
5062
5068
  }
5063
5069
  ]
5070
+ // NEAR (near:mainnet) — DELIBERATELY UNSEEDED: no x402 facilitator settles NEAR yet.
5071
+ // The NEAR `exact` BUYER payload PipRail builds (drivers/near/exact.ts) is LIVE-PROVEN on mainnet —
5072
+ // a real NEP-366 meta-transaction settles a USDC/USDT ft_transfer gaslessly (buyer 0 NEAR, single-use
5073
+ // via the access-key nonce; relay txs CMnQJzrLvwk… USDT + BCCnVHbSCMY… USDC, 2026-06-18). What's
5074
+ // missing is the FACILITATOR side: the public x402-rs (which Ultravioleta DAO runs) has NO NEAR chain
5075
+ // crate (only eip155/solana/aptos), and UVD's `/verify` 400s on a near:mainnet request even though its
5076
+ // `/supported` ADVERTISES `near:mainnet` + feePayer `uvd-facilitator.near` — i.e. the listing is
5077
+ // aspirational, not settle-capable (verified 2026-06-18). So `exact: true` must NOT auto-pick a NEAR
5078
+ // facilitator. Seed here ONLY after a real keyless settle through a facilitator that actually
5079
+ // implements scheme_exact_near.md (THE RULE). Merchants can still pass an explicit
5080
+ // `exact: { settle: { facilitator } }` for any facilitator they've confirmed settles near:mainnet.
5064
5081
  };
5065
5082
  function knownFacilitatorsFor(network) {
5066
5083
  return _nullishCoalesce(KNOWN_FACILITATORS[network], () => ( []));
@@ -5476,6 +5493,12 @@ function createPaymentGate(options) {
5476
5493
  return t;
5477
5494
  }
5478
5495
  }).join("|");
5496
+ } else if ("signedDelegateAction" in exact.payload) {
5497
+ try {
5498
+ nonce = Buffer.from(exact.payload.signedDelegateAction, "base64").toString("base64");
5499
+ } catch (e41) {
5500
+ nonce = exact.payload.signedDelegateAction;
5501
+ }
5479
5502
  } else if ("permit2Authorization" in exact.payload) {
5480
5503
  evmAuth = exact.payload.permit2Authorization;
5481
5504
  nonce = evmAuth.nonce;
@@ -5494,7 +5517,7 @@ function createPaymentGate(options) {
5494
5517
  result = await spec.net.settleExactSelf({ relayer: mode.relayer, payload: exact.payload, accept });
5495
5518
  } else {
5496
5519
  const ftMethod = accept.extra.assetTransferMethod;
5497
- const needsFeePayer = ftMethod === "svm" || ftMethod === "algorand" || ftMethod === "aptos";
5520
+ const needsFeePayer = ftMethod === "svm" || ftMethod === "algorand" || ftMethod === "aptos" || ftMethod === "near";
5498
5521
  if (needsFeePayer && !accept.extra.feePayer) {
5499
5522
  throw new (0, _chunkJG6KRAW6cjs.SettlementError)(
5500
5523
  `exact settle: the ${ftMethod} facilitator rail is missing extra.feePayer (the gas sponsor) \u2014 cannot settle.`
@@ -5614,7 +5637,7 @@ async function signBody(secret, body) {
5614
5637
  const sig = await subtle.sign("HMAC", key, enc.encode(body));
5615
5638
  const hex = Array.from(new Uint8Array(sig)).map((b) => b.toString(16).padStart(2, "0")).join("");
5616
5639
  return `sha256=${hex}`;
5617
- } catch (e41) {
5640
+ } catch (e42) {
5618
5641
  return null;
5619
5642
  }
5620
5643
  }
@@ -5675,7 +5698,7 @@ async function deliverReceipt(receipt, options) {
5675
5698
  const willRetry = !ok && retryable && attempt < maxAttempts;
5676
5699
  try {
5677
5700
  _optionalChain([onAttempt, 'optionalCall', _91 => _91({ attempt, ok, ...status !== void 0 ? { status } : {}, ...error ? { error } : {}, willRetry })]);
5678
- } catch (e42) {
5701
+ } catch (e43) {
5679
5702
  }
5680
5703
  if (ok) return { delivered: true, attempts: attempt, status };
5681
5704
  if (!willRetry) {
package/dist/index.d.cts CHANGED
@@ -94,8 +94,11 @@ interface X402ExactAcceptEntry {
94
94
  * keyless facilitator) signs that fee txn + submits. **Aptos: `'aptos'`** — the payer signs a
95
95
  * fee-payer (sponsored) `primary_fungible_store::transfer` to `payTo` (per
96
96
  * `scheme_exact_aptos.md`); the gate (or a keyless facilitator) adds the fee-payer signature
97
- * + submits, paying gas. PipRail self-settles ALL. */
98
- assetTransferMethod: 'eip3009' | 'permit2' | 'svm' | 'algorand' | 'aptos';
97
+ * + submits, paying gas. **NEAR: `'near'`** — the payer signs a NEP-366 `SignedDelegateAction`
98
+ * authorizing exactly one NEP-141 `ft_transfer` to `payTo` (per `scheme_exact_near.md`); a
99
+ * facilitator-selected relayer (`feePayer` below) prepays gas + the 1 yoctoNEAR and submits, so
100
+ * the buyer holds zero NEAR. PipRail self-settles ALL. */
101
+ assetTransferMethod: 'eip3009' | 'permit2' | 'svm' | 'algorand' | 'aptos' | 'near';
99
102
  /** EIP-712 domain name of the token. OPTIONAL per the exact-EVM scheme (only
100
103
  * `assetTransferMethod` is required) — a foreign rail may omit it. NEVER assumed
101
104
  * from the symbol (USDC's on-chain name() is "USD Coin", not "USDC"); a PipRail gate
@@ -255,9 +258,24 @@ interface ExactAptosPaymentPayload {
255
258
  /** Base64 BCS-serialized buyer (sender) `AccountAuthenticator`. */
256
259
  senderAuth: string;
257
260
  }
261
+ /**
262
+ * The `payload` a client sends for the **NEAR `exact`** variant, per `scheme_exact_near.md`:
263
+ * a base64-encoded, Borsh-serialized NEP-366 `SignedDelegateAction` whose single delegated action
264
+ * is one NEP-141 `ft_transfer` (to `payTo`, the exact `amount`, `deposit: 1` yoctoNEAR). The buyer
265
+ * signs the delegate action with a FULL-ACCESS key (a function-call key can't attach the 1 yocto and
266
+ * is rejected); a facilitator-selected relayer wraps it, prepays gas + the yocto, and submits. The
267
+ * signed delegate action IS the proof — there's no separate authorization object (the NEAR analogue
268
+ * of EIP-3009's `authorization` / SVM's `transaction`). Its single self-contained string field also
269
+ * distinguishes it from every other family's payload shape.
270
+ */
271
+ interface ExactNearPaymentPayload {
272
+ /** Base64 of the Borsh-encoded NEP-366 `SignedDelegateAction` (one `ft_transfer`). */
273
+ signedDelegateAction: string;
274
+ }
258
275
  /** Any `exact`-rail payload shape — EIP-3009 (`authorization`), Permit2 (`permit2Authorization`),
259
- * SVM (`transaction`), Algorand (`paymentGroup`), or Aptos (`transaction` + `senderAuth`). */
260
- type ExactPaymentPayloadAny = ExactPaymentPayload | Permit2PaymentPayload | ExactSvmPaymentPayload | ExactAlgorandPaymentPayload | ExactAptosPaymentPayload;
276
+ * SVM (`transaction`), Algorand (`paymentGroup`), Aptos (`transaction` + `senderAuth`), or NEAR
277
+ * (`signedDelegateAction`). */
278
+ type ExactPaymentPayloadAny = ExactPaymentPayload | Permit2PaymentPayload | ExactSvmPaymentPayload | ExactAlgorandPaymentPayload | ExactAptosPaymentPayload | ExactNearPaymentPayload;
261
279
  interface ParsedExactBase {
262
280
  x402Version: number;
263
281
  /** The client's claimed network (slug or CAIP-2) — for matching, not trust. */
@@ -277,7 +295,8 @@ interface ParsedExactBase {
277
295
  * (`authorization`), `'permit2'` → {@link Permit2PaymentPayload} (`permit2Authorization`),
278
296
  * `'svm'` → {@link ExactSvmPaymentPayload} (`transaction`), `'algorand'` →
279
297
  * {@link ExactAlgorandPaymentPayload} (`paymentGroup`); `'aptos'` →
280
- * {@link ExactAptosPaymentPayload} (`transaction` + `senderAuth`).
298
+ * {@link ExactAptosPaymentPayload} (`transaction` + `senderAuth`); `'near'` →
299
+ * {@link ExactNearPaymentPayload} (`signedDelegateAction`).
281
300
  */
282
301
  type ParsedExactPayment = (ParsedExactBase & {
283
302
  method: 'eip3009';
@@ -294,6 +313,9 @@ type ParsedExactPayment = (ParsedExactBase & {
294
313
  }) | (ParsedExactBase & {
295
314
  method: 'aptos';
296
315
  payload: ExactAptosPaymentPayload;
316
+ }) | (ParsedExactBase & {
317
+ method: 'near';
318
+ payload: ExactNearPaymentPayload;
297
319
  });
298
320
  interface X402Receipt {
299
321
  scheme: 'onchain-proof' | 'exact';
@@ -4313,10 +4335,10 @@ interface DiscoverySigner {
4313
4335
  * chain-agnostic — it never names a family, it just merges `extra`.
4314
4336
  */
4315
4337
  interface ExactRailInfo {
4316
- method: 'eip3009' | 'permit2' | 'svm' | 'algorand' | 'aptos';
4338
+ method: 'eip3009' | 'permit2' | 'svm' | 'algorand' | 'aptos' | 'near';
4317
4339
  /** Family-specific `extra` keys merged into the exact accept (e.g. `{ name, version }`
4318
4340
  * for EVM EIP-3009, `{ feePayer, tokenProgram }` for Solana, `{ feePayer }` for
4319
- * Algorand/Aptos). */
4341
+ * Algorand/Aptos/NEAR). */
4320
4342
  extra?: Record<string, unknown>;
4321
4343
  }
4322
4344
  /**
@@ -6759,7 +6781,7 @@ interface KnownFacilitator {
6759
6781
  /** The x402 schemes it settles (today only `exact`). */
6760
6782
  schemes: ReadonlyArray<'exact'>;
6761
6783
  /** The exact transfer methods it can settle on this network. */
6762
- settles: ReadonlyArray<'eip3009' | 'permit2' | 'svm' | 'algorand' | 'aptos'>;
6784
+ settles: ReadonlyArray<'eip3009' | 'permit2' | 'svm' | 'algorand' | 'aptos' | 'near'>;
6763
6785
  /** A short human note (who it is / caveat). */
6764
6786
  note?: string;
6765
6787
  }
@@ -6780,7 +6802,7 @@ declare function knownFacilitatorsFor(network: Caip2): ReadonlyArray<KnownFacili
6780
6802
  * specific transfer `method`). Returns `undefined` when none is known — the `exact: true`
6781
6803
  * shorthand branches on that to throw a coverage-specific guidance error.
6782
6804
  */
6783
- declare function firstKeylessFacilitator(network: Caip2, method?: 'eip3009' | 'permit2' | 'svm' | 'algorand' | 'aptos'): KnownFacilitator | undefined;
6805
+ declare function firstKeylessFacilitator(network: Caip2, method?: 'eip3009' | 'permit2' | 'svm' | 'algorand' | 'aptos' | 'near'): KnownFacilitator | undefined;
6784
6806
 
6785
6807
  /**
6786
6808
  * Reliable receipt delivery — the durable webhook a stateless gate can't be.
package/dist/index.d.ts CHANGED
@@ -94,8 +94,11 @@ interface X402ExactAcceptEntry {
94
94
  * keyless facilitator) signs that fee txn + submits. **Aptos: `'aptos'`** — the payer signs a
95
95
  * fee-payer (sponsored) `primary_fungible_store::transfer` to `payTo` (per
96
96
  * `scheme_exact_aptos.md`); the gate (or a keyless facilitator) adds the fee-payer signature
97
- * + submits, paying gas. PipRail self-settles ALL. */
98
- assetTransferMethod: 'eip3009' | 'permit2' | 'svm' | 'algorand' | 'aptos';
97
+ * + submits, paying gas. **NEAR: `'near'`** — the payer signs a NEP-366 `SignedDelegateAction`
98
+ * authorizing exactly one NEP-141 `ft_transfer` to `payTo` (per `scheme_exact_near.md`); a
99
+ * facilitator-selected relayer (`feePayer` below) prepays gas + the 1 yoctoNEAR and submits, so
100
+ * the buyer holds zero NEAR. PipRail self-settles ALL. */
101
+ assetTransferMethod: 'eip3009' | 'permit2' | 'svm' | 'algorand' | 'aptos' | 'near';
99
102
  /** EIP-712 domain name of the token. OPTIONAL per the exact-EVM scheme (only
100
103
  * `assetTransferMethod` is required) — a foreign rail may omit it. NEVER assumed
101
104
  * from the symbol (USDC's on-chain name() is "USD Coin", not "USDC"); a PipRail gate
@@ -255,9 +258,24 @@ interface ExactAptosPaymentPayload {
255
258
  /** Base64 BCS-serialized buyer (sender) `AccountAuthenticator`. */
256
259
  senderAuth: string;
257
260
  }
261
+ /**
262
+ * The `payload` a client sends for the **NEAR `exact`** variant, per `scheme_exact_near.md`:
263
+ * a base64-encoded, Borsh-serialized NEP-366 `SignedDelegateAction` whose single delegated action
264
+ * is one NEP-141 `ft_transfer` (to `payTo`, the exact `amount`, `deposit: 1` yoctoNEAR). The buyer
265
+ * signs the delegate action with a FULL-ACCESS key (a function-call key can't attach the 1 yocto and
266
+ * is rejected); a facilitator-selected relayer wraps it, prepays gas + the yocto, and submits. The
267
+ * signed delegate action IS the proof — there's no separate authorization object (the NEAR analogue
268
+ * of EIP-3009's `authorization` / SVM's `transaction`). Its single self-contained string field also
269
+ * distinguishes it from every other family's payload shape.
270
+ */
271
+ interface ExactNearPaymentPayload {
272
+ /** Base64 of the Borsh-encoded NEP-366 `SignedDelegateAction` (one `ft_transfer`). */
273
+ signedDelegateAction: string;
274
+ }
258
275
  /** Any `exact`-rail payload shape — EIP-3009 (`authorization`), Permit2 (`permit2Authorization`),
259
- * SVM (`transaction`), Algorand (`paymentGroup`), or Aptos (`transaction` + `senderAuth`). */
260
- type ExactPaymentPayloadAny = ExactPaymentPayload | Permit2PaymentPayload | ExactSvmPaymentPayload | ExactAlgorandPaymentPayload | ExactAptosPaymentPayload;
276
+ * SVM (`transaction`), Algorand (`paymentGroup`), Aptos (`transaction` + `senderAuth`), or NEAR
277
+ * (`signedDelegateAction`). */
278
+ type ExactPaymentPayloadAny = ExactPaymentPayload | Permit2PaymentPayload | ExactSvmPaymentPayload | ExactAlgorandPaymentPayload | ExactAptosPaymentPayload | ExactNearPaymentPayload;
261
279
  interface ParsedExactBase {
262
280
  x402Version: number;
263
281
  /** The client's claimed network (slug or CAIP-2) — for matching, not trust. */
@@ -277,7 +295,8 @@ interface ParsedExactBase {
277
295
  * (`authorization`), `'permit2'` → {@link Permit2PaymentPayload} (`permit2Authorization`),
278
296
  * `'svm'` → {@link ExactSvmPaymentPayload} (`transaction`), `'algorand'` →
279
297
  * {@link ExactAlgorandPaymentPayload} (`paymentGroup`); `'aptos'` →
280
- * {@link ExactAptosPaymentPayload} (`transaction` + `senderAuth`).
298
+ * {@link ExactAptosPaymentPayload} (`transaction` + `senderAuth`); `'near'` →
299
+ * {@link ExactNearPaymentPayload} (`signedDelegateAction`).
281
300
  */
282
301
  type ParsedExactPayment = (ParsedExactBase & {
283
302
  method: 'eip3009';
@@ -294,6 +313,9 @@ type ParsedExactPayment = (ParsedExactBase & {
294
313
  }) | (ParsedExactBase & {
295
314
  method: 'aptos';
296
315
  payload: ExactAptosPaymentPayload;
316
+ }) | (ParsedExactBase & {
317
+ method: 'near';
318
+ payload: ExactNearPaymentPayload;
297
319
  });
298
320
  interface X402Receipt {
299
321
  scheme: 'onchain-proof' | 'exact';
@@ -4313,10 +4335,10 @@ interface DiscoverySigner {
4313
4335
  * chain-agnostic — it never names a family, it just merges `extra`.
4314
4336
  */
4315
4337
  interface ExactRailInfo {
4316
- method: 'eip3009' | 'permit2' | 'svm' | 'algorand' | 'aptos';
4338
+ method: 'eip3009' | 'permit2' | 'svm' | 'algorand' | 'aptos' | 'near';
4317
4339
  /** Family-specific `extra` keys merged into the exact accept (e.g. `{ name, version }`
4318
4340
  * for EVM EIP-3009, `{ feePayer, tokenProgram }` for Solana, `{ feePayer }` for
4319
- * Algorand/Aptos). */
4341
+ * Algorand/Aptos/NEAR). */
4320
4342
  extra?: Record<string, unknown>;
4321
4343
  }
4322
4344
  /**
@@ -6759,7 +6781,7 @@ interface KnownFacilitator {
6759
6781
  /** The x402 schemes it settles (today only `exact`). */
6760
6782
  schemes: ReadonlyArray<'exact'>;
6761
6783
  /** The exact transfer methods it can settle on this network. */
6762
- settles: ReadonlyArray<'eip3009' | 'permit2' | 'svm' | 'algorand' | 'aptos'>;
6784
+ settles: ReadonlyArray<'eip3009' | 'permit2' | 'svm' | 'algorand' | 'aptos' | 'near'>;
6763
6785
  /** A short human note (who it is / caveat). */
6764
6786
  note?: string;
6765
6787
  }
@@ -6780,7 +6802,7 @@ declare function knownFacilitatorsFor(network: Caip2): ReadonlyArray<KnownFacili
6780
6802
  * specific transfer `method`). Returns `undefined` when none is known — the `exact: true`
6781
6803
  * shorthand branches on that to throw a coverage-specific guidance error.
6782
6804
  */
6783
- declare function firstKeylessFacilitator(network: Caip2, method?: 'eip3009' | 'permit2' | 'svm' | 'algorand' | 'aptos'): KnownFacilitator | undefined;
6805
+ declare function firstKeylessFacilitator(network: Caip2, method?: 'eip3009' | 'permit2' | 'svm' | 'algorand' | 'aptos' | 'near'): KnownFacilitator | undefined;
6784
6806
 
6785
6807
  /**
6786
6808
  * Reliable receipt delivery — the durable webhook a stateless gate can't be.
package/dist/index.js CHANGED
@@ -1396,7 +1396,7 @@ function chainIdFromNetwork(network) {
1396
1396
  const match = /^eip155:(\d+)$/.exec(network);
1397
1397
  if (!match || !match[1]) return null;
1398
1398
  const n = Number(match[1]);
1399
- return Number.isSafeInteger(n) ? n : null;
1399
+ return Number.isSafeInteger(n) && n > 0 ? n : null;
1400
1400
  }
1401
1401
  function buildChallengeHeader(challenge) {
1402
1402
  return toBase64Json(challenge);
@@ -1469,6 +1469,9 @@ function parseExactPaymentHeader(value) {
1469
1469
  const x402Version = typeof v.x402Version === "number" ? v.x402Version : 2;
1470
1470
  const asset = accepted && typeof accepted.asset === "string" ? accepted.asset : void 0;
1471
1471
  const base2 = { x402Version, network, ...asset ? { asset } : {}, raw: v };
1472
+ if (typeof payload.signedDelegateAction === "string") {
1473
+ return { ...base2, method: "near", payload: { signedDelegateAction: payload.signedDelegateAction } };
1474
+ }
1472
1475
  if (typeof payload.transaction === "string" && typeof payload.senderAuth === "string") {
1473
1476
  return { ...base2, method: "aptos", payload: { transaction: payload.transaction, senderAuth: payload.senderAuth } };
1474
1477
  }
@@ -1810,6 +1813,9 @@ function makeEvmNetwork(resolved) {
1810
1813
  if ("paymentGroup" in payload) {
1811
1814
  return { ok: false, error: "signature_invalid", detail: "An Algorand payload was submitted to an EVM exact rail." };
1812
1815
  }
1816
+ if ("signedDelegateAction" in payload) {
1817
+ return { ok: false, error: "signature_invalid", detail: "A NEAR payload was submitted to an EVM exact rail." };
1818
+ }
1813
1819
  return verifyAndSettleExactEvm({
1814
1820
  publicClient,
1815
1821
  walletClient: a.walletClient,
@@ -1906,7 +1912,7 @@ var loaders = {
1906
1912
  near: async () => {
1907
1913
  let mod;
1908
1914
  try {
1909
- mod = await import("./near-MTYBCUYM.js");
1915
+ mod = await import("./near-OTPQD6BI.js");
1910
1916
  } catch (cause) {
1911
1917
  throw new MissingDriverError(
1912
1918
  `NEAR selected, but its package isn't installed. Run: npm install near-api-js`,
@@ -3242,7 +3248,7 @@ var PipRailClient = class {
3242
3248
  );
3243
3249
  if (schemes.includes("exact") && exactOnNet && typeof net.payExact !== "function") {
3244
3250
  throw new UnsupportedSchemeError(
3245
- `This 402 offers a standard 'exact' rail on ${net.network}, but the ${net.family} family can't pay 'exact' (supported on EVM, Solana + Algorand today), and no 'onchain-proof' rail was offered.`
3251
+ `This 402 offers a standard 'exact' rail on ${net.network}, but the ${net.family} family can't pay 'exact' (supported on EVM, Solana, Algorand + NEAR today), and no 'onchain-proof' rail was offered.`
3246
3252
  );
3247
3253
  }
3248
3254
  if (!schemes.includes("exact") && exactOnNet && typeof net.payExact === "function") {
@@ -3638,7 +3644,7 @@ var PipRailClient = class {
3638
3644
  async payExactRail(net, wallet, accept, url, init, quote) {
3639
3645
  if (!net.payExact) {
3640
3646
  throw new UnsupportedSchemeError(
3641
- `the ${net.family} family can't pay a standard 'exact' rail (supported on EVM, Solana + Algorand today).`
3647
+ `the ${net.family} family can't pay a standard 'exact' rail (supported on EVM, Solana, Algorand + NEAR today).`
3642
3648
  );
3643
3649
  }
3644
3650
  throwIfAborted(init?.signal);
@@ -5061,6 +5067,17 @@ var KNOWN_FACILITATORS = {
5061
5067
  note: "Corbits \u2014 keyless, Solana-first fee-payer sponsor. LIVE-settled on Solana 2026-06-15 (tx BCreYer\u2026)."
5062
5068
  }
5063
5069
  ]
5070
+ // NEAR (near:mainnet) — DELIBERATELY UNSEEDED: no x402 facilitator settles NEAR yet.
5071
+ // The NEAR `exact` BUYER payload PipRail builds (drivers/near/exact.ts) is LIVE-PROVEN on mainnet —
5072
+ // a real NEP-366 meta-transaction settles a USDC/USDT ft_transfer gaslessly (buyer 0 NEAR, single-use
5073
+ // via the access-key nonce; relay txs CMnQJzrLvwk… USDT + BCCnVHbSCMY… USDC, 2026-06-18). What's
5074
+ // missing is the FACILITATOR side: the public x402-rs (which Ultravioleta DAO runs) has NO NEAR chain
5075
+ // crate (only eip155/solana/aptos), and UVD's `/verify` 400s on a near:mainnet request even though its
5076
+ // `/supported` ADVERTISES `near:mainnet` + feePayer `uvd-facilitator.near` — i.e. the listing is
5077
+ // aspirational, not settle-capable (verified 2026-06-18). So `exact: true` must NOT auto-pick a NEAR
5078
+ // facilitator. Seed here ONLY after a real keyless settle through a facilitator that actually
5079
+ // implements scheme_exact_near.md (THE RULE). Merchants can still pass an explicit
5080
+ // `exact: { settle: { facilitator } }` for any facilitator they've confirmed settles near:mainnet.
5064
5081
  };
5065
5082
  function knownFacilitatorsFor(network) {
5066
5083
  return KNOWN_FACILITATORS[network] ?? [];
@@ -5476,6 +5493,12 @@ function createPaymentGate(options) {
5476
5493
  return t;
5477
5494
  }
5478
5495
  }).join("|");
5496
+ } else if ("signedDelegateAction" in exact.payload) {
5497
+ try {
5498
+ nonce = Buffer.from(exact.payload.signedDelegateAction, "base64").toString("base64");
5499
+ } catch {
5500
+ nonce = exact.payload.signedDelegateAction;
5501
+ }
5479
5502
  } else if ("permit2Authorization" in exact.payload) {
5480
5503
  evmAuth = exact.payload.permit2Authorization;
5481
5504
  nonce = evmAuth.nonce;
@@ -5494,7 +5517,7 @@ function createPaymentGate(options) {
5494
5517
  result = await spec.net.settleExactSelf({ relayer: mode.relayer, payload: exact.payload, accept });
5495
5518
  } else {
5496
5519
  const ftMethod = accept.extra.assetTransferMethod;
5497
- const needsFeePayer = ftMethod === "svm" || ftMethod === "algorand" || ftMethod === "aptos";
5520
+ const needsFeePayer = ftMethod === "svm" || ftMethod === "algorand" || ftMethod === "aptos" || ftMethod === "near";
5498
5521
  if (needsFeePayer && !accept.extra.feePayer) {
5499
5522
  throw new SettlementError(
5500
5523
  `exact settle: the ${ftMethod} facilitator rail is missing extra.feePayer (the gas sponsor) \u2014 cannot settle.`
@@ -8,6 +8,8 @@
8
8
 
9
9
 
10
10
 
11
+
12
+
11
13
  var _chunkJG6KRAW6cjs = require('./chunk-JG6KRAW6.cjs');
12
14
 
13
15
  // src/drivers/near/index.ts
@@ -15,6 +17,11 @@ var _nearapijs = require('near-api-js');
15
17
 
16
18
  // src/drivers/near/chains.ts
17
19
  var NEAR_DECIMALS = 24;
20
+ function isValidNearAccountId(id) {
21
+ if (id.startsWith("0x")) return false;
22
+ if (id.length < 2 || id.length > 64) return false;
23
+ return /^(([a-z\d]+[-_])*[a-z\d]+\.)*([a-z\d]+[-_])*[a-z\d]+$/.test(id);
24
+ }
18
25
  var NEAR_MAINNET = {
19
26
  caip2: "near:mainnet",
20
27
  defaultRpc: "https://free.rpc.fastnear.com",
@@ -92,6 +99,190 @@ function isNearAffordability(err) {
92
99
  return /not enough|doesn't have enough|does not have enough|lack ?balance|exceeds .*balance|insufficient/i.test(m);
93
100
  }
94
101
 
102
+ // src/drivers/near/exact.ts
103
+
104
+ var _borsh = require('borsh');
105
+ var FT_TRANSFER_GAS2 = 30000000000000n;
106
+ var ONE_YOCTO2 = 1n;
107
+ var ESTIMATED_BLOCK_SECONDS = 1;
108
+ var NONCE_BLOCK_MULTIPLIER = 1000000n;
109
+ async function payExactNear(input) {
110
+ const { signer, senderId, blockHeight, accessKeyNonce, accept } = input;
111
+ if (accept.asset === "native") {
112
+ throw new (0, _chunkJG6KRAW6cjs.UnsupportedSchemeError)(
113
+ "NEAR exact is NEP-141-only (an ft_transfer); native NEAR is not exact-payable. Pay via onchain-proof."
114
+ );
115
+ }
116
+ if (!isValidNearAccountId(accept.asset)) {
117
+ throw new (0, _chunkJG6KRAW6cjs.UnsupportedSchemeError)(`NEAR exact: asset "${accept.asset}" must be a NEP-141 contract account id.`);
118
+ }
119
+ if (!isValidNearAccountId(accept.payTo)) {
120
+ throw new (0, _chunkJG6KRAW6cjs.UnsupportedSchemeError)(`NEAR exact: payTo "${accept.payTo}" is not a valid NEAR account id.`);
121
+ }
122
+ if (!isValidNearAccountId(senderId)) {
123
+ throw new (0, _chunkJG6KRAW6cjs.UnsupportedSchemeError)(`NEAR exact: sender "${senderId}" is not a valid NEAR account id.`);
124
+ }
125
+ const t = accept.maxTimeoutSeconds;
126
+ if (!Number.isInteger(t) || t <= 0) {
127
+ throw new (0, _chunkJG6KRAW6cjs.UnsupportedSchemeError)("NEAR exact: maxTimeoutSeconds must be a positive integer.");
128
+ }
129
+ const timeoutBlocks = BigInt(Math.max(1, Math.ceil(t / ESTIMATED_BLOCK_SECONDS)));
130
+ const maxBlockHeight = blockHeight + timeoutBlocks;
131
+ const nonce = accessKeyNonce + 1n;
132
+ if (nonce >= blockHeight * NONCE_BLOCK_MULTIPLIER) {
133
+ throw new (0, _chunkJG6KRAW6cjs.UnsupportedSchemeError)(
134
+ "NEAR exact: the access-key nonce is at the protocol ceiling for this block height; cannot build a delegate action."
135
+ );
136
+ }
137
+ const publicKey = await signer.getPublicKey();
138
+ const action = _nearapijs.actions.functionCall(
139
+ "ft_transfer",
140
+ { receiver_id: accept.payTo, amount: accept.amount },
141
+ FT_TRANSFER_GAS2,
142
+ ONE_YOCTO2
143
+ );
144
+ const delegateAction = _nearapijs.buildDelegateAction.call(void 0, {
145
+ senderId,
146
+ receiverId: accept.asset,
147
+ actions: [action],
148
+ nonce,
149
+ maxBlockHeight,
150
+ publicKey
151
+ });
152
+ const { signedDelegate } = await signer.signDelegateAction(delegateAction);
153
+ const encoded = _nearapijs.encodeSignedDelegate.call(void 0, signedDelegate);
154
+ return {
155
+ payload: { signedDelegateAction: Buffer.from(encoded).toString("base64") },
156
+ payerFrom: senderId,
157
+ // A stable id for THIS authorization (single-use on-chain via the access-key nonce): the
158
+ // client records it as the spend ref and re-presents the SAME signed action on a retry.
159
+ nonce: `${senderId}:${nonce.toString()}`
160
+ };
161
+ }
162
+ var MAX_RELAY_GAS = 300000000000000n;
163
+ var b64decode = (s) => new Uint8Array(Buffer.from(s, "base64"));
164
+ function shorten(msg) {
165
+ const oneLine = msg.replace(/\s+/g, " ").trim();
166
+ return oneLine.length > 200 ? `${oneLine.slice(0, 200)}\u2026` : oneLine;
167
+ }
168
+ function fail(error, detail) {
169
+ return { ok: false, error, detail };
170
+ }
171
+ function verifyExactNear(payload, accept, currentBlockHeight) {
172
+ if (accept.asset === "native" || !isValidNearAccountId(accept.asset)) {
173
+ return fail("transfer_not_found", `NEAR exact rail asset "${accept.asset}" is not a NEP-141 contract.`);
174
+ }
175
+ if (typeof _optionalChain([payload, 'optionalAccess', _ => _.signedDelegateAction]) !== "string") {
176
+ return fail("signature_invalid", "NEAR exact payload is missing signedDelegateAction.");
177
+ }
178
+ let decoded;
179
+ try {
180
+ decoded = _borsh.deserialize.call(void 0, _nearapijs.SCHEMA.SignedDelegate, b64decode(payload.signedDelegateAction));
181
+ } catch (err) {
182
+ return fail("signature_invalid", `Unparseable SignedDelegateAction: ${shorten(err instanceof Error ? err.message : String(err))}.`);
183
+ }
184
+ const da = _optionalChain([decoded, 'optionalAccess', _2 => _2.delegateAction]);
185
+ const sig = _optionalChain([decoded, 'optionalAccess', _3 => _3.signature]);
186
+ if (!da || sig == null) return fail("signature_invalid", "SignedDelegateAction is missing its delegate action or signature.");
187
+ if (!Array.isArray(da.actions) || da.actions.length !== 1) {
188
+ return fail("transfer_not_found", `the delegate must carry exactly one action, got ${_nullishCoalesce(_optionalChain([da, 'access', _4 => _4.actions, 'optionalAccess', _5 => _5.length]), () => ( 0))}.`);
189
+ }
190
+ const fc = _optionalChain([da, 'access', _6 => _6.actions, 'access', _7 => _7[0], 'optionalAccess', _8 => _8.functionCall]);
191
+ if (!fc || fc.methodName !== "ft_transfer") {
192
+ return fail("transfer_not_found", `the delegated action is not an ft_transfer (got "${_nullishCoalesce(_optionalChain([fc, 'optionalAccess', _9 => _9.methodName]), () => ( "none"))}").`);
193
+ }
194
+ if (da.receiverId !== accept.asset) {
195
+ return fail("transfer_not_found", `delegate receiver ${da.receiverId} \u2260 token contract ${accept.asset}.`);
196
+ }
197
+ let args;
198
+ try {
199
+ args = JSON.parse(Buffer.from(_nullishCoalesce(fc.args, () => ( new Uint8Array()))).toString());
200
+ } catch (e2) {
201
+ return fail("transfer_not_found", "the ft_transfer args are not valid JSON.");
202
+ }
203
+ if (args.receiver_id !== accept.payTo) {
204
+ return fail("wrong_recipient", `ft_transfer pays ${String(args.receiver_id)}, not payTo ${accept.payTo}.`);
205
+ }
206
+ if (typeof args.amount !== "string" || !/^\d+$/.test(args.amount) || BigInt(args.amount) < BigInt(accept.amount)) {
207
+ return fail("amount_too_low", `ft_transfer pays ${String(args.amount)} of the token, required ${accept.amount}.`);
208
+ }
209
+ let deposit;
210
+ let gas;
211
+ try {
212
+ deposit = BigInt(_nullishCoalesce(fc.deposit, () => ( 0)));
213
+ gas = BigInt(_nullishCoalesce(fc.gas, () => ( 0)));
214
+ } catch (e3) {
215
+ return fail("signature_invalid", "the ft_transfer has a malformed gas/deposit.");
216
+ }
217
+ if (deposit !== ONE_YOCTO2) {
218
+ return fail("signature_invalid", `attached deposit ${deposit} \u2260 the required 1 yoctoNEAR (relayer drain guard).`);
219
+ }
220
+ if (gas > MAX_RELAY_GAS) {
221
+ return fail("signature_invalid", `delegated gas ${gas} exceeds the ${MAX_RELAY_GAS} cap (relayer drain guard).`);
222
+ }
223
+ if (currentBlockHeight !== null) {
224
+ let maxBlock;
225
+ try {
226
+ maxBlock = BigInt(_nullishCoalesce(da.maxBlockHeight, () => ( 0)));
227
+ } catch (e4) {
228
+ return fail("signature_invalid", "the delegate has a malformed max_block_height.");
229
+ }
230
+ if (maxBlock <= currentBlockHeight) {
231
+ return fail("payment_expired", `the delegate expired (max_block_height ${maxBlock} \u2264 current ${currentBlockHeight}).`);
232
+ }
233
+ }
234
+ if (!da.senderId || !isValidNearAccountId(String(da.senderId))) {
235
+ return fail("signature_invalid", `the delegate sender "${String(da.senderId)}" is not a valid NEAR account id.`);
236
+ }
237
+ return { ok: true, senderId: String(da.senderId), delegateAction: new (0, _nearapijs.DelegateAction)(da), signature: sig };
238
+ }
239
+ async function verifyAndSettleExactNear(input) {
240
+ const { client, payload, accept } = input;
241
+ let height = null;
242
+ try {
243
+ height = await client.currentBlockHeight();
244
+ } catch (e5) {
245
+ }
246
+ const v = verifyExactNear(payload, accept, height);
247
+ if (!v.ok) return v;
248
+ let result;
249
+ try {
250
+ result = await client.relay({ senderId: v.senderId, delegateAction: v.delegateAction, signature: v.signature });
251
+ } catch (err) {
252
+ const m = err instanceof Error ? err.message : String(err);
253
+ if (/invalid.*nonce|nonce.*used|DelegateActionInvalidNonce/i.test(m)) {
254
+ return fail("tx_already_used", `this delegate was already used (single-use nonce): ${shorten(m)}.`);
255
+ }
256
+ if (/expired|DelegateActionExpired|max_block_height|deadline/i.test(m)) {
257
+ return fail("payment_expired", `the delegate expired before it landed: ${shorten(m)}.`);
258
+ }
259
+ if (/not enough|insufficient|exceeded the prepaid gas|NotEnoughBalance|doesn't have enough|is not registered/i.test(m)) {
260
+ return fail("tx_reverted", `the ft_transfer would fail on chain: ${shorten(m)}.`);
261
+ }
262
+ throw new (0, _chunkJG6KRAW6cjs.SettlementError)(
263
+ `NEAR exact settle: the relayer could not submit the delegate (${shorten(m)}). The buyer's signed delegate is still valid \u2014 fund/fix the relayer and the buyer can re-present it.`,
264
+ { cause: err }
265
+ );
266
+ }
267
+ if (!result.innerSuccess) {
268
+ return fail("tx_reverted", `the ft_transfer receipt did not succeed on chain (tx ${result.txHash}).`);
269
+ }
270
+ return {
271
+ ok: true,
272
+ receipt: {
273
+ scheme: "exact",
274
+ success: true,
275
+ network: accept.network,
276
+ transaction: result.txHash,
277
+ asset: accept.asset,
278
+ amount: accept.amount,
279
+ payer: v.senderId,
280
+ payTo: accept.payTo,
281
+ verifiedAt: (/* @__PURE__ */ new Date()).toISOString()
282
+ }
283
+ };
284
+ }
285
+
95
286
  // src/drivers/near/verify.ts
96
287
  function parseFtTransferEvent(line) {
97
288
  const marker = "EVENT_JSON:";
@@ -102,7 +293,7 @@ function parseFtTransferEvent(line) {
102
293
  if (ev.standard === "nep141" && ev.event === "ft_transfer" && Array.isArray(ev.data)) {
103
294
  return ev.data;
104
295
  }
105
- } catch (e2) {
296
+ } catch (e6) {
106
297
  }
107
298
  return null;
108
299
  }
@@ -113,7 +304,7 @@ async function verifyNear(params) {
113
304
  let tx;
114
305
  try {
115
306
  tx = await reader.txStatus(hash, senderId);
116
- } catch (e3) {
307
+ } catch (e7) {
117
308
  return txNotFound(hash);
118
309
  }
119
310
  if (!tx) return txNotFound(hash);
@@ -134,7 +325,7 @@ async function verifyNear(params) {
134
325
  let paid2;
135
326
  try {
136
327
  paid2 = BigInt(_nullishCoalesce(tx.nativeDeposit, () => ( "0")));
137
- } catch (e4) {
328
+ } catch (e8) {
138
329
  paid2 = 0n;
139
330
  }
140
331
  if (paid2 < required) {
@@ -176,7 +367,7 @@ async function verifyNear(params) {
176
367
  if (d.new_owner_id === accept.payTo && (_nullishCoalesce(d.memo, () => ( ""))) === nonce) {
177
368
  try {
178
369
  paid += BigInt(_nullishCoalesce(d.amount, () => ( "0")));
179
- } catch (e5) {
370
+ } catch (e9) {
180
371
  }
181
372
  if (!payer) payer = _nullishCoalesce(d.old_owner_id, () => ( ""));
182
373
  }
@@ -253,11 +444,6 @@ var nearDriver = {
253
444
  return makeNearNetwork(NEAR_MAINNET, rpcUrl);
254
445
  }
255
446
  };
256
- function isValidNearAccountId(id) {
257
- if (id.startsWith("0x")) return false;
258
- if (id.length < 2 || id.length > 64) return false;
259
- return /^(([a-z\d]+[-_])*[a-z\d]+\.)*([a-z\d]+[-_])*[a-z\d]+$/.test(id);
260
- }
261
447
  function makeNearNetwork(preset, rpcUrl) {
262
448
  const provider = new (0, _nearapijs.JsonRpcProvider)({ url: rpcUrl });
263
449
  const network = preset.caip2;
@@ -276,18 +462,18 @@ function makeNearNetwork(preset, rpcUrl) {
276
462
  logs: _nullishCoalesce(r.outcome.logs, () => ( []))
277
463
  }));
278
464
  const txn = outcome.transaction;
279
- const receiverId = _optionalChain([txn, 'optionalAccess', _ => _.receiver_id]);
280
- const nativeDeposit = sumTransferDeposits(_optionalChain([txn, 'optionalAccess', _2 => _2.actions])).toString();
465
+ const receiverId = _optionalChain([txn, 'optionalAccess', _10 => _10.receiver_id]);
466
+ const nativeDeposit = sumTransferDeposits(_optionalChain([txn, 'optionalAccess', _11 => _11.actions])).toString();
281
467
  let timestampMs;
282
468
  try {
283
- const blockHash = _optionalChain([outcome, 'access', _3 => _3.transaction_outcome, 'optionalAccess', _4 => _4.block_hash]);
469
+ const blockHash = _optionalChain([outcome, 'access', _12 => _12.transaction_outcome, 'optionalAccess', _13 => _13.block_hash]);
284
470
  if (blockHash) {
285
471
  const block = await provider.viewBlock({ blockId: blockHash });
286
472
  const header = block.header;
287
- const ns = _nullishCoalesce(_optionalChain([header, 'optionalAccess', _5 => _5.timestamp_nanosec]), () => ( (_optionalChain([header, 'optionalAccess', _6 => _6.timestamp]) != null ? String(header.timestamp) : void 0)));
473
+ const ns = _nullishCoalesce(_optionalChain([header, 'optionalAccess', _14 => _14.timestamp_nanosec]), () => ( (_optionalChain([header, 'optionalAccess', _15 => _15.timestamp]) != null ? String(header.timestamp) : void 0)));
288
474
  if (ns != null) timestampMs = Number(BigInt(ns) / 1000000n);
289
475
  }
290
- } catch (e6) {
476
+ } catch (e10) {
291
477
  }
292
478
  return { success, receipts, receiverId, nativeDeposit, timestampMs };
293
479
  }
@@ -349,7 +535,7 @@ function makeNearNetwork(preset, rpcUrl) {
349
535
  const { accountId, signer } = resolveNearWallet(wallet._native);
350
536
  const account = new (0, _nearapijs.Account)(accountId, provider, signer);
351
537
  const hashOf = (outcome) => {
352
- const hash2 = _optionalChain([outcome, 'access', _7 => _7.transaction, 'optionalAccess', _8 => _8.hash]);
538
+ const hash2 = _optionalChain([outcome, 'access', _16 => _16.transaction, 'optionalAccess', _17 => _17.hash]);
353
539
  if (!hash2) throw new Error("NEAR: signAndSendTransaction returned no tx hash.");
354
540
  return hash2;
355
541
  };
@@ -379,7 +565,7 @@ function makeNearNetwork(preset, rpcUrl) {
379
565
  try {
380
566
  const tx = await reader.txStatus(hash, senderId);
381
567
  if (tx && tx.success) return { height: "0" };
382
- } catch (e7) {
568
+ } catch (e11) {
383
569
  }
384
570
  throw new (0, _chunkJG6KRAW6cjs.ConfirmationTimeoutError)(`NEAR tx ${hash} not confirmed in time.`);
385
571
  },
@@ -396,7 +582,7 @@ function makeNearNetwork(preset, rpcUrl) {
396
582
  let accountId;
397
583
  try {
398
584
  accountId = resolveNearWallet(wallet._native).accountId;
399
- } catch (e8) {
585
+ } catch (e12) {
400
586
  return { token: null, native: null };
401
587
  }
402
588
  let native = null;
@@ -408,7 +594,7 @@ function makeNearNetwork(preset, rpcUrl) {
408
594
  });
409
595
  native = r.amount != null ? BigInt(r.amount) : null;
410
596
  } catch (e) {
411
- native = /does not exist|UNKNOWN_ACCOUNT/i.test(String(_nullishCoalesce(_optionalChain([e, 'optionalAccess', _9 => _9.message]), () => ( e)))) ? 0n : null;
597
+ native = /does not exist|UNKNOWN_ACCOUNT/i.test(String(_nullishCoalesce(_optionalChain([e, 'optionalAccess', _18 => _18.message]), () => ( e)))) ? 0n : null;
412
598
  }
413
599
  if (asset === "native") return { token: native, native };
414
600
  let token = null;
@@ -422,7 +608,7 @@ function makeNearNetwork(preset, rpcUrl) {
422
608
  });
423
609
  token = r.result ? BigInt(JSON.parse(Buffer.from(r.result).toString())) : null;
424
610
  } catch (e) {
425
- token = /does not exist|not registered|UNKNOWN_ACCOUNT/i.test(String(_nullishCoalesce(_optionalChain([e, 'optionalAccess', _10 => _10.message]), () => ( e)))) ? 0n : null;
611
+ token = /does not exist|not registered|UNKNOWN_ACCOUNT/i.test(String(_nullishCoalesce(_optionalChain([e, 'optionalAccess', _19 => _19.message]), () => ( e)))) ? 0n : null;
426
612
  }
427
613
  return { token, native };
428
614
  },
@@ -438,13 +624,103 @@ function makeNearNetwork(preset, rpcUrl) {
438
624
  });
439
625
  const parsed = r.result ? JSON.parse(Buffer.from(r.result).toString()) : null;
440
626
  return parsed == null ? { ready: false, reason: "NOT_REGISTERED" } : { ready: true };
441
- } catch (e9) {
627
+ } catch (e13) {
442
628
  return { ready: "unknown" };
443
629
  }
444
630
  },
445
631
  async verify(ref, accept) {
446
632
  const { senderId, hash } = decodeRef(ref);
447
633
  return verifyNear({ reader, hash, senderId, accept });
634
+ },
635
+ // Standard x402 `exact` rail, BUYER side — build a NEP-366 SignedDelegateAction authorizing one
636
+ // NEP-141 ft_transfer (per scheme_exact_near.md). The buyer signs with its FULL-ACCESS key and
637
+ // spends ZERO NEAR; a keyless facilitator's relayer prepays the gas + 1 yoctoNEAR and submits.
638
+ // NEAR exact is NEP-141-only + facilitator-settled (see ./exact.ts for why) — native NEAR isn't
639
+ // exact-payable. Pre-reads the access-key nonce + final block height, then defers to payExactNear.
640
+ async payExact(wallet, accept) {
641
+ const { accountId, signer } = resolveNearWallet(wallet._native);
642
+ const publicKey = await signer.getPublicKey();
643
+ const [accessKey, block] = await Promise.all([
644
+ provider.query({
645
+ request_type: "view_access_key",
646
+ finality: "final",
647
+ account_id: accountId,
648
+ public_key: publicKey.toString()
649
+ }),
650
+ provider.viewBlock({ finality: "final" })
651
+ ]);
652
+ const accessKeyNonce = BigInt(_nullishCoalesce(accessKey.nonce, () => ( 0)));
653
+ const blockHeight = BigInt(_nullishCoalesce(_optionalChain([block, 'access', _20 => _20.header, 'optionalAccess', _21 => _21.height]), () => ( 0)));
654
+ const { payload, payerFrom, nonce } = await payExactNear({
655
+ signer,
656
+ senderId: accountId,
657
+ blockHeight,
658
+ accessKeyNonce,
659
+ accept
660
+ });
661
+ return { payload, accepted: accept, payerFrom, nonce };
662
+ },
663
+ // The gate's rail-advertisement SPI. NEAR exact is NEP-141-only. The fee payer (the relayer that
664
+ // prepays gas + the 1 yocto, so the BUYER pays nothing) comes from EITHER the merchant's own bound
665
+ // `relayer` (SELF mode — what works today) OR a facilitator-provided `feePayer` (facilitator mode —
666
+ // for when a NEAR x402 facilitator ships; none does yet). `null` for native / non-NEP-141 / when no
667
+ // fee payer is available. The buyer's SignedDelegateAction is self-contained, so `feePayer` rides in
668
+ // `extra` only for observability + (future) facilitator forwarding.
669
+ async resolveExactRail({ asset, relayer, feePayer }) {
670
+ if (asset === "native" || !isValidNearAccountId(asset)) return null;
671
+ let fp = feePayer;
672
+ if (!fp && relayer) {
673
+ try {
674
+ fp = resolveNearWallet(relayer._native).accountId;
675
+ } catch (e14) {
676
+ return null;
677
+ }
678
+ }
679
+ if (!fp) return null;
680
+ return { method: "near", extra: { feePayer: fp } };
681
+ },
682
+ // Standard x402 `exact` rail, SELLER side (SELF-SETTLE) — decode + verify the inbound delegate
683
+ // against the trusted accept, then RELAY it from the merchant's own NEAR relayer (which prepays the
684
+ // sub-cent gas + the 1 yocto). The buyer stays gasless. THIS is how a NEAR gate gets paid today
685
+ // (no third-party facilitator settles NEAR yet). The drain guard (gas/deposit caps) lives in
686
+ // verifyAndSettleExactNear, invisible to the gate.
687
+ async settleExactSelf({ relayer, payload, accept }) {
688
+ if (!("signedDelegateAction" in payload)) {
689
+ return { ok: false, error: "signature_invalid", detail: "NEAR exact expects a { signedDelegateAction } payload." };
690
+ }
691
+ let relayerWallet;
692
+ try {
693
+ relayerWallet = resolveNearWallet(relayer._native);
694
+ } catch (err) {
695
+ throw new (0, _chunkJG6KRAW6cjs.SettlementError)(
696
+ `NEAR exact settle: the relayer wallet is invalid (${err instanceof Error ? err.message : String(err)}).`,
697
+ { cause: err }
698
+ );
699
+ }
700
+ const relayerAccount = new (0, _nearapijs.Account)(relayerWallet.accountId, provider, relayerWallet.signer);
701
+ const isSuccess = (s) => typeof s === "object" && s !== null && "SuccessValue" in s;
702
+ const client = {
703
+ async currentBlockHeight() {
704
+ try {
705
+ const b = await provider.viewBlock({ finality: "final" });
706
+ return _optionalChain([b, 'access', _22 => _22.header, 'optionalAccess', _23 => _23.height]) != null ? BigInt(b.header.height) : null;
707
+ } catch (e15) {
708
+ return null;
709
+ }
710
+ },
711
+ async relay({ senderId, delegateAction, signature }) {
712
+ const outcome = await relayerAccount.signAndSendTransaction({
713
+ receiverId: senderId,
714
+ actions: [_nearapijs.actions.signedDelegate({ delegateAction, signature })],
715
+ waitUntil: "FINAL"
716
+ });
717
+ const txHash = _nullishCoalesce(_optionalChain([outcome, 'access', _24 => _24.transaction, 'optionalAccess', _25 => _25.hash]), () => ( ""));
718
+ const tokenReceipt = (_nullishCoalesce(outcome.receipts_outcome, () => ( []))).find((r) => _optionalChain([r, 'access', _26 => _26.outcome, 'optionalAccess', _27 => _27.executor_id]) === accept.asset);
719
+ const innerSuccess = tokenReceipt ? isSuccess(_optionalChain([tokenReceipt, 'access', _28 => _28.outcome, 'optionalAccess', _29 => _29.status])) : isSuccess(outcome.status);
720
+ return { txHash, innerSuccess };
721
+ }
722
+ };
723
+ return verifyAndSettleExactNear({ client, payload, accept });
448
724
  }
449
725
  };
450
726
  }
@@ -456,15 +732,15 @@ function decodeRef(ref) {
456
732
  if (i < 0) return { senderId: "", hash: ref };
457
733
  return { senderId: ref.slice(0, i), hash: ref.slice(i + 1) };
458
734
  }
459
- function sumTransferDeposits(actions2) {
460
- if (!Array.isArray(actions2)) return 0n;
735
+ function sumTransferDeposits(actions3) {
736
+ if (!Array.isArray(actions3)) return 0n;
461
737
  let sum = 0n;
462
- for (const a of actions2) {
738
+ for (const a of actions3) {
463
739
  const t = _nullishCoalesce(a.Transfer, () => ( a.transfer));
464
740
  if (t && t.deposit != null) {
465
741
  try {
466
742
  sum += BigInt(t.deposit);
467
- } catch (e10) {
743
+ } catch (e16) {
468
744
  }
469
745
  }
470
746
  }
@@ -2,7 +2,9 @@ import {
2
2
  ConfirmationTimeoutError,
3
3
  InsufficientFundsError,
4
4
  RecipientNotReadyError,
5
+ SettlementError,
5
6
  UnknownTokenError,
7
+ UnsupportedSchemeError,
6
8
  WrongFamilyError,
7
9
  assertNoLegacyWalletKey,
8
10
  nativeCost,
@@ -11,10 +13,15 @@ import {
11
13
  } from "./chunk-7XK22JSQ.js";
12
14
 
13
15
  // src/drivers/near/index.ts
14
- import { JsonRpcProvider, Account, actions } from "near-api-js";
16
+ import { JsonRpcProvider, Account, actions as actions2 } from "near-api-js";
15
17
 
16
18
  // src/drivers/near/chains.ts
17
19
  var NEAR_DECIMALS = 24;
20
+ function isValidNearAccountId(id) {
21
+ if (id.startsWith("0x")) return false;
22
+ if (id.length < 2 || id.length > 64) return false;
23
+ return /^(([a-z\d]+[-_])*[a-z\d]+\.)*([a-z\d]+[-_])*[a-z\d]+$/.test(id);
24
+ }
18
25
  var NEAR_MAINNET = {
19
26
  caip2: "near:mainnet",
20
27
  defaultRpc: "https://free.rpc.fastnear.com",
@@ -92,6 +99,190 @@ function isNearAffordability(err) {
92
99
  return /not enough|doesn't have enough|does not have enough|lack ?balance|exceeds .*balance|insufficient/i.test(m);
93
100
  }
94
101
 
102
+ // src/drivers/near/exact.ts
103
+ import { actions, buildDelegateAction, encodeSignedDelegate, DelegateAction, SCHEMA } from "near-api-js";
104
+ import { deserialize } from "borsh";
105
+ var FT_TRANSFER_GAS2 = 30000000000000n;
106
+ var ONE_YOCTO2 = 1n;
107
+ var ESTIMATED_BLOCK_SECONDS = 1;
108
+ var NONCE_BLOCK_MULTIPLIER = 1000000n;
109
+ async function payExactNear(input) {
110
+ const { signer, senderId, blockHeight, accessKeyNonce, accept } = input;
111
+ if (accept.asset === "native") {
112
+ throw new UnsupportedSchemeError(
113
+ "NEAR exact is NEP-141-only (an ft_transfer); native NEAR is not exact-payable. Pay via onchain-proof."
114
+ );
115
+ }
116
+ if (!isValidNearAccountId(accept.asset)) {
117
+ throw new UnsupportedSchemeError(`NEAR exact: asset "${accept.asset}" must be a NEP-141 contract account id.`);
118
+ }
119
+ if (!isValidNearAccountId(accept.payTo)) {
120
+ throw new UnsupportedSchemeError(`NEAR exact: payTo "${accept.payTo}" is not a valid NEAR account id.`);
121
+ }
122
+ if (!isValidNearAccountId(senderId)) {
123
+ throw new UnsupportedSchemeError(`NEAR exact: sender "${senderId}" is not a valid NEAR account id.`);
124
+ }
125
+ const t = accept.maxTimeoutSeconds;
126
+ if (!Number.isInteger(t) || t <= 0) {
127
+ throw new UnsupportedSchemeError("NEAR exact: maxTimeoutSeconds must be a positive integer.");
128
+ }
129
+ const timeoutBlocks = BigInt(Math.max(1, Math.ceil(t / ESTIMATED_BLOCK_SECONDS)));
130
+ const maxBlockHeight = blockHeight + timeoutBlocks;
131
+ const nonce = accessKeyNonce + 1n;
132
+ if (nonce >= blockHeight * NONCE_BLOCK_MULTIPLIER) {
133
+ throw new UnsupportedSchemeError(
134
+ "NEAR exact: the access-key nonce is at the protocol ceiling for this block height; cannot build a delegate action."
135
+ );
136
+ }
137
+ const publicKey = await signer.getPublicKey();
138
+ const action = actions.functionCall(
139
+ "ft_transfer",
140
+ { receiver_id: accept.payTo, amount: accept.amount },
141
+ FT_TRANSFER_GAS2,
142
+ ONE_YOCTO2
143
+ );
144
+ const delegateAction = buildDelegateAction({
145
+ senderId,
146
+ receiverId: accept.asset,
147
+ actions: [action],
148
+ nonce,
149
+ maxBlockHeight,
150
+ publicKey
151
+ });
152
+ const { signedDelegate } = await signer.signDelegateAction(delegateAction);
153
+ const encoded = encodeSignedDelegate(signedDelegate);
154
+ return {
155
+ payload: { signedDelegateAction: Buffer.from(encoded).toString("base64") },
156
+ payerFrom: senderId,
157
+ // A stable id for THIS authorization (single-use on-chain via the access-key nonce): the
158
+ // client records it as the spend ref and re-presents the SAME signed action on a retry.
159
+ nonce: `${senderId}:${nonce.toString()}`
160
+ };
161
+ }
162
+ var MAX_RELAY_GAS = 300000000000000n;
163
+ var b64decode = (s) => new Uint8Array(Buffer.from(s, "base64"));
164
+ function shorten(msg) {
165
+ const oneLine = msg.replace(/\s+/g, " ").trim();
166
+ return oneLine.length > 200 ? `${oneLine.slice(0, 200)}\u2026` : oneLine;
167
+ }
168
+ function fail(error, detail) {
169
+ return { ok: false, error, detail };
170
+ }
171
+ function verifyExactNear(payload, accept, currentBlockHeight) {
172
+ if (accept.asset === "native" || !isValidNearAccountId(accept.asset)) {
173
+ return fail("transfer_not_found", `NEAR exact rail asset "${accept.asset}" is not a NEP-141 contract.`);
174
+ }
175
+ if (typeof payload?.signedDelegateAction !== "string") {
176
+ return fail("signature_invalid", "NEAR exact payload is missing signedDelegateAction.");
177
+ }
178
+ let decoded;
179
+ try {
180
+ decoded = deserialize(SCHEMA.SignedDelegate, b64decode(payload.signedDelegateAction));
181
+ } catch (err) {
182
+ return fail("signature_invalid", `Unparseable SignedDelegateAction: ${shorten(err instanceof Error ? err.message : String(err))}.`);
183
+ }
184
+ const da = decoded?.delegateAction;
185
+ const sig = decoded?.signature;
186
+ if (!da || sig == null) return fail("signature_invalid", "SignedDelegateAction is missing its delegate action or signature.");
187
+ if (!Array.isArray(da.actions) || da.actions.length !== 1) {
188
+ return fail("transfer_not_found", `the delegate must carry exactly one action, got ${da.actions?.length ?? 0}.`);
189
+ }
190
+ const fc = da.actions[0]?.functionCall;
191
+ if (!fc || fc.methodName !== "ft_transfer") {
192
+ return fail("transfer_not_found", `the delegated action is not an ft_transfer (got "${fc?.methodName ?? "none"}").`);
193
+ }
194
+ if (da.receiverId !== accept.asset) {
195
+ return fail("transfer_not_found", `delegate receiver ${da.receiverId} \u2260 token contract ${accept.asset}.`);
196
+ }
197
+ let args;
198
+ try {
199
+ args = JSON.parse(Buffer.from(fc.args ?? new Uint8Array()).toString());
200
+ } catch {
201
+ return fail("transfer_not_found", "the ft_transfer args are not valid JSON.");
202
+ }
203
+ if (args.receiver_id !== accept.payTo) {
204
+ return fail("wrong_recipient", `ft_transfer pays ${String(args.receiver_id)}, not payTo ${accept.payTo}.`);
205
+ }
206
+ if (typeof args.amount !== "string" || !/^\d+$/.test(args.amount) || BigInt(args.amount) < BigInt(accept.amount)) {
207
+ return fail("amount_too_low", `ft_transfer pays ${String(args.amount)} of the token, required ${accept.amount}.`);
208
+ }
209
+ let deposit;
210
+ let gas;
211
+ try {
212
+ deposit = BigInt(fc.deposit ?? 0);
213
+ gas = BigInt(fc.gas ?? 0);
214
+ } catch {
215
+ return fail("signature_invalid", "the ft_transfer has a malformed gas/deposit.");
216
+ }
217
+ if (deposit !== ONE_YOCTO2) {
218
+ return fail("signature_invalid", `attached deposit ${deposit} \u2260 the required 1 yoctoNEAR (relayer drain guard).`);
219
+ }
220
+ if (gas > MAX_RELAY_GAS) {
221
+ return fail("signature_invalid", `delegated gas ${gas} exceeds the ${MAX_RELAY_GAS} cap (relayer drain guard).`);
222
+ }
223
+ if (currentBlockHeight !== null) {
224
+ let maxBlock;
225
+ try {
226
+ maxBlock = BigInt(da.maxBlockHeight ?? 0);
227
+ } catch {
228
+ return fail("signature_invalid", "the delegate has a malformed max_block_height.");
229
+ }
230
+ if (maxBlock <= currentBlockHeight) {
231
+ return fail("payment_expired", `the delegate expired (max_block_height ${maxBlock} \u2264 current ${currentBlockHeight}).`);
232
+ }
233
+ }
234
+ if (!da.senderId || !isValidNearAccountId(String(da.senderId))) {
235
+ return fail("signature_invalid", `the delegate sender "${String(da.senderId)}" is not a valid NEAR account id.`);
236
+ }
237
+ return { ok: true, senderId: String(da.senderId), delegateAction: new DelegateAction(da), signature: sig };
238
+ }
239
+ async function verifyAndSettleExactNear(input) {
240
+ const { client, payload, accept } = input;
241
+ let height = null;
242
+ try {
243
+ height = await client.currentBlockHeight();
244
+ } catch {
245
+ }
246
+ const v = verifyExactNear(payload, accept, height);
247
+ if (!v.ok) return v;
248
+ let result;
249
+ try {
250
+ result = await client.relay({ senderId: v.senderId, delegateAction: v.delegateAction, signature: v.signature });
251
+ } catch (err) {
252
+ const m = err instanceof Error ? err.message : String(err);
253
+ if (/invalid.*nonce|nonce.*used|DelegateActionInvalidNonce/i.test(m)) {
254
+ return fail("tx_already_used", `this delegate was already used (single-use nonce): ${shorten(m)}.`);
255
+ }
256
+ if (/expired|DelegateActionExpired|max_block_height|deadline/i.test(m)) {
257
+ return fail("payment_expired", `the delegate expired before it landed: ${shorten(m)}.`);
258
+ }
259
+ if (/not enough|insufficient|exceeded the prepaid gas|NotEnoughBalance|doesn't have enough|is not registered/i.test(m)) {
260
+ return fail("tx_reverted", `the ft_transfer would fail on chain: ${shorten(m)}.`);
261
+ }
262
+ throw new SettlementError(
263
+ `NEAR exact settle: the relayer could not submit the delegate (${shorten(m)}). The buyer's signed delegate is still valid \u2014 fund/fix the relayer and the buyer can re-present it.`,
264
+ { cause: err }
265
+ );
266
+ }
267
+ if (!result.innerSuccess) {
268
+ return fail("tx_reverted", `the ft_transfer receipt did not succeed on chain (tx ${result.txHash}).`);
269
+ }
270
+ return {
271
+ ok: true,
272
+ receipt: {
273
+ scheme: "exact",
274
+ success: true,
275
+ network: accept.network,
276
+ transaction: result.txHash,
277
+ asset: accept.asset,
278
+ amount: accept.amount,
279
+ payer: v.senderId,
280
+ payTo: accept.payTo,
281
+ verifiedAt: (/* @__PURE__ */ new Date()).toISOString()
282
+ }
283
+ };
284
+ }
285
+
95
286
  // src/drivers/near/verify.ts
96
287
  function parseFtTransferEvent(line) {
97
288
  const marker = "EVENT_JSON:";
@@ -253,11 +444,6 @@ var nearDriver = {
253
444
  return makeNearNetwork(NEAR_MAINNET, rpcUrl);
254
445
  }
255
446
  };
256
- function isValidNearAccountId(id) {
257
- if (id.startsWith("0x")) return false;
258
- if (id.length < 2 || id.length > 64) return false;
259
- return /^(([a-z\d]+[-_])*[a-z\d]+\.)*([a-z\d]+[-_])*[a-z\d]+$/.test(id);
260
- }
261
447
  function makeNearNetwork(preset, rpcUrl) {
262
448
  const provider = new JsonRpcProvider({ url: rpcUrl });
263
449
  const network = preset.caip2;
@@ -358,7 +544,7 @@ function makeNearNetwork(preset, rpcUrl) {
358
544
  const outcome = await account.signAndSendTransaction({
359
545
  receiverId: contractId,
360
546
  actions: [
361
- actions.functionCall("ft_transfer", { receiver_id: receiverId, amount, memo }, gas, deposit)
547
+ actions2.functionCall("ft_transfer", { receiver_id: receiverId, amount, memo }, gas, deposit)
362
548
  ]
363
549
  });
364
550
  return { hash: hashOf(outcome) };
@@ -366,7 +552,7 @@ function makeNearNetwork(preset, rpcUrl) {
366
552
  async nativeTransfer({ receiverId, amount }) {
367
553
  const outcome = await account.signAndSendTransaction({
368
554
  receiverId,
369
- actions: [actions.transfer(BigInt(amount))]
555
+ actions: [actions2.transfer(BigInt(amount))]
370
556
  });
371
557
  return { hash: hashOf(outcome) };
372
558
  }
@@ -445,6 +631,96 @@ function makeNearNetwork(preset, rpcUrl) {
445
631
  async verify(ref, accept) {
446
632
  const { senderId, hash } = decodeRef(ref);
447
633
  return verifyNear({ reader, hash, senderId, accept });
634
+ },
635
+ // Standard x402 `exact` rail, BUYER side — build a NEP-366 SignedDelegateAction authorizing one
636
+ // NEP-141 ft_transfer (per scheme_exact_near.md). The buyer signs with its FULL-ACCESS key and
637
+ // spends ZERO NEAR; a keyless facilitator's relayer prepays the gas + 1 yoctoNEAR and submits.
638
+ // NEAR exact is NEP-141-only + facilitator-settled (see ./exact.ts for why) — native NEAR isn't
639
+ // exact-payable. Pre-reads the access-key nonce + final block height, then defers to payExactNear.
640
+ async payExact(wallet, accept) {
641
+ const { accountId, signer } = resolveNearWallet(wallet._native);
642
+ const publicKey = await signer.getPublicKey();
643
+ const [accessKey, block] = await Promise.all([
644
+ provider.query({
645
+ request_type: "view_access_key",
646
+ finality: "final",
647
+ account_id: accountId,
648
+ public_key: publicKey.toString()
649
+ }),
650
+ provider.viewBlock({ finality: "final" })
651
+ ]);
652
+ const accessKeyNonce = BigInt(accessKey.nonce ?? 0);
653
+ const blockHeight = BigInt(block.header?.height ?? 0);
654
+ const { payload, payerFrom, nonce } = await payExactNear({
655
+ signer,
656
+ senderId: accountId,
657
+ blockHeight,
658
+ accessKeyNonce,
659
+ accept
660
+ });
661
+ return { payload, accepted: accept, payerFrom, nonce };
662
+ },
663
+ // The gate's rail-advertisement SPI. NEAR exact is NEP-141-only. The fee payer (the relayer that
664
+ // prepays gas + the 1 yocto, so the BUYER pays nothing) comes from EITHER the merchant's own bound
665
+ // `relayer` (SELF mode — what works today) OR a facilitator-provided `feePayer` (facilitator mode —
666
+ // for when a NEAR x402 facilitator ships; none does yet). `null` for native / non-NEP-141 / when no
667
+ // fee payer is available. The buyer's SignedDelegateAction is self-contained, so `feePayer` rides in
668
+ // `extra` only for observability + (future) facilitator forwarding.
669
+ async resolveExactRail({ asset, relayer, feePayer }) {
670
+ if (asset === "native" || !isValidNearAccountId(asset)) return null;
671
+ let fp = feePayer;
672
+ if (!fp && relayer) {
673
+ try {
674
+ fp = resolveNearWallet(relayer._native).accountId;
675
+ } catch {
676
+ return null;
677
+ }
678
+ }
679
+ if (!fp) return null;
680
+ return { method: "near", extra: { feePayer: fp } };
681
+ },
682
+ // Standard x402 `exact` rail, SELLER side (SELF-SETTLE) — decode + verify the inbound delegate
683
+ // against the trusted accept, then RELAY it from the merchant's own NEAR relayer (which prepays the
684
+ // sub-cent gas + the 1 yocto). The buyer stays gasless. THIS is how a NEAR gate gets paid today
685
+ // (no third-party facilitator settles NEAR yet). The drain guard (gas/deposit caps) lives in
686
+ // verifyAndSettleExactNear, invisible to the gate.
687
+ async settleExactSelf({ relayer, payload, accept }) {
688
+ if (!("signedDelegateAction" in payload)) {
689
+ return { ok: false, error: "signature_invalid", detail: "NEAR exact expects a { signedDelegateAction } payload." };
690
+ }
691
+ let relayerWallet;
692
+ try {
693
+ relayerWallet = resolveNearWallet(relayer._native);
694
+ } catch (err) {
695
+ throw new SettlementError(
696
+ `NEAR exact settle: the relayer wallet is invalid (${err instanceof Error ? err.message : String(err)}).`,
697
+ { cause: err }
698
+ );
699
+ }
700
+ const relayerAccount = new Account(relayerWallet.accountId, provider, relayerWallet.signer);
701
+ const isSuccess = (s) => typeof s === "object" && s !== null && "SuccessValue" in s;
702
+ const client = {
703
+ async currentBlockHeight() {
704
+ try {
705
+ const b = await provider.viewBlock({ finality: "final" });
706
+ return b.header?.height != null ? BigInt(b.header.height) : null;
707
+ } catch {
708
+ return null;
709
+ }
710
+ },
711
+ async relay({ senderId, delegateAction, signature }) {
712
+ const outcome = await relayerAccount.signAndSendTransaction({
713
+ receiverId: senderId,
714
+ actions: [actions2.signedDelegate({ delegateAction, signature })],
715
+ waitUntil: "FINAL"
716
+ });
717
+ const txHash = outcome.transaction?.hash ?? "";
718
+ const tokenReceipt = (outcome.receipts_outcome ?? []).find((r) => r.outcome?.executor_id === accept.asset);
719
+ const innerSuccess = tokenReceipt ? isSuccess(tokenReceipt.outcome?.status) : isSuccess(outcome.status);
720
+ return { txHash, innerSuccess };
721
+ }
722
+ };
723
+ return verifyAndSettleExactNear({ client, payload, accept });
448
724
  }
449
725
  };
450
726
  }
@@ -456,10 +732,10 @@ function decodeRef(ref) {
456
732
  if (i < 0) return { senderId: "", hash: ref };
457
733
  return { senderId: ref.slice(0, i), hash: ref.slice(i + 1) };
458
734
  }
459
- function sumTransferDeposits(actions2) {
460
- if (!Array.isArray(actions2)) return 0n;
735
+ function sumTransferDeposits(actions3) {
736
+ if (!Array.isArray(actions3)) return 0n;
461
737
  let sum = 0n;
462
- for (const a of actions2) {
738
+ for (const a of actions3) {
463
739
  const t = a.Transfer ?? a.transfer;
464
740
  if (t && t.deposit != null) {
465
741
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@piprail/sdk",
3
- "version": "2.4.0",
3
+ "version": "2.5.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",
@@ -86,6 +86,7 @@
86
86
  "@ton/crypto": ">=3 <4",
87
87
  "@ton/ton": ">=15 <17",
88
88
  "algosdk": ">=3 <4",
89
+ "borsh": ">=2 <3",
89
90
  "bs58": "^5.0.0",
90
91
  "near-api-js": ">=7 <8",
91
92
  "tronweb": ">=6 <7",
@@ -131,6 +132,9 @@
131
132
  },
132
133
  "algosdk": {
133
134
  "optional": true
135
+ },
136
+ "borsh": {
137
+ "optional": true
134
138
  }
135
139
  },
136
140
  "devDependencies": {
@@ -144,6 +148,7 @@
144
148
  "@ton/ton": "^16.2.4",
145
149
  "@types/node": "^22.10.0",
146
150
  "algosdk": "^3.5.2",
151
+ "borsh": "^2.0.0",
147
152
  "bs58": "^5.0.0",
148
153
  "near-api-js": "^7.2.0",
149
154
  "tronweb": "^6.3.0",