@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.
- package/README.md +304 -28
- package/dist/client-hooks-runtime.d.ts +9 -0
- package/dist/encoding/x402.d.ts +1 -1
- package/dist/errors.d.ts +10 -0
- package/dist/facilitator-capabilities.d.ts +9 -0
- package/dist/index.d.ts +30 -22
- package/dist/index.js +1198 -650
- package/dist/payment-client.d.ts +1 -1
- package/dist/payment-requirements.d.ts +35 -0
- package/dist/protocol.d.ts +33 -0
- package/dist/types/api.d.ts +1 -1
- package/dist/types/hooks.d.ts +17 -1
- package/dist/types/protocol.d.ts +1 -1
- package/dist/types/wallet.d.ts +24 -0
- package/dist/utils/base64.d.ts +4 -0
- package/dist/utils/x402.d.ts +1 -1
- package/dist/validation.d.ts +1 -1
- package/package.json +15 -2
- package/src/abi/erc20.ts +84 -0
- package/src/client-hooks-runtime.ts +153 -0
- package/src/data/tokens.ts +199 -0
- package/src/eip712.ts +108 -0
- package/src/encoding/x402.ts +205 -0
- package/src/encoding.ts +98 -0
- package/src/errors.ts +23 -0
- package/src/facilitator-capabilities.ts +125 -0
- package/src/index.ts +330 -0
- package/src/payment-client.ts +201 -0
- package/src/payment-requirements.ts +354 -0
- package/src/protocol.ts +57 -0
- package/src/types/api.ts +304 -0
- package/src/types/hooks.ts +85 -0
- package/src/types/networks.ts +175 -0
- package/src/types/protocol.ts +182 -0
- package/src/types/v2.ts +282 -0
- package/src/types/wallet.ts +30 -0
- package/src/types/x402.ts +151 -0
- package/src/utils/base64.ts +48 -0
- package/src/utils/routes.ts +240 -0
- package/src/utils/utils/index.ts +7 -0
- package/src/utils/utils/mock-facilitator.ts +184 -0
- package/src/utils/x402.ts +147 -0
- 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
|
+
}
|