Nuclear_Man_D icon

Broken createPosition implementation for uniswapv4

Nuclear_Man_D | PRO | 04/19/25 10:48:59 PM UTC | 0 ⭐ | 12952 👁️ | Never ⏰ | [create, Uniswap, liquidity, uniswapv4]
JavaScript |

2.72 KB

|

Cryptocurrency

|

0 👍

/

0 👎

 
    function _createPosition2(PoolKey calldata key, uint160 sqrtRatioX96, uint160 sqrtRatioAX96, uint160 sqrtRatioBX96, uint128 liquidity) internal {
 
        // Calculate amounts of each token
        // I can't use LiquidityAmounts.getAmountsForLiquidity because the function does not exist in the v4
        // library.  See below links, there is a discrepency between the source and the documentation:
        //  https://docs.uniswap.org/contracts/v4/reference/core/libraries/liquidity-amounts
        //  https://github.com/Uniswap/v4-periphery/blob/main/src/libraries/LiquidityAmounts.sol
        // In any case, I included my own implementation in my utils contract:
        //  http://etherscan.io/address/0xC97B6F6DC641C0f59c724657B91569aF00C28B7D
        // It's based on the UniswapV3 code so I'm pretty sure it works fine.
        (uint256 amount0, uint256 amount1) = utils.getAmountsForLiquidity(sqrtRatioX96, sqrtRatioAX96, sqrtRatioBX96, liquidity);
 
        // This function reverts if the amounts of the tokens are less than amount0 and amount1 by the end of the call
        // From this, we can be sure that we have enough of the tokens, assuming that amount0 and amount1 are correct
        obtainTokens(Currency.unwrap(key.currency0), Currency.unwrap(key.currency1), amount0, amount1);
 
        // Grant allowance to the position manager
        if (Currency.unwrap(key.currency0) != address(0)) permit2.approve(Currency.unwrap(key.currency0), address(v4PositionManager), uint160(amount0), 0);
        permit2.approve(Currency.unwrap(key.currency1), address(v4PositionManager), uint160(amount1), 0);
 
        // Based on code from:
        // https://docs.uniswap.org/contracts/v4/quickstart/manage-liquidity/mint-position
        // https://docs.uniswap.org/contracts/v4/guides/position-manager
        bytes memory actions = abi.encodePacked(
            uint8(Actions.MINT_POSITION),
            uint8(Actions.SETTLE_PAIR)
        );
        bytes[] memory params = new bytes[](2);
        unchecked {
            params[0] = abi.encode(
                key,
                (TickMath.getTickAtSqrtPrice(sqrtRatioAX96) / key.tickSpacing) * key.tickSpacing,
                (TickMath.getTickAtSqrtPrice(sqrtRatioBX96) / key.tickSpacing) * key.tickSpacing,
                (liquidity * 1015) >> 10,  // reduces the inserted liquidity a bit, just in case we barely don't have enough 
                amount0,
                amount1,
                address(this),
                abi.encode(address(this))
            );
        }
        params[1] = abi.encode(key.currency0, key.currency1);
 
        unchecked {
            uint256 deadline = block.timestamp + 60;
            uint256 valueToPass = key.currency0.isAddressZero() ? amount0 : 0;
 
            // Our revert happens inside this call, apparently before SETTLE_PAIR is ever reached:
            v4PositionManager.modifyLiquidities{value: valueToPass}(abi.encode(actions, params), deadline);
        }
    }
 

Comments