Skip to content

Commit

Permalink
move addLiquidity functions to liquiditymanagement
Browse files Browse the repository at this point in the history
  • Loading branch information
tinaszheng committed Nov 29, 2023
1 parent 87e0b2f commit c64e82e
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 60 deletions.
2 changes: 0 additions & 2 deletions contracts/NonfungiblePositionManagerV4.sol
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ contract NonfungiblePositionManagerV4 is
ERC721,
PeripheryImmutableState,
PeripheryValidation,
PeripheryPayments,
LiquidityManagement,
SelfPermit,
Multicall
Expand Down Expand Up @@ -130,7 +129,6 @@ contract NonfungiblePositionManagerV4 is
returns (uint256 tokenId, uint128 liquidity, uint256 amount0, uint256 amount1)
{
// TODO: implement this
// will do something like return mintEntry(params)
}

/// @inheritdoc INonfungiblePositionManagerV4
Expand Down
88 changes: 76 additions & 12 deletions contracts/base/LiquidityManagement.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,33 @@ pragma solidity ^0.8.19;

import {PoolKey} from "@uniswap/v4-core/contracts/types/PoolKey.sol";
import {BalanceDelta} from "@uniswap/v4-core/contracts/types/BalanceDelta.sol";
import {ILockCallback} from "@uniswap/v4-core/contracts/interfaces/callback//ILockCallback.sol";
import {IPeripheryPayments} from "../interfaces/IPeripheryPayments.sol";
import {ILiquidityManagement} from "../interfaces/ILiquidityManagement.sol";
import {ILockCallback} from "@uniswap/v4-core/contracts/interfaces/callback/ILockCallback.sol";
import {TickMath} from "@uniswap/v4-core/contracts/libraries/TickMath.sol";
import {BalanceDelta} from "@uniswap/v4-core/contracts/types/BalanceDelta.sol";
import {IPoolManager} from "@uniswap/v4-core/contracts/interfaces/IPoolManager.sol";
import {Currency, CurrencyLibrary} from "@uniswap/v4-core/contracts/types/Currency.sol";
import {PoolId, PoolIdLibrary} from "@uniswap/v4-core/contracts/types/PoolId.sol";

import {LiquidityAmounts} from "../libraries/LiquidityAmounts.sol";
import {PeripheryImmutableState} from "./PeripheryImmutableState.sol";
import {PeripheryPayments} from "./PeripheryPayments.sol";

/// @title Liquidity management functions
/// @notice Internal functions for safely managing liquidity in Uniswap V4
abstract contract LiquidityManagement is ILockCallback, PeripheryImmutableState, PeripheryPayments {
using CurrencyLibrary for Currency;
using PoolIdLibrary for PoolKey;

error PriceSlippage();

enum CallbackType {AddLiquidity}

struct CallbackData {
CallbackType callbackType;
address sender;
bytes params;
}

abstract contract LiquidityManagement is ILockCallback, ILiquidityManagement, PeripheryImmutableState {
struct AddLiquidityParams {
PoolKey poolKey;
int24 tickLower;
Expand All @@ -20,20 +41,63 @@ abstract contract LiquidityManagement is ILockCallback, ILiquidityManagement, Pe
bytes hookData;
}

function mintEntry(MintParams memory params)
/// @notice Add liquidity to an initialized pool
function addLiquidity(AddLiquidityParams memory params)
internal
returns (uint256 tokenId, uint128 liquidity, BalanceDelta delta)
returns (uint128 liquidity, uint256 amount0, uint256 amount1)
{
// TODO: poolManager.lock call here
(liquidity, amount0, amount1) = abi.decode(
poolManager.lock(abi.encode(CallbackData(CallbackType.AddLiquidity, msg.sender, abi.encode(params)))),
(uint128, uint256, uint256)
);
}

/// @notice Add liquidity to an initialized pool
function addLiquidity(AddLiquidityParams memory params) internal returns (uint128 liquidity, BalanceDelta delta) {
// TODO: copy over addLiquidity helper here
function addLiquidityCallback(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);
liquidity = LiquidityAmounts.getLiquidityForAmounts(
sqrtPriceX96, sqrtRatioAX96, sqrtRatioBX96, params.amount0Desired, params.amount1Desired
);
delta = poolManager.modifyPosition(
params.poolKey,
IPoolManager.ModifyPositionParams(params.tickLower, params.tickUpper, int256(int128(liquidity))),
params.hookData
);
if (
uint256(int256(delta.amount0())) < params.amount0Min || uint256(int256(delta.amount1())) < params.amount1Min
) revert PriceSlippage();
}

function lockAcquired(bytes calldata rawData) external override returns (bytes memory) {
// TODO: handle mint/add/decrease liquidity here
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 data) external override returns (bytes memory) {
CallbackData memory callbackData = abi.decode(data, (CallbackData));
if (callbackData.callbackType == CallbackType.AddLiquidity) {
AddLiquidityParams memory params = abi.decode(callbackData.params, (AddLiquidityParams));
(uint128 liquidity, BalanceDelta delta) = addLiquidityCallback(params);
settleDeltas(callbackData.sender, params.poolKey, delta);
return abi.encode(liquidity, delta.amount0(), delta.amount1());
}

// TODO: handle add/decrease liquidity here
return abi.encode(0);
}
}
39 changes: 1 addition & 38 deletions contracts/interfaces/ILiquidityManagement.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,41 +6,4 @@ import {PoolKey} from "@uniswap/v4-core/contracts/types/PoolKey.sol";

/// @title Liquidity management interface
/// @notice Wrapper around pool manager callbacks
interface ILiquidityManagement is ILockCallback {
struct MintParams {
PoolKey poolKey;
int24 tickLower;
int24 tickUpper;
uint256 amount0Desired;
uint256 amount1Desired;
uint256 amount0Min;
uint256 amount1Min;
address recipient;
uint256 deadline;
bytes hookData;
}

struct IncreaseLiquidityParams {
uint256 tokenId;
uint256 amount0Desired;
uint256 amount1Desired;
uint256 amount0Min;
uint256 amount1Min;
uint256 deadline;
}

struct DecreaseLiquidityParams {
uint256 tokenId;
uint128 liquidity;
uint256 amount0Min;
uint256 amount1Min;
uint256 deadline;
}

struct CollectParams {
uint256 tokenId;
address recipient;
uint128 amount0Max;
uint128 amount1Max;
}
}
interface ILiquidityManagement is ILockCallback {}
46 changes: 38 additions & 8 deletions contracts/interfaces/INonfungiblePositionManagerV4.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,12 @@ import {PoolKey} from "@uniswap/v4-core/contracts/types/PoolKey.sol";
import {Currency} from "@uniswap/v4-core/contracts/types/Currency.sol";

import {IPeripheryPayments} from "./IPeripheryPayments.sol";
import {ILiquidityManagement} from "./ILiquidityManagement.sol";
import {IPeripheryImmutableState} from "./IPeripheryImmutableState.sol";

/// @title Non-fungible token for positions
/// @notice Wraps Uniswap V4 positions in a non-fungible token interface which allows for them to be transferred
/// and authorized.
interface INonfungiblePositionManagerV4 is
ILiquidityManagement,
IPeripheryPayments,
IPeripheryImmutableState,
IERC721Metadata,
IERC721Enumerable
{
interface INonfungiblePositionManagerV4 is IPeripheryImmutableState, IERC721Metadata, IERC721Enumerable {
/// @notice Emitted when liquidity is increased for a position NFT
/// @dev Also emitted when a token is minted
/// @param tokenId The ID of the token for which liquidity was increased
Expand Down Expand Up @@ -82,6 +75,19 @@ interface INonfungiblePositionManagerV4 is
uint128 tokensOwed1
);

struct MintParams {
PoolKey poolKey;
int24 tickLower;
int24 tickUpper;
uint256 amount0Desired;
uint256 amount1Desired;
uint256 amount0Min;
uint256 amount1Min;
address recipient;
uint256 deadline;
bytes hookData;
}

/// @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.
Expand All @@ -95,6 +101,15 @@ interface INonfungiblePositionManagerV4 is
payable
returns (uint256 tokenId, uint128 liquidity, uint256 amount0, uint256 amount1);

struct IncreaseLiquidityParams {
uint256 tokenId;
uint256 amount0Desired;
uint256 amount1Desired;
uint256 amount0Min;
uint256 amount1Min;
uint256 deadline;
}

/// @notice Increases the amount of liquidity in a position, with tokens paid by the `msg.sender`
/// @param params tokenId The ID of the token for which liquidity is being increased,
/// amount0Desired The desired amount of token0 to be spent,
Expand All @@ -110,6 +125,14 @@ interface INonfungiblePositionManagerV4 is
payable
returns (uint128 liquidity, uint256 amount0, uint256 amount1);

struct DecreaseLiquidityParams {
uint256 tokenId;
uint128 liquidity;
uint256 amount0Min;
uint256 amount1Min;
uint256 deadline;
}

/// @notice Decreases the amount of liquidity in a position and accounts it to the position
/// @param params tokenId The ID of the token for which liquidity is being decreased,
/// amount The amount by which liquidity will be decreased,
Expand All @@ -123,6 +146,13 @@ interface INonfungiblePositionManagerV4 is
payable
returns (uint256 amount0, uint256 amount1);

struct CollectParams {
uint256 tokenId;
address recipient;
uint128 amount0Max;
uint128 amount1Max;
}

/// @notice Collects up to a maximum amount of fees owed to a specific position to the recipient
/// @param params tokenId The ID of the NFT for which tokens are being collected,
/// recipient The account that should receive the tokens,
Expand Down

0 comments on commit c64e82e

Please sign in to comment.