本地部署UniswapV3调用mint函数交易回滚问题求助
先查代币授权
调用mint前必须给NonfungiblePositionManager授权足够的代币,授权金额得≥你要存的流动性数量。别光写授权代码,要等授权交易确认再执行mint。排查时直接打印授权余额:console.log(await token.allowance(msg.sender, positionManager.address)),确认数值够不够。核对手续费与池的匹配性
UniswapV3每个池对应唯一手续费等级(0.05%/0.3%/1%),mint传的fee参数必须和已部署池的手续费一致,不然找不到池直接回滚。调用UniswapV3Factory.getPool(token0, token1, fee)看返回的池地址是不是零地址,零地址就是池没建对。检查价格区间参数
tickLower必须小于tickUpper,而且不能超出池允许的tick范围(一般是-887272到887272)。另外最好让这个区间包含当前池的tick,你可以调用池合约的slot0()拿到当前tick,对比一下你设置的区间合不合理。确认账户余额够不够
发起mint的账户得有足够的token0和token1,余额要≥amount0Desired和amount1Desired的数值,不然转账失败直接回滚。打印账户余额看看:console.log(await token0.balanceOf(msg.sender), await token1.balanceOf(msg.sender))。核对本地链合约地址
本地链部署后,把测试代码里用到的Factory、PositionManager、池、代币的地址,和部署日志里的地址逐一比对,别搞混了地址,地址错了肯定执行失败。开调试日志定位
要么在Hardhat配置里开调试,要么给合约加console.log(记得导入hardhat/console.sol),在mint的关键步骤比如池检查、授权验证的地方加日志,看具体在哪一步回滚。也可以给mint交易加gas限制:await positionManager.mint(params, { gasLimit: 1000000 }),开启gas追踪看执行细节。
测试代码片段
// 示例测试代码 describe("UniswapV3 Liquidity Test", () => { let token0, token1, factory, positionManager, pool; beforeEach(async () => { const Token = await ethers.getContractFactory("ERC20Mock"); token0 = await Token.deploy("Token0", "T0", ethers.utils.parseEther("10000")); token1 = await Token.deploy("Token1", "T1", ethers.utils.parseEther("10000")); // 确保token0地址更小 if (token0.address > token1.address) [token0, token1] = [token1, token0]; // 部署Factory、PositionManager等合约逻辑 // ... }); it("should mint position", async () => { const [owner] = await ethers.getSigners(); // 授权代币给PositionManager await token0.approve(positionManager.address, ethers.utils.parseEther("100")); await token1.approve(positionManager.address, ethers.utils.parseEther("100")); const mintParams = { token0: token0.address, token1: token1.address, fee: 3000, // 对应0.3%手续费池 tickLower: -60, tickUpper: 60, amount0Desired: ethers.utils.parseEther("10"), amount1Desired: ethers.utils.parseEther("10"), amount0Min: 0, amount1Min: 0, recipient: owner.address, deadline: Math.floor(Date.now() / 1000) + 3600 }; const tx = await positionManager.mint(mintParams); await tx.wait(); }); });
控制台输出
Error: Transaction reverted without a reason string at NonfungiblePositionManager.mint (contracts/NonfungiblePositionManager.sol:123) at processTicksAndRejections (node:internal/process/task_queues:95:5) at HardhatNode._mineBlockWithPendingTxs (node_modules/hardhat/src/internal/hardhat-network/provider/node.ts:1802:23) at HardhatNode.mineBlock (node_modules/hardhat/src/internal/hardhat-network/provider/node.ts:491:16) at EthModule._sendTransactionAndReturnHash (node_modules/hardhat/src/internal/hardhat-network/provider/modules/eth.ts:1522:18)
内容的提问来源于stack exchange,提问作者Adam d3t

