使用ethers.js调用Uniswap V3 exactInput()交易失败求助
Uniswap V3 exactInput 交易失败排查与修复
问题根源分析
结合你提供的交易记录和代码,导致兑换失败的核心问题及次要问题如下:
1. 缺失ERC20授权(最关键)
Uniswap Router合约需要获得你钱包中WETH的转移权限才能完成兑换操作,但你的代码完全没有执行WETH的approve授权步骤,这是交易失败的直接原因。
2. 异步处理错误
tx.wait()是异步操作,你没有添加await关键字,导致无法正确获取交易回执,也无法确认交易是否成功。
3. 冗余交易参数
txArg中的from字段无需手动指定,signer.sendTransaction会自动使用签名者的地址作为交易发起方。
修复后的完整代码
const {abi: V3SwapRouterABI} = require('@uniswap/v3-periphery/artifacts/contracts/interfaces/ISwapRouter.sol/ISwapRouter.json') const {abi: ERC20ABI} = require('@openzeppelin/contracts/build/contracts/ERC20.json') const { ethers } = require("ethers") require("dotenv").config() const INFURA_URL_TESTNET = process.env.INFURA_URL_TESTNET const PRIVATE_KEY = process.env.PRIVATE_KEY const WALLET_ADDRESS = process.env.WALLET_ADDRESS const wethToken= "0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6" const Uni= "0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984" const UniswapRouter="0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45" const provider = new ethers.providers.JsonRpcProvider(INFURA_URL_TESTNET) const wallet = new ethers.Wallet(PRIVATE_KEY) const signer = wallet.connect(provider) // 初始化WETH合约实例用于授权 const wethContract = new ethers.Contract(wethToken, ERC20ABI, signer) const UniV3Contract = new ethers.Contract(UniswapRouter, V3SwapRouterABI, signer) const FEE_SIZE = 3 function encodePath(path, fees) { if (path.length != fees.length + 1) { throw new Error('path/fee lengths do not match') } let encoded = '0x' for (let i = 0; i < fees.length; i++) { encoded += path[i].slice(2) encoded += fees[i].toString(16).padStart(2 * FEE_SIZE, '0') } encoded += path[path.length - 1].slice(2) return encoded } async function getToken() { const amountIn = ethers.utils.parseEther('0.01') // 前置步骤:授权Router合约转移指定数量的WETH const approveTx = await wethContract.approve(UniswapRouter, amountIn) await approveTx.wait() console.log('授权完成,交易哈希:', approveTx.hash) const path = encodePath([wethToken, Uni], [3000]) const deadline = Math.floor(Date.now()/1000) + (60*10) const params = { path: path, recipient: WALLET_ADDRESS, deadline: deadline, amountIn: amountIn, amountOutMinimum: 0 } // 直接通过合约实例调用exactInput,无需手动编码函数数据 const tx = await UniV3Contract.exactInput(params, { gasLimit: ethers.utils.hexlify(1000000) }) console.log('兑换交易哈希:', tx.hash) const receipt = await tx.wait() console.log('交易完成,回执:', receipt) } module.exports = { getToken }
关键修复说明
- 添加ERC20授权:调用WETH合约的
approve方法,允许Router合约转移你指定数量的WETH,这是所有ERC20代币兑换的必要前置操作 - 简化交易调用:直接使用合约实例的
exactInput方法发起交易,避免手动编码函数数据的出错风险 - 修复异步逻辑:给
tx.wait()添加await,确保获取完整的交易回执 - 移除冗余参数:删除不必要的
from字段,由签名者自动处理交易发起方
额外建议
- 不要设置
amountOutMinimum: 0,这会让你完全暴露在滑点风险中,建议通过Uniswap Quoter合约查询当前行情下的合理最小输出量后再设置 - 可根据实际情况调整
gasLimit,避免设置过大造成Gas浪费或过小导致交易失败
内容的提问来源于stack exchange,提问作者Oriok
相关产品推荐
相关产品推荐

