@relai-fi/x402 0.5.28 → 0.5.30
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/client.cjs +93 -9
- package/dist/client.cjs.map +1 -1
- package/dist/client.js +93 -10
- package/dist/client.js.map +1 -1
- package/dist/index.cjs +93 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +93 -10
- package/dist/index.js.map +1 -1
- package/dist/react/index.cjs +93 -9
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.js +93 -10
- package/dist/react/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1260,6 +1260,88 @@ function createX402Client(config) {
|
|
|
1260
1260
|
}
|
|
1261
1261
|
return null;
|
|
1262
1262
|
}
|
|
1263
|
+
function getBridgeExtension(requirements) {
|
|
1264
|
+
const ext = requirements?.extensions?.bridge;
|
|
1265
|
+
if (!ext?.info?.endpoint || !Array.isArray(ext.info.supportedSourceChains)) return null;
|
|
1266
|
+
return ext.info;
|
|
1267
|
+
}
|
|
1268
|
+
function selectBridgeSource(bridge) {
|
|
1269
|
+
const sourceChains = bridge.supportedSourceChains || [];
|
|
1270
|
+
const sourceAssets = bridge.supportedSourceAssets || [];
|
|
1271
|
+
for (const caip2 of sourceChains) {
|
|
1272
|
+
if (isSolana(caip2) && hasSolanaWallet) {
|
|
1273
|
+
const asset = sourceAssets.find((a) => !a.startsWith("0x")) || "";
|
|
1274
|
+
return { chain: "solana", network: caip2, asset };
|
|
1275
|
+
}
|
|
1276
|
+
if (isEvm(caip2) && effectiveWallets.evm) {
|
|
1277
|
+
const asset = sourceAssets.find((a) => a.startsWith("0x")) || "";
|
|
1278
|
+
return { chain: "evm", network: caip2, asset };
|
|
1279
|
+
}
|
|
1280
|
+
}
|
|
1281
|
+
return null;
|
|
1282
|
+
}
|
|
1283
|
+
async function executeBridgePayment(bridge, accepts, requirements, url) {
|
|
1284
|
+
const source = selectBridgeSource(bridge);
|
|
1285
|
+
if (!source) {
|
|
1286
|
+
throw new Error("[relai-x402] bridge extension found but no wallet matches supported source chains");
|
|
1287
|
+
}
|
|
1288
|
+
const targetAccept = accepts[0];
|
|
1289
|
+
const amount = targetAccept.amount || targetAccept.maxAmountRequired;
|
|
1290
|
+
log(`Bridge: ${source.network} \u2192 ${targetAccept.network}, amount=${amount}`);
|
|
1291
|
+
if (maxAmountAtomic && BigInt(amount) > BigInt(maxAmountAtomic)) {
|
|
1292
|
+
throw new Error(`[relai-x402] Amount ${amount} exceeds max ${maxAmountAtomic}`);
|
|
1293
|
+
}
|
|
1294
|
+
let sourcePaymentHeader;
|
|
1295
|
+
if (source.chain === "solana") {
|
|
1296
|
+
if (!bridge.payTo) {
|
|
1297
|
+
throw new Error("[relai-x402] bridge.info.payTo is required for Solana source payments");
|
|
1298
|
+
}
|
|
1299
|
+
const sourceAccept = {
|
|
1300
|
+
scheme: "exact",
|
|
1301
|
+
network: source.network,
|
|
1302
|
+
asset: source.asset,
|
|
1303
|
+
payTo: bridge.payTo,
|
|
1304
|
+
amount: targetAccept.amount || targetAccept.maxAmountRequired,
|
|
1305
|
+
extra: {
|
|
1306
|
+
...bridge.feePayer ? { feePayer: bridge.feePayer } : {},
|
|
1307
|
+
decimals: 6
|
|
1308
|
+
}
|
|
1309
|
+
};
|
|
1310
|
+
sourcePaymentHeader = await buildSolanaPayment(sourceAccept, requirements, url);
|
|
1311
|
+
} else {
|
|
1312
|
+
const evmNetwork = normalizeNetwork(source.network);
|
|
1313
|
+
const usePermit = evmNetwork && PERMIT_NETWORKS.has(evmNetwork);
|
|
1314
|
+
const sourceAccept = {
|
|
1315
|
+
...targetAccept,
|
|
1316
|
+
network: source.network,
|
|
1317
|
+
asset: source.asset || targetAccept.asset,
|
|
1318
|
+
...bridge.payTo ? { payTo: bridge.payTo } : {}
|
|
1319
|
+
};
|
|
1320
|
+
sourcePaymentHeader = usePermit ? await buildEvmPermitPayment(sourceAccept, requirements, url) : await buildEvmPayment(sourceAccept, requirements, url);
|
|
1321
|
+
}
|
|
1322
|
+
const bridgeRes = await fetch(bridge.endpoint, {
|
|
1323
|
+
method: "POST",
|
|
1324
|
+
headers: { "Content-Type": "application/json" },
|
|
1325
|
+
body: JSON.stringify({
|
|
1326
|
+
sourcePayment: sourcePaymentHeader,
|
|
1327
|
+
sourceChain: source.network,
|
|
1328
|
+
targetAccept,
|
|
1329
|
+
requirements,
|
|
1330
|
+
resource: url,
|
|
1331
|
+
paymentFacilitator: bridge.paymentFacilitator || null
|
|
1332
|
+
})
|
|
1333
|
+
});
|
|
1334
|
+
if (!bridgeRes.ok) {
|
|
1335
|
+
const err = await bridgeRes.json().catch(() => ({}));
|
|
1336
|
+
throw new Error(`[relai-x402] bridge settle failed: ${err.error || bridgeRes.status}`);
|
|
1337
|
+
}
|
|
1338
|
+
const bridgeData = await bridgeRes.json();
|
|
1339
|
+
if (!bridgeData.xPayment) {
|
|
1340
|
+
throw new Error("[relai-x402] bridge endpoint did not return xPayment header");
|
|
1341
|
+
}
|
|
1342
|
+
log(`Bridge settled: sourceTx=${bridgeData.sourceTxId}, targetTx=${bridgeData.targetTxId}`);
|
|
1343
|
+
return bridgeData.xPayment;
|
|
1344
|
+
}
|
|
1263
1345
|
async function evmRpcCall(rpcUrl, to, data) {
|
|
1264
1346
|
const res = await fetch(rpcUrl, {
|
|
1265
1347
|
method: "POST",
|
|
@@ -1517,19 +1599,11 @@ function createX402Client(config) {
|
|
|
1517
1599
|
[],
|
|
1518
1600
|
programId
|
|
1519
1601
|
);
|
|
1520
|
-
const createDestAtaIx = (0, import_spl_token.createAssociatedTokenAccountIdempotentInstruction)(
|
|
1521
|
-
feePayerPubkey,
|
|
1522
|
-
// payer (feePayer covers this)
|
|
1523
|
-
destinationAta,
|
|
1524
|
-
merchantPubkey,
|
|
1525
|
-
mintPubkey,
|
|
1526
|
-
programId
|
|
1527
|
-
);
|
|
1528
1602
|
const { blockhash } = await connection.getLatestBlockhash("confirmed");
|
|
1529
1603
|
const message = new import_web3.TransactionMessage({
|
|
1530
1604
|
payerKey: feePayerPubkey,
|
|
1531
1605
|
recentBlockhash: blockhash,
|
|
1532
|
-
instructions: [
|
|
1606
|
+
instructions: [transferIx]
|
|
1533
1607
|
}).compileToV0Message();
|
|
1534
1608
|
const transaction = new import_web3.VersionedTransaction(message);
|
|
1535
1609
|
const signedTx = await solWallet.signTransaction(transaction);
|
|
@@ -1712,6 +1786,16 @@ function createX402Client(config) {
|
|
|
1712
1786
|
if (!accepts.length) throw new Error("[relai-x402] No payment options in 402 response");
|
|
1713
1787
|
const selected = selectAccept(accepts);
|
|
1714
1788
|
if (!selected) {
|
|
1789
|
+
const bridge = getBridgeExtension(requirements);
|
|
1790
|
+
if (bridge && selectBridgeSource(bridge)) {
|
|
1791
|
+
log("No direct wallet match \u2014 attempting bridge extension flow");
|
|
1792
|
+
const paymentHeader = await executeBridgePayment(bridge, accepts, requirements, url);
|
|
1793
|
+
log("Retrying with X-PAYMENT header (bridge)");
|
|
1794
|
+
return fetch(input, {
|
|
1795
|
+
...requestInitWithHeaders,
|
|
1796
|
+
headers: { ...requestHeaders, "X-PAYMENT": paymentHeader }
|
|
1797
|
+
});
|
|
1798
|
+
}
|
|
1715
1799
|
throw new Error(buildNoWalletError(accepts, false));
|
|
1716
1800
|
}
|
|
1717
1801
|
const { accept, chain } = selected;
|