UniSwapV3 Mint新仓位返回值异常及Tick影响问题求助
Uniswap V3 仓位铸造与池初始化问题排查
我正在开发一个调用Uniswap V3合约的项目,已经查阅白皮书、官方文档及各类公开资料但仍无法解决问题,特此求助——不仅希望解决问题本身,更想厘清文档中的遗漏点。
一、池初始化与mint()的困惑
调用mint()创建新仓位时,函数注释如下:
/// @notice Creates a new position wrapped in a NFT /// @dev Call this when the pool does exist and is initialized. Note that if the pool is created but not initialized /// a method does not exist, i.e. the pool is assumed to be initialized. /// @param params The params necessary to mint a position, encoded as `MintParams` in calldata /// @return tokenId The ID of the token that represents the minted position /// @return liquidity The amount of liquidity for this position /// @return amount0 The amount of token0 /// @return amount1 The amount of token1 function mint(MintParams calldata params) external payable returns ( uint256 tokenId, uint128 liquidity, uint256 amount0, uint256 amount1 );
但官方文档未提及池的初始化方法,我参考GitHub项目实现了池初始化:
// Creates the new pool pool = IUniswapV3Pool( v3Factory.createPool(address(token0), address(token1), fee) ); /* Calculates the initial price (in sqrtPriceX96 format) sqrtPriceX96 = sqrt(price) * 2 ** 96 */ // 设置价格为 1000 token0 = 1 token1 uint160 sqrtPriceX96 = encodePriceSqrt(1, 1000); pool.initialize(sqrtPriceX96);
二、实际执行结果与预期不符
我的目标是存入n ETH和m MING,实现代码如下:
pool = IUniswapV3Pool( v3Factory.createPool(Address.WETH, addressOfMing, fee) ); // 测试用例:仅1:1比例时符合预期 // uint160 sqrtPriceX96 = encodePriceSqrt(1, 1); uint160 sqrtPriceX96 = encodePriceSqrt(amountOfMing, amountOfETH); pool.initialize(sqrtPriceX96); tickSpacing = pool.tickSpacing(); (uint256 _tokenId, , , ) = mintNewPosition(amountOfETH, amountOfMing);
mintNewPosition()的实现:
IERC20 ming = IERC20(addressOfMing); console.log("amount to mint new position: %s -> %s", amountOfETH, amountOfMing); require( ming.balanceOf(address(this)) >= amountOfMing, "insufficient Ming" ); require( weth.balanceOf(address(this)) >= amountOfETH, "insufficient WETH" ); // 授权给仓位管理器 TransferHelper.safeApprove(Address.WETH, address(nonfungiblePositionManager), amountOfETH); TransferHelper.safeApprove(addressOfMing, address(nonfungiblePositionManager), amountOfMing); // 获取tick间隔 (, int24 curTick, , , , , ) = pool.slot0(); curTick = curTick - (curTick % tickSpacing); int24 lowerTick = curTick - (tickSpacing * 2); int24 upperTick = curTick + (tickSpacing * 2); require(curTick % tickSpacing == 0, 'tick error'); INonfungiblePositionManager.MintParams memory params = INonfungiblePositionManager.MintParams({ token0: pool.token0(), token1: pool.token1(), fee: poolFee, tickLower: lowerTick, tickUpper: upperTick, amount0Desired: amountOfETH, amount1Desired: amountOfMing, amount0Min: 0, amount1Min: 0, recipient: address(this), deadline: block.timestamp }); // 注意:DAI/USDC 0.3%费率的池必须已创建并初始化才能铸造仓位 (tokenId, liquidity, amount0, amount1) = nonfungiblePositionManager.mint(params); console.log("new position minted: %s, %s", amount0, amount1);
我的理解:调用pool.initialize(sqrtPriceX96)已确定MING对ETH的价格,使用对应token对调用mint()应无滑点,返回的ETH/MING数量应与存入一致,但实际结果为:
amount to mint new position: 3000000000000000000 -> 222222222222222000000000000000000 new position minted: 3000000000000000000, 25559352082992436084
我是否存在操作错误?
三、更新尝试后的疑问
我发现PoolAddress库要求key.token0 < key.token1,因此修改了池创建代码:
if(Address.WETH < addressOfMing){ console.log("init pool"); pool = IUniswapV3Pool( v3Factory.createPool(Address.WETH, addressOfMing, fee) ); uint160 sqrtPriceX96 = encodePriceSqrt(amountOfMing, amountOfETH); pool.initialize(sqrtPriceX96); tickSpacing = pool.tickSpacing(); (uint256 _tokenId, , , ) = mintNewPosition(amountOfETH, amountOfMing); tokenId = _tokenId; }else{ console.log("init pool reversed"); pool = IUniswapV3Pool( v3Factory.createPool(addressOfMing, Address.WETH, fee) ); uint160 sqrtPriceX96 = encodePriceSqrt(amountOfETH, amountOfMing); pool.initialize(sqrtPriceX96); tickSpacing = pool.tickSpacing(); (uint256 _tokenId, , , ) = mintNewPosition(amountOfMing, amountOfETH); tokenId = _tokenId; }
问题仍存在,但将lowerTick和upperTick扩大1000倍后:
int24 lowerTick = curTick - (tickSpacing * 1000); int24 upperTick = curTick + (tickSpacing * 1000);
结果更接近预期:
amount to mint new position 222222222222222000000000000000000, 3000000000000000000 new position minted -> 222222222222221995864146677687271, 2999106664470400961
但仍不符合预期:按理解,池初始化已确定价格,给定对应token对时,Tick范围不应大幅影响存入的token数量,请问问题出在哪里?
内容的提问来源于stack exchange,提问作者shinado
相关产品推荐
相关产品推荐

