UniSwapV3 铸币新仓位返回意想不到的价值

问题描述 投票:0回答:2

我正在开发一个名为 UniSwap V3 合约的项目。我已经阅读了白皮书、文档以及网上能找到的所有内容来解决这个问题,但一无所获。所以我来这里寻求帮助,不仅是为了解决问题本身,也是为了充分理解我在文档中遗漏的地方。

首先是初始化池。当我尝试创建一个新位置时,我发现函数 min() 上的注释指出:

    /// @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)
            https://docs.uniswap.org/sdk/guides/fetching-prices
            sqrtPriceX96 = sqrt(price) * 2 ** 96
        */
        // Lets set the price to be 1000 token0 = 1 token1
        uint160 sqrtPriceX96 = encodePriceSqrt(1, 1000);
        pool.initialize(sqrtPriceX96);

但是,当我使用这段代码来初始化池时,它从未按预期运行。我会解释如何做。

预期功能是将一对 n ETH 和 m MING 发送到 Uniswap。以下是我的实现方法:

pool = IUniswapV3Pool(
                v3Factory.createPool(Address.WETH, addressOfMing, fee)
            );


            // for testing purpose 
            // only 1 to 1 worked. 
            // 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"
        );


        // Approve the position manager
        TransferHelper.safeApprove(Address.WETH, address(nonfungiblePositionManager), amountOfETH);
        TransferHelper.safeApprove(addressOfMing, address(nonfungiblePositionManager), amountOfMing);


        // Get tick spacing
        (, 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
            });


        // Note that the pool defined by DAI/USDC and fee tier 0.3% must already be 
        // created and initialized in order to mint
        (tokenId, liquidity, amount0, amount1) = nonfungiblePositionManager.mint(params);
        console.log("new position minted: %s, %s", amount0, amount1);

据我了解,当我调用 pool.initialize(sqrtPriceX96) 时,它决定了 MING 对于 ETH 的价格。因此,在使用相同数量的 ETH/MING 对调用 mint() 时,返回的 ETH/MING 数量应该相同,因为在此过程中没有滑点。

但是,这就是我得到的:

amount to mint new position: 3000000000000000000 -> 222222222222222000000000000000000
new position minted:         3000000000000000000, 25559352082992436084

我做错了什么吗?

----------------------------------------更新1--------------------- ---- 我在库 PoolAddress 中找到: require(key.token0 < key.token1) therefore I edited the following code in the pool creation:

            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 增加 1000x

int24 lowerTick = curTick - (tickSpacing * 1000); 
int24 upperTick = curTick + (tickSpacing * 1000);

我得到了比预期更好的结果。

amount to mint new position 222222222222222000000000000000000, 3000000000000000000
    new position minted ->  222222222222221995864146677687271, 2999106664470400961

然而,它并没有按预期工作。只要价格在池初始化时确定,通过提供相同数量的代币对,上限和下限不应(极大)影响添加到流动性中的代币数量。

solidity contract uniswap
2个回答
0
投票

我和你有同样的问题,我必须根据你的发现自己编写代码才能找到初始价格

我已经用solidity编写了它,所以你可能需要在js中重新实现它以供你使用

// src/library/UniswapV3PricingHelper.sol

library UniswapV3PricingHelper {
    uint256 private constant padding = 100;
    // Constants
    uint256 private constant Q96 = 2 ** 96;

    function _sortTokens(
        address _tokenA,
        address _tokenB
    ) internal pure returns (address _sortedTokenA, address _sortedTokenB) {
        require(_tokenA != address(0) && _tokenB != address(0), "Token addresses cannot be zero.");

        // Sort the token addresses
        (_sortedTokenA, _sortedTokenB) = _tokenA < _tokenB ? (_tokenA, _tokenB) : (_tokenB, _tokenA);
    }

    function getInitPrice(
        address _tokenBase,
        address _tokenSwap,
        uint256 tokenBaseAmt,
        uint256 tokenSwapAmt
    ) internal pure returns (address token0, address token1, uint160 initSQRTPrice) {
        (token0, token1) = _sortTokens(_tokenBase, _tokenSwap);
        if (token0 != _tokenBase) initSQRTPrice = encodePriceSqrt(tokenSwapAmt, tokenBaseAmt);
        else initSQRTPrice = encodePriceSqrt(tokenBaseAmt, tokenSwapAmt);
    }

    // Encode price square root function
    function encodePriceSqrt(uint256 reserve0, uint256 reserve1) public pure returns (uint160 sqrtPriceX96) {
        require(reserve0 > 0 && reserve1 > 0, "Reserves must be positive");
        uint256 ratio = Math.sqrt(((reserve1 * padding) / reserve0) / padding) * Q96;
        sqrtPriceX96 = uint160(ratio);
    }
}

在我的库中,_tokenbase 是基础资产,在我的例子中,它是 WETH,tokenSwap 是你想要与 weth 配对的代币,比如说 dai、usdc 或其他东西

此代码假设基础代币和交换代币均为 18 位小数,您需要处理任一代币低于 18 位小数的情况,并可能对金额进行四舍五入


0
投票

@shinado 我正在经历一些与 UniswapV3 类似的问题,在尝试建立仓位时不断出现气体估计错误,想知道您是否可以在这里为我提供任何指导?

对我的 addliq() 函数的气体估计错误感到困惑

© www.soinside.com 2019 - 2024. All rights reserved.