@relai-fi/x402 0.5.29 → 0.5.31

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.js CHANGED
@@ -1211,6 +1211,88 @@ function createX402Client(config) {
1211
1211
  }
1212
1212
  return null;
1213
1213
  }
1214
+ function getBridgeExtension(requirements) {
1215
+ const ext = requirements?.extensions?.bridge;
1216
+ if (!ext?.info?.settleEndpoint || !Array.isArray(ext.info.supportedSourceChains)) return null;
1217
+ return ext.info;
1218
+ }
1219
+ function selectBridgeSource(bridge) {
1220
+ const sourceChains = bridge.supportedSourceChains || [];
1221
+ const sourceAssets = bridge.supportedSourceAssets || [];
1222
+ for (const caip2 of sourceChains) {
1223
+ if (isSolana(caip2) && hasSolanaWallet) {
1224
+ const asset = sourceAssets.find((a) => !a.startsWith("0x")) || "";
1225
+ return { chain: "solana", network: caip2, asset };
1226
+ }
1227
+ if (isEvm(caip2) && effectiveWallets.evm) {
1228
+ const asset = sourceAssets.find((a) => a.startsWith("0x")) || "";
1229
+ return { chain: "evm", network: caip2, asset };
1230
+ }
1231
+ }
1232
+ return null;
1233
+ }
1234
+ async function executeBridgePayment(bridge, accepts, requirements, url) {
1235
+ const source = selectBridgeSource(bridge);
1236
+ if (!source) {
1237
+ throw new Error("[relai-x402] bridge extension found but no wallet matches supported source chains");
1238
+ }
1239
+ const targetAccept = accepts[0];
1240
+ const amount = targetAccept.amount || targetAccept.maxAmountRequired;
1241
+ log(`Bridge: ${source.network} \u2192 ${targetAccept.network}, amount=${amount}`);
1242
+ if (maxAmountAtomic && BigInt(amount) > BigInt(maxAmountAtomic)) {
1243
+ throw new Error(`[relai-x402] Amount ${amount} exceeds max ${maxAmountAtomic}`);
1244
+ }
1245
+ let sourcePaymentHeader;
1246
+ if (source.chain === "solana") {
1247
+ if (!bridge.payTo) {
1248
+ throw new Error("[relai-x402] bridge.info.payTo is required for Solana source payments");
1249
+ }
1250
+ const sourceAccept = {
1251
+ scheme: "exact",
1252
+ network: source.network,
1253
+ asset: source.asset,
1254
+ payTo: bridge.payTo,
1255
+ amount: targetAccept.amount || targetAccept.maxAmountRequired,
1256
+ extra: {
1257
+ ...bridge.feePayerSvm ? { feePayer: bridge.feePayerSvm } : {},
1258
+ decimals: 6
1259
+ }
1260
+ };
1261
+ sourcePaymentHeader = await buildSolanaPayment(sourceAccept, requirements, url);
1262
+ } else {
1263
+ const evmNetwork = normalizeNetwork(source.network);
1264
+ const usePermit = evmNetwork && PERMIT_NETWORKS.has(evmNetwork);
1265
+ const sourceAccept = {
1266
+ ...targetAccept,
1267
+ network: source.network,
1268
+ asset: source.asset || targetAccept.asset,
1269
+ ...bridge.payTo ? { payTo: bridge.payTo } : {}
1270
+ };
1271
+ sourcePaymentHeader = usePermit ? await buildEvmPermitPayment(sourceAccept, requirements, url) : await buildEvmPayment(sourceAccept, requirements, url);
1272
+ }
1273
+ const bridgeRes = await fetch(bridge.settleEndpoint, {
1274
+ method: "POST",
1275
+ headers: { "Content-Type": "application/json" },
1276
+ body: JSON.stringify({
1277
+ sourcePayment: sourcePaymentHeader,
1278
+ sourceChain: source.network,
1279
+ targetAccept,
1280
+ requirements,
1281
+ resource: url,
1282
+ paymentFacilitator: bridge.paymentFacilitator || null
1283
+ })
1284
+ });
1285
+ if (!bridgeRes.ok) {
1286
+ const err = await bridgeRes.json().catch(() => ({}));
1287
+ throw new Error(`[relai-x402] bridge settle failed: ${err.error || bridgeRes.status}`);
1288
+ }
1289
+ const bridgeData = await bridgeRes.json();
1290
+ if (!bridgeData.xPayment) {
1291
+ throw new Error("[relai-x402] bridge endpoint did not return xPayment header");
1292
+ }
1293
+ log(`Bridge settled: sourceTx=${bridgeData.sourceTxId}, targetTx=${bridgeData.targetTxId}`);
1294
+ return bridgeData.xPayment;
1295
+ }
1214
1296
  async function evmRpcCall(rpcUrl, to, data) {
1215
1297
  const res = await fetch(rpcUrl, {
1216
1298
  method: "POST",
@@ -1655,6 +1737,16 @@ function createX402Client(config) {
1655
1737
  if (!accepts.length) throw new Error("[relai-x402] No payment options in 402 response");
1656
1738
  const selected = selectAccept(accepts);
1657
1739
  if (!selected) {
1740
+ const bridge = getBridgeExtension(requirements);
1741
+ if (bridge && selectBridgeSource(bridge)) {
1742
+ log("No direct wallet match \u2014 attempting bridge extension flow");
1743
+ const paymentHeader = await executeBridgePayment(bridge, accepts, requirements, url);
1744
+ log("Retrying with X-PAYMENT header (bridge)");
1745
+ return fetch(input, {
1746
+ ...requestInitWithHeaders,
1747
+ headers: { ...requestHeaders, "X-PAYMENT": paymentHeader }
1748
+ });
1749
+ }
1658
1750
  throw new Error(buildNoWalletError(accepts, false));
1659
1751
  }
1660
1752
  const { accept, chain } = selected;