diff --git a/contracts/NonfungiblePositionManagerV4.sol b/contracts/NonfungiblePositionManagerV4.sol index 587beb43..c23464bf 100644 --- a/contracts/NonfungiblePositionManagerV4.sol +++ b/contracts/NonfungiblePositionManagerV4.sol @@ -6,7 +6,7 @@ import {ERC721} from "@openzeppelin/contracts/token/ERC721/ERC721.sol"; import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol"; import {PoolKey} from "@uniswap/v4-core/contracts/types/PoolKey.sol"; import {IPoolManager, PoolManager} from "@uniswap/v4-core/contracts/PoolManager.sol"; -import {Currency} from "@uniswap/v4-core/contracts/types/Currency.sol"; +import {Currency, CurrencyLibrary} from "@uniswap/v4-core/contracts/types/Currency.sol"; import {BalanceDelta} from "@uniswap/v4-core/contracts/types/BalanceDelta.sol"; import {TickMath} from "@uniswap/v4-core/contracts/libraries/TickMath.sol"; import {PoolId, PoolIdLibrary} from "@uniswap/v4-core/contracts/types/PoolId.sol"; @@ -27,6 +27,7 @@ contract NonfungiblePositionManagerV4 is Multicall { using PoolIdLibrary for PoolKey; + using CurrencyLibrary for Currency; IPoolManager public immutable poolManager; @@ -124,8 +125,32 @@ contract NonfungiblePositionManagerV4 is ); } + function settleDeltas(address from, PoolKey memory poolKey, BalanceDelta delta) internal { + if (delta.amount0() > 0) { + pay(poolKey.currency0, from, address(poolManager), uint256(int256(delta.amount0()))); + poolManager.settle(poolKey.currency0); + } else if (delta.amount0() < 0) { + poolManager.take(poolKey.currency0, address(this), uint128(-delta.amount0())); + } + + if (delta.amount1() > 0) { + pay(poolKey.currency0, from, address(poolManager), uint256(int256(delta.amount1()))); + poolManager.settle(poolKey.currency1); + } else if (delta.amount1() < 0) { + poolManager.take(poolKey.currency1, address(this), uint128(-delta.amount1())); + } + } + function lockAcquired(bytes calldata rawData) external returns (bytes memory) { - // TODO: implement this + require(msg.sender == address(poolManager)); + + CallbackData memory data = abi.decode(rawData, (CallbackData)); + if (data.callbackAction == CallbackAction.Mint) { + MintParams memory params = abi.decode(data.params, (MintParams)); + (uint256 tokenId, uint128 liquidity, BalanceDelta delta) = mintCallback(params); + settleDeltas(data.sender, params.poolKey, delta); + return abi.encode(tokenId, liquidity, delta.amount0(), delta.amount1()); + } } /// @inheritdoc INonfungiblePositionManagerV4 @@ -144,7 +169,29 @@ contract NonfungiblePositionManagerV4 is checkDeadline(params.deadline) returns (uint256 tokenId, uint128 liquidity, uint256 amount0, uint256 amount1) { - poolManager.lock(abi.encode(CallbackData(CallbackAction.Mint, msg.sender, abi.encode(params)))); + (tokenId, liquidity, amount0, amount1) = + poolManager.lock(abi.encode(CallbackData(CallbackAction.Mint, msg.sender, abi.encode(params)))); + } + + function mintCallback(MintParams calldata params) + internal + returns (uint256 tokenId, uint128 liquidity, BalanceDelta delta) + { + PoolId poolId = params.poolKey.toId(); + (liquidity, delta) = addLiquidity( + AddLiquidityParams({ + poolKey: params.poolKey, + tickLower: params.tickLower, + tickUpper: params.tickUpper, + amount0Desired: params.amount0Desired, + amount1Desired: params.amount1Desired, + amount0Min: params.amount0Min, + amount1Min: params.amount1Min + }) + ); + + tokenId = _nextId++; + _mint(tokenId); } modifier isAuthorizedForToken(uint256 tokenId) { @@ -235,7 +282,7 @@ contract NonfungiblePositionManagerV4 is } /// @notice Add liquidity to an initialized pool - function _addLiquidity(AddLiquidityParams memory params) internal returns (uint128 liquidity, BalanceDelta delta) { + function addLiquidity(AddLiquidityParams memory params) internal returns (uint128 liquidity, BalanceDelta delta) { (uint160 sqrtPriceX96,,,) = poolManager.getSlot0(params.poolKey.toId()); uint160 sqrtRatioAX96 = TickMath.getSqrtRatioAtTick(params.tickLower); uint160 sqrtRatioBX96 = TickMath.getSqrtRatioAtTick(params.tickUpper);