@piprail/sdk 2.15.0 → 2.16.0
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/CHANGELOG.md +260 -0
- package/README.md +2 -2
- package/dist/{algorand-CSEUTWNW.js → algorand-25FMBCT3.js} +13 -4
- package/dist/{algorand-I2O24RSM.cjs → algorand-Q3TUQLPK.cjs} +49 -40
- package/dist/{aptos-J7QGCWNW.js → aptos-SBV6SGDP.js} +3 -3
- package/dist/{aptos-GA5AEYYL.cjs → aptos-VBJONBFY.cjs} +36 -36
- package/dist/chunk-2CX7XRZK.js +649 -0
- package/dist/chunk-C52H5TYB.js +474 -0
- package/dist/chunk-OXEFPLZA.cjs +474 -0
- package/dist/{chunk-3FR22M3O.cjs → chunk-QONQSZHJ.cjs} +2 -2
- package/dist/{chunk-3ZWM3DKM.js → chunk-QU25LSVS.js} +2 -2
- package/dist/chunk-V2IJ5HUW.cjs +649 -0
- package/dist/index.cjs +507 -1347
- package/dist/index.d.cts +39 -6
- package/dist/index.d.ts +39 -6
- package/dist/index.js +192 -1032
- package/dist/{ledger-uFtXlIHY.d.cts → ledger-Crc1bZox.d.cts} +164 -10
- package/dist/{ledger-uFtXlIHY.d.ts → ledger-Crc1bZox.d.ts} +164 -10
- package/dist/{near-NDQLGI4U.cjs → near-5LTTDU6G.cjs} +27 -27
- package/dist/{near-YA4Y4IGC.js → near-OLKCMTBI.js} +1 -1
- package/dist/node.d.cts +2 -2
- package/dist/node.d.ts +2 -2
- package/dist/{solana-OU6IUMQM.cjs → solana-AI2G7V33.cjs} +73 -52
- package/dist/{solana-MB6G3OA5.js → solana-HTKDRTD3.js} +32 -11
- package/dist/{stellar-RSNVOIKL.cjs → stellar-E2KWEV2E.cjs} +20 -20
- package/dist/{stellar-WDWSYOED.js → stellar-EUFZLX6J.js} +1 -1
- package/dist/{sui-GVSFNNJX.js → sui-KCIITCYH.js} +6 -2
- package/dist/{sui-MVC46BFJ.cjs → sui-Q3NJOJZS.cjs} +21 -17
- package/dist/{ton-MYOI3U3H.cjs → ton-J7TQWRN4.cjs} +16 -16
- package/dist/{ton-EJMGM3YI.js → ton-WH2JVQOO.js} +1 -1
- package/dist/{tron-VAPVMGJK.js → tron-FXBXDNEY.js} +1 -1
- package/dist/{tron-42X5N4GQ.cjs → tron-HIPMOX7S.cjs} +25 -25
- package/dist/{xrpl-Q2UWPCTJ.js → xrpl-RUOB37QH.js} +283 -5
- package/dist/{xrpl-MGUBUNSZ.cjs → xrpl-SVVS445B.cjs} +312 -34
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -4,6 +4,59 @@ import {
|
|
|
4
4
|
import {
|
|
5
5
|
signReceiptEvm
|
|
6
6
|
} from "./chunk-3SBTJKAG.js";
|
|
7
|
+
import {
|
|
8
|
+
DEFAULT_EXACT_TRANSFER_METHOD,
|
|
9
|
+
EXT_OFFER_RECEIPT,
|
|
10
|
+
EXT_PAYMENT_IDENTIFIER,
|
|
11
|
+
HEADER_REQUIRED,
|
|
12
|
+
HEADER_RESPONSE,
|
|
13
|
+
HEADER_RESPONSE_V1,
|
|
14
|
+
HEADER_SIGNATURE,
|
|
15
|
+
HEADER_SIGNATURE_V1,
|
|
16
|
+
KNOWN_EXACT_TRANSFER_METHODS,
|
|
17
|
+
buildChallengeHeader,
|
|
18
|
+
buildExactSignatureHeader,
|
|
19
|
+
buildPaymentIdentifierAdvertisement,
|
|
20
|
+
buildReceiptExtension,
|
|
21
|
+
buildReceiptHeader,
|
|
22
|
+
buildSignatureHeader,
|
|
23
|
+
buildUptoSignatureHeader,
|
|
24
|
+
buildV1PaymentHeader,
|
|
25
|
+
chainIdFromNetwork,
|
|
26
|
+
decodeBase64Json,
|
|
27
|
+
exactTransferMethod,
|
|
28
|
+
isSettleableExactMethod,
|
|
29
|
+
networkForChain,
|
|
30
|
+
normalizeV1Challenge,
|
|
31
|
+
parseChallenge,
|
|
32
|
+
parseExactObject,
|
|
33
|
+
parseExactPaymentHeader,
|
|
34
|
+
parseReceipt,
|
|
35
|
+
parseReceiptExtension,
|
|
36
|
+
parseSettleResponse,
|
|
37
|
+
parseSignatureHeader,
|
|
38
|
+
parseSignatureObject,
|
|
39
|
+
parseUptoObject,
|
|
40
|
+
parseUptoPaymentHeader,
|
|
41
|
+
pickAccept,
|
|
42
|
+
readPaymentIdentifier
|
|
43
|
+
} from "./chunk-C52H5TYB.js";
|
|
44
|
+
import {
|
|
45
|
+
DIRECTORY_INFO,
|
|
46
|
+
REGISTER_ATTRIBUTION,
|
|
47
|
+
appendAttribution,
|
|
48
|
+
appendKeywords,
|
|
49
|
+
claim402IndexDomain,
|
|
50
|
+
decorateOutcome,
|
|
51
|
+
getDirectoryInfo,
|
|
52
|
+
normalizeNetwork,
|
|
53
|
+
rankResources,
|
|
54
|
+
register402Index,
|
|
55
|
+
registerX402Scan,
|
|
56
|
+
scoreResource,
|
|
57
|
+
searchOpenIndexes,
|
|
58
|
+
verify402IndexDomain
|
|
59
|
+
} from "./chunk-2CX7XRZK.js";
|
|
7
60
|
import {
|
|
8
61
|
ConfirmationTimeoutError,
|
|
9
62
|
InsufficientFundsError,
|
|
@@ -32,7 +85,7 @@ import {
|
|
|
32
85
|
parseUnits,
|
|
33
86
|
rejectForeignToken,
|
|
34
87
|
toInsufficientFundsError
|
|
35
|
-
} from "./chunk-
|
|
88
|
+
} from "./chunk-QU25LSVS.js";
|
|
36
89
|
|
|
37
90
|
// src/drivers/registry.ts
|
|
38
91
|
var byFamily = /* @__PURE__ */ new Map();
|
|
@@ -896,8 +949,8 @@ async function verifyAndSettleExactEvm(input) {
|
|
|
896
949
|
try {
|
|
897
950
|
recovered = await recoverTypedDataAddress({
|
|
898
951
|
domain: {
|
|
899
|
-
name: accept.extra
|
|
900
|
-
version: accept.extra
|
|
952
|
+
name: accept.extra?.name,
|
|
953
|
+
version: accept.extra?.version,
|
|
901
954
|
chainId: chain.id,
|
|
902
955
|
verifyingContract: token
|
|
903
956
|
},
|
|
@@ -969,7 +1022,7 @@ async function verifyAndSettleExactEvm(input) {
|
|
|
969
1022
|
);
|
|
970
1023
|
}
|
|
971
1024
|
try {
|
|
972
|
-
const confirmations = accept.extra
|
|
1025
|
+
const confirmations = accept.extra?.minConfirmations ?? 1;
|
|
973
1026
|
const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash, confirmations });
|
|
974
1027
|
if (receipt.status !== "success") {
|
|
975
1028
|
return { ok: false, error: "tx_reverted", detail: `Settlement tx ${txHash} reverted on-chain.` };
|
|
@@ -1338,7 +1391,7 @@ async function verifyAndSettlePermit2Evm(input) {
|
|
|
1338
1391
|
);
|
|
1339
1392
|
}
|
|
1340
1393
|
try {
|
|
1341
|
-
const confirmations = accept.extra
|
|
1394
|
+
const confirmations = accept.extra?.minConfirmations ?? 1;
|
|
1342
1395
|
const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash, confirmations });
|
|
1343
1396
|
if (receipt.status !== "success") {
|
|
1344
1397
|
return { ok: false, error: "tx_reverted", detail: `Settlement tx ${txHash} reverted on-chain.` };
|
|
@@ -1720,318 +1773,6 @@ async function verifyAndSettleUptoEvm(input) {
|
|
|
1720
1773
|
};
|
|
1721
1774
|
}
|
|
1722
1775
|
|
|
1723
|
-
// src/x402.ts
|
|
1724
|
-
var HEADER_REQUIRED = "payment-required";
|
|
1725
|
-
var HEADER_SIGNATURE = "payment-signature";
|
|
1726
|
-
var HEADER_RESPONSE = "payment-response";
|
|
1727
|
-
var HEADER_SIGNATURE_V1 = "x-payment";
|
|
1728
|
-
var HEADER_RESPONSE_V1 = "x-payment-response";
|
|
1729
|
-
function encodeBase64(str) {
|
|
1730
|
-
if (typeof Buffer !== "undefined") return Buffer.from(str, "utf8").toString("base64");
|
|
1731
|
-
if (typeof btoa === "function" && typeof TextEncoder !== "undefined") {
|
|
1732
|
-
const bytes = new TextEncoder().encode(str);
|
|
1733
|
-
let binary = "";
|
|
1734
|
-
for (let i = 0; i < bytes.length; i++) binary += String.fromCharCode(bytes[i]);
|
|
1735
|
-
return btoa(binary);
|
|
1736
|
-
}
|
|
1737
|
-
throw new Error("No base64 encoder available in this runtime.");
|
|
1738
|
-
}
|
|
1739
|
-
function decodeBase64(b64) {
|
|
1740
|
-
if (typeof Buffer !== "undefined") return Buffer.from(b64, "base64").toString("utf8");
|
|
1741
|
-
if (typeof atob === "function" && typeof TextDecoder !== "undefined") {
|
|
1742
|
-
const binary = atob(b64);
|
|
1743
|
-
const bytes = new Uint8Array(binary.length);
|
|
1744
|
-
for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
|
|
1745
|
-
return new TextDecoder().decode(bytes);
|
|
1746
|
-
}
|
|
1747
|
-
throw new Error("No base64 decoder available in this runtime.");
|
|
1748
|
-
}
|
|
1749
|
-
function fromBase64Json(b64) {
|
|
1750
|
-
try {
|
|
1751
|
-
return JSON.parse(decodeBase64(b64));
|
|
1752
|
-
} catch {
|
|
1753
|
-
return null;
|
|
1754
|
-
}
|
|
1755
|
-
}
|
|
1756
|
-
function decodeBase64Json(value) {
|
|
1757
|
-
return fromBase64Json(value);
|
|
1758
|
-
}
|
|
1759
|
-
function toBase64Json(value) {
|
|
1760
|
-
return encodeBase64(JSON.stringify(value));
|
|
1761
|
-
}
|
|
1762
|
-
function networkForChain(chainId) {
|
|
1763
|
-
return `eip155:${chainId}`;
|
|
1764
|
-
}
|
|
1765
|
-
function chainIdFromNetwork(network) {
|
|
1766
|
-
const match = /^eip155:(\d+)$/.exec(network);
|
|
1767
|
-
if (!match || !match[1]) return null;
|
|
1768
|
-
const n = Number(match[1]);
|
|
1769
|
-
return Number.isSafeInteger(n) && n > 0 ? n : null;
|
|
1770
|
-
}
|
|
1771
|
-
function buildChallengeHeader(challenge) {
|
|
1772
|
-
return toBase64Json(challenge);
|
|
1773
|
-
}
|
|
1774
|
-
function buildReceiptHeader(receipt, extensions) {
|
|
1775
|
-
return toBase64Json(extensions ? { ...receipt, extensions } : receipt);
|
|
1776
|
-
}
|
|
1777
|
-
var EXT_OFFER_RECEIPT = "offer-receipt";
|
|
1778
|
-
function buildReceiptExtension(bundle) {
|
|
1779
|
-
const info = { settlement: bundle.receipt, resource: bundle.resource };
|
|
1780
|
-
if (typeof bundle.decimals === "number") info.decimals = bundle.decimals;
|
|
1781
|
-
if (bundle.attestation) info.receipt = bundle.attestation;
|
|
1782
|
-
return { [EXT_OFFER_RECEIPT]: { info } };
|
|
1783
|
-
}
|
|
1784
|
-
var EXT_PAYMENT_IDENTIFIER = "payment-identifier";
|
|
1785
|
-
var PAYMENT_ID_MIN = 16;
|
|
1786
|
-
var PAYMENT_ID_MAX = 128;
|
|
1787
|
-
var PAYMENT_ID_RE = /^[A-Za-z0-9_-]+$/;
|
|
1788
|
-
function buildPaymentIdentifierAdvertisement() {
|
|
1789
|
-
return {
|
|
1790
|
-
[EXT_PAYMENT_IDENTIFIER]: {
|
|
1791
|
-
info: { required: false },
|
|
1792
|
-
schema: { properties: { id: { type: "string", minLength: PAYMENT_ID_MIN, maxLength: PAYMENT_ID_MAX } } }
|
|
1793
|
-
}
|
|
1794
|
-
};
|
|
1795
|
-
}
|
|
1796
|
-
function readPaymentIdentifier(payload) {
|
|
1797
|
-
if (typeof payload !== "object" || payload === null) return null;
|
|
1798
|
-
const ext = payload.extensions;
|
|
1799
|
-
if (typeof ext !== "object" || ext === null) return null;
|
|
1800
|
-
const block = ext[EXT_PAYMENT_IDENTIFIER];
|
|
1801
|
-
if (typeof block !== "object" || block === null) return null;
|
|
1802
|
-
const info = block.info;
|
|
1803
|
-
if (typeof info !== "object" || info === null) return null;
|
|
1804
|
-
const id = info.id;
|
|
1805
|
-
if (id === void 0) return null;
|
|
1806
|
-
if (typeof id !== "string") return { invalid: "payment-identifier id must be a string" };
|
|
1807
|
-
if (id.length < PAYMENT_ID_MIN || id.length > PAYMENT_ID_MAX) {
|
|
1808
|
-
return { invalid: `payment-identifier id must be ${PAYMENT_ID_MIN}\u2013${PAYMENT_ID_MAX} chars (got ${id.length})` };
|
|
1809
|
-
}
|
|
1810
|
-
if (!PAYMENT_ID_RE.test(id)) {
|
|
1811
|
-
return { invalid: "payment-identifier id must match [A-Za-z0-9_-]" };
|
|
1812
|
-
}
|
|
1813
|
-
return id;
|
|
1814
|
-
}
|
|
1815
|
-
function buildSignatureHeader(signature) {
|
|
1816
|
-
return toBase64Json(signature);
|
|
1817
|
-
}
|
|
1818
|
-
function buildExactSignatureHeader(input) {
|
|
1819
|
-
return toBase64Json({ x402Version: 2, accepted: input.accepted, payload: input.payload });
|
|
1820
|
-
}
|
|
1821
|
-
function buildUptoSignatureHeader(input) {
|
|
1822
|
-
return toBase64Json({ x402Version: 2, accepted: input.accepted, payload: input.payload });
|
|
1823
|
-
}
|
|
1824
|
-
async function parseChallenge(response) {
|
|
1825
|
-
const headerValue = response.headers.get(HEADER_REQUIRED);
|
|
1826
|
-
if (headerValue) {
|
|
1827
|
-
const parsed = fromBase64Json(headerValue);
|
|
1828
|
-
if (isValidChallenge(parsed)) return parsed;
|
|
1829
|
-
}
|
|
1830
|
-
try {
|
|
1831
|
-
const body = await response.clone().json();
|
|
1832
|
-
if (isValidChallenge(body)) return body;
|
|
1833
|
-
} catch {
|
|
1834
|
-
}
|
|
1835
|
-
return null;
|
|
1836
|
-
}
|
|
1837
|
-
function parseReceipt(response) {
|
|
1838
|
-
const headerValue = response.headers.get(HEADER_RESPONSE) ?? response.headers.get(HEADER_RESPONSE_V1);
|
|
1839
|
-
if (!headerValue) return null;
|
|
1840
|
-
const parsed = fromBase64Json(headerValue);
|
|
1841
|
-
if (!isValidReceipt(parsed)) return null;
|
|
1842
|
-
const r = parsed;
|
|
1843
|
-
if (typeof r.transaction !== "string" && typeof r.txHash === "string") r.transaction = r.txHash;
|
|
1844
|
-
return r;
|
|
1845
|
-
}
|
|
1846
|
-
function parseReceiptExtension(response) {
|
|
1847
|
-
const headerValue = response.headers.get(HEADER_RESPONSE) ?? response.headers.get(HEADER_RESPONSE_V1);
|
|
1848
|
-
if (!headerValue) return null;
|
|
1849
|
-
const parsed = fromBase64Json(headerValue);
|
|
1850
|
-
if (!parsed || typeof parsed !== "object") return null;
|
|
1851
|
-
const ext = parsed.extensions;
|
|
1852
|
-
const block = ext?.[EXT_OFFER_RECEIPT];
|
|
1853
|
-
const info = block?.info;
|
|
1854
|
-
if (!info) return null;
|
|
1855
|
-
const settlement = isValidReceipt(info.settlement) ? info.settlement : isValidReceipt(info.receipt) ? info.receipt : void 0;
|
|
1856
|
-
if (!settlement) return null;
|
|
1857
|
-
const attestation = info.receipt && info.receipt !== settlement ? info.receipt : void 0;
|
|
1858
|
-
const res = info.resource;
|
|
1859
|
-
return {
|
|
1860
|
-
piprail: "1",
|
|
1861
|
-
receipt: settlement,
|
|
1862
|
-
resource: { url: res && typeof res.url === "string" ? res.url : "" },
|
|
1863
|
-
...typeof info.decimals === "number" ? { decimals: info.decimals } : {},
|
|
1864
|
-
...attestation ? { attestation } : {}
|
|
1865
|
-
};
|
|
1866
|
-
}
|
|
1867
|
-
function parseSettleResponse(response) {
|
|
1868
|
-
const headerValue = response.headers.get(HEADER_RESPONSE) ?? response.headers.get(HEADER_RESPONSE_V1);
|
|
1869
|
-
if (!headerValue) return null;
|
|
1870
|
-
const parsed = fromBase64Json(headerValue);
|
|
1871
|
-
if (!parsed || typeof parsed !== "object" || typeof parsed.success !== "boolean") return null;
|
|
1872
|
-
return {
|
|
1873
|
-
success: parsed.success,
|
|
1874
|
-
// Tolerate the legacy v1 `txHash` alias for `transaction` (mirrors isValidReceipt/parseReceipt).
|
|
1875
|
-
...typeof parsed.transaction === "string" ? { transaction: parsed.transaction } : typeof parsed.txHash === "string" ? { transaction: parsed.txHash } : {},
|
|
1876
|
-
...typeof parsed.network === "string" ? { network: parsed.network } : {},
|
|
1877
|
-
...typeof parsed.payer === "string" ? { payer: parsed.payer } : {},
|
|
1878
|
-
...typeof parsed.errorReason === "string" ? { errorReason: parsed.errorReason } : {},
|
|
1879
|
-
// The upto SettleResponse's REQUIRED `amount` (actual settled atomic units) — string
|
|
1880
|
-
// passthrough so the upto buyer records ACTUAL, not MAX. Absent on onchain-proof/exact.
|
|
1881
|
-
...typeof parsed.amount === "string" ? { amount: parsed.amount } : {}
|
|
1882
|
-
};
|
|
1883
|
-
}
|
|
1884
|
-
function parseSignatureObject(parsed) {
|
|
1885
|
-
if (!parsed || typeof parsed !== "object") return null;
|
|
1886
|
-
const v = parsed;
|
|
1887
|
-
const accepted = v.accepted;
|
|
1888
|
-
const scheme = accepted?.scheme ?? v.scheme;
|
|
1889
|
-
if (scheme !== "onchain-proof") return null;
|
|
1890
|
-
const payload = v.payload;
|
|
1891
|
-
if (!payload || typeof payload.txHash !== "string" || typeof payload.nonce !== "string") {
|
|
1892
|
-
return null;
|
|
1893
|
-
}
|
|
1894
|
-
if (!accepted) {
|
|
1895
|
-
const synthesized = {
|
|
1896
|
-
scheme: "onchain-proof",
|
|
1897
|
-
...typeof v.network === "string" ? { network: v.network } : {},
|
|
1898
|
-
...typeof v.asset === "string" ? { asset: v.asset } : {}
|
|
1899
|
-
};
|
|
1900
|
-
return { ...v, accepted: synthesized, payload };
|
|
1901
|
-
}
|
|
1902
|
-
return parsed;
|
|
1903
|
-
}
|
|
1904
|
-
function parseSignatureHeader(value) {
|
|
1905
|
-
return parseSignatureObject(fromBase64Json(value));
|
|
1906
|
-
}
|
|
1907
|
-
function parseExactPaymentHeader(value) {
|
|
1908
|
-
return parseExactObject(fromBase64Json(value));
|
|
1909
|
-
}
|
|
1910
|
-
function parseExactObject(parsed) {
|
|
1911
|
-
if (!parsed || typeof parsed !== "object") return null;
|
|
1912
|
-
const v = parsed;
|
|
1913
|
-
const accepted = v.accepted ?? null;
|
|
1914
|
-
const scheme = accepted?.scheme ?? v.scheme;
|
|
1915
|
-
if (scheme !== "exact") return null;
|
|
1916
|
-
const network = accepted?.network ?? v.network;
|
|
1917
|
-
if (typeof network !== "string") return null;
|
|
1918
|
-
const payload = v.payload;
|
|
1919
|
-
if (!payload || typeof payload !== "object") return null;
|
|
1920
|
-
const x402Version = typeof v.x402Version === "number" ? v.x402Version : 2;
|
|
1921
|
-
const asset = accepted && typeof accepted.asset === "string" ? accepted.asset : void 0;
|
|
1922
|
-
const base2 = { x402Version, network, ...asset ? { asset } : {}, raw: v };
|
|
1923
|
-
if (typeof payload.signedDelegateAction === "string") {
|
|
1924
|
-
return { ...base2, method: "near", payload: { signedDelegateAction: payload.signedDelegateAction } };
|
|
1925
|
-
}
|
|
1926
|
-
if (typeof payload.transaction === "string" && typeof payload.senderAuth === "string") {
|
|
1927
|
-
return { ...base2, method: "aptos", payload: { transaction: payload.transaction, senderAuth: payload.senderAuth } };
|
|
1928
|
-
}
|
|
1929
|
-
if (typeof payload.transaction === "string") {
|
|
1930
|
-
return { ...base2, method: "svm", payload: { transaction: payload.transaction } };
|
|
1931
|
-
}
|
|
1932
|
-
if (Array.isArray(payload.paymentGroup)) {
|
|
1933
|
-
const group = payload.paymentGroup;
|
|
1934
|
-
const index = payload.paymentIndex;
|
|
1935
|
-
if (group.length === 0 || group.length > 16 || !group.every((t) => typeof t === "string") || typeof index !== "number" || !Number.isInteger(index) || index < 0 || index >= group.length) {
|
|
1936
|
-
return null;
|
|
1937
|
-
}
|
|
1938
|
-
return {
|
|
1939
|
-
...base2,
|
|
1940
|
-
method: "algorand",
|
|
1941
|
-
payload: { paymentIndex: index, paymentGroup: group }
|
|
1942
|
-
};
|
|
1943
|
-
}
|
|
1944
|
-
const signature = payload.signature;
|
|
1945
|
-
if (typeof signature !== "string") return null;
|
|
1946
|
-
const authorization = payload.authorization;
|
|
1947
|
-
if (authorization && typeof authorization === "object") {
|
|
1948
|
-
for (const k of ["from", "to", "value", "validAfter", "validBefore", "nonce"]) {
|
|
1949
|
-
if (typeof authorization[k] !== "string") return null;
|
|
1950
|
-
}
|
|
1951
|
-
return {
|
|
1952
|
-
...base2,
|
|
1953
|
-
method: "eip3009",
|
|
1954
|
-
payload: { signature, authorization }
|
|
1955
|
-
};
|
|
1956
|
-
}
|
|
1957
|
-
const p2 = payload.permit2Authorization;
|
|
1958
|
-
if (p2 && typeof p2 === "object") {
|
|
1959
|
-
const permitted = p2.permitted;
|
|
1960
|
-
const witness = p2.witness;
|
|
1961
|
-
if (!permitted || typeof permitted !== "object" || !witness || typeof witness !== "object") return null;
|
|
1962
|
-
if (typeof permitted.token !== "string" || typeof permitted.amount !== "string") return null;
|
|
1963
|
-
if (typeof witness.to !== "string" || typeof witness.validAfter !== "string") return null;
|
|
1964
|
-
for (const k of ["from", "spender", "nonce", "deadline"]) {
|
|
1965
|
-
if (typeof p2[k] !== "string") return null;
|
|
1966
|
-
}
|
|
1967
|
-
return {
|
|
1968
|
-
...base2,
|
|
1969
|
-
method: "permit2",
|
|
1970
|
-
payload: { signature, permit2Authorization: p2 }
|
|
1971
|
-
};
|
|
1972
|
-
}
|
|
1973
|
-
return null;
|
|
1974
|
-
}
|
|
1975
|
-
function parseUptoPaymentHeader(value) {
|
|
1976
|
-
return parseUptoObject(fromBase64Json(value));
|
|
1977
|
-
}
|
|
1978
|
-
function parseUptoObject(parsed) {
|
|
1979
|
-
if (!parsed || typeof parsed !== "object") return null;
|
|
1980
|
-
const v = parsed;
|
|
1981
|
-
const accepted = v.accepted ?? null;
|
|
1982
|
-
const scheme = accepted?.scheme ?? v.scheme;
|
|
1983
|
-
if (scheme !== "upto") return null;
|
|
1984
|
-
const network = accepted?.network ?? v.network;
|
|
1985
|
-
if (typeof network !== "string") return null;
|
|
1986
|
-
const payload = v.payload;
|
|
1987
|
-
if (!payload || typeof payload !== "object") return null;
|
|
1988
|
-
const signature = payload.signature;
|
|
1989
|
-
if (typeof signature !== "string") return null;
|
|
1990
|
-
const p2 = payload.permit2Authorization;
|
|
1991
|
-
if (!p2 || typeof p2 !== "object") return null;
|
|
1992
|
-
const permitted = p2.permitted;
|
|
1993
|
-
const witness = p2.witness;
|
|
1994
|
-
if (!permitted || typeof permitted !== "object" || !witness || typeof witness !== "object") return null;
|
|
1995
|
-
if (typeof permitted.token !== "string" || typeof permitted.amount !== "string") return null;
|
|
1996
|
-
if (typeof witness.to !== "string" || typeof witness.facilitator !== "string" || typeof witness.validAfter !== "string") {
|
|
1997
|
-
return null;
|
|
1998
|
-
}
|
|
1999
|
-
for (const k of ["from", "spender", "nonce", "deadline"]) {
|
|
2000
|
-
if (typeof p2[k] !== "string") return null;
|
|
2001
|
-
}
|
|
2002
|
-
const x402Version = typeof v.x402Version === "number" ? v.x402Version : 2;
|
|
2003
|
-
const asset = accepted && typeof accepted.asset === "string" ? accepted.asset : void 0;
|
|
2004
|
-
const base2 = { x402Version, network, ...asset ? { asset } : {}, raw: v };
|
|
2005
|
-
return {
|
|
2006
|
-
...base2,
|
|
2007
|
-
method: "permit2-upto",
|
|
2008
|
-
payload: { signature, permit2Authorization: p2 }
|
|
2009
|
-
};
|
|
2010
|
-
}
|
|
2011
|
-
function isValidChallenge(value) {
|
|
2012
|
-
if (!value || typeof value !== "object") return false;
|
|
2013
|
-
const v = value;
|
|
2014
|
-
if (v.x402Version !== 2) return false;
|
|
2015
|
-
if (!Array.isArray(v.accepts) || v.accepts.length === 0) return false;
|
|
2016
|
-
if (!v.accepts.every((a) => a !== null && typeof a === "object")) return false;
|
|
2017
|
-
if (!v.resource || typeof v.resource !== "object") return false;
|
|
2018
|
-
return true;
|
|
2019
|
-
}
|
|
2020
|
-
function isValidReceipt(value) {
|
|
2021
|
-
if (!value || typeof value !== "object") return false;
|
|
2022
|
-
const v = value;
|
|
2023
|
-
if (v.scheme !== "onchain-proof" && v.scheme !== "exact" && v.scheme !== "upto") return false;
|
|
2024
|
-
if (typeof v.transaction !== "string" && typeof v.txHash !== "string") return false;
|
|
2025
|
-
if (typeof v.payer !== "string") return false;
|
|
2026
|
-
return true;
|
|
2027
|
-
}
|
|
2028
|
-
function pickAccept(challenge, matches) {
|
|
2029
|
-
for (const accept of challenge.accepts) {
|
|
2030
|
-
if (accept.scheme === "onchain-proof" && matches(accept.network)) return accept;
|
|
2031
|
-
}
|
|
2032
|
-
return null;
|
|
2033
|
-
}
|
|
2034
|
-
|
|
2035
1776
|
// src/drivers/evm/index.ts
|
|
2036
1777
|
var evmDriver = {
|
|
2037
1778
|
family: "evm",
|
|
@@ -2260,7 +2001,7 @@ function makeEvmNetwork(resolved) {
|
|
|
2260
2001
|
// Throws UnsupportedSchemeError for a contract signer (or a non-EIP-3009 token on the eip3009 path).
|
|
2261
2002
|
async payExact(wallet, accept) {
|
|
2262
2003
|
const a = wallet._native;
|
|
2263
|
-
const method = accept
|
|
2004
|
+
const method = exactTransferMethod(accept);
|
|
2264
2005
|
if (method === "permit2" || method === "permit2-exact") {
|
|
2265
2006
|
const { payload: payload2, payerFrom: payerFrom2, nonce: nonce2 } = await payPermit2Evm({
|
|
2266
2007
|
publicClient,
|
|
@@ -2296,7 +2037,19 @@ function makeEvmNetwork(resolved) {
|
|
|
2296
2037
|
return resolveExactRailEvm({
|
|
2297
2038
|
asset,
|
|
2298
2039
|
method,
|
|
2299
|
-
|
|
2040
|
+
// `readExactDomain` fails CLOSED to null on two very different causes: the token really
|
|
2041
|
+
// isn't EIP-3009, or the RPC read blipped (rate-limit, timeout, an HTML error page from a
|
|
2042
|
+
// proxy). Treating a blip as "not EIP-3009" silently downgrades a perfectly good gasless
|
|
2043
|
+
// rail to onchain-proof — the merchant's buyers start paying gas and the warning blames
|
|
2044
|
+
// their TOKEN, which is the one thing that isn't wrong. The buyer side already retries
|
|
2045
|
+
// once for exactly this reason (see payExactEvm); the gate side did not, so a rate-limited
|
|
2046
|
+
// public RPC could turn real Base USDC into "this token isn't EIP-3009". Mirror it.
|
|
2047
|
+
readDomain: async (a) => {
|
|
2048
|
+
const first = await readExactDomain(publicClient, a);
|
|
2049
|
+
if (first) return first;
|
|
2050
|
+
await new Promise((r) => setTimeout(r, 300));
|
|
2051
|
+
return readExactDomain(publicClient, a);
|
|
2052
|
+
},
|
|
2300
2053
|
permit2Supported: () => isPermit2ProxyChain(resolved.chainId)
|
|
2301
2054
|
});
|
|
2302
2055
|
},
|
|
@@ -2321,6 +2074,9 @@ function makeEvmNetwork(resolved) {
|
|
|
2321
2074
|
if ("signedDelegateAction" in payload) {
|
|
2322
2075
|
return { ok: false, error: "signature_invalid", detail: "A NEAR payload was submitted to an EVM exact rail." };
|
|
2323
2076
|
}
|
|
2077
|
+
if ("signedTxBlob" in payload) {
|
|
2078
|
+
return { ok: false, error: "signature_invalid", detail: "An XRPL payload was submitted to an EVM exact rail." };
|
|
2079
|
+
}
|
|
2324
2080
|
return verifyAndSettleExactEvm({
|
|
2325
2081
|
publicClient,
|
|
2326
2082
|
walletClient: a.walletClient,
|
|
@@ -2382,7 +2138,7 @@ var loaders = {
|
|
|
2382
2138
|
solana: async () => {
|
|
2383
2139
|
let mod;
|
|
2384
2140
|
try {
|
|
2385
|
-
mod = await import("./solana-
|
|
2141
|
+
mod = await import("./solana-HTKDRTD3.js");
|
|
2386
2142
|
} catch (cause) {
|
|
2387
2143
|
throw new MissingDriverError(
|
|
2388
2144
|
`Solana selected, but its packages aren't installed. Run: npm install @solana/web3.js @solana/spl-token bs58`,
|
|
@@ -2394,7 +2150,7 @@ var loaders = {
|
|
|
2394
2150
|
ton: async () => {
|
|
2395
2151
|
let mod;
|
|
2396
2152
|
try {
|
|
2397
|
-
mod = await import("./ton-
|
|
2153
|
+
mod = await import("./ton-WH2JVQOO.js");
|
|
2398
2154
|
} catch (cause) {
|
|
2399
2155
|
throw new MissingDriverError(
|
|
2400
2156
|
`TON selected, but its packages aren't installed. Run: npm install @ton/ton @ton/core @ton/crypto`,
|
|
@@ -2406,7 +2162,7 @@ var loaders = {
|
|
|
2406
2162
|
stellar: async () => {
|
|
2407
2163
|
let mod;
|
|
2408
2164
|
try {
|
|
2409
|
-
mod = await import("./stellar-
|
|
2165
|
+
mod = await import("./stellar-EUFZLX6J.js");
|
|
2410
2166
|
} catch (cause) {
|
|
2411
2167
|
throw new MissingDriverError(
|
|
2412
2168
|
`Stellar selected, but its package isn't installed. Run: npm install @stellar/stellar-sdk`,
|
|
@@ -2418,7 +2174,7 @@ var loaders = {
|
|
|
2418
2174
|
xrpl: async () => {
|
|
2419
2175
|
let mod;
|
|
2420
2176
|
try {
|
|
2421
|
-
mod = await import("./xrpl-
|
|
2177
|
+
mod = await import("./xrpl-RUOB37QH.js");
|
|
2422
2178
|
} catch (cause) {
|
|
2423
2179
|
throw new MissingDriverError(
|
|
2424
2180
|
`XRPL selected, but its package isn't installed. Run: npm install xrpl`,
|
|
@@ -2430,7 +2186,7 @@ var loaders = {
|
|
|
2430
2186
|
tron: async () => {
|
|
2431
2187
|
let mod;
|
|
2432
2188
|
try {
|
|
2433
|
-
mod = await import("./tron-
|
|
2189
|
+
mod = await import("./tron-FXBXDNEY.js");
|
|
2434
2190
|
} catch (cause) {
|
|
2435
2191
|
throw new MissingDriverError(
|
|
2436
2192
|
`Tron selected, but its package isn't installed. Run: npm install tronweb`,
|
|
@@ -2442,7 +2198,7 @@ var loaders = {
|
|
|
2442
2198
|
sui: async () => {
|
|
2443
2199
|
let mod;
|
|
2444
2200
|
try {
|
|
2445
|
-
mod = await import("./sui-
|
|
2201
|
+
mod = await import("./sui-KCIITCYH.js");
|
|
2446
2202
|
} catch (cause) {
|
|
2447
2203
|
throw new MissingDriverError(
|
|
2448
2204
|
`Sui selected, but its package isn't installed. Run: npm install @mysten/sui`,
|
|
@@ -2454,7 +2210,7 @@ var loaders = {
|
|
|
2454
2210
|
near: async () => {
|
|
2455
2211
|
let mod;
|
|
2456
2212
|
try {
|
|
2457
|
-
mod = await import("./near-
|
|
2213
|
+
mod = await import("./near-OLKCMTBI.js");
|
|
2458
2214
|
} catch (cause) {
|
|
2459
2215
|
throw new MissingDriverError(
|
|
2460
2216
|
`NEAR selected, but its package isn't installed. Run: npm install near-api-js`,
|
|
@@ -2466,7 +2222,7 @@ var loaders = {
|
|
|
2466
2222
|
aptos: async () => {
|
|
2467
2223
|
let mod;
|
|
2468
2224
|
try {
|
|
2469
|
-
mod = await import("./aptos-
|
|
2225
|
+
mod = await import("./aptos-SBV6SGDP.js");
|
|
2470
2226
|
} catch (cause) {
|
|
2471
2227
|
throw new MissingDriverError(
|
|
2472
2228
|
`Aptos selected, but its package isn't installed. Run: npm install @aptos-labs/ts-sdk`,
|
|
@@ -2478,7 +2234,7 @@ var loaders = {
|
|
|
2478
2234
|
algorand: async () => {
|
|
2479
2235
|
let mod;
|
|
2480
2236
|
try {
|
|
2481
|
-
mod = await import("./algorand-
|
|
2237
|
+
mod = await import("./algorand-25FMBCT3.js");
|
|
2482
2238
|
} catch (cause) {
|
|
2483
2239
|
throw new MissingDriverError(
|
|
2484
2240
|
`Algorand selected, but its package isn't installed. Run: npm install algosdk`,
|
|
@@ -2510,619 +2266,6 @@ async function resolveNetwork2(opts) {
|
|
|
2510
2266
|
return resolveNetwork(opts);
|
|
2511
2267
|
}
|
|
2512
2268
|
|
|
2513
|
-
// src/indexes.ts
|
|
2514
|
-
var DIRECTORY_INFO = Object.freeze({
|
|
2515
|
-
"402index": {
|
|
2516
|
-
source: "402index",
|
|
2517
|
-
review: "probe-sync",
|
|
2518
|
-
auth: "none",
|
|
2519
|
-
chains: null,
|
|
2520
|
-
onSuccess: "pending-review",
|
|
2521
|
-
readByDiscover: true,
|
|
2522
|
-
caveat: "402 Index probes your URL on submit (rejecting anything that does not return a real 402), then lists it \u2014 a self-registered resource becomes searchable once it passes automated health + payment-validity checks, with NO domain verification required (observed live: searchable within ~2 days for a healthy endpoint). Verify your domain on 402index.io for instant, guaranteed approval + a verified badge, which also flips every pending listing on that domain live at once."
|
|
2523
|
-
},
|
|
2524
|
-
x402scan: {
|
|
2525
|
-
source: "x402scan",
|
|
2526
|
-
review: "probe-sync",
|
|
2527
|
-
auth: "siwx",
|
|
2528
|
-
chains: ["eip155:8453", "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp"],
|
|
2529
|
-
onSuccess: "live",
|
|
2530
|
-
readByDiscover: false,
|
|
2531
|
-
caveat: "x402scan lists Base/Solana only, needs one wallet signature (SIWX), and requires a resolvable input schema (from /openapi.json or the bazaar extension in the 402 body). It goes live on x402scan.com immediately on success \u2014 but discover() does NOT read x402scan, so the listing won't appear in discover() results."
|
|
2532
|
-
},
|
|
2533
|
-
bazaar: {
|
|
2534
|
-
source: "bazaar",
|
|
2535
|
-
review: "settle-coupled",
|
|
2536
|
-
auth: "facilitator-only",
|
|
2537
|
-
chains: null,
|
|
2538
|
-
onSuccess: "not-listable",
|
|
2539
|
-
readByDiscover: true,
|
|
2540
|
-
caveat: "CDP Bazaar has no register endpoint \u2014 it catalogs a resource only when its own facilitator settles a payment. PipRail verifies locally with no facilitator, so a PipRail resource cannot be listed here (you can still READ Bazaar to find others). List on 402 Index or x402scan instead."
|
|
2541
|
-
}
|
|
2542
|
-
});
|
|
2543
|
-
function getDirectoryInfo(source) {
|
|
2544
|
-
return DIRECTORY_INFO[source];
|
|
2545
|
-
}
|
|
2546
|
-
function decorateOutcome(o) {
|
|
2547
|
-
const info = DIRECTORY_INFO[o.source];
|
|
2548
|
-
return { ...o, visibility: o.visibility ?? (o.ok ? info.onSuccess : "not-listable"), note: info.caveat };
|
|
2549
|
-
}
|
|
2550
|
-
var BAZAAR_URL = "https://api.cdp.coinbase.com/platform/v2/x402/discovery/resources";
|
|
2551
|
-
var INDEX402_SEARCH = "https://402index.io/api/v1/services";
|
|
2552
|
-
var INDEX402_REGISTER = "https://402index.io/api/v1/register";
|
|
2553
|
-
var INDEX402_CLAIM = "https://402index.io/api/v1/claim";
|
|
2554
|
-
var INDEX402_VERIFY = "https://402index.io/api/v1/claim/verify";
|
|
2555
|
-
var X402SCAN_REGISTER = "https://www.x402scan.com/api/x402/registry/register";
|
|
2556
|
-
var USER_AGENT = "@piprail/sdk (+https://piprail.com)";
|
|
2557
|
-
function clientHeaders(extra = {}) {
|
|
2558
|
-
return { "user-agent": USER_AGENT, ...extra };
|
|
2559
|
-
}
|
|
2560
|
-
var SLUG_TO_CAIP2 = {
|
|
2561
|
-
// EVM (the common index-reported slugs; others fall through to net.supports)
|
|
2562
|
-
ethereum: "eip155:1",
|
|
2563
|
-
base: "eip155:8453",
|
|
2564
|
-
polygon: "eip155:137",
|
|
2565
|
-
arbitrum: "eip155:42161",
|
|
2566
|
-
optimism: "eip155:10",
|
|
2567
|
-
avalanche: "eip155:43114",
|
|
2568
|
-
bnb: "eip155:56",
|
|
2569
|
-
bsc: "eip155:56",
|
|
2570
|
-
// non-EVM families — values mirror each driver's bound caip2 exactly
|
|
2571
|
-
solana: "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",
|
|
2572
|
-
ton: "tvm:-239",
|
|
2573
|
-
tron: "tron:mainnet",
|
|
2574
|
-
near: "near:mainnet",
|
|
2575
|
-
sui: "sui:mainnet",
|
|
2576
|
-
aptos: "aptos:1",
|
|
2577
|
-
algorand: "algorand:wGHE2Pwdvd7S12BL5FaOP20EGYesN73ktiC1qzkkit8=",
|
|
2578
|
-
stellar: "stellar:pubnet",
|
|
2579
|
-
xrpl: "xrpl:0"
|
|
2580
|
-
};
|
|
2581
|
-
var LEGACY_CAIP2_ALIAS = {
|
|
2582
|
-
"ton:-239": "tvm:-239"
|
|
2583
|
-
};
|
|
2584
|
-
function normalizeNetwork(network) {
|
|
2585
|
-
const legacy = LEGACY_CAIP2_ALIAS[network];
|
|
2586
|
-
if (legacy) return legacy;
|
|
2587
|
-
if (network.includes(":")) return network;
|
|
2588
|
-
return SLUG_TO_CAIP2[network.toLowerCase()] ?? network;
|
|
2589
|
-
}
|
|
2590
|
-
async function searchOpenIndexes(opts = {}) {
|
|
2591
|
-
const sources = opts.sources ?? ["bazaar", "402index"];
|
|
2592
|
-
const limit = opts.limit ?? 20;
|
|
2593
|
-
const filters = {
|
|
2594
|
-
...optionalRaw("category", opts.category),
|
|
2595
|
-
...optionalRaw("asset", opts.asset),
|
|
2596
|
-
...optionalRaw("maxPrice", opts.maxPrice),
|
|
2597
|
-
...optionalRaw("verified", opts.verified),
|
|
2598
|
-
...optionalRaw("paymentValid", opts.paymentValid),
|
|
2599
|
-
...optionalRaw("sort", opts.sort),
|
|
2600
|
-
...optionalRaw("order", opts.order)
|
|
2601
|
-
};
|
|
2602
|
-
const results = await Promise.all(
|
|
2603
|
-
sources.map((source) => {
|
|
2604
|
-
if (source === "bazaar") return safeSearch(() => searchBazaar(opts.query, limit, opts.signal));
|
|
2605
|
-
if (source === "402index") return safeSearch(() => search402Index(opts.query, limit, filters, opts.signal));
|
|
2606
|
-
return Promise.resolve([]);
|
|
2607
|
-
})
|
|
2608
|
-
);
|
|
2609
|
-
const merged = applyClientFilters(dedupeByResource(results.flat()), opts);
|
|
2610
|
-
const wantRelevance = opts.query !== void 0 && (opts.sort ?? "relevance") === "relevance";
|
|
2611
|
-
if (wantRelevance) return rankResources(merged, opts.query);
|
|
2612
|
-
if (opts.sort && opts.sort !== "relevance") return sortResources(merged, opts.sort, opts.order ?? "desc");
|
|
2613
|
-
return merged;
|
|
2614
|
-
}
|
|
2615
|
-
function optionalRaw(field, value) {
|
|
2616
|
-
return value !== void 0 ? { [field]: value } : {};
|
|
2617
|
-
}
|
|
2618
|
-
function applyClientFilters(items, opts) {
|
|
2619
|
-
let out = items;
|
|
2620
|
-
if (opts.category) {
|
|
2621
|
-
const want = opts.category.toLowerCase();
|
|
2622
|
-
out = out.filter((r) => r.category !== void 0 && r.category.toLowerCase().startsWith(want));
|
|
2623
|
-
}
|
|
2624
|
-
if (opts.maxPrice !== void 0) {
|
|
2625
|
-
const max = opts.maxPrice;
|
|
2626
|
-
out = out.filter((r) => r.priceUsd === void 0 || r.priceUsd <= max);
|
|
2627
|
-
}
|
|
2628
|
-
if (opts.asset) {
|
|
2629
|
-
const want = opts.asset.toLowerCase();
|
|
2630
|
-
out = out.filter((r) => {
|
|
2631
|
-
const known = r.rails.map((x) => x.symbol ?? x.asset).filter((a) => !!a);
|
|
2632
|
-
return known.length === 0 || known.some((a) => a.toLowerCase() === want);
|
|
2633
|
-
});
|
|
2634
|
-
}
|
|
2635
|
-
if (opts.minReliability !== void 0) {
|
|
2636
|
-
const min = opts.minReliability;
|
|
2637
|
-
out = out.filter((r) => r.reliabilityScore === void 0 || r.reliabilityScore >= min);
|
|
2638
|
-
}
|
|
2639
|
-
return out;
|
|
2640
|
-
}
|
|
2641
|
-
function tokenize(s) {
|
|
2642
|
-
return (s ?? "").toLowerCase().match(/[a-z0-9]+/g) ?? [];
|
|
2643
|
-
}
|
|
2644
|
-
var FIELD_WEIGHTS = { name: 6, category: 4, tags: 4, path: 3, description: 2 };
|
|
2645
|
-
function fieldTokens(r) {
|
|
2646
|
-
let pathText = r.resource;
|
|
2647
|
-
try {
|
|
2648
|
-
const u = new URL(r.resource);
|
|
2649
|
-
pathText = `${u.hostname} ${u.pathname}`;
|
|
2650
|
-
} catch {
|
|
2651
|
-
}
|
|
2652
|
-
return [
|
|
2653
|
-
[tokenize(r.name), FIELD_WEIGHTS.name],
|
|
2654
|
-
[tokenize(r.category), FIELD_WEIGHTS.category],
|
|
2655
|
-
[tokenize((r.tags ?? []).join(" ")), FIELD_WEIGHTS.tags],
|
|
2656
|
-
[tokenize(pathText), FIELD_WEIGHTS.path],
|
|
2657
|
-
[tokenize(r.description), FIELD_WEIGHTS.description]
|
|
2658
|
-
];
|
|
2659
|
-
}
|
|
2660
|
-
function scoreResource(r, queryTokens) {
|
|
2661
|
-
if (queryTokens.length === 0) return 0;
|
|
2662
|
-
const fields = fieldTokens(r);
|
|
2663
|
-
let score = 0;
|
|
2664
|
-
let matched = 0;
|
|
2665
|
-
for (const qt of queryTokens) {
|
|
2666
|
-
let hit = false;
|
|
2667
|
-
for (const [toks, w] of fields) {
|
|
2668
|
-
if (toks.includes(qt)) {
|
|
2669
|
-
score += w;
|
|
2670
|
-
hit = true;
|
|
2671
|
-
} else if (qt.length >= 4 && toks.some((t) => t.startsWith(qt) || t.length >= 4 && qt.startsWith(t))) {
|
|
2672
|
-
score += w * 0.4;
|
|
2673
|
-
hit = true;
|
|
2674
|
-
}
|
|
2675
|
-
}
|
|
2676
|
-
if (hit) matched++;
|
|
2677
|
-
}
|
|
2678
|
-
if (matched === 0) return 0;
|
|
2679
|
-
if (matched === queryTokens.length) score += 8;
|
|
2680
|
-
if (r.reliabilityScore !== void 0) score += r.reliabilityScore / 1e3;
|
|
2681
|
-
return score;
|
|
2682
|
-
}
|
|
2683
|
-
function rankResources(items, query) {
|
|
2684
|
-
const qTokens = tokenize(query);
|
|
2685
|
-
if (qTokens.length === 0) return items;
|
|
2686
|
-
return items.map((r, i) => ({ r, i, s: scoreResource(r, qTokens) })).filter((x) => x.s > 0).sort((a, b) => b.s - a.s || a.i - b.i).map((x) => ({ ...x.r, score: x.s }));
|
|
2687
|
-
}
|
|
2688
|
-
function sortResources(items, sort, order) {
|
|
2689
|
-
const dir = order === "asc" ? 1 : -1;
|
|
2690
|
-
const key = (r) => sort === "reliability" || sort === "uptime" ? r.reliabilityScore : sort === "price" ? r.priceUsd : sort === "name" ? (r.name ?? r.resource).toLowerCase() : void 0;
|
|
2691
|
-
return items.map((r, i) => ({ r, i })).sort((a, b) => {
|
|
2692
|
-
const ka = key(a.r);
|
|
2693
|
-
const kb = key(b.r);
|
|
2694
|
-
if (ka === void 0 && kb === void 0) return a.i - b.i;
|
|
2695
|
-
if (ka === void 0) return 1;
|
|
2696
|
-
if (kb === void 0) return -1;
|
|
2697
|
-
if (ka < kb) return -1 * dir;
|
|
2698
|
-
if (ka > kb) return 1 * dir;
|
|
2699
|
-
return a.i - b.i;
|
|
2700
|
-
}).map((x) => x.r);
|
|
2701
|
-
}
|
|
2702
|
-
async function safeSearch(run) {
|
|
2703
|
-
try {
|
|
2704
|
-
return await run();
|
|
2705
|
-
} catch {
|
|
2706
|
-
return [];
|
|
2707
|
-
}
|
|
2708
|
-
}
|
|
2709
|
-
function dedupeByResource(items) {
|
|
2710
|
-
const seen = /* @__PURE__ */ new Set();
|
|
2711
|
-
const out = [];
|
|
2712
|
-
for (const it of items) {
|
|
2713
|
-
const key = it.resource;
|
|
2714
|
-
if (!key || seen.has(key)) continue;
|
|
2715
|
-
seen.add(key);
|
|
2716
|
-
out.push(it);
|
|
2717
|
-
}
|
|
2718
|
-
return out;
|
|
2719
|
-
}
|
|
2720
|
-
async function searchBazaar(query, limit, signal) {
|
|
2721
|
-
const res = await fetch(`${BAZAAR_URL}?limit=${encodeURIComponent(String(limit))}`, {
|
|
2722
|
-
headers: clientHeaders({ accept: "application/json" }),
|
|
2723
|
-
...signal ? { signal } : {}
|
|
2724
|
-
});
|
|
2725
|
-
if (!res.ok) return [];
|
|
2726
|
-
const body = await res.json();
|
|
2727
|
-
const items = Array.isArray(body.items) ? body.items : [];
|
|
2728
|
-
const mapped = items.map(mapBazaarItem).filter((r) => r !== null);
|
|
2729
|
-
return query ? mapped.filter((r) => matchesQuery(r, query)) : mapped;
|
|
2730
|
-
}
|
|
2731
|
-
function mapBazaarItem(raw) {
|
|
2732
|
-
if (!raw || typeof raw !== "object") return null;
|
|
2733
|
-
const o = raw;
|
|
2734
|
-
const resource = pickString(o, "resource", "url", "endpoint");
|
|
2735
|
-
if (!resource) return null;
|
|
2736
|
-
const meta = o.metadata && typeof o.metadata === "object" ? o.metadata : {};
|
|
2737
|
-
return {
|
|
2738
|
-
resource,
|
|
2739
|
-
source: "bazaar",
|
|
2740
|
-
rails: mapRails(o.accepts),
|
|
2741
|
-
...optionalString("name", pickString(meta, "name", "title")),
|
|
2742
|
-
...optionalString("description", pickString(meta, "description") ?? pickString(o, "description")),
|
|
2743
|
-
...optionalString("category", pickString(meta, "category"))
|
|
2744
|
-
};
|
|
2745
|
-
}
|
|
2746
|
-
async function search402Index(query, limit, filters, signal) {
|
|
2747
|
-
const tokens = tokenize(query);
|
|
2748
|
-
const queries = query && tokens.length > 1 ? [.../* @__PURE__ */ new Set([query, ...tokens])].slice(0, 5) : [query];
|
|
2749
|
-
const pages = await Promise.all(queries.map((q) => safeSearch(() => fetch402Page(q, limit, filters, signal))));
|
|
2750
|
-
return dedupeByResource(pages.flat());
|
|
2751
|
-
}
|
|
2752
|
-
async function fetch402Page(query, limit, filters, signal) {
|
|
2753
|
-
const qs = new URLSearchParams({ limit: String(limit) });
|
|
2754
|
-
if (query) qs.set("q", query);
|
|
2755
|
-
if (filters.category) qs.set("category", filters.category);
|
|
2756
|
-
if (filters.asset) qs.set("payment_asset", filters.asset);
|
|
2757
|
-
if (filters.maxPrice !== void 0) qs.set("max_price_usd", String(filters.maxPrice));
|
|
2758
|
-
if (filters.verified) qs.set("verified", "true");
|
|
2759
|
-
if (filters.paymentValid) qs.set("payment_valid", "true");
|
|
2760
|
-
if (filters.sort && filters.sort !== "relevance") {
|
|
2761
|
-
qs.set("sort", filters.sort);
|
|
2762
|
-
qs.set("order", filters.order ?? "desc");
|
|
2763
|
-
}
|
|
2764
|
-
const res = await fetch(`${INDEX402_SEARCH}?${qs.toString()}`, {
|
|
2765
|
-
headers: clientHeaders({ accept: "application/json" }),
|
|
2766
|
-
...signal ? { signal } : {}
|
|
2767
|
-
});
|
|
2768
|
-
if (!res.ok) return [];
|
|
2769
|
-
const body = await res.json();
|
|
2770
|
-
const list = firstArray(body, "services", "results", "items", "data");
|
|
2771
|
-
return list.map(map402IndexItem).filter((r) => r !== null).filter((r) => r.rails.length > 0);
|
|
2772
|
-
}
|
|
2773
|
-
function map402IndexItem(raw) {
|
|
2774
|
-
if (!raw || typeof raw !== "object") return null;
|
|
2775
|
-
const o = raw;
|
|
2776
|
-
const resource = pickString(o, "url", "resource", "endpoint");
|
|
2777
|
-
if (!resource) return null;
|
|
2778
|
-
const protocol = (pickString(o, "protocol") ?? "x402").toLowerCase();
|
|
2779
|
-
if (protocol !== "x402") return null;
|
|
2780
|
-
const rails = Array.isArray(o.accepts) ? mapRails(o.accepts) : railFrom402IndexFields(o);
|
|
2781
|
-
const priceUsd = pickNumber(o, "price_usd", "priceUsd", "price");
|
|
2782
|
-
const reliabilityScore = pickNumber(o, "reliability_score", "reliabilityScore");
|
|
2783
|
-
const tags = pickStringArray(o, "tags", "keywords");
|
|
2784
|
-
return {
|
|
2785
|
-
resource,
|
|
2786
|
-
source: "402index",
|
|
2787
|
-
rails,
|
|
2788
|
-
...priceUsd !== void 0 ? { priceUsd } : {},
|
|
2789
|
-
...reliabilityScore !== void 0 ? { reliabilityScore } : {},
|
|
2790
|
-
...tags ? { tags } : {},
|
|
2791
|
-
...optionalString("name", pickString(o, "name", "title")),
|
|
2792
|
-
...optionalString("description", pickString(o, "description")),
|
|
2793
|
-
...optionalString("category", pickString(o, "category", "tag")),
|
|
2794
|
-
...optionalString("health", pickString(o, "health_status", "health")),
|
|
2795
|
-
// 402 Index reports domain_verified as 0/1; surface a boolean only when the field is present.
|
|
2796
|
-
...o.domain_verified !== void 0 || o.verified !== void 0 ? { verified: isTruthyFlag(o.domain_verified) || isTruthyFlag(o.verified) } : {}
|
|
2797
|
-
};
|
|
2798
|
-
}
|
|
2799
|
-
function isTruthyFlag(v) {
|
|
2800
|
-
return v === 1 || v === true || v === "1" || v === "true";
|
|
2801
|
-
}
|
|
2802
|
-
function railFrom402IndexFields(o) {
|
|
2803
|
-
const network = pickString(o, "payment_network", "network");
|
|
2804
|
-
const asset = pickString(o, "payment_asset", "asset", "token");
|
|
2805
|
-
if (!network && !asset) return [];
|
|
2806
|
-
return [
|
|
2807
|
-
{
|
|
2808
|
-
scheme: "exact",
|
|
2809
|
-
network: network ?? "unknown",
|
|
2810
|
-
...asset ? { asset } : {},
|
|
2811
|
-
...optionalString("symbol", asset)
|
|
2812
|
-
}
|
|
2813
|
-
];
|
|
2814
|
-
}
|
|
2815
|
-
async function register402Index(input) {
|
|
2816
|
-
try {
|
|
2817
|
-
const attributionOn = input.attribution !== false;
|
|
2818
|
-
const withTags = appendKeywords(input.description, input.tags);
|
|
2819
|
-
const description = attributionOn ? appendAttribution(withTags) : withTags;
|
|
2820
|
-
const payload = {
|
|
2821
|
-
url: input.url,
|
|
2822
|
-
name: input.name ?? hostOf(input.url),
|
|
2823
|
-
protocol: "x402",
|
|
2824
|
-
...description ? { description } : {},
|
|
2825
|
-
...typeof input.priceUsd === "number" ? { price_usd: input.priceUsd } : {},
|
|
2826
|
-
...input.asset ? { payment_asset: input.asset } : {},
|
|
2827
|
-
...input.network ? { payment_network: input.network } : {},
|
|
2828
|
-
...input.method ? { http_method: input.method.toUpperCase() } : {},
|
|
2829
|
-
...input.category ? { category: input.category } : {},
|
|
2830
|
-
...input.tags && input.tags.length > 0 ? { tags: input.tags } : {},
|
|
2831
|
-
...input.provider ? { provider: input.provider } : {},
|
|
2832
|
-
...input.contactEmail ? { contact_email: input.contactEmail } : {},
|
|
2833
|
-
...input.probeBody !== void 0 ? { probe_body: input.probeBody } : {},
|
|
2834
|
-
...attributionOn ? { via: "@piprail/sdk" } : {}
|
|
2835
|
-
};
|
|
2836
|
-
const res = await fetch(INDEX402_REGISTER, {
|
|
2837
|
-
method: "POST",
|
|
2838
|
-
headers: clientHeaders({ "content-type": "application/json", accept: "application/json" }),
|
|
2839
|
-
body: JSON.stringify(payload)
|
|
2840
|
-
});
|
|
2841
|
-
if (res.ok) {
|
|
2842
|
-
const body = await res.json().catch(() => ({}));
|
|
2843
|
-
const msg = typeof body.message === "string" && body.message.length > 0 ? body.message : void 0;
|
|
2844
|
-
const live = body.service?.status === "active";
|
|
2845
|
-
return {
|
|
2846
|
-
source: "402index",
|
|
2847
|
-
ok: true,
|
|
2848
|
-
status: res.status,
|
|
2849
|
-
...live ? { visibility: "live" } : {},
|
|
2850
|
-
detail: msg ?? (live ? "Registered + live on 402 Index (domain verified)." : "Registered on 402 Index \u2014 probed on submit, then searchable once it passes automated health + payment checks (verify your domain on 402index.io for instant approval + a verified badge).")
|
|
2851
|
-
};
|
|
2852
|
-
}
|
|
2853
|
-
const why = await readIndexError(res);
|
|
2854
|
-
return {
|
|
2855
|
-
source: "402index",
|
|
2856
|
-
ok: false,
|
|
2857
|
-
status: res.status,
|
|
2858
|
-
detail: why ? `402 Index rejected it (HTTP ${res.status}): ${why}` : `402 Index returned HTTP ${res.status}.`
|
|
2859
|
-
};
|
|
2860
|
-
} catch (err) {
|
|
2861
|
-
return { source: "402index", ok: false, detail: errMsg(err) };
|
|
2862
|
-
}
|
|
2863
|
-
}
|
|
2864
|
-
async function readIndexError(res) {
|
|
2865
|
-
try {
|
|
2866
|
-
const body = await res.json();
|
|
2867
|
-
const parts = [body.error, body.detail, body.message].filter(
|
|
2868
|
-
(p) => typeof p === "string" && p.length > 0
|
|
2869
|
-
);
|
|
2870
|
-
return parts.length ? [...new Set(parts)].join(" \u2014 ") : void 0;
|
|
2871
|
-
} catch {
|
|
2872
|
-
return void 0;
|
|
2873
|
-
}
|
|
2874
|
-
}
|
|
2875
|
-
async function registerX402Scan(input, signer) {
|
|
2876
|
-
try {
|
|
2877
|
-
const challengeRes = await fetch(X402SCAN_REGISTER, {
|
|
2878
|
-
method: "POST",
|
|
2879
|
-
headers: clientHeaders({ "content-type": "application/json", accept: "application/json" }),
|
|
2880
|
-
body: JSON.stringify({ url: input.url })
|
|
2881
|
-
});
|
|
2882
|
-
if (challengeRes.status !== 402) {
|
|
2883
|
-
return {
|
|
2884
|
-
source: "x402scan",
|
|
2885
|
-
ok: challengeRes.ok,
|
|
2886
|
-
status: challengeRes.status,
|
|
2887
|
-
detail: challengeRes.ok ? "Listed on x402scan." : `x402scan returned HTTP ${challengeRes.status} (expected a SIWX 402 challenge).`
|
|
2888
|
-
};
|
|
2889
|
-
}
|
|
2890
|
-
const info = await readSiwxInfo(challengeRes);
|
|
2891
|
-
if (!info) {
|
|
2892
|
-
return { source: "x402scan", ok: false, status: 402, detail: "x402scan SIWX challenge was unparseable." };
|
|
2893
|
-
}
|
|
2894
|
-
const resolvedInfo = { ...info, issuedAt: info.issuedAt ?? (/* @__PURE__ */ new Date()).toISOString() };
|
|
2895
|
-
const message = formatSiweMessage(resolvedInfo, signer.address);
|
|
2896
|
-
const signature = await signer.signMessage(message);
|
|
2897
|
-
const header = encodeBase642(
|
|
2898
|
-
JSON.stringify({ ...resolvedInfo, address: signer.address, type: "eip191", message, signature })
|
|
2899
|
-
);
|
|
2900
|
-
const res = await fetch(X402SCAN_REGISTER, {
|
|
2901
|
-
method: "POST",
|
|
2902
|
-
headers: clientHeaders({
|
|
2903
|
-
"content-type": "application/json",
|
|
2904
|
-
accept: "application/json",
|
|
2905
|
-
"sign-in-with-x": header
|
|
2906
|
-
}),
|
|
2907
|
-
body: JSON.stringify({ url: input.url })
|
|
2908
|
-
});
|
|
2909
|
-
if (res.ok) {
|
|
2910
|
-
return { source: "x402scan", ok: true, status: res.status, detail: "Listed on x402scan (SIWX)." };
|
|
2911
|
-
}
|
|
2912
|
-
const why = await readIndexError(res);
|
|
2913
|
-
return {
|
|
2914
|
-
source: "x402scan",
|
|
2915
|
-
ok: false,
|
|
2916
|
-
status: res.status,
|
|
2917
|
-
detail: why ? `x402scan rejected it (HTTP ${res.status}): ${why}` : `x402scan returned HTTP ${res.status} after signing.`
|
|
2918
|
-
};
|
|
2919
|
-
} catch (err) {
|
|
2920
|
-
return { source: "x402scan", ok: false, detail: errMsg(err) };
|
|
2921
|
-
}
|
|
2922
|
-
}
|
|
2923
|
-
async function claim402IndexDomain(domainOrUrl, opts = {}) {
|
|
2924
|
-
const domain = hostOf(domainOrUrl);
|
|
2925
|
-
try {
|
|
2926
|
-
const res = await fetch(INDEX402_CLAIM, {
|
|
2927
|
-
method: "POST",
|
|
2928
|
-
headers: clientHeaders({ "content-type": "application/json", accept: "application/json" }),
|
|
2929
|
-
body: JSON.stringify({ domain, ...opts.contactEmail ? { contact_email: opts.contactEmail } : {} })
|
|
2930
|
-
});
|
|
2931
|
-
const body = await res.json().catch(() => ({}));
|
|
2932
|
-
if (!res.ok) {
|
|
2933
|
-
return { ok: false, domain, httpStatus: res.status, detail: pickString(body, "error", "detail", "message") ?? `402 Index claim returned HTTP ${res.status}.` };
|
|
2934
|
-
}
|
|
2935
|
-
const verificationToken = pickString(body, "verification_token");
|
|
2936
|
-
const verificationHash = pickString(body, "verification_hash") ?? (verificationToken ? await sha256Hex(verificationToken) : void 0);
|
|
2937
|
-
return {
|
|
2938
|
-
ok: true,
|
|
2939
|
-
domain,
|
|
2940
|
-
httpStatus: res.status,
|
|
2941
|
-
...optionalString("verificationHash", verificationHash),
|
|
2942
|
-
...optionalString("verificationToken", verificationToken),
|
|
2943
|
-
...optionalString("verificationUrl", pickString(body, "verification_url")),
|
|
2944
|
-
...optionalString("instructions", pickString(body, "instructions"))
|
|
2945
|
-
};
|
|
2946
|
-
} catch (err) {
|
|
2947
|
-
return { ok: false, domain, detail: errMsg(err) };
|
|
2948
|
-
}
|
|
2949
|
-
}
|
|
2950
|
-
async function sha256Hex(input) {
|
|
2951
|
-
const digest = await globalThis.crypto.subtle.digest("SHA-256", new TextEncoder().encode(input));
|
|
2952
|
-
return Array.from(new Uint8Array(digest)).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
2953
|
-
}
|
|
2954
|
-
async function verify402IndexDomain(domainOrUrl) {
|
|
2955
|
-
const domain = hostOf(domainOrUrl);
|
|
2956
|
-
try {
|
|
2957
|
-
const res = await fetch(INDEX402_VERIFY, {
|
|
2958
|
-
method: "POST",
|
|
2959
|
-
headers: clientHeaders({ "content-type": "application/json", accept: "application/json" }),
|
|
2960
|
-
body: JSON.stringify({ domain })
|
|
2961
|
-
});
|
|
2962
|
-
const body = await res.json().catch(() => ({}));
|
|
2963
|
-
if (!res.ok) {
|
|
2964
|
-
return { ok: false, domain, httpStatus: res.status, detail: pickString(body, "error", "detail", "message") ?? `402 Index verify returned HTTP ${res.status}.` };
|
|
2965
|
-
}
|
|
2966
|
-
return {
|
|
2967
|
-
ok: true,
|
|
2968
|
-
domain,
|
|
2969
|
-
httpStatus: res.status,
|
|
2970
|
-
...optionalString("status", pickString(body, "status")),
|
|
2971
|
-
...typeof body.services_count === "number" ? { servicesCount: body.services_count } : {}
|
|
2972
|
-
};
|
|
2973
|
-
} catch (err) {
|
|
2974
|
-
return { ok: false, domain, detail: errMsg(err) };
|
|
2975
|
-
}
|
|
2976
|
-
}
|
|
2977
|
-
async function readSiwxInfo(res) {
|
|
2978
|
-
try {
|
|
2979
|
-
const body = await res.json();
|
|
2980
|
-
const ext = body.extensions;
|
|
2981
|
-
const siwx = ext?.["sign-in-with-x"];
|
|
2982
|
-
const info = siwx?.info ?? siwx;
|
|
2983
|
-
if (info && info.chainId == null && Array.isArray(siwx?.supportedChains)) {
|
|
2984
|
-
const evm = siwx.supportedChains.find(
|
|
2985
|
-
(c) => typeof c?.chainId === "string" && c.chainId.startsWith("eip155:")
|
|
2986
|
-
);
|
|
2987
|
-
if (evm && typeof evm.chainId === "string") info.chainId = evm.chainId;
|
|
2988
|
-
}
|
|
2989
|
-
if (info && typeof info.domain === "string" && info.domain.length > 0 && typeof info.nonce === "string" && info.nonce.length > 0 && typeof info.uri === "string" && info.uri.length > 0) {
|
|
2990
|
-
return info;
|
|
2991
|
-
}
|
|
2992
|
-
return null;
|
|
2993
|
-
} catch {
|
|
2994
|
-
return null;
|
|
2995
|
-
}
|
|
2996
|
-
}
|
|
2997
|
-
function formatSiweMessage(info, address) {
|
|
2998
|
-
const chainId = info.chainId ? caip2ToChainId(info.chainId) : 1;
|
|
2999
|
-
const statement = info.statement && info.statement.trim() ? info.statement : void 0;
|
|
3000
|
-
const lines = [
|
|
3001
|
-
`${info.domain} wants you to sign in with your Ethereum account:`,
|
|
3002
|
-
address,
|
|
3003
|
-
"",
|
|
3004
|
-
...statement ? [statement, ""] : [""],
|
|
3005
|
-
`URI: ${info.uri}`,
|
|
3006
|
-
"Version: 1",
|
|
3007
|
-
`Chain ID: ${chainId}`,
|
|
3008
|
-
`Nonce: ${info.nonce}`,
|
|
3009
|
-
`Issued At: ${info.issuedAt}`,
|
|
3010
|
-
...info.expirationTime ? [`Expiration Time: ${info.expirationTime}`] : []
|
|
3011
|
-
];
|
|
3012
|
-
return lines.join("\n");
|
|
3013
|
-
}
|
|
3014
|
-
function caip2ToChainId(caip2) {
|
|
3015
|
-
const m = /^eip155:(\d+)$/.exec(caip2);
|
|
3016
|
-
const n = m ? Number(m[1]) : Number(caip2);
|
|
3017
|
-
return Number.isSafeInteger(n) && n > 0 ? n : 1;
|
|
3018
|
-
}
|
|
3019
|
-
function mapRails(accepts) {
|
|
3020
|
-
if (!Array.isArray(accepts)) return [];
|
|
3021
|
-
const out = [];
|
|
3022
|
-
for (const raw of accepts) {
|
|
3023
|
-
if (!raw || typeof raw !== "object") continue;
|
|
3024
|
-
const a = raw;
|
|
3025
|
-
const network = pickString(a, "network");
|
|
3026
|
-
if (!network) continue;
|
|
3027
|
-
const extra = a.extra && typeof a.extra === "object" ? a.extra : {};
|
|
3028
|
-
out.push({
|
|
3029
|
-
scheme: pickString(a, "scheme") ?? "exact",
|
|
3030
|
-
network,
|
|
3031
|
-
...optionalString("asset", pickString(a, "asset")),
|
|
3032
|
-
...optionalString("amount", pickString(a, "amount", "maxAmountRequired")),
|
|
3033
|
-
...optionalString("payTo", pickString(a, "payTo")),
|
|
3034
|
-
...optionalString("symbol", pickString(extra, "symbol"))
|
|
3035
|
-
});
|
|
3036
|
-
}
|
|
3037
|
-
return out;
|
|
3038
|
-
}
|
|
3039
|
-
function matchesQuery(r, query) {
|
|
3040
|
-
const haystack = [r.name, r.description, r.category, (r.tags ?? []).join(" "), r.resource].filter(Boolean).join(" ").toLowerCase();
|
|
3041
|
-
if (haystack.includes(query.toLowerCase())) return true;
|
|
3042
|
-
const qTokens = tokenize(query);
|
|
3043
|
-
const hayTokens = new Set(tokenize(haystack));
|
|
3044
|
-
return qTokens.some((t) => hayTokens.has(t));
|
|
3045
|
-
}
|
|
3046
|
-
function pickStringArray(o, ...keys) {
|
|
3047
|
-
for (const k of keys) {
|
|
3048
|
-
const v = o[k];
|
|
3049
|
-
if (Array.isArray(v)) {
|
|
3050
|
-
const arr = v.filter((x) => typeof x === "string" && x.length > 0);
|
|
3051
|
-
if (arr.length) return arr;
|
|
3052
|
-
} else if (typeof v === "string" && v.trim()) {
|
|
3053
|
-
const arr = v.split(/[,\s]+/).filter((x) => x.length > 0);
|
|
3054
|
-
if (arr.length) return arr;
|
|
3055
|
-
}
|
|
3056
|
-
}
|
|
3057
|
-
return void 0;
|
|
3058
|
-
}
|
|
3059
|
-
function pickString(o, ...keys) {
|
|
3060
|
-
for (const k of keys) {
|
|
3061
|
-
const v = o[k];
|
|
3062
|
-
if (typeof v === "string" && v.length > 0) return v;
|
|
3063
|
-
}
|
|
3064
|
-
return void 0;
|
|
3065
|
-
}
|
|
3066
|
-
function pickNumber(o, ...keys) {
|
|
3067
|
-
for (const k of keys) {
|
|
3068
|
-
const v = o[k];
|
|
3069
|
-
if (typeof v === "number" && Number.isFinite(v)) return v;
|
|
3070
|
-
if (typeof v === "string" && /^\d+(\.\d+)?$/.test(v.trim())) {
|
|
3071
|
-
const n = Number(v.trim());
|
|
3072
|
-
if (Number.isFinite(n)) return n;
|
|
3073
|
-
}
|
|
3074
|
-
}
|
|
3075
|
-
return void 0;
|
|
3076
|
-
}
|
|
3077
|
-
function optionalString(field, value) {
|
|
3078
|
-
return value !== void 0 ? { [field]: value } : {};
|
|
3079
|
-
}
|
|
3080
|
-
function firstArray(o, ...keys) {
|
|
3081
|
-
for (const k of keys) {
|
|
3082
|
-
if (Array.isArray(o[k])) return o[k];
|
|
3083
|
-
}
|
|
3084
|
-
return Array.isArray(o) ? o : [];
|
|
3085
|
-
}
|
|
3086
|
-
function hostOf(url) {
|
|
3087
|
-
try {
|
|
3088
|
-
const withScheme = /^[a-z][a-z0-9+.-]*:\/\//i.test(url) ? url : `https://${url}`;
|
|
3089
|
-
return new URL(withScheme).hostname || url;
|
|
3090
|
-
} catch {
|
|
3091
|
-
return url;
|
|
3092
|
-
}
|
|
3093
|
-
}
|
|
3094
|
-
function errMsg(err) {
|
|
3095
|
-
return err instanceof Error ? err.message : String(err);
|
|
3096
|
-
}
|
|
3097
|
-
var REGISTER_ATTRIBUTION = "\xB7 Built with @piprail/sdk";
|
|
3098
|
-
function appendAttribution(description) {
|
|
3099
|
-
if (!description) return description;
|
|
3100
|
-
if (/piprail/i.test(description)) return description;
|
|
3101
|
-
const next = `${description.trimEnd()} ${REGISTER_ATTRIBUTION}`;
|
|
3102
|
-
return next.length <= 500 ? next : description;
|
|
3103
|
-
}
|
|
3104
|
-
function appendKeywords(description, tags) {
|
|
3105
|
-
const clean = (tags ?? []).map((t) => t.trim()).filter((t) => t.length > 0);
|
|
3106
|
-
if (clean.length === 0) return description;
|
|
3107
|
-
const have = (description ?? "").toLowerCase();
|
|
3108
|
-
const fresh = [...new Set(clean.filter((t) => !have.includes(t.toLowerCase())))];
|
|
3109
|
-
if (fresh.length === 0) return description;
|
|
3110
|
-
const tail = `Keywords: ${fresh.join(", ")}`;
|
|
3111
|
-
if (!description) return tail;
|
|
3112
|
-
const next = `${description.trimEnd()} \xB7 ${tail}`;
|
|
3113
|
-
return next.length <= 500 ? next : description;
|
|
3114
|
-
}
|
|
3115
|
-
function encodeBase642(str) {
|
|
3116
|
-
if (typeof Buffer !== "undefined") return Buffer.from(str, "utf8").toString("base64");
|
|
3117
|
-
if (typeof btoa === "function" && typeof TextEncoder !== "undefined") {
|
|
3118
|
-
const bytes = new TextEncoder().encode(str);
|
|
3119
|
-
let binary = "";
|
|
3120
|
-
for (let i = 0; i < bytes.length; i++) binary += String.fromCharCode(bytes[i]);
|
|
3121
|
-
return btoa(binary);
|
|
3122
|
-
}
|
|
3123
|
-
throw new Error("No base64 encoder available in this runtime.");
|
|
3124
|
-
}
|
|
3125
|
-
|
|
3126
2269
|
// src/policy.ts
|
|
3127
2270
|
var DENOM_PRECISION = MAX_DECIMALS;
|
|
3128
2271
|
var BUILTIN_DENOMS = {
|
|
@@ -4086,7 +3229,7 @@ var PipRailClient = class {
|
|
|
4086
3229
|
* - Results are cross-scheme (mostly the mainstream `exact` scheme); `fetch()` pays
|
|
4087
3230
|
* `onchain-proof` rails by default, and standard `exact` rails too once you opt in
|
|
4088
3231
|
* with `schemes: ['onchain-proof', 'exact']` (EVM EIP-3009/Permit2 + Solana SVM + Algorand
|
|
4089
|
-
* + Aptos + NEAR).
|
|
3232
|
+
* + Aptos + NEAR + XRPL native XRP).
|
|
4090
3233
|
*/
|
|
4091
3234
|
async discover(opts = {}) {
|
|
4092
3235
|
const found = await searchOpenIndexes({
|
|
@@ -4261,7 +3404,7 @@ var PipRailClient = class {
|
|
|
4261
3404
|
return this.payUptoRail(net, wallet, accept, url, init, quote);
|
|
4262
3405
|
}
|
|
4263
3406
|
if (accept.scheme === "exact") {
|
|
4264
|
-
return this.payExactRail(net, wallet, accept, url, init, quote);
|
|
3407
|
+
return this.payExactRail(net, wallet, accept, url, init, quote, challenge.x402Version);
|
|
4265
3408
|
}
|
|
4266
3409
|
if (accept.scheme !== "onchain-proof") {
|
|
4267
3410
|
throw new UnsupportedSchemeError(
|
|
@@ -4347,15 +3490,35 @@ var PipRailClient = class {
|
|
|
4347
3490
|
if (schemes.includes("exact")) {
|
|
4348
3491
|
out.push(
|
|
4349
3492
|
...challenge.accepts.filter(
|
|
4350
|
-
(a) => a.scheme === "exact" && this.supportsNetwork(net, a.network) && typeof net.payExact === "function" &&
|
|
4351
|
-
|
|
4352
|
-
|
|
4353
|
-
|
|
4354
|
-
|
|
4355
|
-
|
|
4356
|
-
|
|
4357
|
-
|
|
4358
|
-
|
|
3493
|
+
(a) => a.scheme === "exact" && this.supportsNetwork(net, a.network) && typeof net.payExact === "function" && /*
|
|
3494
|
+
* Can this family sign an `exact` payment for THIS asset?
|
|
3495
|
+
*
|
|
3496
|
+
* The default — for every family that doesn't say otherwise — is "any recognised token
|
|
3497
|
+
* yes, the native coin no". `exact` is an EIP-3009/Permit2-style signed-authorization
|
|
3498
|
+
* scheme a native coin can't carry, and `describeAsset('native')` IS non-null
|
|
3499
|
+
* (onchain-proof needs it), so without the rule a 402 advertising a native exact rail
|
|
3500
|
+
* would gather, plan `payable`, even win autoRoute — then throw at pay time.
|
|
3501
|
+
*
|
|
3502
|
+
* XRPL is the first family to overturn it, in BOTH directions. There an `exact` payment
|
|
3503
|
+
* is simply a fully signed `Payment`, so native XRP is the most natural thing to send —
|
|
3504
|
+
* 863 of its 1,732 live rails are priced in XRP. Its ISSUED currencies are excluded
|
|
3505
|
+
* instead: they state a decimal `value` on the wire while the spend policy caps in base
|
|
3506
|
+
* units, so pricing one as base units would let a 12-RLUSD rail slip under any cap.
|
|
3507
|
+
* A driver that declares `exactPayableAsset` replaces this rule for all of its assets.
|
|
3508
|
+
*/
|
|
3509
|
+
(net.exactPayableAsset ? net.exactPayableAsset(a.asset) : a.asset !== "native") && /*
|
|
3510
|
+
* The rail's transfer method must be one a driver can sign — but an ABSENT method is
|
|
3511
|
+
* not an unknown one. `scheme_exact_evm.md`: "If no `assetTransferMethod` is specified
|
|
3512
|
+
* in `PaymentRequired.extra`, clients should default to `eip3009`", and the SVM /
|
|
3513
|
+
* Algorand / Aptos / NEAR / Hedera schemes never define the key at all. This predicate
|
|
3514
|
+
* previously REQUIRED the key, which rejected 91% of the deployed x402 web — every
|
|
3515
|
+
* Solana rail, every Arbitrum rail, 85% of Base — while the pay path had always
|
|
3516
|
+
* handled its absence correctly (the EVM driver defaults to eip3009 and re-derives the
|
|
3517
|
+
* EIP-712 domain on-chain). `isSettleableExactMethod` keeps the real guard: a rail that
|
|
3518
|
+
* NAMES a method we don't implement (the spec's `erc7710`) is still skipped, because
|
|
3519
|
+
* signing an EIP-3009 authorization for it would just be rejected by its facilitator.
|
|
3520
|
+
*/
|
|
3521
|
+
isSettleableExactMethod(a) && net.describeAsset(a.asset) != null && // a foreign rail's maxTimeoutSeconds must be a usable positive integer, or
|
|
4359
3522
|
// signing it would build a NaN/garbage validBefore — drop it silently
|
|
4360
3523
|
// (symmetric with an unrecognised token) rather than leak a raw SyntaxError.
|
|
4361
3524
|
Number.isInteger(a.maxTimeoutSeconds) && a.maxTimeoutSeconds > 0
|
|
@@ -4472,6 +3635,14 @@ var PipRailClient = class {
|
|
|
4472
3635
|
accept,
|
|
4473
3636
|
quote,
|
|
4474
3637
|
cost,
|
|
3638
|
+
// Surface the transfer method we INFERRED, not just the one the rail named — an absent
|
|
3639
|
+
// marker means the scheme's default, and saying so is how an agent (or a maintainer) sees
|
|
3640
|
+
// why a domain-only rail is payable and gasless. The default is PER FAMILY: a Solana rail
|
|
3641
|
+
// naming nothing means `svm`, never `eip3009`.
|
|
3642
|
+
...accept.scheme === "exact" ? {
|
|
3643
|
+
method: accept.extra?.assetTransferMethod ? exactTransferMethod(accept) : `${exactTransferMethod(accept, net.family)} (default)`
|
|
3644
|
+
} : {},
|
|
3645
|
+
...accept.scheme === "upto" ? { method: "permit2-upto" } : {},
|
|
4475
3646
|
state,
|
|
4476
3647
|
blockers,
|
|
4477
3648
|
warnings,
|
|
@@ -4513,7 +3684,7 @@ var PipRailClient = class {
|
|
|
4513
3684
|
const symbol = described?.symbol ?? accept.extra?.symbol;
|
|
4514
3685
|
const amountFormatted = formatUnits(amountBase, decimals);
|
|
4515
3686
|
const intent = {
|
|
4516
|
-
host:
|
|
3687
|
+
host: hostOf(url),
|
|
4517
3688
|
chain: this.opts.chain,
|
|
4518
3689
|
network: accept.network,
|
|
4519
3690
|
asset: accept.asset,
|
|
@@ -4654,7 +3825,7 @@ var PipRailClient = class {
|
|
|
4654
3825
|
}
|
|
4655
3826
|
const record = {
|
|
4656
3827
|
url: quote.url,
|
|
4657
|
-
host:
|
|
3828
|
+
host: hostOf(quote.url),
|
|
4658
3829
|
network: quote.network,
|
|
4659
3830
|
asset: quote.asset,
|
|
4660
3831
|
amountBase,
|
|
@@ -4838,7 +4009,7 @@ var PipRailClient = class {
|
|
|
4838
4009
|
* • a 200 whose SettleResponse says `success:false` → a rejection, NEVER a spend;
|
|
4839
4010
|
* • the spend is recorded EXACTLY ONCE, on an affirmative settlement only.
|
|
4840
4011
|
*/
|
|
4841
|
-
async payExactRail(net, wallet, accept, url, init, quote) {
|
|
4012
|
+
async payExactRail(net, wallet, accept, url, init, quote, x402Version = 2) {
|
|
4842
4013
|
if (!net.payExact) {
|
|
4843
4014
|
throw new UnsupportedSchemeError(
|
|
4844
4015
|
`the ${net.family} family can't pay a standard 'exact' rail (supported on EVM, Solana, Algorand, Aptos + NEAR today).`
|
|
@@ -4847,7 +4018,18 @@ var PipRailClient = class {
|
|
|
4847
4018
|
throwIfAborted(init?.signal);
|
|
4848
4019
|
const { payload, accepted, payerFrom, nonce } = await net.payExact(wallet, accept);
|
|
4849
4020
|
const headers = new Headers(init?.headers);
|
|
4850
|
-
|
|
4021
|
+
if (x402Version === 1) {
|
|
4022
|
+
headers.set(
|
|
4023
|
+
HEADER_SIGNATURE_V1,
|
|
4024
|
+
buildV1PaymentHeader({
|
|
4025
|
+
scheme: accepted.scheme,
|
|
4026
|
+
network: accept.wireNetwork ?? accepted.network,
|
|
4027
|
+
payload
|
|
4028
|
+
})
|
|
4029
|
+
);
|
|
4030
|
+
} else {
|
|
4031
|
+
headers.set(HEADER_SIGNATURE, buildExactSignatureHeader({ accepted, payload }));
|
|
4032
|
+
}
|
|
4851
4033
|
const rejectDefinitive = (why2) => {
|
|
4852
4034
|
this.safeEmit({ kind: "payment-failed", reason: `exact: facilitator rejected nonce=${nonce} (${why2})`, code: why2 });
|
|
4853
4035
|
throw new MaxRetriesExceededError(
|
|
@@ -4874,7 +4056,7 @@ var PipRailClient = class {
|
|
|
4874
4056
|
response = await fetch(url, { ...init ?? {}, headers, signal });
|
|
4875
4057
|
} catch (err) {
|
|
4876
4058
|
throw new PaymentTimeoutError(
|
|
4877
|
-
`exact: no response after submitting the authorization (nonce=${nonce}) to ${
|
|
4059
|
+
`exact: no response after submitting the authorization (nonce=${nonce}) to ${hostOf(url)}. The facilitator may have already settled it \u2014 verify on-chain via ${exactSettleCheckHint(net.family, payerFrom, nonce)} before re-presenting the SAME signed authorization; do NOT re-pay.`,
|
|
4878
4060
|
{ cause: err, ref: nonce }
|
|
4879
4061
|
);
|
|
4880
4062
|
} finally {
|
|
@@ -4958,7 +4140,7 @@ var PipRailClient = class {
|
|
|
4958
4140
|
response = await fetch(url, { ...init ?? {}, headers, signal });
|
|
4959
4141
|
} catch (err) {
|
|
4960
4142
|
throw new PaymentTimeoutError(
|
|
4961
|
-
`upto: no response after submitting the authorization (nonce=${nonce}) to ${
|
|
4143
|
+
`upto: no response after submitting the authorization (nonce=${nonce}) to ${hostOf(url)}. The merchant may have already settled it \u2014 verify on-chain before re-presenting; do NOT re-pay.`,
|
|
4962
4144
|
{ cause: err, ref: nonce }
|
|
4963
4145
|
);
|
|
4964
4146
|
} finally {
|
|
@@ -5132,7 +4314,7 @@ function reasonCodeForPolicy(code) {
|
|
|
5132
4314
|
return "POLICY";
|
|
5133
4315
|
}
|
|
5134
4316
|
}
|
|
5135
|
-
function
|
|
4317
|
+
function hostOf(url) {
|
|
5136
4318
|
try {
|
|
5137
4319
|
return new URL(url).hostname;
|
|
5138
4320
|
} catch {
|
|
@@ -5586,6 +4768,9 @@ A 402 may offer up to three rails; you don't choose per payment \u2014 the clien
|
|
|
5586
4768
|
(e.g. PayAI) \u2014 broadcasts it, so you pay ZERO gas (you need only the token, no native coin). It
|
|
5587
4769
|
works on EVM, Solana, Algorand, Aptos + NEAR, and the on-chain method (EIP-3009 / Permit2 / SVM /
|
|
5588
4770
|
Algorand fee-pooled group / Aptos fee-payer / NEAR SignedDelegateAction) is picked automatically.
|
|
4771
|
+
XRPL also supports exact (native XRP), with ONE difference that matters to your budget: there the
|
|
4772
|
+
PAYER pays the network fee, because on the XRP Ledger the fee lives inside the signed transaction.
|
|
4773
|
+
So keep a little XRP for fees on that chain \u2014 everywhere else exact means you need no native coin.
|
|
5589
4774
|
- upto (the metered/variable x402 rail, opt-in, EVM): the amount you see is a MAXIMUM \u2014 you sign
|
|
5590
4775
|
a ceiling, the server meters real usage and settles the ACTUAL (<= the max). BUDGET AGAINST THE MAX:
|
|
5591
4776
|
the plan/policy treat the ceiling as the spend (a server may charge up to it), so a payable plan
|
|
@@ -6395,82 +5580,61 @@ var KNOWN_FACILITATORS = {
|
|
|
6395
5580
|
keyless: true,
|
|
6396
5581
|
schemes: ["exact"],
|
|
6397
5582
|
settles: ["eip3009"],
|
|
6398
|
-
note: "PayAI
|
|
5583
|
+
note: "PayAI: keyless, sponsors gas (Base USDC EIP-3009). Verified 2026-06-14 (/supported + live demo)."
|
|
6399
5584
|
},
|
|
6400
5585
|
{
|
|
6401
5586
|
url: "https://facilitator.xpay.sh",
|
|
6402
5587
|
keyless: true,
|
|
6403
5588
|
schemes: ["exact"],
|
|
6404
5589
|
settles: ["eip3009"],
|
|
6405
|
-
note: "xpay
|
|
5590
|
+
note: "xpay: keyless, zero-fee, sponsors gas. LIVE-settled on Base 2026-06-15 (tx 0x2273d5\u2026)."
|
|
6406
5591
|
},
|
|
6407
5592
|
{
|
|
6408
5593
|
url: "https://facilitator.ultravioletadao.xyz",
|
|
6409
5594
|
keyless: true,
|
|
6410
5595
|
schemes: ["exact"],
|
|
6411
5596
|
settles: ["eip3009"],
|
|
6412
|
-
note: "Ultravioleta DAO
|
|
5597
|
+
note: "Ultravioleta DAO: keyless, 100% gas-sponsored (Base USDC EIP-3009). LIVE-settled on Base 2026-06-17 (tx 0x58a69042a4129be649c5642456752ede95a5ff921daddfd30560ae70ae5907ff). 2nd UVD validation chain (after HyperEVM)."
|
|
6413
5598
|
},
|
|
6414
5599
|
{
|
|
6415
5600
|
url: "https://x402.dexter.cash",
|
|
6416
5601
|
keyless: true,
|
|
6417
5602
|
schemes: ["exact"],
|
|
6418
5603
|
settles: ["eip3009"],
|
|
6419
|
-
note: "Dexter
|
|
6420
|
-
},
|
|
6421
|
-
{
|
|
6422
|
-
url: "https://facilitator.corbits.dev",
|
|
6423
|
-
keyless: true,
|
|
6424
|
-
schemes: ["exact"],
|
|
6425
|
-
settles: ["eip3009"],
|
|
6426
|
-
note: "Corbits (Faremeter) \u2014 keyless, sponsors gas (Base USDC EIP-3009). LIVE-settled on Base 2026-06-17 (tx 0x2e41c581af023100429ada81f1371bef82d41dd577ed438d72ddc18676d4213d). Also seeded on Monad + Solana."
|
|
5604
|
+
note: "Dexter: keyless, gas-sponsored (Base USDC EIP-3009). LIVE-settled on Base 2026-06-17 (tx 0xdf030e4d5bf41a88c5a3bfe73bb433dfbb90b058d3b8ded63b68e026eedb9de8). Note: ~$0.001 dynamic floor on Base."
|
|
6427
5605
|
},
|
|
6428
5606
|
{
|
|
6429
5607
|
url: "https://facilitator.goplausible.xyz",
|
|
6430
5608
|
keyless: true,
|
|
6431
5609
|
schemes: ["exact"],
|
|
6432
5610
|
settles: ["eip3009"],
|
|
6433
|
-
note: "GoPlausible
|
|
5611
|
+
note: "GoPlausible: keyless, sponsors gas (Base USDC EIP-3009). LIVE-settled on Base 2026-06-17 (tx 0x9bcbc1f01fe1fd1aed2a79e5582555164cc4185e9800189df378a6b46eb9c59e). 2nd GoPlausible validation chain (after Algorand)."
|
|
6434
5612
|
},
|
|
6435
5613
|
{
|
|
6436
5614
|
url: "https://facilitator.cascade.fyi",
|
|
6437
5615
|
keyless: true,
|
|
6438
5616
|
schemes: ["exact"],
|
|
6439
5617
|
settles: ["eip3009"],
|
|
6440
|
-
note: "Cascade
|
|
6441
|
-
},
|
|
6442
|
-
{
|
|
6443
|
-
url: "https://facilitator.bitcoinsapi.com",
|
|
6444
|
-
keyless: true,
|
|
6445
|
-
schemes: ["exact"],
|
|
6446
|
-
settles: ["eip3009"],
|
|
6447
|
-
note: "Satoshi (bitcoinsapi) \u2014 keyless, sponsors gas (Base USDC EIP-3009). LIVE-settled on Base 2026-06-18 (tx 0xbb2b6c354b12c6d07cce91e2b337e38327d4b0833bbd1dfbeda3ad495b67b819)."
|
|
5618
|
+
note: "Cascade: keyless, sponsors gas (Base USDC EIP-3009). LIVE-settled on Base 2026-06-18 (tx 0x2e784725f3c66e170720cc8df43a9248f02ad80914fcbe05dadbdbe411c3b52b)."
|
|
6448
5619
|
}
|
|
6449
5620
|
],
|
|
6450
5621
|
// Monad (eip155:143). Corbits + Ultravioleta DAO each keyless-settle the EVM EIP-3009 exact rail
|
|
6451
5622
|
// (Monad's native Circle USDC), buyer paid zero gas — real LIVE settles, not just /supported reads.
|
|
6452
5623
|
// Makes `exact: true` zero-config gasless on Monad.
|
|
6453
5624
|
"eip155:143": [
|
|
6454
|
-
{
|
|
6455
|
-
url: "https://facilitator.corbits.dev",
|
|
6456
|
-
keyless: true,
|
|
6457
|
-
schemes: ["exact"],
|
|
6458
|
-
settles: ["eip3009"],
|
|
6459
|
-
note: "Corbits (Faremeter) \u2014 keyless, sponsors gas (Monad native USDC EIP-3009). LIVE-settled on Monad 2026-06-17 (tx 0x7797be27ce22c17f7433a0389bd22d46e338899b1faac505fffd068174428ae6)."
|
|
6460
|
-
},
|
|
6461
5625
|
{
|
|
6462
5626
|
url: "https://facilitator.ultravioletadao.xyz",
|
|
6463
5627
|
keyless: true,
|
|
6464
5628
|
schemes: ["exact"],
|
|
6465
5629
|
settles: ["eip3009"],
|
|
6466
|
-
note: "Ultravioleta DAO
|
|
5630
|
+
note: "Ultravioleta DAO: keyless, 100% gas-sponsored (Monad native USDC EIP-3009). LIVE-settled on Monad 2026-06-17 (tx 0xb107576effbaceb5586c07a9ddc996ef2b6d455f1858314995ef83a7c6e64d11). 3rd UVD validation chain."
|
|
6467
5631
|
},
|
|
6468
5632
|
{
|
|
6469
5633
|
url: "https://facilitator.pieverse.io",
|
|
6470
5634
|
keyless: true,
|
|
6471
5635
|
schemes: ["exact"],
|
|
6472
5636
|
settles: ["eip3009"],
|
|
6473
|
-
note: "Pieverse
|
|
5637
|
+
note: "Pieverse: keyless, sponsors gas (Monad USDC EIP-3009). LIVE-settled on Monad 2026-06-17 (tx 0x00cfeb93876e5ef57dcb002510038b7304913233ca286d7ab33c72a8b119eb0d)."
|
|
6474
5638
|
}
|
|
6475
5639
|
],
|
|
6476
5640
|
// BNB Chain (eip155:56). Dexter + Pieverse keyless-settle the EVM EIP-3009 exact rail for BNB's
|
|
@@ -6484,14 +5648,14 @@ var KNOWN_FACILITATORS = {
|
|
|
6484
5648
|
keyless: true,
|
|
6485
5649
|
schemes: ["exact"],
|
|
6486
5650
|
settles: ["eip3009"],
|
|
6487
|
-
note: "Dexter
|
|
5651
|
+
note: "Dexter: keyless, gas-sponsored. BNB EIP-3009 tokens FDUSD/USD1/U (Binance-Peg USDC/USDT are Permit2 \u2192 not facilitator-settleable); ~$0.003 dynamic floor. LIVE-settled on BNB 2026-06-17 with FDUSD (tx 0x6d9eb4e4939f3f3c74cb19424cc7822d66ec8ed5c5c7c330d9f88a5f9ad59e9e); accepts U (verify confirmed 2026-06-21)."
|
|
6488
5652
|
},
|
|
6489
5653
|
{
|
|
6490
5654
|
url: "https://facilitator.pieverse.io",
|
|
6491
5655
|
keyless: true,
|
|
6492
5656
|
schemes: ["exact"],
|
|
6493
5657
|
settles: ["eip3009"],
|
|
6494
|
-
note: "Pieverse
|
|
5658
|
+
note: "Pieverse: keyless, sponsors gas. BNB EIP-3009 tokens FDUSD/USD1/U (same Binance-Peg caveat as Dexter). LIVE-settled on BNB with FDUSD 2026-06-17 (tx 0xb9c76affc45bd07a51559efd813ca71516fc30625478724476c2cf42fc2203d3) AND with the U / United Stables token 2026-06-21 (tx 0x2b3b8c51ae81df441551301c44a64652c84c796af3b9d03ec58ea38f1cb013d5, buyer 0 BNB). A 2nd keyless BNB facilitator (failover for Dexter)."
|
|
6495
5659
|
}
|
|
6496
5660
|
],
|
|
6497
5661
|
// HyperEVM (eip155:999). Ultravioleta DAO keyless-settles the EVM EIP-3009 exact rail (HyperEVM's
|
|
@@ -6504,7 +5668,7 @@ var KNOWN_FACILITATORS = {
|
|
|
6504
5668
|
keyless: true,
|
|
6505
5669
|
schemes: ["exact"],
|
|
6506
5670
|
settles: ["eip3009"],
|
|
6507
|
-
note: "Ultravioleta DAO
|
|
5671
|
+
note: "Ultravioleta DAO: keyless, 100% gas-sponsored (HyperEVM native USDC EIP-3009). LIVE-settled on HyperEVM 2026-06-17 (tx 0x56af8148a92a291f0ce362e250919f7742074e5464ac0f315ad68abaec93bd0a)."
|
|
6508
5672
|
}
|
|
6509
5673
|
],
|
|
6510
5674
|
// ── gasless-extension (2026-06-18): 7 more EVM mainnets, each LIVE-settled by us — a real EIP-3009
|
|
@@ -6521,7 +5685,7 @@ var KNOWN_FACILITATORS = {
|
|
|
6521
5685
|
keyless: true,
|
|
6522
5686
|
schemes: ["exact"],
|
|
6523
5687
|
settles: ["eip3009"],
|
|
6524
|
-
note: "Ultravioleta DAO
|
|
5688
|
+
note: "Ultravioleta DAO: keyless, 100% gas-sponsored (Ethereum native USDC EIP-3009; no settlement floor). LIVE-settled on Ethereum mainnet 2026-06-18 (tx 0x7fcc3cafdf43c52888f0117cde633eff35371f832dfb8dbd84e6fd7704ae5cfc)."
|
|
6525
5689
|
}
|
|
6526
5690
|
],
|
|
6527
5691
|
// Polygon PoS (eip155:137) — FIVE keyless facilitators (the broadest after Base), all live-settled.
|
|
@@ -6531,35 +5695,28 @@ var KNOWN_FACILITATORS = {
|
|
|
6531
5695
|
keyless: true,
|
|
6532
5696
|
schemes: ["exact"],
|
|
6533
5697
|
settles: ["eip3009"],
|
|
6534
|
-
note: "PayAI
|
|
5698
|
+
note: "PayAI: keyless, sponsors gas (Polygon native USDC EIP-3009). LIVE-settled on Polygon 2026-06-18 (tx 0xb37630871504618c4db35e8ef0edd3c99deac102b143b7e5eb738c03fb13a619)."
|
|
6535
5699
|
},
|
|
6536
5700
|
{
|
|
6537
5701
|
url: "https://x402.polygon.technology",
|
|
6538
5702
|
keyless: true,
|
|
6539
5703
|
schemes: ["exact"],
|
|
6540
5704
|
settles: ["eip3009"],
|
|
6541
|
-
note: "Polygon Labs (the official Polygon facilitator)
|
|
6542
|
-
},
|
|
6543
|
-
{
|
|
6544
|
-
url: "https://facilitator.corbits.dev",
|
|
6545
|
-
keyless: true,
|
|
6546
|
-
schemes: ["exact"],
|
|
6547
|
-
settles: ["eip3009"],
|
|
6548
|
-
note: "Corbits (Faremeter) \u2014 keyless, sponsors gas. LIVE-settled on Polygon 2026-06-18 (tx 0x2fadca2ee3cd7fcff32d015e8b06109de6b747d7cd0f80dcd8fb022b2d58d008)."
|
|
5705
|
+
note: "Polygon Labs (the official Polygon facilitator): keyless, sponsors gas. LIVE-settled on Polygon 2026-06-18 (tx 0x6a8ca60ea111959a61a85ad6c4f2ed99e192052ec7b9ffb59baa33691a86f419)."
|
|
6549
5706
|
},
|
|
6550
5707
|
{
|
|
6551
5708
|
url: "https://facilitator.ultravioletadao.xyz",
|
|
6552
5709
|
keyless: true,
|
|
6553
5710
|
schemes: ["exact"],
|
|
6554
5711
|
settles: ["eip3009"],
|
|
6555
|
-
note: "Ultravioleta DAO
|
|
5712
|
+
note: "Ultravioleta DAO: keyless, 100% gas-sponsored. LIVE-settled on Polygon 2026-06-18 (tx 0x0922cd78f3b7c35cc294cf0c0d9b7609e6596eb337be0d197fa5fc511eacba34)."
|
|
6556
5713
|
},
|
|
6557
5714
|
{
|
|
6558
5715
|
url: "https://x402.dexter.cash",
|
|
6559
5716
|
keyless: true,
|
|
6560
5717
|
schemes: ["exact"],
|
|
6561
5718
|
settles: ["eip3009"],
|
|
6562
|
-
note: "Dexter
|
|
5719
|
+
note: "Dexter: keyless, sponsors gas; ~$0.004 dynamic settlement floor (sub-floor \u2192 amount_too_low). LIVE-settled on Polygon 2026-06-18 at $0.005 (tx 0x4a7cfc96e4e2496652435c77b0021db4a459e7bcd97948c15e6bea09077c164b)."
|
|
6563
5720
|
}
|
|
6564
5721
|
],
|
|
6565
5722
|
// Arbitrum One (eip155:42161) — PayAI + UVD + Dexter.
|
|
@@ -6569,21 +5726,21 @@ var KNOWN_FACILITATORS = {
|
|
|
6569
5726
|
keyless: true,
|
|
6570
5727
|
schemes: ["exact"],
|
|
6571
5728
|
settles: ["eip3009"],
|
|
6572
|
-
note: "PayAI
|
|
5729
|
+
note: "PayAI: keyless, sponsors gas (Arbitrum native USDC EIP-3009). LIVE-settled on Arbitrum 2026-06-18 (tx 0x4c7fbfb37ef087bb9bc8872b1b2b0b83ea7ca4cf6b50bc883e51f9b85be61199)."
|
|
6573
5730
|
},
|
|
6574
5731
|
{
|
|
6575
5732
|
url: "https://facilitator.ultravioletadao.xyz",
|
|
6576
5733
|
keyless: true,
|
|
6577
5734
|
schemes: ["exact"],
|
|
6578
5735
|
settles: ["eip3009"],
|
|
6579
|
-
note: "Ultravioleta DAO
|
|
5736
|
+
note: "Ultravioleta DAO: keyless, 100% gas-sponsored. LIVE-settled on Arbitrum 2026-06-18 (tx 0xd1fa7e6ffbd59502bba5809ce181d7936749b93a45c8c2277b4f6d8638326dec)."
|
|
6580
5737
|
},
|
|
6581
5738
|
{
|
|
6582
5739
|
url: "https://x402.dexter.cash",
|
|
6583
5740
|
keyless: true,
|
|
6584
5741
|
schemes: ["exact"],
|
|
6585
5742
|
settles: ["eip3009"],
|
|
6586
|
-
note: "Dexter
|
|
5743
|
+
note: "Dexter: keyless, sponsors gas; ~$0.004 dynamic floor. LIVE-settled on Arbitrum 2026-06-18 at $0.005 (tx 0x0993d51b3859dfd7e8d5b2af709ce64f01ff34ed14bfef665dbb340e7373d599)."
|
|
6587
5744
|
}
|
|
6588
5745
|
],
|
|
6589
5746
|
// Optimism (eip155:10) — Dexter + UVD.
|
|
@@ -6593,14 +5750,14 @@ var KNOWN_FACILITATORS = {
|
|
|
6593
5750
|
keyless: true,
|
|
6594
5751
|
schemes: ["exact"],
|
|
6595
5752
|
settles: ["eip3009"],
|
|
6596
|
-
note: "Dexter
|
|
5753
|
+
note: "Dexter: keyless, sponsors gas; ~$0.004 dynamic floor. LIVE-settled on Optimism 2026-06-18 at $0.005 (tx 0x98b282a5dd698054eff4900ff8547170d4f7605b51140c55147fc5ae485f81da)."
|
|
6597
5754
|
},
|
|
6598
5755
|
{
|
|
6599
5756
|
url: "https://facilitator.ultravioletadao.xyz",
|
|
6600
5757
|
keyless: true,
|
|
6601
5758
|
schemes: ["exact"],
|
|
6602
5759
|
settles: ["eip3009"],
|
|
6603
|
-
note: "Ultravioleta DAO
|
|
5760
|
+
note: "Ultravioleta DAO: keyless, 100% gas-sponsored. LIVE-settled on Optimism 2026-06-18 (tx 0xdd91dfdf12bed2d196e37fa1dea9a0da71a97e3c39a0ec0ed114be6a9af22837)."
|
|
6604
5761
|
}
|
|
6605
5762
|
],
|
|
6606
5763
|
// Avalanche C-Chain (eip155:43114) — PayAI + Dexter. (UVD advertises it but contract_call_failed → unseeded.)
|
|
@@ -6610,14 +5767,14 @@ var KNOWN_FACILITATORS = {
|
|
|
6610
5767
|
keyless: true,
|
|
6611
5768
|
schemes: ["exact"],
|
|
6612
5769
|
settles: ["eip3009"],
|
|
6613
|
-
note: "PayAI
|
|
5770
|
+
note: "PayAI: keyless, sponsors gas (Avalanche native USDC EIP-3009). LIVE-settled on Avalanche 2026-06-18 (tx 0x6a1307bc48a157de236ea03440ea2cb6ad4f27e22dd9c89a4345b4c3edb270c7)."
|
|
6614
5771
|
},
|
|
6615
5772
|
{
|
|
6616
5773
|
url: "https://x402.dexter.cash",
|
|
6617
5774
|
keyless: true,
|
|
6618
5775
|
schemes: ["exact"],
|
|
6619
5776
|
settles: ["eip3009"],
|
|
6620
|
-
note: "Dexter
|
|
5777
|
+
note: "Dexter: keyless, sponsors gas (no floor hit at $0.001 here). LIVE-settled on Avalanche 2026-06-18 (tx 0xb2263e9a4ea3917eee6acabcb454d42a50264fdd69a0781ed8fcaec5590e264b)."
|
|
6621
5778
|
}
|
|
6622
5779
|
],
|
|
6623
5780
|
// Sei (eip155:1329) — PayAI (the only keyless facilitator that lists Sei).
|
|
@@ -6627,7 +5784,7 @@ var KNOWN_FACILITATORS = {
|
|
|
6627
5784
|
keyless: true,
|
|
6628
5785
|
schemes: ["exact"],
|
|
6629
5786
|
settles: ["eip3009"],
|
|
6630
|
-
note: "PayAI
|
|
5787
|
+
note: "PayAI: keyless, sponsors gas (Sei native USDC EIP-3009). LIVE-settled on Sei 2026-06-18 (tx 0xde63679b64749cb59625527e5c7682503c851d66b9b8b8ba217ed7b099461312)."
|
|
6631
5788
|
}
|
|
6632
5789
|
],
|
|
6633
5790
|
// Unichain (eip155:130) — UVD (the only keyless facilitator that lists Unichain).
|
|
@@ -6637,7 +5794,7 @@ var KNOWN_FACILITATORS = {
|
|
|
6637
5794
|
keyless: true,
|
|
6638
5795
|
schemes: ["exact"],
|
|
6639
5796
|
settles: ["eip3009"],
|
|
6640
|
-
note: "Ultravioleta DAO
|
|
5797
|
+
note: "Ultravioleta DAO: keyless, 100% gas-sponsored (Unichain native USDC EIP-3009). LIVE-settled on Unichain 2026-06-18 (tx 0xf8bf4a9a200f24159ac67c6315c30b194257999d7da21471b39d5f2cc32b2236)."
|
|
6641
5798
|
}
|
|
6642
5799
|
],
|
|
6643
5800
|
// Algorand (mainnet, CAIP-2 = full base64 genesis hash). GoPlausible keyless-settles the ratified
|
|
@@ -6653,7 +5810,7 @@ var KNOWN_FACILITATORS = {
|
|
|
6653
5810
|
keyless: true,
|
|
6654
5811
|
schemes: ["exact"],
|
|
6655
5812
|
settles: ["algorand"],
|
|
6656
|
-
note: "GoPlausible
|
|
5813
|
+
note: "GoPlausible: keyless, 100% gas-sponsored (Algorand USDCa, atomic-group fee pooling; both buyer AND merchant pay 0 ALGO). LIVE-settled on Algorand mainnet 2026-06-17 (tx PDVDVRFGJAG2K6AJ7L26OTSCSRL7AURVKEX4D4KHBAOLNSCYENXA). The only keyless Algorand x402 facilitator."
|
|
6657
5814
|
}
|
|
6658
5815
|
],
|
|
6659
5816
|
// Solana (mainnet-beta). Keyless fee-payer sponsors for the SVM exact rail, each LIVE-settled
|
|
@@ -6666,21 +5823,14 @@ var KNOWN_FACILITATORS = {
|
|
|
6666
5823
|
keyless: true,
|
|
6667
5824
|
schemes: ["exact"],
|
|
6668
5825
|
settles: ["svm"],
|
|
6669
|
-
note: "PayAI
|
|
5826
|
+
note: "PayAI: keyless fee-payer sponsor (Solana SPL SVM). LIVE-settled 2026-06-14 (tx 4dL8jRKH\u2026)."
|
|
6670
5827
|
},
|
|
6671
5828
|
{
|
|
6672
5829
|
url: "https://pay.openfacilitator.io",
|
|
6673
5830
|
keyless: true,
|
|
6674
5831
|
schemes: ["exact"],
|
|
6675
5832
|
settles: ["svm"],
|
|
6676
|
-
note: "OpenFacilitator
|
|
6677
|
-
},
|
|
6678
|
-
{
|
|
6679
|
-
url: "https://facilitator.corbits.dev",
|
|
6680
|
-
keyless: true,
|
|
6681
|
-
schemes: ["exact"],
|
|
6682
|
-
settles: ["svm"],
|
|
6683
|
-
note: "Corbits \u2014 keyless, Solana-first fee-payer sponsor. LIVE-settled on Solana 2026-06-15 (tx BCreYer\u2026)."
|
|
5833
|
+
note: "OpenFacilitator: keyless (no signup), fee-payer sponsor. LIVE-settled on Solana 2026-06-15 (tx 5BabDtX\u2026)."
|
|
6684
5834
|
}
|
|
6685
5835
|
]
|
|
6686
5836
|
// NEAR (near:mainnet) — DELIBERATELY UNSEEDED: no x402 facilitator settles NEAR yet.
|
|
@@ -6871,7 +6021,7 @@ function createPaymentGate(options) {
|
|
|
6871
6021
|
);
|
|
6872
6022
|
}
|
|
6873
6023
|
return {
|
|
6874
|
-
skipReason: `${net.network}:
|
|
6024
|
+
skipReason: `${net.network}: auto-selected Permit2, which a third-party facilitator can't settle \u2014 it would serve onchain-proof only here. Either this token isn't EIP-3009 (use USDC / EURC with the facilitator, or \`settle: 'self'\` to settle Permit2 yourself), OR the EIP-712 domain read failed on your RPC (transient): if you expected a gasless rail here, pass a reliable \`rpcUrl\` and retry.`
|
|
6875
6025
|
};
|
|
6876
6026
|
}
|
|
6877
6027
|
const mode = settle === "self" ? { kind: "self", relayer } : {
|
|
@@ -7198,8 +6348,8 @@ function createPaymentGate(options) {
|
|
|
7198
6348
|
maxTimeoutSeconds,
|
|
7199
6349
|
...s.symbol ? { symbol: s.symbol } : {}
|
|
7200
6350
|
};
|
|
7201
|
-
if (s.exact) accepts.push({ scheme: "exact", ...base2, ...railExtra(buildExactAccept(s).extra) });
|
|
7202
|
-
if (s.upto) accepts.push({ scheme: "upto", ...base2, ...railExtra(buildUptoAccept(s).extra) });
|
|
6351
|
+
if (s.exact) accepts.push({ scheme: "exact", ...base2, ...railExtra(buildExactAccept(s).extra ?? {}) });
|
|
6352
|
+
if (s.upto) accepts.push({ scheme: "upto", ...base2, ...railExtra(buildUptoAccept(s).extra ?? {}) });
|
|
7203
6353
|
accepts.push({ scheme: "onchain-proof", ...base2 });
|
|
7204
6354
|
}
|
|
7205
6355
|
return {
|
|
@@ -7212,7 +6362,7 @@ function createPaymentGate(options) {
|
|
|
7212
6362
|
async function verifyOnchainProof(sig) {
|
|
7213
6363
|
const specs = await ready();
|
|
7214
6364
|
const spec = specs.find(
|
|
7215
|
-
(s) => s.net.network === sig.accepted.network && s.asset === sig.accepted.asset
|
|
6365
|
+
(s) => normalizeNetwork(s.net.network) === normalizeNetwork(sig.accepted.network) && s.asset === sig.accepted.asset
|
|
7216
6366
|
);
|
|
7217
6367
|
if (!spec) {
|
|
7218
6368
|
return rejection(
|
|
@@ -7220,7 +6370,7 @@ function createPaymentGate(options) {
|
|
|
7220
6370
|
`Proof claims ${sig.accepted.asset} on ${sig.accepted.network}, which this resource doesn't accept (offered: ${specs.map((s) => `${s.asset}@${s.net.network}`).join(", ")}).`
|
|
7221
6371
|
);
|
|
7222
6372
|
}
|
|
7223
|
-
const ref = sig.payload.txHash;
|
|
6373
|
+
const ref = typeof sig.payload.txHash === "string" ? sig.payload.txHash.trim() : sig.payload.txHash;
|
|
7224
6374
|
if (await claimTx(ref)) return rejection("tx_already_used", `Proof ${ref} was already redeemed.`);
|
|
7225
6375
|
let result;
|
|
7226
6376
|
try {
|
|
@@ -7254,7 +6404,8 @@ function createPaymentGate(options) {
|
|
|
7254
6404
|
return rejection("transfer_not_found", "This resource offers no standard `exact` rail.");
|
|
7255
6405
|
}
|
|
7256
6406
|
const isCaip = exact.network.includes(":");
|
|
7257
|
-
|
|
6407
|
+
const wantExactNet = normalizeNetwork(exact.network);
|
|
6408
|
+
let candidates = isCaip ? exactSpecs.filter((s) => normalizeNetwork(s.net.network) === wantExactNet) : exactSpecs;
|
|
7258
6409
|
if (exact.asset) {
|
|
7259
6410
|
candidates = candidates.filter((s) => s.asset.toLowerCase() === exact.asset.toLowerCase());
|
|
7260
6411
|
}
|
|
@@ -7297,6 +6448,8 @@ function createPaymentGate(options) {
|
|
|
7297
6448
|
} catch {
|
|
7298
6449
|
nonce = exact.payload.signedDelegateAction;
|
|
7299
6450
|
}
|
|
6451
|
+
} else if ("signedTxBlob" in exact.payload) {
|
|
6452
|
+
nonce = exact.payload.signedTxBlob.trim().toUpperCase();
|
|
7300
6453
|
} else if ("permit2Authorization" in exact.payload) {
|
|
7301
6454
|
evmAuth = exact.payload.permit2Authorization;
|
|
7302
6455
|
nonce = evmAuth.nonce;
|
|
@@ -7314,9 +6467,9 @@ function createPaymentGate(options) {
|
|
|
7314
6467
|
if (mode.kind === "self") {
|
|
7315
6468
|
result = await spec.net.settleExactSelf({ relayer: mode.relayer, payload: exact.payload, accept });
|
|
7316
6469
|
} else {
|
|
7317
|
-
const ftMethod = accept.extra
|
|
6470
|
+
const ftMethod = accept.extra?.assetTransferMethod;
|
|
7318
6471
|
const needsFeePayer = ftMethod === "svm" || ftMethod === "algorand" || ftMethod === "aptos" || ftMethod === "near";
|
|
7319
|
-
if (needsFeePayer && !accept.extra
|
|
6472
|
+
if (needsFeePayer && !accept.extra?.feePayer) {
|
|
7320
6473
|
throw new SettlementError(
|
|
7321
6474
|
`exact settle: the ${ftMethod} facilitator rail is missing extra.feePayer (the gas sponsor) \u2014 cannot settle.`
|
|
7322
6475
|
);
|
|
@@ -7337,7 +6490,7 @@ function createPaymentGate(options) {
|
|
|
7337
6490
|
amount: accept.amount,
|
|
7338
6491
|
payTo: accept.payTo,
|
|
7339
6492
|
maxTimeoutSeconds: accept.maxTimeoutSeconds,
|
|
7340
|
-
extra: needsFeePayer ? { feePayer: accept.extra.feePayer } : { name: accept.extra
|
|
6493
|
+
extra: needsFeePayer ? { feePayer: accept.extra.feePayer } : { name: accept.extra?.name ?? "", version: accept.extra?.version ?? "" }
|
|
7341
6494
|
},
|
|
7342
6495
|
receipt: { network: accept.network, asset: accept.asset, payTo: accept.payTo, amount: accept.amount },
|
|
7343
6496
|
// The buyer address, for the receipt's `payer` fallback. EVM carries it in the
|
|
@@ -7385,7 +6538,8 @@ function createPaymentGate(options) {
|
|
|
7385
6538
|
return rejection("transfer_not_found", "This resource offers no standard `upto` (metered) rail.");
|
|
7386
6539
|
}
|
|
7387
6540
|
const isCaip = upto.network.includes(":");
|
|
7388
|
-
|
|
6541
|
+
const wantUptoNet = normalizeNetwork(upto.network);
|
|
6542
|
+
let candidates = isCaip ? uptoSpecs.filter((s) => normalizeNetwork(s.net.network) === wantUptoNet) : uptoSpecs;
|
|
7389
6543
|
if (upto.asset) {
|
|
7390
6544
|
candidates = candidates.filter((s) => s.asset.toLowerCase() === upto.asset.toLowerCase());
|
|
7391
6545
|
}
|
|
@@ -8130,6 +7284,7 @@ export {
|
|
|
8130
7284
|
BUILTIN_DENOMS,
|
|
8131
7285
|
CHAINS,
|
|
8132
7286
|
ConfirmationTimeoutError,
|
|
7287
|
+
DEFAULT_EXACT_TRANSFER_METHOD,
|
|
8133
7288
|
DENOM_PRECISION,
|
|
8134
7289
|
DIRECTORY_INFO,
|
|
8135
7290
|
EIP3009_TYPES,
|
|
@@ -8145,6 +7300,7 @@ export {
|
|
|
8145
7300
|
InsufficientFundsError,
|
|
8146
7301
|
InvalidConfigError,
|
|
8147
7302
|
InvalidEnvelopeError,
|
|
7303
|
+
KNOWN_EXACT_TRANSFER_METHODS,
|
|
8148
7304
|
KNOWN_FACILITATORS,
|
|
8149
7305
|
MCP_PAYMENT_META_KEY,
|
|
8150
7306
|
MCP_PAYMENT_RESPONSE_META_KEY,
|
|
@@ -8193,6 +7349,7 @@ export {
|
|
|
8193
7349
|
buildSelfDescription,
|
|
8194
7350
|
buildSignatureHeader,
|
|
8195
7351
|
buildUptoSignatureHeader,
|
|
7352
|
+
buildV1PaymentHeader,
|
|
8196
7353
|
buildWellKnownX402,
|
|
8197
7354
|
buildWellKnownX402Manifest,
|
|
8198
7355
|
buildX402DnsTxt,
|
|
@@ -8213,6 +7370,7 @@ export {
|
|
|
8213
7370
|
eip3009Abi,
|
|
8214
7371
|
encodeXPaymentHeader,
|
|
8215
7372
|
evaluatePolicy,
|
|
7373
|
+
exactTransferMethod,
|
|
8216
7374
|
explainDecline,
|
|
8217
7375
|
facilitatorCoverage,
|
|
8218
7376
|
fetchAcross,
|
|
@@ -8226,10 +7384,12 @@ export {
|
|
|
8226
7384
|
getDirectoryInfo,
|
|
8227
7385
|
isMcpPaymentRequired,
|
|
8228
7386
|
isPermit2ProxyChain,
|
|
7387
|
+
isSettleableExactMethod,
|
|
8229
7388
|
isUptoProxyChain,
|
|
8230
7389
|
knownFacilitatorsFor,
|
|
8231
7390
|
memorySpendStore,
|
|
8232
7391
|
normalizeNetwork,
|
|
7392
|
+
normalizeV1Challenge,
|
|
8233
7393
|
parseChallenge,
|
|
8234
7394
|
parseExactObject,
|
|
8235
7395
|
parseExactPaymentHeader,
|