@wtflabs/x402-detector 0.0.1-beta.2

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.
@@ -0,0 +1,209 @@
1
+ import { PublicClient, Address } from 'viem';
2
+
3
+ /**
4
+ * 支持的支付方式
5
+ */
6
+ type PaymentMethod = "eip3009" | "permit" | "permit2" | "permit2-witness";
7
+ /**
8
+ * Token 信息
9
+ */
10
+ interface TokenInfo {
11
+ name: string;
12
+ version: string;
13
+ }
14
+ /**
15
+ * Token 支付能力检测结果
16
+ */
17
+ interface TokenPaymentCapabilities {
18
+ /** Token 地址 */
19
+ address: string;
20
+ /** 支持的支付方式列表 */
21
+ supportedMethods: PaymentMethod[];
22
+ /** 详细检测结果 */
23
+ details: {
24
+ /** 是否支持 EIP-3009 (transferWithAuthorization) */
25
+ hasEIP3009: boolean;
26
+ /** 是否支持 EIP-2612 (permit) */
27
+ hasPermit: boolean;
28
+ /** 是否支持 Permit2 (通用授权) */
29
+ hasPermit2Approval: boolean;
30
+ };
31
+ }
32
+ /**
33
+ * 完整的 Token 检测结果(包含 name 和 version)
34
+ */
35
+ interface TokenDetectionResult extends TokenPaymentCapabilities {
36
+ /** Token 名称 */
37
+ name: string;
38
+ /** Token version(用于 EIP-712 签名) */
39
+ version: string;
40
+ }
41
+ /**
42
+ * 预设 Token 配置
43
+ */
44
+ interface PresetTokenConfig {
45
+ /** 支持的支付方式 */
46
+ supportedMethods: PaymentMethod[];
47
+ /** 支持的网络 ID 列表 */
48
+ supportedNetworks: number[];
49
+ /** Token 描述(可选) */
50
+ description?: string;
51
+ }
52
+ /**
53
+ * Logger 接口
54
+ */
55
+ interface Logger {
56
+ log: (message: string) => void;
57
+ error: (message: string, error?: unknown) => void;
58
+ }
59
+ /**
60
+ * TokenDetector 配置选项
61
+ */
62
+ interface TokenDetectorOptions {
63
+ /** 自定义 logger,默认使用 console */
64
+ logger?: Logger | null;
65
+ }
66
+
67
+ /**
68
+ * EIP-3009 方法签名
69
+ * - transferWithAuthorization(address,address,uint256,uint256,uint256,bytes32,uint8,bytes32,bytes32)
70
+ *
71
+ * 支持多个方法签名变体,以兼容不同的实现:
72
+ * - 0xe3ee160e: 标准 EIP-3009 实现
73
+ * - 0xcf092995: 某些代币的替代实现
74
+ */
75
+ declare const EIP3009_SIGNATURES: readonly ["0xe3ee160e", "0xcf092995"];
76
+ /**
77
+ * EIP-2612 Permit 方法签名
78
+ * - permit(address,address,uint256,uint256,uint8,bytes32,bytes32)
79
+ */
80
+ declare const EIP2612_PERMIT: "0xd505accf";
81
+ /**
82
+ * Uniswap Permit2 合约地址(所有链相同)
83
+ */
84
+ declare const PERMIT2_ADDRESS: "0x000000000022D473030F116dDEE9F6B43aC78BA3";
85
+ /**
86
+ * EIP-1967 标准实现槽位
87
+ * keccak256("eip1967.proxy.implementation") - 1
88
+ */
89
+ declare const EIP1967_IMPLEMENTATION_SLOT: "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc";
90
+ /**
91
+ * EIP-1822 UUPS 实现槽位
92
+ * keccak256("PROXIABLE")
93
+ */
94
+ declare const EIP1822_IMPLEMENTATION_SLOT: "0x7050c9e0f4ca769c69bd3a8ef740bc37934f8e2c036e5a723fd8ee048ed3f8c3";
95
+ /**
96
+ * 预设 Token 配置
97
+ * 用于已知的特殊 Token,避免重复检测
98
+ */
99
+ declare const PRESET_TOKEN_CAPABILITIES: Record<string, PresetTokenConfig>;
100
+
101
+ /**
102
+ * 检测 Token 支持的支付方式
103
+ *
104
+ * @param tokenAddress - Token 地址
105
+ * @param client - viem PublicClient
106
+ * @param logger - 可选的 logger
107
+ * @returns 检测结果
108
+ */
109
+ declare function detectTokenPaymentMethods(tokenAddress: string, client: PublicClient, logger?: Logger | null): Promise<TokenPaymentCapabilities>;
110
+ /**
111
+ * 获取推荐的支付方式(仅返回 schema 支持的类型)
112
+ * 按优先级排序:eip3009 > permit > permit2
113
+ * 注意:permit2-witness 会被映射为 permit2,因为它们在 schema 中是同一种支付类型
114
+ *
115
+ * @param tokenAddress - Token 地址
116
+ * @param client - viem PublicClient
117
+ * @param logger - 可选的 logger
118
+ * @returns 推荐的支付方式
119
+ */
120
+ declare function getRecommendedPaymentMethod(tokenAddress: string, client: PublicClient, logger?: Logger | null): Promise<"eip3009" | "permit2" | "permit" | null>;
121
+ /**
122
+ * 获取 Token 的 name 和 version 信息(用于 EIP-712 签名)
123
+ * 支持代理合约(会自动从代理合约读取,因为代理合约会 delegatecall 到实现合约)
124
+ *
125
+ * @param tokenAddress - Token 地址
126
+ * @param client - viem PublicClient
127
+ * @param logger - 可选的 logger
128
+ * @returns Token 的 name 和 version
129
+ */
130
+ declare function getTokenInfo(tokenAddress: string, client: PublicClient, logger?: Logger | null): Promise<TokenInfo>;
131
+
132
+ /**
133
+ * 检测合约是否是代理合约,并获取实现合约地址
134
+ *
135
+ * @param client - viem PublicClient
136
+ * @param proxyAddress - 代理合约地址
137
+ * @param logger - 可选的 logger
138
+ * @returns 实现合约地址或 null
139
+ */
140
+ declare function getImplementationAddress(client: PublicClient, proxyAddress: Address, logger?: Logger | null): Promise<Address | null>;
141
+
142
+ /**
143
+ * Token 检测器 - 带缓存功能的 SDK
144
+ *
145
+ * 主要用于 x402-server,也可以独立使用
146
+ */
147
+ declare class TokenDetector {
148
+ /** 缓存存储 (chainId:address -> TokenDetectionResult) */
149
+ private cache;
150
+ /** viem PublicClient */
151
+ private client;
152
+ /** Logger 实例 */
153
+ private logger;
154
+ /**
155
+ * 构造函数
156
+ *
157
+ * @param client - viem PublicClient
158
+ * @param options - 可选配置
159
+ */
160
+ constructor(client: PublicClient, options?: TokenDetectorOptions);
161
+ /**
162
+ * 完整检测(同时获取支付能力和 Token 信息)
163
+ * 优先从缓存读取,缓存未命中时执行检测并缓存结果
164
+ *
165
+ * @param tokenAddress - Token 地址
166
+ * @returns 完整的检测结果
167
+ */
168
+ detect(tokenAddress: string): Promise<TokenDetectionResult>;
169
+ /**
170
+ * 获取推荐的支付方式
171
+ * 优先级:eip3009 > permit > permit2
172
+ *
173
+ * @param tokenAddress - Token 地址
174
+ * @returns 推荐的支付方式
175
+ */
176
+ getRecommendedMethod(tokenAddress: string): Promise<"eip3009" | "permit" | "permit2" | null>;
177
+ /**
178
+ * 批量初始化(预热缓存)
179
+ * 并行检测多个 Token 并缓存结果
180
+ *
181
+ * @param tokenAddresses - Token 地址列表
182
+ * @returns 检测结果数组
183
+ */
184
+ initialize(tokenAddresses: string[]): Promise<TokenDetectionResult[]>;
185
+ /**
186
+ * 清除缓存
187
+ *
188
+ * @param tokenAddress - 可选,指定要清除的 Token 地址
189
+ */
190
+ clearCache(tokenAddress?: string): Promise<void>;
191
+ /**
192
+ * 获取缓存统计
193
+ *
194
+ * @returns 缓存统计信息
195
+ */
196
+ getCacheStats(): {
197
+ size: number;
198
+ keys: string[];
199
+ };
200
+ /**
201
+ * 生成缓存键
202
+ *
203
+ * @param tokenAddress - Token 地址
204
+ * @returns 缓存键
205
+ */
206
+ private getCacheKey;
207
+ }
208
+
209
+ export { EIP1822_IMPLEMENTATION_SLOT, EIP1967_IMPLEMENTATION_SLOT, EIP2612_PERMIT, EIP3009_SIGNATURES, type Logger, PERMIT2_ADDRESS, PRESET_TOKEN_CAPABILITIES, type PaymentMethod, type PresetTokenConfig, type TokenDetectionResult, TokenDetector, type TokenDetectorOptions, type TokenInfo, type TokenPaymentCapabilities, detectTokenPaymentMethods, getImplementationAddress, getRecommendedPaymentMethod, getTokenInfo };
@@ -0,0 +1,453 @@
1
+ // src/constants.ts
2
+ var EIP3009_SIGNATURES = ["0xe3ee160e", "0xcf092995"];
3
+ var EIP2612_PERMIT = "0xd505accf";
4
+ var PERMIT2_ADDRESS = "0x000000000022D473030F116dDEE9F6B43aC78BA3";
5
+ var EIP1967_IMPLEMENTATION_SLOT = "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc";
6
+ var EIP1822_IMPLEMENTATION_SLOT = "0x7050c9e0f4ca769c69bd3a8ef740bc37934f8e2c036e5a723fd8ee048ed3f8c3";
7
+ var PRESET_TOKEN_CAPABILITIES = {
8
+ // World Liberty Financial USD - 只支持 permit
9
+ "0x8d0d000ee44948fc98c9b98a4fa4921476f08b0d": {
10
+ supportedMethods: ["permit"],
11
+ supportedNetworks: [56],
12
+ // BSC
13
+ description: "World Liberty Financial USD (WLFI)"
14
+ }
15
+ // 可以继续添加更多预设代币
16
+ // 示例:
17
+ // "0x其他代币地址": {
18
+ // supportedMethods: ["eip3009", "permit"],
19
+ // supportedNetworks: [1, 56],
20
+ // description: "代币名称",
21
+ // },
22
+ };
23
+
24
+ // src/proxy.ts
25
+ var defaultLogger = {
26
+ log: (message) => console.log(message),
27
+ error: (message, error) => console.error(message, error)
28
+ };
29
+ async function getImplementationAddress(client, proxyAddress, logger = defaultLogger) {
30
+ try {
31
+ try {
32
+ const implSlotData = await client.getStorageAt({
33
+ address: proxyAddress,
34
+ slot: EIP1967_IMPLEMENTATION_SLOT
35
+ });
36
+ if (implSlotData && implSlotData !== "0x0000000000000000000000000000000000000000000000000000000000000000") {
37
+ const implAddress = `0x${implSlotData.slice(-40)}`;
38
+ if (implAddress !== "0x0000000000000000000000000000000000000000") {
39
+ logger == null ? void 0 : logger.log(` \u{1F4E6} Detected EIP-1967 proxy, implementation: ${implAddress}`);
40
+ return implAddress;
41
+ }
42
+ }
43
+ } catch {
44
+ }
45
+ try {
46
+ const uupsSlotData = await client.getStorageAt({
47
+ address: proxyAddress,
48
+ slot: EIP1822_IMPLEMENTATION_SLOT
49
+ });
50
+ if (uupsSlotData && uupsSlotData !== "0x0000000000000000000000000000000000000000000000000000000000000000") {
51
+ const implAddress = `0x${uupsSlotData.slice(-40)}`;
52
+ if (implAddress !== "0x0000000000000000000000000000000000000000") {
53
+ logger == null ? void 0 : logger.log(` \u{1F4E6} Detected EIP-1822 UUPS proxy, implementation: ${implAddress}`);
54
+ return implAddress;
55
+ }
56
+ }
57
+ } catch {
58
+ }
59
+ try {
60
+ const implABI = [
61
+ {
62
+ inputs: [],
63
+ name: "implementation",
64
+ outputs: [{ name: "", type: "address" }],
65
+ stateMutability: "view",
66
+ type: "function"
67
+ }
68
+ ];
69
+ const implAddress = await client.readContract({
70
+ address: proxyAddress,
71
+ abi: implABI,
72
+ functionName: "implementation"
73
+ });
74
+ if (implAddress && implAddress !== "0x0000000000000000000000000000000000000000") {
75
+ logger == null ? void 0 : logger.log(` \u{1F4E6} Detected proxy via implementation(), implementation: ${implAddress}`);
76
+ return implAddress;
77
+ }
78
+ } catch {
79
+ }
80
+ return null;
81
+ } catch (error) {
82
+ logger == null ? void 0 : logger.error("Error detecting proxy implementation:", error);
83
+ return null;
84
+ }
85
+ }
86
+
87
+ // src/detector.ts
88
+ var defaultLogger2 = {
89
+ log: (message) => console.log(message),
90
+ error: (message, error) => console.error(message, error)
91
+ };
92
+ async function hasMethod(client, tokenAddress, methodSelector, logger = defaultLogger2) {
93
+ try {
94
+ const code = await client.getCode({ address: tokenAddress });
95
+ if (!code) return false;
96
+ const hasMethodInProxy = code.toLowerCase().includes(methodSelector.slice(2).toLowerCase());
97
+ if (hasMethodInProxy) {
98
+ return true;
99
+ }
100
+ const implAddress = await getImplementationAddress(client, tokenAddress, logger);
101
+ if (implAddress) {
102
+ const implCode = await client.getCode({ address: implAddress });
103
+ if (implCode) {
104
+ const hasMethodInImpl = implCode.toLowerCase().includes(methodSelector.slice(2).toLowerCase());
105
+ if (hasMethodInImpl) {
106
+ logger == null ? void 0 : logger.log(` \u2705 Method ${methodSelector} found in implementation contract`);
107
+ }
108
+ return hasMethodInImpl;
109
+ }
110
+ }
111
+ return false;
112
+ } catch (error) {
113
+ logger == null ? void 0 : logger.error(`Error checking method ${methodSelector}:`, error);
114
+ return false;
115
+ }
116
+ }
117
+ async function hasAnyMethod(client, tokenAddress, methodSelectors, logger = defaultLogger2) {
118
+ try {
119
+ const code = await client.getCode({ address: tokenAddress });
120
+ if (!code) return false;
121
+ const codeLower = code.toLowerCase();
122
+ const hasMethodInProxy = methodSelectors.some(
123
+ (selector) => codeLower.includes(selector.slice(2).toLowerCase())
124
+ );
125
+ if (hasMethodInProxy) {
126
+ return true;
127
+ }
128
+ const implAddress = await getImplementationAddress(client, tokenAddress, logger);
129
+ if (implAddress) {
130
+ const implCode = await client.getCode({ address: implAddress });
131
+ if (implCode) {
132
+ const implCodeLower = implCode.toLowerCase();
133
+ const hasMethodInImpl = methodSelectors.some(
134
+ (selector) => implCodeLower.includes(selector.slice(2).toLowerCase())
135
+ );
136
+ if (hasMethodInImpl) {
137
+ logger == null ? void 0 : logger.log(` \u2705 Method(s) found in implementation contract`);
138
+ }
139
+ return hasMethodInImpl;
140
+ }
141
+ }
142
+ return false;
143
+ } catch (error) {
144
+ logger == null ? void 0 : logger.error(`Error checking methods ${methodSelectors.join(", ")}:`, error);
145
+ return false;
146
+ }
147
+ }
148
+ async function checkPermit2Support(client, logger = defaultLogger2) {
149
+ try {
150
+ const permit2Code = await client.getCode({ address: PERMIT2_ADDRESS });
151
+ if (!permit2Code) return false;
152
+ return true;
153
+ } catch (error) {
154
+ logger == null ? void 0 : logger.error("Error checking Permit2 support:", error);
155
+ return false;
156
+ }
157
+ }
158
+ async function detectTokenPaymentMethods(tokenAddress, client, logger = defaultLogger2) {
159
+ const address = tokenAddress.toLowerCase();
160
+ const chainId = await client.getChainId();
161
+ const presetCapabilities = PRESET_TOKEN_CAPABILITIES[address];
162
+ if (presetCapabilities) {
163
+ if (!chainId || !presetCapabilities.supportedNetworks.includes(chainId)) {
164
+ return {
165
+ address,
166
+ supportedMethods: [],
167
+ details: {
168
+ hasEIP3009: false,
169
+ hasPermit: false,
170
+ hasPermit2Approval: false
171
+ }
172
+ };
173
+ }
174
+ const hasEIP30092 = presetCapabilities.supportedMethods.includes("eip3009");
175
+ const hasPermit2 = presetCapabilities.supportedMethods.includes("permit");
176
+ const hasPermit2Approval2 = presetCapabilities.supportedMethods.includes("permit2") || presetCapabilities.supportedMethods.includes("permit2-witness");
177
+ if (hasEIP30092) {
178
+ logger == null ? void 0 : logger.log(" \u2705 EIP-3009 (transferWithAuthorization) - from preset");
179
+ }
180
+ if (hasPermit2) {
181
+ logger == null ? void 0 : logger.log(" \u2705 EIP-2612 (permit) - from preset");
182
+ }
183
+ if (hasPermit2Approval2) {
184
+ logger == null ? void 0 : logger.log(" \u2705 Permit2 support - from preset");
185
+ }
186
+ return {
187
+ address,
188
+ supportedMethods: presetCapabilities.supportedMethods,
189
+ details: {
190
+ hasEIP3009: hasEIP30092,
191
+ hasPermit: hasPermit2,
192
+ hasPermit2Approval: hasPermit2Approval2
193
+ }
194
+ };
195
+ }
196
+ logger == null ? void 0 : logger.log(`\u{1F50D} Detecting payment methods for token ${address}...`);
197
+ const [hasEIP3009, hasPermit, hasPermit2Approval] = await Promise.all([
198
+ hasAnyMethod(client, address, EIP3009_SIGNATURES, logger),
199
+ hasMethod(client, address, EIP2612_PERMIT, logger),
200
+ checkPermit2Support(client, logger)
201
+ ]);
202
+ const supportedMethods = [];
203
+ if (hasEIP3009) {
204
+ supportedMethods.push("eip3009");
205
+ logger == null ? void 0 : logger.log(" \u2705 EIP-3009 (transferWithAuthorization) detected");
206
+ }
207
+ if (hasPermit) {
208
+ supportedMethods.push("permit");
209
+ logger == null ? void 0 : logger.log(" \u2705 EIP-2612 (permit) detected");
210
+ }
211
+ if (hasPermit2Approval) {
212
+ supportedMethods.push("permit2");
213
+ supportedMethods.push("permit2-witness");
214
+ logger == null ? void 0 : logger.log(" \u2705 Permit2 support available (universal)");
215
+ }
216
+ if (supportedMethods.length === 0) {
217
+ logger == null ? void 0 : logger.log(" \u26A0\uFE0F No advanced payment methods detected (standard ERC-20 only)");
218
+ }
219
+ return {
220
+ address,
221
+ supportedMethods,
222
+ details: {
223
+ hasEIP3009,
224
+ hasPermit,
225
+ hasPermit2Approval
226
+ }
227
+ };
228
+ }
229
+ async function getRecommendedPaymentMethod(tokenAddress, client, logger = defaultLogger2) {
230
+ const capabilities = await detectTokenPaymentMethods(tokenAddress, client, logger);
231
+ const { supportedMethods } = capabilities;
232
+ if (supportedMethods.includes("eip3009")) return "eip3009";
233
+ if (supportedMethods.includes("permit")) return "permit";
234
+ if (supportedMethods.includes("permit2") || supportedMethods.includes("permit2-witness")) {
235
+ return "permit2";
236
+ }
237
+ return null;
238
+ }
239
+ async function getTokenInfo(tokenAddress, client, logger = defaultLogger2) {
240
+ const address = tokenAddress.toLowerCase();
241
+ const erc20ABI = [
242
+ {
243
+ inputs: [],
244
+ name: "name",
245
+ outputs: [{ name: "", type: "string" }],
246
+ stateMutability: "view",
247
+ type: "function"
248
+ }
249
+ ];
250
+ const eip712DomainABI = [
251
+ {
252
+ inputs: [],
253
+ name: "eip712Domain",
254
+ outputs: [
255
+ { name: "fields", type: "bytes1" },
256
+ { name: "name", type: "string" },
257
+ { name: "version", type: "string" },
258
+ { name: "chainId", type: "uint256" },
259
+ { name: "verifyingContract", type: "address" },
260
+ { name: "salt", type: "bytes32" },
261
+ { name: "extensions", type: "uint256[]" }
262
+ ],
263
+ stateMutability: "view",
264
+ type: "function"
265
+ }
266
+ ];
267
+ const versionABI = [
268
+ {
269
+ inputs: [],
270
+ name: "version",
271
+ outputs: [{ name: "", type: "string" }],
272
+ stateMutability: "view",
273
+ type: "function"
274
+ }
275
+ ];
276
+ try {
277
+ const implAddress = await getImplementationAddress(client, address, logger);
278
+ if (implAddress) {
279
+ logger == null ? void 0 : logger.log(
280
+ ` \u{1F4E6} Reading token info from proxy, actual calls will be delegated to implementation`
281
+ );
282
+ }
283
+ const name = await client.readContract({
284
+ address,
285
+ abi: erc20ABI,
286
+ functionName: "name"
287
+ });
288
+ let version = "1";
289
+ try {
290
+ const result = await client.readContract({
291
+ address,
292
+ abi: eip712DomainABI,
293
+ functionName: "eip712Domain"
294
+ });
295
+ version = result[2];
296
+ } catch {
297
+ try {
298
+ version = await client.readContract({
299
+ address,
300
+ abi: versionABI,
301
+ functionName: "version"
302
+ });
303
+ } catch {
304
+ logger == null ? void 0 : logger.log(` \u2139\uFE0F Using default version "1" for token ${address}`);
305
+ }
306
+ }
307
+ return {
308
+ name,
309
+ version
310
+ };
311
+ } catch (error) {
312
+ logger == null ? void 0 : logger.error(`Error getting token info for ${address}:`, error);
313
+ throw new Error(`Failed to get token info: ${error}`);
314
+ }
315
+ }
316
+
317
+ // src/cache.ts
318
+ var defaultLogger3 = {
319
+ log: (message) => console.log(message),
320
+ error: (message, error) => console.error(message, error)
321
+ };
322
+ var TokenDetector = class {
323
+ /**
324
+ * 构造函数
325
+ *
326
+ * @param client - viem PublicClient
327
+ * @param options - 可选配置
328
+ */
329
+ constructor(client, options) {
330
+ /** 缓存存储 (chainId:address -> TokenDetectionResult) */
331
+ this.cache = /* @__PURE__ */ new Map();
332
+ this.client = client;
333
+ this.logger = (options == null ? void 0 : options.logger) === null ? null : (options == null ? void 0 : options.logger) || defaultLogger3;
334
+ }
335
+ /**
336
+ * 完整检测(同时获取支付能力和 Token 信息)
337
+ * 优先从缓存读取,缓存未命中时执行检测并缓存结果
338
+ *
339
+ * @param tokenAddress - Token 地址
340
+ * @returns 完整的检测结果
341
+ */
342
+ async detect(tokenAddress) {
343
+ var _a, _b;
344
+ const cacheKey = await this.getCacheKey(tokenAddress);
345
+ const cached = this.cache.get(cacheKey);
346
+ if (cached) {
347
+ (_a = this.logger) == null ? void 0 : _a.log(`\u{1F4BE} Using cached result for token ${tokenAddress}`);
348
+ return cached;
349
+ }
350
+ (_b = this.logger) == null ? void 0 : _b.log(`\u{1F50D} Detecting token ${tokenAddress}...`);
351
+ const [capabilities, info] = await Promise.all([
352
+ detectTokenPaymentMethods(tokenAddress, this.client, this.logger),
353
+ getTokenInfo(tokenAddress, this.client, this.logger)
354
+ ]);
355
+ const result = {
356
+ ...capabilities,
357
+ ...info
358
+ };
359
+ this.cache.set(cacheKey, result);
360
+ return result;
361
+ }
362
+ /**
363
+ * 获取推荐的支付方式
364
+ * 优先级:eip3009 > permit > permit2
365
+ *
366
+ * @param tokenAddress - Token 地址
367
+ * @returns 推荐的支付方式
368
+ */
369
+ async getRecommendedMethod(tokenAddress) {
370
+ const result = await this.detect(tokenAddress);
371
+ const { supportedMethods } = result;
372
+ if (supportedMethods.includes("eip3009")) return "eip3009";
373
+ if (supportedMethods.includes("permit")) return "permit";
374
+ if (supportedMethods.includes("permit2") || supportedMethods.includes("permit2-witness")) {
375
+ return "permit2";
376
+ }
377
+ return null;
378
+ }
379
+ /**
380
+ * 批量初始化(预热缓存)
381
+ * 并行检测多个 Token 并缓存结果
382
+ *
383
+ * @param tokenAddresses - Token 地址列表
384
+ * @returns 检测结果数组
385
+ */
386
+ async initialize(tokenAddresses) {
387
+ var _a, _b;
388
+ (_a = this.logger) == null ? void 0 : _a.log(`\u{1F525} Warming up cache for ${tokenAddresses.length} tokens...`);
389
+ const results = await Promise.all(
390
+ tokenAddresses.map(
391
+ (address) => this.detect(address).catch((error) => {
392
+ var _a2;
393
+ (_a2 = this.logger) == null ? void 0 : _a2.error(`Failed to detect token ${address}:`, error);
394
+ return null;
395
+ })
396
+ )
397
+ );
398
+ const successCount = results.filter((r) => r !== null).length;
399
+ (_b = this.logger) == null ? void 0 : _b.log(`\u2705 Successfully detected ${successCount}/${tokenAddresses.length} tokens`);
400
+ return results.filter((r) => r !== null);
401
+ }
402
+ /**
403
+ * 清除缓存
404
+ *
405
+ * @param tokenAddress - 可选,指定要清除的 Token 地址
406
+ */
407
+ async clearCache(tokenAddress) {
408
+ var _a, _b;
409
+ if (tokenAddress) {
410
+ const cacheKey = await this.getCacheKey(tokenAddress);
411
+ this.cache.delete(cacheKey);
412
+ (_a = this.logger) == null ? void 0 : _a.log(`\u{1F5D1}\uFE0F Cleared cache for token ${tokenAddress}`);
413
+ } else {
414
+ this.cache.clear();
415
+ (_b = this.logger) == null ? void 0 : _b.log(`\u{1F5D1}\uFE0F Cleared all cache`);
416
+ }
417
+ }
418
+ /**
419
+ * 获取缓存统计
420
+ *
421
+ * @returns 缓存统计信息
422
+ */
423
+ getCacheStats() {
424
+ return {
425
+ size: this.cache.size,
426
+ keys: Array.from(this.cache.keys())
427
+ };
428
+ }
429
+ /**
430
+ * 生成缓存键
431
+ *
432
+ * @param tokenAddress - Token 地址
433
+ * @returns 缓存键
434
+ */
435
+ async getCacheKey(tokenAddress) {
436
+ const chainId = await this.client.getChainId();
437
+ return `${chainId}:${tokenAddress.toLowerCase()}`;
438
+ }
439
+ };
440
+ export {
441
+ EIP1822_IMPLEMENTATION_SLOT,
442
+ EIP1967_IMPLEMENTATION_SLOT,
443
+ EIP2612_PERMIT,
444
+ EIP3009_SIGNATURES,
445
+ PERMIT2_ADDRESS,
446
+ PRESET_TOKEN_CAPABILITIES,
447
+ TokenDetector,
448
+ detectTokenPaymentMethods,
449
+ getImplementationAddress,
450
+ getRecommendedPaymentMethod,
451
+ getTokenInfo
452
+ };
453
+ //# sourceMappingURL=index.mjs.map