使用ethers.js在Uniswap V3兑换时遇RPC执行回滚错误求助
问题:Uniswap V3 Router兑换无MetaMask弹窗且执行回滚(Polygon网络+ethers.js)
问题现象
- USDC授权已在MetaMask确认成功,但兑换步骤无签名弹窗
- 控制台报错:
inpage.js:1 MetaMask - RPC Error: Internal JSON-RPC error. code: -32603 data: code: -32000 message: "execution reverted"
代码片段
const provider = new ethers.providers.Web3Provider(window.ethereum); const send_account = await provider.getSigner().getAddress(); //my address //Swap from USDC to MTS or any other token addressOfUSDC='0x2791bca1f2de4661ed88a30c99a7a9449aa84174' // Address of USDC in Polygon const ERC20Contract = new ethers.Contract(addressOfUSDC, ERC20ABI, provider); swapRouterAddress="0xe592427a0aece92de3edee1f18e0157c05861564"; //Uniswap v3 router indadr="0x440416D85E5D51424da371297E3d7Ef28312BF62"; //Any token address to which I want to swap approvalAmount=12; //12 USDC await ERC20Contract .connect(provider.getSigner()) .approve(swapRouterAddress, approvalAmount*1000000) //After this step we see confirmation to spend 12$ in metamask bn=ethers.BigNumber.from(approvalAmount*1000000); //BigNumber from approvalAmount const params = { tokenIn: addressOfUSDC, tokenOut: indadr, fee: ethers.BigNumber.from(3000), recipient: send_account, deadline: ethers.BigNumber.from(Math.floor(Date.now() / 1000) + (60 * 10)), amountIn: bn, amountOutMinimum: ethers.BigNumber.from(0), sqrtPriceLimitX96: ethers.BigNumber.from(0), } const UniswapContract= new ethers.Contract(swapRouterAddress, ERC20ABI2, provider); dd=await UniswapContract .connect(provider.getSigner()) .exactInputSingle(params) console.log(dd);
已排查操作
- 更换过ABI文件
- 验证过Uniswap Router地址正确性
- 尝试过Uniswap V2的
swapExactTokensForTokens函数,问题依旧
核心修复点
1. 替换Uniswap Router的ABI(最关键)
你用ERC20ABI2初始化Uniswap V3 Router合约是错误的——Router的ABI和ERC20完全不同,错误的ABI会导致合约调用直接回滚,甚至不触发MetaMask签名请求。
- 解决:从PolygonScan导出
0xe592427a0aece92de3edee1f18e0157c05861564的官方ABI,或使用Uniswap SDK提供的Router ABI。
2. 修正参数格式
fee参数无需用ethers.BigNumber.from转换,直接传入数字3000(对应0.3%手续费,是Uniswap V3的合法档位)- 金额计算建议用
ethers.utils.parseUnits避免浮点数精度问题:// 替代原来的bn=ethers.BigNumber.from(approvalAmount*1000000) const amountIn = ethers.utils.parseUnits(approvalAmount.toString(), 6); // USDC是6位小数 deadline直接计算为数字即可,ethers会自动处理为BigNumber:deadline: Math.floor(Date.now() / 1000) + 600 // 10分钟有效期
3. 检查授权与网络
- 确认授权金额足够:调用
ERC20Contract.allowance(send_account, swapRouterAddress)查看剩余授权额度,确保≥兑换金额 - 确认MetaMask当前网络为Polygon(ChainID 137),避免跨网络调用
修复后示例代码片段
const provider = new ethers.providers.Web3Provider(window.ethereum); const signer = provider.getSigner(); const send_account = await signer.getAddress(); // 常量定义 const addressOfUSDC = '0x2791bca1f2de4661ed88a30c99a7a9449aa84174'; const swapRouterAddress = '0xe592427a0aece92de3edee1f18e0157c05861564'; const indadr = '0x440416D85E5D51424da371297E3d7Ef28312BF62'; const approvalAmount = 12; // USDC授权 const ERC20Contract = new ethers.Contract(addressOfUSDC, ERC20ABI, signer); const approveTx = await ERC20Contract.approve(swapRouterAddress, ethers.utils.parseUnits(approvalAmount.toString(), 6)); await approveTx.wait(); console.log("授权完成"); // 初始化Uniswap Router合约(使用正确ABI) const UNISWAP_V3_ROUTER_ABI = [/* 填入正确的Router ABI */]; const UniswapContract = new ethers.Contract(swapRouterAddress, UNISWAP_V3_ROUTER_ABI, signer); // 兑换参数 const params = { tokenIn: addressOfUSDC, tokenOut: indadr, fee: 3000, recipient: send_account, deadline: Math.floor(Date.now() / 1000) + 600, amountIn: ethers.utils.parseUnits(approvalAmount.toString(), 6), amountOutMinimum: ethers.BigNumber.from(0), sqrtPriceLimitX96: ethers.BigNumber.from(0), }; // 执行兑换 const swapTx = await UniswapContract.exactInputSingle(params); await swapTx.wait(); console.log("兑换完成,交易哈希:", swapTx.hash);
内容的提问来源于stack exchange,提问作者Jay
相关产品推荐
相关产品推荐

