uvd-x402-sdk 2.0.1
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/LICENSE +21 -0
- package/README.md +782 -0
- package/dist/index-BrBqP1I8.d.ts +199 -0
- package/dist/index-D6Sr4ARD.d.mts +429 -0
- package/dist/index-D6Sr4ARD.d.ts +429 -0
- package/dist/index-DJ4Cvrev.d.mts +199 -0
- package/dist/index.d.mts +3 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +1178 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +1146 -0
- package/dist/index.mjs.map +1 -0
- package/dist/providers/evm/index.d.mts +84 -0
- package/dist/providers/evm/index.d.ts +84 -0
- package/dist/providers/evm/index.js +740 -0
- package/dist/providers/evm/index.js.map +1 -0
- package/dist/providers/evm/index.mjs +735 -0
- package/dist/providers/evm/index.mjs.map +1 -0
- package/dist/providers/near/index.d.mts +99 -0
- package/dist/providers/near/index.d.ts +99 -0
- package/dist/providers/near/index.js +483 -0
- package/dist/providers/near/index.js.map +1 -0
- package/dist/providers/near/index.mjs +478 -0
- package/dist/providers/near/index.mjs.map +1 -0
- package/dist/providers/solana/index.d.mts +115 -0
- package/dist/providers/solana/index.d.ts +115 -0
- package/dist/providers/solana/index.js +771 -0
- package/dist/providers/solana/index.js.map +1 -0
- package/dist/providers/solana/index.mjs +765 -0
- package/dist/providers/solana/index.mjs.map +1 -0
- package/dist/providers/stellar/index.d.mts +67 -0
- package/dist/providers/stellar/index.d.ts +67 -0
- package/dist/providers/stellar/index.js +306 -0
- package/dist/providers/stellar/index.js.map +1 -0
- package/dist/providers/stellar/index.mjs +301 -0
- package/dist/providers/stellar/index.mjs.map +1 -0
- package/dist/react/index.d.mts +73 -0
- package/dist/react/index.d.ts +73 -0
- package/dist/react/index.js +1218 -0
- package/dist/react/index.js.map +1 -0
- package/dist/react/index.mjs +1211 -0
- package/dist/react/index.mjs.map +1 -0
- package/dist/utils/index.d.mts +103 -0
- package/dist/utils/index.d.ts +103 -0
- package/dist/utils/index.js +575 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/index.mjs +562 -0
- package/dist/utils/index.mjs.map +1 -0
- package/package.json +149 -0
- package/src/chains/index.ts +539 -0
- package/src/client/X402Client.ts +663 -0
- package/src/client/index.ts +1 -0
- package/src/index.ts +166 -0
- package/src/providers/evm/index.ts +394 -0
- package/src/providers/near/index.ts +664 -0
- package/src/providers/solana/index.ts +489 -0
- package/src/providers/stellar/index.ts +376 -0
- package/src/react/index.tsx +417 -0
- package/src/types/index.ts +561 -0
- package/src/utils/index.ts +20 -0
- package/src/utils/x402.ts +295 -0
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* uvd-x402-sdk - x402 Protocol Utilities
|
|
3
|
+
*
|
|
4
|
+
* Utilities for working with x402 v1 and v2 protocols.
|
|
5
|
+
* Handles version detection, payload encoding, and CAIP-2 conversions.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type {
|
|
9
|
+
X402Header,
|
|
10
|
+
X402HeaderV1,
|
|
11
|
+
X402HeaderV2,
|
|
12
|
+
X402PayloadData,
|
|
13
|
+
X402PaymentOption,
|
|
14
|
+
X402Version,
|
|
15
|
+
ChainConfig,
|
|
16
|
+
} from '../types';
|
|
17
|
+
import { CAIP2_IDENTIFIERS, CAIP2_TO_CHAIN } from '../types';
|
|
18
|
+
import { getChainByName } from '../chains';
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Detect x402 version from a response header or body
|
|
22
|
+
*
|
|
23
|
+
* @param data - The 402 response data (parsed JSON or header value)
|
|
24
|
+
* @returns The detected version (1 or 2)
|
|
25
|
+
*/
|
|
26
|
+
export function detectX402Version(data: unknown): X402Version {
|
|
27
|
+
if (typeof data !== 'object' || data === null) {
|
|
28
|
+
return 1; // Default to v1
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const obj = data as Record<string, unknown>;
|
|
32
|
+
|
|
33
|
+
// Check explicit version field
|
|
34
|
+
if (obj.x402Version === 2) {
|
|
35
|
+
return 2;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Check for v2 indicators
|
|
39
|
+
if (obj.accepts && Array.isArray(obj.accepts)) {
|
|
40
|
+
return 2;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Check if network is in CAIP-2 format
|
|
44
|
+
if (typeof obj.network === 'string') {
|
|
45
|
+
if (obj.network.includes(':')) {
|
|
46
|
+
return 2;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return 1;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Convert chain name to CAIP-2 identifier
|
|
55
|
+
*
|
|
56
|
+
* @param chainName - Chain name (e.g., 'base', 'solana')
|
|
57
|
+
* @returns CAIP-2 identifier (e.g., 'eip155:8453', 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp')
|
|
58
|
+
*/
|
|
59
|
+
export function chainToCAIP2(chainName: string): string {
|
|
60
|
+
const caip2 = CAIP2_IDENTIFIERS[chainName.toLowerCase()];
|
|
61
|
+
if (caip2) {
|
|
62
|
+
return caip2;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Try to construct from chain config
|
|
66
|
+
const chain = getChainByName(chainName);
|
|
67
|
+
if (chain) {
|
|
68
|
+
if (chain.networkType === 'evm') {
|
|
69
|
+
return `eip155:${chain.chainId}`;
|
|
70
|
+
}
|
|
71
|
+
// For non-EVM, return the name as-is with network prefix
|
|
72
|
+
return `${chain.networkType}:${chainName}`;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return chainName; // Return as-is if unknown
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Convert CAIP-2 identifier to chain name
|
|
80
|
+
*
|
|
81
|
+
* @param caip2 - CAIP-2 identifier
|
|
82
|
+
* @returns Chain name or null if unknown
|
|
83
|
+
*/
|
|
84
|
+
export function caip2ToChain(caip2: string): string | null {
|
|
85
|
+
// Check direct mapping
|
|
86
|
+
if (CAIP2_TO_CHAIN[caip2]) {
|
|
87
|
+
return CAIP2_TO_CHAIN[caip2];
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Try to extract from EIP-155 format
|
|
91
|
+
const match = caip2.match(/^eip155:(\d+)$/);
|
|
92
|
+
if (match) {
|
|
93
|
+
const chainId = parseInt(match[1], 10);
|
|
94
|
+
// Find chain by ID
|
|
95
|
+
for (const [name, _config] of Object.entries(CAIP2_IDENTIFIERS)) {
|
|
96
|
+
const chain = getChainByName(name);
|
|
97
|
+
if (chain?.chainId === chainId) {
|
|
98
|
+
return name;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Try to extract from network:name format
|
|
104
|
+
const parts = caip2.split(':');
|
|
105
|
+
if (parts.length === 2) {
|
|
106
|
+
const networkName = parts[1];
|
|
107
|
+
if (getChainByName(networkName)) {
|
|
108
|
+
return networkName;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Parse network identifier from either v1 or v2 format
|
|
117
|
+
*
|
|
118
|
+
* @param network - Network identifier (v1 string or v2 CAIP-2)
|
|
119
|
+
* @returns Normalized chain name
|
|
120
|
+
*/
|
|
121
|
+
export function parseNetworkIdentifier(network: string): string {
|
|
122
|
+
// If it contains a colon, it's likely CAIP-2
|
|
123
|
+
if (network.includes(':')) {
|
|
124
|
+
return caip2ToChain(network) || network;
|
|
125
|
+
}
|
|
126
|
+
return network.toLowerCase();
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Encode x402 payload as base64 header value
|
|
131
|
+
*
|
|
132
|
+
* @param header - The x402 header object
|
|
133
|
+
* @returns Base64-encoded string
|
|
134
|
+
*/
|
|
135
|
+
export function encodeX402Header(header: X402Header): string {
|
|
136
|
+
return btoa(JSON.stringify(header));
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Decode x402 header from base64 string
|
|
141
|
+
*
|
|
142
|
+
* @param encoded - Base64-encoded header value
|
|
143
|
+
* @returns Parsed x402 header
|
|
144
|
+
*/
|
|
145
|
+
export function decodeX402Header(encoded: string): X402Header {
|
|
146
|
+
const json = atob(encoded);
|
|
147
|
+
return JSON.parse(json) as X402Header;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Create x402 v1 header
|
|
152
|
+
*
|
|
153
|
+
* @param network - Chain name (e.g., 'base')
|
|
154
|
+
* @param payload - Network-specific payload
|
|
155
|
+
* @returns x402 v1 header object
|
|
156
|
+
*/
|
|
157
|
+
export function createX402V1Header(
|
|
158
|
+
network: string,
|
|
159
|
+
payload: X402PayloadData
|
|
160
|
+
): X402HeaderV1 {
|
|
161
|
+
return {
|
|
162
|
+
x402Version: 1,
|
|
163
|
+
scheme: 'exact',
|
|
164
|
+
network,
|
|
165
|
+
payload,
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Create x402 v2 header
|
|
171
|
+
*
|
|
172
|
+
* @param network - CAIP-2 network identifier
|
|
173
|
+
* @param payload - Network-specific payload
|
|
174
|
+
* @param accepts - Optional array of payment options
|
|
175
|
+
* @returns x402 v2 header object
|
|
176
|
+
*/
|
|
177
|
+
export function createX402V2Header(
|
|
178
|
+
network: string,
|
|
179
|
+
payload: X402PayloadData,
|
|
180
|
+
accepts?: X402PaymentOption[]
|
|
181
|
+
): X402HeaderV2 {
|
|
182
|
+
const header: X402HeaderV2 = {
|
|
183
|
+
x402Version: 2,
|
|
184
|
+
scheme: 'exact',
|
|
185
|
+
network: network.includes(':') ? network : chainToCAIP2(network),
|
|
186
|
+
payload,
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
if (accepts && accepts.length > 0) {
|
|
190
|
+
header.accepts = accepts;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
return header;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Create x402 header with automatic version selection
|
|
198
|
+
*
|
|
199
|
+
* @param chainConfig - Chain configuration
|
|
200
|
+
* @param payload - Network-specific payload
|
|
201
|
+
* @param version - Version to use (1, 2, or 'auto')
|
|
202
|
+
* @returns x402 header object
|
|
203
|
+
*/
|
|
204
|
+
export function createX402Header(
|
|
205
|
+
chainConfig: ChainConfig,
|
|
206
|
+
payload: X402PayloadData,
|
|
207
|
+
version: X402Version | 'auto' = 'auto'
|
|
208
|
+
): X402Header {
|
|
209
|
+
// Default to v1 for maximum compatibility
|
|
210
|
+
const effectiveVersion = version === 'auto' ? 1 : version;
|
|
211
|
+
|
|
212
|
+
if (effectiveVersion === 2) {
|
|
213
|
+
return createX402V2Header(chainConfig.name, payload);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
return createX402V1Header(chainConfig.name, payload);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Generate payment options array for multi-network support
|
|
221
|
+
*
|
|
222
|
+
* @param chainConfigs - Array of chain configurations
|
|
223
|
+
* @param amount - Amount in USDC (e.g., "10.00")
|
|
224
|
+
* @param facilitator - Optional facilitator URL override
|
|
225
|
+
* @returns Array of x402 v2 payment options
|
|
226
|
+
*/
|
|
227
|
+
export function generatePaymentOptions(
|
|
228
|
+
chainConfigs: ChainConfig[],
|
|
229
|
+
amount: string,
|
|
230
|
+
facilitator?: string
|
|
231
|
+
): X402PaymentOption[] {
|
|
232
|
+
// Convert amount to atomic units for each chain
|
|
233
|
+
return chainConfigs
|
|
234
|
+
.filter(chain => chain.x402.enabled)
|
|
235
|
+
.map(chain => {
|
|
236
|
+
const atomicAmount = Math.floor(
|
|
237
|
+
parseFloat(amount) * Math.pow(10, chain.usdc.decimals)
|
|
238
|
+
).toString();
|
|
239
|
+
|
|
240
|
+
return {
|
|
241
|
+
network: chainToCAIP2(chain.name),
|
|
242
|
+
asset: chain.usdc.address,
|
|
243
|
+
amount: atomicAmount,
|
|
244
|
+
facilitator: facilitator || chain.x402.facilitatorUrl,
|
|
245
|
+
};
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Check if a network string is in CAIP-2 format
|
|
251
|
+
*
|
|
252
|
+
* @param network - Network identifier
|
|
253
|
+
* @returns True if CAIP-2 format
|
|
254
|
+
*/
|
|
255
|
+
export function isCAIP2Format(network: string): boolean {
|
|
256
|
+
return network.includes(':');
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Convert between x402 v1 and v2 header formats
|
|
261
|
+
*
|
|
262
|
+
* @param header - Source header
|
|
263
|
+
* @param targetVersion - Target version
|
|
264
|
+
* @returns Converted header
|
|
265
|
+
*/
|
|
266
|
+
export function convertX402Header(
|
|
267
|
+
header: X402Header,
|
|
268
|
+
targetVersion: X402Version
|
|
269
|
+
): X402Header {
|
|
270
|
+
if (header.x402Version === targetVersion) {
|
|
271
|
+
return header;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
if (targetVersion === 2) {
|
|
275
|
+
// v1 -> v2
|
|
276
|
+
return {
|
|
277
|
+
x402Version: 2,
|
|
278
|
+
scheme: 'exact',
|
|
279
|
+
network: chainToCAIP2(header.network),
|
|
280
|
+
payload: header.payload,
|
|
281
|
+
};
|
|
282
|
+
} else {
|
|
283
|
+
// v2 -> v1
|
|
284
|
+
const chainName = isCAIP2Format(header.network)
|
|
285
|
+
? caip2ToChain(header.network) || header.network
|
|
286
|
+
: header.network;
|
|
287
|
+
|
|
288
|
+
return {
|
|
289
|
+
x402Version: 1,
|
|
290
|
+
scheme: 'exact',
|
|
291
|
+
network: chainName,
|
|
292
|
+
payload: header.payload,
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
}
|