@relai-fi/x402 0.6.1 → 0.6.3

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.cts CHANGED
@@ -1,6 +1,84 @@
1
- export { B as BridgePluginConfig, D as DynamicPrice, j as FeedbackPluginConfig, F as FreeTierPluginConfig, b as PaymentInfo, g as PluginContext, h as PluginResult, P as ProtectOptions, R as Relai, d as RelaiIntegritasFlow, e as RelaiIntegritasOptions, f as RelaiPlugin, a as RelaiServerConfig, i as ScorePluginConfig, S as SettleResult, k as SolanaFeedbackPluginConfig, c as StripePayTo, R as default, s as stripePayTo } from './server-8gWh9oky.cjs';
2
- export { RelayWebSocketFactory, RelayWebSocketLike, X402Client, X402ClientConfig, X402FetchInit, X402IntegritasConfig, X402IntegritasFlow, X402NetworkSelectionMode, X402RelayWsConfig, X402RelayWsError, X402RelayWsResponse, X402RequestOptions, default as createX402Client } from './client.cjs';
1
+ export { B as BridgePluginConfig, D as DynamicPrice, j as FeedbackPluginConfig, F as FreeTierPluginConfig, M as MppServerHandler, b as PaymentInfo, g as PluginContext, h as PluginResult, P as ProtectOptions, R as Relai, d as RelaiIntegritasFlow, e as RelaiIntegritasOptions, f as RelaiPlugin, a as RelaiServerConfig, i as ScorePluginConfig, S as SettleResult, k as SolanaFeedbackPluginConfig, c as StripePayTo, R as default, s as stripePayTo } from './server-CBZ2RjEP.cjs';
2
+ export { MppHandler, RelayWebSocketFactory, RelayWebSocketLike, X402Client, X402ClientConfig, X402FetchInit, X402IntegritasConfig, X402IntegritasFlow, X402NetworkSelectionMode, X402RelayWsConfig, X402RelayWsError, X402RelayWsResponse, X402RequestOptions, default as createX402Client } from './client.cjs';
3
3
  export { RelayFeedbackConfig, submitRelayFeedback } from './relay-feedback.cjs';
4
4
  export { A as AcceptsExtra, B as BASE_MAINNET_NETWORK, C as CAIP2_TO_NETWORK, b as CHAIN_IDS, E as EXPLORER_TX_URL, l as EvmWallet, N as NETWORK_CAIP2, e as NETWORK_LABELS, d as NETWORK_TOKENS, c as NetworkToken, P as PaymentAccept, o as PaymentRequired, R as RELAI_FACILITATOR_URL, h as RELAI_NETWORKS, a as RelaiNetwork, m as ResourceInfo, S as SOLANA_MAINNET_NETWORK, k as SolanaWallet, U as USDC_ADDRESSES, g as USDC_BASE, f as USDC_SOLANA, W as WalletSet, j as isEvm, i as isSolana, n as normalizeNetwork, r as resolveToken } from './types-Y9ni5XwY.cjs';
5
5
  export { BridgeBalances, BridgeQuoteResult, BridgeResult } from './management.cjs';
6
6
  export { NETWORK_V1_TO_V2, NETWORK_V2_TO_V1, convertPayloadToVersion, convertV1ToV2, convertV2ToV1, detectPayloadVersion, formatUsd, fromAtomicUnits, isEvmNetwork, isSolanaNetwork, networkV1ToV2, networkV2ToV1, normalizePaymentHeader, toAtomicUnits } from './utils/index.cjs';
7
+
8
+ /**
9
+ * Payment Code API — BLIK-style x402 payment codes
10
+ *
11
+ * generatePaymentCode() — sign EIP-3009 authorization and register on SKALE L3
12
+ * redeemPaymentCode() — redeem a code (payee calls this, triggers Base L2 settlement)
13
+ * getPaymentCode() — check code status
14
+ */
15
+ interface PaymentCodeConfig {
16
+ facilitatorUrl?: string;
17
+ }
18
+ interface GeneratePaymentCodeParams {
19
+ /** EIP-3009 signer — must implement signTypedData */
20
+ signer: {
21
+ getAddress(): Promise<string>;
22
+ signTypedData(domain: object, types: object, value: object): Promise<string>;
23
+ };
24
+ /** Payee wallet address */
25
+ to: string;
26
+ /** Amount in USDC micro-units (6 decimals), e.g. 1000 = $0.001 */
27
+ value: string | bigint;
28
+ /** USDC contract address on Base L2 (defaults to Base mainnet USDC) */
29
+ usdcContract?: string;
30
+ /** TTL in seconds (default: 120) */
31
+ ttl?: number;
32
+ }
33
+ interface PaymentCode {
34
+ code: string;
35
+ validBefore: number;
36
+ expiresIn: number;
37
+ }
38
+ interface RedeemResult {
39
+ success: boolean;
40
+ code: string;
41
+ l3TxHash: string;
42
+ l2TxHash: string;
43
+ explorerUrl: string;
44
+ amount: string;
45
+ from: string;
46
+ to: string;
47
+ }
48
+ interface CodeStatus {
49
+ code: string;
50
+ from: string;
51
+ to: string;
52
+ value: string;
53
+ validBefore: number;
54
+ redeemed: boolean;
55
+ expired: boolean;
56
+ redeemable: boolean;
57
+ }
58
+ /**
59
+ * Generate a BLIK-style x402 payment code backed by EIP-3009.
60
+ *
61
+ * @example
62
+ * const { code } = await generatePaymentCode(config, {
63
+ * signer: walletClient,
64
+ * to: "0xMerchant...",
65
+ * value: "1000", // $0.001 USDC
66
+ * ttl: 120,
67
+ * });
68
+ * // code = "X7K9P2AB"
69
+ */
70
+ declare function generatePaymentCode(config: PaymentCodeConfig, params: GeneratePaymentCodeParams): Promise<PaymentCode>;
71
+ /**
72
+ * Redeem a payment code. Triggers Base L2 settlement via relayer.
73
+ *
74
+ * @example
75
+ * const result = await redeemPaymentCode(config, "X7K9P2AB");
76
+ * // result.l2TxHash = "0x..."
77
+ */
78
+ declare function redeemPaymentCode(config: PaymentCodeConfig, code: string): Promise<RedeemResult>;
79
+ /**
80
+ * Get the status of a payment code.
81
+ */
82
+ declare function getPaymentCode(config: PaymentCodeConfig, code: string): Promise<CodeStatus>;
83
+
84
+ export { type CodeStatus, type GeneratePaymentCodeParams, type PaymentCode, type PaymentCodeConfig, type RedeemResult, generatePaymentCode, getPaymentCode, redeemPaymentCode };
package/dist/index.d.ts CHANGED
@@ -1,6 +1,84 @@
1
- export { B as BridgePluginConfig, D as DynamicPrice, j as FeedbackPluginConfig, F as FreeTierPluginConfig, b as PaymentInfo, g as PluginContext, h as PluginResult, P as ProtectOptions, R as Relai, d as RelaiIntegritasFlow, e as RelaiIntegritasOptions, f as RelaiPlugin, a as RelaiServerConfig, i as ScorePluginConfig, S as SettleResult, k as SolanaFeedbackPluginConfig, c as StripePayTo, R as default, s as stripePayTo } from './server-JtlTglrW.js';
2
- export { RelayWebSocketFactory, RelayWebSocketLike, X402Client, X402ClientConfig, X402FetchInit, X402IntegritasConfig, X402IntegritasFlow, X402NetworkSelectionMode, X402RelayWsConfig, X402RelayWsError, X402RelayWsResponse, X402RequestOptions, default as createX402Client } from './client.js';
1
+ export { B as BridgePluginConfig, D as DynamicPrice, j as FeedbackPluginConfig, F as FreeTierPluginConfig, M as MppServerHandler, b as PaymentInfo, g as PluginContext, h as PluginResult, P as ProtectOptions, R as Relai, d as RelaiIntegritasFlow, e as RelaiIntegritasOptions, f as RelaiPlugin, a as RelaiServerConfig, i as ScorePluginConfig, S as SettleResult, k as SolanaFeedbackPluginConfig, c as StripePayTo, R as default, s as stripePayTo } from './server-DaySqG5H.js';
2
+ export { MppHandler, RelayWebSocketFactory, RelayWebSocketLike, X402Client, X402ClientConfig, X402FetchInit, X402IntegritasConfig, X402IntegritasFlow, X402NetworkSelectionMode, X402RelayWsConfig, X402RelayWsError, X402RelayWsResponse, X402RequestOptions, default as createX402Client } from './client.js';
3
3
  export { RelayFeedbackConfig, submitRelayFeedback } from './relay-feedback.js';
4
4
  export { A as AcceptsExtra, B as BASE_MAINNET_NETWORK, C as CAIP2_TO_NETWORK, b as CHAIN_IDS, E as EXPLORER_TX_URL, l as EvmWallet, N as NETWORK_CAIP2, e as NETWORK_LABELS, d as NETWORK_TOKENS, c as NetworkToken, P as PaymentAccept, o as PaymentRequired, R as RELAI_FACILITATOR_URL, h as RELAI_NETWORKS, a as RelaiNetwork, m as ResourceInfo, S as SOLANA_MAINNET_NETWORK, k as SolanaWallet, U as USDC_ADDRESSES, g as USDC_BASE, f as USDC_SOLANA, W as WalletSet, j as isEvm, i as isSolana, n as normalizeNetwork, r as resolveToken } from './types-Y9ni5XwY.js';
5
5
  export { BridgeBalances, BridgeQuoteResult, BridgeResult } from './management.js';
6
6
  export { NETWORK_V1_TO_V2, NETWORK_V2_TO_V1, convertPayloadToVersion, convertV1ToV2, convertV2ToV1, detectPayloadVersion, formatUsd, fromAtomicUnits, isEvmNetwork, isSolanaNetwork, networkV1ToV2, networkV2ToV1, normalizePaymentHeader, toAtomicUnits } from './utils/index.js';
7
+
8
+ /**
9
+ * Payment Code API — BLIK-style x402 payment codes
10
+ *
11
+ * generatePaymentCode() — sign EIP-3009 authorization and register on SKALE L3
12
+ * redeemPaymentCode() — redeem a code (payee calls this, triggers Base L2 settlement)
13
+ * getPaymentCode() — check code status
14
+ */
15
+ interface PaymentCodeConfig {
16
+ facilitatorUrl?: string;
17
+ }
18
+ interface GeneratePaymentCodeParams {
19
+ /** EIP-3009 signer — must implement signTypedData */
20
+ signer: {
21
+ getAddress(): Promise<string>;
22
+ signTypedData(domain: object, types: object, value: object): Promise<string>;
23
+ };
24
+ /** Payee wallet address */
25
+ to: string;
26
+ /** Amount in USDC micro-units (6 decimals), e.g. 1000 = $0.001 */
27
+ value: string | bigint;
28
+ /** USDC contract address on Base L2 (defaults to Base mainnet USDC) */
29
+ usdcContract?: string;
30
+ /** TTL in seconds (default: 120) */
31
+ ttl?: number;
32
+ }
33
+ interface PaymentCode {
34
+ code: string;
35
+ validBefore: number;
36
+ expiresIn: number;
37
+ }
38
+ interface RedeemResult {
39
+ success: boolean;
40
+ code: string;
41
+ l3TxHash: string;
42
+ l2TxHash: string;
43
+ explorerUrl: string;
44
+ amount: string;
45
+ from: string;
46
+ to: string;
47
+ }
48
+ interface CodeStatus {
49
+ code: string;
50
+ from: string;
51
+ to: string;
52
+ value: string;
53
+ validBefore: number;
54
+ redeemed: boolean;
55
+ expired: boolean;
56
+ redeemable: boolean;
57
+ }
58
+ /**
59
+ * Generate a BLIK-style x402 payment code backed by EIP-3009.
60
+ *
61
+ * @example
62
+ * const { code } = await generatePaymentCode(config, {
63
+ * signer: walletClient,
64
+ * to: "0xMerchant...",
65
+ * value: "1000", // $0.001 USDC
66
+ * ttl: 120,
67
+ * });
68
+ * // code = "X7K9P2AB"
69
+ */
70
+ declare function generatePaymentCode(config: PaymentCodeConfig, params: GeneratePaymentCodeParams): Promise<PaymentCode>;
71
+ /**
72
+ * Redeem a payment code. Triggers Base L2 settlement via relayer.
73
+ *
74
+ * @example
75
+ * const result = await redeemPaymentCode(config, "X7K9P2AB");
76
+ * // result.l2TxHash = "0x..."
77
+ */
78
+ declare function redeemPaymentCode(config: PaymentCodeConfig, code: string): Promise<RedeemResult>;
79
+ /**
80
+ * Get the status of a payment code.
81
+ */
82
+ declare function getPaymentCode(config: PaymentCodeConfig, code: string): Promise<CodeStatus>;
83
+
84
+ export { type CodeStatus, type GeneratePaymentCodeParams, type PaymentCode, type PaymentCodeConfig, type RedeemResult, generatePaymentCode, getPaymentCode, redeemPaymentCode };
package/dist/index.js CHANGED
@@ -1,3 +1,10 @@
1
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
+ }) : x)(function(x) {
4
+ if (typeof require !== "undefined") return require.apply(this, arguments);
5
+ throw Error('Dynamic require of "' + x + '" is not supported');
6
+ });
7
+
1
8
  // src/types.ts
2
9
  var RELAI_FACILITATOR_URL = "https://facilitator.x402.fi";
3
10
  var NETWORK_CAIP2 = {
@@ -454,6 +461,7 @@ var Relai = class {
454
461
  this.network = config.network;
455
462
  this.facilitatorUrl = config.facilitatorUrl || RELAI_FACILITATOR_URL;
456
463
  this.plugins = config.plugins ?? [];
464
+ this.mpp = config.mpp;
457
465
  }
458
466
  async runPluginInit() {
459
467
  for (const plugin of this.plugins) {
@@ -558,6 +566,119 @@ var Relai = class {
558
566
  const integritasFlow = headerIntegritasFlow || configuredIntegritas.flow;
559
567
  const integritasMode = integritasFlow === "single" ? "single_signature_fee_included" : integritasFlow === "dual" ? "dual_signature_split" : void 0;
560
568
  const paymentHeader = req.headers["x-payment"] || req.headers["payment-signature"] || req.headers["x-payment-signature"];
569
+ const authHeader = req.headers["authorization"] || "";
570
+ console.log(`[Relai] MPP check: paymentHeader=${!!paymentHeader}, hasMpp=${!!self.mpp}, authHeader=${authHeader?.slice(0, 30)}`);
571
+ if (!paymentHeader && self.mpp && /^Payment\s+/i.test(authHeader)) {
572
+ try {
573
+ const mppAmount = resolvedPrice.toFixed(6);
574
+ const mppUrl = `${req.protocol}://${req.get("host")}${req.originalUrl}`;
575
+ const mppHeaders = new Headers();
576
+ for (const [k, v] of Object.entries(req.headers)) {
577
+ if (typeof v === "string") mppHeaders.set(k, v);
578
+ }
579
+ const mppRequest = new Request(mppUrl, { method: req.method, headers: mppHeaders });
580
+ const chargeHandler = self.mpp.charge({ amount: mppAmount });
581
+ const mppResult = await chargeHandler(mppRequest);
582
+ console.log(`[Relai] MPP charge result: status=${mppResult.status}, keys=${Object.keys(mppResult)}, hasChallenge=${!!mppResult.challenge}, hasWithReceipt=${!!mppResult.withReceipt}`);
583
+ if (mppResult.status === 402 && mppResult.challenge instanceof Response) {
584
+ const retryAuth = mppResult.challenge.headers.get("www-authenticate");
585
+ console.log(`[Relai] MPP re-challenged (credential not accepted). New WWW-Auth: ${retryAuth?.slice(0, 60)}`);
586
+ }
587
+ if (mppResult.status !== 200 && !mppResult.withReceipt && mppResult.status !== 402) {
588
+ if (self.plugins.length > 0) {
589
+ const mppFailCtx = {
590
+ network,
591
+ price: resolvedPrice,
592
+ path: req.path || req.originalUrl || "/",
593
+ method: (req.method || "GET").toUpperCase()
594
+ };
595
+ const mppFailResult = {
596
+ success: false,
597
+ payer: "mpp",
598
+ error: `MPP charge failed with status ${mppResult.status}`
599
+ };
600
+ for (const plugin of self.plugins) {
601
+ if (!plugin.afterSettled) continue;
602
+ try {
603
+ await plugin.afterSettled(req, mppFailResult, mppFailCtx);
604
+ } catch (pluginErr) {
605
+ console.warn(`[Relai] Plugin '${plugin.name}' afterSettled error (non-blocking):`, pluginErr);
606
+ }
607
+ }
608
+ }
609
+ }
610
+ if (mppResult.status === 200 || mppResult.withReceipt) {
611
+ const receipt = mppResult.receipt || {};
612
+ const paymentInfo2 = {
613
+ verified: true,
614
+ transactionId: receipt.reference || "",
615
+ payer: receipt.method || "mpp",
616
+ network,
617
+ amount: resolvedPrice
618
+ };
619
+ req.payment = paymentInfo2;
620
+ req.x402Payer = receipt.method ? `${receipt.method}-mpp` : "mpp";
621
+ req.x402Paid = true;
622
+ req.x402Transaction = receipt.reference || "";
623
+ req.x402Network = network;
624
+ if (mppResult.withReceipt) {
625
+ const dummyResponse = new Response(null);
626
+ const receiptResponse = mppResult.withReceipt(dummyResponse);
627
+ const receiptHeader = receiptResponse.headers.get("payment-receipt");
628
+ if (receiptHeader) res.setHeader("Payment-Receipt", receiptHeader);
629
+ }
630
+ options.onPaymentSettled?.(req, {
631
+ success: true,
632
+ transaction: receipt.reference,
633
+ payer: req.x402Payer
634
+ });
635
+ if (self.plugins.length > 0) {
636
+ const settleCtx = {
637
+ network,
638
+ price: resolvedPrice,
639
+ path: req.path || req.originalUrl || "/",
640
+ method: (req.method || "GET").toUpperCase()
641
+ };
642
+ for (const plugin of self.plugins) {
643
+ if (!plugin.afterSettled) continue;
644
+ try {
645
+ await plugin.afterSettled(req, {
646
+ success: true,
647
+ transaction: receipt.reference,
648
+ payer: req.x402Payer
649
+ }, settleCtx);
650
+ } catch (pluginErr) {
651
+ console.warn(`[Relai] Plugin '${plugin.name}' afterSettled error (non-blocking):`, pluginErr);
652
+ }
653
+ }
654
+ }
655
+ return next();
656
+ }
657
+ } catch (mppErr) {
658
+ console.warn(`[Relai] MPP verification failed (${mppErr instanceof Error ? mppErr.message : mppErr}), falling through to x402`);
659
+ if (self.plugins.length > 0) {
660
+ const mppErrCtx = {
661
+ network,
662
+ price: resolvedPrice,
663
+ path: req.path || req.originalUrl || "/",
664
+ method: (req.method || "GET").toUpperCase()
665
+ };
666
+ const mppErrResult = {
667
+ success: false,
668
+ payer: "mpp",
669
+ error: mppErr instanceof Error ? mppErr.message : String(mppErr)
670
+ };
671
+ for (const plugin of self.plugins) {
672
+ if (!plugin.afterSettled) continue;
673
+ try {
674
+ await plugin.afterSettled(req, mppErrResult, mppErrCtx);
675
+ } catch (pluginErr) {
676
+ console.warn(`[Relai] Plugin '${plugin.name}' afterSettled error (non-blocking):`, pluginErr);
677
+ }
678
+ }
679
+ }
680
+ }
681
+ }
561
682
  if (!paymentHeader && self.plugins.length > 0) {
562
683
  if (!self.pluginInitPromise) {
563
684
  self.pluginInitPromise = self.runPluginInit();
@@ -712,6 +833,21 @@ var Relai = class {
712
833
  }
713
834
  }
714
835
  }
836
+ if (self.mpp?.charge) {
837
+ try {
838
+ const mppAmount = resolvedPrice.toFixed(6);
839
+ const chargeHandler = self.mpp.charge({ amount: mppAmount });
840
+ const mockReq = new Request(`${req.protocol}://${req.get("host")}${req.originalUrl}`);
841
+ const mppResult = await chargeHandler(mockReq);
842
+ if (mppResult?.challenge instanceof Response) {
843
+ const wwwAuth = mppResult.challenge.headers.get("www-authenticate");
844
+ if (wwwAuth) {
845
+ res.setHeader("WWW-Authenticate", wwwAuth);
846
+ }
847
+ }
848
+ } catch {
849
+ }
850
+ }
715
851
  return res.status(402).json(paymentRequiredResponse);
716
852
  }
717
853
  let paymentProof;
@@ -802,6 +938,22 @@ var Relai = class {
802
938
  });
803
939
  const result = await settleRes.json();
804
940
  if (!result.success) {
941
+ if (self.plugins.length > 0) {
942
+ const failCtx = {
943
+ network,
944
+ price: resolvedPrice,
945
+ path: req.path || req.originalUrl || "/",
946
+ method: (req.method || "GET").toUpperCase()
947
+ };
948
+ for (const plugin of self.plugins) {
949
+ if (!plugin.afterSettled) continue;
950
+ try {
951
+ await plugin.afterSettled(req, result, failCtx);
952
+ } catch (pluginErr) {
953
+ console.warn(`[Relai] Plugin '${plugin.name}' afterSettled error (non-blocking):`, pluginErr);
954
+ }
955
+ }
956
+ }
805
957
  return res.status(402).json({
806
958
  x402Version: 2,
807
959
  error: result.errorReason || result.error || "Payment settlement failed"
@@ -926,7 +1078,8 @@ function createX402Client(config) {
926
1078
  maxAmountAtomic,
927
1079
  integritas,
928
1080
  verbose = false,
929
- defaultHeaders = {}
1081
+ defaultHeaders = {},
1082
+ mpp
930
1083
  } = config;
931
1084
  const relayWsEnabled = relayWs?.enabled === true;
932
1085
  const relayWsPreflightTimeoutMs = relayWs?.preflightTimeoutMs ?? 5e3;
@@ -1906,6 +2059,31 @@ function createX402Client(config) {
1906
2059
  const response = await fetch(input, requestInitWithHeaders);
1907
2060
  if (response.status !== 402) return response;
1908
2061
  log("Got 402 Payment Required");
2062
+ if (mpp) {
2063
+ const wwwAuth = response.headers.get("www-authenticate");
2064
+ if (wwwAuth && /^Payment\s+/i.test(wwwAuth.trim())) {
2065
+ log("MPP challenge detected in WWW-Authenticate header");
2066
+ try {
2067
+ const credential = await mpp.createCredential(response);
2068
+ if (credential) {
2069
+ log("MPP credential created, retrying with Authorization: Payment");
2070
+ const mppRetry = await fetch(input, {
2071
+ ...requestInitWithHeaders,
2072
+ headers: {
2073
+ ...requestHeaders,
2074
+ "Authorization": credential.startsWith("Payment ") ? credential : `Payment ${credential}`
2075
+ }
2076
+ });
2077
+ if (mppRetry.status !== 402) {
2078
+ return mppRetry;
2079
+ }
2080
+ log("MPP retry still returned 402, falling through to x402");
2081
+ }
2082
+ } catch (mppErr) {
2083
+ log(`MPP payment failed (${mppErr instanceof Error ? mppErr.message : mppErr}), falling through to x402`);
2084
+ }
2085
+ }
2086
+ }
1909
2087
  let requirementsFromBody = null;
1910
2088
  try {
1911
2089
  requirementsFromBody = await response.clone().json();
@@ -2033,6 +2211,96 @@ function submitRelayFeedback(config) {
2033
2211
  })();
2034
2212
  }
2035
2213
 
2214
+ // src/payment-codes.ts
2215
+ var DEFAULT_FACILITATOR = "https://relai.fi/facilitator";
2216
+ var DEFAULT_USDC_BASE = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
2217
+ var EIP3009_TYPES = {
2218
+ TransferWithAuthorization: [
2219
+ { name: "from", type: "address" },
2220
+ { name: "to", type: "address" },
2221
+ { name: "value", type: "uint256" },
2222
+ { name: "validAfter", type: "uint256" },
2223
+ { name: "validBefore", type: "uint256" },
2224
+ { name: "nonce", type: "bytes32" }
2225
+ ]
2226
+ };
2227
+ function randomBytes32() {
2228
+ const bytes = new Uint8Array(32);
2229
+ if (typeof globalThis.crypto !== "undefined") {
2230
+ globalThis.crypto.getRandomValues(bytes);
2231
+ } else {
2232
+ const { randomBytes } = __require("crypto");
2233
+ randomBytes(32).copy(Buffer.from(bytes.buffer));
2234
+ }
2235
+ return "0x" + Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
2236
+ }
2237
+ async function generatePaymentCode(config, params) {
2238
+ const { signer, to, value, usdcContract, ttl = 120 } = params;
2239
+ const facilitatorUrl = config.facilitatorUrl || DEFAULT_FACILITATOR;
2240
+ const usdc = usdcContract || DEFAULT_USDC_BASE;
2241
+ const from = await signer.getAddress();
2242
+ const now = Math.floor(Date.now() / 1e3);
2243
+ const validAfter = 0;
2244
+ const validBefore = now + ttl;
2245
+ const nonce = randomBytes32();
2246
+ const domain = {
2247
+ name: "USD Coin",
2248
+ version: "2",
2249
+ chainId: 8453,
2250
+ // Base mainnet
2251
+ verifyingContract: usdc
2252
+ };
2253
+ const message = {
2254
+ from,
2255
+ to,
2256
+ value: BigInt(value).toString(),
2257
+ validAfter,
2258
+ validBefore,
2259
+ nonce
2260
+ };
2261
+ const signature = await signer.signTypedData(domain, EIP3009_TYPES, message);
2262
+ const res = await fetch(`${facilitatorUrl}/payment-codes`, {
2263
+ method: "POST",
2264
+ headers: { "Content-Type": "application/json" },
2265
+ body: JSON.stringify({
2266
+ from,
2267
+ to,
2268
+ value: BigInt(value).toString(),
2269
+ validAfter,
2270
+ validBefore,
2271
+ nonce,
2272
+ signature,
2273
+ usdcContract: usdc
2274
+ })
2275
+ });
2276
+ if (!res.ok) {
2277
+ const err = await res.json().catch(() => ({}));
2278
+ throw new Error(`Failed to register payment code: ${err.error || res.status}`);
2279
+ }
2280
+ return res.json();
2281
+ }
2282
+ async function redeemPaymentCode(config, code) {
2283
+ const facilitatorUrl = config.facilitatorUrl || DEFAULT_FACILITATOR;
2284
+ const res = await fetch(`${facilitatorUrl}/payment-codes/${code.toUpperCase()}/redeem`, {
2285
+ method: "POST",
2286
+ headers: { "Content-Type": "application/json" }
2287
+ });
2288
+ if (!res.ok) {
2289
+ const err = await res.json().catch(() => ({}));
2290
+ throw new Error(`Failed to redeem payment code: ${err.error || res.status}`);
2291
+ }
2292
+ return res.json();
2293
+ }
2294
+ async function getPaymentCode(config, code) {
2295
+ const facilitatorUrl = config.facilitatorUrl || DEFAULT_FACILITATOR;
2296
+ const res = await fetch(`${facilitatorUrl}/payment-codes/${code.toUpperCase()}`);
2297
+ if (!res.ok) {
2298
+ const err = await res.json().catch(() => ({}));
2299
+ throw new Error(`Payment code not found: ${err.error || res.status}`);
2300
+ }
2301
+ return res.json();
2302
+ }
2303
+
2036
2304
  // src/utils/payload-converter.ts
2037
2305
  var NETWORK_V1_TO_V2 = {
2038
2306
  "solana": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",
@@ -2197,6 +2465,8 @@ export {
2197
2465
  detectPayloadVersion,
2198
2466
  formatUsd,
2199
2467
  fromAtomicUnits,
2468
+ generatePaymentCode,
2469
+ getPaymentCode,
2200
2470
  isEvm,
2201
2471
  isEvmNetwork,
2202
2472
  isSolana,
@@ -2205,6 +2475,7 @@ export {
2205
2475
  networkV2ToV1,
2206
2476
  normalizeNetwork,
2207
2477
  normalizePaymentHeader,
2478
+ redeemPaymentCode,
2208
2479
  resolveToken,
2209
2480
  stripePayTo,
2210
2481
  submitRelayFeedback,