@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/index.cjs
CHANGED
|
@@ -7021,6 +7021,7 @@ __export(index_exports, {
|
|
|
7021
7021
|
CHAIN_IDS: () => CHAIN_IDS,
|
|
7022
7022
|
EXPLORER_TX_URL: () => EXPLORER_TX_URL,
|
|
7023
7023
|
NETWORK_CAIP2: () => NETWORK_CAIP2,
|
|
7024
|
+
NETWORK_CONFIGS: () => NETWORK_CONFIGS,
|
|
7024
7025
|
NETWORK_LABELS: () => NETWORK_LABELS,
|
|
7025
7026
|
NETWORK_TOKENS: () => NETWORK_TOKENS,
|
|
7026
7027
|
NETWORK_V1_TO_V2: () => NETWORK_V1_TO_V2,
|
|
@@ -7032,9 +7033,12 @@ __export(index_exports, {
|
|
|
7032
7033
|
USDC_ADDRESSES: () => USDC_ADDRESSES,
|
|
7033
7034
|
USDC_BASE: () => USDC_BASE,
|
|
7034
7035
|
USDC_SOLANA: () => USDC_SOLANA,
|
|
7036
|
+
cancelPaymentCode: () => cancelPaymentCode,
|
|
7035
7037
|
convertPayloadToVersion: () => convertPayloadToVersion,
|
|
7036
7038
|
convertV1ToV2: () => convertV1ToV2,
|
|
7037
7039
|
convertV2ToV1: () => convertV2ToV1,
|
|
7040
|
+
createPayRequest: () => createPayRequest,
|
|
7041
|
+
createPrivateKeySigner: () => createPrivateKeySigner,
|
|
7038
7042
|
createX402Client: () => createX402Client,
|
|
7039
7043
|
default: () => Relai,
|
|
7040
7044
|
detectPayloadVersion: () => detectPayloadVersion,
|
|
@@ -7044,6 +7048,8 @@ __export(index_exports, {
|
|
|
7044
7048
|
formatUsd: () => formatUsd,
|
|
7045
7049
|
fromAtomicUnits: () => fromAtomicUnits,
|
|
7046
7050
|
generatePaymentCode: () => generatePaymentCode,
|
|
7051
|
+
generatePaymentCodesBatch: () => generatePaymentCodesBatch,
|
|
7052
|
+
getPayRequest: () => getPayRequest,
|
|
7047
7053
|
getPaymentCode: () => getPaymentCode,
|
|
7048
7054
|
isEvm: () => isEvm,
|
|
7049
7055
|
isEvmNetwork: () => isEvmNetwork,
|
|
@@ -7053,6 +7059,8 @@ __export(index_exports, {
|
|
|
7053
7059
|
networkV2ToV1: () => networkV2ToV1,
|
|
7054
7060
|
normalizeNetwork: () => normalizeNetwork,
|
|
7055
7061
|
normalizePaymentHeader: () => normalizePaymentHeader,
|
|
7062
|
+
payPayRequest: () => payPayRequest,
|
|
7063
|
+
payPayRequestWithCode: () => payPayRequestWithCode,
|
|
7056
7064
|
redeemPaymentCode: () => redeemPaymentCode,
|
|
7057
7065
|
resolveToken: () => resolveToken,
|
|
7058
7066
|
stripePayTo: () => stripePayTo,
|
|
@@ -7624,7 +7632,6 @@ var Relai = class {
|
|
|
7624
7632
|
const integritasMode = integritasFlow === "single" ? "single_signature_fee_included" : integritasFlow === "dual" ? "dual_signature_split" : void 0;
|
|
7625
7633
|
const paymentHeader = req.headers["x-payment"] || req.headers["payment-signature"] || req.headers["x-payment-signature"];
|
|
7626
7634
|
const authHeader = req.headers["authorization"] || "";
|
|
7627
|
-
console.log(`[Relai] MPP check: paymentHeader=${!!paymentHeader}, hasMpp=${!!self.mpp}, authHeader=${authHeader?.slice(0, 30)}`);
|
|
7628
7635
|
if (!paymentHeader && self.mpp && /^Payment\s+/i.test(authHeader)) {
|
|
7629
7636
|
try {
|
|
7630
7637
|
const mppAmount = resolvedPrice.toFixed(6);
|
|
@@ -7636,10 +7643,7 @@ var Relai = class {
|
|
|
7636
7643
|
const mppRequest = new Request(mppUrl, { method: req.method, headers: mppHeaders });
|
|
7637
7644
|
const chargeHandler = self.mpp.charge({ amount: mppAmount });
|
|
7638
7645
|
const mppResult = await chargeHandler(mppRequest);
|
|
7639
|
-
console.log(`[Relai] MPP charge result: status=${mppResult.status}, keys=${Object.keys(mppResult)}, hasChallenge=${!!mppResult.challenge}, hasWithReceipt=${!!mppResult.withReceipt}`);
|
|
7640
7646
|
if (mppResult.status === 402 && mppResult.challenge instanceof Response) {
|
|
7641
|
-
const retryAuth = mppResult.challenge.headers.get("www-authenticate");
|
|
7642
|
-
console.log(`[Relai] MPP re-challenged (credential not accepted). New WWW-Auth: ${retryAuth?.slice(0, 60)}`);
|
|
7643
7647
|
}
|
|
7644
7648
|
if (mppResult.status !== 200 && !mppResult.withReceipt && mppResult.status !== 402) {
|
|
7645
7649
|
if (self.plugins.length > 0) {
|
|
@@ -7682,7 +7686,10 @@ var Relai = class {
|
|
|
7682
7686
|
const dummyResponse = new Response(null);
|
|
7683
7687
|
const receiptResponse = mppResult.withReceipt(dummyResponse);
|
|
7684
7688
|
const receiptHeader = receiptResponse.headers.get("payment-receipt");
|
|
7685
|
-
if (receiptHeader)
|
|
7689
|
+
if (receiptHeader) {
|
|
7690
|
+
res.setHeader?.("Payment-Receipt", receiptHeader);
|
|
7691
|
+
res.setHeader?.("Cache-Control", "private");
|
|
7692
|
+
}
|
|
7686
7693
|
}
|
|
7687
7694
|
options.onPaymentSettled?.(req, {
|
|
7688
7695
|
success: true,
|
|
@@ -7899,12 +7906,13 @@ var Relai = class {
|
|
|
7899
7906
|
if (mppResult?.challenge instanceof Response) {
|
|
7900
7907
|
const wwwAuth = mppResult.challenge.headers.get("www-authenticate");
|
|
7901
7908
|
if (wwwAuth) {
|
|
7902
|
-
res.setHeader("WWW-Authenticate", wwwAuth);
|
|
7909
|
+
res.setHeader?.("WWW-Authenticate", wwwAuth);
|
|
7903
7910
|
}
|
|
7904
7911
|
}
|
|
7905
7912
|
} catch {
|
|
7906
7913
|
}
|
|
7907
7914
|
}
|
|
7915
|
+
res.setHeader?.("Cache-Control", "no-store");
|
|
7908
7916
|
return res.status(402).json(paymentRequiredResponse);
|
|
7909
7917
|
}
|
|
7910
7918
|
let paymentProof;
|
|
@@ -7921,39 +7929,6 @@ var Relai = class {
|
|
|
7921
7929
|
});
|
|
7922
7930
|
}
|
|
7923
7931
|
}
|
|
7924
|
-
if (paymentProof.bridged === true && paymentProof.targetTxId) {
|
|
7925
|
-
console.log(`[Relai] Bridged payment accepted: source=${paymentProof.sourceTxId}, target=${paymentProof.targetTxId}`);
|
|
7926
|
-
const paymentInfo2 = {
|
|
7927
|
-
verified: true,
|
|
7928
|
-
transactionId: paymentProof.targetTxId,
|
|
7929
|
-
payer: paymentProof.sourceTxId || "bridge",
|
|
7930
|
-
network,
|
|
7931
|
-
amount: resolvedPrice
|
|
7932
|
-
};
|
|
7933
|
-
req.payment = paymentInfo2;
|
|
7934
|
-
req.x402Payer = paymentProof.sourceTxId || "bridge";
|
|
7935
|
-
req.x402Paid = true;
|
|
7936
|
-
req.x402Transaction = paymentProof.targetTxId;
|
|
7937
|
-
req.x402Network = network;
|
|
7938
|
-
req.x402Bridged = true;
|
|
7939
|
-
req.x402SourceChain = paymentProof.sourceChain;
|
|
7940
|
-
const paymentResponse2 = {
|
|
7941
|
-
x402Version: 2,
|
|
7942
|
-
scheme: "exact",
|
|
7943
|
-
network: caip2,
|
|
7944
|
-
transaction: paymentProof.targetTxId,
|
|
7945
|
-
payer: paymentProof.sourceTxId,
|
|
7946
|
-
amount: amount2,
|
|
7947
|
-
asset,
|
|
7948
|
-
bridged: true
|
|
7949
|
-
};
|
|
7950
|
-
res.setHeader(
|
|
7951
|
-
"PAYMENT-RESPONSE",
|
|
7952
|
-
Buffer.from(JSON.stringify(paymentResponse2)).toString("base64")
|
|
7953
|
-
);
|
|
7954
|
-
options.onPaymentSettled?.(req, { success: true, transaction: paymentProof.targetTxId, payer: paymentProof.sourceTxId });
|
|
7955
|
-
return next();
|
|
7956
|
-
}
|
|
7957
7932
|
let settlePayTo;
|
|
7958
7933
|
if (stripeConfig) {
|
|
7959
7934
|
settlePayTo = paymentProof.payload?.authorization?.to || paymentProof.accepted?.payTo || "";
|
|
@@ -8100,6 +8075,73 @@ var server_default = Relai;
|
|
|
8100
8075
|
// src/client.ts
|
|
8101
8076
|
var import_web3 = require("@solana/web3.js");
|
|
8102
8077
|
var import_spl_token = require("@solana/spl-token");
|
|
8078
|
+
|
|
8079
|
+
// src/bridge.ts
|
|
8080
|
+
var RELAI_API_BASE = "https://api.relai.fi";
|
|
8081
|
+
var _cacheMap = /* @__PURE__ */ new Map();
|
|
8082
|
+
var CACHE_TTL = 5 * 60 * 1e3;
|
|
8083
|
+
async function getBridgeInfo(baseUrl = RELAI_API_BASE) {
|
|
8084
|
+
const key = baseUrl.replace(/\/$/, "");
|
|
8085
|
+
const now = Date.now();
|
|
8086
|
+
const cached2 = _cacheMap.get(key);
|
|
8087
|
+
if (cached2 && now - cached2.time < CACHE_TTL) return cached2.info;
|
|
8088
|
+
const url2 = `${key}/bridge/info`;
|
|
8089
|
+
const res = await fetch(url2);
|
|
8090
|
+
if (!res.ok) {
|
|
8091
|
+
if (cached2) return cached2.info;
|
|
8092
|
+
throw new Error(`[relai:bridge] Failed to fetch ${url2}: ${res.status}`);
|
|
8093
|
+
}
|
|
8094
|
+
const data = await res.json();
|
|
8095
|
+
const info = {
|
|
8096
|
+
settleEndpoint: data.settleEndpoint,
|
|
8097
|
+
supportedSourceChains: data.supportedSourceChains || [],
|
|
8098
|
+
supportedSourceAssets: data.supportedSourceAssets || [],
|
|
8099
|
+
payTo: data.payTo || {},
|
|
8100
|
+
feePayerSvm: data.feePayerSvm ?? null,
|
|
8101
|
+
feeBps: data.feeBps ?? 100,
|
|
8102
|
+
paymentFacilitator: data.paymentFacilitator || "https://facilitator.x402.fi"
|
|
8103
|
+
};
|
|
8104
|
+
_cacheMap.set(key, { info, time: now });
|
|
8105
|
+
return info;
|
|
8106
|
+
}
|
|
8107
|
+
async function settleBridge(settleEndpoint, body) {
|
|
8108
|
+
const res = await fetch(settleEndpoint, {
|
|
8109
|
+
method: "POST",
|
|
8110
|
+
headers: { "Content-Type": "application/json" },
|
|
8111
|
+
body: JSON.stringify(body)
|
|
8112
|
+
});
|
|
8113
|
+
if (!res.ok) {
|
|
8114
|
+
const err = await res.json().catch(() => ({}));
|
|
8115
|
+
throw new Error(`[relai:bridge] settle failed: ${err.error || res.status}${err.details ? " \u2014 " + err.details : ""}`);
|
|
8116
|
+
}
|
|
8117
|
+
return res.json();
|
|
8118
|
+
}
|
|
8119
|
+
function selectSourceChain(supportedChains, hasEvmWallet, hasSolanaWallet, preferredSourceChainId) {
|
|
8120
|
+
if (preferredSourceChainId && hasEvmWallet) {
|
|
8121
|
+
const preferred = `eip155:${preferredSourceChainId}`;
|
|
8122
|
+
if (supportedChains.includes(preferred)) {
|
|
8123
|
+
return { type: "evm", chain: preferred };
|
|
8124
|
+
}
|
|
8125
|
+
}
|
|
8126
|
+
if (hasSolanaWallet) {
|
|
8127
|
+
const sol = supportedChains.find((c) => c.startsWith("solana:"));
|
|
8128
|
+
if (sol) return { type: "solana", chain: sol };
|
|
8129
|
+
}
|
|
8130
|
+
if (hasEvmWallet) {
|
|
8131
|
+
for (const chain of supportedChains) {
|
|
8132
|
+
if (chain.startsWith("eip155:")) {
|
|
8133
|
+
return { type: "evm", chain };
|
|
8134
|
+
}
|
|
8135
|
+
}
|
|
8136
|
+
}
|
|
8137
|
+
return null;
|
|
8138
|
+
}
|
|
8139
|
+
function computeSourceAmount(targetAmount, feeBps) {
|
|
8140
|
+
const fee = targetAmount * BigInt(feeBps) / 10000n;
|
|
8141
|
+
return targetAmount + fee;
|
|
8142
|
+
}
|
|
8143
|
+
|
|
8144
|
+
// src/client.ts
|
|
8103
8145
|
var PERMIT_NETWORKS = /* @__PURE__ */ new Set([]);
|
|
8104
8146
|
var DEFAULT_EVM_RPC_URLS = {
|
|
8105
8147
|
"skale-base": "https://skale-base.skalenodes.com/v1/base",
|
|
@@ -8125,7 +8167,8 @@ function createX402Client(config2) {
|
|
|
8125
8167
|
integritas,
|
|
8126
8168
|
verbose = false,
|
|
8127
8169
|
defaultHeaders = {},
|
|
8128
|
-
mpp
|
|
8170
|
+
mpp,
|
|
8171
|
+
bridge: bridgeConfig
|
|
8129
8172
|
} = config2;
|
|
8130
8173
|
const relayWsEnabled = relayWs?.enabled === true;
|
|
8131
8174
|
const relayWsPreflightTimeoutMs = relayWs?.preflightTimeoutMs ?? 5e3;
|
|
@@ -9240,6 +9283,70 @@ function createX402Client(config2) {
|
|
|
9240
9283
|
headers: { ...requestHeaders, "X-PAYMENT": paymentHeader }
|
|
9241
9284
|
});
|
|
9242
9285
|
}
|
|
9286
|
+
if (bridgeConfig?.enabled) {
|
|
9287
|
+
log("No direct wallet match \u2014 attempting auto-bridge via RelAI API");
|
|
9288
|
+
try {
|
|
9289
|
+
const info = await getBridgeInfo(bridgeConfig.baseUrl);
|
|
9290
|
+
const targetAccept = accepts[0];
|
|
9291
|
+
const hasEvm = !!effectiveWallets.evm;
|
|
9292
|
+
const hasSol = !!hasSolanaWallet;
|
|
9293
|
+
const source = selectSourceChain(info.supportedSourceChains, hasEvm, hasSol);
|
|
9294
|
+
if (source) {
|
|
9295
|
+
const bridgePayTo = info.payTo[source.chain];
|
|
9296
|
+
if (bridgePayTo) {
|
|
9297
|
+
const targetAmount = targetAccept.amount || targetAccept.maxAmountRequired;
|
|
9298
|
+
const sourceAmount = computeSourceAmount(BigInt(targetAmount), info.feeBps).toString();
|
|
9299
|
+
const sourceChainIdx = info.supportedSourceChains.indexOf(source.chain);
|
|
9300
|
+
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")) || "");
|
|
9301
|
+
let sourcePaymentHeader;
|
|
9302
|
+
const sourceAccept = {
|
|
9303
|
+
scheme: "exact",
|
|
9304
|
+
network: source.chain,
|
|
9305
|
+
asset: sourceAsset,
|
|
9306
|
+
payTo: bridgePayTo,
|
|
9307
|
+
amount: sourceAmount,
|
|
9308
|
+
extra: {
|
|
9309
|
+
...targetAccept.extra || {},
|
|
9310
|
+
...source.type === "solana" && info.feePayerSvm ? { feePayer: info.feePayerSvm } : {}
|
|
9311
|
+
}
|
|
9312
|
+
};
|
|
9313
|
+
if (source.type === "solana" && hasSolanaWallet) {
|
|
9314
|
+
sourcePaymentHeader = await buildSolanaPayment(sourceAccept, requirements, url2);
|
|
9315
|
+
} else if (source.type === "evm") {
|
|
9316
|
+
const evmNetwork = normalizeNetwork(source.chain);
|
|
9317
|
+
const usePermit = evmNetwork && PERMIT_NETWORKS.has(evmNetwork);
|
|
9318
|
+
sourcePaymentHeader = usePermit ? await buildEvmPermitPayment(sourceAccept, requirements, url2) : await buildEvmPayment(sourceAccept, requirements, url2);
|
|
9319
|
+
} else {
|
|
9320
|
+
throw new Error(`[relai-x402] No wallet for source chain type: ${source.type}`);
|
|
9321
|
+
}
|
|
9322
|
+
const settleData = await settleBridge(info.settleEndpoint, {
|
|
9323
|
+
sourcePayment: sourcePaymentHeader,
|
|
9324
|
+
sourceChain: source.chain,
|
|
9325
|
+
targetAccept: {
|
|
9326
|
+
scheme: "exact",
|
|
9327
|
+
network: targetAccept.network,
|
|
9328
|
+
asset: targetAccept.asset,
|
|
9329
|
+
payTo: targetAccept.payTo,
|
|
9330
|
+
amount: targetAmount
|
|
9331
|
+
},
|
|
9332
|
+
requirements,
|
|
9333
|
+
resource: url2,
|
|
9334
|
+
paymentFacilitator: info.paymentFacilitator
|
|
9335
|
+
});
|
|
9336
|
+
if (settleData.xPayment) {
|
|
9337
|
+
log(`Auto-bridge settled: target=${settleData.targetTxId}`);
|
|
9338
|
+
return fetch(input, {
|
|
9339
|
+
...requestInitWithHeaders,
|
|
9340
|
+
headers: { ...requestHeaders, "X-PAYMENT": settleData.xPayment }
|
|
9341
|
+
});
|
|
9342
|
+
}
|
|
9343
|
+
throw new Error("[relai-x402] Bridge settle did not return xPayment");
|
|
9344
|
+
}
|
|
9345
|
+
}
|
|
9346
|
+
} catch (bridgeErr) {
|
|
9347
|
+
log(`Auto-bridge failed: ${bridgeErr instanceof Error ? bridgeErr.message : bridgeErr}`);
|
|
9348
|
+
}
|
|
9349
|
+
}
|
|
9243
9350
|
throw new Error(buildNoWalletError(accepts, false));
|
|
9244
9351
|
}
|
|
9245
9352
|
const { accept, chain } = selected;
|
|
@@ -9336,8 +9443,37 @@ function submitRelayFeedback(config2) {
|
|
|
9336
9443
|
}
|
|
9337
9444
|
|
|
9338
9445
|
// src/payment-codes.ts
|
|
9339
|
-
var
|
|
9340
|
-
var
|
|
9446
|
+
var import_ethers2 = require("ethers");
|
|
9447
|
+
var NETWORK_CONFIGS = {
|
|
9448
|
+
"base": {
|
|
9449
|
+
chainId: 8453,
|
|
9450
|
+
usdc: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
|
|
9451
|
+
domainName: "USD Coin",
|
|
9452
|
+
rpc: "https://mainnet.base.org",
|
|
9453
|
+
settlementNetwork: "base"
|
|
9454
|
+
},
|
|
9455
|
+
"base-sepolia": {
|
|
9456
|
+
chainId: 84532,
|
|
9457
|
+
usdc: "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
|
|
9458
|
+
domainName: "USDC",
|
|
9459
|
+
rpc: "https://sepolia.base.org",
|
|
9460
|
+
settlementNetwork: "base-sepolia"
|
|
9461
|
+
},
|
|
9462
|
+
"skale-base-sepolia": {
|
|
9463
|
+
chainId: 324705682,
|
|
9464
|
+
usdc: "0x2e08028E3C4c2356572E096d8EF835cD5C6030bD",
|
|
9465
|
+
domainName: "Bridged USDC (SKALE Bridge)",
|
|
9466
|
+
rpc: "https://base-sepolia-testnet.skalenodes.com/v1/jubilant-horrible-ancha",
|
|
9467
|
+
settlementNetwork: "skale-base-sepolia"
|
|
9468
|
+
},
|
|
9469
|
+
"skale-base": {
|
|
9470
|
+
chainId: 1482601649,
|
|
9471
|
+
usdc: "0x85889c8c714505E0c94b30fcfcF64fE3Ac8FCb20",
|
|
9472
|
+
domainName: "Bridged USDC",
|
|
9473
|
+
rpc: "https://skale-base.skalenodes.com/v1/base",
|
|
9474
|
+
settlementNetwork: "skale-base"
|
|
9475
|
+
}
|
|
9476
|
+
};
|
|
9341
9477
|
var EIP3009_TYPES = {
|
|
9342
9478
|
TransferWithAuthorization: [
|
|
9343
9479
|
{ name: "from", type: "address" },
|
|
@@ -9348,6 +9484,14 @@ var EIP3009_TYPES = {
|
|
|
9348
9484
|
{ name: "nonce", type: "bytes32" }
|
|
9349
9485
|
]
|
|
9350
9486
|
};
|
|
9487
|
+
function createPrivateKeySigner(privateKey) {
|
|
9488
|
+
const wallet = new import_ethers2.ethers.Wallet(privateKey);
|
|
9489
|
+
return {
|
|
9490
|
+
getAddress: () => Promise.resolve(wallet.address),
|
|
9491
|
+
signTypedData: (domain2, types, value) => wallet.signTypedData(domain2, types, value)
|
|
9492
|
+
};
|
|
9493
|
+
}
|
|
9494
|
+
var DEFAULT_FACILITATOR = "https://relai.fi/facilitator";
|
|
9351
9495
|
function randomBytes32() {
|
|
9352
9496
|
const bytes = new Uint8Array(32);
|
|
9353
9497
|
if (typeof globalThis.crypto !== "undefined") {
|
|
@@ -9358,69 +9502,323 @@ function randomBytes32() {
|
|
|
9358
9502
|
}
|
|
9359
9503
|
return "0x" + Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
9360
9504
|
}
|
|
9361
|
-
async function
|
|
9362
|
-
const
|
|
9363
|
-
|
|
9364
|
-
const
|
|
9365
|
-
|
|
9366
|
-
|
|
9367
|
-
|
|
9368
|
-
|
|
9369
|
-
const nonce = randomBytes32();
|
|
9505
|
+
async function fetchToAddress(facilitatorUrl, network) {
|
|
9506
|
+
const res = await fetch(`${facilitatorUrl}/payment-codes/relayer?network=${network}`);
|
|
9507
|
+
if (!res.ok) throw new Error("Failed to fetch relayer address from facilitator");
|
|
9508
|
+
const data = await res.json();
|
|
9509
|
+
if (!data.toAddress) throw new Error("Facilitator returned no toAddress");
|
|
9510
|
+
return data.toAddress;
|
|
9511
|
+
}
|
|
9512
|
+
async function signEip3009(signer, net, from4, toAddress, value, validAfter, validBefore, nonce, usdcOverride) {
|
|
9370
9513
|
const domain2 = {
|
|
9371
|
-
name:
|
|
9514
|
+
name: net.domainName,
|
|
9372
9515
|
version: "2",
|
|
9373
|
-
chainId:
|
|
9374
|
-
|
|
9375
|
-
verifyingContract: usdc
|
|
9516
|
+
chainId: net.chainId,
|
|
9517
|
+
verifyingContract: usdcOverride ?? net.usdc
|
|
9376
9518
|
};
|
|
9377
|
-
|
|
9519
|
+
return signer.signTypedData(domain2, EIP3009_TYPES, {
|
|
9378
9520
|
from: from4,
|
|
9379
|
-
to,
|
|
9380
|
-
value
|
|
9521
|
+
to: toAddress,
|
|
9522
|
+
value,
|
|
9381
9523
|
validAfter,
|
|
9382
9524
|
validBefore,
|
|
9383
9525
|
nonce
|
|
9384
|
-
};
|
|
9385
|
-
|
|
9526
|
+
});
|
|
9527
|
+
}
|
|
9528
|
+
async function generatePaymentCode(config2, params) {
|
|
9529
|
+
const {
|
|
9530
|
+
signer,
|
|
9531
|
+
value,
|
|
9532
|
+
ttl = 86400,
|
|
9533
|
+
description,
|
|
9534
|
+
payee,
|
|
9535
|
+
usdcContract,
|
|
9536
|
+
network = "base-sepolia"
|
|
9537
|
+
} = params;
|
|
9538
|
+
const facilitatorUrl = config2.facilitatorUrl ?? DEFAULT_FACILITATOR;
|
|
9539
|
+
const net = NETWORK_CONFIGS[network];
|
|
9540
|
+
if (!net) throw new Error(`Unsupported network: ${network}`);
|
|
9541
|
+
const from4 = await signer.getAddress();
|
|
9542
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
9543
|
+
const validBefore = now + ttl;
|
|
9544
|
+
const nonce = randomBytes32();
|
|
9545
|
+
const usdc = usdcContract ?? net.usdc;
|
|
9546
|
+
const toAddress = await fetchToAddress(facilitatorUrl, network);
|
|
9547
|
+
const signature2 = await signEip3009(
|
|
9548
|
+
signer,
|
|
9549
|
+
net,
|
|
9550
|
+
from4,
|
|
9551
|
+
toAddress,
|
|
9552
|
+
BigInt(value).toString(),
|
|
9553
|
+
0,
|
|
9554
|
+
validBefore,
|
|
9555
|
+
nonce,
|
|
9556
|
+
usdc
|
|
9557
|
+
);
|
|
9386
9558
|
const res = await fetch(`${facilitatorUrl}/payment-codes`, {
|
|
9387
9559
|
method: "POST",
|
|
9388
9560
|
headers: { "Content-Type": "application/json" },
|
|
9389
9561
|
body: JSON.stringify({
|
|
9390
9562
|
from: from4,
|
|
9391
|
-
to,
|
|
9392
9563
|
value: BigInt(value).toString(),
|
|
9393
|
-
validAfter,
|
|
9564
|
+
validAfter: 0,
|
|
9394
9565
|
validBefore,
|
|
9395
9566
|
nonce,
|
|
9396
9567
|
signature: signature2,
|
|
9397
|
-
usdcContract: usdc
|
|
9568
|
+
usdcContract: usdc,
|
|
9569
|
+
settlementNetwork: net.settlementNetwork,
|
|
9570
|
+
...description ? { description } : {},
|
|
9571
|
+
...payee ? { payee } : {}
|
|
9398
9572
|
})
|
|
9399
9573
|
});
|
|
9400
9574
|
if (!res.ok) {
|
|
9401
9575
|
const err = await res.json().catch(() => ({}));
|
|
9402
|
-
throw new Error(`Failed to register payment code: ${err.error
|
|
9576
|
+
throw new Error(`Failed to register payment code: ${err.error ?? res.status}`);
|
|
9403
9577
|
}
|
|
9404
9578
|
return res.json();
|
|
9405
9579
|
}
|
|
9406
|
-
async function
|
|
9407
|
-
const
|
|
9408
|
-
|
|
9580
|
+
async function generatePaymentCodesBatch(config2, params) {
|
|
9581
|
+
const {
|
|
9582
|
+
signer,
|
|
9583
|
+
codes,
|
|
9584
|
+
payee,
|
|
9585
|
+
usdcContract,
|
|
9586
|
+
network = "base-sepolia",
|
|
9587
|
+
authToken
|
|
9588
|
+
} = params;
|
|
9589
|
+
const facilitatorUrl = config2.facilitatorUrl ?? DEFAULT_FACILITATOR;
|
|
9590
|
+
const net = NETWORK_CONFIGS[network];
|
|
9591
|
+
if (!net) throw new Error(`Unsupported network: ${network}`);
|
|
9592
|
+
if (codes.length > 20) throw new Error("Maximum 20 codes per batch");
|
|
9593
|
+
const from4 = await signer.getAddress();
|
|
9594
|
+
const usdc = usdcContract ?? net.usdc;
|
|
9595
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
9596
|
+
const toAddress = await fetchToAddress(facilitatorUrl, network);
|
|
9597
|
+
const signedCodes = await Promise.all(
|
|
9598
|
+
codes.map(async (item) => {
|
|
9599
|
+
const validBefore = now + (item.ttl ?? 86400);
|
|
9600
|
+
const nonce = randomBytes32();
|
|
9601
|
+
const value = BigInt(item.value).toString();
|
|
9602
|
+
const signature2 = await signEip3009(
|
|
9603
|
+
signer,
|
|
9604
|
+
net,
|
|
9605
|
+
from4,
|
|
9606
|
+
toAddress,
|
|
9607
|
+
value,
|
|
9608
|
+
0,
|
|
9609
|
+
validBefore,
|
|
9610
|
+
nonce,
|
|
9611
|
+
usdc
|
|
9612
|
+
);
|
|
9613
|
+
return { value, validAfter: 0, validBefore, nonce, signature: signature2 };
|
|
9614
|
+
})
|
|
9615
|
+
);
|
|
9616
|
+
const res = await fetch(`${facilitatorUrl}/payment-codes/batch`, {
|
|
9409
9617
|
method: "POST",
|
|
9410
|
-
headers: {
|
|
9618
|
+
headers: {
|
|
9619
|
+
"Content-Type": "application/json",
|
|
9620
|
+
"Authorization": `Bearer ${authToken}`
|
|
9621
|
+
},
|
|
9622
|
+
body: JSON.stringify({
|
|
9623
|
+
from: from4,
|
|
9624
|
+
settlementNetwork: net.settlementNetwork,
|
|
9625
|
+
usdcContract: usdc,
|
|
9626
|
+
...payee ? { payee } : {},
|
|
9627
|
+
codes: signedCodes
|
|
9628
|
+
})
|
|
9411
9629
|
});
|
|
9412
9630
|
if (!res.ok) {
|
|
9413
9631
|
const err = await res.json().catch(() => ({}));
|
|
9414
|
-
throw new Error(`
|
|
9632
|
+
throw new Error(`Batch registration failed: ${err.error ?? res.status}`);
|
|
9633
|
+
}
|
|
9634
|
+
return res.json();
|
|
9635
|
+
}
|
|
9636
|
+
async function redeemPaymentCode(config2, code, payee) {
|
|
9637
|
+
const facilitatorUrl = config2.facilitatorUrl ?? DEFAULT_FACILITATOR;
|
|
9638
|
+
const res = await fetch(
|
|
9639
|
+
`${facilitatorUrl}/payment-codes/${code.trim().toUpperCase()}/redeem`,
|
|
9640
|
+
{
|
|
9641
|
+
method: "POST",
|
|
9642
|
+
headers: { "Content-Type": "application/json" },
|
|
9643
|
+
body: JSON.stringify(payee ? { payee } : {})
|
|
9644
|
+
}
|
|
9645
|
+
);
|
|
9646
|
+
if (!res.ok) {
|
|
9647
|
+
const err = await res.json().catch(() => ({}));
|
|
9648
|
+
throw new Error(err.error ?? `Redeem failed: ${res.status}`);
|
|
9415
9649
|
}
|
|
9416
9650
|
return res.json();
|
|
9417
9651
|
}
|
|
9418
9652
|
async function getPaymentCode(config2, code) {
|
|
9419
|
-
const facilitatorUrl = config2.facilitatorUrl
|
|
9420
|
-
const res = await fetch(
|
|
9653
|
+
const facilitatorUrl = config2.facilitatorUrl ?? DEFAULT_FACILITATOR;
|
|
9654
|
+
const res = await fetch(
|
|
9655
|
+
`${facilitatorUrl}/payment-codes/${code.trim().toUpperCase()}`
|
|
9656
|
+
);
|
|
9657
|
+
if (!res.ok) {
|
|
9658
|
+
const err = await res.json().catch(() => ({}));
|
|
9659
|
+
throw new Error(`Payment code not found: ${err.error ?? res.status}`);
|
|
9660
|
+
}
|
|
9661
|
+
return res.json();
|
|
9662
|
+
}
|
|
9663
|
+
async function cancelPaymentCode(config2, code) {
|
|
9664
|
+
const facilitatorUrl = config2.facilitatorUrl ?? DEFAULT_FACILITATOR;
|
|
9665
|
+
const res = await fetch(
|
|
9666
|
+
`${facilitatorUrl}/payment-codes/${code.trim().toUpperCase()}`,
|
|
9667
|
+
{ method: "DELETE" }
|
|
9668
|
+
);
|
|
9421
9669
|
if (!res.ok) {
|
|
9422
9670
|
const err = await res.json().catch(() => ({}));
|
|
9423
|
-
throw new Error(`
|
|
9671
|
+
throw new Error(`Cancel failed: ${err.error ?? res.status}`);
|
|
9672
|
+
}
|
|
9673
|
+
return res.json();
|
|
9674
|
+
}
|
|
9675
|
+
|
|
9676
|
+
// src/payment-requests.ts
|
|
9677
|
+
var DEFAULT_FACILITATOR2 = "https://relai.fi/facilitator";
|
|
9678
|
+
var EIP3009_TYPES2 = {
|
|
9679
|
+
TransferWithAuthorization: [
|
|
9680
|
+
{ name: "from", type: "address" },
|
|
9681
|
+
{ name: "to", type: "address" },
|
|
9682
|
+
{ name: "value", type: "uint256" },
|
|
9683
|
+
{ name: "validAfter", type: "uint256" },
|
|
9684
|
+
{ name: "validBefore", type: "uint256" },
|
|
9685
|
+
{ name: "nonce", type: "bytes32" }
|
|
9686
|
+
]
|
|
9687
|
+
};
|
|
9688
|
+
function randomBytes322() {
|
|
9689
|
+
const bytes = new Uint8Array(32);
|
|
9690
|
+
if (typeof globalThis.crypto !== "undefined") {
|
|
9691
|
+
globalThis.crypto.getRandomValues(bytes);
|
|
9692
|
+
} else {
|
|
9693
|
+
const { randomBytes: randomBytes2 } = require("crypto");
|
|
9694
|
+
randomBytes2(32).copy(Buffer.from(bytes.buffer));
|
|
9695
|
+
}
|
|
9696
|
+
return "0x" + Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
9697
|
+
}
|
|
9698
|
+
async function createPayRequest(config2, params) {
|
|
9699
|
+
const {
|
|
9700
|
+
to,
|
|
9701
|
+
amount: amount2,
|
|
9702
|
+
network = "base-sepolia",
|
|
9703
|
+
description,
|
|
9704
|
+
ttlSeconds
|
|
9705
|
+
} = params;
|
|
9706
|
+
const facilitatorUrl = config2.facilitatorUrl ?? DEFAULT_FACILITATOR2;
|
|
9707
|
+
const res = await fetch(`${facilitatorUrl}/payment-requests`, {
|
|
9708
|
+
method: "POST",
|
|
9709
|
+
headers: { "Content-Type": "application/json" },
|
|
9710
|
+
body: JSON.stringify({
|
|
9711
|
+
to,
|
|
9712
|
+
amount: Number(amount2),
|
|
9713
|
+
network,
|
|
9714
|
+
...description ? { description } : {},
|
|
9715
|
+
...ttlSeconds ? { ttlSeconds } : {}
|
|
9716
|
+
})
|
|
9717
|
+
});
|
|
9718
|
+
if (!res.ok) {
|
|
9719
|
+
const err = await res.json().catch(() => ({}));
|
|
9720
|
+
throw new Error(`Failed to create payment request: ${err.error ?? res.status}`);
|
|
9721
|
+
}
|
|
9722
|
+
return res.json();
|
|
9723
|
+
}
|
|
9724
|
+
async function getPayRequest(config2, code) {
|
|
9725
|
+
const facilitatorUrl = config2.facilitatorUrl ?? DEFAULT_FACILITATOR2;
|
|
9726
|
+
const res = await fetch(
|
|
9727
|
+
`${facilitatorUrl}/payment-requests/${code.trim().toUpperCase()}`
|
|
9728
|
+
);
|
|
9729
|
+
if (!res.ok) {
|
|
9730
|
+
const err = await res.json().catch(() => ({}));
|
|
9731
|
+
throw new Error(`Payment request not found: ${err.error ?? res.status}`);
|
|
9732
|
+
}
|
|
9733
|
+
return res.json();
|
|
9734
|
+
}
|
|
9735
|
+
async function payPayRequest(config2, code, signer) {
|
|
9736
|
+
const facilitatorUrl = config2.facilitatorUrl ?? DEFAULT_FACILITATOR2;
|
|
9737
|
+
const info = await getPayRequest(config2, code);
|
|
9738
|
+
if (!info.payable) {
|
|
9739
|
+
throw new Error(
|
|
9740
|
+
info.status === "paid" ? "Payment request already paid" : "Payment request expired or not payable"
|
|
9741
|
+
);
|
|
9742
|
+
}
|
|
9743
|
+
const netKey = info.network;
|
|
9744
|
+
const net = NETWORK_CONFIGS[netKey];
|
|
9745
|
+
if (!net) throw new Error(`Unknown network from payment request: ${info.network}`);
|
|
9746
|
+
const from4 = await signer.getAddress();
|
|
9747
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
9748
|
+
const validBefore = Math.min(now + 300, info.validUntil);
|
|
9749
|
+
const nonce = randomBytes322();
|
|
9750
|
+
const domain2 = {
|
|
9751
|
+
name: net.domainName,
|
|
9752
|
+
version: "2",
|
|
9753
|
+
chainId: net.chainId,
|
|
9754
|
+
verifyingContract: info.usdcContract
|
|
9755
|
+
};
|
|
9756
|
+
const signature2 = await signer.signTypedData(domain2, EIP3009_TYPES2, {
|
|
9757
|
+
from: from4,
|
|
9758
|
+
to: info.toAddress,
|
|
9759
|
+
// settler/relayer — NOT the merchant directly
|
|
9760
|
+
value: String(info.amount),
|
|
9761
|
+
validAfter: 0,
|
|
9762
|
+
validBefore,
|
|
9763
|
+
nonce
|
|
9764
|
+
});
|
|
9765
|
+
const res = await fetch(
|
|
9766
|
+
`${facilitatorUrl}/payment-requests/${code.trim().toUpperCase()}/pay`,
|
|
9767
|
+
{
|
|
9768
|
+
method: "POST",
|
|
9769
|
+
headers: { "Content-Type": "application/json" },
|
|
9770
|
+
body: JSON.stringify({ from: from4, validAfter: 0, validBefore, nonce, signature: signature2 })
|
|
9771
|
+
}
|
|
9772
|
+
);
|
|
9773
|
+
if (!res.ok) {
|
|
9774
|
+
const err = await res.json().catch(() => ({}));
|
|
9775
|
+
throw new Error(err.error ?? `Payment failed: ${res.status}`);
|
|
9776
|
+
}
|
|
9777
|
+
return res.json();
|
|
9778
|
+
}
|
|
9779
|
+
async function payPayRequestWithCode(config2, requestCode, paymentCode, options = {}) {
|
|
9780
|
+
const { allowOverpayment = true, returnChange = "code" } = options;
|
|
9781
|
+
const info = await getPayRequest(config2, requestCode);
|
|
9782
|
+
if (!info.payable) {
|
|
9783
|
+
throw new Error(
|
|
9784
|
+
info.status === "paid" ? "Payment request already paid" : "Payment request expired or not payable"
|
|
9785
|
+
);
|
|
9786
|
+
}
|
|
9787
|
+
const codeStatus = await getPaymentCode(config2, paymentCode);
|
|
9788
|
+
if (!codeStatus.redeemable) {
|
|
9789
|
+
throw new Error(
|
|
9790
|
+
codeStatus.redeemed ? "Payment code already redeemed" : "Payment code expired or not redeemable"
|
|
9791
|
+
);
|
|
9792
|
+
}
|
|
9793
|
+
const codeValue = BigInt(codeStatus.value);
|
|
9794
|
+
const reqAmount = BigInt(info.amount);
|
|
9795
|
+
if (codeValue < reqAmount) {
|
|
9796
|
+
throw new Error(
|
|
9797
|
+
`Payment code value (${Number(codeValue) / 1e6} USDC) is less than the request amount (${Number(reqAmount) / 1e6} USDC)`
|
|
9798
|
+
);
|
|
9799
|
+
}
|
|
9800
|
+
if (!allowOverpayment && codeValue > reqAmount) {
|
|
9801
|
+
throw new Error(
|
|
9802
|
+
`Payment code value (${Number(codeValue) / 1e6} USDC) exceeds the request amount (${Number(reqAmount) / 1e6} USDC). Generate a code for the exact amount, or pass { allowOverpayment: true }.`
|
|
9803
|
+
);
|
|
9804
|
+
}
|
|
9805
|
+
const facilitatorUrl = config2.facilitatorUrl ?? "https://relai.fi/facilitator";
|
|
9806
|
+
const usePartial = codeValue > reqAmount;
|
|
9807
|
+
const res = await fetch(
|
|
9808
|
+
`${facilitatorUrl}/payment-codes/${paymentCode.trim().toUpperCase()}/redeem`,
|
|
9809
|
+
{
|
|
9810
|
+
method: "POST",
|
|
9811
|
+
headers: { "Content-Type": "application/json" },
|
|
9812
|
+
body: JSON.stringify({
|
|
9813
|
+
payee: info.to,
|
|
9814
|
+
...usePartial ? { invoiceAmount: info.amount.toString() } : {},
|
|
9815
|
+
...usePartial ? { returnChangeAsCode: returnChange === "code" } : {}
|
|
9816
|
+
})
|
|
9817
|
+
}
|
|
9818
|
+
);
|
|
9819
|
+
if (!res.ok) {
|
|
9820
|
+
const err = await res.json().catch(() => ({}));
|
|
9821
|
+
throw new Error(err.error ?? `Redeem failed: ${res.status}`);
|
|
9424
9822
|
}
|
|
9425
9823
|
return res.json();
|
|
9426
9824
|
}
|
|
@@ -22935,8 +23333,50 @@ var charge = Method_exports.from({
|
|
|
22935
23333
|
}
|
|
22936
23334
|
});
|
|
22937
23335
|
|
|
22938
|
-
// src/mpp/
|
|
23336
|
+
// src/mpp/verify-erc20.ts
|
|
22939
23337
|
var TRANSFER_EVENT_TOPIC = "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef";
|
|
23338
|
+
async function verifyErc20Transfer(opts) {
|
|
23339
|
+
const { txHash, rpcUrl, tokenAddress, recipient, expectedAmount } = opts;
|
|
23340
|
+
let receipt = null;
|
|
23341
|
+
for (let attempt = 0; attempt < 5; attempt++) {
|
|
23342
|
+
const receiptRes = await fetch(rpcUrl, {
|
|
23343
|
+
method: "POST",
|
|
23344
|
+
headers: { "Content-Type": "application/json" },
|
|
23345
|
+
body: JSON.stringify({
|
|
23346
|
+
jsonrpc: "2.0",
|
|
23347
|
+
id: 1,
|
|
23348
|
+
method: "eth_getTransactionReceipt",
|
|
23349
|
+
params: [txHash]
|
|
23350
|
+
})
|
|
23351
|
+
});
|
|
23352
|
+
const receiptData = await receiptRes.json();
|
|
23353
|
+
if (receiptData.error) {
|
|
23354
|
+
throw new Error(`RPC error: ${receiptData.error.message}`);
|
|
23355
|
+
}
|
|
23356
|
+
receipt = receiptData.result;
|
|
23357
|
+
if (receipt) break;
|
|
23358
|
+
await new Promise((r) => setTimeout(r, (attempt + 1) * 1e3));
|
|
23359
|
+
}
|
|
23360
|
+
if (!receipt) {
|
|
23361
|
+
throw new Error("Transaction not found or not yet confirmed");
|
|
23362
|
+
}
|
|
23363
|
+
if (receipt.status !== "0x1") {
|
|
23364
|
+
throw new Error("Transaction failed on-chain");
|
|
23365
|
+
}
|
|
23366
|
+
const recipientPadded = "0x" + recipient.slice(2).toLowerCase().padStart(64, "0");
|
|
23367
|
+
const tokenLower = tokenAddress.toLowerCase();
|
|
23368
|
+
const matchingLog = receipt.logs.find((log) => {
|
|
23369
|
+
if (log.address.toLowerCase() !== tokenLower) return false;
|
|
23370
|
+
if (log.topics[0] !== TRANSFER_EVENT_TOPIC) return false;
|
|
23371
|
+
if (log.topics[2]?.toLowerCase() !== recipientPadded) return false;
|
|
23372
|
+
return BigInt(log.data) >= expectedAmount;
|
|
23373
|
+
});
|
|
23374
|
+
if (!matchingLog) {
|
|
23375
|
+
throw new Error("No matching ERC-20 Transfer found for recipient and amount");
|
|
23376
|
+
}
|
|
23377
|
+
}
|
|
23378
|
+
|
|
23379
|
+
// src/mpp/evm-server.ts
|
|
22940
23380
|
function evmCharge(config2) {
|
|
22941
23381
|
const {
|
|
22942
23382
|
recipient,
|
|
@@ -22978,39 +23418,13 @@ function evmCharge(config2) {
|
|
|
22978
23418
|
if (!txHash || !txHash.startsWith("0x")) {
|
|
22979
23419
|
throw new Error("Missing or invalid transaction hash in credential payload");
|
|
22980
23420
|
}
|
|
22981
|
-
|
|
22982
|
-
|
|
22983
|
-
|
|
22984
|
-
|
|
22985
|
-
|
|
22986
|
-
|
|
22987
|
-
id: 1,
|
|
22988
|
-
method: "eth_getTransactionReceipt",
|
|
22989
|
-
params: [txHash]
|
|
22990
|
-
})
|
|
22991
|
-
});
|
|
22992
|
-
const receiptData = await receiptRes.json();
|
|
22993
|
-
if (receiptData.error) {
|
|
22994
|
-
throw new Error(`RPC error: ${receiptData.error.message}`);
|
|
22995
|
-
}
|
|
22996
|
-
const receipt = receiptData.result;
|
|
22997
|
-
if (!receipt) {
|
|
22998
|
-
throw new Error("Transaction not found or not yet confirmed");
|
|
22999
|
-
}
|
|
23000
|
-
if (receipt.status !== "0x1") {
|
|
23001
|
-
throw new Error("Transaction failed on-chain");
|
|
23002
|
-
}
|
|
23003
|
-
const recipientPadded = "0x" + recipient.slice(2).toLowerCase().padStart(64, "0");
|
|
23004
|
-
const tokenLower = tokenAddress.toLowerCase();
|
|
23005
|
-
const matchingLog = receipt.logs.find((log) => {
|
|
23006
|
-
if (log.address.toLowerCase() !== tokenLower) return false;
|
|
23007
|
-
if (log.topics[0] !== TRANSFER_EVENT_TOPIC) return false;
|
|
23008
|
-
if (log.topics[2]?.toLowerCase() !== recipientPadded) return false;
|
|
23009
|
-
return BigInt(log.data) >= expectedAmount;
|
|
23421
|
+
await verifyErc20Transfer({
|
|
23422
|
+
txHash,
|
|
23423
|
+
rpcUrl,
|
|
23424
|
+
tokenAddress,
|
|
23425
|
+
recipient,
|
|
23426
|
+
expectedAmount: BigInt(cred.challenge.request.amount)
|
|
23010
23427
|
});
|
|
23011
|
-
if (!matchingLog) {
|
|
23012
|
-
throw new Error("No matching ERC-20 Transfer found for recipient and amount");
|
|
23013
|
-
}
|
|
23014
23428
|
return Receipt_exports.from({
|
|
23015
23429
|
method: "evm",
|
|
23016
23430
|
reference: txHash,
|
|
@@ -26336,6 +26750,65 @@ async function waitForReceipt(rpcUrl, txHash, timeoutMs = 3e4) {
|
|
|
26336
26750
|
}
|
|
26337
26751
|
return false;
|
|
26338
26752
|
}
|
|
26753
|
+
|
|
26754
|
+
// src/mpp/bridge-method.ts
|
|
26755
|
+
var charge2 = Method_exports.from({
|
|
26756
|
+
intent: "charge",
|
|
26757
|
+
name: "bridge",
|
|
26758
|
+
schema: {
|
|
26759
|
+
credential: {
|
|
26760
|
+
payload: zod_exports.object({
|
|
26761
|
+
/** "settled" = client called bridge settle, targetTxHash is proof */
|
|
26762
|
+
type: zod_exports.string(),
|
|
26763
|
+
/** Target chain tx hash (0x-prefixed) — server verifies on-chain */
|
|
26764
|
+
targetTxHash: zod_exports.optional(zod_exports.string()),
|
|
26765
|
+
/** Source chain tx hash/signature (for auditing) */
|
|
26766
|
+
sourceTxHash: zod_exports.optional(zod_exports.string()),
|
|
26767
|
+
/** CAIP-2 source chain used */
|
|
26768
|
+
sourceChain: zod_exports.optional(zod_exports.string())
|
|
26769
|
+
})
|
|
26770
|
+
},
|
|
26771
|
+
request: zod_exports.object({
|
|
26772
|
+
/** Amount in target token base units */
|
|
26773
|
+
amount: zod_exports.string(),
|
|
26774
|
+
/** Target ERC-20 token contract address */
|
|
26775
|
+
currency: zod_exports.string(),
|
|
26776
|
+
/** Target chain recipient address (merchant) */
|
|
26777
|
+
recipient: zod_exports.string(),
|
|
26778
|
+
/** Human-readable description */
|
|
26779
|
+
description: zod_exports.optional(zod_exports.string()),
|
|
26780
|
+
methodDetails: zod_exports.object({
|
|
26781
|
+
/** Target chain ID (where the merchant gets paid) */
|
|
26782
|
+
targetChainId: zod_exports.number(),
|
|
26783
|
+
/** Human-readable target network name (e.g. "skale-base") */
|
|
26784
|
+
targetNetwork: zod_exports.optional(zod_exports.string()),
|
|
26785
|
+
/** Target chain RPC URL (for server-side verification) */
|
|
26786
|
+
targetRpcUrl: zod_exports.optional(zod_exports.string()),
|
|
26787
|
+
/** Target token decimals */
|
|
26788
|
+
targetDecimals: zod_exports.optional(zod_exports.number()),
|
|
26789
|
+
/** Bridge settle endpoint URL */
|
|
26790
|
+
settleEndpoint: zod_exports.string(),
|
|
26791
|
+
/** Supported source chains (CAIP-2 format, e.g. ["eip155:8453", "solana:5eykt4..."]) */
|
|
26792
|
+
supportedSourceChains: zod_exports.array(zod_exports.string()),
|
|
26793
|
+
/** Supported source token addresses */
|
|
26794
|
+
supportedSourceAssets: zod_exports.optional(zod_exports.array(zod_exports.string())),
|
|
26795
|
+
/** Bridge receiver addresses per source chain: { [caip2]: address } */
|
|
26796
|
+
payToMap: zod_exports.record(zod_exports.string(), zod_exports.string()),
|
|
26797
|
+
/** Solana fee payer address (bridge facilitator sponsors gas) */
|
|
26798
|
+
feePayerSvm: zod_exports.optional(zod_exports.string()),
|
|
26799
|
+
/** Bridge fee in basis points */
|
|
26800
|
+
feeBps: zod_exports.optional(zod_exports.number()),
|
|
26801
|
+
/** Payment facilitator URL */
|
|
26802
|
+
paymentFacilitator: zod_exports.optional(zod_exports.string()),
|
|
26803
|
+
/** Unique reference ID (for replay protection) */
|
|
26804
|
+
reference: zod_exports.string()
|
|
26805
|
+
})
|
|
26806
|
+
})
|
|
26807
|
+
}
|
|
26808
|
+
});
|
|
26809
|
+
|
|
26810
|
+
// src/mpp/bridge-server.ts
|
|
26811
|
+
var BRIDGE_INFO_TTL_MS = 5 * 60 * 1e3;
|
|
26339
26812
|
// Annotate the CommonJS export names for ESM import in node:
|
|
26340
26813
|
0 && (module.exports = {
|
|
26341
26814
|
BASE_MAINNET_NETWORK,
|
|
@@ -26343,6 +26816,7 @@ async function waitForReceipt(rpcUrl, txHash, timeoutMs = 3e4) {
|
|
|
26343
26816
|
CHAIN_IDS,
|
|
26344
26817
|
EXPLORER_TX_URL,
|
|
26345
26818
|
NETWORK_CAIP2,
|
|
26819
|
+
NETWORK_CONFIGS,
|
|
26346
26820
|
NETWORK_LABELS,
|
|
26347
26821
|
NETWORK_TOKENS,
|
|
26348
26822
|
NETWORK_V1_TO_V2,
|
|
@@ -26354,9 +26828,12 @@ async function waitForReceipt(rpcUrl, txHash, timeoutMs = 3e4) {
|
|
|
26354
26828
|
USDC_ADDRESSES,
|
|
26355
26829
|
USDC_BASE,
|
|
26356
26830
|
USDC_SOLANA,
|
|
26831
|
+
cancelPaymentCode,
|
|
26357
26832
|
convertPayloadToVersion,
|
|
26358
26833
|
convertV1ToV2,
|
|
26359
26834
|
convertV2ToV1,
|
|
26835
|
+
createPayRequest,
|
|
26836
|
+
createPrivateKeySigner,
|
|
26360
26837
|
createX402Client,
|
|
26361
26838
|
detectPayloadVersion,
|
|
26362
26839
|
evmChargeClient,
|
|
@@ -26365,6 +26842,8 @@ async function waitForReceipt(rpcUrl, txHash, timeoutMs = 3e4) {
|
|
|
26365
26842
|
formatUsd,
|
|
26366
26843
|
fromAtomicUnits,
|
|
26367
26844
|
generatePaymentCode,
|
|
26845
|
+
generatePaymentCodesBatch,
|
|
26846
|
+
getPayRequest,
|
|
26368
26847
|
getPaymentCode,
|
|
26369
26848
|
isEvm,
|
|
26370
26849
|
isEvmNetwork,
|
|
@@ -26374,6 +26853,8 @@ async function waitForReceipt(rpcUrl, txHash, timeoutMs = 3e4) {
|
|
|
26374
26853
|
networkV2ToV1,
|
|
26375
26854
|
normalizeNetwork,
|
|
26376
26855
|
normalizePaymentHeader,
|
|
26856
|
+
payPayRequest,
|
|
26857
|
+
payPayRequestWithCode,
|
|
26377
26858
|
redeemPaymentCode,
|
|
26378
26859
|
resolveToken,
|
|
26379
26860
|
stripePayTo,
|