@relai-fi/x402 0.6.5 → 0.6.7
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/README.md +251 -0
- package/dist/bridge.cjs +109 -0
- package/dist/bridge.cjs.map +1 -0
- package/dist/bridge.d.cts +78 -0
- package/dist/bridge.d.ts +78 -0
- package/dist/bridge.js +80 -0
- package/dist/bridge.js.map +1 -0
- package/dist/client.cjs +131 -1
- package/dist/client.cjs.map +1 -1
- package/dist/client.d.cts +13 -1
- package/dist/client.d.ts +13 -1
- package/dist/client.js +131 -1
- package/dist/client.js.map +1 -1
- package/dist/index.cjs +586 -105
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +291 -30
- package/dist/index.d.ts +291 -30
- package/dist/index.js +578 -105
- package/dist/index.js.map +1 -1
- package/dist/mpp/bridge-client.cjs +23922 -0
- package/dist/mpp/bridge-client.cjs.map +1 -0
- package/dist/mpp/bridge-client.d.cts +58 -0
- package/dist/mpp/bridge-client.d.ts +58 -0
- package/dist/mpp/bridge-client.js +23892 -0
- package/dist/mpp/bridge-client.js.map +1 -0
- package/dist/mpp/bridge-method.cjs +13202 -0
- package/dist/mpp/bridge-method.cjs.map +1 -0
- package/dist/mpp/bridge-method.d.cts +69 -0
- package/dist/mpp/bridge-method.d.ts +69 -0
- package/dist/mpp/bridge-method.js +13181 -0
- package/dist/mpp/bridge-method.js.map +1 -0
- package/dist/mpp/bridge-server.cjs +13887 -0
- package/dist/mpp/bridge-server.cjs.map +1 -0
- package/dist/mpp/bridge-server.d.cts +62 -0
- package/dist/mpp/bridge-server.d.ts +62 -0
- package/dist/mpp/bridge-server.js +13866 -0
- package/dist/mpp/bridge-server.js.map +1 -0
- package/dist/mpp/evm-server.cjs +49 -33
- package/dist/mpp/evm-server.cjs.map +1 -1
- package/dist/mpp/evm-server.js +49 -33
- package/dist/mpp/evm-server.js.map +1 -1
- package/dist/mpp/verify-erc20.cjs +71 -0
- package/dist/mpp/verify-erc20.cjs.map +1 -0
- package/dist/mpp/verify-erc20.d.cts +27 -0
- package/dist/mpp/verify-erc20.d.ts +27 -0
- package/dist/mpp/verify-erc20.js +46 -0
- package/dist/mpp/verify-erc20.js.map +1 -0
- package/dist/mpp/verify-spl.cjs +96 -0
- package/dist/mpp/verify-spl.cjs.map +1 -0
- package/dist/mpp/verify-spl.d.cts +30 -0
- package/dist/mpp/verify-spl.d.ts +30 -0
- package/dist/mpp/verify-spl.js +71 -0
- package/dist/mpp/verify-spl.js.map +1 -0
- package/dist/mpp/with-bridge.cjs +23956 -0
- package/dist/mpp/with-bridge.cjs.map +1 -0
- package/dist/mpp/with-bridge.d.cts +53 -0
- package/dist/mpp/with-bridge.d.ts +53 -0
- package/dist/mpp/with-bridge.js +23926 -0
- package/dist/mpp/with-bridge.js.map +1 -0
- package/dist/plugins.d.cts +2 -2
- package/dist/plugins.d.ts +2 -2
- package/dist/react/index.cjs +131 -1
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +1 -1
- package/dist/react/index.d.ts +1 -1
- package/dist/react/index.js +131 -1
- package/dist/react/index.js.map +1 -1
- package/dist/{server-DaySqG5H.d.ts → server-D9ZfrFFx.d.ts} +1 -1
- package/dist/{server-CBZ2RjEP.d.cts → server-DgMG2zhy.d.cts} +1 -1
- package/dist/server.cjs +6 -39
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.cts +2 -2
- package/dist/server.d.ts +2 -2
- package/dist/server.js +6 -39
- package/dist/server.js.map +1 -1
- package/dist/{types-Y9ni5XwY.d.cts → types-DjEveKgt.d.cts} +1 -1
- package/dist/{types-Y9ni5XwY.d.ts → types-DjEveKgt.d.ts} +1 -1
- package/package.json +31 -1
package/dist/client.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { W as WalletSet,
|
|
1
|
+
import { W as WalletSet, S as SolanaWallet, R as RelaiNetwork } from './types-DjEveKgt.js';
|
|
2
2
|
|
|
3
3
|
type X402NetworkSelectionMode = 'prefer_then_any' | 'strict_preferred';
|
|
4
4
|
/**
|
|
@@ -62,6 +62,18 @@ interface X402ClientConfig {
|
|
|
62
62
|
* Pass an mppx client instance (from `Mppx.create()`).
|
|
63
63
|
*/
|
|
64
64
|
mpp?: MppHandler;
|
|
65
|
+
/**
|
|
66
|
+
* Enable transparent cross-chain bridge.
|
|
67
|
+
* When set, the client auto-discovers bridge info from the RelAI API and
|
|
68
|
+
* bridges payments when no wallet matches the server's accepted chains.
|
|
69
|
+
* The server does NOT need to advertise bridge support — it just verifies
|
|
70
|
+
* a normal on-chain payment on its target chain.
|
|
71
|
+
*/
|
|
72
|
+
bridge?: {
|
|
73
|
+
enabled?: boolean;
|
|
74
|
+
/** RelAI API base URL for auto-discovery (default: https://api.relai.fi) */
|
|
75
|
+
baseUrl?: string;
|
|
76
|
+
};
|
|
65
77
|
}
|
|
66
78
|
type X402IntegritasFlow = 'single' | 'dual';
|
|
67
79
|
interface X402IntegritasConfig {
|
package/dist/client.js
CHANGED
|
@@ -226,6 +226,71 @@ function normalizeNetwork(network) {
|
|
|
226
226
|
return null;
|
|
227
227
|
}
|
|
228
228
|
|
|
229
|
+
// src/bridge.ts
|
|
230
|
+
var RELAI_API_BASE = "https://api.relai.fi";
|
|
231
|
+
var _cacheMap = /* @__PURE__ */ new Map();
|
|
232
|
+
var CACHE_TTL = 5 * 60 * 1e3;
|
|
233
|
+
async function getBridgeInfo(baseUrl = RELAI_API_BASE) {
|
|
234
|
+
const key = baseUrl.replace(/\/$/, "");
|
|
235
|
+
const now = Date.now();
|
|
236
|
+
const cached = _cacheMap.get(key);
|
|
237
|
+
if (cached && now - cached.time < CACHE_TTL) return cached.info;
|
|
238
|
+
const url = `${key}/bridge/info`;
|
|
239
|
+
const res = await fetch(url);
|
|
240
|
+
if (!res.ok) {
|
|
241
|
+
if (cached) return cached.info;
|
|
242
|
+
throw new Error(`[relai:bridge] Failed to fetch ${url}: ${res.status}`);
|
|
243
|
+
}
|
|
244
|
+
const data = await res.json();
|
|
245
|
+
const info = {
|
|
246
|
+
settleEndpoint: data.settleEndpoint,
|
|
247
|
+
supportedSourceChains: data.supportedSourceChains || [],
|
|
248
|
+
supportedSourceAssets: data.supportedSourceAssets || [],
|
|
249
|
+
payTo: data.payTo || {},
|
|
250
|
+
feePayerSvm: data.feePayerSvm ?? null,
|
|
251
|
+
feeBps: data.feeBps ?? 100,
|
|
252
|
+
paymentFacilitator: data.paymentFacilitator || "https://facilitator.x402.fi"
|
|
253
|
+
};
|
|
254
|
+
_cacheMap.set(key, { info, time: now });
|
|
255
|
+
return info;
|
|
256
|
+
}
|
|
257
|
+
async function settleBridge(settleEndpoint, body) {
|
|
258
|
+
const res = await fetch(settleEndpoint, {
|
|
259
|
+
method: "POST",
|
|
260
|
+
headers: { "Content-Type": "application/json" },
|
|
261
|
+
body: JSON.stringify(body)
|
|
262
|
+
});
|
|
263
|
+
if (!res.ok) {
|
|
264
|
+
const err = await res.json().catch(() => ({}));
|
|
265
|
+
throw new Error(`[relai:bridge] settle failed: ${err.error || res.status}${err.details ? " \u2014 " + err.details : ""}`);
|
|
266
|
+
}
|
|
267
|
+
return res.json();
|
|
268
|
+
}
|
|
269
|
+
function selectSourceChain(supportedChains, hasEvmWallet, hasSolanaWallet, preferredSourceChainId) {
|
|
270
|
+
if (preferredSourceChainId && hasEvmWallet) {
|
|
271
|
+
const preferred = `eip155:${preferredSourceChainId}`;
|
|
272
|
+
if (supportedChains.includes(preferred)) {
|
|
273
|
+
return { type: "evm", chain: preferred };
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
if (hasSolanaWallet) {
|
|
277
|
+
const sol = supportedChains.find((c) => c.startsWith("solana:"));
|
|
278
|
+
if (sol) return { type: "solana", chain: sol };
|
|
279
|
+
}
|
|
280
|
+
if (hasEvmWallet) {
|
|
281
|
+
for (const chain of supportedChains) {
|
|
282
|
+
if (chain.startsWith("eip155:")) {
|
|
283
|
+
return { type: "evm", chain };
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
return null;
|
|
288
|
+
}
|
|
289
|
+
function computeSourceAmount(targetAmount, feeBps) {
|
|
290
|
+
const fee = targetAmount * BigInt(feeBps) / 10000n;
|
|
291
|
+
return targetAmount + fee;
|
|
292
|
+
}
|
|
293
|
+
|
|
229
294
|
// src/client.ts
|
|
230
295
|
var PERMIT_NETWORKS = /* @__PURE__ */ new Set([]);
|
|
231
296
|
var DEFAULT_EVM_RPC_URLS = {
|
|
@@ -252,7 +317,8 @@ function createX402Client(config) {
|
|
|
252
317
|
integritas,
|
|
253
318
|
verbose = false,
|
|
254
319
|
defaultHeaders = {},
|
|
255
|
-
mpp
|
|
320
|
+
mpp,
|
|
321
|
+
bridge: bridgeConfig
|
|
256
322
|
} = config;
|
|
257
323
|
const relayWsEnabled = relayWs?.enabled === true;
|
|
258
324
|
const relayWsPreflightTimeoutMs = relayWs?.preflightTimeoutMs ?? 5e3;
|
|
@@ -1367,6 +1433,70 @@ function createX402Client(config) {
|
|
|
1367
1433
|
headers: { ...requestHeaders, "X-PAYMENT": paymentHeader }
|
|
1368
1434
|
});
|
|
1369
1435
|
}
|
|
1436
|
+
if (bridgeConfig?.enabled) {
|
|
1437
|
+
log("No direct wallet match \u2014 attempting auto-bridge via RelAI API");
|
|
1438
|
+
try {
|
|
1439
|
+
const info = await getBridgeInfo(bridgeConfig.baseUrl);
|
|
1440
|
+
const targetAccept = accepts[0];
|
|
1441
|
+
const hasEvm = !!effectiveWallets.evm;
|
|
1442
|
+
const hasSol = !!hasSolanaWallet;
|
|
1443
|
+
const source = selectSourceChain(info.supportedSourceChains, hasEvm, hasSol);
|
|
1444
|
+
if (source) {
|
|
1445
|
+
const bridgePayTo = info.payTo[source.chain];
|
|
1446
|
+
if (bridgePayTo) {
|
|
1447
|
+
const targetAmount = targetAccept.amount || targetAccept.maxAmountRequired;
|
|
1448
|
+
const sourceAmount = computeSourceAmount(BigInt(targetAmount), info.feeBps).toString();
|
|
1449
|
+
const sourceChainIdx = info.supportedSourceChains.indexOf(source.chain);
|
|
1450
|
+
const sourceAsset = sourceChainIdx >= 0 && info.supportedSourceAssets[sourceChainIdx] || (source.type === "evm" ? info.supportedSourceAssets.find((a) => a.startsWith("0x")) || targetAccept.asset : info.supportedSourceAssets.find((a) => !a.startsWith("0x")) || "");
|
|
1451
|
+
let sourcePaymentHeader;
|
|
1452
|
+
const sourceAccept = {
|
|
1453
|
+
scheme: "exact",
|
|
1454
|
+
network: source.chain,
|
|
1455
|
+
asset: sourceAsset,
|
|
1456
|
+
payTo: bridgePayTo,
|
|
1457
|
+
amount: sourceAmount,
|
|
1458
|
+
extra: {
|
|
1459
|
+
...targetAccept.extra || {},
|
|
1460
|
+
...source.type === "solana" && info.feePayerSvm ? { feePayer: info.feePayerSvm } : {}
|
|
1461
|
+
}
|
|
1462
|
+
};
|
|
1463
|
+
if (source.type === "solana" && hasSolanaWallet) {
|
|
1464
|
+
sourcePaymentHeader = await buildSolanaPayment(sourceAccept, requirements, url);
|
|
1465
|
+
} else if (source.type === "evm") {
|
|
1466
|
+
const evmNetwork = normalizeNetwork(source.chain);
|
|
1467
|
+
const usePermit = evmNetwork && PERMIT_NETWORKS.has(evmNetwork);
|
|
1468
|
+
sourcePaymentHeader = usePermit ? await buildEvmPermitPayment(sourceAccept, requirements, url) : await buildEvmPayment(sourceAccept, requirements, url);
|
|
1469
|
+
} else {
|
|
1470
|
+
throw new Error(`[relai-x402] No wallet for source chain type: ${source.type}`);
|
|
1471
|
+
}
|
|
1472
|
+
const settleData = await settleBridge(info.settleEndpoint, {
|
|
1473
|
+
sourcePayment: sourcePaymentHeader,
|
|
1474
|
+
sourceChain: source.chain,
|
|
1475
|
+
targetAccept: {
|
|
1476
|
+
scheme: "exact",
|
|
1477
|
+
network: targetAccept.network,
|
|
1478
|
+
asset: targetAccept.asset,
|
|
1479
|
+
payTo: targetAccept.payTo,
|
|
1480
|
+
amount: targetAmount
|
|
1481
|
+
},
|
|
1482
|
+
requirements,
|
|
1483
|
+
resource: url,
|
|
1484
|
+
paymentFacilitator: info.paymentFacilitator
|
|
1485
|
+
});
|
|
1486
|
+
if (settleData.xPayment) {
|
|
1487
|
+
log(`Auto-bridge settled: target=${settleData.targetTxId}`);
|
|
1488
|
+
return fetch(input, {
|
|
1489
|
+
...requestInitWithHeaders,
|
|
1490
|
+
headers: { ...requestHeaders, "X-PAYMENT": settleData.xPayment }
|
|
1491
|
+
});
|
|
1492
|
+
}
|
|
1493
|
+
throw new Error("[relai-x402] Bridge settle did not return xPayment");
|
|
1494
|
+
}
|
|
1495
|
+
}
|
|
1496
|
+
} catch (bridgeErr) {
|
|
1497
|
+
log(`Auto-bridge failed: ${bridgeErr instanceof Error ? bridgeErr.message : bridgeErr}`);
|
|
1498
|
+
}
|
|
1499
|
+
}
|
|
1370
1500
|
throw new Error(buildNoWalletError(accepts, false));
|
|
1371
1501
|
}
|
|
1372
1502
|
const { accept, chain } = selected;
|