@wtflabs/x402-server 0.0.1-beta.3 → 0.0.1-beta.4
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/index.d.mts +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +99 -3
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +99 -3
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
package/dist/index.d.mts
CHANGED
|
@@ -39,7 +39,7 @@ interface VerifyResult {
|
|
|
39
39
|
*/
|
|
40
40
|
interface SettleResult {
|
|
41
41
|
success: boolean;
|
|
42
|
-
|
|
42
|
+
transaction?: string;
|
|
43
43
|
error?: string;
|
|
44
44
|
}
|
|
45
45
|
|
|
@@ -212,6 +212,7 @@ declare function detectTokenPaymentMethods(tokenAddress: string, client: PublicC
|
|
|
212
212
|
declare function getRecommendedPaymentMethod(capabilities: TokenPaymentCapabilities): "eip3009" | "permit2" | "permit" | null;
|
|
213
213
|
/**
|
|
214
214
|
* 获取 token 的 name 和 version 信息(用于 EIP-712 签名)
|
|
215
|
+
* 支持代理合约(会自动从代理合约读取,因为代理合约会 delegatecall 到实现合约)
|
|
215
216
|
* @param tokenAddress 代币地址
|
|
216
217
|
* @param client viem PublicClient
|
|
217
218
|
* @returns Token 的 name 和 version
|
package/dist/index.d.ts
CHANGED
|
@@ -39,7 +39,7 @@ interface VerifyResult {
|
|
|
39
39
|
*/
|
|
40
40
|
interface SettleResult {
|
|
41
41
|
success: boolean;
|
|
42
|
-
|
|
42
|
+
transaction?: string;
|
|
43
43
|
error?: string;
|
|
44
44
|
}
|
|
45
45
|
|
|
@@ -212,6 +212,7 @@ declare function detectTokenPaymentMethods(tokenAddress: string, client: PublicC
|
|
|
212
212
|
declare function getRecommendedPaymentMethod(capabilities: TokenPaymentCapabilities): "eip3009" | "permit2" | "permit" | null;
|
|
213
213
|
/**
|
|
214
214
|
* 获取 token 的 name 和 version 信息(用于 EIP-712 签名)
|
|
215
|
+
* 支持代理合约(会自动从代理合约读取,因为代理合约会 delegatecall 到实现合约)
|
|
215
216
|
* @param tokenAddress 代币地址
|
|
216
217
|
* @param client viem PublicClient
|
|
217
218
|
* @returns Token 的 name 和 version
|
package/dist/index.js
CHANGED
|
@@ -31,11 +31,85 @@ module.exports = __toCommonJS(index_exports);
|
|
|
31
31
|
var EIP3009_SIGNATURES = ["0xe3ee160e", "0xcf092995"];
|
|
32
32
|
var EIP2612_PERMIT = "0xd505accf";
|
|
33
33
|
var PERMIT2_ADDRESS = "0x000000000022D473030F116dDEE9F6B43aC78BA3";
|
|
34
|
+
var EIP1967_IMPLEMENTATION_SLOT = "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc";
|
|
35
|
+
var EIP1822_IMPLEMENTATION_SLOT = "0x7050c9e0f4ca769c69bd3a8ef740bc37934f8e2c036e5a723fd8ee048ed3f8c3";
|
|
36
|
+
async function getImplementationAddress(client, proxyAddress) {
|
|
37
|
+
try {
|
|
38
|
+
try {
|
|
39
|
+
const implSlotData = await client.getStorageAt({
|
|
40
|
+
address: proxyAddress,
|
|
41
|
+
slot: EIP1967_IMPLEMENTATION_SLOT
|
|
42
|
+
});
|
|
43
|
+
if (implSlotData && implSlotData !== "0x0000000000000000000000000000000000000000000000000000000000000000") {
|
|
44
|
+
const implAddress = `0x${implSlotData.slice(-40)}`;
|
|
45
|
+
if (implAddress !== "0x0000000000000000000000000000000000000000") {
|
|
46
|
+
console.log(` \u{1F4E6} Detected EIP-1967 proxy, implementation: ${implAddress}`);
|
|
47
|
+
return implAddress;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
} catch {
|
|
51
|
+
}
|
|
52
|
+
try {
|
|
53
|
+
const uupsSlotData = await client.getStorageAt({
|
|
54
|
+
address: proxyAddress,
|
|
55
|
+
slot: EIP1822_IMPLEMENTATION_SLOT
|
|
56
|
+
});
|
|
57
|
+
if (uupsSlotData && uupsSlotData !== "0x0000000000000000000000000000000000000000000000000000000000000000") {
|
|
58
|
+
const implAddress = `0x${uupsSlotData.slice(-40)}`;
|
|
59
|
+
if (implAddress !== "0x0000000000000000000000000000000000000000") {
|
|
60
|
+
console.log(` \u{1F4E6} Detected EIP-1822 UUPS proxy, implementation: ${implAddress}`);
|
|
61
|
+
return implAddress;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
} catch {
|
|
65
|
+
}
|
|
66
|
+
try {
|
|
67
|
+
const implABI = [
|
|
68
|
+
{
|
|
69
|
+
inputs: [],
|
|
70
|
+
name: "implementation",
|
|
71
|
+
outputs: [{ name: "", type: "address" }],
|
|
72
|
+
stateMutability: "view",
|
|
73
|
+
type: "function"
|
|
74
|
+
}
|
|
75
|
+
];
|
|
76
|
+
const implAddress = await client.readContract({
|
|
77
|
+
address: proxyAddress,
|
|
78
|
+
abi: implABI,
|
|
79
|
+
functionName: "implementation"
|
|
80
|
+
});
|
|
81
|
+
if (implAddress && implAddress !== "0x0000000000000000000000000000000000000000") {
|
|
82
|
+
console.log(` \u{1F4E6} Detected proxy via implementation(), implementation: ${implAddress}`);
|
|
83
|
+
return implAddress;
|
|
84
|
+
}
|
|
85
|
+
} catch {
|
|
86
|
+
}
|
|
87
|
+
return null;
|
|
88
|
+
} catch (error) {
|
|
89
|
+
console.error("Error detecting proxy implementation:", error);
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
34
93
|
async function hasMethod(client, tokenAddress, methodSelector) {
|
|
35
94
|
try {
|
|
36
95
|
const code = await client.getBytecode({ address: tokenAddress });
|
|
37
96
|
if (!code) return false;
|
|
38
|
-
|
|
97
|
+
const hasMethodInProxy = code.toLowerCase().includes(methodSelector.slice(2).toLowerCase());
|
|
98
|
+
if (hasMethodInProxy) {
|
|
99
|
+
return true;
|
|
100
|
+
}
|
|
101
|
+
const implAddress = await getImplementationAddress(client, tokenAddress);
|
|
102
|
+
if (implAddress) {
|
|
103
|
+
const implCode = await client.getBytecode({ address: implAddress });
|
|
104
|
+
if (implCode) {
|
|
105
|
+
const hasMethodInImpl = implCode.toLowerCase().includes(methodSelector.slice(2).toLowerCase());
|
|
106
|
+
if (hasMethodInImpl) {
|
|
107
|
+
console.log(` \u2705 Method ${methodSelector} found in implementation contract`);
|
|
108
|
+
}
|
|
109
|
+
return hasMethodInImpl;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return false;
|
|
39
113
|
} catch (error) {
|
|
40
114
|
console.error(`Error checking method ${methodSelector}:`, error);
|
|
41
115
|
return false;
|
|
@@ -46,9 +120,27 @@ async function hasAnyMethod(client, tokenAddress, methodSelectors) {
|
|
|
46
120
|
const code = await client.getBytecode({ address: tokenAddress });
|
|
47
121
|
if (!code) return false;
|
|
48
122
|
const codeLower = code.toLowerCase();
|
|
49
|
-
|
|
123
|
+
const hasMethodInProxy = methodSelectors.some(
|
|
50
124
|
(selector) => codeLower.includes(selector.slice(2).toLowerCase())
|
|
51
125
|
);
|
|
126
|
+
if (hasMethodInProxy) {
|
|
127
|
+
return true;
|
|
128
|
+
}
|
|
129
|
+
const implAddress = await getImplementationAddress(client, tokenAddress);
|
|
130
|
+
if (implAddress) {
|
|
131
|
+
const implCode = await client.getBytecode({ address: implAddress });
|
|
132
|
+
if (implCode) {
|
|
133
|
+
const implCodeLower = implCode.toLowerCase();
|
|
134
|
+
const hasMethodInImpl = methodSelectors.some(
|
|
135
|
+
(selector) => implCodeLower.includes(selector.slice(2).toLowerCase())
|
|
136
|
+
);
|
|
137
|
+
if (hasMethodInImpl) {
|
|
138
|
+
console.log(` \u2705 Method(s) found in implementation contract`);
|
|
139
|
+
}
|
|
140
|
+
return hasMethodInImpl;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
return false;
|
|
52
144
|
} catch (error) {
|
|
53
145
|
console.error(`Error checking methods ${methodSelectors.join(", ")}:`, error);
|
|
54
146
|
return false;
|
|
@@ -146,6 +238,10 @@ async function getTokenInfo(tokenAddress, client) {
|
|
|
146
238
|
}
|
|
147
239
|
];
|
|
148
240
|
try {
|
|
241
|
+
const implAddress = await getImplementationAddress(client, address);
|
|
242
|
+
if (implAddress) {
|
|
243
|
+
console.log(` \u{1F4E6} Reading token info from proxy, actual calls will be delegated to implementation`);
|
|
244
|
+
}
|
|
149
245
|
const name = await client.readContract({
|
|
150
246
|
address,
|
|
151
247
|
abi: erc20ABI,
|
|
@@ -359,7 +455,7 @@ var X402Server = class {
|
|
|
359
455
|
}
|
|
360
456
|
return {
|
|
361
457
|
success: true,
|
|
362
|
-
|
|
458
|
+
transaction: result.transaction
|
|
363
459
|
};
|
|
364
460
|
} catch (error) {
|
|
365
461
|
return {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/token-detection.ts","../src/server.ts"],"sourcesContent":["export { X402Server } from \"./server\";\nexport * from \"./types\";\nexport * from \"./token-detection\";\n\n","import type { Address, PublicClient } from \"viem\";\n\n/**\n * Token 信息\n */\nexport interface TokenInfo {\n name: string;\n version: string;\n}\n\n/**\n * 支持的支付方式\n */\nexport type PaymentMethod = \"eip3009\" | \"permit\" | \"permit2\" | \"permit2-witness\";\n\n/**\n * 检测结果\n */\nexport interface TokenPaymentCapabilities {\n address: string;\n supportedMethods: PaymentMethod[];\n details: {\n hasEIP3009: boolean;\n hasPermit: boolean;\n hasPermit2Approval: boolean;\n };\n}\n\n/**\n * EIP-3009 方法签名\n * - transferWithAuthorization(address,address,uint256,uint256,uint256,bytes32,uint8,bytes32,bytes32)\n * \n * 支持多个方法签名变体,以兼容不同的实现:\n * - 0xe3ee160e: 标准 EIP-3009 实现\n * - 0xcf092995: 某些代币的替代实现\n */\nconst EIP3009_SIGNATURES = [\"0xe3ee160e\", \"0xcf092995\"] as const;\n\n/**\n * EIP-2612 Permit 方法签名\n * - permit(address,address,uint256,uint256,uint8,bytes32,bytes32)\n */\nconst EIP2612_PERMIT = \"0xd505accf\" as const;\n\n/**\n * Uniswap Permit2 合约地址(所有链相同)\n */\nconst PERMIT2_ADDRESS = \"0x000000000022D473030F116dDEE9F6B43aC78BA3\" as const;\n\n/**\n * 检查合约是否支持某个方法(通过字节码检查)\n */\nasync function hasMethod(\n client: PublicClient,\n tokenAddress: Address,\n methodSelector: string\n): Promise<boolean> {\n try {\n // 尝试获取合约代码\n const code = await client.getBytecode({ address: tokenAddress });\n if (!code) return false;\n\n // 检查字节码中是否包含方法选择器\n return code.toLowerCase().includes(methodSelector.slice(2).toLowerCase());\n } catch (error) {\n console.error(`Error checking method ${methodSelector}:`, error);\n return false;\n }\n}\n\n/**\n * 检查合约是否支持多个方法签名中的任意一个\n */\nasync function hasAnyMethod(\n client: PublicClient,\n tokenAddress: Address,\n methodSelectors: readonly string[]\n): Promise<boolean> {\n try {\n // 尝试获取合约代码\n const code = await client.getBytecode({ address: tokenAddress });\n if (!code) return false;\n\n const codeLower = code.toLowerCase();\n\n // 检查是否包含任何一个方法选择器\n return methodSelectors.some(selector =>\n codeLower.includes(selector.slice(2).toLowerCase())\n );\n } catch (error) {\n console.error(`Error checking methods ${methodSelectors.join(\", \")}:`, error);\n return false;\n }\n}\n\n/**\n * 检查 Permit2 合约是否在该链上部署\n */\nasync function checkPermit2Support(client: PublicClient): Promise<boolean> {\n try {\n // 检查 Permit2 合约是否在该链上部署\n const permit2Code = await client.getBytecode({ address: PERMIT2_ADDRESS });\n if (!permit2Code) return false;\n\n // 如果 Permit2 存在,理论上任何 ERC-20 都可以使用它\n return true;\n } catch (error) {\n console.error(\"Error checking Permit2 support:\", error);\n return false;\n }\n}\n\n/**\n * 检测代币支持的支付方式\n * @param tokenAddress 代币地址\n * @param client viem PublicClient\n * @returns 检测结果\n */\nexport async function detectTokenPaymentMethods(\n tokenAddress: string,\n client: PublicClient\n): Promise<TokenPaymentCapabilities> {\n const address = tokenAddress.toLowerCase() as Address;\n\n console.log(`🔍 Detecting payment methods for token ${address}...`);\n\n // 并行检测所有方法\n const [hasEIP3009, hasPermit, hasPermit2Approval] = await Promise.all([\n hasAnyMethod(client, address, EIP3009_SIGNATURES),\n hasMethod(client, address, EIP2612_PERMIT),\n checkPermit2Support(client),\n ]);\n\n // 构建支持的方法列表\n const supportedMethods: PaymentMethod[] = [];\n\n if (hasEIP3009) {\n supportedMethods.push(\"eip3009\");\n console.log(\" ✅ EIP-3009 (transferWithAuthorization) detected\");\n }\n\n if (hasPermit) {\n supportedMethods.push(\"permit\");\n console.log(\" ✅ EIP-2612 (permit) detected\");\n }\n\n if (hasPermit2Approval) {\n supportedMethods.push(\"permit2\");\n supportedMethods.push(\"permit2-witness\");\n console.log(\" ✅ Permit2 support available (universal)\");\n }\n\n if (supportedMethods.length === 0) {\n console.log(\" ⚠️ No advanced payment methods detected (standard ERC-20 only)\");\n }\n\n return {\n address,\n supportedMethods,\n details: {\n hasEIP3009,\n hasPermit,\n hasPermit2Approval,\n },\n };\n}\n\n/**\n * 获取推荐的支付方式(仅返回 schema 支持的类型)\n * 按优先级排序:eip3009 > permit > permit2\n * 注意:permit2-witness 会被映射为 permit2,因为它们在 schema 中是同一种支付类型\n */\nexport function getRecommendedPaymentMethod(\n capabilities: TokenPaymentCapabilities\n): \"eip3009\" | \"permit2\" | \"permit\" | null {\n const { supportedMethods } = capabilities;\n\n if (supportedMethods.includes(\"eip3009\")) return \"eip3009\";\n if (supportedMethods.includes(\"permit\")) return \"permit\";\n // permit2 和 permit2-witness 都映射为 permit2(schema 只支持 permit2)\n if (supportedMethods.includes(\"permit2\") || supportedMethods.includes(\"permit2-witness\")) {\n return \"permit2\";\n }\n\n return null;\n}\n\n/**\n * 获取 token 的 name 和 version 信息(用于 EIP-712 签名)\n * @param tokenAddress 代币地址\n * @param client viem PublicClient\n * @returns Token 的 name 和 version\n */\nexport async function getTokenInfo(\n tokenAddress: string,\n client: PublicClient\n): Promise<TokenInfo> {\n const address = tokenAddress.toLowerCase() as Address;\n\n // ERC-20 标准 ABI\n const erc20ABI = [\n {\n inputs: [],\n name: \"name\",\n outputs: [{ name: \"\", type: \"string\" }],\n stateMutability: \"view\",\n type: \"function\",\n },\n ] as const;\n\n // EIP-5267 eip712Domain ABI(OpenZeppelin v5+)\n const eip712DomainABI = [\n {\n inputs: [],\n name: \"eip712Domain\",\n outputs: [\n { name: \"fields\", type: \"bytes1\" },\n { name: \"name\", type: \"string\" },\n { name: \"version\", type: \"string\" },\n { name: \"chainId\", type: \"uint256\" },\n { name: \"verifyingContract\", type: \"address\" },\n { name: \"salt\", type: \"bytes32\" },\n { name: \"extensions\", type: \"uint256[]\" },\n ],\n stateMutability: \"view\",\n type: \"function\",\n },\n ] as const;\n\n // version() ABI(OpenZeppelin v4)\n const versionABI = [\n {\n inputs: [],\n name: \"version\",\n outputs: [{ name: \"\", type: \"string\" }],\n stateMutability: \"view\",\n type: \"function\",\n },\n ] as const;\n\n try {\n // 获取 token name\n const name = await client.readContract({\n address,\n abi: erc20ABI,\n functionName: \"name\",\n });\n\n // 尝试获取 version,优先使用 EIP-5267\n let version = \"1\"; // 默认版本\n try {\n const result = await client.readContract({\n address,\n abi: eip712DomainABI,\n functionName: \"eip712Domain\",\n });\n // eip712Domain 返回 [fields, name, version, chainId, verifyingContract, salt, extensions]\n version = result[2] as string; // version 是第 3 个元素(索引 2)\n } catch {\n // 回退到 version() 函数(OpenZeppelin v4)\n try {\n version = await client.readContract({\n address,\n abi: versionABI,\n functionName: \"version\",\n });\n } catch {\n // 如果两种方法都不可用,使用默认值 \"1\"\n console.log(` ℹ️ Using default version \"1\" for token ${address}`);\n }\n }\n\n return {\n name: name as string,\n version: version as string,\n };\n } catch (error) {\n console.error(`Error getting token info for ${address}:`, error);\n throw new Error(`Failed to get token info: ${error}`);\n }\n}\n\n","import type { Facilitator } from \"@wtflabs/x402-facilitator\";\nimport type { X402PaymentSchema, X402PaymentSchemaWithExtra } from \"@wtflabs/x402-schema\";\nimport type { PublicClient } from \"viem\";\nimport type {\n InitializeResult,\n SettleResult,\n VerifyResult,\n X402ServerConfig,\n} from \"./types\";\nimport { PaymentPayload, PaymentRequirements } from \"@wtflabs/x402/types\";\nimport { detectTokenPaymentMethods, getRecommendedPaymentMethod, getTokenInfo, type PaymentMethod } from \"./token-detection\";\n\n/**\n * X402Server 类\n * 集成 facilitator, schema 和 client,提供完整的服务端支付处理\n *\n * @example\n * ```typescript\n * import { X402Server } from \"@wtflabs/x402-server\";\n * import { Facilitator } from \"@wtflabs/x402-facilitator\";\n * import { X402PaymentSchema } from \"@wtflabs/x402-schema\";\n * import { createPublicClient, http } from \"viem\";\n * import { bscTestnet } from \"viem/chains\";\n *\n * const facilitator = new Facilitator({\n * recipientAddress: \"0x1234...\",\n * });\n *\n * const schema = new X402PaymentSchema({\n * scheme: \"exact\",\n * network: \"bsc-testnet\",\n * maxAmountRequired: \"100000\",\n * resource: \"http://localhost:3000/protected-resource\",\n * description: \"Access to protected resource\",\n * mimeType: \"application/json\",\n * payTo: \"0x1234...\",\n * maxTimeoutSeconds: 3600,\n * asset: \"0x5678...\",\n * });\n *\n * const client = createPublicClient({\n * chain: bscTestnet,\n * transport: http(),\n * });\n *\n * const server = new X402Server({\n * facilitator,\n * schema,\n * client,\n * });\n *\n * // 初始化和校验\n * await server.initialize();\n *\n * // 验证\n * const verifyResult = await server.verify();\n *\n * // 结算\n * const settleResult = await server.settle(paymentPayload, paymentRequirements);\n * ```\n */\nexport class X402Server {\n private facilitator: Facilitator;\n private schema: X402PaymentSchema;\n private client: PublicClient;\n private initialized: boolean = false;\n\n constructor(config: X402ServerConfig) {\n this.facilitator = config.facilitator;\n this.schema = config.schema;\n this.client = config.client;\n }\n\n /**\n * 初始化服务器\n * 初始化和校验 schema 等数据,对 schema 增加 facilitator 数据 extra: {relayer}\n * 并获取 token 的 name 和 version 信息\n */\n async initialize(): Promise<InitializeResult> {\n try {\n // 验证 schema\n this.schema.verify();\n\n // 获取 token 信息(name 和 version)并添加到 schema extra 中\n const schemaAsset = this.schema.get(\"asset\");\n if (schemaAsset) {\n try {\n const tokenInfo = await getTokenInfo(schemaAsset, this.client);\n this.schema.setExtra({\n relayer: this.facilitator.relayer,\n name: tokenInfo.name,\n version: tokenInfo.version,\n });\n console.log(`✅ Token info retrieved: ${tokenInfo.name} v${tokenInfo.version}`);\n } catch (error) {\n console.warn(`⚠️ Failed to get token info, signatures may fail:`, error);\n // 仍然设置 relayer,但没有 name 和 version\n this.schema.setExtra({\n relayer: this.facilitator.relayer,\n });\n }\n } else {\n // 如果没有 asset,只设置 relayer\n this.schema.setExtra({\n relayer: this.facilitator.relayer,\n });\n }\n\n // TODO 将_verify中的内容内置到initialize中\n const verifyResult = await this._verify();\n if (!verifyResult.success) {\n return {\n success: false,\n error: verifyResult.errors?.[0] || \"Verification failed\",\n };\n }\n\n this.initialized = true;\n return { success: true };\n } catch (error) {\n return {\n success: false,\n error:\n error instanceof Error\n ? error.message\n : \"Initialization failed\",\n };\n }\n }\n\n /**\n * 验证配置\n * 1. 验证 client network 是否和 schema 的 network 匹配\n * 2. 验证 facilitator recipientAddress 和 schema payTo 是否一致\n */\n async _verify(): Promise<VerifyResult> {\n\n const errors: string[] = [];\n\n try {\n // 1. 检测 token 对 permit 和 eip3009 的支持\n const schemaAsset = this.schema.get(\"asset\");\n if (schemaAsset) {\n const tokenCapabilities = await detectTokenPaymentMethods(\n schemaAsset,\n this.client\n );\n\n // 如果 schema 中不存在 paymentType,则根据 tokenCapabilities 自动确定\n // 优先级:eip3009 > permit2 > permit\n const currentPaymentType = this.schema.get(\"paymentType\");\n if (!currentPaymentType) {\n const recommendedMethod = getRecommendedPaymentMethod(tokenCapabilities);\n if (recommendedMethod) {\n this.schema.set(\"paymentType\", recommendedMethod);\n // console.log(`✅ Auto-selected payment method: ${recommendedMethod}`);\n } else {\n errors.push(\n `Token ${schemaAsset} does not support any advanced payment methods (permit, eip3009, permit2). Please specify paymentType manually.`\n );\n }\n } else {\n // 验证 schema 中指定的 paymentType 是否被 token 支持\n if (!tokenCapabilities.supportedMethods.includes(currentPaymentType)) {\n errors.push(\n `Token ${schemaAsset} does not support the specified payment method \"${currentPaymentType}\". Supported methods: ${tokenCapabilities.supportedMethods.join(\", \")}`\n );\n }\n }\n\n // 如果 token 不支持任何高级支付方法,给出警告\n if (tokenCapabilities.supportedMethods.length === 0) {\n errors.push(\n `Token ${schemaAsset} does not support any advanced payment methods (permit, eip3009, permit2)`\n );\n }\n }\n\n // 2. 检查 facilitator 的 /supported 是否包含此代币和链\n const clientChainId = this.client.chain?.id;\n const schemaNetwork = this.schema.get(\"network\");\n\n if (clientChainId && schemaAsset) {\n const facilitatorSupported = await this.facilitator.supported({\n chainId: clientChainId,\n tokenAddress: schemaAsset,\n });\n\n // console.log(\n // `Checking facilitator support for chainId ${clientChainId} and token ${schemaAsset}`\n // );\n\n // 检查 facilitator 是否支持当前的链和代币组合\n const isSupportedByFacilitator = facilitatorSupported.kinds.some(\n (kind) => {\n // 检查网络匹配\n const networkMatches = kind.network === schemaNetwork;\n\n // 检查资产匹配\n const assetsInKind = (kind.extra as any)?.assets || [];\n const assetMatches = assetsInKind.some(\n (asset: any) =>\n asset.address.toLowerCase() === schemaAsset.toLowerCase()\n );\n\n return networkMatches && assetMatches;\n }\n );\n\n if (!isSupportedByFacilitator) {\n errors.push(\n `Facilitator does not support token ${schemaAsset} on network ${schemaNetwork} (chainId: ${clientChainId})`\n );\n } else {\n // console.log(`✅ Facilitator supports this configuration`);\n }\n\n // 3. 检查当前配置的链是否在 /supported 中\n const chainSupported = facilitatorSupported.kinds.some(\n (kind) => kind.network === schemaNetwork\n );\n\n if (!chainSupported) {\n errors.push(\n `Facilitator does not support network ${schemaNetwork} (chainId: ${clientChainId})`\n );\n }\n }\n\n // 4. 验证 network 匹配\n // 简化的网络验证逻辑\n // 实际应用中可能需要更复杂的网络匹配逻辑\n if (clientChainId) {\n // 检查 schema network 是否包含 chainId\n const networkValid = this.validateNetwork(\n schemaNetwork,\n clientChainId,\n );\n if (!networkValid) {\n errors.push(\n `Network mismatch: client chainId ${clientChainId} does not match schema network ${schemaNetwork}`,\n );\n }\n }\n\n // 2. 验证 payTo 和 recipientAddress 匹配\n const schemaPayTo = this.schema.get(\"payTo\");\n const facilitatorRecipientAddress =\n this.facilitator.recipientAddress;\n\n if (\n schemaPayTo.toLowerCase() !==\n facilitatorRecipientAddress.toLowerCase()\n ) {\n errors.push(\n `Address mismatch: schema payTo ${schemaPayTo} does not match facilitator recipientAddress ${facilitatorRecipientAddress}`,\n );\n }\n\n // 3. 调用 facilitator verify(如果有支付负载的话)\n // 这里暂时只做配置验证,实际支付验证在处理支付时进行\n\n return {\n success: errors.length === 0,\n errors: errors.length > 0 ? errors : undefined,\n };\n } catch (error) {\n errors.push(\n error instanceof Error\n ? error.message\n : \"Unknown verification error\",\n );\n return {\n success: false,\n errors,\n };\n }\n }\n\n /**\n * 结算支付\n * @param paymentPayload 支付负载\n * @param paymentRequirements 支付要求\n */\n async settle(\n paymentPayload: any,\n paymentRequirements: any,\n ): Promise<SettleResult> {\n if (!this.initialized) {\n return {\n success: false,\n error:\n \"Server not initialized. Please call initialize() first.\",\n };\n }\n\n try {\n // 调用 facilitator 进行结算\n const result = await this.facilitator.settle(\n paymentPayload,\n paymentRequirements,\n );\n\n if (!result.success) {\n return {\n success: false,\n error: result.error || result.errorMessage,\n };\n }\n\n return {\n success: true,\n transactionHash: result.transactionHash,\n };\n } catch (error) {\n return {\n success: false,\n error:\n error instanceof Error\n ? error.message\n : \"Settlement failed\",\n };\n }\n }\n\n /**\n * 验证支付负载\n * @param paymentPayload 支付负载\n * @param paymentRequirements 支付要求\n */\n async verifyPayment(\n paymentPayload: any,\n paymentRequirements: any,\n ): Promise<{\n success: boolean;\n data?: string;\n error?: string;\n }> {\n if (!this.initialized) {\n return {\n success: false,\n error:\n \"Server not initialized. Please call initialize() first.\",\n };\n }\n\n try {\n const result = await this.facilitator.verify(\n paymentPayload,\n paymentRequirements,\n );\n\n return {\n success: result.success,\n data: result.payer,\n error: result.error || result.errorMessage,\n };\n } catch (error) {\n return {\n success: false,\n error:\n error instanceof Error\n ? error.message\n : \"Payment verification failed\",\n };\n }\n }\n\n /**\n * 获取 facilitator\n */\n getFacilitator(): Facilitator {\n return this.facilitator;\n }\n\n /**\n * 获取 schema\n */\n getSchema(): X402PaymentSchema {\n return this.schema;\n }\n\n /**\n * 获取 client\n */\n getClient(): PublicClient {\n return this.client;\n }\n\n /**\n * 检查是否已初始化\n */\n isInitialized(): boolean {\n return this.initialized;\n }\n\n /**\n * 验证网络是否匹配\n * @param schemaNetwork schema 中的 network\n * @param clientChainId client 的 chainId\n * @returns 是否匹配\n */\n private validateNetwork(\n schemaNetwork: string,\n clientChainId: number,\n ): boolean {\n // 如果是 eip155: 格式\n if (schemaNetwork.startsWith(\"eip155:\")) {\n const chainId = parseInt(schemaNetwork.split(\":\")[1] || \"0\");\n return chainId === clientChainId;\n }\n\n // 常见网络名称映射\n const networkMap: Record<string, number> = {\n \"ethereum\": 1,\n \"goerli\": 5,\n \"sepolia\": 11155111,\n \"base\": 8453,\n \"base-sepolia\": 84532,\n \"bsc\": 56,\n \"bsc-testnet\": 97,\n \"polygon\": 137,\n \"polygon-mumbai\": 80001,\n \"arbitrum\": 42161,\n \"arbitrum-goerli\": 421613,\n \"optimism\": 10,\n \"optimism-goerli\": 420,\n \"avalanche\": 43114,\n \"avalanche-fuji\": 43113,\n };\n\n const expectedChainId = networkMap[schemaNetwork];\n if (expectedChainId !== undefined) {\n return expectedChainId === clientChainId;\n }\n\n // 如果无法匹配,返回 true(宽松验证)\n return true;\n }\n\n /**\n * 解析支付 header\n * @param paymentHeaderBase64 Base64 编码的支付 header\n * @returns 解析结果,成功时返回 paymentPayload 和 paymentRequirements,失败时返回服务端的支付要求\n */\n parsePaymentHeader(\n paymentHeaderBase64: string,\n ):\n | {\n success: true;\n data: {\n paymentPayload: PaymentPayload;\n paymentRequirements: PaymentRequirements;\n };\n }\n | { success: false; data: PaymentRequirements; error: string } {\n // 获取服务端的支付要求(从 schema 转换)\n const paymentRequirements = this.schema.toJSON() as PaymentRequirements;\n\n // 检查是否有 payment header\n if (!paymentHeaderBase64) {\n return {\n success: false,\n data: paymentRequirements,\n error: \"No X-PAYMENT header\",\n };\n }\n\n // 解码 payment header\n let paymentPayload: PaymentPayload;\n try {\n const paymentHeaderJson = Buffer.from(\n paymentHeaderBase64,\n \"base64\",\n ).toString(\"utf-8\");\n paymentPayload = JSON.parse(paymentHeaderJson) as PaymentPayload;\n } catch (err) {\n return {\n success: false,\n data: paymentRequirements,\n error: \"Invalid payment header format\",\n };\n }\n\n // 验证支付数据与服务端 schema 是否一致\n const validationError = this.validatePaymentPayload(\n paymentPayload,\n paymentRequirements,\n );\n if (validationError) {\n return {\n success: false,\n data: paymentRequirements,\n error: validationError,\n };\n }\n\n // 返回成功结果\n return {\n success: true,\n data: {\n paymentPayload,\n paymentRequirements,\n },\n };\n }\n\n /**\n * 验证客户端的支付数据是否与服务端要求一致\n * @param paymentPayload 客户端的支付负载\n * @param paymentRequirements 服务端的支付要求\n * @returns 错误信息,如果验证通过则返回 null\n */\n private validatePaymentPayload(\n paymentPayload: PaymentPayload,\n paymentRequirements: PaymentRequirements,\n ): string | null {\n // 1. 验证 scheme\n if (paymentPayload.scheme !== paymentRequirements.scheme) {\n return `Scheme mismatch: expected '${paymentRequirements.scheme}', got '${paymentPayload.scheme}'`;\n }\n\n // 2. 验证 network\n if (paymentPayload.network !== paymentRequirements.network) {\n return `Network mismatch: expected '${paymentRequirements.network}', got '${paymentPayload.network}'`;\n }\n\n // 3. 验证支付金额(从 payload 中提取)\n if (paymentPayload.payload) {\n const authorization = (paymentPayload.payload as any).authorization;\n if (authorization?.value) {\n const paymentAmount = BigInt(authorization.value);\n const maxAmount = BigInt(paymentRequirements.maxAmountRequired);\n\n if (paymentAmount !== maxAmount) {\n return `Payment amount error ${paymentAmount} !== ${maxAmount}`;\n }\n }\n\n // 4. 验证 payTo 地址\n if (authorization?.to) {\n const expectedPayTo = paymentRequirements.payTo.toLowerCase();\n const actualPayTo = authorization.to.toLowerCase();\n\n if (actualPayTo !== expectedPayTo && actualPayTo !== paymentRequirements.extra?.relayer?.toLowerCase()) {\n return `PayTo address mismatch: expected '${expectedPayTo}', got '${actualPayTo}'`;\n }\n }\n\n // 5. 验证 asset 地址(如果是 permit 或 permit2)\n const authorizationType = (paymentPayload.payload as any)\n .authorizationType;\n if (\n authorizationType === \"permit\" ||\n authorizationType === \"permit2\" ||\n authorizationType === \"eip3009\"\n ) {\n // 对于 permit/permit2,asset 通常在 schema 中,需要与实际调用的合约匹配\n // 这里可以添加更多验证逻辑\n }\n }\n\n // 验证通过\n return null;\n }\n}\n\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/token-detection.ts","../src/server.ts"],"sourcesContent":["export { X402Server } from \"./server\";\nexport * from \"./types\";\nexport * from \"./token-detection\";\n\n","import type { Address, PublicClient } from \"viem\";\n\n/**\n * Token 信息\n */\nexport interface TokenInfo {\n name: string;\n version: string;\n}\n\n/**\n * 支持的支付方式\n */\nexport type PaymentMethod = \"eip3009\" | \"permit\" | \"permit2\" | \"permit2-witness\";\n\n/**\n * 检测结果\n */\nexport interface TokenPaymentCapabilities {\n address: string;\n supportedMethods: PaymentMethod[];\n details: {\n hasEIP3009: boolean;\n hasPermit: boolean;\n hasPermit2Approval: boolean;\n };\n}\n\n/**\n * EIP-3009 方法签名\n * - transferWithAuthorization(address,address,uint256,uint256,uint256,bytes32,uint8,bytes32,bytes32)\n * \n * 支持多个方法签名变体,以兼容不同的实现:\n * - 0xe3ee160e: 标准 EIP-3009 实现\n * - 0xcf092995: 某些代币的替代实现\n */\nconst EIP3009_SIGNATURES = [\"0xe3ee160e\", \"0xcf092995\"] as const;\n\n/**\n * EIP-2612 Permit 方法签名\n * - permit(address,address,uint256,uint256,uint8,bytes32,bytes32)\n */\nconst EIP2612_PERMIT = \"0xd505accf\" as const;\n\n/**\n * Uniswap Permit2 合约地址(所有链相同)\n */\nconst PERMIT2_ADDRESS = \"0x000000000022D473030F116dDEE9F6B43aC78BA3\" as const;\n\n/**\n * EIP-1967 标准实现槽位\n * keccak256(\"eip1967.proxy.implementation\") - 1\n */\nconst EIP1967_IMPLEMENTATION_SLOT = \"0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc\" as const;\n\n/**\n * EIP-1822 UUPS 实现槽位\n * keccak256(\"PROXIABLE\")\n */\nconst EIP1822_IMPLEMENTATION_SLOT = \"0x7050c9e0f4ca769c69bd3a8ef740bc37934f8e2c036e5a723fd8ee048ed3f8c3\" as const;\n\n/**\n * OpenZeppelin implementation() 函数签名\n */\nconst IMPLEMENTATION_FUNCTION = \"0x5c60da1b\" as const;\n\n/**\n * 检测合约是否是代理合约,并获取实现合约地址\n */\nasync function getImplementationAddress(\n client: PublicClient,\n proxyAddress: Address\n): Promise<Address | null> {\n try {\n // 方法1: 尝试读取 EIP-1967 存储槽位\n try {\n const implSlotData = await client.getStorageAt({\n address: proxyAddress,\n slot: EIP1967_IMPLEMENTATION_SLOT,\n });\n if (implSlotData && implSlotData !== \"0x0000000000000000000000000000000000000000000000000000000000000000\") {\n // 从存储槽中提取地址(最后20字节)\n const implAddress = `0x${implSlotData.slice(-40)}` as Address;\n if (implAddress !== \"0x0000000000000000000000000000000000000000\") {\n console.log(` 📦 Detected EIP-1967 proxy, implementation: ${implAddress}`);\n return implAddress;\n }\n }\n } catch {\n // 继续尝试其他方法\n }\n\n // 方法2: 尝试读取 EIP-1822 存储槽位\n try {\n const uupsSlotData = await client.getStorageAt({\n address: proxyAddress,\n slot: EIP1822_IMPLEMENTATION_SLOT,\n });\n if (uupsSlotData && uupsSlotData !== \"0x0000000000000000000000000000000000000000000000000000000000000000\") {\n const implAddress = `0x${uupsSlotData.slice(-40)}` as Address;\n if (implAddress !== \"0x0000000000000000000000000000000000000000\") {\n console.log(` 📦 Detected EIP-1822 UUPS proxy, implementation: ${implAddress}`);\n return implAddress;\n }\n }\n } catch {\n // 继续尝试其他方法\n }\n\n // 方法3: 尝试调用 implementation() 函数\n try {\n const implABI = [\n {\n inputs: [],\n name: \"implementation\",\n outputs: [{ name: \"\", type: \"address\" }],\n stateMutability: \"view\",\n type: \"function\",\n },\n ] as const;\n\n const implAddress = await client.readContract({\n address: proxyAddress,\n abi: implABI,\n functionName: \"implementation\",\n }) as Address;\n\n if (implAddress && implAddress !== \"0x0000000000000000000000000000000000000000\") {\n console.log(` 📦 Detected proxy via implementation(), implementation: ${implAddress}`);\n return implAddress;\n }\n } catch {\n // 不是代理合约或不支持 implementation() 函数\n }\n\n return null;\n } catch (error) {\n console.error(\"Error detecting proxy implementation:\", error);\n return null;\n }\n}\n\n/**\n * 检查合约是否支持某个方法(通过字节码检查)\n * 支持代理合约检测\n */\nasync function hasMethod(\n client: PublicClient,\n tokenAddress: Address,\n methodSelector: string\n): Promise<boolean> {\n try {\n // 尝试获取合约代码\n const code = await client.getBytecode({ address: tokenAddress });\n if (!code) return false;\n\n // 检查字节码中是否包含方法选择器\n const hasMethodInProxy = code.toLowerCase().includes(methodSelector.slice(2).toLowerCase());\n\n // 如果代理合约中找到了方法,直接返回 true\n if (hasMethodInProxy) {\n return true;\n }\n\n // 如果代理合约中没有找到,尝试检测是否是代理合约\n const implAddress = await getImplementationAddress(client, tokenAddress);\n if (implAddress) {\n // 获取实现合约的字节码\n const implCode = await client.getBytecode({ address: implAddress });\n if (implCode) {\n const hasMethodInImpl = implCode.toLowerCase().includes(methodSelector.slice(2).toLowerCase());\n if (hasMethodInImpl) {\n console.log(` ✅ Method ${methodSelector} found in implementation contract`);\n }\n return hasMethodInImpl;\n }\n }\n\n return false;\n } catch (error) {\n console.error(`Error checking method ${methodSelector}:`, error);\n return false;\n }\n}\n\n/**\n * 检查合约是否支持多个方法签名中的任意一个\n * 支持代理合约检测\n */\nasync function hasAnyMethod(\n client: PublicClient,\n tokenAddress: Address,\n methodSelectors: readonly string[]\n): Promise<boolean> {\n try {\n // 尝试获取合约代码\n const code = await client.getBytecode({ address: tokenAddress });\n if (!code) return false;\n\n const codeLower = code.toLowerCase();\n\n // 检查代理合约中是否包含任何一个方法选择器\n const hasMethodInProxy = methodSelectors.some(selector =>\n codeLower.includes(selector.slice(2).toLowerCase())\n );\n\n // 如果代理合约中找到了方法,直接返回 true\n if (hasMethodInProxy) {\n return true;\n }\n\n // 如果代理合约中没有找到,尝试检测是否是代理合约\n const implAddress = await getImplementationAddress(client, tokenAddress);\n if (implAddress) {\n // 获取实现合约的字节码\n const implCode = await client.getBytecode({ address: implAddress });\n if (implCode) {\n const implCodeLower = implCode.toLowerCase();\n const hasMethodInImpl = methodSelectors.some(selector =>\n implCodeLower.includes(selector.slice(2).toLowerCase())\n );\n if (hasMethodInImpl) {\n console.log(` ✅ Method(s) found in implementation contract`);\n }\n return hasMethodInImpl;\n }\n }\n\n return false;\n } catch (error) {\n console.error(`Error checking methods ${methodSelectors.join(\", \")}:`, error);\n return false;\n }\n}\n\n/**\n * 检查 Permit2 合约是否在该链上部署\n */\nasync function checkPermit2Support(client: PublicClient): Promise<boolean> {\n try {\n // 检查 Permit2 合约是否在该链上部署\n const permit2Code = await client.getBytecode({ address: PERMIT2_ADDRESS });\n if (!permit2Code) return false;\n\n // 如果 Permit2 存在,理论上任何 ERC-20 都可以使用它\n return true;\n } catch (error) {\n console.error(\"Error checking Permit2 support:\", error);\n return false;\n }\n}\n\n/**\n * 检测代币支持的支付方式\n * @param tokenAddress 代币地址\n * @param client viem PublicClient\n * @returns 检测结果\n */\nexport async function detectTokenPaymentMethods(\n tokenAddress: string,\n client: PublicClient\n): Promise<TokenPaymentCapabilities> {\n const address = tokenAddress.toLowerCase() as Address;\n\n console.log(`🔍 Detecting payment methods for token ${address}...`);\n\n // 并行检测所有方法\n const [hasEIP3009, hasPermit, hasPermit2Approval] = await Promise.all([\n hasAnyMethod(client, address, EIP3009_SIGNATURES),\n hasMethod(client, address, EIP2612_PERMIT),\n checkPermit2Support(client),\n ]);\n\n // 构建支持的方法列表\n const supportedMethods: PaymentMethod[] = [];\n\n if (hasEIP3009) {\n supportedMethods.push(\"eip3009\");\n console.log(\" ✅ EIP-3009 (transferWithAuthorization) detected\");\n }\n\n if (hasPermit) {\n supportedMethods.push(\"permit\");\n console.log(\" ✅ EIP-2612 (permit) detected\");\n }\n\n if (hasPermit2Approval) {\n supportedMethods.push(\"permit2\");\n supportedMethods.push(\"permit2-witness\");\n console.log(\" ✅ Permit2 support available (universal)\");\n }\n\n if (supportedMethods.length === 0) {\n console.log(\" ⚠️ No advanced payment methods detected (standard ERC-20 only)\");\n }\n\n return {\n address,\n supportedMethods,\n details: {\n hasEIP3009,\n hasPermit,\n hasPermit2Approval,\n },\n };\n}\n\n/**\n * 获取推荐的支付方式(仅返回 schema 支持的类型)\n * 按优先级排序:eip3009 > permit > permit2\n * 注意:permit2-witness 会被映射为 permit2,因为它们在 schema 中是同一种支付类型\n */\nexport function getRecommendedPaymentMethod(\n capabilities: TokenPaymentCapabilities\n): \"eip3009\" | \"permit2\" | \"permit\" | null {\n const { supportedMethods } = capabilities;\n\n if (supportedMethods.includes(\"eip3009\")) return \"eip3009\";\n if (supportedMethods.includes(\"permit\")) return \"permit\";\n // permit2 和 permit2-witness 都映射为 permit2(schema 只支持 permit2)\n if (supportedMethods.includes(\"permit2\") || supportedMethods.includes(\"permit2-witness\")) {\n return \"permit2\";\n }\n\n return null;\n}\n\n/**\n * 获取 token 的 name 和 version 信息(用于 EIP-712 签名)\n * 支持代理合约(会自动从代理合约读取,因为代理合约会 delegatecall 到实现合约)\n * @param tokenAddress 代币地址\n * @param client viem PublicClient\n * @returns Token 的 name 和 version\n */\nexport async function getTokenInfo(\n tokenAddress: string,\n client: PublicClient\n): Promise<TokenInfo> {\n const address = tokenAddress.toLowerCase() as Address;\n\n // ERC-20 标准 ABI\n const erc20ABI = [\n {\n inputs: [],\n name: \"name\",\n outputs: [{ name: \"\", type: \"string\" }],\n stateMutability: \"view\",\n type: \"function\",\n },\n ] as const;\n\n // EIP-5267 eip712Domain ABI(OpenZeppelin v5+)\n const eip712DomainABI = [\n {\n inputs: [],\n name: \"eip712Domain\",\n outputs: [\n { name: \"fields\", type: \"bytes1\" },\n { name: \"name\", type: \"string\" },\n { name: \"version\", type: \"string\" },\n { name: \"chainId\", type: \"uint256\" },\n { name: \"verifyingContract\", type: \"address\" },\n { name: \"salt\", type: \"bytes32\" },\n { name: \"extensions\", type: \"uint256[]\" },\n ],\n stateMutability: \"view\",\n type: \"function\",\n },\n ] as const;\n\n // version() ABI(OpenZeppelin v4)\n const versionABI = [\n {\n inputs: [],\n name: \"version\",\n outputs: [{ name: \"\", type: \"string\" }],\n stateMutability: \"view\",\n type: \"function\",\n },\n ] as const;\n\n try {\n // 检测是否为代理合约\n const implAddress = await getImplementationAddress(client, address);\n if (implAddress) {\n console.log(` 📦 Reading token info from proxy, actual calls will be delegated to implementation`);\n }\n\n // 获取 token name (对于代理合约,delegatecall 会自动转发到实现合约)\n const name = await client.readContract({\n address,\n abi: erc20ABI,\n functionName: \"name\",\n });\n\n // 尝试获取 version,优先使用 EIP-5267\n let version = \"1\"; // 默认版本\n try {\n const result = await client.readContract({\n address,\n abi: eip712DomainABI,\n functionName: \"eip712Domain\",\n });\n // eip712Domain 返回 [fields, name, version, chainId, verifyingContract, salt, extensions]\n version = result[2] as string; // version 是第 3 个元素(索引 2)\n } catch {\n // 回退到 version() 函数(OpenZeppelin v4)\n try {\n version = await client.readContract({\n address,\n abi: versionABI,\n functionName: \"version\",\n });\n } catch {\n // 如果两种方法都不可用,使用默认值 \"1\"\n console.log(` ℹ️ Using default version \"1\" for token ${address}`);\n }\n }\n\n return {\n name: name as string,\n version: version as string,\n };\n } catch (error) {\n console.error(`Error getting token info for ${address}:`, error);\n throw new Error(`Failed to get token info: ${error}`);\n }\n}\n\n","import type { Facilitator } from \"@wtflabs/x402-facilitator\";\nimport type { X402PaymentSchema, X402PaymentSchemaWithExtra } from \"@wtflabs/x402-schema\";\nimport type { PublicClient } from \"viem\";\nimport type {\n InitializeResult,\n SettleResult,\n VerifyResult,\n X402ServerConfig,\n} from \"./types\";\nimport { PaymentPayload, PaymentRequirements } from \"@wtflabs/x402/types\";\nimport { detectTokenPaymentMethods, getRecommendedPaymentMethod, getTokenInfo, type PaymentMethod } from \"./token-detection\";\n\n/**\n * X402Server 类\n * 集成 facilitator, schema 和 client,提供完整的服务端支付处理\n *\n * @example\n * ```typescript\n * import { X402Server } from \"@wtflabs/x402-server\";\n * import { Facilitator } from \"@wtflabs/x402-facilitator\";\n * import { X402PaymentSchema } from \"@wtflabs/x402-schema\";\n * import { createPublicClient, http } from \"viem\";\n * import { bscTestnet } from \"viem/chains\";\n *\n * const facilitator = new Facilitator({\n * recipientAddress: \"0x1234...\",\n * });\n *\n * const schema = new X402PaymentSchema({\n * scheme: \"exact\",\n * network: \"bsc-testnet\",\n * maxAmountRequired: \"100000\",\n * resource: \"http://localhost:3000/protected-resource\",\n * description: \"Access to protected resource\",\n * mimeType: \"application/json\",\n * payTo: \"0x1234...\",\n * maxTimeoutSeconds: 3600,\n * asset: \"0x5678...\",\n * });\n *\n * const client = createPublicClient({\n * chain: bscTestnet,\n * transport: http(),\n * });\n *\n * const server = new X402Server({\n * facilitator,\n * schema,\n * client,\n * });\n *\n * // 初始化和校验\n * await server.initialize();\n *\n * // 验证\n * const verifyResult = await server.verify();\n *\n * // 结算\n * const settleResult = await server.settle(paymentPayload, paymentRequirements);\n * ```\n */\nexport class X402Server {\n private facilitator: Facilitator;\n private schema: X402PaymentSchema;\n private client: PublicClient;\n private initialized: boolean = false;\n\n constructor(config: X402ServerConfig) {\n this.facilitator = config.facilitator;\n this.schema = config.schema;\n this.client = config.client;\n }\n\n /**\n * 初始化服务器\n * 初始化和校验 schema 等数据,对 schema 增加 facilitator 数据 extra: {relayer}\n * 并获取 token 的 name 和 version 信息\n */\n async initialize(): Promise<InitializeResult> {\n try {\n // 验证 schema\n this.schema.verify();\n\n // 获取 token 信息(name 和 version)并添加到 schema extra 中\n const schemaAsset = this.schema.get(\"asset\");\n if (schemaAsset) {\n try {\n const tokenInfo = await getTokenInfo(schemaAsset, this.client);\n this.schema.setExtra({\n relayer: this.facilitator.relayer,\n name: tokenInfo.name,\n version: tokenInfo.version,\n });\n console.log(`✅ Token info retrieved: ${tokenInfo.name} v${tokenInfo.version}`);\n } catch (error) {\n console.warn(`⚠️ Failed to get token info, signatures may fail:`, error);\n // 仍然设置 relayer,但没有 name 和 version\n this.schema.setExtra({\n relayer: this.facilitator.relayer,\n });\n }\n } else {\n // 如果没有 asset,只设置 relayer\n this.schema.setExtra({\n relayer: this.facilitator.relayer,\n });\n }\n\n // TODO 将_verify中的内容内置到initialize中\n const verifyResult = await this._verify();\n if (!verifyResult.success) {\n return {\n success: false,\n error: verifyResult.errors?.[0] || \"Verification failed\",\n };\n }\n\n this.initialized = true;\n return { success: true };\n } catch (error) {\n return {\n success: false,\n error:\n error instanceof Error\n ? error.message\n : \"Initialization failed\",\n };\n }\n }\n\n /**\n * 验证配置\n * 1. 验证 client network 是否和 schema 的 network 匹配\n * 2. 验证 facilitator recipientAddress 和 schema payTo 是否一致\n */\n async _verify(): Promise<VerifyResult> {\n\n const errors: string[] = [];\n\n try {\n // 1. 检测 token 对 permit 和 eip3009 的支持\n const schemaAsset = this.schema.get(\"asset\");\n if (schemaAsset) {\n const tokenCapabilities = await detectTokenPaymentMethods(\n schemaAsset,\n this.client\n );\n\n // 如果 schema 中不存在 paymentType,则根据 tokenCapabilities 自动确定\n // 优先级:eip3009 > permit2 > permit\n const currentPaymentType = this.schema.get(\"paymentType\");\n if (!currentPaymentType) {\n const recommendedMethod = getRecommendedPaymentMethod(tokenCapabilities);\n if (recommendedMethod) {\n this.schema.set(\"paymentType\", recommendedMethod);\n // console.log(`✅ Auto-selected payment method: ${recommendedMethod}`);\n } else {\n errors.push(\n `Token ${schemaAsset} does not support any advanced payment methods (permit, eip3009, permit2). Please specify paymentType manually.`\n );\n }\n } else {\n // 验证 schema 中指定的 paymentType 是否被 token 支持\n if (!tokenCapabilities.supportedMethods.includes(currentPaymentType)) {\n errors.push(\n `Token ${schemaAsset} does not support the specified payment method \"${currentPaymentType}\". Supported methods: ${tokenCapabilities.supportedMethods.join(\", \")}`\n );\n }\n }\n\n // 如果 token 不支持任何高级支付方法,给出警告\n if (tokenCapabilities.supportedMethods.length === 0) {\n errors.push(\n `Token ${schemaAsset} does not support any advanced payment methods (permit, eip3009, permit2)`\n );\n }\n }\n\n // 2. 检查 facilitator 的 /supported 是否包含此代币和链\n const clientChainId = this.client.chain?.id;\n const schemaNetwork = this.schema.get(\"network\");\n\n if (clientChainId && schemaAsset) {\n const facilitatorSupported = await this.facilitator.supported({\n chainId: clientChainId,\n tokenAddress: schemaAsset,\n });\n\n // console.log(\n // `Checking facilitator support for chainId ${clientChainId} and token ${schemaAsset}`\n // );\n\n // 检查 facilitator 是否支持当前的链和代币组合\n const isSupportedByFacilitator = facilitatorSupported.kinds.some(\n (kind) => {\n // 检查网络匹配\n const networkMatches = kind.network === schemaNetwork;\n\n // 检查资产匹配\n const assetsInKind = (kind.extra as any)?.assets || [];\n const assetMatches = assetsInKind.some(\n (asset: any) =>\n asset.address.toLowerCase() === schemaAsset.toLowerCase()\n );\n\n return networkMatches && assetMatches;\n }\n );\n\n if (!isSupportedByFacilitator) {\n errors.push(\n `Facilitator does not support token ${schemaAsset} on network ${schemaNetwork} (chainId: ${clientChainId})`\n );\n } else {\n // console.log(`✅ Facilitator supports this configuration`);\n }\n\n // 3. 检查当前配置的链是否在 /supported 中\n const chainSupported = facilitatorSupported.kinds.some(\n (kind) => kind.network === schemaNetwork\n );\n\n if (!chainSupported) {\n errors.push(\n `Facilitator does not support network ${schemaNetwork} (chainId: ${clientChainId})`\n );\n }\n }\n\n // 4. 验证 network 匹配\n // 简化的网络验证逻辑\n // 实际应用中可能需要更复杂的网络匹配逻辑\n if (clientChainId) {\n // 检查 schema network 是否包含 chainId\n const networkValid = this.validateNetwork(\n schemaNetwork,\n clientChainId,\n );\n if (!networkValid) {\n errors.push(\n `Network mismatch: client chainId ${clientChainId} does not match schema network ${schemaNetwork}`,\n );\n }\n }\n\n // 2. 验证 payTo 和 recipientAddress 匹配\n const schemaPayTo = this.schema.get(\"payTo\");\n const facilitatorRecipientAddress =\n this.facilitator.recipientAddress;\n\n if (\n schemaPayTo.toLowerCase() !==\n facilitatorRecipientAddress.toLowerCase()\n ) {\n errors.push(\n `Address mismatch: schema payTo ${schemaPayTo} does not match facilitator recipientAddress ${facilitatorRecipientAddress}`,\n );\n }\n\n // 3. 调用 facilitator verify(如果有支付负载的话)\n // 这里暂时只做配置验证,实际支付验证在处理支付时进行\n\n return {\n success: errors.length === 0,\n errors: errors.length > 0 ? errors : undefined,\n };\n } catch (error) {\n errors.push(\n error instanceof Error\n ? error.message\n : \"Unknown verification error\",\n );\n return {\n success: false,\n errors,\n };\n }\n }\n\n /**\n * 结算支付\n * @param paymentPayload 支付负载\n * @param paymentRequirements 支付要求\n */\n async settle(\n paymentPayload: any,\n paymentRequirements: any,\n ): Promise<SettleResult> {\n if (!this.initialized) {\n return {\n success: false,\n error:\n \"Server not initialized. Please call initialize() first.\",\n };\n }\n\n try {\n // 调用 facilitator 进行结算\n const result = await this.facilitator.settle(\n paymentPayload,\n paymentRequirements,\n );\n\n if (!result.success) {\n return {\n success: false,\n error: result.error || result.errorMessage,\n };\n }\n\n return {\n success: true,\n transaction: result.transaction,\n };\n } catch (error) {\n return {\n success: false,\n error:\n error instanceof Error\n ? error.message\n : \"Settlement failed\",\n };\n }\n }\n\n /**\n * 验证支付负载\n * @param paymentPayload 支付负载\n * @param paymentRequirements 支付要求\n */\n async verifyPayment(\n paymentPayload: any,\n paymentRequirements: any,\n ): Promise<{\n success: boolean;\n data?: string;\n error?: string;\n }> {\n if (!this.initialized) {\n return {\n success: false,\n error:\n \"Server not initialized. Please call initialize() first.\",\n };\n }\n\n try {\n const result = await this.facilitator.verify(\n paymentPayload,\n paymentRequirements,\n );\n\n return {\n success: result.success,\n data: result.payer,\n error: result.error || result.errorMessage,\n };\n } catch (error) {\n return {\n success: false,\n error:\n error instanceof Error\n ? error.message\n : \"Payment verification failed\",\n };\n }\n }\n\n /**\n * 获取 facilitator\n */\n getFacilitator(): Facilitator {\n return this.facilitator;\n }\n\n /**\n * 获取 schema\n */\n getSchema(): X402PaymentSchema {\n return this.schema;\n }\n\n /**\n * 获取 client\n */\n getClient(): PublicClient {\n return this.client;\n }\n\n /**\n * 检查是否已初始化\n */\n isInitialized(): boolean {\n return this.initialized;\n }\n\n /**\n * 验证网络是否匹配\n * @param schemaNetwork schema 中的 network\n * @param clientChainId client 的 chainId\n * @returns 是否匹配\n */\n private validateNetwork(\n schemaNetwork: string,\n clientChainId: number,\n ): boolean {\n // 如果是 eip155: 格式\n if (schemaNetwork.startsWith(\"eip155:\")) {\n const chainId = parseInt(schemaNetwork.split(\":\")[1] || \"0\");\n return chainId === clientChainId;\n }\n\n // 常见网络名称映射\n const networkMap: Record<string, number> = {\n \"ethereum\": 1,\n \"goerli\": 5,\n \"sepolia\": 11155111,\n \"base\": 8453,\n \"base-sepolia\": 84532,\n \"bsc\": 56,\n \"bsc-testnet\": 97,\n \"polygon\": 137,\n \"polygon-mumbai\": 80001,\n \"arbitrum\": 42161,\n \"arbitrum-goerli\": 421613,\n \"optimism\": 10,\n \"optimism-goerli\": 420,\n \"avalanche\": 43114,\n \"avalanche-fuji\": 43113,\n };\n\n const expectedChainId = networkMap[schemaNetwork];\n if (expectedChainId !== undefined) {\n return expectedChainId === clientChainId;\n }\n\n // 如果无法匹配,返回 true(宽松验证)\n return true;\n }\n\n /**\n * 解析支付 header\n * @param paymentHeaderBase64 Base64 编码的支付 header\n * @returns 解析结果,成功时返回 paymentPayload 和 paymentRequirements,失败时返回服务端的支付要求\n */\n parsePaymentHeader(\n paymentHeaderBase64: string,\n ):\n | {\n success: true;\n data: {\n paymentPayload: PaymentPayload;\n paymentRequirements: PaymentRequirements;\n };\n }\n | { success: false; data: PaymentRequirements; error: string } {\n // 获取服务端的支付要求(从 schema 转换)\n const paymentRequirements = this.schema.toJSON() as PaymentRequirements;\n\n // 检查是否有 payment header\n if (!paymentHeaderBase64) {\n return {\n success: false,\n data: paymentRequirements,\n error: \"No X-PAYMENT header\",\n };\n }\n\n // 解码 payment header\n let paymentPayload: PaymentPayload;\n try {\n const paymentHeaderJson = Buffer.from(\n paymentHeaderBase64,\n \"base64\",\n ).toString(\"utf-8\");\n paymentPayload = JSON.parse(paymentHeaderJson) as PaymentPayload;\n } catch (err) {\n return {\n success: false,\n data: paymentRequirements,\n error: \"Invalid payment header format\",\n };\n }\n\n // 验证支付数据与服务端 schema 是否一致\n const validationError = this.validatePaymentPayload(\n paymentPayload,\n paymentRequirements,\n );\n if (validationError) {\n return {\n success: false,\n data: paymentRequirements,\n error: validationError,\n };\n }\n\n // 返回成功结果\n return {\n success: true,\n data: {\n paymentPayload,\n paymentRequirements,\n },\n };\n }\n\n /**\n * 验证客户端的支付数据是否与服务端要求一致\n * @param paymentPayload 客户端的支付负载\n * @param paymentRequirements 服务端的支付要求\n * @returns 错误信息,如果验证通过则返回 null\n */\n private validatePaymentPayload(\n paymentPayload: PaymentPayload,\n paymentRequirements: PaymentRequirements,\n ): string | null {\n // 1. 验证 scheme\n if (paymentPayload.scheme !== paymentRequirements.scheme) {\n return `Scheme mismatch: expected '${paymentRequirements.scheme}', got '${paymentPayload.scheme}'`;\n }\n\n // 2. 验证 network\n if (paymentPayload.network !== paymentRequirements.network) {\n return `Network mismatch: expected '${paymentRequirements.network}', got '${paymentPayload.network}'`;\n }\n\n // 3. 验证支付金额(从 payload 中提取)\n if (paymentPayload.payload) {\n const authorization = (paymentPayload.payload as any).authorization;\n if (authorization?.value) {\n const paymentAmount = BigInt(authorization.value);\n const maxAmount = BigInt(paymentRequirements.maxAmountRequired);\n\n if (paymentAmount !== maxAmount) {\n return `Payment amount error ${paymentAmount} !== ${maxAmount}`;\n }\n }\n\n // 4. 验证 payTo 地址\n if (authorization?.to) {\n const expectedPayTo = paymentRequirements.payTo.toLowerCase();\n const actualPayTo = authorization.to.toLowerCase();\n\n if (actualPayTo !== expectedPayTo && actualPayTo !== paymentRequirements.extra?.relayer?.toLowerCase()) {\n return `PayTo address mismatch: expected '${expectedPayTo}', got '${actualPayTo}'`;\n }\n }\n\n // 5. 验证 asset 地址(如果是 permit 或 permit2)\n const authorizationType = (paymentPayload.payload as any)\n .authorizationType;\n if (\n authorizationType === \"permit\" ||\n authorizationType === \"permit2\" ||\n authorizationType === \"eip3009\"\n ) {\n // 对于 permit/permit2,asset 通常在 schema 中,需要与实际调用的合约匹配\n // 这里可以添加更多验证逻辑\n }\n }\n\n // 验证通过\n return null;\n }\n}\n\n"],"mappings":"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","names":[]}
|
package/dist/index.mjs
CHANGED
|
@@ -2,11 +2,85 @@
|
|
|
2
2
|
var EIP3009_SIGNATURES = ["0xe3ee160e", "0xcf092995"];
|
|
3
3
|
var EIP2612_PERMIT = "0xd505accf";
|
|
4
4
|
var PERMIT2_ADDRESS = "0x000000000022D473030F116dDEE9F6B43aC78BA3";
|
|
5
|
+
var EIP1967_IMPLEMENTATION_SLOT = "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc";
|
|
6
|
+
var EIP1822_IMPLEMENTATION_SLOT = "0x7050c9e0f4ca769c69bd3a8ef740bc37934f8e2c036e5a723fd8ee048ed3f8c3";
|
|
7
|
+
async function getImplementationAddress(client, proxyAddress) {
|
|
8
|
+
try {
|
|
9
|
+
try {
|
|
10
|
+
const implSlotData = await client.getStorageAt({
|
|
11
|
+
address: proxyAddress,
|
|
12
|
+
slot: EIP1967_IMPLEMENTATION_SLOT
|
|
13
|
+
});
|
|
14
|
+
if (implSlotData && implSlotData !== "0x0000000000000000000000000000000000000000000000000000000000000000") {
|
|
15
|
+
const implAddress = `0x${implSlotData.slice(-40)}`;
|
|
16
|
+
if (implAddress !== "0x0000000000000000000000000000000000000000") {
|
|
17
|
+
console.log(` \u{1F4E6} Detected EIP-1967 proxy, implementation: ${implAddress}`);
|
|
18
|
+
return implAddress;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
} catch {
|
|
22
|
+
}
|
|
23
|
+
try {
|
|
24
|
+
const uupsSlotData = await client.getStorageAt({
|
|
25
|
+
address: proxyAddress,
|
|
26
|
+
slot: EIP1822_IMPLEMENTATION_SLOT
|
|
27
|
+
});
|
|
28
|
+
if (uupsSlotData && uupsSlotData !== "0x0000000000000000000000000000000000000000000000000000000000000000") {
|
|
29
|
+
const implAddress = `0x${uupsSlotData.slice(-40)}`;
|
|
30
|
+
if (implAddress !== "0x0000000000000000000000000000000000000000") {
|
|
31
|
+
console.log(` \u{1F4E6} Detected EIP-1822 UUPS proxy, implementation: ${implAddress}`);
|
|
32
|
+
return implAddress;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
} catch {
|
|
36
|
+
}
|
|
37
|
+
try {
|
|
38
|
+
const implABI = [
|
|
39
|
+
{
|
|
40
|
+
inputs: [],
|
|
41
|
+
name: "implementation",
|
|
42
|
+
outputs: [{ name: "", type: "address" }],
|
|
43
|
+
stateMutability: "view",
|
|
44
|
+
type: "function"
|
|
45
|
+
}
|
|
46
|
+
];
|
|
47
|
+
const implAddress = await client.readContract({
|
|
48
|
+
address: proxyAddress,
|
|
49
|
+
abi: implABI,
|
|
50
|
+
functionName: "implementation"
|
|
51
|
+
});
|
|
52
|
+
if (implAddress && implAddress !== "0x0000000000000000000000000000000000000000") {
|
|
53
|
+
console.log(` \u{1F4E6} Detected proxy via implementation(), implementation: ${implAddress}`);
|
|
54
|
+
return implAddress;
|
|
55
|
+
}
|
|
56
|
+
} catch {
|
|
57
|
+
}
|
|
58
|
+
return null;
|
|
59
|
+
} catch (error) {
|
|
60
|
+
console.error("Error detecting proxy implementation:", error);
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
5
64
|
async function hasMethod(client, tokenAddress, methodSelector) {
|
|
6
65
|
try {
|
|
7
66
|
const code = await client.getBytecode({ address: tokenAddress });
|
|
8
67
|
if (!code) return false;
|
|
9
|
-
|
|
68
|
+
const hasMethodInProxy = code.toLowerCase().includes(methodSelector.slice(2).toLowerCase());
|
|
69
|
+
if (hasMethodInProxy) {
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
const implAddress = await getImplementationAddress(client, tokenAddress);
|
|
73
|
+
if (implAddress) {
|
|
74
|
+
const implCode = await client.getBytecode({ address: implAddress });
|
|
75
|
+
if (implCode) {
|
|
76
|
+
const hasMethodInImpl = implCode.toLowerCase().includes(methodSelector.slice(2).toLowerCase());
|
|
77
|
+
if (hasMethodInImpl) {
|
|
78
|
+
console.log(` \u2705 Method ${methodSelector} found in implementation contract`);
|
|
79
|
+
}
|
|
80
|
+
return hasMethodInImpl;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return false;
|
|
10
84
|
} catch (error) {
|
|
11
85
|
console.error(`Error checking method ${methodSelector}:`, error);
|
|
12
86
|
return false;
|
|
@@ -17,9 +91,27 @@ async function hasAnyMethod(client, tokenAddress, methodSelectors) {
|
|
|
17
91
|
const code = await client.getBytecode({ address: tokenAddress });
|
|
18
92
|
if (!code) return false;
|
|
19
93
|
const codeLower = code.toLowerCase();
|
|
20
|
-
|
|
94
|
+
const hasMethodInProxy = methodSelectors.some(
|
|
21
95
|
(selector) => codeLower.includes(selector.slice(2).toLowerCase())
|
|
22
96
|
);
|
|
97
|
+
if (hasMethodInProxy) {
|
|
98
|
+
return true;
|
|
99
|
+
}
|
|
100
|
+
const implAddress = await getImplementationAddress(client, tokenAddress);
|
|
101
|
+
if (implAddress) {
|
|
102
|
+
const implCode = await client.getBytecode({ address: implAddress });
|
|
103
|
+
if (implCode) {
|
|
104
|
+
const implCodeLower = implCode.toLowerCase();
|
|
105
|
+
const hasMethodInImpl = methodSelectors.some(
|
|
106
|
+
(selector) => implCodeLower.includes(selector.slice(2).toLowerCase())
|
|
107
|
+
);
|
|
108
|
+
if (hasMethodInImpl) {
|
|
109
|
+
console.log(` \u2705 Method(s) found in implementation contract`);
|
|
110
|
+
}
|
|
111
|
+
return hasMethodInImpl;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return false;
|
|
23
115
|
} catch (error) {
|
|
24
116
|
console.error(`Error checking methods ${methodSelectors.join(", ")}:`, error);
|
|
25
117
|
return false;
|
|
@@ -117,6 +209,10 @@ async function getTokenInfo(tokenAddress, client) {
|
|
|
117
209
|
}
|
|
118
210
|
];
|
|
119
211
|
try {
|
|
212
|
+
const implAddress = await getImplementationAddress(client, address);
|
|
213
|
+
if (implAddress) {
|
|
214
|
+
console.log(` \u{1F4E6} Reading token info from proxy, actual calls will be delegated to implementation`);
|
|
215
|
+
}
|
|
120
216
|
const name = await client.readContract({
|
|
121
217
|
address,
|
|
122
218
|
abi: erc20ABI,
|
|
@@ -330,7 +426,7 @@ var X402Server = class {
|
|
|
330
426
|
}
|
|
331
427
|
return {
|
|
332
428
|
success: true,
|
|
333
|
-
|
|
429
|
+
transaction: result.transaction
|
|
334
430
|
};
|
|
335
431
|
} catch (error) {
|
|
336
432
|
return {
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/token-detection.ts","../src/server.ts"],"sourcesContent":["import type { Address, PublicClient } from \"viem\";\n\n/**\n * Token 信息\n */\nexport interface TokenInfo {\n name: string;\n version: string;\n}\n\n/**\n * 支持的支付方式\n */\nexport type PaymentMethod = \"eip3009\" | \"permit\" | \"permit2\" | \"permit2-witness\";\n\n/**\n * 检测结果\n */\nexport interface TokenPaymentCapabilities {\n address: string;\n supportedMethods: PaymentMethod[];\n details: {\n hasEIP3009: boolean;\n hasPermit: boolean;\n hasPermit2Approval: boolean;\n };\n}\n\n/**\n * EIP-3009 方法签名\n * - transferWithAuthorization(address,address,uint256,uint256,uint256,bytes32,uint8,bytes32,bytes32)\n * \n * 支持多个方法签名变体,以兼容不同的实现:\n * - 0xe3ee160e: 标准 EIP-3009 实现\n * - 0xcf092995: 某些代币的替代实现\n */\nconst EIP3009_SIGNATURES = [\"0xe3ee160e\", \"0xcf092995\"] as const;\n\n/**\n * EIP-2612 Permit 方法签名\n * - permit(address,address,uint256,uint256,uint8,bytes32,bytes32)\n */\nconst EIP2612_PERMIT = \"0xd505accf\" as const;\n\n/**\n * Uniswap Permit2 合约地址(所有链相同)\n */\nconst PERMIT2_ADDRESS = \"0x000000000022D473030F116dDEE9F6B43aC78BA3\" as const;\n\n/**\n * 检查合约是否支持某个方法(通过字节码检查)\n */\nasync function hasMethod(\n client: PublicClient,\n tokenAddress: Address,\n methodSelector: string\n): Promise<boolean> {\n try {\n // 尝试获取合约代码\n const code = await client.getBytecode({ address: tokenAddress });\n if (!code) return false;\n\n // 检查字节码中是否包含方法选择器\n return code.toLowerCase().includes(methodSelector.slice(2).toLowerCase());\n } catch (error) {\n console.error(`Error checking method ${methodSelector}:`, error);\n return false;\n }\n}\n\n/**\n * 检查合约是否支持多个方法签名中的任意一个\n */\nasync function hasAnyMethod(\n client: PublicClient,\n tokenAddress: Address,\n methodSelectors: readonly string[]\n): Promise<boolean> {\n try {\n // 尝试获取合约代码\n const code = await client.getBytecode({ address: tokenAddress });\n if (!code) return false;\n\n const codeLower = code.toLowerCase();\n\n // 检查是否包含任何一个方法选择器\n return methodSelectors.some(selector =>\n codeLower.includes(selector.slice(2).toLowerCase())\n );\n } catch (error) {\n console.error(`Error checking methods ${methodSelectors.join(\", \")}:`, error);\n return false;\n }\n}\n\n/**\n * 检查 Permit2 合约是否在该链上部署\n */\nasync function checkPermit2Support(client: PublicClient): Promise<boolean> {\n try {\n // 检查 Permit2 合约是否在该链上部署\n const permit2Code = await client.getBytecode({ address: PERMIT2_ADDRESS });\n if (!permit2Code) return false;\n\n // 如果 Permit2 存在,理论上任何 ERC-20 都可以使用它\n return true;\n } catch (error) {\n console.error(\"Error checking Permit2 support:\", error);\n return false;\n }\n}\n\n/**\n * 检测代币支持的支付方式\n * @param tokenAddress 代币地址\n * @param client viem PublicClient\n * @returns 检测结果\n */\nexport async function detectTokenPaymentMethods(\n tokenAddress: string,\n client: PublicClient\n): Promise<TokenPaymentCapabilities> {\n const address = tokenAddress.toLowerCase() as Address;\n\n console.log(`🔍 Detecting payment methods for token ${address}...`);\n\n // 并行检测所有方法\n const [hasEIP3009, hasPermit, hasPermit2Approval] = await Promise.all([\n hasAnyMethod(client, address, EIP3009_SIGNATURES),\n hasMethod(client, address, EIP2612_PERMIT),\n checkPermit2Support(client),\n ]);\n\n // 构建支持的方法列表\n const supportedMethods: PaymentMethod[] = [];\n\n if (hasEIP3009) {\n supportedMethods.push(\"eip3009\");\n console.log(\" ✅ EIP-3009 (transferWithAuthorization) detected\");\n }\n\n if (hasPermit) {\n supportedMethods.push(\"permit\");\n console.log(\" ✅ EIP-2612 (permit) detected\");\n }\n\n if (hasPermit2Approval) {\n supportedMethods.push(\"permit2\");\n supportedMethods.push(\"permit2-witness\");\n console.log(\" ✅ Permit2 support available (universal)\");\n }\n\n if (supportedMethods.length === 0) {\n console.log(\" ⚠️ No advanced payment methods detected (standard ERC-20 only)\");\n }\n\n return {\n address,\n supportedMethods,\n details: {\n hasEIP3009,\n hasPermit,\n hasPermit2Approval,\n },\n };\n}\n\n/**\n * 获取推荐的支付方式(仅返回 schema 支持的类型)\n * 按优先级排序:eip3009 > permit > permit2\n * 注意:permit2-witness 会被映射为 permit2,因为它们在 schema 中是同一种支付类型\n */\nexport function getRecommendedPaymentMethod(\n capabilities: TokenPaymentCapabilities\n): \"eip3009\" | \"permit2\" | \"permit\" | null {\n const { supportedMethods } = capabilities;\n\n if (supportedMethods.includes(\"eip3009\")) return \"eip3009\";\n if (supportedMethods.includes(\"permit\")) return \"permit\";\n // permit2 和 permit2-witness 都映射为 permit2(schema 只支持 permit2)\n if (supportedMethods.includes(\"permit2\") || supportedMethods.includes(\"permit2-witness\")) {\n return \"permit2\";\n }\n\n return null;\n}\n\n/**\n * 获取 token 的 name 和 version 信息(用于 EIP-712 签名)\n * @param tokenAddress 代币地址\n * @param client viem PublicClient\n * @returns Token 的 name 和 version\n */\nexport async function getTokenInfo(\n tokenAddress: string,\n client: PublicClient\n): Promise<TokenInfo> {\n const address = tokenAddress.toLowerCase() as Address;\n\n // ERC-20 标准 ABI\n const erc20ABI = [\n {\n inputs: [],\n name: \"name\",\n outputs: [{ name: \"\", type: \"string\" }],\n stateMutability: \"view\",\n type: \"function\",\n },\n ] as const;\n\n // EIP-5267 eip712Domain ABI(OpenZeppelin v5+)\n const eip712DomainABI = [\n {\n inputs: [],\n name: \"eip712Domain\",\n outputs: [\n { name: \"fields\", type: \"bytes1\" },\n { name: \"name\", type: \"string\" },\n { name: \"version\", type: \"string\" },\n { name: \"chainId\", type: \"uint256\" },\n { name: \"verifyingContract\", type: \"address\" },\n { name: \"salt\", type: \"bytes32\" },\n { name: \"extensions\", type: \"uint256[]\" },\n ],\n stateMutability: \"view\",\n type: \"function\",\n },\n ] as const;\n\n // version() ABI(OpenZeppelin v4)\n const versionABI = [\n {\n inputs: [],\n name: \"version\",\n outputs: [{ name: \"\", type: \"string\" }],\n stateMutability: \"view\",\n type: \"function\",\n },\n ] as const;\n\n try {\n // 获取 token name\n const name = await client.readContract({\n address,\n abi: erc20ABI,\n functionName: \"name\",\n });\n\n // 尝试获取 version,优先使用 EIP-5267\n let version = \"1\"; // 默认版本\n try {\n const result = await client.readContract({\n address,\n abi: eip712DomainABI,\n functionName: \"eip712Domain\",\n });\n // eip712Domain 返回 [fields, name, version, chainId, verifyingContract, salt, extensions]\n version = result[2] as string; // version 是第 3 个元素(索引 2)\n } catch {\n // 回退到 version() 函数(OpenZeppelin v4)\n try {\n version = await client.readContract({\n address,\n abi: versionABI,\n functionName: \"version\",\n });\n } catch {\n // 如果两种方法都不可用,使用默认值 \"1\"\n console.log(` ℹ️ Using default version \"1\" for token ${address}`);\n }\n }\n\n return {\n name: name as string,\n version: version as string,\n };\n } catch (error) {\n console.error(`Error getting token info for ${address}:`, error);\n throw new Error(`Failed to get token info: ${error}`);\n }\n}\n\n","import type { Facilitator } from \"@wtflabs/x402-facilitator\";\nimport type { X402PaymentSchema, X402PaymentSchemaWithExtra } from \"@wtflabs/x402-schema\";\nimport type { PublicClient } from \"viem\";\nimport type {\n InitializeResult,\n SettleResult,\n VerifyResult,\n X402ServerConfig,\n} from \"./types\";\nimport { PaymentPayload, PaymentRequirements } from \"@wtflabs/x402/types\";\nimport { detectTokenPaymentMethods, getRecommendedPaymentMethod, getTokenInfo, type PaymentMethod } from \"./token-detection\";\n\n/**\n * X402Server 类\n * 集成 facilitator, schema 和 client,提供完整的服务端支付处理\n *\n * @example\n * ```typescript\n * import { X402Server } from \"@wtflabs/x402-server\";\n * import { Facilitator } from \"@wtflabs/x402-facilitator\";\n * import { X402PaymentSchema } from \"@wtflabs/x402-schema\";\n * import { createPublicClient, http } from \"viem\";\n * import { bscTestnet } from \"viem/chains\";\n *\n * const facilitator = new Facilitator({\n * recipientAddress: \"0x1234...\",\n * });\n *\n * const schema = new X402PaymentSchema({\n * scheme: \"exact\",\n * network: \"bsc-testnet\",\n * maxAmountRequired: \"100000\",\n * resource: \"http://localhost:3000/protected-resource\",\n * description: \"Access to protected resource\",\n * mimeType: \"application/json\",\n * payTo: \"0x1234...\",\n * maxTimeoutSeconds: 3600,\n * asset: \"0x5678...\",\n * });\n *\n * const client = createPublicClient({\n * chain: bscTestnet,\n * transport: http(),\n * });\n *\n * const server = new X402Server({\n * facilitator,\n * schema,\n * client,\n * });\n *\n * // 初始化和校验\n * await server.initialize();\n *\n * // 验证\n * const verifyResult = await server.verify();\n *\n * // 结算\n * const settleResult = await server.settle(paymentPayload, paymentRequirements);\n * ```\n */\nexport class X402Server {\n private facilitator: Facilitator;\n private schema: X402PaymentSchema;\n private client: PublicClient;\n private initialized: boolean = false;\n\n constructor(config: X402ServerConfig) {\n this.facilitator = config.facilitator;\n this.schema = config.schema;\n this.client = config.client;\n }\n\n /**\n * 初始化服务器\n * 初始化和校验 schema 等数据,对 schema 增加 facilitator 数据 extra: {relayer}\n * 并获取 token 的 name 和 version 信息\n */\n async initialize(): Promise<InitializeResult> {\n try {\n // 验证 schema\n this.schema.verify();\n\n // 获取 token 信息(name 和 version)并添加到 schema extra 中\n const schemaAsset = this.schema.get(\"asset\");\n if (schemaAsset) {\n try {\n const tokenInfo = await getTokenInfo(schemaAsset, this.client);\n this.schema.setExtra({\n relayer: this.facilitator.relayer,\n name: tokenInfo.name,\n version: tokenInfo.version,\n });\n console.log(`✅ Token info retrieved: ${tokenInfo.name} v${tokenInfo.version}`);\n } catch (error) {\n console.warn(`⚠️ Failed to get token info, signatures may fail:`, error);\n // 仍然设置 relayer,但没有 name 和 version\n this.schema.setExtra({\n relayer: this.facilitator.relayer,\n });\n }\n } else {\n // 如果没有 asset,只设置 relayer\n this.schema.setExtra({\n relayer: this.facilitator.relayer,\n });\n }\n\n // TODO 将_verify中的内容内置到initialize中\n const verifyResult = await this._verify();\n if (!verifyResult.success) {\n return {\n success: false,\n error: verifyResult.errors?.[0] || \"Verification failed\",\n };\n }\n\n this.initialized = true;\n return { success: true };\n } catch (error) {\n return {\n success: false,\n error:\n error instanceof Error\n ? error.message\n : \"Initialization failed\",\n };\n }\n }\n\n /**\n * 验证配置\n * 1. 验证 client network 是否和 schema 的 network 匹配\n * 2. 验证 facilitator recipientAddress 和 schema payTo 是否一致\n */\n async _verify(): Promise<VerifyResult> {\n\n const errors: string[] = [];\n\n try {\n // 1. 检测 token 对 permit 和 eip3009 的支持\n const schemaAsset = this.schema.get(\"asset\");\n if (schemaAsset) {\n const tokenCapabilities = await detectTokenPaymentMethods(\n schemaAsset,\n this.client\n );\n\n // 如果 schema 中不存在 paymentType,则根据 tokenCapabilities 自动确定\n // 优先级:eip3009 > permit2 > permit\n const currentPaymentType = this.schema.get(\"paymentType\");\n if (!currentPaymentType) {\n const recommendedMethod = getRecommendedPaymentMethod(tokenCapabilities);\n if (recommendedMethod) {\n this.schema.set(\"paymentType\", recommendedMethod);\n // console.log(`✅ Auto-selected payment method: ${recommendedMethod}`);\n } else {\n errors.push(\n `Token ${schemaAsset} does not support any advanced payment methods (permit, eip3009, permit2). Please specify paymentType manually.`\n );\n }\n } else {\n // 验证 schema 中指定的 paymentType 是否被 token 支持\n if (!tokenCapabilities.supportedMethods.includes(currentPaymentType)) {\n errors.push(\n `Token ${schemaAsset} does not support the specified payment method \"${currentPaymentType}\". Supported methods: ${tokenCapabilities.supportedMethods.join(\", \")}`\n );\n }\n }\n\n // 如果 token 不支持任何高级支付方法,给出警告\n if (tokenCapabilities.supportedMethods.length === 0) {\n errors.push(\n `Token ${schemaAsset} does not support any advanced payment methods (permit, eip3009, permit2)`\n );\n }\n }\n\n // 2. 检查 facilitator 的 /supported 是否包含此代币和链\n const clientChainId = this.client.chain?.id;\n const schemaNetwork = this.schema.get(\"network\");\n\n if (clientChainId && schemaAsset) {\n const facilitatorSupported = await this.facilitator.supported({\n chainId: clientChainId,\n tokenAddress: schemaAsset,\n });\n\n // console.log(\n // `Checking facilitator support for chainId ${clientChainId} and token ${schemaAsset}`\n // );\n\n // 检查 facilitator 是否支持当前的链和代币组合\n const isSupportedByFacilitator = facilitatorSupported.kinds.some(\n (kind) => {\n // 检查网络匹配\n const networkMatches = kind.network === schemaNetwork;\n\n // 检查资产匹配\n const assetsInKind = (kind.extra as any)?.assets || [];\n const assetMatches = assetsInKind.some(\n (asset: any) =>\n asset.address.toLowerCase() === schemaAsset.toLowerCase()\n );\n\n return networkMatches && assetMatches;\n }\n );\n\n if (!isSupportedByFacilitator) {\n errors.push(\n `Facilitator does not support token ${schemaAsset} on network ${schemaNetwork} (chainId: ${clientChainId})`\n );\n } else {\n // console.log(`✅ Facilitator supports this configuration`);\n }\n\n // 3. 检查当前配置的链是否在 /supported 中\n const chainSupported = facilitatorSupported.kinds.some(\n (kind) => kind.network === schemaNetwork\n );\n\n if (!chainSupported) {\n errors.push(\n `Facilitator does not support network ${schemaNetwork} (chainId: ${clientChainId})`\n );\n }\n }\n\n // 4. 验证 network 匹配\n // 简化的网络验证逻辑\n // 实际应用中可能需要更复杂的网络匹配逻辑\n if (clientChainId) {\n // 检查 schema network 是否包含 chainId\n const networkValid = this.validateNetwork(\n schemaNetwork,\n clientChainId,\n );\n if (!networkValid) {\n errors.push(\n `Network mismatch: client chainId ${clientChainId} does not match schema network ${schemaNetwork}`,\n );\n }\n }\n\n // 2. 验证 payTo 和 recipientAddress 匹配\n const schemaPayTo = this.schema.get(\"payTo\");\n const facilitatorRecipientAddress =\n this.facilitator.recipientAddress;\n\n if (\n schemaPayTo.toLowerCase() !==\n facilitatorRecipientAddress.toLowerCase()\n ) {\n errors.push(\n `Address mismatch: schema payTo ${schemaPayTo} does not match facilitator recipientAddress ${facilitatorRecipientAddress}`,\n );\n }\n\n // 3. 调用 facilitator verify(如果有支付负载的话)\n // 这里暂时只做配置验证,实际支付验证在处理支付时进行\n\n return {\n success: errors.length === 0,\n errors: errors.length > 0 ? errors : undefined,\n };\n } catch (error) {\n errors.push(\n error instanceof Error\n ? error.message\n : \"Unknown verification error\",\n );\n return {\n success: false,\n errors,\n };\n }\n }\n\n /**\n * 结算支付\n * @param paymentPayload 支付负载\n * @param paymentRequirements 支付要求\n */\n async settle(\n paymentPayload: any,\n paymentRequirements: any,\n ): Promise<SettleResult> {\n if (!this.initialized) {\n return {\n success: false,\n error:\n \"Server not initialized. Please call initialize() first.\",\n };\n }\n\n try {\n // 调用 facilitator 进行结算\n const result = await this.facilitator.settle(\n paymentPayload,\n paymentRequirements,\n );\n\n if (!result.success) {\n return {\n success: false,\n error: result.error || result.errorMessage,\n };\n }\n\n return {\n success: true,\n transactionHash: result.transactionHash,\n };\n } catch (error) {\n return {\n success: false,\n error:\n error instanceof Error\n ? error.message\n : \"Settlement failed\",\n };\n }\n }\n\n /**\n * 验证支付负载\n * @param paymentPayload 支付负载\n * @param paymentRequirements 支付要求\n */\n async verifyPayment(\n paymentPayload: any,\n paymentRequirements: any,\n ): Promise<{\n success: boolean;\n data?: string;\n error?: string;\n }> {\n if (!this.initialized) {\n return {\n success: false,\n error:\n \"Server not initialized. Please call initialize() first.\",\n };\n }\n\n try {\n const result = await this.facilitator.verify(\n paymentPayload,\n paymentRequirements,\n );\n\n return {\n success: result.success,\n data: result.payer,\n error: result.error || result.errorMessage,\n };\n } catch (error) {\n return {\n success: false,\n error:\n error instanceof Error\n ? error.message\n : \"Payment verification failed\",\n };\n }\n }\n\n /**\n * 获取 facilitator\n */\n getFacilitator(): Facilitator {\n return this.facilitator;\n }\n\n /**\n * 获取 schema\n */\n getSchema(): X402PaymentSchema {\n return this.schema;\n }\n\n /**\n * 获取 client\n */\n getClient(): PublicClient {\n return this.client;\n }\n\n /**\n * 检查是否已初始化\n */\n isInitialized(): boolean {\n return this.initialized;\n }\n\n /**\n * 验证网络是否匹配\n * @param schemaNetwork schema 中的 network\n * @param clientChainId client 的 chainId\n * @returns 是否匹配\n */\n private validateNetwork(\n schemaNetwork: string,\n clientChainId: number,\n ): boolean {\n // 如果是 eip155: 格式\n if (schemaNetwork.startsWith(\"eip155:\")) {\n const chainId = parseInt(schemaNetwork.split(\":\")[1] || \"0\");\n return chainId === clientChainId;\n }\n\n // 常见网络名称映射\n const networkMap: Record<string, number> = {\n \"ethereum\": 1,\n \"goerli\": 5,\n \"sepolia\": 11155111,\n \"base\": 8453,\n \"base-sepolia\": 84532,\n \"bsc\": 56,\n \"bsc-testnet\": 97,\n \"polygon\": 137,\n \"polygon-mumbai\": 80001,\n \"arbitrum\": 42161,\n \"arbitrum-goerli\": 421613,\n \"optimism\": 10,\n \"optimism-goerli\": 420,\n \"avalanche\": 43114,\n \"avalanche-fuji\": 43113,\n };\n\n const expectedChainId = networkMap[schemaNetwork];\n if (expectedChainId !== undefined) {\n return expectedChainId === clientChainId;\n }\n\n // 如果无法匹配,返回 true(宽松验证)\n return true;\n }\n\n /**\n * 解析支付 header\n * @param paymentHeaderBase64 Base64 编码的支付 header\n * @returns 解析结果,成功时返回 paymentPayload 和 paymentRequirements,失败时返回服务端的支付要求\n */\n parsePaymentHeader(\n paymentHeaderBase64: string,\n ):\n | {\n success: true;\n data: {\n paymentPayload: PaymentPayload;\n paymentRequirements: PaymentRequirements;\n };\n }\n | { success: false; data: PaymentRequirements; error: string } {\n // 获取服务端的支付要求(从 schema 转换)\n const paymentRequirements = this.schema.toJSON() as PaymentRequirements;\n\n // 检查是否有 payment header\n if (!paymentHeaderBase64) {\n return {\n success: false,\n data: paymentRequirements,\n error: \"No X-PAYMENT header\",\n };\n }\n\n // 解码 payment header\n let paymentPayload: PaymentPayload;\n try {\n const paymentHeaderJson = Buffer.from(\n paymentHeaderBase64,\n \"base64\",\n ).toString(\"utf-8\");\n paymentPayload = JSON.parse(paymentHeaderJson) as PaymentPayload;\n } catch (err) {\n return {\n success: false,\n data: paymentRequirements,\n error: \"Invalid payment header format\",\n };\n }\n\n // 验证支付数据与服务端 schema 是否一致\n const validationError = this.validatePaymentPayload(\n paymentPayload,\n paymentRequirements,\n );\n if (validationError) {\n return {\n success: false,\n data: paymentRequirements,\n error: validationError,\n };\n }\n\n // 返回成功结果\n return {\n success: true,\n data: {\n paymentPayload,\n paymentRequirements,\n },\n };\n }\n\n /**\n * 验证客户端的支付数据是否与服务端要求一致\n * @param paymentPayload 客户端的支付负载\n * @param paymentRequirements 服务端的支付要求\n * @returns 错误信息,如果验证通过则返回 null\n */\n private validatePaymentPayload(\n paymentPayload: PaymentPayload,\n paymentRequirements: PaymentRequirements,\n ): string | null {\n // 1. 验证 scheme\n if (paymentPayload.scheme !== paymentRequirements.scheme) {\n return `Scheme mismatch: expected '${paymentRequirements.scheme}', got '${paymentPayload.scheme}'`;\n }\n\n // 2. 验证 network\n if (paymentPayload.network !== paymentRequirements.network) {\n return `Network mismatch: expected '${paymentRequirements.network}', got '${paymentPayload.network}'`;\n }\n\n // 3. 验证支付金额(从 payload 中提取)\n if (paymentPayload.payload) {\n const authorization = (paymentPayload.payload as any).authorization;\n if (authorization?.value) {\n const paymentAmount = BigInt(authorization.value);\n const maxAmount = BigInt(paymentRequirements.maxAmountRequired);\n\n if (paymentAmount !== maxAmount) {\n return `Payment amount error ${paymentAmount} !== ${maxAmount}`;\n }\n }\n\n // 4. 验证 payTo 地址\n if (authorization?.to) {\n const expectedPayTo = paymentRequirements.payTo.toLowerCase();\n const actualPayTo = authorization.to.toLowerCase();\n\n if (actualPayTo !== expectedPayTo && actualPayTo !== paymentRequirements.extra?.relayer?.toLowerCase()) {\n return `PayTo address mismatch: expected '${expectedPayTo}', got '${actualPayTo}'`;\n }\n }\n\n // 5. 验证 asset 地址(如果是 permit 或 permit2)\n const authorizationType = (paymentPayload.payload as any)\n .authorizationType;\n if (\n authorizationType === \"permit\" ||\n authorizationType === \"permit2\" ||\n authorizationType === \"eip3009\"\n ) {\n // 对于 permit/permit2,asset 通常在 schema 中,需要与实际调用的合约匹配\n // 这里可以添加更多验证逻辑\n }\n }\n\n // 验证通过\n return null;\n }\n}\n\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/token-detection.ts","../src/server.ts"],"sourcesContent":["import type { Address, PublicClient } from \"viem\";\n\n/**\n * Token 信息\n */\nexport interface TokenInfo {\n name: string;\n version: string;\n}\n\n/**\n * 支持的支付方式\n */\nexport type PaymentMethod = \"eip3009\" | \"permit\" | \"permit2\" | \"permit2-witness\";\n\n/**\n * 检测结果\n */\nexport interface TokenPaymentCapabilities {\n address: string;\n supportedMethods: PaymentMethod[];\n details: {\n hasEIP3009: boolean;\n hasPermit: boolean;\n hasPermit2Approval: boolean;\n };\n}\n\n/**\n * EIP-3009 方法签名\n * - transferWithAuthorization(address,address,uint256,uint256,uint256,bytes32,uint8,bytes32,bytes32)\n * \n * 支持多个方法签名变体,以兼容不同的实现:\n * - 0xe3ee160e: 标准 EIP-3009 实现\n * - 0xcf092995: 某些代币的替代实现\n */\nconst EIP3009_SIGNATURES = [\"0xe3ee160e\", \"0xcf092995\"] as const;\n\n/**\n * EIP-2612 Permit 方法签名\n * - permit(address,address,uint256,uint256,uint8,bytes32,bytes32)\n */\nconst EIP2612_PERMIT = \"0xd505accf\" as const;\n\n/**\n * Uniswap Permit2 合约地址(所有链相同)\n */\nconst PERMIT2_ADDRESS = \"0x000000000022D473030F116dDEE9F6B43aC78BA3\" as const;\n\n/**\n * EIP-1967 标准实现槽位\n * keccak256(\"eip1967.proxy.implementation\") - 1\n */\nconst EIP1967_IMPLEMENTATION_SLOT = \"0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc\" as const;\n\n/**\n * EIP-1822 UUPS 实现槽位\n * keccak256(\"PROXIABLE\")\n */\nconst EIP1822_IMPLEMENTATION_SLOT = \"0x7050c9e0f4ca769c69bd3a8ef740bc37934f8e2c036e5a723fd8ee048ed3f8c3\" as const;\n\n/**\n * OpenZeppelin implementation() 函数签名\n */\nconst IMPLEMENTATION_FUNCTION = \"0x5c60da1b\" as const;\n\n/**\n * 检测合约是否是代理合约,并获取实现合约地址\n */\nasync function getImplementationAddress(\n client: PublicClient,\n proxyAddress: Address\n): Promise<Address | null> {\n try {\n // 方法1: 尝试读取 EIP-1967 存储槽位\n try {\n const implSlotData = await client.getStorageAt({\n address: proxyAddress,\n slot: EIP1967_IMPLEMENTATION_SLOT,\n });\n if (implSlotData && implSlotData !== \"0x0000000000000000000000000000000000000000000000000000000000000000\") {\n // 从存储槽中提取地址(最后20字节)\n const implAddress = `0x${implSlotData.slice(-40)}` as Address;\n if (implAddress !== \"0x0000000000000000000000000000000000000000\") {\n console.log(` 📦 Detected EIP-1967 proxy, implementation: ${implAddress}`);\n return implAddress;\n }\n }\n } catch {\n // 继续尝试其他方法\n }\n\n // 方法2: 尝试读取 EIP-1822 存储槽位\n try {\n const uupsSlotData = await client.getStorageAt({\n address: proxyAddress,\n slot: EIP1822_IMPLEMENTATION_SLOT,\n });\n if (uupsSlotData && uupsSlotData !== \"0x0000000000000000000000000000000000000000000000000000000000000000\") {\n const implAddress = `0x${uupsSlotData.slice(-40)}` as Address;\n if (implAddress !== \"0x0000000000000000000000000000000000000000\") {\n console.log(` 📦 Detected EIP-1822 UUPS proxy, implementation: ${implAddress}`);\n return implAddress;\n }\n }\n } catch {\n // 继续尝试其他方法\n }\n\n // 方法3: 尝试调用 implementation() 函数\n try {\n const implABI = [\n {\n inputs: [],\n name: \"implementation\",\n outputs: [{ name: \"\", type: \"address\" }],\n stateMutability: \"view\",\n type: \"function\",\n },\n ] as const;\n\n const implAddress = await client.readContract({\n address: proxyAddress,\n abi: implABI,\n functionName: \"implementation\",\n }) as Address;\n\n if (implAddress && implAddress !== \"0x0000000000000000000000000000000000000000\") {\n console.log(` 📦 Detected proxy via implementation(), implementation: ${implAddress}`);\n return implAddress;\n }\n } catch {\n // 不是代理合约或不支持 implementation() 函数\n }\n\n return null;\n } catch (error) {\n console.error(\"Error detecting proxy implementation:\", error);\n return null;\n }\n}\n\n/**\n * 检查合约是否支持某个方法(通过字节码检查)\n * 支持代理合约检测\n */\nasync function hasMethod(\n client: PublicClient,\n tokenAddress: Address,\n methodSelector: string\n): Promise<boolean> {\n try {\n // 尝试获取合约代码\n const code = await client.getBytecode({ address: tokenAddress });\n if (!code) return false;\n\n // 检查字节码中是否包含方法选择器\n const hasMethodInProxy = code.toLowerCase().includes(methodSelector.slice(2).toLowerCase());\n\n // 如果代理合约中找到了方法,直接返回 true\n if (hasMethodInProxy) {\n return true;\n }\n\n // 如果代理合约中没有找到,尝试检测是否是代理合约\n const implAddress = await getImplementationAddress(client, tokenAddress);\n if (implAddress) {\n // 获取实现合约的字节码\n const implCode = await client.getBytecode({ address: implAddress });\n if (implCode) {\n const hasMethodInImpl = implCode.toLowerCase().includes(methodSelector.slice(2).toLowerCase());\n if (hasMethodInImpl) {\n console.log(` ✅ Method ${methodSelector} found in implementation contract`);\n }\n return hasMethodInImpl;\n }\n }\n\n return false;\n } catch (error) {\n console.error(`Error checking method ${methodSelector}:`, error);\n return false;\n }\n}\n\n/**\n * 检查合约是否支持多个方法签名中的任意一个\n * 支持代理合约检测\n */\nasync function hasAnyMethod(\n client: PublicClient,\n tokenAddress: Address,\n methodSelectors: readonly string[]\n): Promise<boolean> {\n try {\n // 尝试获取合约代码\n const code = await client.getBytecode({ address: tokenAddress });\n if (!code) return false;\n\n const codeLower = code.toLowerCase();\n\n // 检查代理合约中是否包含任何一个方法选择器\n const hasMethodInProxy = methodSelectors.some(selector =>\n codeLower.includes(selector.slice(2).toLowerCase())\n );\n\n // 如果代理合约中找到了方法,直接返回 true\n if (hasMethodInProxy) {\n return true;\n }\n\n // 如果代理合约中没有找到,尝试检测是否是代理合约\n const implAddress = await getImplementationAddress(client, tokenAddress);\n if (implAddress) {\n // 获取实现合约的字节码\n const implCode = await client.getBytecode({ address: implAddress });\n if (implCode) {\n const implCodeLower = implCode.toLowerCase();\n const hasMethodInImpl = methodSelectors.some(selector =>\n implCodeLower.includes(selector.slice(2).toLowerCase())\n );\n if (hasMethodInImpl) {\n console.log(` ✅ Method(s) found in implementation contract`);\n }\n return hasMethodInImpl;\n }\n }\n\n return false;\n } catch (error) {\n console.error(`Error checking methods ${methodSelectors.join(\", \")}:`, error);\n return false;\n }\n}\n\n/**\n * 检查 Permit2 合约是否在该链上部署\n */\nasync function checkPermit2Support(client: PublicClient): Promise<boolean> {\n try {\n // 检查 Permit2 合约是否在该链上部署\n const permit2Code = await client.getBytecode({ address: PERMIT2_ADDRESS });\n if (!permit2Code) return false;\n\n // 如果 Permit2 存在,理论上任何 ERC-20 都可以使用它\n return true;\n } catch (error) {\n console.error(\"Error checking Permit2 support:\", error);\n return false;\n }\n}\n\n/**\n * 检测代币支持的支付方式\n * @param tokenAddress 代币地址\n * @param client viem PublicClient\n * @returns 检测结果\n */\nexport async function detectTokenPaymentMethods(\n tokenAddress: string,\n client: PublicClient\n): Promise<TokenPaymentCapabilities> {\n const address = tokenAddress.toLowerCase() as Address;\n\n console.log(`🔍 Detecting payment methods for token ${address}...`);\n\n // 并行检测所有方法\n const [hasEIP3009, hasPermit, hasPermit2Approval] = await Promise.all([\n hasAnyMethod(client, address, EIP3009_SIGNATURES),\n hasMethod(client, address, EIP2612_PERMIT),\n checkPermit2Support(client),\n ]);\n\n // 构建支持的方法列表\n const supportedMethods: PaymentMethod[] = [];\n\n if (hasEIP3009) {\n supportedMethods.push(\"eip3009\");\n console.log(\" ✅ EIP-3009 (transferWithAuthorization) detected\");\n }\n\n if (hasPermit) {\n supportedMethods.push(\"permit\");\n console.log(\" ✅ EIP-2612 (permit) detected\");\n }\n\n if (hasPermit2Approval) {\n supportedMethods.push(\"permit2\");\n supportedMethods.push(\"permit2-witness\");\n console.log(\" ✅ Permit2 support available (universal)\");\n }\n\n if (supportedMethods.length === 0) {\n console.log(\" ⚠️ No advanced payment methods detected (standard ERC-20 only)\");\n }\n\n return {\n address,\n supportedMethods,\n details: {\n hasEIP3009,\n hasPermit,\n hasPermit2Approval,\n },\n };\n}\n\n/**\n * 获取推荐的支付方式(仅返回 schema 支持的类型)\n * 按优先级排序:eip3009 > permit > permit2\n * 注意:permit2-witness 会被映射为 permit2,因为它们在 schema 中是同一种支付类型\n */\nexport function getRecommendedPaymentMethod(\n capabilities: TokenPaymentCapabilities\n): \"eip3009\" | \"permit2\" | \"permit\" | null {\n const { supportedMethods } = capabilities;\n\n if (supportedMethods.includes(\"eip3009\")) return \"eip3009\";\n if (supportedMethods.includes(\"permit\")) return \"permit\";\n // permit2 和 permit2-witness 都映射为 permit2(schema 只支持 permit2)\n if (supportedMethods.includes(\"permit2\") || supportedMethods.includes(\"permit2-witness\")) {\n return \"permit2\";\n }\n\n return null;\n}\n\n/**\n * 获取 token 的 name 和 version 信息(用于 EIP-712 签名)\n * 支持代理合约(会自动从代理合约读取,因为代理合约会 delegatecall 到实现合约)\n * @param tokenAddress 代币地址\n * @param client viem PublicClient\n * @returns Token 的 name 和 version\n */\nexport async function getTokenInfo(\n tokenAddress: string,\n client: PublicClient\n): Promise<TokenInfo> {\n const address = tokenAddress.toLowerCase() as Address;\n\n // ERC-20 标准 ABI\n const erc20ABI = [\n {\n inputs: [],\n name: \"name\",\n outputs: [{ name: \"\", type: \"string\" }],\n stateMutability: \"view\",\n type: \"function\",\n },\n ] as const;\n\n // EIP-5267 eip712Domain ABI(OpenZeppelin v5+)\n const eip712DomainABI = [\n {\n inputs: [],\n name: \"eip712Domain\",\n outputs: [\n { name: \"fields\", type: \"bytes1\" },\n { name: \"name\", type: \"string\" },\n { name: \"version\", type: \"string\" },\n { name: \"chainId\", type: \"uint256\" },\n { name: \"verifyingContract\", type: \"address\" },\n { name: \"salt\", type: \"bytes32\" },\n { name: \"extensions\", type: \"uint256[]\" },\n ],\n stateMutability: \"view\",\n type: \"function\",\n },\n ] as const;\n\n // version() ABI(OpenZeppelin v4)\n const versionABI = [\n {\n inputs: [],\n name: \"version\",\n outputs: [{ name: \"\", type: \"string\" }],\n stateMutability: \"view\",\n type: \"function\",\n },\n ] as const;\n\n try {\n // 检测是否为代理合约\n const implAddress = await getImplementationAddress(client, address);\n if (implAddress) {\n console.log(` 📦 Reading token info from proxy, actual calls will be delegated to implementation`);\n }\n\n // 获取 token name (对于代理合约,delegatecall 会自动转发到实现合约)\n const name = await client.readContract({\n address,\n abi: erc20ABI,\n functionName: \"name\",\n });\n\n // 尝试获取 version,优先使用 EIP-5267\n let version = \"1\"; // 默认版本\n try {\n const result = await client.readContract({\n address,\n abi: eip712DomainABI,\n functionName: \"eip712Domain\",\n });\n // eip712Domain 返回 [fields, name, version, chainId, verifyingContract, salt, extensions]\n version = result[2] as string; // version 是第 3 个元素(索引 2)\n } catch {\n // 回退到 version() 函数(OpenZeppelin v4)\n try {\n version = await client.readContract({\n address,\n abi: versionABI,\n functionName: \"version\",\n });\n } catch {\n // 如果两种方法都不可用,使用默认值 \"1\"\n console.log(` ℹ️ Using default version \"1\" for token ${address}`);\n }\n }\n\n return {\n name: name as string,\n version: version as string,\n };\n } catch (error) {\n console.error(`Error getting token info for ${address}:`, error);\n throw new Error(`Failed to get token info: ${error}`);\n }\n}\n\n","import type { Facilitator } from \"@wtflabs/x402-facilitator\";\nimport type { X402PaymentSchema, X402PaymentSchemaWithExtra } from \"@wtflabs/x402-schema\";\nimport type { PublicClient } from \"viem\";\nimport type {\n InitializeResult,\n SettleResult,\n VerifyResult,\n X402ServerConfig,\n} from \"./types\";\nimport { PaymentPayload, PaymentRequirements } from \"@wtflabs/x402/types\";\nimport { detectTokenPaymentMethods, getRecommendedPaymentMethod, getTokenInfo, type PaymentMethod } from \"./token-detection\";\n\n/**\n * X402Server 类\n * 集成 facilitator, schema 和 client,提供完整的服务端支付处理\n *\n * @example\n * ```typescript\n * import { X402Server } from \"@wtflabs/x402-server\";\n * import { Facilitator } from \"@wtflabs/x402-facilitator\";\n * import { X402PaymentSchema } from \"@wtflabs/x402-schema\";\n * import { createPublicClient, http } from \"viem\";\n * import { bscTestnet } from \"viem/chains\";\n *\n * const facilitator = new Facilitator({\n * recipientAddress: \"0x1234...\",\n * });\n *\n * const schema = new X402PaymentSchema({\n * scheme: \"exact\",\n * network: \"bsc-testnet\",\n * maxAmountRequired: \"100000\",\n * resource: \"http://localhost:3000/protected-resource\",\n * description: \"Access to protected resource\",\n * mimeType: \"application/json\",\n * payTo: \"0x1234...\",\n * maxTimeoutSeconds: 3600,\n * asset: \"0x5678...\",\n * });\n *\n * const client = createPublicClient({\n * chain: bscTestnet,\n * transport: http(),\n * });\n *\n * const server = new X402Server({\n * facilitator,\n * schema,\n * client,\n * });\n *\n * // 初始化和校验\n * await server.initialize();\n *\n * // 验证\n * const verifyResult = await server.verify();\n *\n * // 结算\n * const settleResult = await server.settle(paymentPayload, paymentRequirements);\n * ```\n */\nexport class X402Server {\n private facilitator: Facilitator;\n private schema: X402PaymentSchema;\n private client: PublicClient;\n private initialized: boolean = false;\n\n constructor(config: X402ServerConfig) {\n this.facilitator = config.facilitator;\n this.schema = config.schema;\n this.client = config.client;\n }\n\n /**\n * 初始化服务器\n * 初始化和校验 schema 等数据,对 schema 增加 facilitator 数据 extra: {relayer}\n * 并获取 token 的 name 和 version 信息\n */\n async initialize(): Promise<InitializeResult> {\n try {\n // 验证 schema\n this.schema.verify();\n\n // 获取 token 信息(name 和 version)并添加到 schema extra 中\n const schemaAsset = this.schema.get(\"asset\");\n if (schemaAsset) {\n try {\n const tokenInfo = await getTokenInfo(schemaAsset, this.client);\n this.schema.setExtra({\n relayer: this.facilitator.relayer,\n name: tokenInfo.name,\n version: tokenInfo.version,\n });\n console.log(`✅ Token info retrieved: ${tokenInfo.name} v${tokenInfo.version}`);\n } catch (error) {\n console.warn(`⚠️ Failed to get token info, signatures may fail:`, error);\n // 仍然设置 relayer,但没有 name 和 version\n this.schema.setExtra({\n relayer: this.facilitator.relayer,\n });\n }\n } else {\n // 如果没有 asset,只设置 relayer\n this.schema.setExtra({\n relayer: this.facilitator.relayer,\n });\n }\n\n // TODO 将_verify中的内容内置到initialize中\n const verifyResult = await this._verify();\n if (!verifyResult.success) {\n return {\n success: false,\n error: verifyResult.errors?.[0] || \"Verification failed\",\n };\n }\n\n this.initialized = true;\n return { success: true };\n } catch (error) {\n return {\n success: false,\n error:\n error instanceof Error\n ? error.message\n : \"Initialization failed\",\n };\n }\n }\n\n /**\n * 验证配置\n * 1. 验证 client network 是否和 schema 的 network 匹配\n * 2. 验证 facilitator recipientAddress 和 schema payTo 是否一致\n */\n async _verify(): Promise<VerifyResult> {\n\n const errors: string[] = [];\n\n try {\n // 1. 检测 token 对 permit 和 eip3009 的支持\n const schemaAsset = this.schema.get(\"asset\");\n if (schemaAsset) {\n const tokenCapabilities = await detectTokenPaymentMethods(\n schemaAsset,\n this.client\n );\n\n // 如果 schema 中不存在 paymentType,则根据 tokenCapabilities 自动确定\n // 优先级:eip3009 > permit2 > permit\n const currentPaymentType = this.schema.get(\"paymentType\");\n if (!currentPaymentType) {\n const recommendedMethod = getRecommendedPaymentMethod(tokenCapabilities);\n if (recommendedMethod) {\n this.schema.set(\"paymentType\", recommendedMethod);\n // console.log(`✅ Auto-selected payment method: ${recommendedMethod}`);\n } else {\n errors.push(\n `Token ${schemaAsset} does not support any advanced payment methods (permit, eip3009, permit2). Please specify paymentType manually.`\n );\n }\n } else {\n // 验证 schema 中指定的 paymentType 是否被 token 支持\n if (!tokenCapabilities.supportedMethods.includes(currentPaymentType)) {\n errors.push(\n `Token ${schemaAsset} does not support the specified payment method \"${currentPaymentType}\". Supported methods: ${tokenCapabilities.supportedMethods.join(\", \")}`\n );\n }\n }\n\n // 如果 token 不支持任何高级支付方法,给出警告\n if (tokenCapabilities.supportedMethods.length === 0) {\n errors.push(\n `Token ${schemaAsset} does not support any advanced payment methods (permit, eip3009, permit2)`\n );\n }\n }\n\n // 2. 检查 facilitator 的 /supported 是否包含此代币和链\n const clientChainId = this.client.chain?.id;\n const schemaNetwork = this.schema.get(\"network\");\n\n if (clientChainId && schemaAsset) {\n const facilitatorSupported = await this.facilitator.supported({\n chainId: clientChainId,\n tokenAddress: schemaAsset,\n });\n\n // console.log(\n // `Checking facilitator support for chainId ${clientChainId} and token ${schemaAsset}`\n // );\n\n // 检查 facilitator 是否支持当前的链和代币组合\n const isSupportedByFacilitator = facilitatorSupported.kinds.some(\n (kind) => {\n // 检查网络匹配\n const networkMatches = kind.network === schemaNetwork;\n\n // 检查资产匹配\n const assetsInKind = (kind.extra as any)?.assets || [];\n const assetMatches = assetsInKind.some(\n (asset: any) =>\n asset.address.toLowerCase() === schemaAsset.toLowerCase()\n );\n\n return networkMatches && assetMatches;\n }\n );\n\n if (!isSupportedByFacilitator) {\n errors.push(\n `Facilitator does not support token ${schemaAsset} on network ${schemaNetwork} (chainId: ${clientChainId})`\n );\n } else {\n // console.log(`✅ Facilitator supports this configuration`);\n }\n\n // 3. 检查当前配置的链是否在 /supported 中\n const chainSupported = facilitatorSupported.kinds.some(\n (kind) => kind.network === schemaNetwork\n );\n\n if (!chainSupported) {\n errors.push(\n `Facilitator does not support network ${schemaNetwork} (chainId: ${clientChainId})`\n );\n }\n }\n\n // 4. 验证 network 匹配\n // 简化的网络验证逻辑\n // 实际应用中可能需要更复杂的网络匹配逻辑\n if (clientChainId) {\n // 检查 schema network 是否包含 chainId\n const networkValid = this.validateNetwork(\n schemaNetwork,\n clientChainId,\n );\n if (!networkValid) {\n errors.push(\n `Network mismatch: client chainId ${clientChainId} does not match schema network ${schemaNetwork}`,\n );\n }\n }\n\n // 2. 验证 payTo 和 recipientAddress 匹配\n const schemaPayTo = this.schema.get(\"payTo\");\n const facilitatorRecipientAddress =\n this.facilitator.recipientAddress;\n\n if (\n schemaPayTo.toLowerCase() !==\n facilitatorRecipientAddress.toLowerCase()\n ) {\n errors.push(\n `Address mismatch: schema payTo ${schemaPayTo} does not match facilitator recipientAddress ${facilitatorRecipientAddress}`,\n );\n }\n\n // 3. 调用 facilitator verify(如果有支付负载的话)\n // 这里暂时只做配置验证,实际支付验证在处理支付时进行\n\n return {\n success: errors.length === 0,\n errors: errors.length > 0 ? errors : undefined,\n };\n } catch (error) {\n errors.push(\n error instanceof Error\n ? error.message\n : \"Unknown verification error\",\n );\n return {\n success: false,\n errors,\n };\n }\n }\n\n /**\n * 结算支付\n * @param paymentPayload 支付负载\n * @param paymentRequirements 支付要求\n */\n async settle(\n paymentPayload: any,\n paymentRequirements: any,\n ): Promise<SettleResult> {\n if (!this.initialized) {\n return {\n success: false,\n error:\n \"Server not initialized. Please call initialize() first.\",\n };\n }\n\n try {\n // 调用 facilitator 进行结算\n const result = await this.facilitator.settle(\n paymentPayload,\n paymentRequirements,\n );\n\n if (!result.success) {\n return {\n success: false,\n error: result.error || result.errorMessage,\n };\n }\n\n return {\n success: true,\n transaction: result.transaction,\n };\n } catch (error) {\n return {\n success: false,\n error:\n error instanceof Error\n ? error.message\n : \"Settlement failed\",\n };\n }\n }\n\n /**\n * 验证支付负载\n * @param paymentPayload 支付负载\n * @param paymentRequirements 支付要求\n */\n async verifyPayment(\n paymentPayload: any,\n paymentRequirements: any,\n ): Promise<{\n success: boolean;\n data?: string;\n error?: string;\n }> {\n if (!this.initialized) {\n return {\n success: false,\n error:\n \"Server not initialized. Please call initialize() first.\",\n };\n }\n\n try {\n const result = await this.facilitator.verify(\n paymentPayload,\n paymentRequirements,\n );\n\n return {\n success: result.success,\n data: result.payer,\n error: result.error || result.errorMessage,\n };\n } catch (error) {\n return {\n success: false,\n error:\n error instanceof Error\n ? error.message\n : \"Payment verification failed\",\n };\n }\n }\n\n /**\n * 获取 facilitator\n */\n getFacilitator(): Facilitator {\n return this.facilitator;\n }\n\n /**\n * 获取 schema\n */\n getSchema(): X402PaymentSchema {\n return this.schema;\n }\n\n /**\n * 获取 client\n */\n getClient(): PublicClient {\n return this.client;\n }\n\n /**\n * 检查是否已初始化\n */\n isInitialized(): boolean {\n return this.initialized;\n }\n\n /**\n * 验证网络是否匹配\n * @param schemaNetwork schema 中的 network\n * @param clientChainId client 的 chainId\n * @returns 是否匹配\n */\n private validateNetwork(\n schemaNetwork: string,\n clientChainId: number,\n ): boolean {\n // 如果是 eip155: 格式\n if (schemaNetwork.startsWith(\"eip155:\")) {\n const chainId = parseInt(schemaNetwork.split(\":\")[1] || \"0\");\n return chainId === clientChainId;\n }\n\n // 常见网络名称映射\n const networkMap: Record<string, number> = {\n \"ethereum\": 1,\n \"goerli\": 5,\n \"sepolia\": 11155111,\n \"base\": 8453,\n \"base-sepolia\": 84532,\n \"bsc\": 56,\n \"bsc-testnet\": 97,\n \"polygon\": 137,\n \"polygon-mumbai\": 80001,\n \"arbitrum\": 42161,\n \"arbitrum-goerli\": 421613,\n \"optimism\": 10,\n \"optimism-goerli\": 420,\n \"avalanche\": 43114,\n \"avalanche-fuji\": 43113,\n };\n\n const expectedChainId = networkMap[schemaNetwork];\n if (expectedChainId !== undefined) {\n return expectedChainId === clientChainId;\n }\n\n // 如果无法匹配,返回 true(宽松验证)\n return true;\n }\n\n /**\n * 解析支付 header\n * @param paymentHeaderBase64 Base64 编码的支付 header\n * @returns 解析结果,成功时返回 paymentPayload 和 paymentRequirements,失败时返回服务端的支付要求\n */\n parsePaymentHeader(\n paymentHeaderBase64: string,\n ):\n | {\n success: true;\n data: {\n paymentPayload: PaymentPayload;\n paymentRequirements: PaymentRequirements;\n };\n }\n | { success: false; data: PaymentRequirements; error: string } {\n // 获取服务端的支付要求(从 schema 转换)\n const paymentRequirements = this.schema.toJSON() as PaymentRequirements;\n\n // 检查是否有 payment header\n if (!paymentHeaderBase64) {\n return {\n success: false,\n data: paymentRequirements,\n error: \"No X-PAYMENT header\",\n };\n }\n\n // 解码 payment header\n let paymentPayload: PaymentPayload;\n try {\n const paymentHeaderJson = Buffer.from(\n paymentHeaderBase64,\n \"base64\",\n ).toString(\"utf-8\");\n paymentPayload = JSON.parse(paymentHeaderJson) as PaymentPayload;\n } catch (err) {\n return {\n success: false,\n data: paymentRequirements,\n error: \"Invalid payment header format\",\n };\n }\n\n // 验证支付数据与服务端 schema 是否一致\n const validationError = this.validatePaymentPayload(\n paymentPayload,\n paymentRequirements,\n );\n if (validationError) {\n return {\n success: false,\n data: paymentRequirements,\n error: validationError,\n };\n }\n\n // 返回成功结果\n return {\n success: true,\n data: {\n paymentPayload,\n paymentRequirements,\n },\n };\n }\n\n /**\n * 验证客户端的支付数据是否与服务端要求一致\n * @param paymentPayload 客户端的支付负载\n * @param paymentRequirements 服务端的支付要求\n * @returns 错误信息,如果验证通过则返回 null\n */\n private validatePaymentPayload(\n paymentPayload: PaymentPayload,\n paymentRequirements: PaymentRequirements,\n ): string | null {\n // 1. 验证 scheme\n if (paymentPayload.scheme !== paymentRequirements.scheme) {\n return `Scheme mismatch: expected '${paymentRequirements.scheme}', got '${paymentPayload.scheme}'`;\n }\n\n // 2. 验证 network\n if (paymentPayload.network !== paymentRequirements.network) {\n return `Network mismatch: expected '${paymentRequirements.network}', got '${paymentPayload.network}'`;\n }\n\n // 3. 验证支付金额(从 payload 中提取)\n if (paymentPayload.payload) {\n const authorization = (paymentPayload.payload as any).authorization;\n if (authorization?.value) {\n const paymentAmount = BigInt(authorization.value);\n const maxAmount = BigInt(paymentRequirements.maxAmountRequired);\n\n if (paymentAmount !== maxAmount) {\n return `Payment amount error ${paymentAmount} !== ${maxAmount}`;\n }\n }\n\n // 4. 验证 payTo 地址\n if (authorization?.to) {\n const expectedPayTo = paymentRequirements.payTo.toLowerCase();\n const actualPayTo = authorization.to.toLowerCase();\n\n if (actualPayTo !== expectedPayTo && actualPayTo !== paymentRequirements.extra?.relayer?.toLowerCase()) {\n return `PayTo address mismatch: expected '${expectedPayTo}', got '${actualPayTo}'`;\n }\n }\n\n // 5. 验证 asset 地址(如果是 permit 或 permit2)\n const authorizationType = (paymentPayload.payload as any)\n .authorizationType;\n if (\n authorizationType === \"permit\" ||\n authorizationType === \"permit2\" ||\n authorizationType === \"eip3009\"\n ) {\n // 对于 permit/permit2,asset 通常在 schema 中,需要与实际调用的合约匹配\n // 这里可以添加更多验证逻辑\n }\n }\n\n // 验证通过\n return null;\n }\n}\n\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wtflabs/x402-server",
|
|
3
|
-
"version": "0.0.1-beta.
|
|
3
|
+
"version": "0.0.1-beta.4",
|
|
4
4
|
"main": "./dist/index.js",
|
|
5
5
|
"module": "./dist/index.mjs",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -21,8 +21,8 @@
|
|
|
21
21
|
"dependencies": {
|
|
22
22
|
"@wtflabs/x402": "^0.0.1-beta.4",
|
|
23
23
|
"viem": "^2.21.26",
|
|
24
|
-
"@wtflabs/x402-
|
|
25
|
-
"@wtflabs/x402-
|
|
24
|
+
"@wtflabs/x402-schema": "0.0.1-beta.4",
|
|
25
|
+
"@wtflabs/x402-facilitator": "0.0.1-beta.4"
|
|
26
26
|
},
|
|
27
27
|
"exports": {
|
|
28
28
|
".": {
|