@armory-sh/base 0.2.21-alpha.3.16 → 0.2.21-alpha.3.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/encoding/x402.d.ts +2 -6
- package/dist/fixtures/payloads.d.ts +1 -2
- package/dist/index.d.ts +7 -5
- package/dist/index.js +150 -134
- package/dist/payment-client.d.ts +24 -0
- package/dist/types/protocol.d.ts +0 -4
- package/dist/types/x402.d.ts +1 -37
- package/package.json +1 -1
- package/dist/types/v1.d.ts +0 -156
package/dist/encoding/x402.d.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Payment payloads are JSON-encoded for transport in HTTP headers.
|
|
5
5
|
* Matches the Coinbase x402 v2 SDK format.
|
|
6
6
|
*/
|
|
7
|
-
import type { PaymentPayload, X402Response,
|
|
7
|
+
import type { PaymentPayload, X402Response, PaymentRequirements, SettlementResponse } from "../types/x402";
|
|
8
8
|
/**
|
|
9
9
|
* Safe Base64 encode (URL-safe, no padding)
|
|
10
10
|
*/
|
|
@@ -16,7 +16,7 @@ export declare function safeBase64Decode(str: string): string;
|
|
|
16
16
|
/**
|
|
17
17
|
* Encode payment payload to JSON string
|
|
18
18
|
*/
|
|
19
|
-
export declare function encodePayment(payload: PaymentPayload
|
|
19
|
+
export declare function encodePayment(payload: PaymentPayload): string;
|
|
20
20
|
/**
|
|
21
21
|
* Decode payment payload from JSON string
|
|
22
22
|
*/
|
|
@@ -56,10 +56,6 @@ export declare function createPaymentRequiredHeaders(requirements: PaymentRequir
|
|
|
56
56
|
* Create settlement response headers (V2 format)
|
|
57
57
|
*/
|
|
58
58
|
export declare function createSettlementHeaders(settlement: SettlementResponse): Record<string, string>;
|
|
59
|
-
/**
|
|
60
|
-
* Type guard for legacy V2 payload (without x402Version)
|
|
61
|
-
*/
|
|
62
|
-
export declare function isLegacyV2(payload: unknown): payload is PaymentPayloadV2;
|
|
63
59
|
/**
|
|
64
60
|
* Decode settlement from headers (V2 only)
|
|
65
61
|
*/
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Mock Payment Payloads for Testing (V2 Only)
|
|
3
3
|
*/
|
|
4
|
-
import type {
|
|
4
|
+
import type { PaymentPayloadV2 } from "@armory-sh/base";
|
|
5
5
|
export declare const TEST_PRIVATE_KEY = "0x0000000000000000000000000000000000000000000000000000000000000000001";
|
|
6
6
|
export declare const TEST_PAYER_ADDRESS = "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb1";
|
|
7
7
|
export declare const TEST_PAY_TO_ADDRESS = "0x1234567890123456789012345678901234567890";
|
|
8
8
|
export declare const TEST_CONTRACT_ADDRESS = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48";
|
|
9
9
|
export declare const createX402V2Payload: (nonce?: string) => PaymentPayloadV2;
|
|
10
|
-
export declare const createLegacyV2Payload: (nonce?: string) => X402PayloadV2;
|
|
11
10
|
export declare const INVALID_PAYLOADS: {
|
|
12
11
|
readonly missingFields: {};
|
|
13
12
|
readonly invalidAddress: PaymentPayloadV2;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
export type { Address as X402Address, Hex, X402Version, Scheme, Network as X402Network, ExactEvmAuthorization, ExactEvmPayload, PaymentPayload as X402PaymentPayload, UnsignedPaymentPayload as X402UnsignedPaymentPayload, PaymentRequirements as X402PaymentRequirements, SettlementResponse as X402SettlementResponse, VerifyResponse, X402Response,
|
|
2
|
-
export { X402_VERSION, SCHEMES, isPaymentPayload, isExactEvmPayload,
|
|
3
|
-
export { safeBase64Encode, safeBase64Decode, encodePayment, decodePayment, encodeSettlementResponse, decodeSettlementResponse, encodeX402Response, decodeX402Response, detectPaymentVersion, extractPaymentFromHeaders, createPaymentRequiredHeaders, createSettlementHeaders,
|
|
1
|
+
export type { Address as X402Address, Hex, X402Version, Scheme, Network as X402Network, ExactEvmAuthorization, ExactEvmPayload, PaymentPayload as X402PaymentPayload, UnsignedPaymentPayload as X402UnsignedPaymentPayload, PaymentRequirements as X402PaymentRequirements, SettlementResponse as X402SettlementResponse, VerifyResponse, X402Response, } from "./types/x402";
|
|
2
|
+
export { X402_VERSION, SCHEMES, isPaymentPayload, isExactEvmPayload, } from "./types/x402";
|
|
3
|
+
export { safeBase64Encode, safeBase64Decode, encodePayment, decodePayment, encodeSettlementResponse, decodeSettlementResponse, encodeX402Response, decodeX402Response, detectPaymentVersion, extractPaymentFromHeaders, createPaymentRequiredHeaders, createSettlementHeaders, } from "./encoding/x402";
|
|
4
4
|
export { createNonce, toAtomicUnits, fromAtomicUnits, caip2ToNetwork, networkToCaip2, getCurrentTimestamp, isValidAddress, normalizeAddress, } from "./utils/x402";
|
|
5
5
|
export type { CAIP2Network as CAIP2ChainId, CAIPAssetId, Address, Signature, PayToV2, Extensions, PaymentPayloadV2, PaymentRequirementsV2, SettlementResponseV2, PaymentRequiredV2, ResourceInfo, EIP3009Authorization, SchemePayloadV2, } from "./types/v2";
|
|
6
6
|
export { V2_HEADERS, isCAIP2ChainId, isCAIPAssetId, isAddress, isPaymentRequiredV2, isPaymentPayloadV2, assetIdToAddress, addressToAssetId, parseSignature as parseSignatureV2, combineSignature as combineSignatureV2, } from "./types/v2";
|
|
7
7
|
export type { PaymentPayload, PaymentRequirements, SettlementResponse, PaymentRequired, } from "./types/protocol";
|
|
8
|
-
export { isX402V2Payload, isX402V2Requirements, isX402V2Settlement, isX402V2PaymentRequired,
|
|
8
|
+
export { isX402V2Payload, isX402V2Requirements, isX402V2Settlement, isX402V2PaymentRequired, isSettlementSuccessful, getTxHash, PAYMENT_SIGNATURE_HEADER, PAYMENT_RESPONSE_HEADER, PAYMENT_REQUIRED_HEADER, } from "./types/protocol";
|
|
9
9
|
export type { NetworkConfig, CustomToken } from "./types/networks";
|
|
10
10
|
export { NETWORKS, getNetworkConfig, getNetworkByChainId, getMainnets, getTestnets, registerToken, getCustomToken, getAllCustomTokens, unregisterToken, isCustomToken, } from "./types/networks";
|
|
11
11
|
export { TOKENS, USDC_BASE, EURC_BASE, USDC_BASE_SEPOLIA, USDC_SKALE_BASE, SKL_SKALE_BASE, USDT_SKALE_BASE, WBTC_SKALE_BASE, WETH_SKALE_BASE, SKL_SKALE_BASE_SEPOLIA, USDC_SKALE_BASE_SEPOLIA, USDT_SKALE_BASE_SEPOLIA, WBTC_SKALE_BASE_SEPOLIA, WETH_SKALE_BASE_SEPOLIA, getToken, getAllTokens, getTokensBySymbol, getTokensByChain, getUSDCTokens, getEURCTokens, getSKLTokens, getUSDTTokens, getWBTCTokens, getWETHTokens, } from "./data/tokens";
|
|
@@ -19,5 +19,7 @@ export { parseRoutePattern, matchRoute, findMatchingRoute, validateRouteConfig,
|
|
|
19
19
|
export { encodePaymentV2, decodePaymentV2, encodeSettlementV2, decodeSettlementV2, isPaymentV2, isSettlementV2, } from "./encoding";
|
|
20
20
|
export type { NetworkId, TokenId, FacilitatorConfig, FacilitatorVerifyResult, FacilitatorSettleResult, SettlementMode, PayToAddress, AcceptPaymentOptions, PricingConfig, PaymentResult, PaymentError, PaymentErrorCode, ArmoryPaymentResult, ResolvedNetwork, ResolvedToken, ResolvedFacilitator, ResolvedPaymentConfig, ValidationError, } from "./types/api";
|
|
21
21
|
export type { PaymentRequiredContext, PaymentPayloadContext, HookResult, OnPaymentRequiredHook, BeforePaymentHook, ExtensionHook, HookConfig, HookRegistry, } from "./types/hooks";
|
|
22
|
-
export {
|
|
22
|
+
export type { FacilitatorClientConfig, SupportedKind, SupportedResponse, } from "./payment-client";
|
|
23
|
+
export { verifyPayment, settlePayment, getSupported, decodePayloadHeader, extractPayerAddress, } from "./payment-client";
|
|
24
|
+
export { createX402V2Payload, INVALID_PAYLOADS, TEST_PAYER_ADDRESS, TEST_PAY_TO_ADDRESS, TEST_CONTRACT_ADDRESS, TEST_PRIVATE_KEY, } from "./fixtures/payloads";
|
|
23
25
|
export { DEFAULT_PAYMENT_CONFIG, type TestPaymentConfig } from "./fixtures/config";
|
package/dist/index.js
CHANGED
|
@@ -1,110 +1,14 @@
|
|
|
1
1
|
import { randomBytes } from 'crypto';
|
|
2
2
|
|
|
3
3
|
// src/types/x402.ts
|
|
4
|
-
var X402_VERSION =
|
|
4
|
+
var X402_VERSION = 2;
|
|
5
5
|
var SCHEMES = ["exact"];
|
|
6
|
-
var CHAIN_ID_TO_NETWORK = {
|
|
7
|
-
1: "ethereum",
|
|
8
|
-
8453: "base",
|
|
9
|
-
84532: "base-sepolia",
|
|
10
|
-
137: "polygon",
|
|
11
|
-
42161: "arbitrum",
|
|
12
|
-
421614: "arbitrum-sepolia",
|
|
13
|
-
10: "optimism",
|
|
14
|
-
11155420: "optimism-sepolia",
|
|
15
|
-
11155111: "ethereum-sepolia"
|
|
16
|
-
};
|
|
17
6
|
function isPaymentPayload(obj) {
|
|
18
7
|
return typeof obj === "object" && obj !== null && "x402Version" in obj && "scheme" in obj && "network" in obj && "payload" in obj;
|
|
19
8
|
}
|
|
20
9
|
function isExactEvmPayload(obj) {
|
|
21
10
|
return typeof obj === "object" && obj !== null && "signature" in obj && "authorization" in obj;
|
|
22
11
|
}
|
|
23
|
-
function extractNetworkFromLegacy(legacy) {
|
|
24
|
-
if ("network" in legacy && typeof legacy.network === "string") {
|
|
25
|
-
return legacy.network;
|
|
26
|
-
}
|
|
27
|
-
if ("chainId" in legacy && typeof legacy.chainId === "string") {
|
|
28
|
-
const match = legacy.chainId.match(/^eip155:(\d+)$/);
|
|
29
|
-
if (match) {
|
|
30
|
-
const chainId = parseInt(match[1], 10);
|
|
31
|
-
return CHAIN_ID_TO_NETWORK[chainId] || `eip155:${chainId}`;
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
if ("chainId" in legacy && typeof legacy.chainId === "number") {
|
|
35
|
-
return CHAIN_ID_TO_NETWORK[legacy.chainId] || `eip155:${legacy.chainId}`;
|
|
36
|
-
}
|
|
37
|
-
return "base";
|
|
38
|
-
}
|
|
39
|
-
function extractSignatureFromLegacy(legacy) {
|
|
40
|
-
if ("v" in legacy && "r" in legacy && "s" in legacy) {
|
|
41
|
-
const v = legacy.v.toString(16).padStart(2, "0");
|
|
42
|
-
const r = legacy.r.startsWith("0x") ? legacy.r.slice(2) : legacy.r;
|
|
43
|
-
const s = legacy.s.startsWith("0x") ? legacy.s.slice(2) : legacy.s;
|
|
44
|
-
return `0x${r}${s}${v}`;
|
|
45
|
-
}
|
|
46
|
-
if ("signature" in legacy && typeof legacy.signature === "object" && legacy.signature !== null) {
|
|
47
|
-
const sig = legacy.signature;
|
|
48
|
-
const v = sig.v.toString(16).padStart(2, "0");
|
|
49
|
-
const r = sig.r.startsWith("0x") ? sig.r.slice(2) : sig.r;
|
|
50
|
-
const s = sig.s.startsWith("0x") ? sig.s.slice(2) : sig.s;
|
|
51
|
-
return `0x${r}${s}${v}`;
|
|
52
|
-
}
|
|
53
|
-
return "0x";
|
|
54
|
-
}
|
|
55
|
-
function convertAmountToAtomic(amount) {
|
|
56
|
-
if (amount.includes(".")) {
|
|
57
|
-
const parts = amount.split(".");
|
|
58
|
-
const whole = parts[0];
|
|
59
|
-
const fractional = parts[1] || "";
|
|
60
|
-
const paddedFractional = fractional.padEnd(6, "0").slice(0, 6);
|
|
61
|
-
return `${whole}${paddedFractional}`;
|
|
62
|
-
}
|
|
63
|
-
return amount;
|
|
64
|
-
}
|
|
65
|
-
function convertNonceToHex(nonce) {
|
|
66
|
-
if (nonce.startsWith("0x") && nonce.length === 66) {
|
|
67
|
-
return nonce;
|
|
68
|
-
}
|
|
69
|
-
const hex = BigInt(nonce).toString(16).padStart(64, "0");
|
|
70
|
-
return `0x${hex}`;
|
|
71
|
-
}
|
|
72
|
-
function extractFromAddress(legacy) {
|
|
73
|
-
return legacy.from;
|
|
74
|
-
}
|
|
75
|
-
function extractToAddress(legacy) {
|
|
76
|
-
if ("to" in legacy && typeof legacy.to === "string") {
|
|
77
|
-
return legacy.to;
|
|
78
|
-
}
|
|
79
|
-
return legacy.from;
|
|
80
|
-
}
|
|
81
|
-
function legacyToPaymentPayload(legacy) {
|
|
82
|
-
if (isPaymentPayload(legacy)) {
|
|
83
|
-
return legacy;
|
|
84
|
-
}
|
|
85
|
-
const network = extractNetworkFromLegacy(legacy);
|
|
86
|
-
const signature = extractSignatureFromLegacy(legacy);
|
|
87
|
-
const value = convertAmountToAtomic(legacy.amount);
|
|
88
|
-
const nonce = convertNonceToHex(legacy.nonce);
|
|
89
|
-
const from = extractFromAddress(legacy);
|
|
90
|
-
const to = extractToAddress(legacy);
|
|
91
|
-
return {
|
|
92
|
-
x402Version: X402_VERSION,
|
|
93
|
-
scheme: "exact",
|
|
94
|
-
network,
|
|
95
|
-
payload: {
|
|
96
|
-
signature,
|
|
97
|
-
authorization: {
|
|
98
|
-
from,
|
|
99
|
-
to,
|
|
100
|
-
value,
|
|
101
|
-
validAfter: "0",
|
|
102
|
-
validBefore: legacy.expiry.toString(),
|
|
103
|
-
nonce
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
};
|
|
107
|
-
}
|
|
108
12
|
|
|
109
13
|
// src/types/v2.ts
|
|
110
14
|
var V2_HEADERS = {
|
|
@@ -165,13 +69,10 @@ function safeBase64Decode(str) {
|
|
|
165
69
|
return Buffer.from(str, "base64").toString("utf-8");
|
|
166
70
|
}
|
|
167
71
|
function encodePayment(payload) {
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
normalizedPayload = payload;
|
|
171
|
-
} else {
|
|
172
|
-
normalizedPayload = legacyToPaymentPayload(payload);
|
|
72
|
+
if (!isPaymentPayload(payload)) {
|
|
73
|
+
throw new Error("Invalid payment payload format");
|
|
173
74
|
}
|
|
174
|
-
const safePayload = JSON.parse(JSON.stringify(
|
|
75
|
+
const safePayload = JSON.parse(JSON.stringify(payload, (_, value) => {
|
|
175
76
|
if (typeof value === "bigint") {
|
|
176
77
|
return value.toString();
|
|
177
78
|
}
|
|
@@ -180,10 +81,15 @@ function encodePayment(payload) {
|
|
|
180
81
|
return safeBase64Encode(JSON.stringify(safePayload));
|
|
181
82
|
}
|
|
182
83
|
function decodePayment(encoded) {
|
|
183
|
-
|
|
184
|
-
|
|
84
|
+
let parsed;
|
|
85
|
+
try {
|
|
86
|
+
parsed = JSON.parse(encoded);
|
|
87
|
+
} catch {
|
|
88
|
+
const decoded = safeBase64Decode(encoded);
|
|
89
|
+
parsed = JSON.parse(decoded);
|
|
90
|
+
}
|
|
185
91
|
if (!isPaymentPayload(parsed)) {
|
|
186
|
-
|
|
92
|
+
throw new Error("Invalid payment payload format");
|
|
187
93
|
}
|
|
188
94
|
return parsed;
|
|
189
95
|
}
|
|
@@ -197,15 +103,23 @@ function encodeSettlementResponse(response) {
|
|
|
197
103
|
return safeBase64Encode(JSON.stringify(safeResponse));
|
|
198
104
|
}
|
|
199
105
|
function decodeSettlementResponse(encoded) {
|
|
200
|
-
|
|
201
|
-
|
|
106
|
+
try {
|
|
107
|
+
return JSON.parse(encoded);
|
|
108
|
+
} catch {
|
|
109
|
+
const decoded = safeBase64Decode(encoded);
|
|
110
|
+
return JSON.parse(decoded);
|
|
111
|
+
}
|
|
202
112
|
}
|
|
203
113
|
function encodeX402Response(response) {
|
|
204
114
|
return safeBase64Encode(JSON.stringify(response));
|
|
205
115
|
}
|
|
206
116
|
function decodeX402Response(encoded) {
|
|
207
|
-
|
|
208
|
-
|
|
117
|
+
try {
|
|
118
|
+
return JSON.parse(encoded);
|
|
119
|
+
} catch {
|
|
120
|
+
const decoded = safeBase64Decode(encoded);
|
|
121
|
+
return JSON.parse(decoded);
|
|
122
|
+
}
|
|
209
123
|
}
|
|
210
124
|
function detectPaymentVersion(headers) {
|
|
211
125
|
if (headers.has("PAYMENT-SIGNATURE")) {
|
|
@@ -237,9 +151,6 @@ function createSettlementHeaders(settlement) {
|
|
|
237
151
|
[V2_HEADERS.PAYMENT_RESPONSE]: encodeSettlementResponse(settlement)
|
|
238
152
|
};
|
|
239
153
|
}
|
|
240
|
-
function isLegacyV2(payload) {
|
|
241
|
-
return typeof payload === "object" && payload !== null && "signature" in payload && typeof payload.signature === "object";
|
|
242
|
-
}
|
|
243
154
|
function createNonce() {
|
|
244
155
|
const bytes = randomBytes(32);
|
|
245
156
|
return `0x${bytes.toString("hex")}`;
|
|
@@ -315,12 +226,6 @@ function normalizeAddress(address) {
|
|
|
315
226
|
function isX402V2Payload(obj) {
|
|
316
227
|
return typeof obj === "object" && obj !== null && "x402Version" in obj && obj.x402Version === 2 && "signature" in obj && "chainId" in obj && "assetId" in obj;
|
|
317
228
|
}
|
|
318
|
-
function isLegacyV2Payload(obj) {
|
|
319
|
-
if (typeof obj !== "object" || obj === null) return false;
|
|
320
|
-
const record = obj;
|
|
321
|
-
const signature = record.signature;
|
|
322
|
-
return "signature" in record && typeof signature === "object" && signature !== null && "v" in signature && "chainId" in record && typeof record.chainId === "string" && record.chainId.startsWith("eip155:") && "assetId" in record && !("x402Version" in record);
|
|
323
|
-
}
|
|
324
229
|
function isX402V2Requirements(obj) {
|
|
325
230
|
return typeof obj === "object" && obj !== null && "scheme" in obj && obj.scheme === "exact" && "network" in obj && typeof obj.network === "string" && obj.network.startsWith("eip155:") && // CAIP-2 format
|
|
326
231
|
"amount" in obj && "asset" in obj && "payTo" in obj && "maxTimeoutSeconds" in obj;
|
|
@@ -1291,6 +1196,131 @@ var decodeSettlementV2 = (encoded) => base64JsonDecode(encoded);
|
|
|
1291
1196
|
var isPaymentV2 = (payload) => "signature" in payload && typeof payload.signature === "object";
|
|
1292
1197
|
var isSettlementV2 = (response) => "status" in response;
|
|
1293
1198
|
|
|
1199
|
+
// src/payment-client.ts
|
|
1200
|
+
var DEFAULT_FACILITATOR_URL = "https://facilitator.payai.network";
|
|
1201
|
+
function toJsonSafe(data) {
|
|
1202
|
+
function convert(value) {
|
|
1203
|
+
if (value !== null && typeof value === "object" && !Array.isArray(value)) {
|
|
1204
|
+
return Object.fromEntries(Object.entries(value).map(([key, val]) => [key, convert(val)]));
|
|
1205
|
+
}
|
|
1206
|
+
if (Array.isArray(value)) {
|
|
1207
|
+
return value.map(convert);
|
|
1208
|
+
}
|
|
1209
|
+
if (typeof value === "bigint") {
|
|
1210
|
+
return value.toString();
|
|
1211
|
+
}
|
|
1212
|
+
return value;
|
|
1213
|
+
}
|
|
1214
|
+
return convert(data);
|
|
1215
|
+
}
|
|
1216
|
+
function resolveUrl(config) {
|
|
1217
|
+
return config?.url ?? DEFAULT_FACILITATOR_URL;
|
|
1218
|
+
}
|
|
1219
|
+
async function resolveHeaders(config) {
|
|
1220
|
+
const base = { "Content-Type": "application/json" };
|
|
1221
|
+
if (!config?.createHeaders) return base;
|
|
1222
|
+
const extra = await config.createHeaders();
|
|
1223
|
+
return { ...base, ...extra };
|
|
1224
|
+
}
|
|
1225
|
+
async function verifyPayment(payload, requirements, config) {
|
|
1226
|
+
const url = resolveUrl(config);
|
|
1227
|
+
const headers = await resolveHeaders(config);
|
|
1228
|
+
const response = await fetch(`${url}/verify`, {
|
|
1229
|
+
method: "POST",
|
|
1230
|
+
headers,
|
|
1231
|
+
body: JSON.stringify({
|
|
1232
|
+
x402Version: payload.x402Version,
|
|
1233
|
+
paymentPayload: toJsonSafe(payload),
|
|
1234
|
+
paymentRequirements: toJsonSafe(requirements)
|
|
1235
|
+
})
|
|
1236
|
+
});
|
|
1237
|
+
if (response.status !== 200) {
|
|
1238
|
+
const text = await response.text().catch(() => response.statusText);
|
|
1239
|
+
throw new Error(`Facilitator verify failed: ${response.status} ${text}`);
|
|
1240
|
+
}
|
|
1241
|
+
return await response.json();
|
|
1242
|
+
}
|
|
1243
|
+
async function settlePayment(payload, requirements, config) {
|
|
1244
|
+
const url = resolveUrl(config);
|
|
1245
|
+
const headers = await resolveHeaders(config);
|
|
1246
|
+
const response = await fetch(`${url}/settle`, {
|
|
1247
|
+
method: "POST",
|
|
1248
|
+
headers,
|
|
1249
|
+
body: JSON.stringify({
|
|
1250
|
+
x402Version: payload.x402Version,
|
|
1251
|
+
paymentPayload: toJsonSafe(payload),
|
|
1252
|
+
paymentRequirements: toJsonSafe(requirements)
|
|
1253
|
+
})
|
|
1254
|
+
});
|
|
1255
|
+
if (response.status !== 200) {
|
|
1256
|
+
const text = await response.text().catch(() => response.statusText);
|
|
1257
|
+
throw new Error(`Facilitator settle failed: ${response.status} ${text}`);
|
|
1258
|
+
}
|
|
1259
|
+
return await response.json();
|
|
1260
|
+
}
|
|
1261
|
+
async function getSupported(config) {
|
|
1262
|
+
const url = resolveUrl(config);
|
|
1263
|
+
const headers = await resolveHeaders(config);
|
|
1264
|
+
const response = await fetch(`${url}/supported`, {
|
|
1265
|
+
method: "GET",
|
|
1266
|
+
headers
|
|
1267
|
+
});
|
|
1268
|
+
if (response.status !== 200) {
|
|
1269
|
+
throw new Error(`Facilitator supported failed: ${response.statusText}`);
|
|
1270
|
+
}
|
|
1271
|
+
return await response.json();
|
|
1272
|
+
}
|
|
1273
|
+
function tryParseHeaderJson(headerValue) {
|
|
1274
|
+
if (headerValue.startsWith("{")) {
|
|
1275
|
+
return JSON.parse(headerValue);
|
|
1276
|
+
}
|
|
1277
|
+
const normalized = headerValue.replace(/-/g, "+").replace(/_/g, "/").padEnd(Math.ceil(headerValue.length / 4) * 4, "=");
|
|
1278
|
+
return JSON.parse(Buffer.from(normalized, "base64").toString("utf-8"));
|
|
1279
|
+
}
|
|
1280
|
+
function isCompactV2Payload(payload) {
|
|
1281
|
+
if (typeof payload !== "object" || payload === null) return false;
|
|
1282
|
+
const record = payload;
|
|
1283
|
+
return typeof record.x402Version === "number" && "payload" in record;
|
|
1284
|
+
}
|
|
1285
|
+
function decodePayloadHeader(headerValue, defaults) {
|
|
1286
|
+
if (headerValue.startsWith("{")) {
|
|
1287
|
+
const parsed = JSON.parse(headerValue);
|
|
1288
|
+
if (isPaymentPayload(parsed)) return parsed;
|
|
1289
|
+
if (isCompactV2Payload(parsed)) {
|
|
1290
|
+
const compact = parsed;
|
|
1291
|
+
return {
|
|
1292
|
+
x402Version: 2,
|
|
1293
|
+
scheme: defaults?.scheme ?? "exact",
|
|
1294
|
+
network: defaults?.network ?? "base",
|
|
1295
|
+
payload: compact.payload
|
|
1296
|
+
};
|
|
1297
|
+
}
|
|
1298
|
+
throw new Error("Invalid payment payload: unrecognized format");
|
|
1299
|
+
}
|
|
1300
|
+
try {
|
|
1301
|
+
return decodePayment(headerValue);
|
|
1302
|
+
} catch {
|
|
1303
|
+
const parsed = tryParseHeaderJson(headerValue);
|
|
1304
|
+
if (isPaymentPayload(parsed)) return parsed;
|
|
1305
|
+
if (isCompactV2Payload(parsed)) {
|
|
1306
|
+
const compact = parsed;
|
|
1307
|
+
return {
|
|
1308
|
+
x402Version: 2,
|
|
1309
|
+
scheme: defaults?.scheme ?? "exact",
|
|
1310
|
+
network: defaults?.network ?? "base",
|
|
1311
|
+
payload: compact.payload
|
|
1312
|
+
};
|
|
1313
|
+
}
|
|
1314
|
+
throw new Error("Invalid payment payload: unrecognized format");
|
|
1315
|
+
}
|
|
1316
|
+
}
|
|
1317
|
+
function extractPayerAddress(payload) {
|
|
1318
|
+
if (isExactEvmPayload(payload.payload)) {
|
|
1319
|
+
return payload.payload.authorization.from;
|
|
1320
|
+
}
|
|
1321
|
+
throw new Error("Unable to extract payer address from payload");
|
|
1322
|
+
}
|
|
1323
|
+
|
|
1294
1324
|
// src/fixtures/payloads.ts
|
|
1295
1325
|
var TEST_PRIVATE_KEY = "0x0000000000000000000000000000000000000000000000000000000000000000001";
|
|
1296
1326
|
var TEST_PAYER_ADDRESS = "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb1";
|
|
@@ -1318,20 +1348,6 @@ var createX402V2Payload = (nonce) => ({
|
|
|
1318
1348
|
description: "Test resource"
|
|
1319
1349
|
}
|
|
1320
1350
|
});
|
|
1321
|
-
var createLegacyV2Payload = (nonce) => ({
|
|
1322
|
-
from: TEST_PAYER_ADDRESS,
|
|
1323
|
-
to: TEST_PAY_TO_ADDRESS,
|
|
1324
|
-
amount: "1000000",
|
|
1325
|
-
nonce: nonce ?? "test_legacy_v2_nonce",
|
|
1326
|
-
expiry: Math.floor(Date.now() / 1e3) + 3600,
|
|
1327
|
-
signature: {
|
|
1328
|
-
v: 27,
|
|
1329
|
-
r: `0x${"f".repeat(64)}`,
|
|
1330
|
-
s: `0x${"0".repeat(64)}`
|
|
1331
|
-
},
|
|
1332
|
-
chainId: "eip155:84532",
|
|
1333
|
-
assetId: `eip155:84532/erc20:${TEST_CONTRACT_ADDRESS.slice(2)}`
|
|
1334
|
-
});
|
|
1335
1351
|
var INVALID_PAYLOADS = {
|
|
1336
1352
|
missingFields: {},
|
|
1337
1353
|
invalidAddress: {
|
|
@@ -1381,4 +1397,4 @@ var DEFAULT_PAYMENT_CONFIG = {
|
|
|
1381
1397
|
}
|
|
1382
1398
|
};
|
|
1383
1399
|
|
|
1384
|
-
export { DEFAULT_PAYMENT_CONFIG, EIP712_TYPES, ERC20_ABI, EURC_BASE, INVALID_PAYLOADS, NETWORKS, PAYMENT_REQUIRED_HEADER, PAYMENT_RESPONSE_HEADER, PAYMENT_SIGNATURE_HEADER, SCHEMES, SKL_SKALE_BASE, SKL_SKALE_BASE_SEPOLIA, TEST_CONTRACT_ADDRESS, TEST_PAYER_ADDRESS, TEST_PAY_TO_ADDRESS, TEST_PRIVATE_KEY, TOKENS, USDC_BASE, USDC_BASE_SEPOLIA, USDC_DOMAIN, USDC_SKALE_BASE, USDC_SKALE_BASE_SEPOLIA, USDT_SKALE_BASE, USDT_SKALE_BASE_SEPOLIA, V2_HEADERS, WBTC_SKALE_BASE, WBTC_SKALE_BASE_SEPOLIA, WETH_SKALE_BASE, WETH_SKALE_BASE_SEPOLIA, X402_VERSION, addressToAssetId, assetIdToAddress, caip2ToNetwork, checkFacilitatorSupport, combineSignature as combineSignatureV2, createEIP712Domain, createError,
|
|
1400
|
+
export { DEFAULT_PAYMENT_CONFIG, EIP712_TYPES, ERC20_ABI, EURC_BASE, INVALID_PAYLOADS, NETWORKS, PAYMENT_REQUIRED_HEADER, PAYMENT_RESPONSE_HEADER, PAYMENT_SIGNATURE_HEADER, SCHEMES, SKL_SKALE_BASE, SKL_SKALE_BASE_SEPOLIA, TEST_CONTRACT_ADDRESS, TEST_PAYER_ADDRESS, TEST_PAY_TO_ADDRESS, TEST_PRIVATE_KEY, TOKENS, USDC_BASE, USDC_BASE_SEPOLIA, USDC_DOMAIN, USDC_SKALE_BASE, USDC_SKALE_BASE_SEPOLIA, USDT_SKALE_BASE, USDT_SKALE_BASE_SEPOLIA, V2_HEADERS, WBTC_SKALE_BASE, WBTC_SKALE_BASE_SEPOLIA, WETH_SKALE_BASE, WETH_SKALE_BASE_SEPOLIA, X402_VERSION, addressToAssetId, assetIdToAddress, caip2ToNetwork, checkFacilitatorSupport, combineSignature as combineSignatureV2, createEIP712Domain, createError, createNonce, createPaymentRequiredHeaders, createSettlementHeaders, createTransferWithAuthorization, createX402V2Payload, decodePayloadHeader, decodePayment, decodePaymentV2, decodeSettlementResponse, decodeSettlementV2, decodeX402Response, detectPaymentVersion, encodePayment, encodePaymentV2, encodeSettlementResponse, encodeSettlementV2, encodeX402Response, extractPayerAddress, extractPaymentFromHeaders, findMatchingRoute, fromAtomicUnits, getAllCustomTokens, getAllTokens, getAvailableNetworks, getAvailableTokens, getCurrentTimestamp, getCustomToken, getEURCTokens, getMainnets, getNetworkByChainId, getNetworkConfig, getSKLTokens, getSupported, getTestnets, getToken, getTokensByChain, getTokensBySymbol, getTxHash, getUSDCTokens, getUSDTTokens, getWBTCTokens, getWETHTokens, isAddress, isCAIP2ChainId, isCAIPAssetId, isCustomToken, isExactEvmPayload, isPaymentPayload, isPaymentPayloadV2, isPaymentRequiredV2, isPaymentV2, isResolvedNetwork, isResolvedToken, isSettlementSuccessful, isSettlementV2, isValidAddress, isValidationError, isX402V2Payload, isX402V2PaymentRequired, isX402V2Requirements, isX402V2Settlement, matchRoute, networkToCaip2, normalizeAddress, normalizeNetworkName, parseRoutePattern, parseSignature as parseSignatureV2, registerToken, resolveFacilitator, resolveNetwork, resolveToken, safeBase64Decode, safeBase64Encode, settlePayment, toAtomicUnits, unregisterToken, validateAcceptConfig, validatePaymentConfig, validateRouteConfig, validateTransferWithAuthorization, verifyPayment };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { PaymentPayload, PaymentRequirements, VerifyResponse, SettlementResponse } from "./types/x402";
|
|
2
|
+
export interface FacilitatorClientConfig {
|
|
3
|
+
url: string;
|
|
4
|
+
createHeaders?: () => Record<string, string> | Promise<Record<string, string>>;
|
|
5
|
+
}
|
|
6
|
+
export declare function verifyPayment(payload: PaymentPayload, requirements: PaymentRequirements, config?: FacilitatorClientConfig): Promise<VerifyResponse>;
|
|
7
|
+
export declare function settlePayment(payload: PaymentPayload, requirements: PaymentRequirements, config?: FacilitatorClientConfig): Promise<SettlementResponse>;
|
|
8
|
+
export interface SupportedKind {
|
|
9
|
+
x402Version: number;
|
|
10
|
+
scheme: string;
|
|
11
|
+
network: string;
|
|
12
|
+
extra?: Record<string, unknown>;
|
|
13
|
+
}
|
|
14
|
+
export interface SupportedResponse {
|
|
15
|
+
kinds: SupportedKind[];
|
|
16
|
+
}
|
|
17
|
+
interface DecodePayloadDefaults {
|
|
18
|
+
scheme?: string;
|
|
19
|
+
network?: string;
|
|
20
|
+
}
|
|
21
|
+
export declare function getSupported(config?: FacilitatorClientConfig): Promise<SupportedResponse>;
|
|
22
|
+
export declare function decodePayloadHeader(headerValue: string, defaults?: DecodePayloadDefaults): PaymentPayload;
|
|
23
|
+
export declare function extractPayerAddress(payload: PaymentPayload): string;
|
|
24
|
+
export {};
|
package/dist/types/protocol.d.ts
CHANGED
|
@@ -53,10 +53,6 @@ export type CAIPAssetId = `eip155:${string}/erc20:${string}`;
|
|
|
53
53
|
* Check if payload is x402 V2 format (Coinbase format)
|
|
54
54
|
*/
|
|
55
55
|
export declare function isX402V2Payload(obj: unknown): obj is PaymentPayloadV2;
|
|
56
|
-
/**
|
|
57
|
-
* Check if payload is legacy Armory V2 format
|
|
58
|
-
*/
|
|
59
|
-
export declare function isLegacyV2Payload(obj: unknown): boolean;
|
|
60
56
|
/**
|
|
61
57
|
* Check if requirements is x402 V2 format
|
|
62
58
|
*/
|
package/dist/types/x402.d.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
export type Address = `0x${string}`;
|
|
8
8
|
export type Hex = `0x${string}`;
|
|
9
|
-
export declare const X402_VERSION:
|
|
9
|
+
export declare const X402_VERSION: 2;
|
|
10
10
|
export type X402Version = typeof X402_VERSION;
|
|
11
11
|
export declare const SCHEMES: readonly ["exact"];
|
|
12
12
|
export type Scheme = (typeof SCHEMES)[number];
|
|
@@ -92,44 +92,8 @@ export interface X402Response {
|
|
|
92
92
|
accepts?: PaymentRequirements[];
|
|
93
93
|
payer?: Address;
|
|
94
94
|
}
|
|
95
|
-
export interface PaymentPayloadV1 {
|
|
96
|
-
from: string;
|
|
97
|
-
to: string;
|
|
98
|
-
amount: string;
|
|
99
|
-
nonce: string;
|
|
100
|
-
expiry: number;
|
|
101
|
-
v: number;
|
|
102
|
-
r: string;
|
|
103
|
-
s: string;
|
|
104
|
-
chainId: number;
|
|
105
|
-
contractAddress: string;
|
|
106
|
-
network: string;
|
|
107
|
-
}
|
|
108
|
-
export interface PaymentPayloadV2 {
|
|
109
|
-
from: Address;
|
|
110
|
-
to: Address | {
|
|
111
|
-
role?: string;
|
|
112
|
-
callback?: string;
|
|
113
|
-
};
|
|
114
|
-
amount: string;
|
|
115
|
-
nonce: string;
|
|
116
|
-
expiry: number;
|
|
117
|
-
signature: {
|
|
118
|
-
v: number;
|
|
119
|
-
r: string;
|
|
120
|
-
s: string;
|
|
121
|
-
};
|
|
122
|
-
chainId: `eip155:${string}`;
|
|
123
|
-
assetId: `eip155:${string}/erc20:${string}`;
|
|
124
|
-
extensions?: Record<string, unknown>;
|
|
125
|
-
}
|
|
126
|
-
export type LegacyPaymentPayload = PaymentPayloadV1 | PaymentPayloadV2;
|
|
127
95
|
/**
|
|
128
96
|
* Type guards
|
|
129
97
|
*/
|
|
130
98
|
export declare function isPaymentPayload(obj: unknown): obj is PaymentPayload;
|
|
131
99
|
export declare function isExactEvmPayload(obj: unknown): obj is ExactEvmPayload;
|
|
132
|
-
/**
|
|
133
|
-
* Convert legacy payload to new format
|
|
134
|
-
*/
|
|
135
|
-
export declare function legacyToPaymentPayload(legacy: LegacyPaymentPayload | PaymentPayload): PaymentPayload;
|
package/package.json
CHANGED
package/dist/types/v1.d.ts
DELETED
|
@@ -1,156 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Armory V1 Types - x402 Protocol V1 Compatible
|
|
3
|
-
*
|
|
4
|
-
* Supports both the x402 V1 specification format and legacy Armory V1 format.
|
|
5
|
-
*
|
|
6
|
-
* x402 V1 Specification: https://github.com/coinbase/x402
|
|
7
|
-
*/
|
|
8
|
-
import type { Address } from "./v2";
|
|
9
|
-
/**
|
|
10
|
-
* Network name for x402 V1 (e.g., "base-sepolia", "ethereum-mainnet")
|
|
11
|
-
*/
|
|
12
|
-
export type X402V1Network = string;
|
|
13
|
-
/**
|
|
14
|
-
* EIP-3009 authorization data (same format for V1 and V2)
|
|
15
|
-
*/
|
|
16
|
-
export interface EIP3009AuthorizationV1 {
|
|
17
|
-
from: Address;
|
|
18
|
-
to: Address;
|
|
19
|
-
value: string;
|
|
20
|
-
validAfter: string;
|
|
21
|
-
validBefore: string;
|
|
22
|
-
nonce: `0x${string}`;
|
|
23
|
-
}
|
|
24
|
-
/**
|
|
25
|
-
* Payment requirements for a specific payment method (x402 V1)
|
|
26
|
-
*/
|
|
27
|
-
export interface X402PaymentRequirementsV1 {
|
|
28
|
-
scheme: "exact";
|
|
29
|
-
network: X402V1Network;
|
|
30
|
-
maxAmountRequired: string;
|
|
31
|
-
asset: Address;
|
|
32
|
-
payTo: Address;
|
|
33
|
-
resource: string;
|
|
34
|
-
description: string;
|
|
35
|
-
mimeType?: string;
|
|
36
|
-
outputSchema?: object | null;
|
|
37
|
-
maxTimeoutSeconds: number;
|
|
38
|
-
extra?: Record<string, unknown>;
|
|
39
|
-
}
|
|
40
|
-
/**
|
|
41
|
-
* Payment requirements response (x402 V1)
|
|
42
|
-
* Matches x402 V1 PaymentRequirementsResponse spec
|
|
43
|
-
*/
|
|
44
|
-
export interface X402PaymentRequiredV1 {
|
|
45
|
-
x402Version: 1;
|
|
46
|
-
error: string;
|
|
47
|
-
accepts: X402PaymentRequirementsV1[];
|
|
48
|
-
}
|
|
49
|
-
/**
|
|
50
|
-
* Scheme payload data (x402 V1)
|
|
51
|
-
*/
|
|
52
|
-
export interface X402SchemePayloadV1 {
|
|
53
|
-
signature: `0x${string}`;
|
|
54
|
-
authorization: EIP3009AuthorizationV1;
|
|
55
|
-
}
|
|
56
|
-
/**
|
|
57
|
-
* Payment payload (x402 V1)
|
|
58
|
-
* Matches x402 V1 PaymentPayload spec
|
|
59
|
-
*/
|
|
60
|
-
export interface X402PaymentPayloadV1 {
|
|
61
|
-
x402Version: 1;
|
|
62
|
-
scheme: "exact";
|
|
63
|
-
network: X402V1Network;
|
|
64
|
-
payload: X402SchemePayloadV1;
|
|
65
|
-
}
|
|
66
|
-
/**
|
|
67
|
-
* Settlement response (x402 V1)
|
|
68
|
-
* Matches x402 V1 SettlementResponse spec
|
|
69
|
-
*/
|
|
70
|
-
export interface X402SettlementResponseV1 {
|
|
71
|
-
success: boolean;
|
|
72
|
-
errorReason?: string;
|
|
73
|
-
transaction: string;
|
|
74
|
-
network: X402V1Network;
|
|
75
|
-
payer: Address;
|
|
76
|
-
}
|
|
77
|
-
/**
|
|
78
|
-
* Legacy Armory V1 payment payload format
|
|
79
|
-
* @deprecated Use X402PaymentPayloadV1 for new code
|
|
80
|
-
*/
|
|
81
|
-
export interface LegacyPaymentPayloadV1 {
|
|
82
|
-
from: string;
|
|
83
|
-
to: string;
|
|
84
|
-
amount: string;
|
|
85
|
-
nonce: string;
|
|
86
|
-
expiry: number;
|
|
87
|
-
v: number;
|
|
88
|
-
r: string;
|
|
89
|
-
s: string;
|
|
90
|
-
chainId: number;
|
|
91
|
-
contractAddress: string;
|
|
92
|
-
network: string;
|
|
93
|
-
}
|
|
94
|
-
/**
|
|
95
|
-
* Legacy Armory V1 payment requirements format
|
|
96
|
-
* @deprecated Use X402PaymentRequirementsV1 for new code
|
|
97
|
-
*/
|
|
98
|
-
export interface LegacyPaymentRequirementsV1 {
|
|
99
|
-
amount: string;
|
|
100
|
-
network: string;
|
|
101
|
-
contractAddress: string;
|
|
102
|
-
payTo: string;
|
|
103
|
-
expiry: number;
|
|
104
|
-
}
|
|
105
|
-
/**
|
|
106
|
-
* Legacy Armory V1 settlement response format
|
|
107
|
-
* @deprecated Use X402SettlementResponseV1 for new code
|
|
108
|
-
*/
|
|
109
|
-
export interface LegacySettlementResponseV1 {
|
|
110
|
-
success: boolean;
|
|
111
|
-
txHash?: string;
|
|
112
|
-
error?: string;
|
|
113
|
-
timestamp: number;
|
|
114
|
-
}
|
|
115
|
-
export type PaymentPayloadV1 = X402PaymentPayloadV1 | LegacyPaymentPayloadV1;
|
|
116
|
-
export type PaymentRequirementsV1 = X402PaymentRequirementsV1 | LegacyPaymentRequirementsV1;
|
|
117
|
-
export type SettlementResponseV1 = X402SettlementResponseV1 | LegacySettlementResponseV1;
|
|
118
|
-
export declare const V1_HEADERS: {
|
|
119
|
-
readonly PAYMENT: "X-PAYMENT";
|
|
120
|
-
readonly PAYMENT_RESPONSE: "X-PAYMENT-RESPONSE";
|
|
121
|
-
readonly PAYMENT_REQUIRED: "X-PAYMENT-REQUIRED";
|
|
122
|
-
};
|
|
123
|
-
export declare function encodeX402PaymentRequiredV1(data: X402PaymentRequiredV1): string;
|
|
124
|
-
export declare function decodeX402PaymentRequiredV1(encoded: string): X402PaymentRequiredV1;
|
|
125
|
-
export declare function encodeX402PaymentPayloadV1(data: X402PaymentPayloadV1): string;
|
|
126
|
-
export declare function decodeX402PaymentPayloadV1(encoded: string): X402PaymentPayloadV1;
|
|
127
|
-
export declare function encodeX402SettlementResponseV1(data: X402SettlementResponseV1): string;
|
|
128
|
-
export declare function decodeX402SettlementResponseV1(encoded: string): X402SettlementResponseV1;
|
|
129
|
-
/**
|
|
130
|
-
* @deprecated Use encodeX402PaymentPayloadV1 instead
|
|
131
|
-
*/
|
|
132
|
-
export declare function encodePaymentPayloadLegacy(payload: LegacyPaymentPayloadV1): string;
|
|
133
|
-
/**
|
|
134
|
-
* @deprecated Use decodeX402PaymentPayloadV1 instead
|
|
135
|
-
*/
|
|
136
|
-
export declare function decodePaymentPayloadLegacy(encoded: string): LegacyPaymentPayloadV1;
|
|
137
|
-
/**
|
|
138
|
-
* @deprecated Use encodeX402SettlementResponseV1 instead
|
|
139
|
-
*/
|
|
140
|
-
export declare function encodeSettlementResponseLegacy(response: LegacySettlementResponseV1): string;
|
|
141
|
-
/**
|
|
142
|
-
* @deprecated Use decodeX402SettlementResponseV1 instead
|
|
143
|
-
*/
|
|
144
|
-
export declare function decodeSettlementResponseLegacy(encoded: string): LegacySettlementResponseV1;
|
|
145
|
-
/**
|
|
146
|
-
* Check if value is x402 V1 PaymentRequired
|
|
147
|
-
*/
|
|
148
|
-
export declare function isX402PaymentRequiredV1(obj: unknown): obj is X402PaymentRequiredV1;
|
|
149
|
-
/**
|
|
150
|
-
* Check if value is x402 V1 PaymentPayload
|
|
151
|
-
*/
|
|
152
|
-
export declare function isX402PaymentPayloadV1(obj: unknown): obj is X402PaymentPayloadV1;
|
|
153
|
-
/**
|
|
154
|
-
* Check if value is legacy Armory V1 format
|
|
155
|
-
*/
|
|
156
|
-
export declare function isLegacyPaymentPayloadV1(obj: unknown): obj is LegacyPaymentPayloadV1;
|