Base Layer2网络Uniswap V3+ethers.js代币兑换执行回滚问题
问题分析与修复方案
你遇到的合约执行回滚问题,主要是代码里的几个错误导致的,下面是具体修复点和修正后的代码:
关键错误点
- swap参数错误:
exactInputSingle的参数结构中不存在nounce(拼写也错误,应为nonce),交易的nonce是放在交易选项里,而非swap函数参数中,多余的参数会直接导致合约调用失败。 - amountIn硬编码不匹配:你已经计算了
amountIn变量,却使用硬编码的十六进制值,可能导致实际输入金额和授权金额不匹配。 - Gas设置不符合Base网络规范:Base Layer2采用EIP-1559计费模式,使用
gasPrice会引发兼容性问题,应改用maxFeePerGas和maxPriorityFeePerGas。 - 未等待授权交易确认:授权交易提交后直接执行swap,可能授权还未上链生效,导致合约检测不到足够的授权额度。
修正后的完整代码
import { getPoolImmutables, getPoolState } from './utils'; const { ethers } = require('ethers'); const { abi: IUniswapV3PoolABI } = require('@uniswap/v3-core/artifacts/contracts/interfaces/IUniswapV3Pool.sol/IUniswapV3Pool.json'); const SwapRouterABI = require('./routerabi.json'); const ERC20ABI = require('./abi.json'); const QUICKNODE_HTTP_ENDPOINT = 'https://sepolia.base.org'; const WALLET_ADDRESS = ''; // 填入你的钱包地址 const WALLET_SECRET = ''; // 填入你的钱包私钥 const provider = new ethers.providers.JsonRpcProvider(QUICKNODE_HTTP_ENDPOINT); const poolAddress = '0x7516D071921973fDFf29C071f42d21C227CF5740'; const swapRouterAddress = '0x050E797f3625EC8785265e1d9BDd4799b97528A1'; async function main() { try { const poolContract = new ethers.Contract(poolAddress, IUniswapV3PoolABI, provider); const immutables = await getPoolImmutables(poolContract); const state = await getPoolState(poolContract); const wallet = new ethers.Wallet(WALLET_SECRET); const connectedWallet = wallet.connect(provider); const swapRouterContract = new ethers.Contract(swapRouterAddress, SwapRouterABI, connectedWallet); const inputAmount = 0.09; const amountIn = ethers.utils.parseUnits(inputAmount.toString(), 18); const approvalAmount = amountIn.mul(10); // 用ethers的BigNumber运算,避免字符串转换错误 const tokenContract0 = new ethers.Contract(immutables.token1, ERC20ABI, connectedWallet); // 提交授权交易并等待确认 const approvalResponse = await tokenContract0.approve(swapRouterAddress, approvalAmount); await approvalResponse.wait(); console.log('授权交易已确认,交易哈希:', approvalResponse.hash); // 构建正确的swap参数 const params = { tokenIn: immutables.token1, tokenOut: immutables.token0, fee: immutables.fee, recipient: WALLET_ADDRESS, deadline: Math.floor(Date.now() / 1000) + 60 * 10, // 10分钟后过期 amountIn: amountIn, // 使用计算好的变量,而非硬编码 amountOutMinimum: 0, // 测试网可设为0,主网建议计算滑点后的最小值 sqrtPriceLimitX96: 0, // 不限制价格滑点 }; // 获取当前交易nonce,作为交易选项参数 const nonce = await connectedWallet.getTransactionCount(); const transaction = await swapRouterContract.exactInputSingle(params, { gasLimit: ethers.utils.hexlify(1000000), maxFeePerGas: ethers.utils.parseUnits('10', 'gwei'), maxPriorityFeePerGas: ethers.utils.parseUnits('2', 'gwei'), nonce: nonce, }); console.log('Swap交易已提交,交易哈希:', transaction.hash); const receipt = await transaction.wait(); console.log('Swap交易已确认,区块号:', receipt.blockNumber); } catch (error) { console.error('交易失败:', error); } } main();
额外说明
- 关于execute函数:你提到的
execute是Uniswap Router的批量交易函数,用于一次执行多个操作(如swap+添加流动性),单纯的代币兑换使用exactInputSingle是完全正确的,不需要改用execute。 - 滑点控制:主网环境下不要将
amountOutMinimum设为0,建议根据当前池状态计算可接受的最小输出金额,避免因滑点过大导致损失。 - BigNumber运算:ethers.js中处理代币金额时,应使用内置的BigNumber方法(如
mul、div),避免直接用JavaScript的数值运算导致精度丢失。
内容的提问来源于stack exchange,提问作者Ghassane Aboughazaouat
相关产品推荐
相关产品推荐

