@relai-fi/x402 0.6.9 → 0.6.10

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.cjs CHANGED
@@ -2118,10 +2118,14 @@ __export(index_exports, {
2118
2118
  USDC_SOLANA: () => USDC_SOLANA,
2119
2119
  cancelPaymentCode: () => cancelPaymentCode,
2120
2120
  cancelSolanaPaymentCode: () => cancelSolanaPaymentCode,
2121
+ cancelStoredPaymentCode: () => cancelStoredPaymentCode,
2122
+ claimPaymentLink: () => claimPaymentLink,
2121
2123
  convertPayloadToVersion: () => convertPayloadToVersion,
2122
2124
  convertV1ToV2: () => convertV1ToV2,
2123
2125
  convertV2ToV1: () => convertV2ToV1,
2124
2126
  createPayRequest: () => createPayRequest,
2127
+ createPaymentCode: () => createPaymentCode,
2128
+ createPaymentCodesBatch: () => createPaymentCodesBatch,
2125
2129
  createPrivateKeySigner: () => createPrivateKeySigner,
2126
2130
  createX402Client: () => createX402Client,
2127
2131
  default: () => Relai,
@@ -2136,11 +2140,13 @@ __export(index_exports, {
2136
2140
  generateSolanaPaymentCode: () => generateSolanaPaymentCode,
2137
2141
  getPayRequest: () => getPayRequest,
2138
2142
  getPaymentCode: () => getPaymentCode,
2143
+ getPaymentCodeDetails: () => getPaymentCodeDetails,
2139
2144
  getSolanaPaymentCode: () => getSolanaPaymentCode,
2140
2145
  isEvm: () => isEvm,
2141
2146
  isEvmNetwork: () => isEvmNetwork,
2142
2147
  isSolana: () => isSolana,
2143
2148
  isSolanaNetwork: () => isSolanaNetwork,
2149
+ listOwnerPaymentCodes: () => listOwnerPaymentCodes,
2144
2150
  networkV1ToV2: () => networkV1ToV2,
2145
2151
  networkV2ToV1: () => networkV2ToV1,
2146
2152
  normalizeNetwork: () => normalizeNetwork,
@@ -2148,8 +2154,10 @@ __export(index_exports, {
2148
2154
  payPayRequest: () => payPayRequest,
2149
2155
  payPayRequestWithCode: () => payPayRequestWithCode,
2150
2156
  payPayRequestWithSolana: () => payPayRequestWithSolana,
2157
+ payPayRequestWithStoredCode: () => payPayRequestWithStoredCode,
2151
2158
  redeemPaymentCode: () => redeemPaymentCode,
2152
2159
  redeemSolanaPaymentCode: () => redeemSolanaPaymentCode,
2160
+ redeemStoredPaymentCode: () => redeemStoredPaymentCode,
2153
2161
  resolveToken: () => resolveToken,
2154
2162
  stripePayTo: () => stripePayTo,
2155
2163
  submitRelayFeedback: () => submitRelayFeedback,
@@ -4520,19 +4528,26 @@ function submitRelayFeedback(config2) {
4520
4528
 
4521
4529
  // src/solana-payment-codes.ts
4522
4530
  var DEFAULT_FACILITATOR = "https://relai.fi/facilitator";
4523
- function generateCode() {
4531
+ function generateCode(network, claimLink = false) {
4524
4532
  const chars = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
4525
- const bytes = new Uint8Array(8);
4533
+ const randomLength = claimLink ? 6 : 7;
4534
+ const bytes = new Uint8Array(randomLength);
4526
4535
  if (typeof globalThis !== "undefined" && globalThis.crypto?.getRandomValues) {
4527
4536
  globalThis.crypto.getRandomValues(bytes);
4528
4537
  } else {
4529
4538
  const { randomBytes } = require("crypto");
4530
- randomBytes(8).copy(Buffer.from(bytes.buffer));
4539
+ randomBytes(randomLength).copy(Buffer.from(bytes.buffer));
4531
4540
  }
4532
- let code = "";
4533
- for (let i = 0; i < 8; i++) code += chars[bytes[i] % chars.length];
4541
+ let code = network === "solana-devnet" ? "D" : "S";
4542
+ if (claimLink) code += "Z";
4543
+ for (let i = 0; i < bytes.length; i++) code += chars[bytes[i] % chars.length];
4534
4544
  return code;
4535
4545
  }
4546
+ function buildClaimUrl(facilitatorUrl, claimToken) {
4547
+ if (!claimToken) return null;
4548
+ const origin = new URL(facilitatorUrl).origin;
4549
+ return new URL(`/claim/${claimToken}`, origin).toString();
4550
+ }
4536
4551
  async function anchorDisc(name) {
4537
4552
  const preimage = new TextEncoder().encode(`global:${name}`);
4538
4553
  if (typeof globalThis !== "undefined" && globalThis.crypto?.subtle) {
@@ -4542,14 +4557,21 @@ async function anchorDisc(name) {
4542
4557
  const { createHash } = require("crypto");
4543
4558
  return new Uint8Array(createHash("sha256").update(preimage).digest()).slice(0, 8);
4544
4559
  }
4560
+ function writeBigInt64LE(target, value, offset) {
4561
+ let remaining = BigInt.asUintN(64, value);
4562
+ for (let index = 0; index < 8; index += 1) {
4563
+ target[offset + index] = Number(remaining & 0xffn);
4564
+ remaining >>= 8n;
4565
+ }
4566
+ }
4545
4567
  async function buildInstructionData(name, codeBytes, extra) {
4546
4568
  const disc = await anchorDisc(name);
4547
4569
  if (name === "create_vault" && extra) {
4548
4570
  const buf2 = Buffer.alloc(32);
4549
4571
  Buffer.from(disc).copy(buf2, 0);
4550
4572
  Buffer.from(codeBytes).copy(buf2, 8);
4551
- buf2.writeBigUInt64LE(extra.amount, 16);
4552
- buf2.writeBigInt64LE(extra.validUntil, 24);
4573
+ writeBigInt64LE(buf2, extra.amount, 16);
4574
+ writeBigInt64LE(buf2, extra.validUntil, 24);
4553
4575
  return buf2;
4554
4576
  }
4555
4577
  const buf = Buffer.alloc(16);
@@ -4559,7 +4581,7 @@ async function buildInstructionData(name, codeBytes, extra) {
4559
4581
  }
4560
4582
  async function generateSolanaPaymentCode(config2, wallet, params) {
4561
4583
  const facilitatorUrl = config2.facilitatorUrl ?? DEFAULT_FACILITATOR;
4562
- const { solanaRpcUrl, ttlSeconds = 86400 } = params;
4584
+ const { solanaRpcUrl, ttlSeconds = 86400, claimLink = false } = params;
4563
4585
  const amount2 = BigInt(params.amount);
4564
4586
  if (amount2 <= 0n) throw new Error("amount must be positive");
4565
4587
  if (!wallet.publicKey) throw new Error("Solana wallet not connected");
@@ -4570,7 +4592,7 @@ async function generateSolanaPaymentCode(config2, wallet, params) {
4570
4592
  const relayerAddr = relayerInfo.address;
4571
4593
  const programId = relayerInfo.programId;
4572
4594
  const usdcMint = relayerInfo.networks?.[network]?.usdc ?? (network === "solana-devnet" ? "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU" : "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v");
4573
- const code = generateCode();
4595
+ const code = generateCode(network, claimLink);
4574
4596
  const codeBytes = new TextEncoder().encode(code);
4575
4597
  const {
4576
4598
  Connection: Connection2,
@@ -4602,6 +4624,8 @@ async function generateSolanaPaymentCode(config2, wallet, params) {
4602
4624
  const createVaultIx = new TransactionInstruction({
4603
4625
  programId: programPK,
4604
4626
  keys: [
4627
+ { pubkey: relayerPK, isSigner: true, isWritable: true },
4628
+ // caller / fee payer
4605
4629
  { pubkey: buyerPK, isSigner: true, isWritable: true },
4606
4630
  // buyer
4607
4631
  { pubkey: vaultPda, isSigner: false, isWritable: true },
@@ -4633,7 +4657,9 @@ async function generateSolanaPaymentCode(config2, wallet, params) {
4633
4657
  code,
4634
4658
  amount: amount2.toString(),
4635
4659
  network,
4636
- ttlSeconds
4660
+ ttlSeconds,
4661
+ claimLink,
4662
+ ...params.description ? { description: params.description } : {}
4637
4663
  };
4638
4664
  const res = await fetch(`${facilitatorUrl}/solana-payment-codes`, {
4639
4665
  method: "POST",
@@ -4644,7 +4670,129 @@ async function generateSolanaPaymentCode(config2, wallet, params) {
4644
4670
  const err = await res.json().catch(() => ({}));
4645
4671
  throw new Error(err.error ?? `generateSolanaPaymentCode failed: ${res.status}`);
4646
4672
  }
4647
- return res.json();
4673
+ const payload = await res.json();
4674
+ if (payload.claimLink === true) {
4675
+ const claimToken = typeof payload.claimToken === "string" ? payload.claimToken : null;
4676
+ const sanitized = { ...payload };
4677
+ delete sanitized.claimToken;
4678
+ delete sanitized.id;
4679
+ delete sanitized.code;
4680
+ return {
4681
+ ...sanitized,
4682
+ claimLink: true,
4683
+ claimUrl: buildClaimUrl(facilitatorUrl, claimToken)
4684
+ };
4685
+ }
4686
+ return payload;
4687
+ }
4688
+ async function generateSolanaPaymentCodesBatch(config2, wallet, params) {
4689
+ const facilitatorUrl = config2.facilitatorUrl ?? DEFAULT_FACILITATOR;
4690
+ const items = Array.isArray(params.items) ? params.items : [];
4691
+ if (items.length === 0) throw new Error("items must not be empty");
4692
+ if (items.length > 10) throw new Error("Maximum 10 Solana batch items are supported per transaction");
4693
+ if (!wallet.publicKey) throw new Error("Solana wallet not connected");
4694
+ const infoRes = await fetch(`${facilitatorUrl}/solana-payment-codes/relayer-info`);
4695
+ if (!infoRes.ok) throw new Error("Failed to fetch Solana relayer info");
4696
+ const relayerInfo = await infoRes.json();
4697
+ const network = params.network ?? relayerInfo.defaultNetwork ?? "solana";
4698
+ const relayerAddr = relayerInfo.address;
4699
+ const programId = relayerInfo.programId;
4700
+ const usdcMint = relayerInfo.networks?.[network]?.usdc ?? (network === "solana-devnet" ? "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU" : "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v");
4701
+ const {
4702
+ Connection: Connection2,
4703
+ PublicKey: PublicKey2,
4704
+ TransactionMessage: TransactionMessage2,
4705
+ VersionedTransaction: VersionedTransaction2,
4706
+ TransactionInstruction
4707
+ } = await import("@solana/web3.js");
4708
+ const {
4709
+ getAssociatedTokenAddressSync,
4710
+ TOKEN_PROGRAM_ID: TOKEN_PROGRAM_ID2,
4711
+ ASSOCIATED_TOKEN_PROGRAM_ID
4712
+ } = await import("@solana/spl-token");
4713
+ const rpcUrl = params.solanaRpcUrl ?? (network === "solana-devnet" ? "https://api.devnet.solana.com" : "https://api.mainnet-beta.solana.com");
4714
+ const connection = new Connection2(rpcUrl, "confirmed");
4715
+ const programPK = new PublicKey2(programId);
4716
+ const mintPK = new PublicKey2(usdcMint);
4717
+ const buyerPK = new PublicKey2(wallet.publicKey.toString());
4718
+ const relayerPK = new PublicKey2(relayerAddr);
4719
+ const buyerAta = getAssociatedTokenAddressSync(mintPK, buyerPK, false, TOKEN_PROGRAM_ID2);
4720
+ const systemProgram = new PublicKey2("11111111111111111111111111111111");
4721
+ const usedCodes = /* @__PURE__ */ new Set();
4722
+ const preparedItems = [];
4723
+ const instructions = [];
4724
+ let totalAmount = 0n;
4725
+ for (const item of items) {
4726
+ const amount2 = BigInt(item.amount);
4727
+ if (amount2 <= 0n) throw new Error("Each batch item amount must be positive");
4728
+ const ttlSeconds = Math.min(Math.max(Math.round(Number(item.ttlSeconds ?? 86400)), 60), 604800);
4729
+ const validUntil = BigInt(Math.floor(Date.now() / 1e3) + ttlSeconds);
4730
+ let code = generateCode(network, false);
4731
+ while (usedCodes.has(code)) code = generateCode(network, false);
4732
+ usedCodes.add(code);
4733
+ const codeBytes = new TextEncoder().encode(code);
4734
+ const [vaultPda] = PublicKey2.findProgramAddressSync(
4735
+ [Buffer.from("vault"), Buffer.from(codeBytes)],
4736
+ programPK
4737
+ );
4738
+ const vaultAta = getAssociatedTokenAddressSync(mintPK, vaultPda, true, TOKEN_PROGRAM_ID2);
4739
+ const ixData = await buildInstructionData("create_vault", codeBytes, { amount: amount2, validUntil });
4740
+ instructions.push(new TransactionInstruction({
4741
+ programId: programPK,
4742
+ keys: [
4743
+ { pubkey: relayerPK, isSigner: true, isWritable: true },
4744
+ { pubkey: buyerPK, isSigner: true, isWritable: true },
4745
+ { pubkey: vaultPda, isSigner: false, isWritable: true },
4746
+ { pubkey: vaultAta, isSigner: false, isWritable: true },
4747
+ { pubkey: buyerAta, isSigner: false, isWritable: true },
4748
+ { pubkey: mintPK, isSigner: false, isWritable: false },
4749
+ { pubkey: TOKEN_PROGRAM_ID2, isSigner: false, isWritable: false },
4750
+ { pubkey: ASSOCIATED_TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
4751
+ { pubkey: systemProgram, isSigner: false, isWritable: false }
4752
+ ],
4753
+ data: ixData
4754
+ }));
4755
+ preparedItems.push({
4756
+ code,
4757
+ amount: amount2,
4758
+ ttlSeconds,
4759
+ description: item.description,
4760
+ validUntil
4761
+ });
4762
+ totalAmount += amount2;
4763
+ }
4764
+ const { blockhash } = await connection.getLatestBlockhash("confirmed");
4765
+ const message = new TransactionMessage2({
4766
+ payerKey: relayerPK,
4767
+ recentBlockhash: blockhash,
4768
+ instructions
4769
+ }).compileToV0Message();
4770
+ const tx = new VersionedTransaction2(message);
4771
+ const signed = await wallet.signTransaction(tx);
4772
+ const serialized = Buffer.from(signed.serialize()).toString("base64");
4773
+ const res = await fetch(`${facilitatorUrl}/solana-payment-codes/batch`, {
4774
+ method: "POST",
4775
+ headers: { "Content-Type": "application/json" },
4776
+ body: JSON.stringify({
4777
+ transaction: serialized,
4778
+ network,
4779
+ items: preparedItems.map((item) => ({
4780
+ code: item.code,
4781
+ amount: item.amount.toString(),
4782
+ ttlSeconds: item.ttlSeconds,
4783
+ ...item.description ? { description: item.description } : {}
4784
+ }))
4785
+ })
4786
+ });
4787
+ if (!res.ok) {
4788
+ const err = await res.json().catch(() => ({}));
4789
+ throw new Error(err.error ?? `generateSolanaPaymentCodesBatch failed: ${res.status}`);
4790
+ }
4791
+ const payload = await res.json();
4792
+ return {
4793
+ ...payload,
4794
+ totalAmount: typeof payload.totalAmount === "string" ? payload.totalAmount : totalAmount.toString()
4795
+ };
4648
4796
  }
4649
4797
  async function getSolanaPaymentCode(config2, code) {
4650
4798
  const facilitatorUrl = config2.facilitatorUrl ?? DEFAULT_FACILITATOR;
@@ -4714,6 +4862,8 @@ async function cancelSolanaPaymentCode(config2, code, wallet, options = {}) {
4714
4862
  const cancelIx = new TransactionInstruction({
4715
4863
  programId: programPK,
4716
4864
  keys: [
4865
+ { pubkey: relayerPK, isSigner: true, isWritable: true },
4866
+ // caller / fee payer
4717
4867
  { pubkey: buyerPK, isSigner: true, isWritable: true },
4718
4868
  // buyer (must sign)
4719
4869
  { pubkey: vaultPda, isSigner: false, isWritable: true },
@@ -4803,6 +4953,7 @@ function createPrivateKeySigner(privateKey) {
4803
4953
  };
4804
4954
  }
4805
4955
  var DEFAULT_FACILITATOR2 = "https://relai.fi/facilitator";
4956
+ var AUTHORIZATION_WINDOW_SECONDS = 3600;
4806
4957
  function randomBytes32() {
4807
4958
  const bytes = new Uint8Array(32);
4808
4959
  if (typeof globalThis.crypto !== "undefined") {
@@ -4820,6 +4971,14 @@ async function fetchToAddress(facilitatorUrl, network) {
4820
4971
  if (!data.toAddress) throw new Error("Facilitator returned no toAddress");
4821
4972
  return data.toAddress;
4822
4973
  }
4974
+ async function fetchEscrowAddress(facilitatorUrl, network) {
4975
+ const res = await fetch(`${facilitatorUrl}/payment-codes/relayer-address`);
4976
+ if (!res.ok) throw new Error("Failed to fetch escrow address from facilitator");
4977
+ const data = await res.json();
4978
+ const escrowAddress = data.escrowAddresses?.[network];
4979
+ if (!escrowAddress) throw new Error(`Facilitator returned no escrow address for ${network}`);
4980
+ return escrowAddress;
4981
+ }
4823
4982
  async function signEip3009(signer, net, from4, toAddress, value, validAfter, validBefore, nonce, usdcOverride) {
4824
4983
  const domain2 = {
4825
4984
  name: net.domainName,
@@ -4894,8 +5053,7 @@ async function generatePaymentCodesBatch(config2, params) {
4894
5053
  codes,
4895
5054
  payee,
4896
5055
  usdcContract,
4897
- network = "base-sepolia",
4898
- authToken
5056
+ network = "base-sepolia"
4899
5057
  } = params;
4900
5058
  const facilitatorUrl = config2.facilitatorUrl ?? DEFAULT_FACILITATOR2;
4901
5059
  const net = NETWORK_CONFIGS[network];
@@ -4905,44 +5063,76 @@ async function generatePaymentCodesBatch(config2, params) {
4905
5063
  const usdc = usdcContract ?? net.usdc;
4906
5064
  const now = Math.floor(Date.now() / 1e3);
4907
5065
  const toAddress = await fetchToAddress(facilitatorUrl, network);
4908
- const signedCodes = await Promise.all(
4909
- codes.map(async (item) => {
5066
+ const escrowAddress = await fetchEscrowAddress(facilitatorUrl, network);
5067
+ const results = [];
5068
+ const failed = [];
5069
+ for (let index = 0; index < codes.length; index += 1) {
5070
+ const item = codes[index];
5071
+ try {
4910
5072
  const validBefore = now + (item.ttl ?? 86400);
5073
+ const authorizationValidBefore = Math.min(validBefore, now + AUTHORIZATION_WINDOW_SECONDS);
4911
5074
  const nonce = randomBytes32();
4912
5075
  const value = BigInt(item.value).toString();
5076
+ const authorization = {
5077
+ from: from4,
5078
+ to: escrowAddress,
5079
+ value,
5080
+ validAfter: 0,
5081
+ validBefore: authorizationValidBefore,
5082
+ nonce
5083
+ };
4913
5084
  const signature2 = await signEip3009(
4914
5085
  signer,
4915
5086
  net,
4916
5087
  from4,
4917
- toAddress,
5088
+ escrowAddress,
4918
5089
  value,
4919
- 0,
4920
- validBefore,
4921
- nonce,
5090
+ authorization.validAfter,
5091
+ authorization.validBefore,
5092
+ authorization.nonce,
4922
5093
  usdc
4923
5094
  );
4924
- return { value, validAfter: 0, validBefore, nonce, signature: signature2 };
4925
- })
4926
- );
4927
- const res = await fetch(`${facilitatorUrl}/payment-codes/batch`, {
4928
- method: "POST",
4929
- headers: {
4930
- "Content-Type": "application/json",
4931
- "Authorization": `Bearer ${authToken}`
4932
- },
4933
- body: JSON.stringify({
4934
- from: from4,
4935
- settlementNetwork: net.settlementNetwork,
4936
- usdcContract: usdc,
4937
- ...payee ? { payee } : {},
4938
- codes: signedCodes
4939
- })
4940
- });
4941
- if (!res.ok) {
4942
- const err = await res.json().catch(() => ({}));
4943
- throw new Error(`Batch registration failed: ${err.error ?? res.status}`);
5095
+ const res = await fetch(`${facilitatorUrl}/payment-codes`, {
5096
+ method: "POST",
5097
+ headers: { "Content-Type": "application/json" },
5098
+ body: JSON.stringify({
5099
+ from: from4,
5100
+ value,
5101
+ validBefore,
5102
+ usdcContract: usdc,
5103
+ settlementNetwork: net.settlementNetwork,
5104
+ escrowMode: true,
5105
+ ...payee ? { payee } : {},
5106
+ signature: signature2,
5107
+ authorization
5108
+ })
5109
+ });
5110
+ if (!res.ok) {
5111
+ const err = await res.json().catch(() => ({}));
5112
+ failed.push({ index, error: String(err.error ?? err.detail ?? res.status) });
5113
+ continue;
5114
+ }
5115
+ const payload = await res.json();
5116
+ results.push({
5117
+ code: String(payload.code ?? ""),
5118
+ validBefore: Number(payload.validBefore ?? validBefore),
5119
+ expiresIn: Number(payload.expiresIn ?? validBefore - Math.floor(Date.now() / 1e3)),
5120
+ locked: Boolean(payload.locked ?? payee)
5121
+ });
5122
+ } catch (error48) {
5123
+ failed.push({
5124
+ index,
5125
+ error: error48 instanceof Error ? error48.message : String(error48)
5126
+ });
5127
+ }
4944
5128
  }
4945
- return res.json();
5129
+ return {
5130
+ registered: results.length,
5131
+ codes: results,
5132
+ failed,
5133
+ relayerAddress: toAddress,
5134
+ settlementNetwork: net.settlementNetwork
5135
+ };
4946
5136
  }
4947
5137
  async function redeemPaymentCode(config2, code, payee) {
4948
5138
  const facilitatorUrl = config2.facilitatorUrl ?? DEFAULT_FACILITATOR2;
@@ -5211,6 +5401,528 @@ async function payPayRequestWithSolana(config2, requestCode, wallet, options = {
5211
5401
  return res.json();
5212
5402
  }
5213
5403
 
5404
+ // src/current-payment-codes.ts
5405
+ var import_ethers3 = require("ethers");
5406
+ var import_bs58 = __toESM(require("bs58"), 1);
5407
+ var DEFAULT_FACILITATOR4 = "https://relai.fi/facilitator";
5408
+ var TRANSFER_WITH_AUTHORIZATION_DOMAIN_VERSION = "2";
5409
+ var AUTHORIZATION_WINDOW_SECONDS2 = 3600;
5410
+ var EVM_ESCROW_ABI = ["function cancel(bytes8 code) external"];
5411
+ var EIP3009_TYPES3 = {
5412
+ TransferWithAuthorization: [
5413
+ { name: "from", type: "address" },
5414
+ { name: "to", type: "address" },
5415
+ { name: "value", type: "uint256" },
5416
+ { name: "validAfter", type: "uint256" },
5417
+ { name: "validBefore", type: "uint256" },
5418
+ { name: "nonce", type: "bytes32" }
5419
+ ]
5420
+ };
5421
+ function isEvmAddress(value) {
5422
+ return /^0x[0-9a-fA-F]{40}$/i.test(value);
5423
+ }
5424
+ function codeToBytes8(code) {
5425
+ const normalized = code.trim().toUpperCase();
5426
+ const bytes = import_ethers3.ethers.toUtf8Bytes(normalized);
5427
+ if (bytes.length !== 8) throw new Error("Payment code must be exactly 8 characters long");
5428
+ return import_ethers3.ethers.hexlify(bytes);
5429
+ }
5430
+ function randomBytes323() {
5431
+ const bytes = new Uint8Array(32);
5432
+ if (typeof globalThis.crypto !== "undefined" && globalThis.crypto?.getRandomValues) {
5433
+ globalThis.crypto.getRandomValues(bytes);
5434
+ } else {
5435
+ const { randomBytes } = require("crypto");
5436
+ randomBytes(32).copy(Buffer.from(bytes.buffer));
5437
+ }
5438
+ return `0x${Array.from(bytes).map((byte) => byte.toString(16).padStart(2, "0")).join("")}`;
5439
+ }
5440
+ function extractClaimToken(claimUrlOrToken) {
5441
+ const normalized = claimUrlOrToken.trim();
5442
+ if (!normalized) throw new Error("Claim URL or claim token is required");
5443
+ const directValue = normalized.split("?")[0]?.split("#")[0]?.trim() ?? "";
5444
+ if (!directValue.includes("/")) return directValue;
5445
+ try {
5446
+ const url2 = new URL(normalized);
5447
+ const segments = url2.pathname.split("/").filter(Boolean);
5448
+ return segments[segments.length - 1] ?? "";
5449
+ } catch {
5450
+ const segments = directValue.split("/").filter(Boolean);
5451
+ return segments[segments.length - 1] ?? "";
5452
+ }
5453
+ }
5454
+ function buildClaimUrl2(facilitatorUrl, claimToken) {
5455
+ if (!claimToken) return null;
5456
+ const origin = new URL(facilitatorUrl).origin;
5457
+ return new URL(`/claim/${claimToken}`, origin).toString();
5458
+ }
5459
+ function buildCancelAuthorizationMessage(code, owner, issuedAt) {
5460
+ return [
5461
+ "RelAI Codes",
5462
+ "Authorize payment code cancellation",
5463
+ `Code: ${code.trim().toUpperCase()}`,
5464
+ `Owner: ${owner.toLowerCase()}`,
5465
+ `Issued At: ${issuedAt}`
5466
+ ].join("\n");
5467
+ }
5468
+ function buildClaimLinkCancelAuthorizationMessage(claimToken, owner, issuedAt) {
5469
+ return [
5470
+ "RelAI Codes",
5471
+ "Authorize claim link cancellation",
5472
+ `Claim Token: ${claimToken}`,
5473
+ `Owner: ${owner.toLowerCase()}`,
5474
+ `Issued At: ${issuedAt}`
5475
+ ].join("\n");
5476
+ }
5477
+ function buildEvmClaimLinkAuthorizationMessage(params) {
5478
+ return [
5479
+ "RelAI EVM Claim Link",
5480
+ `Claim Token: ${params.claimToken}`,
5481
+ `Claimer: ${params.claimer.toLowerCase()}`,
5482
+ `Mode: ${params.mode}`,
5483
+ `Target Address: ${params.targetAddress ?? "-"}`,
5484
+ `Target Network: ${params.targetNetwork ?? "-"}`,
5485
+ `Issued At: ${params.issuedAt}`
5486
+ ].join("\n");
5487
+ }
5488
+ function buildSolanaClaimLinkAuthorizationMessage(params) {
5489
+ return [
5490
+ "RelAI Solana Claim Link",
5491
+ `Claim Token: ${params.claimToken}`,
5492
+ `Claimer: ${params.claimer}`,
5493
+ `Mode: ${params.mode}`,
5494
+ `Target Address: ${params.targetAddress ?? "-"}`,
5495
+ `Target Network: ${params.targetNetwork ?? "-"}`,
5496
+ `Issued At: ${params.issuedAt}`
5497
+ ].join("\n");
5498
+ }
5499
+ async function readJson(response) {
5500
+ return response.json().catch(() => ({}));
5501
+ }
5502
+ async function fetchWithPayload(url2, init) {
5503
+ const response = await fetch(url2, init);
5504
+ const payload = await readJson(response);
5505
+ return { response, payload };
5506
+ }
5507
+ function buildRequestError(response, payload) {
5508
+ return new Error(String(payload.error || payload.detail || payload.message || `Request failed (${response.status})`));
5509
+ }
5510
+ function isNotFoundResponse(response, payload) {
5511
+ return response.status === 404 || payload.errorCode === "not_found";
5512
+ }
5513
+ async function fetchStoredCodeWithFallback(facilitatorUrl, normalizedCode, options = {}) {
5514
+ const suffix = options.suffix ? `/${options.suffix.replace(/^\/+/, "")}` : "";
5515
+ const attempts = [
5516
+ { kind: "evm", url: `${facilitatorUrl}/payment-codes/${normalizedCode}${suffix}` },
5517
+ { kind: "solana", url: `${facilitatorUrl}/solana-payment-codes/${normalizedCode}${suffix}` }
5518
+ ];
5519
+ let lastError = null;
5520
+ for (const attempt of attempts) {
5521
+ const { response, payload } = await fetchWithPayload(attempt.url, options.init);
5522
+ if (response.ok) {
5523
+ return { kind: attempt.kind, payload };
5524
+ }
5525
+ if (!isNotFoundResponse(response, payload)) {
5526
+ throw buildRequestError(response, payload);
5527
+ }
5528
+ lastError = buildRequestError(response, payload);
5529
+ }
5530
+ throw lastError ?? new Error("Payment code not found");
5531
+ }
5532
+ async function fetchOrThrow(url2, init) {
5533
+ const { response, payload } = await fetchWithPayload(url2, init);
5534
+ if (!response.ok) {
5535
+ throw buildRequestError(response, payload);
5536
+ }
5537
+ return payload;
5538
+ }
5539
+ function sanitizeClaimLinkResponse(payload, facilitatorUrl, fallbackClaimToken) {
5540
+ const claimToken = typeof payload.claimToken === "string" ? payload.claimToken : fallbackClaimToken ?? null;
5541
+ const sanitized = { ...payload };
5542
+ delete sanitized.claimToken;
5543
+ delete sanitized.id;
5544
+ return {
5545
+ ...sanitized,
5546
+ claimUrl: buildClaimUrl2(facilitatorUrl, claimToken)
5547
+ };
5548
+ }
5549
+ async function createPaymentCode(config2, params) {
5550
+ const facilitatorUrl = config2.facilitatorUrl ?? DEFAULT_FACILITATOR4;
5551
+ const ttlSeconds = Math.max(60, Math.round(Number(params.ttlSeconds ?? 86400)));
5552
+ if ("wallet" in params) {
5553
+ const amount3 = BigInt(params.amount);
5554
+ if (amount3 <= 0n) throw new Error("amount must be positive");
5555
+ return generateSolanaPaymentCode(config2, params.wallet, {
5556
+ amount: amount3,
5557
+ network: params.network,
5558
+ claimLink: params.claimLink === true,
5559
+ description: params.description,
5560
+ ttlSeconds
5561
+ });
5562
+ }
5563
+ const network = params.network ?? "base-sepolia";
5564
+ const net = NETWORK_CONFIGS[network];
5565
+ if (!net) throw new Error(`Unsupported network: ${network}`);
5566
+ const amount2 = BigInt(params.amount);
5567
+ if (amount2 <= 0n) throw new Error("amount must be positive");
5568
+ const relayerConfig = await fetchOrThrow(`${facilitatorUrl}/payment-codes/relayer-address`);
5569
+ const escrowAddresses = relayerConfig.escrowAddresses ?? {};
5570
+ const escrowAddress = escrowAddresses[network];
5571
+ if (!escrowAddress) throw new Error(`EVM escrow is not configured for ${network}`);
5572
+ const from4 = await params.signer.getAddress();
5573
+ const now = Math.floor(Date.now() / 1e3);
5574
+ const validBefore = now + ttlSeconds;
5575
+ const authorizationValidBefore = String(Math.min(validBefore, now + AUTHORIZATION_WINDOW_SECONDS2));
5576
+ const authorizationNonce = randomBytes323();
5577
+ const usdcContract = params.usdcContract ?? net.usdc;
5578
+ const domain2 = {
5579
+ name: net.domainName,
5580
+ version: TRANSFER_WITH_AUTHORIZATION_DOMAIN_VERSION,
5581
+ chainId: net.chainId,
5582
+ verifyingContract: usdcContract
5583
+ };
5584
+ const authorization = {
5585
+ from: from4,
5586
+ to: escrowAddress,
5587
+ value: amount2.toString(),
5588
+ validAfter: "0",
5589
+ validBefore: authorizationValidBefore,
5590
+ nonce: authorizationNonce
5591
+ };
5592
+ const signature2 = await params.signer.signTypedData(domain2, EIP3009_TYPES3, authorization);
5593
+ const payload = await fetchOrThrow(`${facilitatorUrl}/payment-codes`, {
5594
+ method: "POST",
5595
+ headers: { "Content-Type": "application/json" },
5596
+ body: JSON.stringify({
5597
+ from: from4,
5598
+ value: amount2.toString(),
5599
+ validBefore,
5600
+ usdcContract,
5601
+ settlementNetwork: network,
5602
+ escrowMode: true,
5603
+ claimLink: params.claimLink === true,
5604
+ ...params.description ? { description: params.description } : {},
5605
+ ...params.payee ? { payee: params.payee } : {},
5606
+ signature: signature2,
5607
+ authorization
5608
+ })
5609
+ });
5610
+ return params.claimLink === true ? sanitizeClaimLinkResponse(payload, facilitatorUrl) : payload;
5611
+ }
5612
+ async function createPaymentCodesBatch(config2, params) {
5613
+ const facilitatorUrl = config2.facilitatorUrl ?? DEFAULT_FACILITATOR4;
5614
+ if (!Array.isArray(params.codes) || params.codes.length === 0) {
5615
+ throw new Error("codes must not be empty");
5616
+ }
5617
+ if ("wallet" in params) {
5618
+ const items = params.codes.map((item) => ({
5619
+ amount: item.amount,
5620
+ ttlSeconds: item.ttlSeconds,
5621
+ description: item.description
5622
+ }));
5623
+ return generateSolanaPaymentCodesBatch(config2, params.wallet, {
5624
+ network: params.network,
5625
+ items
5626
+ });
5627
+ }
5628
+ const network = params.network ?? "base-sepolia";
5629
+ const net = NETWORK_CONFIGS[network];
5630
+ if (!net) throw new Error(`Unsupported network: ${network}`);
5631
+ const relayerConfig = await fetchOrThrow(`${facilitatorUrl}/payment-codes/relayer-address`);
5632
+ const escrowAddresses = relayerConfig.escrowAddresses ?? {};
5633
+ const escrowAddress = escrowAddresses[network];
5634
+ if (!escrowAddress) throw new Error(`EVM escrow is not configured for ${network}`);
5635
+ const from4 = await params.signer.getAddress();
5636
+ const now = Math.floor(Date.now() / 1e3);
5637
+ const usdcContract = params.usdcContract ?? net.usdc;
5638
+ const normalizedCodes = params.codes.map((item) => {
5639
+ const amount2 = BigInt(item.amount);
5640
+ if (amount2 <= 0n) throw new Error("Each batch code amount must be positive");
5641
+ const ttlSeconds = Math.max(60, Math.round(Number(item.ttlSeconds ?? 86400)));
5642
+ return {
5643
+ value: amount2,
5644
+ validBefore: now + ttlSeconds,
5645
+ description: item.description?.trim() || void 0
5646
+ };
5647
+ });
5648
+ const totalAmount = normalizedCodes.reduce((sum, item) => sum + item.value, 0n);
5649
+ const authorizationValidBefore = String(now + AUTHORIZATION_WINDOW_SECONDS2);
5650
+ const authorizationNonce = randomBytes323();
5651
+ const domain2 = {
5652
+ name: net.domainName,
5653
+ version: TRANSFER_WITH_AUTHORIZATION_DOMAIN_VERSION,
5654
+ chainId: net.chainId,
5655
+ verifyingContract: usdcContract
5656
+ };
5657
+ const authorization = {
5658
+ from: from4,
5659
+ to: escrowAddress,
5660
+ value: totalAmount.toString(),
5661
+ validAfter: "0",
5662
+ validBefore: authorizationValidBefore,
5663
+ nonce: authorizationNonce
5664
+ };
5665
+ const signature2 = await params.signer.signTypedData(domain2, EIP3009_TYPES3, authorization);
5666
+ return fetchOrThrow(`${facilitatorUrl}/payment-codes/batch-funded`, {
5667
+ method: "POST",
5668
+ headers: { "Content-Type": "application/json" },
5669
+ body: JSON.stringify({
5670
+ from: from4,
5671
+ usdcContract,
5672
+ settlementNetwork: network,
5673
+ ...params.payee ? { payee: params.payee } : {},
5674
+ signature: signature2,
5675
+ authorization,
5676
+ codes: normalizedCodes.map((item) => ({
5677
+ value: item.value.toString(),
5678
+ validBefore: item.validBefore,
5679
+ ...item.description ? { description: item.description } : {}
5680
+ }))
5681
+ })
5682
+ });
5683
+ }
5684
+ async function listOwnerPaymentCodes(config2, params) {
5685
+ const facilitatorUrl = config2.facilitatorUrl ?? DEFAULT_FACILITATOR4;
5686
+ if (params.walletType === "solana") {
5687
+ if (!params.wallet.publicKey) throw new Error("Solana wallet not connected");
5688
+ const walletAddress2 = params.wallet.publicKey.toString();
5689
+ const challenge2 = await fetchOrThrow(`${facilitatorUrl}/payment-codes/owner/challenge`, {
5690
+ method: "POST",
5691
+ headers: { "Content-Type": "application/json" },
5692
+ body: JSON.stringify({ walletAddress: walletAddress2, walletType: "solana" })
5693
+ });
5694
+ const message2 = typeof challenge2.message === "string" ? challenge2.message : "";
5695
+ if (!message2) throw new Error("Failed to load owner challenge message");
5696
+ const signatureBytes = await params.wallet.signMessage(new TextEncoder().encode(message2));
5697
+ const session2 = await fetchOrThrow(`${facilitatorUrl}/payment-codes/owner/session`, {
5698
+ method: "POST",
5699
+ headers: { "Content-Type": "application/json" },
5700
+ body: JSON.stringify({ walletAddress: walletAddress2, walletType: "solana", signature: import_bs58.default.encode(signatureBytes) })
5701
+ });
5702
+ const accessToken2 = typeof session2.accessToken === "string" ? session2.accessToken : "";
5703
+ if (!accessToken2) throw new Error("Failed to create owner session");
5704
+ return fetchOrThrow(`${facilitatorUrl}/payment-codes/owner/codes`, {
5705
+ headers: { Authorization: `Bearer ${accessToken2}` }
5706
+ });
5707
+ }
5708
+ const walletAddress = await params.wallet.getAddress();
5709
+ const challenge = await fetchOrThrow(`${facilitatorUrl}/payment-codes/owner/challenge`, {
5710
+ method: "POST",
5711
+ headers: { "Content-Type": "application/json" },
5712
+ body: JSON.stringify({ walletAddress, walletType: "evm" })
5713
+ });
5714
+ const message = typeof challenge.message === "string" ? challenge.message : "";
5715
+ if (!message) throw new Error("Failed to load owner challenge message");
5716
+ const session = await fetchOrThrow(`${facilitatorUrl}/payment-codes/owner/session`, {
5717
+ method: "POST",
5718
+ headers: { "Content-Type": "application/json" },
5719
+ body: JSON.stringify({ walletAddress, walletType: "evm", signature: await params.wallet.signMessage(message) })
5720
+ });
5721
+ const accessToken = typeof session.accessToken === "string" ? session.accessToken : "";
5722
+ if (!accessToken) throw new Error("Failed to create owner session");
5723
+ return fetchOrThrow(`${facilitatorUrl}/payment-codes/owner/codes`, {
5724
+ headers: { Authorization: `Bearer ${accessToken}` }
5725
+ });
5726
+ }
5727
+ async function getPaymentCode2(config2, code) {
5728
+ const facilitatorUrl = config2.facilitatorUrl ?? DEFAULT_FACILITATOR4;
5729
+ const normalizedCode = code.trim().toUpperCase();
5730
+ const { payload } = await fetchStoredCodeWithFallback(facilitatorUrl, normalizedCode);
5731
+ return payload;
5732
+ }
5733
+ var getPaymentCodeDetails = getPaymentCode2;
5734
+ async function redeemStoredPaymentCode(config2, code, params) {
5735
+ const facilitatorUrl = config2.facilitatorUrl ?? DEFAULT_FACILITATOR4;
5736
+ const normalizedCode = code.trim().toUpperCase();
5737
+ const { payload } = await fetchStoredCodeWithFallback(facilitatorUrl, normalizedCode, {
5738
+ suffix: "redeem",
5739
+ init: {
5740
+ method: "POST",
5741
+ headers: { "Content-Type": "application/json" },
5742
+ body: JSON.stringify({
5743
+ payee: params.payee,
5744
+ ...params.evmNetwork ? { evmNetwork: params.evmNetwork } : {},
5745
+ ...params.solanaNetwork ? { solanaNetwork: params.solanaNetwork } : {}
5746
+ })
5747
+ }
5748
+ });
5749
+ return payload;
5750
+ }
5751
+ async function cancelStoredPaymentCode(config2, code, params = {}) {
5752
+ const facilitatorUrl = config2.facilitatorUrl ?? DEFAULT_FACILITATOR4;
5753
+ const normalizedCode = code.trim().toUpperCase();
5754
+ const statusInfo = await fetchStoredCodeWithFallback(facilitatorUrl, normalizedCode);
5755
+ if (statusInfo.kind === "solana") {
5756
+ if (!params.solanaWallet) {
5757
+ throw new Error("A Solana wallet is required to cancel this payment code");
5758
+ }
5759
+ return cancelSolanaPaymentCode(config2, normalizedCode, params.solanaWallet, {
5760
+ network: params.network === "solana" || params.network === "solana-devnet" ? params.network : void 0
5761
+ });
5762
+ }
5763
+ if (!params.wallet) {
5764
+ throw new Error("An EVM wallet is required to cancel this payment code");
5765
+ }
5766
+ const status = statusInfo.payload;
5767
+ const owner = await params.wallet.getAddress();
5768
+ const network = params.network ?? String(status.settlementNetwork || "base-sepolia");
5769
+ if (status.claimLink === true && typeof status.claimToken === "string" && status.escrowMode === true) {
5770
+ const issuedAt2 = Date.now();
5771
+ return fetchOrThrow(`${facilitatorUrl}/payment-codes/claim-links/evm/${status.claimToken}/cancel`, {
5772
+ method: "POST",
5773
+ headers: { "Content-Type": "application/json" },
5774
+ body: JSON.stringify({
5775
+ owner,
5776
+ issuedAt: issuedAt2,
5777
+ signature: await params.wallet.signMessage(buildClaimLinkCancelAuthorizationMessage(status.claimToken, owner, issuedAt2))
5778
+ })
5779
+ });
5780
+ }
5781
+ if (status.escrowMode === true) {
5782
+ if (!params.wallet.sendTransaction) {
5783
+ throw new Error("This EVM wallet does not support sendTransaction, which is required for escrow cancellation");
5784
+ }
5785
+ const relayerConfig = await fetchOrThrow(`${facilitatorUrl}/payment-codes/relayer-address`);
5786
+ const escrowAddresses = relayerConfig.escrowAddresses ?? {};
5787
+ const escrowAddress = escrowAddresses[network];
5788
+ if (!escrowAddress) throw new Error(`EVM escrow is not configured for ${network}`);
5789
+ const cancelInterface = new import_ethers3.ethers.Interface(EVM_ESCROW_ABI);
5790
+ const tx = await params.wallet.sendTransaction({
5791
+ to: escrowAddress,
5792
+ data: cancelInterface.encodeFunctionData("cancel", [codeToBytes8(normalizedCode)])
5793
+ });
5794
+ await tx.wait();
5795
+ return {
5796
+ success: true,
5797
+ code: normalizedCode,
5798
+ cancelTxHash: tx.hash,
5799
+ network
5800
+ };
5801
+ }
5802
+ const issuedAt = Date.now();
5803
+ return fetchOrThrow(`${facilitatorUrl}/payment-codes/${normalizedCode}/cancel`, {
5804
+ method: "POST",
5805
+ headers: { "Content-Type": "application/json" },
5806
+ body: JSON.stringify({
5807
+ owner,
5808
+ issuedAt,
5809
+ signature: await params.wallet.signMessage(buildCancelAuthorizationMessage(normalizedCode, owner, issuedAt))
5810
+ })
5811
+ });
5812
+ }
5813
+ async function claimPaymentLink(config2, claimUrlOrToken, params) {
5814
+ const facilitatorUrl = config2.facilitatorUrl ?? DEFAULT_FACILITATOR4;
5815
+ const claimToken = extractClaimToken(claimUrlOrToken);
5816
+ if (!claimToken) throw new Error("Claim URL or claim token is required");
5817
+ const issuedAt = Date.now();
5818
+ const mode = params.mode ?? "claim-usdc";
5819
+ if ("solanaWallet" in params && params.solanaWallet) {
5820
+ if (!params.solanaWallet.publicKey) throw new Error("Solana wallet not connected");
5821
+ const claimer2 = params.solanaWallet.publicKey.toString();
5822
+ const requestedPayee2 = params.payee?.trim() || claimer2;
5823
+ const targetAddress2 = mode === "claim-usdc" ? isEvmAddress(requestedPayee2) ? requestedPayee2.toLowerCase() : requestedPayee2 : null;
5824
+ const targetNetwork2 = mode === "claim-usdc" ? targetAddress2 == null ? null : isEvmAddress(targetAddress2) ? params.evmNetwork ?? null : params.solanaNetwork ?? null : null;
5825
+ const message2 = buildSolanaClaimLinkAuthorizationMessage({
5826
+ claimToken,
5827
+ claimer: claimer2,
5828
+ issuedAt,
5829
+ mode,
5830
+ targetAddress: targetAddress2,
5831
+ targetNetwork: targetNetwork2
5832
+ });
5833
+ const signatureBytes = await params.solanaWallet.signMessage(new TextEncoder().encode(message2));
5834
+ const payload2 = await fetchOrThrow(`${facilitatorUrl}/solana-payment-codes/claim-links/${claimToken}/claim`, {
5835
+ method: "POST",
5836
+ headers: { "Content-Type": "application/json" },
5837
+ body: JSON.stringify({
5838
+ claimer: claimer2,
5839
+ issuedAt,
5840
+ signature: import_bs58.default.encode(signatureBytes),
5841
+ mode,
5842
+ ...targetAddress2 ? { targetAddress: targetAddress2 } : {},
5843
+ ...targetNetwork2 ? { targetNetwork: targetNetwork2 } : {}
5844
+ })
5845
+ });
5846
+ return sanitizeClaimLinkResponse(payload2, facilitatorUrl, claimToken);
5847
+ }
5848
+ if (!("wallet" in params) || !params.wallet) {
5849
+ throw new Error("An EVM wallet or Solana wallet is required to claim this payment link");
5850
+ }
5851
+ const claimer = (await params.wallet.getAddress()).toLowerCase();
5852
+ const requestedPayee = params.payee?.trim() || claimer;
5853
+ const targetAddress = mode === "claim-usdc" ? isEvmAddress(requestedPayee) ? requestedPayee.toLowerCase() : requestedPayee : null;
5854
+ const targetNetwork = mode === "claim-usdc" ? targetAddress == null ? null : isEvmAddress(targetAddress) ? params.evmNetwork ?? null : params.solanaNetwork ?? null : null;
5855
+ const message = buildEvmClaimLinkAuthorizationMessage({
5856
+ claimToken,
5857
+ claimer,
5858
+ issuedAt,
5859
+ mode,
5860
+ targetAddress,
5861
+ targetNetwork
5862
+ });
5863
+ const payload = await fetchOrThrow(`${facilitatorUrl}/payment-codes/claim-links/evm/${claimToken}/claim`, {
5864
+ method: "POST",
5865
+ headers: { "Content-Type": "application/json" },
5866
+ body: JSON.stringify({
5867
+ claimer,
5868
+ issuedAt,
5869
+ signature: await params.wallet.signMessage(message),
5870
+ mode,
5871
+ ...targetAddress ? { targetAddress, payee: targetAddress } : {},
5872
+ ...targetNetwork ? { targetNetwork } : {},
5873
+ ...targetAddress && isEvmAddress(targetAddress) && targetNetwork ? { evmNetwork: targetNetwork } : {},
5874
+ ...targetAddress && !isEvmAddress(targetAddress) && targetNetwork ? { solanaNetwork: targetNetwork } : {}
5875
+ })
5876
+ });
5877
+ return sanitizeClaimLinkResponse(payload, facilitatorUrl, claimToken);
5878
+ }
5879
+ async function payPayRequestWithStoredCode(config2, requestCode, paymentCode, options = {}) {
5880
+ const facilitatorUrl = config2.facilitatorUrl ?? DEFAULT_FACILITATOR4;
5881
+ const normalizedRequestCode = requestCode.trim().toUpperCase();
5882
+ const normalizedPaymentCode = paymentCode.trim().toUpperCase();
5883
+ const codeStatusInfo = await fetchStoredCodeWithFallback(facilitatorUrl, normalizedPaymentCode);
5884
+ if (codeStatusInfo.kind === "solana") {
5885
+ return fetchOrThrow(`${facilitatorUrl}/solana-payment-codes/${normalizedPaymentCode}/pay-request`, {
5886
+ method: "POST",
5887
+ headers: { "Content-Type": "application/json" },
5888
+ body: JSON.stringify({
5889
+ requestCode: normalizedRequestCode,
5890
+ ...options.changeAddress ? { changeAddress: options.changeAddress } : {}
5891
+ })
5892
+ });
5893
+ }
5894
+ const requestInfo = await getPayRequest(config2, normalizedRequestCode);
5895
+ const codeStatus = codeStatusInfo.payload;
5896
+ const allowOverpayment = options.allowOverpayment ?? true;
5897
+ const returnChange = options.returnChange ?? "code";
5898
+ const codeValue = BigInt(String(codeStatus.value ?? 0));
5899
+ const requestAmount = BigInt(requestInfo.amount);
5900
+ if (codeValue < requestAmount) {
5901
+ throw new Error(
5902
+ `Payment code value (${Number(codeValue) / 1e6} USDC) is less than the request amount (${Number(requestAmount) / 1e6} USDC)`
5903
+ );
5904
+ }
5905
+ if (!allowOverpayment && codeValue > requestAmount) {
5906
+ throw new Error(
5907
+ `Payment code value (${Number(codeValue) / 1e6} USDC) exceeds the request amount (${Number(requestAmount) / 1e6} USDC)`
5908
+ );
5909
+ }
5910
+ const merchantAddress = String(requestInfo.to);
5911
+ const requestNetwork = String(requestInfo.network);
5912
+ const usePartial = codeValue > requestAmount;
5913
+ return fetchOrThrow(`${facilitatorUrl}/payment-codes/${normalizedPaymentCode}/redeem`, {
5914
+ method: "POST",
5915
+ headers: { "Content-Type": "application/json" },
5916
+ body: JSON.stringify({
5917
+ payee: merchantAddress,
5918
+ ...usePartial ? { invoiceAmount: requestInfo.amount.toString() } : {},
5919
+ ...usePartial ? { returnChangeAsCode: returnChange === "code" } : {},
5920
+ ...usePartial && options.changeAddress ? { changeAddress: options.changeAddress } : {},
5921
+ ...isEvmAddress(merchantAddress) ? { evmNetwork: requestNetwork } : { solanaNetwork: requestNetwork }
5922
+ })
5923
+ });
5924
+ }
5925
+
5214
5926
  // src/utils/payload-converter.ts
5215
5927
  var NETWORK_V1_TO_V2 = {
5216
5928
  "solana": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",
@@ -18991,10 +19703,14 @@ var BRIDGE_INFO_TTL_MS = 5 * 60 * 1e3;
18991
19703
  USDC_SOLANA,
18992
19704
  cancelPaymentCode,
18993
19705
  cancelSolanaPaymentCode,
19706
+ cancelStoredPaymentCode,
19707
+ claimPaymentLink,
18994
19708
  convertPayloadToVersion,
18995
19709
  convertV1ToV2,
18996
19710
  convertV2ToV1,
18997
19711
  createPayRequest,
19712
+ createPaymentCode,
19713
+ createPaymentCodesBatch,
18998
19714
  createPrivateKeySigner,
18999
19715
  createX402Client,
19000
19716
  detectPayloadVersion,
@@ -19008,11 +19724,13 @@ var BRIDGE_INFO_TTL_MS = 5 * 60 * 1e3;
19008
19724
  generateSolanaPaymentCode,
19009
19725
  getPayRequest,
19010
19726
  getPaymentCode,
19727
+ getPaymentCodeDetails,
19011
19728
  getSolanaPaymentCode,
19012
19729
  isEvm,
19013
19730
  isEvmNetwork,
19014
19731
  isSolana,
19015
19732
  isSolanaNetwork,
19733
+ listOwnerPaymentCodes,
19016
19734
  networkV1ToV2,
19017
19735
  networkV2ToV1,
19018
19736
  normalizeNetwork,
@@ -19020,8 +19738,10 @@ var BRIDGE_INFO_TTL_MS = 5 * 60 * 1e3;
19020
19738
  payPayRequest,
19021
19739
  payPayRequestWithCode,
19022
19740
  payPayRequestWithSolana,
19741
+ payPayRequestWithStoredCode,
19023
19742
  redeemPaymentCode,
19024
19743
  redeemSolanaPaymentCode,
19744
+ redeemStoredPaymentCode,
19025
19745
  resolveToken,
19026
19746
  stripePayTo,
19027
19747
  submitRelayFeedback,