moltspay 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,204 @@
1
+ // src/verify/index.ts
2
+ import { ethers } from "ethers";
3
+
4
+ // src/chains/index.ts
5
+ var CHAINS = {
6
+ // ============ 主网 ============
7
+ base: {
8
+ name: "Base",
9
+ chainId: 8453,
10
+ rpc: "https://mainnet.base.org",
11
+ usdc: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
12
+ explorer: "https://basescan.org/address/",
13
+ explorerTx: "https://basescan.org/tx/",
14
+ avgBlockTime: 2
15
+ },
16
+ polygon: {
17
+ name: "Polygon",
18
+ chainId: 137,
19
+ rpc: "https://polygon-rpc.com",
20
+ usdc: "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359",
21
+ explorer: "https://polygonscan.com/address/",
22
+ explorerTx: "https://polygonscan.com/tx/",
23
+ avgBlockTime: 2
24
+ },
25
+ ethereum: {
26
+ name: "Ethereum",
27
+ chainId: 1,
28
+ rpc: "https://eth.llamarpc.com",
29
+ usdc: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
30
+ explorer: "https://etherscan.io/address/",
31
+ explorerTx: "https://etherscan.io/tx/",
32
+ avgBlockTime: 12
33
+ },
34
+ // ============ 测试网 ============
35
+ base_sepolia: {
36
+ name: "Base Sepolia",
37
+ chainId: 84532,
38
+ rpc: "https://sepolia.base.org",
39
+ usdc: "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
40
+ explorer: "https://sepolia.basescan.org/address/",
41
+ explorerTx: "https://sepolia.basescan.org/tx/",
42
+ avgBlockTime: 2
43
+ },
44
+ sepolia: {
45
+ name: "Sepolia",
46
+ chainId: 11155111,
47
+ rpc: "https://rpc.sepolia.org",
48
+ usdc: "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238",
49
+ explorer: "https://sepolia.etherscan.io/address/",
50
+ explorerTx: "https://sepolia.etherscan.io/tx/",
51
+ avgBlockTime: 12
52
+ }
53
+ };
54
+ function getChain(name) {
55
+ const config = CHAINS[name];
56
+ if (!config) {
57
+ throw new Error(`Unsupported chain: ${name}. Supported: ${Object.keys(CHAINS).join(", ")}`);
58
+ }
59
+ return config;
60
+ }
61
+ function getChainById(chainId) {
62
+ return Object.values(CHAINS).find((c) => c.chainId === chainId);
63
+ }
64
+
65
+ // src/verify/index.ts
66
+ var TRANSFER_EVENT_TOPIC = ethers.id("Transfer(address,address,uint256)");
67
+ async function verifyPayment(params) {
68
+ const { txHash, expectedAmount, expectedTo } = params;
69
+ let chain;
70
+ try {
71
+ if (typeof params.chain === "number") {
72
+ chain = getChainById(params.chain);
73
+ } else {
74
+ chain = getChain(params.chain || "base");
75
+ }
76
+ if (!chain) {
77
+ return { verified: false, error: `\u4E0D\u652F\u6301\u7684\u94FE: ${params.chain}` };
78
+ }
79
+ } catch (e) {
80
+ return { verified: false, error: `\u4E0D\u652F\u6301\u7684\u94FE: ${params.chain}` };
81
+ }
82
+ try {
83
+ const provider = new ethers.JsonRpcProvider(chain.rpc);
84
+ const receipt = await provider.getTransactionReceipt(txHash);
85
+ if (!receipt) {
86
+ return { verified: false, error: "\u4EA4\u6613\u672A\u627E\u5230\u6216\u672A\u786E\u8BA4" };
87
+ }
88
+ if (receipt.status !== 1) {
89
+ return { verified: false, error: "\u4EA4\u6613\u5931\u8D25" };
90
+ }
91
+ const usdcAddress = chain.usdc?.toLowerCase();
92
+ if (!usdcAddress) {
93
+ return { verified: false, error: `\u94FE ${chain.name} \u672A\u914D\u7F6EUSDC\u5730\u5740` };
94
+ }
95
+ for (const log of receipt.logs) {
96
+ if (log.address.toLowerCase() !== usdcAddress) {
97
+ continue;
98
+ }
99
+ if (log.topics.length < 3 || log.topics[0] !== TRANSFER_EVENT_TOPIC) {
100
+ continue;
101
+ }
102
+ const from = "0x" + log.topics[1].slice(-40);
103
+ const to = "0x" + log.topics[2].slice(-40);
104
+ const amountRaw = BigInt(log.data);
105
+ const amount = Number(amountRaw) / 1e6;
106
+ if (expectedTo && to.toLowerCase() !== expectedTo.toLowerCase()) {
107
+ continue;
108
+ }
109
+ if (amount < expectedAmount) {
110
+ return {
111
+ verified: false,
112
+ error: `\u91D1\u989D\u4E0D\u8DB3: \u6536\u5230 ${amount} USDC, \u9700\u8981 ${expectedAmount} USDC`,
113
+ amount,
114
+ from,
115
+ to,
116
+ txHash,
117
+ blockNumber: receipt.blockNumber
118
+ };
119
+ }
120
+ return {
121
+ verified: true,
122
+ amount,
123
+ from,
124
+ to,
125
+ txHash,
126
+ blockNumber: receipt.blockNumber
127
+ };
128
+ }
129
+ return { verified: false, error: "\u672A\u627E\u5230USDC\u8F6C\u8D26\u8BB0\u5F55" };
130
+ } catch (e) {
131
+ return { verified: false, error: e.message || String(e) };
132
+ }
133
+ }
134
+ async function getTransactionStatus(txHash, chain = "base") {
135
+ let chainConfig;
136
+ try {
137
+ chainConfig = typeof chain === "number" ? getChainById(chain) : getChain(chain);
138
+ if (!chainConfig) return { status: "not_found" };
139
+ } catch {
140
+ return { status: "not_found" };
141
+ }
142
+ try {
143
+ const provider = new ethers.JsonRpcProvider(chainConfig.rpc);
144
+ const receipt = await provider.getTransactionReceipt(txHash);
145
+ if (!receipt) {
146
+ const tx = await provider.getTransaction(txHash);
147
+ if (tx) {
148
+ return { status: "pending" };
149
+ }
150
+ return { status: "not_found" };
151
+ }
152
+ const currentBlock = await provider.getBlockNumber();
153
+ const confirmations = currentBlock - receipt.blockNumber;
154
+ if (receipt.status === 1) {
155
+ return {
156
+ status: "confirmed",
157
+ blockNumber: receipt.blockNumber,
158
+ confirmations
159
+ };
160
+ } else {
161
+ return {
162
+ status: "failed",
163
+ blockNumber: receipt.blockNumber
164
+ };
165
+ }
166
+ } catch {
167
+ return { status: "not_found" };
168
+ }
169
+ }
170
+ async function waitForTransaction(txHash, chain = "base", confirmations = 1, timeoutMs = 6e4) {
171
+ let chainConfig;
172
+ try {
173
+ chainConfig = typeof chain === "number" ? getChainById(chain) : getChain(chain);
174
+ if (!chainConfig) {
175
+ return { verified: false, confirmed: false, error: `\u4E0D\u652F\u6301\u7684\u94FE: ${chain}` };
176
+ }
177
+ } catch (e) {
178
+ return { verified: false, confirmed: false, error: `\u4E0D\u652F\u6301\u7684\u94FE: ${chain}` };
179
+ }
180
+ const provider = new ethers.JsonRpcProvider(chainConfig.rpc);
181
+ try {
182
+ const receipt = await provider.waitForTransaction(txHash, confirmations, timeoutMs);
183
+ if (!receipt) {
184
+ return { verified: false, confirmed: false, error: "\u7B49\u5F85\u8D85\u65F6" };
185
+ }
186
+ if (receipt.status !== 1) {
187
+ return { verified: false, confirmed: true, error: "\u4EA4\u6613\u5931\u8D25" };
188
+ }
189
+ return {
190
+ verified: true,
191
+ confirmed: true,
192
+ txHash,
193
+ blockNumber: receipt.blockNumber
194
+ };
195
+ } catch (e) {
196
+ return { verified: false, confirmed: false, error: e.message || String(e) };
197
+ }
198
+ }
199
+ export {
200
+ getTransactionStatus,
201
+ verifyPayment,
202
+ waitForTransaction
203
+ };
204
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/verify/index.ts","../../src/chains/index.ts"],"sourcesContent":["/**\n * 链上支付验证模块\n */\n\nimport { ethers } from 'ethers';\nimport { getChain, getChainById, type ChainConfig, type ChainName } from '../chains';\n\n// ERC20 Transfer 事件签名\nconst TRANSFER_EVENT_TOPIC = ethers.id('Transfer(address,address,uint256)');\n\nexport interface VerifyPaymentParams {\n txHash: string;\n expectedAmount: number;\n expectedTo?: string;\n chain?: string | number;\n}\n\nexport interface VerifyPaymentResult {\n verified: boolean;\n amount?: number;\n from?: string;\n to?: string;\n txHash?: string;\n blockNumber?: number;\n error?: string;\n}\n\n/**\n * 验证链上支付\n */\nexport async function verifyPayment(params: VerifyPaymentParams): Promise<VerifyPaymentResult> {\n const { txHash, expectedAmount, expectedTo } = params;\n \n // 获取链配置\n let chain: ChainConfig | undefined;\n try {\n if (typeof params.chain === 'number') {\n chain = getChainById(params.chain);\n } else {\n chain = getChain((params.chain || 'base') as ChainName);\n }\n if (!chain) {\n return { verified: false, error: `不支持的链: ${params.chain}` };\n }\n } catch (e) {\n return { verified: false, error: `不支持的链: ${params.chain}` };\n }\n\n try {\n const provider = new ethers.JsonRpcProvider(chain.rpc);\n \n // 获取交易回执\n const receipt = await provider.getTransactionReceipt(txHash);\n \n if (!receipt) {\n return { verified: false, error: '交易未找到或未确认' };\n }\n\n if (receipt.status !== 1) {\n return { verified: false, error: '交易失败' };\n }\n\n // 解析 Transfer 事件\n const usdcAddress = chain.usdc?.toLowerCase();\n if (!usdcAddress) {\n return { verified: false, error: `链 ${chain.name} 未配置USDC地址` };\n }\n\n for (const log of receipt.logs) {\n // 检查是否是 USDC 合约\n if (log.address.toLowerCase() !== usdcAddress) {\n continue;\n }\n\n // 检查是否是 Transfer 事件\n if (log.topics.length < 3 || log.topics[0] !== TRANSFER_EVENT_TOPIC) {\n continue;\n }\n\n // 解析 Transfer 事件参数\n const from = '0x' + log.topics[1].slice(-40);\n const to = '0x' + log.topics[2].slice(-40);\n const amountRaw = BigInt(log.data);\n const amount = Number(amountRaw) / 1e6; // USDC 6位小数\n\n // 验证收款地址\n if (expectedTo && to.toLowerCase() !== expectedTo.toLowerCase()) {\n continue;\n }\n\n // 验证金额\n if (amount < expectedAmount) {\n return {\n verified: false,\n error: `金额不足: 收到 ${amount} USDC, 需要 ${expectedAmount} USDC`,\n amount,\n from,\n to,\n txHash,\n blockNumber: receipt.blockNumber,\n };\n }\n\n // 验证成功\n return {\n verified: true,\n amount,\n from,\n to,\n txHash,\n blockNumber: receipt.blockNumber,\n };\n }\n\n return { verified: false, error: '未找到USDC转账记录' };\n\n } catch (e: any) {\n return { verified: false, error: e.message || String(e) };\n }\n}\n\n/**\n * 获取交易状态\n */\nexport async function getTransactionStatus(\n txHash: string,\n chain: string | number = 'base'\n): Promise<{\n status: 'pending' | 'confirmed' | 'failed' | 'not_found';\n blockNumber?: number;\n confirmations?: number;\n}> {\n let chainConfig: ChainConfig | undefined;\n try {\n chainConfig = typeof chain === 'number' ? getChainById(chain) : getChain(chain as ChainName);\n if (!chainConfig) return { status: 'not_found' };\n } catch {\n return { status: 'not_found' };\n }\n\n try {\n const provider = new ethers.JsonRpcProvider(chainConfig.rpc);\n const receipt = await provider.getTransactionReceipt(txHash);\n\n if (!receipt) {\n // 检查是否在 pending 池中\n const tx = await provider.getTransaction(txHash);\n if (tx) {\n return { status: 'pending' };\n }\n return { status: 'not_found' };\n }\n\n const currentBlock = await provider.getBlockNumber();\n const confirmations = currentBlock - receipt.blockNumber;\n\n if (receipt.status === 1) {\n return {\n status: 'confirmed',\n blockNumber: receipt.blockNumber,\n confirmations,\n };\n } else {\n return {\n status: 'failed',\n blockNumber: receipt.blockNumber,\n };\n }\n } catch {\n return { status: 'not_found' };\n }\n}\n\n/**\n * 等待交易确认\n */\nexport async function waitForTransaction(\n txHash: string,\n chain: string | number = 'base',\n confirmations = 1,\n timeoutMs = 60000\n): Promise<VerifyPaymentResult & { confirmed: boolean }> {\n let chainConfig: ChainConfig | undefined;\n try {\n chainConfig = typeof chain === 'number' ? getChainById(chain) : getChain(chain as ChainName);\n if (!chainConfig) {\n return { verified: false, confirmed: false, error: `不支持的链: ${chain}` };\n }\n } catch (e) {\n return { verified: false, confirmed: false, error: `不支持的链: ${chain}` };\n }\n\n const provider = new ethers.JsonRpcProvider(chainConfig.rpc);\n \n try {\n const receipt = await provider.waitForTransaction(txHash, confirmations, timeoutMs);\n \n if (!receipt) {\n return { verified: false, confirmed: false, error: '等待超时' };\n }\n\n if (receipt.status !== 1) {\n return { verified: false, confirmed: true, error: '交易失败' };\n }\n\n return {\n verified: true,\n confirmed: true,\n txHash,\n blockNumber: receipt.blockNumber,\n };\n } catch (e: any) {\n return { verified: false, confirmed: false, error: e.message || String(e) };\n }\n}\n","/**\n * 区块链配置\n */\n\nimport type { ChainConfig, ChainName } from '../types/index.js';\n\nexport const CHAINS: Record<ChainName, ChainConfig> = {\n // ============ 主网 ============\n base: {\n name: 'Base',\n chainId: 8453,\n rpc: 'https://mainnet.base.org',\n usdc: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',\n explorer: 'https://basescan.org/address/',\n explorerTx: 'https://basescan.org/tx/',\n avgBlockTime: 2,\n },\n polygon: {\n name: 'Polygon',\n chainId: 137,\n rpc: 'https://polygon-rpc.com',\n usdc: '0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359',\n explorer: 'https://polygonscan.com/address/',\n explorerTx: 'https://polygonscan.com/tx/',\n avgBlockTime: 2,\n },\n ethereum: {\n name: 'Ethereum',\n chainId: 1,\n rpc: 'https://eth.llamarpc.com',\n usdc: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',\n explorer: 'https://etherscan.io/address/',\n explorerTx: 'https://etherscan.io/tx/',\n avgBlockTime: 12,\n },\n\n // ============ 测试网 ============\n base_sepolia: {\n name: 'Base Sepolia',\n chainId: 84532,\n rpc: 'https://sepolia.base.org',\n usdc: '0x036CbD53842c5426634e7929541eC2318f3dCF7e',\n explorer: 'https://sepolia.basescan.org/address/',\n explorerTx: 'https://sepolia.basescan.org/tx/',\n avgBlockTime: 2,\n },\n sepolia: {\n name: 'Sepolia',\n chainId: 11155111,\n rpc: 'https://rpc.sepolia.org',\n usdc: '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238',\n explorer: 'https://sepolia.etherscan.io/address/',\n explorerTx: 'https://sepolia.etherscan.io/tx/',\n avgBlockTime: 12,\n },\n};\n\n/**\n * 获取链配置\n */\nexport function getChain(name: ChainName): ChainConfig {\n const config = CHAINS[name];\n if (!config) {\n throw new Error(`Unsupported chain: ${name}. Supported: ${Object.keys(CHAINS).join(', ')}`);\n }\n return config;\n}\n\n/**\n * 列出所有支持的链\n */\nexport function listChains(): ChainName[] {\n return Object.keys(CHAINS) as ChainName[];\n}\n\n/**\n * 根据 chainId 获取链配置\n */\nexport function getChainById(chainId: number): ChainConfig | undefined {\n return Object.values(CHAINS).find(c => c.chainId === chainId);\n}\n\n/**\n * ERC20 ABI(最小化,仅包含需要的方法)\n */\nexport const ERC20_ABI = [\n 'function balanceOf(address owner) view returns (uint256)',\n 'function transfer(address to, uint256 amount) returns (bool)',\n 'function approve(address spender, uint256 amount) returns (bool)',\n 'function allowance(address owner, address spender) view returns (uint256)',\n 'function decimals() view returns (uint8)',\n 'function symbol() view returns (string)',\n 'function name() view returns (string)',\n 'function nonces(address owner) view returns (uint256)',\n 'function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)',\n 'event Transfer(address indexed from, address indexed to, uint256 value)',\n 'event Approval(address indexed owner, address indexed spender, uint256 value)',\n];\n\nexport type { ChainConfig, ChainName };\n"],"mappings":"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","names":[]}
@@ -58,8 +58,12 @@ declare class SecureWallet {
58
58
  getBalance(): Promise<WalletBalance>;
59
59
  /**
60
60
  * 安全转账(带限额和白名单检查)
61
+ *
62
+ * 支持两种调用方式:
63
+ * - transfer({ to, amount, reason?, requester? })
64
+ * - transfer(to, amount)
61
65
  */
62
- transfer(params: TransferParams): Promise<TransferResult>;
66
+ transfer(paramsOrTo: TransferParams | string, amountArg?: number | string): Promise<TransferResult>;
63
67
  /**
64
68
  * 审批待处理转账
65
69
  */
@@ -58,8 +58,12 @@ declare class SecureWallet {
58
58
  getBalance(): Promise<WalletBalance>;
59
59
  /**
60
60
  * 安全转账(带限额和白名单检查)
61
+ *
62
+ * 支持两种调用方式:
63
+ * - transfer({ to, amount, reason?, requester? })
64
+ * - transfer(to, amount)
61
65
  */
62
- transfer(params: TransferParams): Promise<TransferResult>;
66
+ transfer(paramsOrTo: TransferParams | string, amountArg?: number | string): Promise<TransferResult>;
63
67
  /**
64
68
  * 审批待处理转账
65
69
  */
@@ -388,8 +388,21 @@ var SecureWallet = class {
388
388
  }
389
389
  /**
390
390
  * 安全转账(带限额和白名单检查)
391
+ *
392
+ * 支持两种调用方式:
393
+ * - transfer({ to, amount, reason?, requester? })
394
+ * - transfer(to, amount)
391
395
  */
392
- async transfer(params) {
396
+ async transfer(paramsOrTo, amountArg) {
397
+ let params;
398
+ if (typeof paramsOrTo === "string") {
399
+ params = {
400
+ to: paramsOrTo,
401
+ amount: typeof amountArg === "string" ? parseFloat(amountArg) : amountArg || 0
402
+ };
403
+ } else {
404
+ params = paramsOrTo;
405
+ }
393
406
  const { to, amount, reason, requester } = params;
394
407
  const toAddress = to.toLowerCase();
395
408
  const requestId = `tr_${Date.now().toString(36)}${Math.random().toString(36).slice(2, 8)}`;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/wallet/index.ts","../../src/wallet/Wallet.ts","../../src/chains/index.ts","../../src/audit/AuditLog.ts","../../src/wallet/SecureWallet.ts"],"sourcesContent":["export { Wallet, type WalletConfig } from './Wallet.js';\nexport { SecureWallet } from './SecureWallet.js';\n","/**\n * Wallet - 基础托管钱包\n * \n * 功能:\n * - 查询余额\n * - 发送 USDC 转账\n */\n\nimport { ethers } from 'ethers';\nimport { getChain, ERC20_ABI } from '../chains/index.js';\nimport type {\n ChainName,\n ChainConfig,\n WalletBalance,\n TransferResult,\n} from '../types/index.js';\n\nexport interface WalletConfig {\n chain?: ChainName;\n privateKey?: string;\n rpcUrl?: string;\n}\n\nexport class Wallet {\n readonly chain: ChainName;\n readonly chainConfig: ChainConfig;\n readonly address: string;\n \n private wallet: ethers.Wallet;\n private provider: ethers.JsonRpcProvider;\n private usdcContract: ethers.Contract;\n\n constructor(config: WalletConfig = {}) {\n this.chain = config.chain || 'base_sepolia';\n this.chainConfig = getChain(this.chain);\n \n const privateKey = config.privateKey || process.env.PAYMENT_AGENT_PRIVATE_KEY;\n if (!privateKey) {\n throw new Error('privateKey is required. Set via config or PAYMENT_AGENT_PRIVATE_KEY env var.');\n }\n\n const rpcUrl = config.rpcUrl || this.chainConfig.rpc;\n this.provider = new ethers.JsonRpcProvider(rpcUrl);\n this.wallet = new ethers.Wallet(privateKey, this.provider);\n this.address = this.wallet.address;\n \n this.usdcContract = new ethers.Contract(\n this.chainConfig.usdc,\n ERC20_ABI,\n this.wallet\n );\n }\n\n /**\n * 获取钱包余额\n */\n async getBalance(): Promise<WalletBalance> {\n const [ethBalance, usdcBalance] = await Promise.all([\n this.provider.getBalance(this.address),\n this.usdcContract.balanceOf(this.address),\n ]);\n\n return {\n address: this.address,\n eth: ethers.formatEther(ethBalance),\n usdc: (Number(usdcBalance) / 1e6).toFixed(2),\n chain: this.chain,\n };\n }\n\n /**\n * 发送 USDC 转账\n */\n async transfer(to: string, amount: number): Promise<TransferResult> {\n try {\n // 验证地址\n to = ethers.getAddress(to);\n \n // 转换金额(USDC 6位小数)\n const amountWei = BigInt(Math.floor(amount * 1e6));\n\n // 检查余额\n const balance = await this.usdcContract.balanceOf(this.address);\n if (BigInt(balance) < amountWei) {\n return {\n success: false,\n error: `Insufficient USDC balance: ${Number(balance) / 1e6} < ${amount}`,\n };\n }\n\n // 发送交易\n const tx = await this.usdcContract.transfer(to, amountWei);\n const receipt = await tx.wait();\n\n if (receipt.status === 1) {\n return {\n success: true,\n tx_hash: tx.hash,\n from: this.address,\n to,\n amount,\n gas_used: Number(receipt.gasUsed),\n block_number: receipt.blockNumber,\n explorer_url: `${this.chainConfig.explorerTx}${tx.hash}`,\n };\n } else {\n return {\n success: false,\n tx_hash: tx.hash,\n error: 'Transaction reverted',\n };\n }\n } catch (error) {\n return {\n success: false,\n error: (error as Error).message,\n };\n }\n }\n\n /**\n * 获取 ETH 余额\n */\n async getEthBalance(): Promise<string> {\n const balance = await this.provider.getBalance(this.address);\n return ethers.formatEther(balance);\n }\n\n /**\n * 获取 USDC 余额\n */\n async getUsdcBalance(): Promise<string> {\n const balance = await this.usdcContract.balanceOf(this.address);\n return (Number(balance) / 1e6).toFixed(2);\n }\n}\n","/**\n * 区块链配置\n */\n\nimport type { ChainConfig, ChainName } from '../types/index.js';\n\nexport const CHAINS: Record<ChainName, ChainConfig> = {\n // ============ 主网 ============\n base: {\n name: 'Base',\n chainId: 8453,\n rpc: 'https://mainnet.base.org',\n usdc: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',\n explorer: 'https://basescan.org/address/',\n explorerTx: 'https://basescan.org/tx/',\n avgBlockTime: 2,\n },\n polygon: {\n name: 'Polygon',\n chainId: 137,\n rpc: 'https://polygon-rpc.com',\n usdc: '0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359',\n explorer: 'https://polygonscan.com/address/',\n explorerTx: 'https://polygonscan.com/tx/',\n avgBlockTime: 2,\n },\n ethereum: {\n name: 'Ethereum',\n chainId: 1,\n rpc: 'https://eth.llamarpc.com',\n usdc: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',\n explorer: 'https://etherscan.io/address/',\n explorerTx: 'https://etherscan.io/tx/',\n avgBlockTime: 12,\n },\n\n // ============ 测试网 ============\n base_sepolia: {\n name: 'Base Sepolia',\n chainId: 84532,\n rpc: 'https://sepolia.base.org',\n usdc: '0x036CbD53842c5426634e7929541eC2318f3dCF7e',\n explorer: 'https://sepolia.basescan.org/address/',\n explorerTx: 'https://sepolia.basescan.org/tx/',\n avgBlockTime: 2,\n },\n sepolia: {\n name: 'Sepolia',\n chainId: 11155111,\n rpc: 'https://rpc.sepolia.org',\n usdc: '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238',\n explorer: 'https://sepolia.etherscan.io/address/',\n explorerTx: 'https://sepolia.etherscan.io/tx/',\n avgBlockTime: 12,\n },\n};\n\n/**\n * 获取链配置\n */\nexport function getChain(name: ChainName): ChainConfig {\n const config = CHAINS[name];\n if (!config) {\n throw new Error(`Unsupported chain: ${name}. Supported: ${Object.keys(CHAINS).join(', ')}`);\n }\n return config;\n}\n\n/**\n * 列出所有支持的链\n */\nexport function listChains(): ChainName[] {\n return Object.keys(CHAINS) as ChainName[];\n}\n\n/**\n * 根据 chainId 获取链配置\n */\nexport function getChainById(chainId: number): ChainConfig | undefined {\n return Object.values(CHAINS).find(c => c.chainId === chainId);\n}\n\n/**\n * ERC20 ABI(最小化,仅包含需要的方法)\n */\nexport const ERC20_ABI = [\n 'function balanceOf(address owner) view returns (uint256)',\n 'function transfer(address to, uint256 amount) returns (bool)',\n 'function approve(address spender, uint256 amount) returns (bool)',\n 'function allowance(address owner, address spender) view returns (uint256)',\n 'function decimals() view returns (uint8)',\n 'function symbol() view returns (string)',\n 'function name() view returns (string)',\n 'function nonces(address owner) view returns (uint256)',\n 'function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)',\n 'event Transfer(address indexed from, address indexed to, uint256 value)',\n 'event Approval(address indexed owner, address indexed spender, uint256 value)',\n];\n\nexport type { ChainConfig, ChainName };\n","/**\n * AuditLog - 不可篡改审计日志\n * \n * 特点:\n * - 链式哈希,任何修改都会破坏链条\n * - 按日期分文件存储\n * - JSONL 格式便于追加和解析\n */\n\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport * as crypto from 'crypto';\nimport type { AuditEntry, AuditAction } from '../types/index.js';\n\nexport interface LogParams {\n action: AuditAction;\n request_id: string;\n from?: string;\n to?: string;\n amount?: number;\n tx_hash?: string;\n reason?: string;\n requester?: string;\n metadata?: Record<string, unknown>;\n}\n\nexport class AuditLog {\n private basePath: string;\n private lastHash: string = '0000000000000000';\n\n constructor(basePath?: string) {\n this.basePath = basePath || path.join(process.cwd(), 'data', 'audit');\n this.ensureDir();\n this.loadLastHash();\n }\n\n /**\n * 记录审计日志\n */\n async log(params: LogParams): Promise<AuditEntry> {\n const now = new Date();\n \n const entry: AuditEntry = {\n timestamp: now.getTime() / 1000,\n datetime: now.toISOString(),\n action: params.action,\n request_id: params.request_id,\n from: params.from,\n to: params.to,\n amount: params.amount,\n tx_hash: params.tx_hash,\n reason: params.reason,\n requester: params.requester,\n prev_hash: this.lastHash,\n hash: '', // 计算后填充\n metadata: params.metadata,\n };\n\n // 计算哈希(不包含 hash 字段本身)\n entry.hash = this.calculateHash(entry);\n this.lastHash = entry.hash;\n\n // 写入文件\n const filePath = this.getFilePath(now);\n const line = JSON.stringify(entry) + '\\n';\n fs.appendFileSync(filePath, line, 'utf-8');\n\n return entry;\n }\n\n /**\n * 读取指定日期的日志\n */\n read(date?: Date): AuditEntry[] {\n const filePath = this.getFilePath(date || new Date());\n \n if (!fs.existsSync(filePath)) {\n return [];\n }\n\n const content = fs.readFileSync(filePath, 'utf-8');\n const lines = content.trim().split('\\n').filter(Boolean);\n \n return lines.map(line => JSON.parse(line) as AuditEntry);\n }\n\n /**\n * 验证日志完整性\n */\n verify(date?: Date): { valid: boolean; errors: string[] } {\n const entries = this.read(date);\n const errors: string[] = [];\n\n for (let i = 0; i < entries.length; i++) {\n const entry = entries[i];\n \n // 验证哈希\n const expectedHash = this.calculateHash(entry);\n if (entry.hash !== expectedHash) {\n errors.push(`Entry ${i}: hash mismatch (expected ${expectedHash}, got ${entry.hash})`);\n }\n\n // 验证链接\n if (i > 0 && entry.prev_hash !== entries[i - 1].hash) {\n errors.push(`Entry ${i}: prev_hash mismatch`);\n }\n }\n\n return { valid: errors.length === 0, errors };\n }\n\n /**\n * 搜索日志\n */\n search(filter: Partial<{\n action: AuditAction;\n request_id: string;\n from: string;\n to: string;\n startDate: Date;\n endDate: Date;\n }>): AuditEntry[] {\n const results: AuditEntry[] = [];\n const startDate = filter.startDate || new Date(Date.now() - 30 * 24 * 60 * 60 * 1000);\n const endDate = filter.endDate || new Date();\n\n // 遍历日期范围\n const current = new Date(startDate);\n while (current <= endDate) {\n const entries = this.read(current);\n \n for (const entry of entries) {\n let match = true;\n\n if (filter.action && entry.action !== filter.action) match = false;\n if (filter.request_id && entry.request_id !== filter.request_id) match = false;\n if (filter.from && entry.from?.toLowerCase() !== filter.from.toLowerCase()) match = false;\n if (filter.to && entry.to?.toLowerCase() !== filter.to.toLowerCase()) match = false;\n\n if (match) {\n results.push(entry);\n }\n }\n\n current.setDate(current.getDate() + 1);\n }\n\n return results;\n }\n\n /**\n * 获取日志文件路径\n */\n private getFilePath(date: Date): string {\n const dateStr = date.toISOString().slice(0, 10);\n return path.join(this.basePath, `audit_${dateStr}.jsonl`);\n }\n\n /**\n * 计算条目哈希\n */\n private calculateHash(entry: AuditEntry): string {\n const data = {\n timestamp: entry.timestamp,\n action: entry.action,\n request_id: entry.request_id,\n from: entry.from,\n to: entry.to,\n amount: entry.amount,\n tx_hash: entry.tx_hash,\n prev_hash: entry.prev_hash,\n };\n \n const str = JSON.stringify(data);\n return crypto.createHash('sha256').update(str).digest('hex').slice(0, 16);\n }\n\n /**\n * 加载最后一条日志的哈希\n */\n private loadLastHash(): void {\n const today = new Date();\n \n // 检查今天和昨天的日志\n for (let i = 0; i < 2; i++) {\n const date = new Date(today);\n date.setDate(date.getDate() - i);\n \n const entries = this.read(date);\n if (entries.length > 0) {\n this.lastHash = entries[entries.length - 1].hash;\n return;\n }\n }\n }\n\n /**\n * 确保目录存在\n */\n private ensureDir(): void {\n if (!fs.existsSync(this.basePath)) {\n fs.mkdirSync(this.basePath, { recursive: true });\n }\n }\n}\n","/**\n * SecureWallet - 安全托管钱包\n * \n * 在基础 Wallet 之上增加:\n * - 单笔限额控制\n * - 日限额控制\n * - 白名单机制\n * - 审计日志\n * - 超限审批队列\n */\n\nimport { Wallet, type WalletConfig } from './Wallet.js';\nimport { AuditLog } from '../audit/AuditLog.js';\nimport type {\n SecurityLimits,\n SecureWalletConfig,\n TransferResult,\n TransferParams,\n PendingTransfer,\n} from '../types/index.js';\n\nconst DEFAULT_LIMITS: SecurityLimits = {\n singleMax: 100, // 单笔最大 $100\n dailyMax: 1000, // 日最大 $1000\n requireWhitelist: true,\n};\n\nexport class SecureWallet {\n private wallet: Wallet;\n private limits: SecurityLimits;\n private whitelist: Set<string>;\n private auditLog: AuditLog;\n private dailyTotal: number = 0;\n private dailyDate: string = '';\n private pendingTransfers: Map<string, PendingTransfer> = new Map();\n\n constructor(config: SecureWalletConfig = {}) {\n this.wallet = new Wallet({\n chain: config.chain,\n privateKey: config.privateKey,\n });\n\n this.limits = { ...DEFAULT_LIMITS, ...config.limits };\n this.whitelist = new Set((config.whitelist || []).map(a => a.toLowerCase()));\n this.auditLog = new AuditLog(config.auditPath);\n }\n\n /**\n * 获取钱包地址\n */\n get address(): string {\n return this.wallet.address;\n }\n\n /**\n * 获取余额\n */\n async getBalance() {\n return this.wallet.getBalance();\n }\n\n /**\n * 安全转账(带限额和白名单检查)\n */\n async transfer(params: TransferParams): Promise<TransferResult> {\n const { to, amount, reason, requester } = params;\n const toAddress = to.toLowerCase();\n const requestId = `tr_${Date.now().toString(36)}${Math.random().toString(36).slice(2, 8)}`;\n\n // 记录请求\n await this.auditLog.log({\n action: 'transfer_request',\n request_id: requestId,\n from: this.wallet.address,\n to,\n amount,\n reason,\n requester,\n });\n\n // 1. 白名单检查\n if (this.limits.requireWhitelist && !this.whitelist.has(toAddress)) {\n await this.auditLog.log({\n action: 'transfer_failed',\n request_id: requestId,\n metadata: { error: 'Address not in whitelist' },\n });\n return { success: false, error: `Address not in whitelist: ${to}` };\n }\n\n // 2. 单笔限额检查\n if (amount > this.limits.singleMax) {\n // 加入审批队列\n const pending: PendingTransfer = {\n id: requestId,\n to,\n amount,\n reason,\n requester,\n created_at: new Date().toISOString(),\n status: 'pending',\n };\n this.pendingTransfers.set(requestId, pending);\n \n await this.auditLog.log({\n action: 'transfer_request',\n request_id: requestId,\n metadata: { pending: true, reason: 'Exceeds single limit' },\n });\n \n return {\n success: false,\n error: `Amount ${amount} exceeds single limit ${this.limits.singleMax}. Pending approval: ${requestId}`,\n };\n }\n\n // 3. 日限额检查\n this.updateDailyTotal();\n if (this.dailyTotal + amount > this.limits.dailyMax) {\n const pending: PendingTransfer = {\n id: requestId,\n to,\n amount,\n reason,\n requester,\n created_at: new Date().toISOString(),\n status: 'pending',\n };\n this.pendingTransfers.set(requestId, pending);\n \n await this.auditLog.log({\n action: 'transfer_request',\n request_id: requestId,\n metadata: { pending: true, reason: 'Exceeds daily limit' },\n });\n \n return {\n success: false,\n error: `Daily limit would be exceeded (${this.dailyTotal} + ${amount} > ${this.limits.dailyMax}). Pending approval: ${requestId}`,\n };\n }\n\n // 4. 执行转账\n const result = await this.wallet.transfer(to, amount);\n\n // 5. 记录结果\n if (result.success) {\n this.dailyTotal += amount;\n await this.auditLog.log({\n action: 'transfer_executed',\n request_id: requestId,\n from: this.wallet.address,\n to,\n amount,\n tx_hash: result.tx_hash,\n reason,\n requester,\n });\n } else {\n await this.auditLog.log({\n action: 'transfer_failed',\n request_id: requestId,\n metadata: { error: result.error },\n });\n }\n\n return result;\n }\n\n /**\n * 审批待处理转账\n */\n async approve(requestId: string, approver: string): Promise<TransferResult> {\n const pending = this.pendingTransfers.get(requestId);\n if (!pending) {\n return { success: false, error: `Pending transfer not found: ${requestId}` };\n }\n\n if (pending.status !== 'pending') {\n return { success: false, error: `Transfer already ${pending.status}` };\n }\n\n await this.auditLog.log({\n action: 'transfer_approved',\n request_id: requestId,\n metadata: { approver },\n });\n\n pending.status = 'approved';\n\n // 执行转账(跳过限额检查)\n const result = await this.wallet.transfer(pending.to, pending.amount);\n\n if (result.success) {\n pending.status = 'executed';\n this.dailyTotal += pending.amount;\n \n await this.auditLog.log({\n action: 'transfer_executed',\n request_id: requestId,\n from: this.wallet.address,\n to: pending.to,\n amount: pending.amount,\n tx_hash: result.tx_hash,\n reason: pending.reason,\n requester: pending.requester,\n metadata: { approved_by: approver },\n });\n } else {\n await this.auditLog.log({\n action: 'transfer_failed',\n request_id: requestId,\n metadata: { error: result.error },\n });\n }\n\n return result;\n }\n\n /**\n * 拒绝待处理转账\n */\n async reject(requestId: string, rejecter: string, reason?: string): Promise<void> {\n const pending = this.pendingTransfers.get(requestId);\n if (!pending) {\n throw new Error(`Pending transfer not found: ${requestId}`);\n }\n\n pending.status = 'rejected';\n\n await this.auditLog.log({\n action: 'transfer_rejected',\n request_id: requestId,\n metadata: { rejected_by: rejecter, reason },\n });\n }\n\n /**\n * 添加白名单地址\n */\n async addToWhitelist(address: string, addedBy: string): Promise<void> {\n const addr = address.toLowerCase();\n this.whitelist.add(addr);\n\n await this.auditLog.log({\n action: 'whitelist_add',\n request_id: `wl_${Date.now()}`,\n to: address,\n metadata: { added_by: addedBy },\n });\n }\n\n /**\n * 移除白名单地址\n */\n async removeFromWhitelist(address: string, removedBy: string): Promise<void> {\n const addr = address.toLowerCase();\n this.whitelist.delete(addr);\n\n await this.auditLog.log({\n action: 'whitelist_remove',\n request_id: `wl_${Date.now()}`,\n to: address,\n metadata: { removed_by: removedBy },\n });\n }\n\n /**\n * 检查地址是否在白名单\n */\n isWhitelisted(address: string): boolean {\n return this.whitelist.has(address.toLowerCase());\n }\n\n /**\n * 获取待处理转账列表\n */\n getPendingTransfers(): PendingTransfer[] {\n return Array.from(this.pendingTransfers.values())\n .filter(p => p.status === 'pending');\n }\n\n /**\n * 获取当前限额配置\n */\n getLimits(): SecurityLimits {\n return { ...this.limits };\n }\n\n /**\n * 获取今日已用额度\n */\n getDailyUsed(): number {\n this.updateDailyTotal();\n return this.dailyTotal;\n }\n\n /**\n * 更新日限额计数器\n */\n private updateDailyTotal(): void {\n const today = new Date().toISOString().slice(0, 10);\n if (this.dailyDate !== today) {\n this.dailyDate = today;\n this.dailyTotal = 0;\n }\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/wallet/index.ts","../../src/wallet/Wallet.ts","../../src/chains/index.ts","../../src/audit/AuditLog.ts","../../src/wallet/SecureWallet.ts"],"sourcesContent":["export { Wallet, type WalletConfig } from './Wallet.js';\nexport { SecureWallet } from './SecureWallet.js';\n","/**\n * Wallet - 基础托管钱包\n * \n * 功能:\n * - 查询余额\n * - 发送 USDC 转账\n */\n\nimport { ethers } from 'ethers';\nimport { getChain, ERC20_ABI } from '../chains/index.js';\nimport type {\n ChainName,\n ChainConfig,\n WalletBalance,\n TransferResult,\n} from '../types/index.js';\n\nexport interface WalletConfig {\n chain?: ChainName;\n privateKey?: string;\n rpcUrl?: string;\n}\n\nexport class Wallet {\n readonly chain: ChainName;\n readonly chainConfig: ChainConfig;\n readonly address: string;\n \n private wallet: ethers.Wallet;\n private provider: ethers.JsonRpcProvider;\n private usdcContract: ethers.Contract;\n\n constructor(config: WalletConfig = {}) {\n this.chain = config.chain || 'base_sepolia';\n this.chainConfig = getChain(this.chain);\n \n const privateKey = config.privateKey || process.env.PAYMENT_AGENT_PRIVATE_KEY;\n if (!privateKey) {\n throw new Error('privateKey is required. Set via config or PAYMENT_AGENT_PRIVATE_KEY env var.');\n }\n\n const rpcUrl = config.rpcUrl || this.chainConfig.rpc;\n this.provider = new ethers.JsonRpcProvider(rpcUrl);\n this.wallet = new ethers.Wallet(privateKey, this.provider);\n this.address = this.wallet.address;\n \n this.usdcContract = new ethers.Contract(\n this.chainConfig.usdc,\n ERC20_ABI,\n this.wallet\n );\n }\n\n /**\n * 获取钱包余额\n */\n async getBalance(): Promise<WalletBalance> {\n const [ethBalance, usdcBalance] = await Promise.all([\n this.provider.getBalance(this.address),\n this.usdcContract.balanceOf(this.address),\n ]);\n\n return {\n address: this.address,\n eth: ethers.formatEther(ethBalance),\n usdc: (Number(usdcBalance) / 1e6).toFixed(2),\n chain: this.chain,\n };\n }\n\n /**\n * 发送 USDC 转账\n */\n async transfer(to: string, amount: number): Promise<TransferResult> {\n try {\n // 验证地址\n to = ethers.getAddress(to);\n \n // 转换金额(USDC 6位小数)\n const amountWei = BigInt(Math.floor(amount * 1e6));\n\n // 检查余额\n const balance = await this.usdcContract.balanceOf(this.address);\n if (BigInt(balance) < amountWei) {\n return {\n success: false,\n error: `Insufficient USDC balance: ${Number(balance) / 1e6} < ${amount}`,\n };\n }\n\n // 发送交易\n const tx = await this.usdcContract.transfer(to, amountWei);\n const receipt = await tx.wait();\n\n if (receipt.status === 1) {\n return {\n success: true,\n tx_hash: tx.hash,\n from: this.address,\n to,\n amount,\n gas_used: Number(receipt.gasUsed),\n block_number: receipt.blockNumber,\n explorer_url: `${this.chainConfig.explorerTx}${tx.hash}`,\n };\n } else {\n return {\n success: false,\n tx_hash: tx.hash,\n error: 'Transaction reverted',\n };\n }\n } catch (error) {\n return {\n success: false,\n error: (error as Error).message,\n };\n }\n }\n\n /**\n * 获取 ETH 余额\n */\n async getEthBalance(): Promise<string> {\n const balance = await this.provider.getBalance(this.address);\n return ethers.formatEther(balance);\n }\n\n /**\n * 获取 USDC 余额\n */\n async getUsdcBalance(): Promise<string> {\n const balance = await this.usdcContract.balanceOf(this.address);\n return (Number(balance) / 1e6).toFixed(2);\n }\n}\n","/**\n * 区块链配置\n */\n\nimport type { ChainConfig, ChainName } from '../types/index.js';\n\nexport const CHAINS: Record<ChainName, ChainConfig> = {\n // ============ 主网 ============\n base: {\n name: 'Base',\n chainId: 8453,\n rpc: 'https://mainnet.base.org',\n usdc: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',\n explorer: 'https://basescan.org/address/',\n explorerTx: 'https://basescan.org/tx/',\n avgBlockTime: 2,\n },\n polygon: {\n name: 'Polygon',\n chainId: 137,\n rpc: 'https://polygon-rpc.com',\n usdc: '0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359',\n explorer: 'https://polygonscan.com/address/',\n explorerTx: 'https://polygonscan.com/tx/',\n avgBlockTime: 2,\n },\n ethereum: {\n name: 'Ethereum',\n chainId: 1,\n rpc: 'https://eth.llamarpc.com',\n usdc: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',\n explorer: 'https://etherscan.io/address/',\n explorerTx: 'https://etherscan.io/tx/',\n avgBlockTime: 12,\n },\n\n // ============ 测试网 ============\n base_sepolia: {\n name: 'Base Sepolia',\n chainId: 84532,\n rpc: 'https://sepolia.base.org',\n usdc: '0x036CbD53842c5426634e7929541eC2318f3dCF7e',\n explorer: 'https://sepolia.basescan.org/address/',\n explorerTx: 'https://sepolia.basescan.org/tx/',\n avgBlockTime: 2,\n },\n sepolia: {\n name: 'Sepolia',\n chainId: 11155111,\n rpc: 'https://rpc.sepolia.org',\n usdc: '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238',\n explorer: 'https://sepolia.etherscan.io/address/',\n explorerTx: 'https://sepolia.etherscan.io/tx/',\n avgBlockTime: 12,\n },\n};\n\n/**\n * 获取链配置\n */\nexport function getChain(name: ChainName): ChainConfig {\n const config = CHAINS[name];\n if (!config) {\n throw new Error(`Unsupported chain: ${name}. Supported: ${Object.keys(CHAINS).join(', ')}`);\n }\n return config;\n}\n\n/**\n * 列出所有支持的链\n */\nexport function listChains(): ChainName[] {\n return Object.keys(CHAINS) as ChainName[];\n}\n\n/**\n * 根据 chainId 获取链配置\n */\nexport function getChainById(chainId: number): ChainConfig | undefined {\n return Object.values(CHAINS).find(c => c.chainId === chainId);\n}\n\n/**\n * ERC20 ABI(最小化,仅包含需要的方法)\n */\nexport const ERC20_ABI = [\n 'function balanceOf(address owner) view returns (uint256)',\n 'function transfer(address to, uint256 amount) returns (bool)',\n 'function approve(address spender, uint256 amount) returns (bool)',\n 'function allowance(address owner, address spender) view returns (uint256)',\n 'function decimals() view returns (uint8)',\n 'function symbol() view returns (string)',\n 'function name() view returns (string)',\n 'function nonces(address owner) view returns (uint256)',\n 'function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)',\n 'event Transfer(address indexed from, address indexed to, uint256 value)',\n 'event Approval(address indexed owner, address indexed spender, uint256 value)',\n];\n\nexport type { ChainConfig, ChainName };\n","/**\n * AuditLog - 不可篡改审计日志\n * \n * 特点:\n * - 链式哈希,任何修改都会破坏链条\n * - 按日期分文件存储\n * - JSONL 格式便于追加和解析\n */\n\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport * as crypto from 'crypto';\nimport type { AuditEntry, AuditAction } from '../types/index.js';\n\nexport interface LogParams {\n action: AuditAction;\n request_id: string;\n from?: string;\n to?: string;\n amount?: number;\n tx_hash?: string;\n reason?: string;\n requester?: string;\n metadata?: Record<string, unknown>;\n}\n\nexport class AuditLog {\n private basePath: string;\n private lastHash: string = '0000000000000000';\n\n constructor(basePath?: string) {\n this.basePath = basePath || path.join(process.cwd(), 'data', 'audit');\n this.ensureDir();\n this.loadLastHash();\n }\n\n /**\n * 记录审计日志\n */\n async log(params: LogParams): Promise<AuditEntry> {\n const now = new Date();\n \n const entry: AuditEntry = {\n timestamp: now.getTime() / 1000,\n datetime: now.toISOString(),\n action: params.action,\n request_id: params.request_id,\n from: params.from,\n to: params.to,\n amount: params.amount,\n tx_hash: params.tx_hash,\n reason: params.reason,\n requester: params.requester,\n prev_hash: this.lastHash,\n hash: '', // 计算后填充\n metadata: params.metadata,\n };\n\n // 计算哈希(不包含 hash 字段本身)\n entry.hash = this.calculateHash(entry);\n this.lastHash = entry.hash;\n\n // 写入文件\n const filePath = this.getFilePath(now);\n const line = JSON.stringify(entry) + '\\n';\n fs.appendFileSync(filePath, line, 'utf-8');\n\n return entry;\n }\n\n /**\n * 读取指定日期的日志\n */\n read(date?: Date): AuditEntry[] {\n const filePath = this.getFilePath(date || new Date());\n \n if (!fs.existsSync(filePath)) {\n return [];\n }\n\n const content = fs.readFileSync(filePath, 'utf-8');\n const lines = content.trim().split('\\n').filter(Boolean);\n \n return lines.map(line => JSON.parse(line) as AuditEntry);\n }\n\n /**\n * 验证日志完整性\n */\n verify(date?: Date): { valid: boolean; errors: string[] } {\n const entries = this.read(date);\n const errors: string[] = [];\n\n for (let i = 0; i < entries.length; i++) {\n const entry = entries[i];\n \n // 验证哈希\n const expectedHash = this.calculateHash(entry);\n if (entry.hash !== expectedHash) {\n errors.push(`Entry ${i}: hash mismatch (expected ${expectedHash}, got ${entry.hash})`);\n }\n\n // 验证链接\n if (i > 0 && entry.prev_hash !== entries[i - 1].hash) {\n errors.push(`Entry ${i}: prev_hash mismatch`);\n }\n }\n\n return { valid: errors.length === 0, errors };\n }\n\n /**\n * 搜索日志\n */\n search(filter: Partial<{\n action: AuditAction;\n request_id: string;\n from: string;\n to: string;\n startDate: Date;\n endDate: Date;\n }>): AuditEntry[] {\n const results: AuditEntry[] = [];\n const startDate = filter.startDate || new Date(Date.now() - 30 * 24 * 60 * 60 * 1000);\n const endDate = filter.endDate || new Date();\n\n // 遍历日期范围\n const current = new Date(startDate);\n while (current <= endDate) {\n const entries = this.read(current);\n \n for (const entry of entries) {\n let match = true;\n\n if (filter.action && entry.action !== filter.action) match = false;\n if (filter.request_id && entry.request_id !== filter.request_id) match = false;\n if (filter.from && entry.from?.toLowerCase() !== filter.from.toLowerCase()) match = false;\n if (filter.to && entry.to?.toLowerCase() !== filter.to.toLowerCase()) match = false;\n\n if (match) {\n results.push(entry);\n }\n }\n\n current.setDate(current.getDate() + 1);\n }\n\n return results;\n }\n\n /**\n * 获取日志文件路径\n */\n private getFilePath(date: Date): string {\n const dateStr = date.toISOString().slice(0, 10);\n return path.join(this.basePath, `audit_${dateStr}.jsonl`);\n }\n\n /**\n * 计算条目哈希\n */\n private calculateHash(entry: AuditEntry): string {\n const data = {\n timestamp: entry.timestamp,\n action: entry.action,\n request_id: entry.request_id,\n from: entry.from,\n to: entry.to,\n amount: entry.amount,\n tx_hash: entry.tx_hash,\n prev_hash: entry.prev_hash,\n };\n \n const str = JSON.stringify(data);\n return crypto.createHash('sha256').update(str).digest('hex').slice(0, 16);\n }\n\n /**\n * 加载最后一条日志的哈希\n */\n private loadLastHash(): void {\n const today = new Date();\n \n // 检查今天和昨天的日志\n for (let i = 0; i < 2; i++) {\n const date = new Date(today);\n date.setDate(date.getDate() - i);\n \n const entries = this.read(date);\n if (entries.length > 0) {\n this.lastHash = entries[entries.length - 1].hash;\n return;\n }\n }\n }\n\n /**\n * 确保目录存在\n */\n private ensureDir(): void {\n if (!fs.existsSync(this.basePath)) {\n fs.mkdirSync(this.basePath, { recursive: true });\n }\n }\n}\n","/**\n * SecureWallet - 安全托管钱包\n * \n * 在基础 Wallet 之上增加:\n * - 单笔限额控制\n * - 日限额控制\n * - 白名单机制\n * - 审计日志\n * - 超限审批队列\n */\n\nimport { Wallet, type WalletConfig } from './Wallet.js';\nimport { AuditLog } from '../audit/AuditLog.js';\nimport type {\n SecurityLimits,\n SecureWalletConfig,\n TransferResult,\n TransferParams,\n PendingTransfer,\n} from '../types/index.js';\n\nconst DEFAULT_LIMITS: SecurityLimits = {\n singleMax: 100, // 单笔最大 $100\n dailyMax: 1000, // 日最大 $1000\n requireWhitelist: true,\n};\n\nexport class SecureWallet {\n private wallet: Wallet;\n private limits: SecurityLimits;\n private whitelist: Set<string>;\n private auditLog: AuditLog;\n private dailyTotal: number = 0;\n private dailyDate: string = '';\n private pendingTransfers: Map<string, PendingTransfer> = new Map();\n\n constructor(config: SecureWalletConfig = {}) {\n this.wallet = new Wallet({\n chain: config.chain,\n privateKey: config.privateKey,\n });\n\n this.limits = { ...DEFAULT_LIMITS, ...config.limits };\n this.whitelist = new Set((config.whitelist || []).map(a => a.toLowerCase()));\n this.auditLog = new AuditLog(config.auditPath);\n }\n\n /**\n * 获取钱包地址\n */\n get address(): string {\n return this.wallet.address;\n }\n\n /**\n * 获取余额\n */\n async getBalance() {\n return this.wallet.getBalance();\n }\n\n /**\n * 安全转账(带限额和白名单检查)\n * \n * 支持两种调用方式:\n * - transfer({ to, amount, reason?, requester? })\n * - transfer(to, amount)\n */\n async transfer(paramsOrTo: TransferParams | string, amountArg?: number | string): Promise<TransferResult> {\n // 支持两种调用方式\n let params: TransferParams;\n if (typeof paramsOrTo === 'string') {\n params = { \n to: paramsOrTo, \n amount: typeof amountArg === 'string' ? parseFloat(amountArg) : (amountArg || 0)\n };\n } else {\n params = paramsOrTo;\n }\n \n const { to, amount, reason, requester } = params;\n const toAddress = to.toLowerCase();\n const requestId = `tr_${Date.now().toString(36)}${Math.random().toString(36).slice(2, 8)}`;\n\n // 记录请求\n await this.auditLog.log({\n action: 'transfer_request',\n request_id: requestId,\n from: this.wallet.address,\n to,\n amount,\n reason,\n requester,\n });\n\n // 1. 白名单检查\n if (this.limits.requireWhitelist && !this.whitelist.has(toAddress)) {\n await this.auditLog.log({\n action: 'transfer_failed',\n request_id: requestId,\n metadata: { error: 'Address not in whitelist' },\n });\n return { success: false, error: `Address not in whitelist: ${to}` };\n }\n\n // 2. 单笔限额检查\n if (amount > this.limits.singleMax) {\n // 加入审批队列\n const pending: PendingTransfer = {\n id: requestId,\n to,\n amount,\n reason,\n requester,\n created_at: new Date().toISOString(),\n status: 'pending',\n };\n this.pendingTransfers.set(requestId, pending);\n \n await this.auditLog.log({\n action: 'transfer_request',\n request_id: requestId,\n metadata: { pending: true, reason: 'Exceeds single limit' },\n });\n \n return {\n success: false,\n error: `Amount ${amount} exceeds single limit ${this.limits.singleMax}. Pending approval: ${requestId}`,\n };\n }\n\n // 3. 日限额检查\n this.updateDailyTotal();\n if (this.dailyTotal + amount > this.limits.dailyMax) {\n const pending: PendingTransfer = {\n id: requestId,\n to,\n amount,\n reason,\n requester,\n created_at: new Date().toISOString(),\n status: 'pending',\n };\n this.pendingTransfers.set(requestId, pending);\n \n await this.auditLog.log({\n action: 'transfer_request',\n request_id: requestId,\n metadata: { pending: true, reason: 'Exceeds daily limit' },\n });\n \n return {\n success: false,\n error: `Daily limit would be exceeded (${this.dailyTotal} + ${amount} > ${this.limits.dailyMax}). Pending approval: ${requestId}`,\n };\n }\n\n // 4. 执行转账\n const result = await this.wallet.transfer(to, amount);\n\n // 5. 记录结果\n if (result.success) {\n this.dailyTotal += amount;\n await this.auditLog.log({\n action: 'transfer_executed',\n request_id: requestId,\n from: this.wallet.address,\n to,\n amount,\n tx_hash: result.tx_hash,\n reason,\n requester,\n });\n } else {\n await this.auditLog.log({\n action: 'transfer_failed',\n request_id: requestId,\n metadata: { error: result.error },\n });\n }\n\n return result;\n }\n\n /**\n * 审批待处理转账\n */\n async approve(requestId: string, approver: string): Promise<TransferResult> {\n const pending = this.pendingTransfers.get(requestId);\n if (!pending) {\n return { success: false, error: `Pending transfer not found: ${requestId}` };\n }\n\n if (pending.status !== 'pending') {\n return { success: false, error: `Transfer already ${pending.status}` };\n }\n\n await this.auditLog.log({\n action: 'transfer_approved',\n request_id: requestId,\n metadata: { approver },\n });\n\n pending.status = 'approved';\n\n // 执行转账(跳过限额检查)\n const result = await this.wallet.transfer(pending.to, pending.amount);\n\n if (result.success) {\n pending.status = 'executed';\n this.dailyTotal += pending.amount;\n \n await this.auditLog.log({\n action: 'transfer_executed',\n request_id: requestId,\n from: this.wallet.address,\n to: pending.to,\n amount: pending.amount,\n tx_hash: result.tx_hash,\n reason: pending.reason,\n requester: pending.requester,\n metadata: { approved_by: approver },\n });\n } else {\n await this.auditLog.log({\n action: 'transfer_failed',\n request_id: requestId,\n metadata: { error: result.error },\n });\n }\n\n return result;\n }\n\n /**\n * 拒绝待处理转账\n */\n async reject(requestId: string, rejecter: string, reason?: string): Promise<void> {\n const pending = this.pendingTransfers.get(requestId);\n if (!pending) {\n throw new Error(`Pending transfer not found: ${requestId}`);\n }\n\n pending.status = 'rejected';\n\n await this.auditLog.log({\n action: 'transfer_rejected',\n request_id: requestId,\n metadata: { rejected_by: rejecter, reason },\n });\n }\n\n /**\n * 添加白名单地址\n */\n async addToWhitelist(address: string, addedBy: string): Promise<void> {\n const addr = address.toLowerCase();\n this.whitelist.add(addr);\n\n await this.auditLog.log({\n action: 'whitelist_add',\n request_id: `wl_${Date.now()}`,\n to: address,\n metadata: { added_by: addedBy },\n });\n }\n\n /**\n * 移除白名单地址\n */\n async removeFromWhitelist(address: string, removedBy: string): Promise<void> {\n const addr = address.toLowerCase();\n this.whitelist.delete(addr);\n\n await this.auditLog.log({\n action: 'whitelist_remove',\n request_id: `wl_${Date.now()}`,\n to: address,\n metadata: { removed_by: removedBy },\n });\n }\n\n /**\n * 检查地址是否在白名单\n */\n isWhitelisted(address: string): boolean {\n return this.whitelist.has(address.toLowerCase());\n }\n\n /**\n * 获取待处理转账列表\n */\n getPendingTransfers(): PendingTransfer[] {\n return Array.from(this.pendingTransfers.values())\n .filter(p => p.status === 'pending');\n }\n\n /**\n * 获取当前限额配置\n */\n getLimits(): SecurityLimits {\n return { ...this.limits };\n }\n\n /**\n * 获取今日已用额度\n */\n getDailyUsed(): number {\n this.updateDailyTotal();\n return this.dailyTotal;\n }\n\n /**\n * 更新日限额计数器\n */\n private updateDailyTotal(): void {\n const today = new Date().toISOString().slice(0, 10);\n if (this.dailyDate !== today) {\n this.dailyDate = today;\n this.dailyTotal = 0;\n }\n }\n}\n"],"mappings":"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","names":[]}
@@ -351,8 +351,21 @@ var SecureWallet = class {
351
351
  }
352
352
  /**
353
353
  * 安全转账(带限额和白名单检查)
354
+ *
355
+ * 支持两种调用方式:
356
+ * - transfer({ to, amount, reason?, requester? })
357
+ * - transfer(to, amount)
354
358
  */
355
- async transfer(params) {
359
+ async transfer(paramsOrTo, amountArg) {
360
+ let params;
361
+ if (typeof paramsOrTo === "string") {
362
+ params = {
363
+ to: paramsOrTo,
364
+ amount: typeof amountArg === "string" ? parseFloat(amountArg) : amountArg || 0
365
+ };
366
+ } else {
367
+ params = paramsOrTo;
368
+ }
356
369
  const { to, amount, reason, requester } = params;
357
370
  const toAddress = to.toLowerCase();
358
371
  const requestId = `tr_${Date.now().toString(36)}${Math.random().toString(36).slice(2, 8)}`;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/wallet/Wallet.ts","../../src/chains/index.ts","../../src/audit/AuditLog.ts","../../src/wallet/SecureWallet.ts"],"sourcesContent":["/**\n * Wallet - 基础托管钱包\n * \n * 功能:\n * - 查询余额\n * - 发送 USDC 转账\n */\n\nimport { ethers } from 'ethers';\nimport { getChain, ERC20_ABI } from '../chains/index.js';\nimport type {\n ChainName,\n ChainConfig,\n WalletBalance,\n TransferResult,\n} from '../types/index.js';\n\nexport interface WalletConfig {\n chain?: ChainName;\n privateKey?: string;\n rpcUrl?: string;\n}\n\nexport class Wallet {\n readonly chain: ChainName;\n readonly chainConfig: ChainConfig;\n readonly address: string;\n \n private wallet: ethers.Wallet;\n private provider: ethers.JsonRpcProvider;\n private usdcContract: ethers.Contract;\n\n constructor(config: WalletConfig = {}) {\n this.chain = config.chain || 'base_sepolia';\n this.chainConfig = getChain(this.chain);\n \n const privateKey = config.privateKey || process.env.PAYMENT_AGENT_PRIVATE_KEY;\n if (!privateKey) {\n throw new Error('privateKey is required. Set via config or PAYMENT_AGENT_PRIVATE_KEY env var.');\n }\n\n const rpcUrl = config.rpcUrl || this.chainConfig.rpc;\n this.provider = new ethers.JsonRpcProvider(rpcUrl);\n this.wallet = new ethers.Wallet(privateKey, this.provider);\n this.address = this.wallet.address;\n \n this.usdcContract = new ethers.Contract(\n this.chainConfig.usdc,\n ERC20_ABI,\n this.wallet\n );\n }\n\n /**\n * 获取钱包余额\n */\n async getBalance(): Promise<WalletBalance> {\n const [ethBalance, usdcBalance] = await Promise.all([\n this.provider.getBalance(this.address),\n this.usdcContract.balanceOf(this.address),\n ]);\n\n return {\n address: this.address,\n eth: ethers.formatEther(ethBalance),\n usdc: (Number(usdcBalance) / 1e6).toFixed(2),\n chain: this.chain,\n };\n }\n\n /**\n * 发送 USDC 转账\n */\n async transfer(to: string, amount: number): Promise<TransferResult> {\n try {\n // 验证地址\n to = ethers.getAddress(to);\n \n // 转换金额(USDC 6位小数)\n const amountWei = BigInt(Math.floor(amount * 1e6));\n\n // 检查余额\n const balance = await this.usdcContract.balanceOf(this.address);\n if (BigInt(balance) < amountWei) {\n return {\n success: false,\n error: `Insufficient USDC balance: ${Number(balance) / 1e6} < ${amount}`,\n };\n }\n\n // 发送交易\n const tx = await this.usdcContract.transfer(to, amountWei);\n const receipt = await tx.wait();\n\n if (receipt.status === 1) {\n return {\n success: true,\n tx_hash: tx.hash,\n from: this.address,\n to,\n amount,\n gas_used: Number(receipt.gasUsed),\n block_number: receipt.blockNumber,\n explorer_url: `${this.chainConfig.explorerTx}${tx.hash}`,\n };\n } else {\n return {\n success: false,\n tx_hash: tx.hash,\n error: 'Transaction reverted',\n };\n }\n } catch (error) {\n return {\n success: false,\n error: (error as Error).message,\n };\n }\n }\n\n /**\n * 获取 ETH 余额\n */\n async getEthBalance(): Promise<string> {\n const balance = await this.provider.getBalance(this.address);\n return ethers.formatEther(balance);\n }\n\n /**\n * 获取 USDC 余额\n */\n async getUsdcBalance(): Promise<string> {\n const balance = await this.usdcContract.balanceOf(this.address);\n return (Number(balance) / 1e6).toFixed(2);\n }\n}\n","/**\n * 区块链配置\n */\n\nimport type { ChainConfig, ChainName } from '../types/index.js';\n\nexport const CHAINS: Record<ChainName, ChainConfig> = {\n // ============ 主网 ============\n base: {\n name: 'Base',\n chainId: 8453,\n rpc: 'https://mainnet.base.org',\n usdc: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',\n explorer: 'https://basescan.org/address/',\n explorerTx: 'https://basescan.org/tx/',\n avgBlockTime: 2,\n },\n polygon: {\n name: 'Polygon',\n chainId: 137,\n rpc: 'https://polygon-rpc.com',\n usdc: '0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359',\n explorer: 'https://polygonscan.com/address/',\n explorerTx: 'https://polygonscan.com/tx/',\n avgBlockTime: 2,\n },\n ethereum: {\n name: 'Ethereum',\n chainId: 1,\n rpc: 'https://eth.llamarpc.com',\n usdc: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',\n explorer: 'https://etherscan.io/address/',\n explorerTx: 'https://etherscan.io/tx/',\n avgBlockTime: 12,\n },\n\n // ============ 测试网 ============\n base_sepolia: {\n name: 'Base Sepolia',\n chainId: 84532,\n rpc: 'https://sepolia.base.org',\n usdc: '0x036CbD53842c5426634e7929541eC2318f3dCF7e',\n explorer: 'https://sepolia.basescan.org/address/',\n explorerTx: 'https://sepolia.basescan.org/tx/',\n avgBlockTime: 2,\n },\n sepolia: {\n name: 'Sepolia',\n chainId: 11155111,\n rpc: 'https://rpc.sepolia.org',\n usdc: '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238',\n explorer: 'https://sepolia.etherscan.io/address/',\n explorerTx: 'https://sepolia.etherscan.io/tx/',\n avgBlockTime: 12,\n },\n};\n\n/**\n * 获取链配置\n */\nexport function getChain(name: ChainName): ChainConfig {\n const config = CHAINS[name];\n if (!config) {\n throw new Error(`Unsupported chain: ${name}. Supported: ${Object.keys(CHAINS).join(', ')}`);\n }\n return config;\n}\n\n/**\n * 列出所有支持的链\n */\nexport function listChains(): ChainName[] {\n return Object.keys(CHAINS) as ChainName[];\n}\n\n/**\n * 根据 chainId 获取链配置\n */\nexport function getChainById(chainId: number): ChainConfig | undefined {\n return Object.values(CHAINS).find(c => c.chainId === chainId);\n}\n\n/**\n * ERC20 ABI(最小化,仅包含需要的方法)\n */\nexport const ERC20_ABI = [\n 'function balanceOf(address owner) view returns (uint256)',\n 'function transfer(address to, uint256 amount) returns (bool)',\n 'function approve(address spender, uint256 amount) returns (bool)',\n 'function allowance(address owner, address spender) view returns (uint256)',\n 'function decimals() view returns (uint8)',\n 'function symbol() view returns (string)',\n 'function name() view returns (string)',\n 'function nonces(address owner) view returns (uint256)',\n 'function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)',\n 'event Transfer(address indexed from, address indexed to, uint256 value)',\n 'event Approval(address indexed owner, address indexed spender, uint256 value)',\n];\n\nexport type { ChainConfig, ChainName };\n","/**\n * AuditLog - 不可篡改审计日志\n * \n * 特点:\n * - 链式哈希,任何修改都会破坏链条\n * - 按日期分文件存储\n * - JSONL 格式便于追加和解析\n */\n\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport * as crypto from 'crypto';\nimport type { AuditEntry, AuditAction } from '../types/index.js';\n\nexport interface LogParams {\n action: AuditAction;\n request_id: string;\n from?: string;\n to?: string;\n amount?: number;\n tx_hash?: string;\n reason?: string;\n requester?: string;\n metadata?: Record<string, unknown>;\n}\n\nexport class AuditLog {\n private basePath: string;\n private lastHash: string = '0000000000000000';\n\n constructor(basePath?: string) {\n this.basePath = basePath || path.join(process.cwd(), 'data', 'audit');\n this.ensureDir();\n this.loadLastHash();\n }\n\n /**\n * 记录审计日志\n */\n async log(params: LogParams): Promise<AuditEntry> {\n const now = new Date();\n \n const entry: AuditEntry = {\n timestamp: now.getTime() / 1000,\n datetime: now.toISOString(),\n action: params.action,\n request_id: params.request_id,\n from: params.from,\n to: params.to,\n amount: params.amount,\n tx_hash: params.tx_hash,\n reason: params.reason,\n requester: params.requester,\n prev_hash: this.lastHash,\n hash: '', // 计算后填充\n metadata: params.metadata,\n };\n\n // 计算哈希(不包含 hash 字段本身)\n entry.hash = this.calculateHash(entry);\n this.lastHash = entry.hash;\n\n // 写入文件\n const filePath = this.getFilePath(now);\n const line = JSON.stringify(entry) + '\\n';\n fs.appendFileSync(filePath, line, 'utf-8');\n\n return entry;\n }\n\n /**\n * 读取指定日期的日志\n */\n read(date?: Date): AuditEntry[] {\n const filePath = this.getFilePath(date || new Date());\n \n if (!fs.existsSync(filePath)) {\n return [];\n }\n\n const content = fs.readFileSync(filePath, 'utf-8');\n const lines = content.trim().split('\\n').filter(Boolean);\n \n return lines.map(line => JSON.parse(line) as AuditEntry);\n }\n\n /**\n * 验证日志完整性\n */\n verify(date?: Date): { valid: boolean; errors: string[] } {\n const entries = this.read(date);\n const errors: string[] = [];\n\n for (let i = 0; i < entries.length; i++) {\n const entry = entries[i];\n \n // 验证哈希\n const expectedHash = this.calculateHash(entry);\n if (entry.hash !== expectedHash) {\n errors.push(`Entry ${i}: hash mismatch (expected ${expectedHash}, got ${entry.hash})`);\n }\n\n // 验证链接\n if (i > 0 && entry.prev_hash !== entries[i - 1].hash) {\n errors.push(`Entry ${i}: prev_hash mismatch`);\n }\n }\n\n return { valid: errors.length === 0, errors };\n }\n\n /**\n * 搜索日志\n */\n search(filter: Partial<{\n action: AuditAction;\n request_id: string;\n from: string;\n to: string;\n startDate: Date;\n endDate: Date;\n }>): AuditEntry[] {\n const results: AuditEntry[] = [];\n const startDate = filter.startDate || new Date(Date.now() - 30 * 24 * 60 * 60 * 1000);\n const endDate = filter.endDate || new Date();\n\n // 遍历日期范围\n const current = new Date(startDate);\n while (current <= endDate) {\n const entries = this.read(current);\n \n for (const entry of entries) {\n let match = true;\n\n if (filter.action && entry.action !== filter.action) match = false;\n if (filter.request_id && entry.request_id !== filter.request_id) match = false;\n if (filter.from && entry.from?.toLowerCase() !== filter.from.toLowerCase()) match = false;\n if (filter.to && entry.to?.toLowerCase() !== filter.to.toLowerCase()) match = false;\n\n if (match) {\n results.push(entry);\n }\n }\n\n current.setDate(current.getDate() + 1);\n }\n\n return results;\n }\n\n /**\n * 获取日志文件路径\n */\n private getFilePath(date: Date): string {\n const dateStr = date.toISOString().slice(0, 10);\n return path.join(this.basePath, `audit_${dateStr}.jsonl`);\n }\n\n /**\n * 计算条目哈希\n */\n private calculateHash(entry: AuditEntry): string {\n const data = {\n timestamp: entry.timestamp,\n action: entry.action,\n request_id: entry.request_id,\n from: entry.from,\n to: entry.to,\n amount: entry.amount,\n tx_hash: entry.tx_hash,\n prev_hash: entry.prev_hash,\n };\n \n const str = JSON.stringify(data);\n return crypto.createHash('sha256').update(str).digest('hex').slice(0, 16);\n }\n\n /**\n * 加载最后一条日志的哈希\n */\n private loadLastHash(): void {\n const today = new Date();\n \n // 检查今天和昨天的日志\n for (let i = 0; i < 2; i++) {\n const date = new Date(today);\n date.setDate(date.getDate() - i);\n \n const entries = this.read(date);\n if (entries.length > 0) {\n this.lastHash = entries[entries.length - 1].hash;\n return;\n }\n }\n }\n\n /**\n * 确保目录存在\n */\n private ensureDir(): void {\n if (!fs.existsSync(this.basePath)) {\n fs.mkdirSync(this.basePath, { recursive: true });\n }\n }\n}\n","/**\n * SecureWallet - 安全托管钱包\n * \n * 在基础 Wallet 之上增加:\n * - 单笔限额控制\n * - 日限额控制\n * - 白名单机制\n * - 审计日志\n * - 超限审批队列\n */\n\nimport { Wallet, type WalletConfig } from './Wallet.js';\nimport { AuditLog } from '../audit/AuditLog.js';\nimport type {\n SecurityLimits,\n SecureWalletConfig,\n TransferResult,\n TransferParams,\n PendingTransfer,\n} from '../types/index.js';\n\nconst DEFAULT_LIMITS: SecurityLimits = {\n singleMax: 100, // 单笔最大 $100\n dailyMax: 1000, // 日最大 $1000\n requireWhitelist: true,\n};\n\nexport class SecureWallet {\n private wallet: Wallet;\n private limits: SecurityLimits;\n private whitelist: Set<string>;\n private auditLog: AuditLog;\n private dailyTotal: number = 0;\n private dailyDate: string = '';\n private pendingTransfers: Map<string, PendingTransfer> = new Map();\n\n constructor(config: SecureWalletConfig = {}) {\n this.wallet = new Wallet({\n chain: config.chain,\n privateKey: config.privateKey,\n });\n\n this.limits = { ...DEFAULT_LIMITS, ...config.limits };\n this.whitelist = new Set((config.whitelist || []).map(a => a.toLowerCase()));\n this.auditLog = new AuditLog(config.auditPath);\n }\n\n /**\n * 获取钱包地址\n */\n get address(): string {\n return this.wallet.address;\n }\n\n /**\n * 获取余额\n */\n async getBalance() {\n return this.wallet.getBalance();\n }\n\n /**\n * 安全转账(带限额和白名单检查)\n */\n async transfer(params: TransferParams): Promise<TransferResult> {\n const { to, amount, reason, requester } = params;\n const toAddress = to.toLowerCase();\n const requestId = `tr_${Date.now().toString(36)}${Math.random().toString(36).slice(2, 8)}`;\n\n // 记录请求\n await this.auditLog.log({\n action: 'transfer_request',\n request_id: requestId,\n from: this.wallet.address,\n to,\n amount,\n reason,\n requester,\n });\n\n // 1. 白名单检查\n if (this.limits.requireWhitelist && !this.whitelist.has(toAddress)) {\n await this.auditLog.log({\n action: 'transfer_failed',\n request_id: requestId,\n metadata: { error: 'Address not in whitelist' },\n });\n return { success: false, error: `Address not in whitelist: ${to}` };\n }\n\n // 2. 单笔限额检查\n if (amount > this.limits.singleMax) {\n // 加入审批队列\n const pending: PendingTransfer = {\n id: requestId,\n to,\n amount,\n reason,\n requester,\n created_at: new Date().toISOString(),\n status: 'pending',\n };\n this.pendingTransfers.set(requestId, pending);\n \n await this.auditLog.log({\n action: 'transfer_request',\n request_id: requestId,\n metadata: { pending: true, reason: 'Exceeds single limit' },\n });\n \n return {\n success: false,\n error: `Amount ${amount} exceeds single limit ${this.limits.singleMax}. Pending approval: ${requestId}`,\n };\n }\n\n // 3. 日限额检查\n this.updateDailyTotal();\n if (this.dailyTotal + amount > this.limits.dailyMax) {\n const pending: PendingTransfer = {\n id: requestId,\n to,\n amount,\n reason,\n requester,\n created_at: new Date().toISOString(),\n status: 'pending',\n };\n this.pendingTransfers.set(requestId, pending);\n \n await this.auditLog.log({\n action: 'transfer_request',\n request_id: requestId,\n metadata: { pending: true, reason: 'Exceeds daily limit' },\n });\n \n return {\n success: false,\n error: `Daily limit would be exceeded (${this.dailyTotal} + ${amount} > ${this.limits.dailyMax}). Pending approval: ${requestId}`,\n };\n }\n\n // 4. 执行转账\n const result = await this.wallet.transfer(to, amount);\n\n // 5. 记录结果\n if (result.success) {\n this.dailyTotal += amount;\n await this.auditLog.log({\n action: 'transfer_executed',\n request_id: requestId,\n from: this.wallet.address,\n to,\n amount,\n tx_hash: result.tx_hash,\n reason,\n requester,\n });\n } else {\n await this.auditLog.log({\n action: 'transfer_failed',\n request_id: requestId,\n metadata: { error: result.error },\n });\n }\n\n return result;\n }\n\n /**\n * 审批待处理转账\n */\n async approve(requestId: string, approver: string): Promise<TransferResult> {\n const pending = this.pendingTransfers.get(requestId);\n if (!pending) {\n return { success: false, error: `Pending transfer not found: ${requestId}` };\n }\n\n if (pending.status !== 'pending') {\n return { success: false, error: `Transfer already ${pending.status}` };\n }\n\n await this.auditLog.log({\n action: 'transfer_approved',\n request_id: requestId,\n metadata: { approver },\n });\n\n pending.status = 'approved';\n\n // 执行转账(跳过限额检查)\n const result = await this.wallet.transfer(pending.to, pending.amount);\n\n if (result.success) {\n pending.status = 'executed';\n this.dailyTotal += pending.amount;\n \n await this.auditLog.log({\n action: 'transfer_executed',\n request_id: requestId,\n from: this.wallet.address,\n to: pending.to,\n amount: pending.amount,\n tx_hash: result.tx_hash,\n reason: pending.reason,\n requester: pending.requester,\n metadata: { approved_by: approver },\n });\n } else {\n await this.auditLog.log({\n action: 'transfer_failed',\n request_id: requestId,\n metadata: { error: result.error },\n });\n }\n\n return result;\n }\n\n /**\n * 拒绝待处理转账\n */\n async reject(requestId: string, rejecter: string, reason?: string): Promise<void> {\n const pending = this.pendingTransfers.get(requestId);\n if (!pending) {\n throw new Error(`Pending transfer not found: ${requestId}`);\n }\n\n pending.status = 'rejected';\n\n await this.auditLog.log({\n action: 'transfer_rejected',\n request_id: requestId,\n metadata: { rejected_by: rejecter, reason },\n });\n }\n\n /**\n * 添加白名单地址\n */\n async addToWhitelist(address: string, addedBy: string): Promise<void> {\n const addr = address.toLowerCase();\n this.whitelist.add(addr);\n\n await this.auditLog.log({\n action: 'whitelist_add',\n request_id: `wl_${Date.now()}`,\n to: address,\n metadata: { added_by: addedBy },\n });\n }\n\n /**\n * 移除白名单地址\n */\n async removeFromWhitelist(address: string, removedBy: string): Promise<void> {\n const addr = address.toLowerCase();\n this.whitelist.delete(addr);\n\n await this.auditLog.log({\n action: 'whitelist_remove',\n request_id: `wl_${Date.now()}`,\n to: address,\n metadata: { removed_by: removedBy },\n });\n }\n\n /**\n * 检查地址是否在白名单\n */\n isWhitelisted(address: string): boolean {\n return this.whitelist.has(address.toLowerCase());\n }\n\n /**\n * 获取待处理转账列表\n */\n getPendingTransfers(): PendingTransfer[] {\n return Array.from(this.pendingTransfers.values())\n .filter(p => p.status === 'pending');\n }\n\n /**\n * 获取当前限额配置\n */\n getLimits(): SecurityLimits {\n return { ...this.limits };\n }\n\n /**\n * 获取今日已用额度\n */\n getDailyUsed(): number {\n this.updateDailyTotal();\n return this.dailyTotal;\n }\n\n /**\n * 更新日限额计数器\n */\n private updateDailyTotal(): void {\n const today = new Date().toISOString().slice(0, 10);\n if (this.dailyDate !== today) {\n this.dailyDate = today;\n this.dailyTotal = 0;\n }\n }\n}\n"],"mappings":";AAQA,SAAS,cAAc;;;ACFhB,IAAM,SAAyC;AAAA;AAAA,EAEpD,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,SAAS;AAAA,IACT,KAAK;AAAA,IACL,MAAM;AAAA,IACN,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,cAAc;AAAA,EAChB;AAAA,EACA,SAAS;AAAA,IACP,MAAM;AAAA,IACN,SAAS;AAAA,IACT,KAAK;AAAA,IACL,MAAM;AAAA,IACN,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,cAAc;AAAA,EAChB;AAAA,EACA,UAAU;AAAA,IACR,MAAM;AAAA,IACN,SAAS;AAAA,IACT,KAAK;AAAA,IACL,MAAM;AAAA,IACN,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,cAAc;AAAA,EAChB;AAAA;AAAA,EAGA,cAAc;AAAA,IACZ,MAAM;AAAA,IACN,SAAS;AAAA,IACT,KAAK;AAAA,IACL,MAAM;AAAA,IACN,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,cAAc;AAAA,EAChB;AAAA,EACA,SAAS;AAAA,IACP,MAAM;AAAA,IACN,SAAS;AAAA,IACT,KAAK;AAAA,IACL,MAAM;AAAA,IACN,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,cAAc;AAAA,EAChB;AACF;AAKO,SAAS,SAAS,MAA8B;AACrD,QAAM,SAAS,OAAO,IAAI;AAC1B,MAAI,CAAC,QAAQ;AACX,UAAM,IAAI,MAAM,sBAAsB,IAAI,gBAAgB,OAAO,KAAK,MAAM,EAAE,KAAK,IAAI,CAAC,EAAE;AAAA,EAC5F;AACA,SAAO;AACT;AAmBO,IAAM,YAAY;AAAA,EACvB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;;;AD1EO,IAAM,SAAN,MAAa;AAAA,EACT;AAAA,EACA;AAAA,EACA;AAAA,EAED;AAAA,EACA;AAAA,EACA;AAAA,EAER,YAAY,SAAuB,CAAC,GAAG;AACrC,SAAK,QAAQ,OAAO,SAAS;AAC7B,SAAK,cAAc,SAAS,KAAK,KAAK;AAEtC,UAAM,aAAa,OAAO,cAAc,QAAQ,IAAI;AACpD,QAAI,CAAC,YAAY;AACf,YAAM,IAAI,MAAM,8EAA8E;AAAA,IAChG;AAEA,UAAM,SAAS,OAAO,UAAU,KAAK,YAAY;AACjD,SAAK,WAAW,IAAI,OAAO,gBAAgB,MAAM;AACjD,SAAK,SAAS,IAAI,OAAO,OAAO,YAAY,KAAK,QAAQ;AACzD,SAAK,UAAU,KAAK,OAAO;AAE3B,SAAK,eAAe,IAAI,OAAO;AAAA,MAC7B,KAAK,YAAY;AAAA,MACjB;AAAA,MACA,KAAK;AAAA,IACP;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,aAAqC;AACzC,UAAM,CAAC,YAAY,WAAW,IAAI,MAAM,QAAQ,IAAI;AAAA,MAClD,KAAK,SAAS,WAAW,KAAK,OAAO;AAAA,MACrC,KAAK,aAAa,UAAU,KAAK,OAAO;AAAA,IAC1C,CAAC;AAED,WAAO;AAAA,MACL,SAAS,KAAK;AAAA,MACd,KAAK,OAAO,YAAY,UAAU;AAAA,MAClC,OAAO,OAAO,WAAW,IAAI,KAAK,QAAQ,CAAC;AAAA,MAC3C,OAAO,KAAK;AAAA,IACd;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,SAAS,IAAY,QAAyC;AAClE,QAAI;AAEF,WAAK,OAAO,WAAW,EAAE;AAGzB,YAAM,YAAY,OAAO,KAAK,MAAM,SAAS,GAAG,CAAC;AAGjD,YAAM,UAAU,MAAM,KAAK,aAAa,UAAU,KAAK,OAAO;AAC9D,UAAI,OAAO,OAAO,IAAI,WAAW;AAC/B,eAAO;AAAA,UACL,SAAS;AAAA,UACT,OAAO,8BAA8B,OAAO,OAAO,IAAI,GAAG,MAAM,MAAM;AAAA,QACxE;AAAA,MACF;AAGA,YAAM,KAAK,MAAM,KAAK,aAAa,SAAS,IAAI,SAAS;AACzD,YAAM,UAAU,MAAM,GAAG,KAAK;AAE9B,UAAI,QAAQ,WAAW,GAAG;AACxB,eAAO;AAAA,UACL,SAAS;AAAA,UACT,SAAS,GAAG;AAAA,UACZ,MAAM,KAAK;AAAA,UACX;AAAA,UACA;AAAA,UACA,UAAU,OAAO,QAAQ,OAAO;AAAA,UAChC,cAAc,QAAQ;AAAA,UACtB,cAAc,GAAG,KAAK,YAAY,UAAU,GAAG,GAAG,IAAI;AAAA,QACxD;AAAA,MACF,OAAO;AACL,eAAO;AAAA,UACL,SAAS;AAAA,UACT,SAAS,GAAG;AAAA,UACZ,OAAO;AAAA,QACT;AAAA,MACF;AAAA,IACF,SAAS,OAAO;AACd,aAAO;AAAA,QACL,SAAS;AAAA,QACT,OAAQ,MAAgB;AAAA,MAC1B;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,gBAAiC;AACrC,UAAM,UAAU,MAAM,KAAK,SAAS,WAAW,KAAK,OAAO;AAC3D,WAAO,OAAO,YAAY,OAAO;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,iBAAkC;AACtC,UAAM,UAAU,MAAM,KAAK,aAAa,UAAU,KAAK,OAAO;AAC9D,YAAQ,OAAO,OAAO,IAAI,KAAK,QAAQ,CAAC;AAAA,EAC1C;AACF;;;AE9HA,YAAY,QAAQ;AACpB,YAAY,UAAU;AACtB,YAAY,YAAY;AAejB,IAAM,WAAN,MAAe;AAAA,EACZ;AAAA,EACA,WAAmB;AAAA,EAE3B,YAAY,UAAmB;AAC7B,SAAK,WAAW,YAAiB,UAAK,QAAQ,IAAI,GAAG,QAAQ,OAAO;AACpE,SAAK,UAAU;AACf,SAAK,aAAa;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,IAAI,QAAwC;AAChD,UAAM,MAAM,oBAAI,KAAK;AAErB,UAAM,QAAoB;AAAA,MACxB,WAAW,IAAI,QAAQ,IAAI;AAAA,MAC3B,UAAU,IAAI,YAAY;AAAA,MAC1B,QAAQ,OAAO;AAAA,MACf,YAAY,OAAO;AAAA,MACnB,MAAM,OAAO;AAAA,MACb,IAAI,OAAO;AAAA,MACX,QAAQ,OAAO;AAAA,MACf,SAAS,OAAO;AAAA,MAChB,QAAQ,OAAO;AAAA,MACf,WAAW,OAAO;AAAA,MAClB,WAAW,KAAK;AAAA,MAChB,MAAM;AAAA;AAAA,MACN,UAAU,OAAO;AAAA,IACnB;AAGA,UAAM,OAAO,KAAK,cAAc,KAAK;AACrC,SAAK,WAAW,MAAM;AAGtB,UAAM,WAAW,KAAK,YAAY,GAAG;AACrC,UAAM,OAAO,KAAK,UAAU,KAAK,IAAI;AACrC,IAAG,kBAAe,UAAU,MAAM,OAAO;AAEzC,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,KAAK,MAA2B;AAC9B,UAAM,WAAW,KAAK,YAAY,QAAQ,oBAAI,KAAK,CAAC;AAEpD,QAAI,CAAI,cAAW,QAAQ,GAAG;AAC5B,aAAO,CAAC;AAAA,IACV;AAEA,UAAM,UAAa,gBAAa,UAAU,OAAO;AACjD,UAAM,QAAQ,QAAQ,KAAK,EAAE,MAAM,IAAI,EAAE,OAAO,OAAO;AAEvD,WAAO,MAAM,IAAI,UAAQ,KAAK,MAAM,IAAI,CAAe;AAAA,EACzD;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,MAAmD;AACxD,UAAM,UAAU,KAAK,KAAK,IAAI;AAC9B,UAAM,SAAmB,CAAC;AAE1B,aAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;AACvC,YAAM,QAAQ,QAAQ,CAAC;AAGvB,YAAM,eAAe,KAAK,cAAc,KAAK;AAC7C,UAAI,MAAM,SAAS,cAAc;AAC/B,eAAO,KAAK,SAAS,CAAC,6BAA6B,YAAY,SAAS,MAAM,IAAI,GAAG;AAAA,MACvF;AAGA,UAAI,IAAI,KAAK,MAAM,cAAc,QAAQ,IAAI,CAAC,EAAE,MAAM;AACpD,eAAO,KAAK,SAAS,CAAC,sBAAsB;AAAA,MAC9C;AAAA,IACF;AAEA,WAAO,EAAE,OAAO,OAAO,WAAW,GAAG,OAAO;AAAA,EAC9C;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,QAOW;AAChB,UAAM,UAAwB,CAAC;AAC/B,UAAM,YAAY,OAAO,aAAa,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,KAAK,KAAK,GAAI;AACpF,UAAM,UAAU,OAAO,WAAW,oBAAI,KAAK;AAG3C,UAAM,UAAU,IAAI,KAAK,SAAS;AAClC,WAAO,WAAW,SAAS;AACzB,YAAM,UAAU,KAAK,KAAK,OAAO;AAEjC,iBAAW,SAAS,SAAS;AAC3B,YAAI,QAAQ;AAEZ,YAAI,OAAO,UAAU,MAAM,WAAW,OAAO,OAAQ,SAAQ;AAC7D,YAAI,OAAO,cAAc,MAAM,eAAe,OAAO,WAAY,SAAQ;AACzE,YAAI,OAAO,QAAQ,MAAM,MAAM,YAAY,MAAM,OAAO,KAAK,YAAY,EAAG,SAAQ;AACpF,YAAI,OAAO,MAAM,MAAM,IAAI,YAAY,MAAM,OAAO,GAAG,YAAY,EAAG,SAAQ;AAE9E,YAAI,OAAO;AACT,kBAAQ,KAAK,KAAK;AAAA,QACpB;AAAA,MACF;AAEA,cAAQ,QAAQ,QAAQ,QAAQ,IAAI,CAAC;AAAA,IACvC;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKQ,YAAY,MAAoB;AACtC,UAAM,UAAU,KAAK,YAAY,EAAE,MAAM,GAAG,EAAE;AAC9C,WAAY,UAAK,KAAK,UAAU,SAAS,OAAO,QAAQ;AAAA,EAC1D;AAAA;AAAA;AAAA;AAAA,EAKQ,cAAc,OAA2B;AAC/C,UAAM,OAAO;AAAA,MACX,WAAW,MAAM;AAAA,MACjB,QAAQ,MAAM;AAAA,MACd,YAAY,MAAM;AAAA,MAClB,MAAM,MAAM;AAAA,MACZ,IAAI,MAAM;AAAA,MACV,QAAQ,MAAM;AAAA,MACd,SAAS,MAAM;AAAA,MACf,WAAW,MAAM;AAAA,IACnB;AAEA,UAAM,MAAM,KAAK,UAAU,IAAI;AAC/B,WAAc,kBAAW,QAAQ,EAAE,OAAO,GAAG,EAAE,OAAO,KAAK,EAAE,MAAM,GAAG,EAAE;AAAA,EAC1E;AAAA;AAAA;AAAA;AAAA,EAKQ,eAAqB;AAC3B,UAAM,QAAQ,oBAAI,KAAK;AAGvB,aAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1B,YAAM,OAAO,IAAI,KAAK,KAAK;AAC3B,WAAK,QAAQ,KAAK,QAAQ,IAAI,CAAC;AAE/B,YAAM,UAAU,KAAK,KAAK,IAAI;AAC9B,UAAI,QAAQ,SAAS,GAAG;AACtB,aAAK,WAAW,QAAQ,QAAQ,SAAS,CAAC,EAAE;AAC5C;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,YAAkB;AACxB,QAAI,CAAI,cAAW,KAAK,QAAQ,GAAG;AACjC,MAAG,aAAU,KAAK,UAAU,EAAE,WAAW,KAAK,CAAC;AAAA,IACjD;AAAA,EACF;AACF;;;ACvLA,IAAM,iBAAiC;AAAA,EACrC,WAAW;AAAA;AAAA,EACX,UAAU;AAAA;AAAA,EACV,kBAAkB;AACpB;AAEO,IAAM,eAAN,MAAmB;AAAA,EAChB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,aAAqB;AAAA,EACrB,YAAoB;AAAA,EACpB,mBAAiD,oBAAI,IAAI;AAAA,EAEjE,YAAY,SAA6B,CAAC,GAAG;AAC3C,SAAK,SAAS,IAAI,OAAO;AAAA,MACvB,OAAO,OAAO;AAAA,MACd,YAAY,OAAO;AAAA,IACrB,CAAC;AAED,SAAK,SAAS,EAAE,GAAG,gBAAgB,GAAG,OAAO,OAAO;AACpD,SAAK,YAAY,IAAI,KAAK,OAAO,aAAa,CAAC,GAAG,IAAI,OAAK,EAAE,YAAY,CAAC,CAAC;AAC3E,SAAK,WAAW,IAAI,SAAS,OAAO,SAAS;AAAA,EAC/C;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,UAAkB;AACpB,WAAO,KAAK,OAAO;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,aAAa;AACjB,WAAO,KAAK,OAAO,WAAW;AAAA,EAChC;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,SAAS,QAAiD;AAC9D,UAAM,EAAE,IAAI,QAAQ,QAAQ,UAAU,IAAI;AAC1C,UAAM,YAAY,GAAG,YAAY;AACjC,UAAM,YAAY,MAAM,KAAK,IAAI,EAAE,SAAS,EAAE,CAAC,GAAG,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,GAAG,CAAC,CAAC;AAGxF,UAAM,KAAK,SAAS,IAAI;AAAA,MACtB,QAAQ;AAAA,MACR,YAAY;AAAA,MACZ,MAAM,KAAK,OAAO;AAAA,MAClB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAGD,QAAI,KAAK,OAAO,oBAAoB,CAAC,KAAK,UAAU,IAAI,SAAS,GAAG;AAClE,YAAM,KAAK,SAAS,IAAI;AAAA,QACtB,QAAQ;AAAA,QACR,YAAY;AAAA,QACZ,UAAU,EAAE,OAAO,2BAA2B;AAAA,MAChD,CAAC;AACD,aAAO,EAAE,SAAS,OAAO,OAAO,6BAA6B,EAAE,GAAG;AAAA,IACpE;AAGA,QAAI,SAAS,KAAK,OAAO,WAAW;AAElC,YAAM,UAA2B;AAAA,QAC/B,IAAI;AAAA,QACJ;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,aAAY,oBAAI,KAAK,GAAE,YAAY;AAAA,QACnC,QAAQ;AAAA,MACV;AACA,WAAK,iBAAiB,IAAI,WAAW,OAAO;AAE5C,YAAM,KAAK,SAAS,IAAI;AAAA,QACtB,QAAQ;AAAA,QACR,YAAY;AAAA,QACZ,UAAU,EAAE,SAAS,MAAM,QAAQ,uBAAuB;AAAA,MAC5D,CAAC;AAED,aAAO;AAAA,QACL,SAAS;AAAA,QACT,OAAO,UAAU,MAAM,yBAAyB,KAAK,OAAO,SAAS,uBAAuB,SAAS;AAAA,MACvG;AAAA,IACF;AAGA,SAAK,iBAAiB;AACtB,QAAI,KAAK,aAAa,SAAS,KAAK,OAAO,UAAU;AACnD,YAAM,UAA2B;AAAA,QAC/B,IAAI;AAAA,QACJ;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,aAAY,oBAAI,KAAK,GAAE,YAAY;AAAA,QACnC,QAAQ;AAAA,MACV;AACA,WAAK,iBAAiB,IAAI,WAAW,OAAO;AAE5C,YAAM,KAAK,SAAS,IAAI;AAAA,QACtB,QAAQ;AAAA,QACR,YAAY;AAAA,QACZ,UAAU,EAAE,SAAS,MAAM,QAAQ,sBAAsB;AAAA,MAC3D,CAAC;AAED,aAAO;AAAA,QACL,SAAS;AAAA,QACT,OAAO,kCAAkC,KAAK,UAAU,MAAM,MAAM,MAAM,KAAK,OAAO,QAAQ,wBAAwB,SAAS;AAAA,MACjI;AAAA,IACF;AAGA,UAAM,SAAS,MAAM,KAAK,OAAO,SAAS,IAAI,MAAM;AAGpD,QAAI,OAAO,SAAS;AAClB,WAAK,cAAc;AACnB,YAAM,KAAK,SAAS,IAAI;AAAA,QACtB,QAAQ;AAAA,QACR,YAAY;AAAA,QACZ,MAAM,KAAK,OAAO;AAAA,QAClB;AAAA,QACA;AAAA,QACA,SAAS,OAAO;AAAA,QAChB;AAAA,QACA;AAAA,MACF,CAAC;AAAA,IACH,OAAO;AACL,YAAM,KAAK,SAAS,IAAI;AAAA,QACtB,QAAQ;AAAA,QACR,YAAY;AAAA,QACZ,UAAU,EAAE,OAAO,OAAO,MAAM;AAAA,MAClC,CAAC;AAAA,IACH;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,QAAQ,WAAmB,UAA2C;AAC1E,UAAM,UAAU,KAAK,iBAAiB,IAAI,SAAS;AACnD,QAAI,CAAC,SAAS;AACZ,aAAO,EAAE,SAAS,OAAO,OAAO,+BAA+B,SAAS,GAAG;AAAA,IAC7E;AAEA,QAAI,QAAQ,WAAW,WAAW;AAChC,aAAO,EAAE,SAAS,OAAO,OAAO,oBAAoB,QAAQ,MAAM,GAAG;AAAA,IACvE;AAEA,UAAM,KAAK,SAAS,IAAI;AAAA,MACtB,QAAQ;AAAA,MACR,YAAY;AAAA,MACZ,UAAU,EAAE,SAAS;AAAA,IACvB,CAAC;AAED,YAAQ,SAAS;AAGjB,UAAM,SAAS,MAAM,KAAK,OAAO,SAAS,QAAQ,IAAI,QAAQ,MAAM;AAEpE,QAAI,OAAO,SAAS;AAClB,cAAQ,SAAS;AACjB,WAAK,cAAc,QAAQ;AAE3B,YAAM,KAAK,SAAS,IAAI;AAAA,QACtB,QAAQ;AAAA,QACR,YAAY;AAAA,QACZ,MAAM,KAAK,OAAO;AAAA,QAClB,IAAI,QAAQ;AAAA,QACZ,QAAQ,QAAQ;AAAA,QAChB,SAAS,OAAO;AAAA,QAChB,QAAQ,QAAQ;AAAA,QAChB,WAAW,QAAQ;AAAA,QACnB,UAAU,EAAE,aAAa,SAAS;AAAA,MACpC,CAAC;AAAA,IACH,OAAO;AACL,YAAM,KAAK,SAAS,IAAI;AAAA,QACtB,QAAQ;AAAA,QACR,YAAY;AAAA,QACZ,UAAU,EAAE,OAAO,OAAO,MAAM;AAAA,MAClC,CAAC;AAAA,IACH;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,OAAO,WAAmB,UAAkB,QAAgC;AAChF,UAAM,UAAU,KAAK,iBAAiB,IAAI,SAAS;AACnD,QAAI,CAAC,SAAS;AACZ,YAAM,IAAI,MAAM,+BAA+B,SAAS,EAAE;AAAA,IAC5D;AAEA,YAAQ,SAAS;AAEjB,UAAM,KAAK,SAAS,IAAI;AAAA,MACtB,QAAQ;AAAA,MACR,YAAY;AAAA,MACZ,UAAU,EAAE,aAAa,UAAU,OAAO;AAAA,IAC5C,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,eAAe,SAAiB,SAAgC;AACpE,UAAM,OAAO,QAAQ,YAAY;AACjC,SAAK,UAAU,IAAI,IAAI;AAEvB,UAAM,KAAK,SAAS,IAAI;AAAA,MACtB,QAAQ;AAAA,MACR,YAAY,MAAM,KAAK,IAAI,CAAC;AAAA,MAC5B,IAAI;AAAA,MACJ,UAAU,EAAE,UAAU,QAAQ;AAAA,IAChC,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,oBAAoB,SAAiB,WAAkC;AAC3E,UAAM,OAAO,QAAQ,YAAY;AACjC,SAAK,UAAU,OAAO,IAAI;AAE1B,UAAM,KAAK,SAAS,IAAI;AAAA,MACtB,QAAQ;AAAA,MACR,YAAY,MAAM,KAAK,IAAI,CAAC;AAAA,MAC5B,IAAI;AAAA,MACJ,UAAU,EAAE,YAAY,UAAU;AAAA,IACpC,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,cAAc,SAA0B;AACtC,WAAO,KAAK,UAAU,IAAI,QAAQ,YAAY,CAAC;AAAA,EACjD;AAAA;AAAA;AAAA;AAAA,EAKA,sBAAyC;AACvC,WAAO,MAAM,KAAK,KAAK,iBAAiB,OAAO,CAAC,EAC7C,OAAO,OAAK,EAAE,WAAW,SAAS;AAAA,EACvC;AAAA;AAAA;AAAA;AAAA,EAKA,YAA4B;AAC1B,WAAO,EAAE,GAAG,KAAK,OAAO;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA,EAKA,eAAuB;AACrB,SAAK,iBAAiB;AACtB,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKQ,mBAAyB;AAC/B,UAAM,SAAQ,oBAAI,KAAK,GAAE,YAAY,EAAE,MAAM,GAAG,EAAE;AAClD,QAAI,KAAK,cAAc,OAAO;AAC5B,WAAK,YAAY;AACjB,WAAK,aAAa;AAAA,IACpB;AAAA,EACF;AACF;","names":[]}
1
+ {"version":3,"sources":["../../src/wallet/Wallet.ts","../../src/chains/index.ts","../../src/audit/AuditLog.ts","../../src/wallet/SecureWallet.ts"],"sourcesContent":["/**\n * Wallet - 基础托管钱包\n * \n * 功能:\n * - 查询余额\n * - 发送 USDC 转账\n */\n\nimport { ethers } from 'ethers';\nimport { getChain, ERC20_ABI } from '../chains/index.js';\nimport type {\n ChainName,\n ChainConfig,\n WalletBalance,\n TransferResult,\n} from '../types/index.js';\n\nexport interface WalletConfig {\n chain?: ChainName;\n privateKey?: string;\n rpcUrl?: string;\n}\n\nexport class Wallet {\n readonly chain: ChainName;\n readonly chainConfig: ChainConfig;\n readonly address: string;\n \n private wallet: ethers.Wallet;\n private provider: ethers.JsonRpcProvider;\n private usdcContract: ethers.Contract;\n\n constructor(config: WalletConfig = {}) {\n this.chain = config.chain || 'base_sepolia';\n this.chainConfig = getChain(this.chain);\n \n const privateKey = config.privateKey || process.env.PAYMENT_AGENT_PRIVATE_KEY;\n if (!privateKey) {\n throw new Error('privateKey is required. Set via config or PAYMENT_AGENT_PRIVATE_KEY env var.');\n }\n\n const rpcUrl = config.rpcUrl || this.chainConfig.rpc;\n this.provider = new ethers.JsonRpcProvider(rpcUrl);\n this.wallet = new ethers.Wallet(privateKey, this.provider);\n this.address = this.wallet.address;\n \n this.usdcContract = new ethers.Contract(\n this.chainConfig.usdc,\n ERC20_ABI,\n this.wallet\n );\n }\n\n /**\n * 获取钱包余额\n */\n async getBalance(): Promise<WalletBalance> {\n const [ethBalance, usdcBalance] = await Promise.all([\n this.provider.getBalance(this.address),\n this.usdcContract.balanceOf(this.address),\n ]);\n\n return {\n address: this.address,\n eth: ethers.formatEther(ethBalance),\n usdc: (Number(usdcBalance) / 1e6).toFixed(2),\n chain: this.chain,\n };\n }\n\n /**\n * 发送 USDC 转账\n */\n async transfer(to: string, amount: number): Promise<TransferResult> {\n try {\n // 验证地址\n to = ethers.getAddress(to);\n \n // 转换金额(USDC 6位小数)\n const amountWei = BigInt(Math.floor(amount * 1e6));\n\n // 检查余额\n const balance = await this.usdcContract.balanceOf(this.address);\n if (BigInt(balance) < amountWei) {\n return {\n success: false,\n error: `Insufficient USDC balance: ${Number(balance) / 1e6} < ${amount}`,\n };\n }\n\n // 发送交易\n const tx = await this.usdcContract.transfer(to, amountWei);\n const receipt = await tx.wait();\n\n if (receipt.status === 1) {\n return {\n success: true,\n tx_hash: tx.hash,\n from: this.address,\n to,\n amount,\n gas_used: Number(receipt.gasUsed),\n block_number: receipt.blockNumber,\n explorer_url: `${this.chainConfig.explorerTx}${tx.hash}`,\n };\n } else {\n return {\n success: false,\n tx_hash: tx.hash,\n error: 'Transaction reverted',\n };\n }\n } catch (error) {\n return {\n success: false,\n error: (error as Error).message,\n };\n }\n }\n\n /**\n * 获取 ETH 余额\n */\n async getEthBalance(): Promise<string> {\n const balance = await this.provider.getBalance(this.address);\n return ethers.formatEther(balance);\n }\n\n /**\n * 获取 USDC 余额\n */\n async getUsdcBalance(): Promise<string> {\n const balance = await this.usdcContract.balanceOf(this.address);\n return (Number(balance) / 1e6).toFixed(2);\n }\n}\n","/**\n * 区块链配置\n */\n\nimport type { ChainConfig, ChainName } from '../types/index.js';\n\nexport const CHAINS: Record<ChainName, ChainConfig> = {\n // ============ 主网 ============\n base: {\n name: 'Base',\n chainId: 8453,\n rpc: 'https://mainnet.base.org',\n usdc: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',\n explorer: 'https://basescan.org/address/',\n explorerTx: 'https://basescan.org/tx/',\n avgBlockTime: 2,\n },\n polygon: {\n name: 'Polygon',\n chainId: 137,\n rpc: 'https://polygon-rpc.com',\n usdc: '0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359',\n explorer: 'https://polygonscan.com/address/',\n explorerTx: 'https://polygonscan.com/tx/',\n avgBlockTime: 2,\n },\n ethereum: {\n name: 'Ethereum',\n chainId: 1,\n rpc: 'https://eth.llamarpc.com',\n usdc: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',\n explorer: 'https://etherscan.io/address/',\n explorerTx: 'https://etherscan.io/tx/',\n avgBlockTime: 12,\n },\n\n // ============ 测试网 ============\n base_sepolia: {\n name: 'Base Sepolia',\n chainId: 84532,\n rpc: 'https://sepolia.base.org',\n usdc: '0x036CbD53842c5426634e7929541eC2318f3dCF7e',\n explorer: 'https://sepolia.basescan.org/address/',\n explorerTx: 'https://sepolia.basescan.org/tx/',\n avgBlockTime: 2,\n },\n sepolia: {\n name: 'Sepolia',\n chainId: 11155111,\n rpc: 'https://rpc.sepolia.org',\n usdc: '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238',\n explorer: 'https://sepolia.etherscan.io/address/',\n explorerTx: 'https://sepolia.etherscan.io/tx/',\n avgBlockTime: 12,\n },\n};\n\n/**\n * 获取链配置\n */\nexport function getChain(name: ChainName): ChainConfig {\n const config = CHAINS[name];\n if (!config) {\n throw new Error(`Unsupported chain: ${name}. Supported: ${Object.keys(CHAINS).join(', ')}`);\n }\n return config;\n}\n\n/**\n * 列出所有支持的链\n */\nexport function listChains(): ChainName[] {\n return Object.keys(CHAINS) as ChainName[];\n}\n\n/**\n * 根据 chainId 获取链配置\n */\nexport function getChainById(chainId: number): ChainConfig | undefined {\n return Object.values(CHAINS).find(c => c.chainId === chainId);\n}\n\n/**\n * ERC20 ABI(最小化,仅包含需要的方法)\n */\nexport const ERC20_ABI = [\n 'function balanceOf(address owner) view returns (uint256)',\n 'function transfer(address to, uint256 amount) returns (bool)',\n 'function approve(address spender, uint256 amount) returns (bool)',\n 'function allowance(address owner, address spender) view returns (uint256)',\n 'function decimals() view returns (uint8)',\n 'function symbol() view returns (string)',\n 'function name() view returns (string)',\n 'function nonces(address owner) view returns (uint256)',\n 'function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)',\n 'event Transfer(address indexed from, address indexed to, uint256 value)',\n 'event Approval(address indexed owner, address indexed spender, uint256 value)',\n];\n\nexport type { ChainConfig, ChainName };\n","/**\n * AuditLog - 不可篡改审计日志\n * \n * 特点:\n * - 链式哈希,任何修改都会破坏链条\n * - 按日期分文件存储\n * - JSONL 格式便于追加和解析\n */\n\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport * as crypto from 'crypto';\nimport type { AuditEntry, AuditAction } from '../types/index.js';\n\nexport interface LogParams {\n action: AuditAction;\n request_id: string;\n from?: string;\n to?: string;\n amount?: number;\n tx_hash?: string;\n reason?: string;\n requester?: string;\n metadata?: Record<string, unknown>;\n}\n\nexport class AuditLog {\n private basePath: string;\n private lastHash: string = '0000000000000000';\n\n constructor(basePath?: string) {\n this.basePath = basePath || path.join(process.cwd(), 'data', 'audit');\n this.ensureDir();\n this.loadLastHash();\n }\n\n /**\n * 记录审计日志\n */\n async log(params: LogParams): Promise<AuditEntry> {\n const now = new Date();\n \n const entry: AuditEntry = {\n timestamp: now.getTime() / 1000,\n datetime: now.toISOString(),\n action: params.action,\n request_id: params.request_id,\n from: params.from,\n to: params.to,\n amount: params.amount,\n tx_hash: params.tx_hash,\n reason: params.reason,\n requester: params.requester,\n prev_hash: this.lastHash,\n hash: '', // 计算后填充\n metadata: params.metadata,\n };\n\n // 计算哈希(不包含 hash 字段本身)\n entry.hash = this.calculateHash(entry);\n this.lastHash = entry.hash;\n\n // 写入文件\n const filePath = this.getFilePath(now);\n const line = JSON.stringify(entry) + '\\n';\n fs.appendFileSync(filePath, line, 'utf-8');\n\n return entry;\n }\n\n /**\n * 读取指定日期的日志\n */\n read(date?: Date): AuditEntry[] {\n const filePath = this.getFilePath(date || new Date());\n \n if (!fs.existsSync(filePath)) {\n return [];\n }\n\n const content = fs.readFileSync(filePath, 'utf-8');\n const lines = content.trim().split('\\n').filter(Boolean);\n \n return lines.map(line => JSON.parse(line) as AuditEntry);\n }\n\n /**\n * 验证日志完整性\n */\n verify(date?: Date): { valid: boolean; errors: string[] } {\n const entries = this.read(date);\n const errors: string[] = [];\n\n for (let i = 0; i < entries.length; i++) {\n const entry = entries[i];\n \n // 验证哈希\n const expectedHash = this.calculateHash(entry);\n if (entry.hash !== expectedHash) {\n errors.push(`Entry ${i}: hash mismatch (expected ${expectedHash}, got ${entry.hash})`);\n }\n\n // 验证链接\n if (i > 0 && entry.prev_hash !== entries[i - 1].hash) {\n errors.push(`Entry ${i}: prev_hash mismatch`);\n }\n }\n\n return { valid: errors.length === 0, errors };\n }\n\n /**\n * 搜索日志\n */\n search(filter: Partial<{\n action: AuditAction;\n request_id: string;\n from: string;\n to: string;\n startDate: Date;\n endDate: Date;\n }>): AuditEntry[] {\n const results: AuditEntry[] = [];\n const startDate = filter.startDate || new Date(Date.now() - 30 * 24 * 60 * 60 * 1000);\n const endDate = filter.endDate || new Date();\n\n // 遍历日期范围\n const current = new Date(startDate);\n while (current <= endDate) {\n const entries = this.read(current);\n \n for (const entry of entries) {\n let match = true;\n\n if (filter.action && entry.action !== filter.action) match = false;\n if (filter.request_id && entry.request_id !== filter.request_id) match = false;\n if (filter.from && entry.from?.toLowerCase() !== filter.from.toLowerCase()) match = false;\n if (filter.to && entry.to?.toLowerCase() !== filter.to.toLowerCase()) match = false;\n\n if (match) {\n results.push(entry);\n }\n }\n\n current.setDate(current.getDate() + 1);\n }\n\n return results;\n }\n\n /**\n * 获取日志文件路径\n */\n private getFilePath(date: Date): string {\n const dateStr = date.toISOString().slice(0, 10);\n return path.join(this.basePath, `audit_${dateStr}.jsonl`);\n }\n\n /**\n * 计算条目哈希\n */\n private calculateHash(entry: AuditEntry): string {\n const data = {\n timestamp: entry.timestamp,\n action: entry.action,\n request_id: entry.request_id,\n from: entry.from,\n to: entry.to,\n amount: entry.amount,\n tx_hash: entry.tx_hash,\n prev_hash: entry.prev_hash,\n };\n \n const str = JSON.stringify(data);\n return crypto.createHash('sha256').update(str).digest('hex').slice(0, 16);\n }\n\n /**\n * 加载最后一条日志的哈希\n */\n private loadLastHash(): void {\n const today = new Date();\n \n // 检查今天和昨天的日志\n for (let i = 0; i < 2; i++) {\n const date = new Date(today);\n date.setDate(date.getDate() - i);\n \n const entries = this.read(date);\n if (entries.length > 0) {\n this.lastHash = entries[entries.length - 1].hash;\n return;\n }\n }\n }\n\n /**\n * 确保目录存在\n */\n private ensureDir(): void {\n if (!fs.existsSync(this.basePath)) {\n fs.mkdirSync(this.basePath, { recursive: true });\n }\n }\n}\n","/**\n * SecureWallet - 安全托管钱包\n * \n * 在基础 Wallet 之上增加:\n * - 单笔限额控制\n * - 日限额控制\n * - 白名单机制\n * - 审计日志\n * - 超限审批队列\n */\n\nimport { Wallet, type WalletConfig } from './Wallet.js';\nimport { AuditLog } from '../audit/AuditLog.js';\nimport type {\n SecurityLimits,\n SecureWalletConfig,\n TransferResult,\n TransferParams,\n PendingTransfer,\n} from '../types/index.js';\n\nconst DEFAULT_LIMITS: SecurityLimits = {\n singleMax: 100, // 单笔最大 $100\n dailyMax: 1000, // 日最大 $1000\n requireWhitelist: true,\n};\n\nexport class SecureWallet {\n private wallet: Wallet;\n private limits: SecurityLimits;\n private whitelist: Set<string>;\n private auditLog: AuditLog;\n private dailyTotal: number = 0;\n private dailyDate: string = '';\n private pendingTransfers: Map<string, PendingTransfer> = new Map();\n\n constructor(config: SecureWalletConfig = {}) {\n this.wallet = new Wallet({\n chain: config.chain,\n privateKey: config.privateKey,\n });\n\n this.limits = { ...DEFAULT_LIMITS, ...config.limits };\n this.whitelist = new Set((config.whitelist || []).map(a => a.toLowerCase()));\n this.auditLog = new AuditLog(config.auditPath);\n }\n\n /**\n * 获取钱包地址\n */\n get address(): string {\n return this.wallet.address;\n }\n\n /**\n * 获取余额\n */\n async getBalance() {\n return this.wallet.getBalance();\n }\n\n /**\n * 安全转账(带限额和白名单检查)\n * \n * 支持两种调用方式:\n * - transfer({ to, amount, reason?, requester? })\n * - transfer(to, amount)\n */\n async transfer(paramsOrTo: TransferParams | string, amountArg?: number | string): Promise<TransferResult> {\n // 支持两种调用方式\n let params: TransferParams;\n if (typeof paramsOrTo === 'string') {\n params = { \n to: paramsOrTo, \n amount: typeof amountArg === 'string' ? parseFloat(amountArg) : (amountArg || 0)\n };\n } else {\n params = paramsOrTo;\n }\n \n const { to, amount, reason, requester } = params;\n const toAddress = to.toLowerCase();\n const requestId = `tr_${Date.now().toString(36)}${Math.random().toString(36).slice(2, 8)}`;\n\n // 记录请求\n await this.auditLog.log({\n action: 'transfer_request',\n request_id: requestId,\n from: this.wallet.address,\n to,\n amount,\n reason,\n requester,\n });\n\n // 1. 白名单检查\n if (this.limits.requireWhitelist && !this.whitelist.has(toAddress)) {\n await this.auditLog.log({\n action: 'transfer_failed',\n request_id: requestId,\n metadata: { error: 'Address not in whitelist' },\n });\n return { success: false, error: `Address not in whitelist: ${to}` };\n }\n\n // 2. 单笔限额检查\n if (amount > this.limits.singleMax) {\n // 加入审批队列\n const pending: PendingTransfer = {\n id: requestId,\n to,\n amount,\n reason,\n requester,\n created_at: new Date().toISOString(),\n status: 'pending',\n };\n this.pendingTransfers.set(requestId, pending);\n \n await this.auditLog.log({\n action: 'transfer_request',\n request_id: requestId,\n metadata: { pending: true, reason: 'Exceeds single limit' },\n });\n \n return {\n success: false,\n error: `Amount ${amount} exceeds single limit ${this.limits.singleMax}. Pending approval: ${requestId}`,\n };\n }\n\n // 3. 日限额检查\n this.updateDailyTotal();\n if (this.dailyTotal + amount > this.limits.dailyMax) {\n const pending: PendingTransfer = {\n id: requestId,\n to,\n amount,\n reason,\n requester,\n created_at: new Date().toISOString(),\n status: 'pending',\n };\n this.pendingTransfers.set(requestId, pending);\n \n await this.auditLog.log({\n action: 'transfer_request',\n request_id: requestId,\n metadata: { pending: true, reason: 'Exceeds daily limit' },\n });\n \n return {\n success: false,\n error: `Daily limit would be exceeded (${this.dailyTotal} + ${amount} > ${this.limits.dailyMax}). Pending approval: ${requestId}`,\n };\n }\n\n // 4. 执行转账\n const result = await this.wallet.transfer(to, amount);\n\n // 5. 记录结果\n if (result.success) {\n this.dailyTotal += amount;\n await this.auditLog.log({\n action: 'transfer_executed',\n request_id: requestId,\n from: this.wallet.address,\n to,\n amount,\n tx_hash: result.tx_hash,\n reason,\n requester,\n });\n } else {\n await this.auditLog.log({\n action: 'transfer_failed',\n request_id: requestId,\n metadata: { error: result.error },\n });\n }\n\n return result;\n }\n\n /**\n * 审批待处理转账\n */\n async approve(requestId: string, approver: string): Promise<TransferResult> {\n const pending = this.pendingTransfers.get(requestId);\n if (!pending) {\n return { success: false, error: `Pending transfer not found: ${requestId}` };\n }\n\n if (pending.status !== 'pending') {\n return { success: false, error: `Transfer already ${pending.status}` };\n }\n\n await this.auditLog.log({\n action: 'transfer_approved',\n request_id: requestId,\n metadata: { approver },\n });\n\n pending.status = 'approved';\n\n // 执行转账(跳过限额检查)\n const result = await this.wallet.transfer(pending.to, pending.amount);\n\n if (result.success) {\n pending.status = 'executed';\n this.dailyTotal += pending.amount;\n \n await this.auditLog.log({\n action: 'transfer_executed',\n request_id: requestId,\n from: this.wallet.address,\n to: pending.to,\n amount: pending.amount,\n tx_hash: result.tx_hash,\n reason: pending.reason,\n requester: pending.requester,\n metadata: { approved_by: approver },\n });\n } else {\n await this.auditLog.log({\n action: 'transfer_failed',\n request_id: requestId,\n metadata: { error: result.error },\n });\n }\n\n return result;\n }\n\n /**\n * 拒绝待处理转账\n */\n async reject(requestId: string, rejecter: string, reason?: string): Promise<void> {\n const pending = this.pendingTransfers.get(requestId);\n if (!pending) {\n throw new Error(`Pending transfer not found: ${requestId}`);\n }\n\n pending.status = 'rejected';\n\n await this.auditLog.log({\n action: 'transfer_rejected',\n request_id: requestId,\n metadata: { rejected_by: rejecter, reason },\n });\n }\n\n /**\n * 添加白名单地址\n */\n async addToWhitelist(address: string, addedBy: string): Promise<void> {\n const addr = address.toLowerCase();\n this.whitelist.add(addr);\n\n await this.auditLog.log({\n action: 'whitelist_add',\n request_id: `wl_${Date.now()}`,\n to: address,\n metadata: { added_by: addedBy },\n });\n }\n\n /**\n * 移除白名单地址\n */\n async removeFromWhitelist(address: string, removedBy: string): Promise<void> {\n const addr = address.toLowerCase();\n this.whitelist.delete(addr);\n\n await this.auditLog.log({\n action: 'whitelist_remove',\n request_id: `wl_${Date.now()}`,\n to: address,\n metadata: { removed_by: removedBy },\n });\n }\n\n /**\n * 检查地址是否在白名单\n */\n isWhitelisted(address: string): boolean {\n return this.whitelist.has(address.toLowerCase());\n }\n\n /**\n * 获取待处理转账列表\n */\n getPendingTransfers(): PendingTransfer[] {\n return Array.from(this.pendingTransfers.values())\n .filter(p => p.status === 'pending');\n }\n\n /**\n * 获取当前限额配置\n */\n getLimits(): SecurityLimits {\n return { ...this.limits };\n }\n\n /**\n * 获取今日已用额度\n */\n getDailyUsed(): number {\n this.updateDailyTotal();\n return this.dailyTotal;\n }\n\n /**\n * 更新日限额计数器\n */\n private updateDailyTotal(): void {\n const today = new Date().toISOString().slice(0, 10);\n if (this.dailyDate !== today) {\n this.dailyDate = today;\n this.dailyTotal = 0;\n }\n }\n}\n"],"mappings":";AAQA,SAAS,cAAc;;;ACFhB,IAAM,SAAyC;AAAA;AAAA,EAEpD,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,SAAS;AAAA,IACT,KAAK;AAAA,IACL,MAAM;AAAA,IACN,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,cAAc;AAAA,EAChB;AAAA,EACA,SAAS;AAAA,IACP,MAAM;AAAA,IACN,SAAS;AAAA,IACT,KAAK;AAAA,IACL,MAAM;AAAA,IACN,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,cAAc;AAAA,EAChB;AAAA,EACA,UAAU;AAAA,IACR,MAAM;AAAA,IACN,SAAS;AAAA,IACT,KAAK;AAAA,IACL,MAAM;AAAA,IACN,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,cAAc;AAAA,EAChB;AAAA;AAAA,EAGA,cAAc;AAAA,IACZ,MAAM;AAAA,IACN,SAAS;AAAA,IACT,KAAK;AAAA,IACL,MAAM;AAAA,IACN,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,cAAc;AAAA,EAChB;AAAA,EACA,SAAS;AAAA,IACP,MAAM;AAAA,IACN,SAAS;AAAA,IACT,KAAK;AAAA,IACL,MAAM;AAAA,IACN,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,cAAc;AAAA,EAChB;AACF;AAKO,SAAS,SAAS,MAA8B;AACrD,QAAM,SAAS,OAAO,IAAI;AAC1B,MAAI,CAAC,QAAQ;AACX,UAAM,IAAI,MAAM,sBAAsB,IAAI,gBAAgB,OAAO,KAAK,MAAM,EAAE,KAAK,IAAI,CAAC,EAAE;AAAA,EAC5F;AACA,SAAO;AACT;AAmBO,IAAM,YAAY;AAAA,EACvB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;;;AD1EO,IAAM,SAAN,MAAa;AAAA,EACT;AAAA,EACA;AAAA,EACA;AAAA,EAED;AAAA,EACA;AAAA,EACA;AAAA,EAER,YAAY,SAAuB,CAAC,GAAG;AACrC,SAAK,QAAQ,OAAO,SAAS;AAC7B,SAAK,cAAc,SAAS,KAAK,KAAK;AAEtC,UAAM,aAAa,OAAO,cAAc,QAAQ,IAAI;AACpD,QAAI,CAAC,YAAY;AACf,YAAM,IAAI,MAAM,8EAA8E;AAAA,IAChG;AAEA,UAAM,SAAS,OAAO,UAAU,KAAK,YAAY;AACjD,SAAK,WAAW,IAAI,OAAO,gBAAgB,MAAM;AACjD,SAAK,SAAS,IAAI,OAAO,OAAO,YAAY,KAAK,QAAQ;AACzD,SAAK,UAAU,KAAK,OAAO;AAE3B,SAAK,eAAe,IAAI,OAAO;AAAA,MAC7B,KAAK,YAAY;AAAA,MACjB;AAAA,MACA,KAAK;AAAA,IACP;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,aAAqC;AACzC,UAAM,CAAC,YAAY,WAAW,IAAI,MAAM,QAAQ,IAAI;AAAA,MAClD,KAAK,SAAS,WAAW,KAAK,OAAO;AAAA,MACrC,KAAK,aAAa,UAAU,KAAK,OAAO;AAAA,IAC1C,CAAC;AAED,WAAO;AAAA,MACL,SAAS,KAAK;AAAA,MACd,KAAK,OAAO,YAAY,UAAU;AAAA,MAClC,OAAO,OAAO,WAAW,IAAI,KAAK,QAAQ,CAAC;AAAA,MAC3C,OAAO,KAAK;AAAA,IACd;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,SAAS,IAAY,QAAyC;AAClE,QAAI;AAEF,WAAK,OAAO,WAAW,EAAE;AAGzB,YAAM,YAAY,OAAO,KAAK,MAAM,SAAS,GAAG,CAAC;AAGjD,YAAM,UAAU,MAAM,KAAK,aAAa,UAAU,KAAK,OAAO;AAC9D,UAAI,OAAO,OAAO,IAAI,WAAW;AAC/B,eAAO;AAAA,UACL,SAAS;AAAA,UACT,OAAO,8BAA8B,OAAO,OAAO,IAAI,GAAG,MAAM,MAAM;AAAA,QACxE;AAAA,MACF;AAGA,YAAM,KAAK,MAAM,KAAK,aAAa,SAAS,IAAI,SAAS;AACzD,YAAM,UAAU,MAAM,GAAG,KAAK;AAE9B,UAAI,QAAQ,WAAW,GAAG;AACxB,eAAO;AAAA,UACL,SAAS;AAAA,UACT,SAAS,GAAG;AAAA,UACZ,MAAM,KAAK;AAAA,UACX;AAAA,UACA;AAAA,UACA,UAAU,OAAO,QAAQ,OAAO;AAAA,UAChC,cAAc,QAAQ;AAAA,UACtB,cAAc,GAAG,KAAK,YAAY,UAAU,GAAG,GAAG,IAAI;AAAA,QACxD;AAAA,MACF,OAAO;AACL,eAAO;AAAA,UACL,SAAS;AAAA,UACT,SAAS,GAAG;AAAA,UACZ,OAAO;AAAA,QACT;AAAA,MACF;AAAA,IACF,SAAS,OAAO;AACd,aAAO;AAAA,QACL,SAAS;AAAA,QACT,OAAQ,MAAgB;AAAA,MAC1B;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,gBAAiC;AACrC,UAAM,UAAU,MAAM,KAAK,SAAS,WAAW,KAAK,OAAO;AAC3D,WAAO,OAAO,YAAY,OAAO;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,iBAAkC;AACtC,UAAM,UAAU,MAAM,KAAK,aAAa,UAAU,KAAK,OAAO;AAC9D,YAAQ,OAAO,OAAO,IAAI,KAAK,QAAQ,CAAC;AAAA,EAC1C;AACF;;;AE9HA,YAAY,QAAQ;AACpB,YAAY,UAAU;AACtB,YAAY,YAAY;AAejB,IAAM,WAAN,MAAe;AAAA,EACZ;AAAA,EACA,WAAmB;AAAA,EAE3B,YAAY,UAAmB;AAC7B,SAAK,WAAW,YAAiB,UAAK,QAAQ,IAAI,GAAG,QAAQ,OAAO;AACpE,SAAK,UAAU;AACf,SAAK,aAAa;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,IAAI,QAAwC;AAChD,UAAM,MAAM,oBAAI,KAAK;AAErB,UAAM,QAAoB;AAAA,MACxB,WAAW,IAAI,QAAQ,IAAI;AAAA,MAC3B,UAAU,IAAI,YAAY;AAAA,MAC1B,QAAQ,OAAO;AAAA,MACf,YAAY,OAAO;AAAA,MACnB,MAAM,OAAO;AAAA,MACb,IAAI,OAAO;AAAA,MACX,QAAQ,OAAO;AAAA,MACf,SAAS,OAAO;AAAA,MAChB,QAAQ,OAAO;AAAA,MACf,WAAW,OAAO;AAAA,MAClB,WAAW,KAAK;AAAA,MAChB,MAAM;AAAA;AAAA,MACN,UAAU,OAAO;AAAA,IACnB;AAGA,UAAM,OAAO,KAAK,cAAc,KAAK;AACrC,SAAK,WAAW,MAAM;AAGtB,UAAM,WAAW,KAAK,YAAY,GAAG;AACrC,UAAM,OAAO,KAAK,UAAU,KAAK,IAAI;AACrC,IAAG,kBAAe,UAAU,MAAM,OAAO;AAEzC,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,KAAK,MAA2B;AAC9B,UAAM,WAAW,KAAK,YAAY,QAAQ,oBAAI,KAAK,CAAC;AAEpD,QAAI,CAAI,cAAW,QAAQ,GAAG;AAC5B,aAAO,CAAC;AAAA,IACV;AAEA,UAAM,UAAa,gBAAa,UAAU,OAAO;AACjD,UAAM,QAAQ,QAAQ,KAAK,EAAE,MAAM,IAAI,EAAE,OAAO,OAAO;AAEvD,WAAO,MAAM,IAAI,UAAQ,KAAK,MAAM,IAAI,CAAe;AAAA,EACzD;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,MAAmD;AACxD,UAAM,UAAU,KAAK,KAAK,IAAI;AAC9B,UAAM,SAAmB,CAAC;AAE1B,aAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;AACvC,YAAM,QAAQ,QAAQ,CAAC;AAGvB,YAAM,eAAe,KAAK,cAAc,KAAK;AAC7C,UAAI,MAAM,SAAS,cAAc;AAC/B,eAAO,KAAK,SAAS,CAAC,6BAA6B,YAAY,SAAS,MAAM,IAAI,GAAG;AAAA,MACvF;AAGA,UAAI,IAAI,KAAK,MAAM,cAAc,QAAQ,IAAI,CAAC,EAAE,MAAM;AACpD,eAAO,KAAK,SAAS,CAAC,sBAAsB;AAAA,MAC9C;AAAA,IACF;AAEA,WAAO,EAAE,OAAO,OAAO,WAAW,GAAG,OAAO;AAAA,EAC9C;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,QAOW;AAChB,UAAM,UAAwB,CAAC;AAC/B,UAAM,YAAY,OAAO,aAAa,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,KAAK,KAAK,GAAI;AACpF,UAAM,UAAU,OAAO,WAAW,oBAAI,KAAK;AAG3C,UAAM,UAAU,IAAI,KAAK,SAAS;AAClC,WAAO,WAAW,SAAS;AACzB,YAAM,UAAU,KAAK,KAAK,OAAO;AAEjC,iBAAW,SAAS,SAAS;AAC3B,YAAI,QAAQ;AAEZ,YAAI,OAAO,UAAU,MAAM,WAAW,OAAO,OAAQ,SAAQ;AAC7D,YAAI,OAAO,cAAc,MAAM,eAAe,OAAO,WAAY,SAAQ;AACzE,YAAI,OAAO,QAAQ,MAAM,MAAM,YAAY,MAAM,OAAO,KAAK,YAAY,EAAG,SAAQ;AACpF,YAAI,OAAO,MAAM,MAAM,IAAI,YAAY,MAAM,OAAO,GAAG,YAAY,EAAG,SAAQ;AAE9E,YAAI,OAAO;AACT,kBAAQ,KAAK,KAAK;AAAA,QACpB;AAAA,MACF;AAEA,cAAQ,QAAQ,QAAQ,QAAQ,IAAI,CAAC;AAAA,IACvC;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKQ,YAAY,MAAoB;AACtC,UAAM,UAAU,KAAK,YAAY,EAAE,MAAM,GAAG,EAAE;AAC9C,WAAY,UAAK,KAAK,UAAU,SAAS,OAAO,QAAQ;AAAA,EAC1D;AAAA;AAAA;AAAA;AAAA,EAKQ,cAAc,OAA2B;AAC/C,UAAM,OAAO;AAAA,MACX,WAAW,MAAM;AAAA,MACjB,QAAQ,MAAM;AAAA,MACd,YAAY,MAAM;AAAA,MAClB,MAAM,MAAM;AAAA,MACZ,IAAI,MAAM;AAAA,MACV,QAAQ,MAAM;AAAA,MACd,SAAS,MAAM;AAAA,MACf,WAAW,MAAM;AAAA,IACnB;AAEA,UAAM,MAAM,KAAK,UAAU,IAAI;AAC/B,WAAc,kBAAW,QAAQ,EAAE,OAAO,GAAG,EAAE,OAAO,KAAK,EAAE,MAAM,GAAG,EAAE;AAAA,EAC1E;AAAA;AAAA;AAAA;AAAA,EAKQ,eAAqB;AAC3B,UAAM,QAAQ,oBAAI,KAAK;AAGvB,aAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1B,YAAM,OAAO,IAAI,KAAK,KAAK;AAC3B,WAAK,QAAQ,KAAK,QAAQ,IAAI,CAAC;AAE/B,YAAM,UAAU,KAAK,KAAK,IAAI;AAC9B,UAAI,QAAQ,SAAS,GAAG;AACtB,aAAK,WAAW,QAAQ,QAAQ,SAAS,CAAC,EAAE;AAC5C;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,YAAkB;AACxB,QAAI,CAAI,cAAW,KAAK,QAAQ,GAAG;AACjC,MAAG,aAAU,KAAK,UAAU,EAAE,WAAW,KAAK,CAAC;AAAA,IACjD;AAAA,EACF;AACF;;;ACvLA,IAAM,iBAAiC;AAAA,EACrC,WAAW;AAAA;AAAA,EACX,UAAU;AAAA;AAAA,EACV,kBAAkB;AACpB;AAEO,IAAM,eAAN,MAAmB;AAAA,EAChB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,aAAqB;AAAA,EACrB,YAAoB;AAAA,EACpB,mBAAiD,oBAAI,IAAI;AAAA,EAEjE,YAAY,SAA6B,CAAC,GAAG;AAC3C,SAAK,SAAS,IAAI,OAAO;AAAA,MACvB,OAAO,OAAO;AAAA,MACd,YAAY,OAAO;AAAA,IACrB,CAAC;AAED,SAAK,SAAS,EAAE,GAAG,gBAAgB,GAAG,OAAO,OAAO;AACpD,SAAK,YAAY,IAAI,KAAK,OAAO,aAAa,CAAC,GAAG,IAAI,OAAK,EAAE,YAAY,CAAC,CAAC;AAC3E,SAAK,WAAW,IAAI,SAAS,OAAO,SAAS;AAAA,EAC/C;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,UAAkB;AACpB,WAAO,KAAK,OAAO;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,aAAa;AACjB,WAAO,KAAK,OAAO,WAAW;AAAA,EAChC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,SAAS,YAAqC,WAAsD;AAExG,QAAI;AACJ,QAAI,OAAO,eAAe,UAAU;AAClC,eAAS;AAAA,QACP,IAAI;AAAA,QACJ,QAAQ,OAAO,cAAc,WAAW,WAAW,SAAS,IAAK,aAAa;AAAA,MAChF;AAAA,IACF,OAAO;AACL,eAAS;AAAA,IACX;AAEA,UAAM,EAAE,IAAI,QAAQ,QAAQ,UAAU,IAAI;AAC1C,UAAM,YAAY,GAAG,YAAY;AACjC,UAAM,YAAY,MAAM,KAAK,IAAI,EAAE,SAAS,EAAE,CAAC,GAAG,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,GAAG,CAAC,CAAC;AAGxF,UAAM,KAAK,SAAS,IAAI;AAAA,MACtB,QAAQ;AAAA,MACR,YAAY;AAAA,MACZ,MAAM,KAAK,OAAO;AAAA,MAClB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAGD,QAAI,KAAK,OAAO,oBAAoB,CAAC,KAAK,UAAU,IAAI,SAAS,GAAG;AAClE,YAAM,KAAK,SAAS,IAAI;AAAA,QACtB,QAAQ;AAAA,QACR,YAAY;AAAA,QACZ,UAAU,EAAE,OAAO,2BAA2B;AAAA,MAChD,CAAC;AACD,aAAO,EAAE,SAAS,OAAO,OAAO,6BAA6B,EAAE,GAAG;AAAA,IACpE;AAGA,QAAI,SAAS,KAAK,OAAO,WAAW;AAElC,YAAM,UAA2B;AAAA,QAC/B,IAAI;AAAA,QACJ;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,aAAY,oBAAI,KAAK,GAAE,YAAY;AAAA,QACnC,QAAQ;AAAA,MACV;AACA,WAAK,iBAAiB,IAAI,WAAW,OAAO;AAE5C,YAAM,KAAK,SAAS,IAAI;AAAA,QACtB,QAAQ;AAAA,QACR,YAAY;AAAA,QACZ,UAAU,EAAE,SAAS,MAAM,QAAQ,uBAAuB;AAAA,MAC5D,CAAC;AAED,aAAO;AAAA,QACL,SAAS;AAAA,QACT,OAAO,UAAU,MAAM,yBAAyB,KAAK,OAAO,SAAS,uBAAuB,SAAS;AAAA,MACvG;AAAA,IACF;AAGA,SAAK,iBAAiB;AACtB,QAAI,KAAK,aAAa,SAAS,KAAK,OAAO,UAAU;AACnD,YAAM,UAA2B;AAAA,QAC/B,IAAI;AAAA,QACJ;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,aAAY,oBAAI,KAAK,GAAE,YAAY;AAAA,QACnC,QAAQ;AAAA,MACV;AACA,WAAK,iBAAiB,IAAI,WAAW,OAAO;AAE5C,YAAM,KAAK,SAAS,IAAI;AAAA,QACtB,QAAQ;AAAA,QACR,YAAY;AAAA,QACZ,UAAU,EAAE,SAAS,MAAM,QAAQ,sBAAsB;AAAA,MAC3D,CAAC;AAED,aAAO;AAAA,QACL,SAAS;AAAA,QACT,OAAO,kCAAkC,KAAK,UAAU,MAAM,MAAM,MAAM,KAAK,OAAO,QAAQ,wBAAwB,SAAS;AAAA,MACjI;AAAA,IACF;AAGA,UAAM,SAAS,MAAM,KAAK,OAAO,SAAS,IAAI,MAAM;AAGpD,QAAI,OAAO,SAAS;AAClB,WAAK,cAAc;AACnB,YAAM,KAAK,SAAS,IAAI;AAAA,QACtB,QAAQ;AAAA,QACR,YAAY;AAAA,QACZ,MAAM,KAAK,OAAO;AAAA,QAClB;AAAA,QACA;AAAA,QACA,SAAS,OAAO;AAAA,QAChB;AAAA,QACA;AAAA,MACF,CAAC;AAAA,IACH,OAAO;AACL,YAAM,KAAK,SAAS,IAAI;AAAA,QACtB,QAAQ;AAAA,QACR,YAAY;AAAA,QACZ,UAAU,EAAE,OAAO,OAAO,MAAM;AAAA,MAClC,CAAC;AAAA,IACH;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,QAAQ,WAAmB,UAA2C;AAC1E,UAAM,UAAU,KAAK,iBAAiB,IAAI,SAAS;AACnD,QAAI,CAAC,SAAS;AACZ,aAAO,EAAE,SAAS,OAAO,OAAO,+BAA+B,SAAS,GAAG;AAAA,IAC7E;AAEA,QAAI,QAAQ,WAAW,WAAW;AAChC,aAAO,EAAE,SAAS,OAAO,OAAO,oBAAoB,QAAQ,MAAM,GAAG;AAAA,IACvE;AAEA,UAAM,KAAK,SAAS,IAAI;AAAA,MACtB,QAAQ;AAAA,MACR,YAAY;AAAA,MACZ,UAAU,EAAE,SAAS;AAAA,IACvB,CAAC;AAED,YAAQ,SAAS;AAGjB,UAAM,SAAS,MAAM,KAAK,OAAO,SAAS,QAAQ,IAAI,QAAQ,MAAM;AAEpE,QAAI,OAAO,SAAS;AAClB,cAAQ,SAAS;AACjB,WAAK,cAAc,QAAQ;AAE3B,YAAM,KAAK,SAAS,IAAI;AAAA,QACtB,QAAQ;AAAA,QACR,YAAY;AAAA,QACZ,MAAM,KAAK,OAAO;AAAA,QAClB,IAAI,QAAQ;AAAA,QACZ,QAAQ,QAAQ;AAAA,QAChB,SAAS,OAAO;AAAA,QAChB,QAAQ,QAAQ;AAAA,QAChB,WAAW,QAAQ;AAAA,QACnB,UAAU,EAAE,aAAa,SAAS;AAAA,MACpC,CAAC;AAAA,IACH,OAAO;AACL,YAAM,KAAK,SAAS,IAAI;AAAA,QACtB,QAAQ;AAAA,QACR,YAAY;AAAA,QACZ,UAAU,EAAE,OAAO,OAAO,MAAM;AAAA,MAClC,CAAC;AAAA,IACH;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,OAAO,WAAmB,UAAkB,QAAgC;AAChF,UAAM,UAAU,KAAK,iBAAiB,IAAI,SAAS;AACnD,QAAI,CAAC,SAAS;AACZ,YAAM,IAAI,MAAM,+BAA+B,SAAS,EAAE;AAAA,IAC5D;AAEA,YAAQ,SAAS;AAEjB,UAAM,KAAK,SAAS,IAAI;AAAA,MACtB,QAAQ;AAAA,MACR,YAAY;AAAA,MACZ,UAAU,EAAE,aAAa,UAAU,OAAO;AAAA,IAC5C,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,eAAe,SAAiB,SAAgC;AACpE,UAAM,OAAO,QAAQ,YAAY;AACjC,SAAK,UAAU,IAAI,IAAI;AAEvB,UAAM,KAAK,SAAS,IAAI;AAAA,MACtB,QAAQ;AAAA,MACR,YAAY,MAAM,KAAK,IAAI,CAAC;AAAA,MAC5B,IAAI;AAAA,MACJ,UAAU,EAAE,UAAU,QAAQ;AAAA,IAChC,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,oBAAoB,SAAiB,WAAkC;AAC3E,UAAM,OAAO,QAAQ,YAAY;AACjC,SAAK,UAAU,OAAO,IAAI;AAE1B,UAAM,KAAK,SAAS,IAAI;AAAA,MACtB,QAAQ;AAAA,MACR,YAAY,MAAM,KAAK,IAAI,CAAC;AAAA,MAC5B,IAAI;AAAA,MACJ,UAAU,EAAE,YAAY,UAAU;AAAA,IACpC,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,cAAc,SAA0B;AACtC,WAAO,KAAK,UAAU,IAAI,QAAQ,YAAY,CAAC;AAAA,EACjD;AAAA;AAAA;AAAA;AAAA,EAKA,sBAAyC;AACvC,WAAO,MAAM,KAAK,KAAK,iBAAiB,OAAO,CAAC,EAC7C,OAAO,OAAK,EAAE,WAAW,SAAS;AAAA,EACvC;AAAA;AAAA;AAAA;AAAA,EAKA,YAA4B;AAC1B,WAAO,EAAE,GAAG,KAAK,OAAO;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA,EAKA,eAAuB;AACrB,SAAK,iBAAiB;AACtB,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKQ,mBAAyB;AAC/B,UAAM,SAAQ,oBAAI,KAAK,GAAE,YAAY,EAAE,MAAM,GAAG,EAAE;AAClD,QAAI,KAAK,cAAc,OAAO;AAC5B,WAAK,YAAY;AACjB,WAAK,aAAa;AAAA,IACpB;AAAA,EACF;AACF;","names":[]}