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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 11:22:34