You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Uniswap V3程序化兑换主网交易失败问题求助

主网Uniswap V3交易失败的修复方案

1. 修正Provider配置

代码中仍在使用测试网的环境变量INFURA_URL_TESTNET,即使你修改了该变量的值为主网地址,也建议直接改为主网专属变量避免混淆:

// 替换为你的主网INFURA地址变量
const INFURA_URL_MAINNET = process.env.INFURA_URL_MAINNET
const provider = new ethers.providers.JsonRpcProvider(INFURA_URL_MAINNET)

2. 确保代币地址完全替换为主网地址

代码中当前的address0和address1仍是Goerli测试网地址,必须替换为你给出的主网地址:

// 主网WETH
const address0 = '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2'
// 主网DAI
const address1 = '0x6B175474E89094C44Da98b954EedeAC495271d0F'

3. 修复滑点设置(关键)

将amountOutMinimum设为0在主网几乎必然失败——MEV机器人或价格波动会导致交易因滑点超限被回滚。需要基于当前池的价格计算合理的最小输出值:

// 在获取poolState后添加以下代码计算最小输出
const tokenInContract = new ethers.Contract(immutables.token1, ERC20ABI, provider)
const tokenOutContract = new ethers.Contract(immutables.token0, ERC20ABI, provider)

// 通过sqrtPriceX96计算当前价格
const sqrtPrice = ethers.BigNumber.from(state.sqrtPriceX96)
const price = sqrtPrice.mul(sqrtPrice).div(ethers.BigNumber.from(2).pow(192))
const amountOut = amountIn.mul(price).div(ethers.BigNumber.from(10).pow(decimals1 - decimals0))

// 设置1%滑点(可根据需求调整)
const slippage = 10 // 1% = 10/1000
const amountOutMinimum = amountOut.sub(amountOut.mul(slippage).div(1000))

然后将params中的amountOutMinimum替换为这个变量:

const params = {
    // ...其他参数
    amountOutMinimum: amountOutMinimum,
    // ...
}

4. 动态预估Gas Limit

硬编码gasLimit: 1000000在主网可能不足,建议用estimateGas预估实际需要的gas并预留缓冲:

// 先预估gas
const gasLimit = await swapRouterContract.connect(connectedWallet).estimateGas.exactInputSingle(params)

// 执行交易时使用预估值并加10%缓冲
const transaction = swapRouterContract.connect(connectedWallet).exactInputSingle(
    params,
    {
        gasLimit: gasLimit.mul(110).div(100)
    }
).then(transaction => {
    console.log(transaction)
})

5. 检查并完成代币授权

主网中必须确保你的钱包已经授权SwapRouter花费你的WETH(tokenIn)。可以添加授权函数:

async function approveToken(tokenAddress, spenderAddress, amount, wallet) {
    const tokenContract = new ethers.Contract(tokenAddress, ERC20ABI, wallet)
    const allowance = await tokenContract.allowance(wallet.address, spenderAddress)
    if (allowance.lt(amount)) {
        const tx = await tokenContract.approve(spenderAddress, ethers.constants.MaxUint256)
        await tx.wait()
        console.log('授权完成')
    }
}

在buy函数中创建swapRouterContract后调用:

await approveToken(immutables.token1, swapRouterAddress, amountIn, connectedWallet)

6. 验证Pool地址正确性

确保getPool返回的是主网WETH/DAI 0.05% fee的池地址(主网该池地址为0x8ad599c3A0ff1De082011EFDDc58f1908eb6e6D8),手动对比确认,避免因代币顺序或fee参数错误导致获取到不存在的池。


内容的提问来源于stack exchange,提问作者Kenikik

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 19:31:01