@armory-sh/base 0.2.28 → 0.2.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/README.md +304 -28
  2. package/dist/client-hooks-runtime.d.ts +9 -0
  3. package/dist/encoding/x402.d.ts +1 -1
  4. package/dist/errors.d.ts +10 -0
  5. package/dist/facilitator-capabilities.d.ts +9 -0
  6. package/dist/index.d.ts +30 -22
  7. package/dist/index.js +1198 -650
  8. package/dist/payment-client.d.ts +1 -1
  9. package/dist/payment-requirements.d.ts +35 -0
  10. package/dist/protocol.d.ts +33 -0
  11. package/dist/types/api.d.ts +1 -1
  12. package/dist/types/hooks.d.ts +17 -1
  13. package/dist/types/protocol.d.ts +1 -1
  14. package/dist/types/wallet.d.ts +24 -0
  15. package/dist/utils/base64.d.ts +4 -0
  16. package/dist/utils/x402.d.ts +1 -1
  17. package/dist/validation.d.ts +1 -1
  18. package/package.json +15 -2
  19. package/src/abi/erc20.ts +84 -0
  20. package/src/client-hooks-runtime.ts +153 -0
  21. package/src/data/tokens.ts +199 -0
  22. package/src/eip712.ts +108 -0
  23. package/src/encoding/x402.ts +205 -0
  24. package/src/encoding.ts +98 -0
  25. package/src/errors.ts +23 -0
  26. package/src/facilitator-capabilities.ts +125 -0
  27. package/src/index.ts +330 -0
  28. package/src/payment-client.ts +201 -0
  29. package/src/payment-requirements.ts +354 -0
  30. package/src/protocol.ts +57 -0
  31. package/src/types/api.ts +304 -0
  32. package/src/types/hooks.ts +85 -0
  33. package/src/types/networks.ts +175 -0
  34. package/src/types/protocol.ts +182 -0
  35. package/src/types/v2.ts +282 -0
  36. package/src/types/wallet.ts +30 -0
  37. package/src/types/x402.ts +151 -0
  38. package/src/utils/base64.ts +48 -0
  39. package/src/utils/routes.ts +240 -0
  40. package/src/utils/utils/index.ts +7 -0
  41. package/src/utils/utils/mock-facilitator.ts +184 -0
  42. package/src/utils/x402.ts +147 -0
  43. package/src/validation.ts +654 -0
package/src/index.ts ADDED
@@ -0,0 +1,330 @@
1
+ // ============================================
2
+ // Types from x402 (Coinbase-compatible)
3
+ // ============================================
4
+
5
+ // ============================================
6
+ // ERC20 ABI
7
+ // ============================================
8
+ export type {
9
+ BalanceOfParams,
10
+ BalanceOfReturnType,
11
+ ERC20Abi,
12
+ NameReturnType,
13
+ ReceiveWithAuthorizationParams,
14
+ SymbolReturnType,
15
+ TransferWithAuthorizationParams,
16
+ } from "./abi/erc20";
17
+ export { ERC20_ABI } from "./abi/erc20";
18
+ export {
19
+ runAfterPaymentResponseHooks,
20
+ runBeforeSignPaymentHooks,
21
+ runOnPaymentRequiredHooks,
22
+ selectRequirementWithHooks,
23
+ } from "./client-hooks-runtime";
24
+ export {
25
+ EURC_BASE,
26
+ getAllTokens,
27
+ getEURCTokens,
28
+ getSKLTokens,
29
+ getToken,
30
+ getTokensByChain,
31
+ getTokensBySymbol,
32
+ getUSDCTokens,
33
+ getUSDTTokens,
34
+ getWBTCTokens,
35
+ getWETHTokens,
36
+ SKL_SKALE_BASE,
37
+ SKL_SKALE_BASE_SEPOLIA,
38
+ TOKENS,
39
+ USDC_BASE,
40
+ USDC_BASE_SEPOLIA,
41
+ USDC_SKALE_BASE,
42
+ USDC_SKALE_BASE_SEPOLIA,
43
+ USDT_SKALE_BASE,
44
+ USDT_SKALE_BASE_SEPOLIA,
45
+ WBTC_SKALE_BASE,
46
+ WBTC_SKALE_BASE_SEPOLIA,
47
+ WETH_SKALE_BASE,
48
+ WETH_SKALE_BASE_SEPOLIA,
49
+ } from "./data/tokens";
50
+ // ============================================
51
+ // EIP-712 utilities
52
+ // ============================================
53
+ export type {
54
+ EIP712Domain,
55
+ EIP712Types,
56
+ TransferWithAuthorization,
57
+ TypedDataDomain,
58
+ TypedDataField,
59
+ } from "./eip712";
60
+ export {
61
+ createEIP712Domain,
62
+ createTransferWithAuthorization,
63
+ EIP712_TYPES,
64
+ USDC_DOMAIN,
65
+ validateTransferWithAuthorization,
66
+ } from "./eip712";
67
+ // ============================================
68
+ // Encoding functions (V2 only from encoding.ts)
69
+ // ============================================
70
+ export {
71
+ decodePaymentV2,
72
+ decodeSettlementV2,
73
+ encodePaymentV2,
74
+ encodeSettlementV2,
75
+ isPaymentV2,
76
+ isSettlementV2,
77
+ } from "./encoding";
78
+ export type { PaymentRequiredOptions } from "./encoding/x402";
79
+ // ============================================
80
+ // Encoding utilities from x402
81
+ // ============================================
82
+ export {
83
+ createPaymentRequiredHeaders,
84
+ createSettlementHeaders,
85
+ decodePayment,
86
+ decodeSettlementResponse,
87
+ decodeX402Response,
88
+ detectPaymentVersion,
89
+ encodePayment,
90
+ encodeSettlementResponse,
91
+ encodeX402Response,
92
+ extractPaymentFromHeaders,
93
+ safeBase64Decode,
94
+ safeBase64Encode,
95
+ } from "./encoding/x402";
96
+ // ============================================
97
+ // Client error classes (shared across all client packages)
98
+ // ============================================
99
+ export {
100
+ PaymentException,
101
+ SigningError,
102
+ X402ClientError,
103
+ } from "./errors";
104
+ // ============================================
105
+ // Facilitator client
106
+ // ============================================
107
+ export type {
108
+ FacilitatorClientConfig,
109
+ SupportedKind,
110
+ SupportedResponse,
111
+ } from "./payment-client";
112
+ export {
113
+ decodePayloadHeader,
114
+ extractPayerAddress,
115
+ getSupported,
116
+ settlePayment,
117
+ verifyPayment,
118
+ } from "./payment-client";
119
+ export {
120
+ clearFacilitatorCapabilityCache,
121
+ filterExtensionsForFacilitator,
122
+ filterExtensionsForFacilitators,
123
+ filterExtensionsForRequirements,
124
+ } from "./facilitator-capabilities";
125
+ export type {
126
+ PaymentConfig,
127
+ ResolvedRequirementsConfig,
128
+ } from "./payment-requirements";
129
+ export {
130
+ createPaymentRequirements,
131
+ findRequirementByAccepted,
132
+ findRequirementByNetwork,
133
+ resolveFacilitatorUrlFromRequirement,
134
+ } from "./payment-requirements";
135
+ // ============================================
136
+ // Protocol utilities (shared across all client packages)
137
+ // ============================================
138
+ export {
139
+ calculateValidBefore,
140
+ detectX402Version,
141
+ generateNonce,
142
+ getPaymentHeaderName,
143
+ parseJsonOrBase64,
144
+ } from "./protocol";
145
+ // ============================================
146
+ // Simple types
147
+ // ============================================
148
+ export type {
149
+ AcceptPaymentOptions,
150
+ ArmoryPaymentResult,
151
+ FacilitatorConfig,
152
+ FacilitatorSettleResult,
153
+ FacilitatorVerifyResult,
154
+ NetworkId,
155
+ PaymentError,
156
+ PaymentErrorCode,
157
+ PaymentResult,
158
+ PayToAddress,
159
+ PricingConfig,
160
+ ResolvedFacilitator,
161
+ ResolvedNetwork,
162
+ ResolvedPaymentConfig,
163
+ ResolvedToken,
164
+ SettlementMode,
165
+ TokenId,
166
+ ValidationError,
167
+ } from "./types/api";
168
+ // ============================================
169
+ // Hook system for extensions
170
+ // ============================================
171
+ export type {
172
+ BeforePaymentHook,
173
+ ClientHook,
174
+ ClientHookErrorContext,
175
+ ExtensionHook,
176
+ HookConfig,
177
+ HookRegistry,
178
+ HookResult,
179
+ OnPaymentRequiredHook,
180
+ PaymentPayloadContext,
181
+ PaymentRequiredContext,
182
+ } from "./types/hooks";
183
+ // ============================================
184
+ // Network and token configuration
185
+ // ============================================
186
+ export type { CustomToken, NetworkConfig } from "./types/networks";
187
+ export {
188
+ getAllCustomTokens,
189
+ getCustomToken,
190
+ getMainnets,
191
+ getNetworkByChainId,
192
+ getNetworkConfig,
193
+ getTestnets,
194
+ isCustomToken,
195
+ NETWORKS,
196
+ registerToken,
197
+ unregisterToken,
198
+ } from "./types/networks";
199
+ // ============================================
200
+ // Protocol union types and version helpers
201
+ // ============================================
202
+ export type {
203
+ PaymentPayload,
204
+ PaymentRequired,
205
+ PaymentRequirements,
206
+ SettlementResponse,
207
+ } from "./types/protocol";
208
+ export {
209
+ getTxHash,
210
+ isSettlementSuccessful,
211
+ isX402V2Payload,
212
+ isX402V2PaymentRequired,
213
+ isX402V2Requirements,
214
+ isX402V2Settlement,
215
+ PAYMENT_REQUIRED_HEADER,
216
+ PAYMENT_RESPONSE_HEADER,
217
+ PAYMENT_SIGNATURE_HEADER,
218
+ } from "./types/protocol";
219
+ // ============================================
220
+ // V2 types and functions (x402 V2 compatible)
221
+ // ============================================
222
+ export type {
223
+ Address,
224
+ CAIP2Network as CAIP2ChainId,
225
+ CAIPAssetId,
226
+ EIP3009Authorization,
227
+ Extensions,
228
+ PaymentPayloadV2,
229
+ PaymentRequiredV2,
230
+ PaymentRequirementsV2,
231
+ PayToV2,
232
+ ResourceInfo,
233
+ SchemePayloadV2,
234
+ SettlementResponseV2,
235
+ Signature,
236
+ } from "./types/v2";
237
+ export {
238
+ addressToAssetId,
239
+ assetIdToAddress,
240
+ combineSignature as combineSignatureV2,
241
+ isAddress,
242
+ isCAIP2ChainId,
243
+ isCAIPAssetId,
244
+ isPaymentPayloadV2,
245
+ isPaymentRequiredV2,
246
+ parseSignature as parseSignatureV2,
247
+ V2_HEADERS,
248
+ } from "./types/v2";
249
+ // ============================================
250
+ // Wallet adapter interface
251
+ // ============================================
252
+ export type { PaymentWallet } from "./types/wallet";
253
+ export type {
254
+ Address as X402Address,
255
+ ExactEvmAuthorization,
256
+ ExactEvmPayload,
257
+ Hex,
258
+ Network as X402Network,
259
+ PaymentPayload as X402PaymentPayload,
260
+ PaymentRequirements as X402PaymentRequirements,
261
+ Scheme,
262
+ SettlementResponse as X402SettlementResponse,
263
+ UnsignedPaymentPayload as X402UnsignedPaymentPayload,
264
+ VerifyResponse,
265
+ X402Response,
266
+ X402Version,
267
+ } from "./types/x402";
268
+ export {
269
+ isExactEvmPayload,
270
+ isPaymentPayload,
271
+ SCHEMES,
272
+ X402_VERSION,
273
+ } from "./types/x402";
274
+ // ============================================
275
+ // Base64 utilities
276
+ // ============================================
277
+ export {
278
+ decodeBase64ToUtf8,
279
+ encodeUtf8ToBase64,
280
+ normalizeBase64Url,
281
+ toBase64Url,
282
+ } from "./utils/base64";
283
+ // ============================================
284
+ // Route matching utilities
285
+ // ============================================
286
+ export type {
287
+ ParsedPattern,
288
+ RouteConfig,
289
+ RouteInputConfig,
290
+ RouteMatcher,
291
+ RoutePattern,
292
+ RouteValidationError,
293
+ } from "./utils/routes";
294
+ export {
295
+ findMatchingRoute,
296
+ matchRoute,
297
+ parseRoutePattern,
298
+ validateRouteConfig,
299
+ } from "./utils/routes";
300
+ // ============================================
301
+ // Utilities from x402
302
+ // ============================================
303
+ export {
304
+ caip2ToNetwork,
305
+ createNonce,
306
+ fromAtomicUnits,
307
+ getCurrentTimestamp,
308
+ isValidAddress,
309
+ networkToCaip2,
310
+ normalizeAddress,
311
+ toAtomicUnits,
312
+ } from "./utils/x402";
313
+ // ============================================
314
+ // Validation utilities
315
+ // ============================================
316
+ export {
317
+ checkFacilitatorSupport,
318
+ createError,
319
+ getAvailableNetworks,
320
+ getAvailableTokens,
321
+ isResolvedNetwork,
322
+ isResolvedToken,
323
+ isValidationError,
324
+ normalizeNetworkName,
325
+ resolveFacilitator,
326
+ resolveNetwork,
327
+ resolveToken,
328
+ validateAcceptConfig,
329
+ validatePaymentConfig,
330
+ } from "./validation";
@@ -0,0 +1,201 @@
1
+ import type {
2
+ PaymentPayload,
3
+ PaymentRequirements,
4
+ SettlementResponse,
5
+ VerifyResponse,
6
+ } from "./types/x402";
7
+ import { isExactEvmPayload, isPaymentPayload } from "./types/x402";
8
+ import { decodeBase64ToUtf8 } from "./utils/base64";
9
+
10
+ export interface FacilitatorClientConfig {
11
+ url: string;
12
+ createHeaders?: () =>
13
+ | Record<string, string>
14
+ | Promise<Record<string, string>>;
15
+ }
16
+
17
+ const DEFAULT_FACILITATOR_URL = "https://facilitator.payai.network";
18
+
19
+ function toJsonSafe(data: object): object {
20
+ function convert(value: unknown): unknown {
21
+ if (value !== null && typeof value === "object" && !Array.isArray(value)) {
22
+ return Object.fromEntries(
23
+ Object.entries(value).map(([key, val]) => [key, convert(val)]),
24
+ );
25
+ }
26
+ if (Array.isArray(value)) {
27
+ return value.map(convert);
28
+ }
29
+ if (typeof value === "bigint") {
30
+ return value.toString();
31
+ }
32
+ return value;
33
+ }
34
+ return convert(data) as object;
35
+ }
36
+
37
+ function resolveUrl(config?: FacilitatorClientConfig): string {
38
+ return config?.url ?? DEFAULT_FACILITATOR_URL;
39
+ }
40
+
41
+ async function resolveHeaders(
42
+ config?: FacilitatorClientConfig,
43
+ ): Promise<Record<string, string>> {
44
+ const base: Record<string, string> = { "Content-Type": "application/json" };
45
+ if (!config?.createHeaders) return base;
46
+ const extra = await config.createHeaders();
47
+ return { ...base, ...extra };
48
+ }
49
+
50
+ export async function verifyPayment(
51
+ payload: PaymentPayload,
52
+ requirements: PaymentRequirements,
53
+ config?: FacilitatorClientConfig,
54
+ ): Promise<VerifyResponse> {
55
+ const url = resolveUrl(config);
56
+ const headers = await resolveHeaders(config);
57
+
58
+ const response = await fetch(`${url}/verify`, {
59
+ method: "POST",
60
+ headers,
61
+ body: JSON.stringify({
62
+ paymentPayload: toJsonSafe(payload),
63
+ paymentRequirements: toJsonSafe(requirements),
64
+ }),
65
+ });
66
+
67
+ if (response.status !== 200) {
68
+ const text = await response.text().catch(() => response.statusText);
69
+ throw new Error(`Facilitator verify failed: ${response.status} ${text}`);
70
+ }
71
+
72
+ return (await response.json()) as VerifyResponse;
73
+ }
74
+
75
+ export async function settlePayment(
76
+ payload: PaymentPayload,
77
+ requirements: PaymentRequirements,
78
+ config?: FacilitatorClientConfig,
79
+ ): Promise<SettlementResponse> {
80
+ const url = resolveUrl(config);
81
+ const headers = await resolveHeaders(config);
82
+
83
+ const response = await fetch(`${url}/settle`, {
84
+ method: "POST",
85
+ headers,
86
+ body: JSON.stringify({
87
+ paymentPayload: toJsonSafe(payload),
88
+ paymentRequirements: toJsonSafe(requirements),
89
+ }),
90
+ });
91
+
92
+ if (response.status !== 200) {
93
+ const text = await response.text().catch(() => response.statusText);
94
+ throw new Error(`Facilitator settle failed: ${response.status} ${text}`);
95
+ }
96
+
97
+ return (await response.json()) as SettlementResponse;
98
+ }
99
+
100
+ export interface SupportedKind {
101
+ x402Version: number;
102
+ scheme: string;
103
+ network: string;
104
+ extra?: Record<string, unknown>;
105
+ }
106
+
107
+ export interface SupportedResponse {
108
+ kinds: SupportedKind[];
109
+ }
110
+
111
+ interface DecodePayloadDefaults {
112
+ accepted?: PaymentRequirements;
113
+ }
114
+
115
+ export async function getSupported(
116
+ config?: FacilitatorClientConfig,
117
+ ): Promise<SupportedResponse> {
118
+ const url = resolveUrl(config);
119
+ const headers = await resolveHeaders(config);
120
+
121
+ const response = await fetch(`${url}/supported`, {
122
+ method: "GET",
123
+ headers,
124
+ });
125
+
126
+ if (response.status !== 200) {
127
+ throw new Error(`Facilitator supported failed: ${response.statusText}`);
128
+ }
129
+
130
+ return (await response.json()) as SupportedResponse;
131
+ }
132
+
133
+ function isCompactV2Payload(
134
+ payload: unknown,
135
+ ): payload is { x402Version: number; payload: unknown } {
136
+ if (typeof payload !== "object" || payload === null) return false;
137
+ const record = payload as Record<string, unknown>;
138
+ return (
139
+ typeof record.x402Version === "number" &&
140
+ "payload" in record &&
141
+ !("accepted" in record)
142
+ );
143
+ }
144
+
145
+ export function decodePayloadHeader(
146
+ headerValue: string,
147
+ defaults?: DecodePayloadDefaults,
148
+ ): PaymentPayload {
149
+ if (headerValue.startsWith("{")) {
150
+ const parsed = JSON.parse(headerValue);
151
+ if (isPaymentPayload(parsed)) return parsed;
152
+ if (isCompactV2Payload(parsed)) {
153
+ const compact = parsed as { payload: PaymentPayload["payload"] };
154
+ if (!defaults?.accepted) {
155
+ throw new Error(
156
+ "Invalid payment payload: missing 'accepted' field and no defaults provided",
157
+ );
158
+ }
159
+ return {
160
+ x402Version: 2,
161
+ accepted: defaults.accepted,
162
+ payload: compact.payload,
163
+ };
164
+ }
165
+ throw new Error("Invalid payment payload: unrecognized format");
166
+ }
167
+
168
+ const normalized = headerValue
169
+ .replace(/-/g, "+")
170
+ .replace(/_/g, "/")
171
+ .padEnd(Math.ceil(headerValue.length / 4) * 4, "=");
172
+
173
+ try {
174
+ const decoded = JSON.parse(decodeBase64ToUtf8(normalized));
175
+ if (isPaymentPayload(decoded)) return decoded;
176
+ if (isCompactV2Payload(decoded)) {
177
+ const compact = decoded as { payload: PaymentPayload["payload"] };
178
+ if (!defaults?.accepted) {
179
+ throw new Error(
180
+ "Invalid payment payload: missing 'accepted' field and no defaults provided",
181
+ );
182
+ }
183
+ return {
184
+ x402Version: 2,
185
+ accepted: defaults.accepted,
186
+ payload: compact.payload,
187
+ };
188
+ }
189
+ throw new Error("Invalid payment payload: unrecognized format");
190
+ } catch {
191
+ throw new Error("Invalid payment payload: failed to decode");
192
+ }
193
+ }
194
+
195
+ export function extractPayerAddress(payload: PaymentPayload): string {
196
+ if (isExactEvmPayload(payload.payload)) {
197
+ return payload.payload.authorization.from;
198
+ }
199
+
200
+ throw new Error("Unable to extract payer address from payload");
201
+ }