使用UniswapV2兑换ETH为WETH时path参数如何配置
Uniswap V2 Router ETH兑换WETH问题修正
Uniswap V2 Router所有涉及原生ETH的兑换函数(包括swapExactETHForTokens、swapETHForExactTokens、swapExactETHForTokensSupportingFeeOnTransferTokens),强制要求path数组的第一个元素必须是部署在对应链上的WETH9合约地址,传0地址会直接触发INVALID_PATH异常回滚交易。
你当前的代码存在3个核心错误:
- 函数选型错误。ETH兑换等额WETH不需要走Uniswap的swap交易流程:WETH是原生ETH的1:1映射资产,兑换无滑点、无手续费,直接调用WETH合约的
deposit()方法,向合约转入对应数量的原生ETH,就会自动得到等量WETH,是成本最低、逻辑最简洁的实现。
硬走Router的swap逻辑兑换WETH无法执行:swap流程要求path至少包含两个不同资产,对应需要两个资产组成的流动池,WETH与WETH之间不存在交易对,合约执行时会直接报错。 - deadline参数逻辑错误。
(await ethers.provider.getBlock('latest').timestamp) * 2的写法完全不符合参数要求:deadline的作用是限制交易最晚打包时间,避免交易长时间停留在内存池被恶意节点打包利用,常规写法是取最新区块时间戳加3001800秒(即530分钟过期)。直接将当前时间戳乘2得到的过期时间在数十年后,等于交易永久有效,存在严重安全风险。 - 金额参数逻辑错误。将地址全部ETH余额同时作为
amountOut(期望获得的目标资产数量)和msg.value(传入的原生ETH数量)传入swapETHForExactTokens无法执行:该函数兑换时会扣除Uniswap 0.3%的交易手续费,传入等额ETH无法兑换到等额目标资产,会触发EXCESSIVE_INPUT_AMOUNT异常回滚。
正确实现代码
推荐方案:直接调用WETH合约存款(ETH换WETH最优解)
// 提前完成WETH合约实例化,deposit为payable方法 const tx = await this.weth.deposit({ value: ethers.utils.parseEther("你要兑换的ETH数量"), // 单位为wei,想换多少ETH就传多少 from: attacker.address }) await tx.wait() // 交易确认后,attacker.address地址下会收到对应数量的WETH
如果你实际需求是通过Uniswap将ETH兑换为其他ERC20代币(而非WETH本身),可参考以下正确写法(以ETH兑换USDC为例):
const latestBlock = await ethers.provider.getBlock('latest') const deadline = latestBlock.timestamp + 300 // 交易5分钟后过期 await this.uniswapRouter.swapExactETHForTokens( ethers.utils.parseUnits("0", 6), // 可根据滑点设置最少获得的USDC数量,填0代表不限制最低到账 [this.weth.address, this.usdc.address], // path首元素固定为WETH地址,后续按兑换顺序填目标资产 attacker.address, deadline, { value: ethers.utils.parseEther("你要花费的ETH数量") } )
内容的提问来源于stack exchange,提问作者JuanXavier
相关产品推荐
相关产品推荐

