Adding And Removing Liquidity is handled by ConcentratedLiquidityPoolMananger.sol by its mint and burn functions respectively. ConcentratedLiquidityPoolMananger is Dfyn's Concentrated Liquidity Pool periphery contract that combines non-fungible position management and staking. Lets look at mint function first
While adding liquidity Mint function in ConcentratedLiquidityPoolManager is called which mints a new position as a NFT returned as positionId.
The mint
function is used to mint a new non-fungible token (NFT) or add liquidity to an existing one. The NFT is associated with a Concentrated Liquidity Pool, and its value is determined by the amount of liquidity it holds and the range of prices it covers.
/// @notice Mints Position
/// @param pool address of pool
/// @param lowerOld tick below lower tick
/// @param lower lower tick
/// @param upperOld tick below upper
/// @param upper upper tick
/// @param amount0Desired token0 input amount
/// @param amount1Desired token1 input amount
/// @param native user wallet/vault
/// @param minLiquidity min liquidity to mint
/// @param positionId position nft id
function mint(
IConcentratedLiquidityPool pool,
int24 lowerOld,
int24 lower,
int24 upperOld,
int24 upper,
uint128 amount0Desired,
uint128 amount1Desired,
bool native,
uint256 minLiquidity,
uint256 positionId
) external payable returns (uint256 _positionId) {
The function takes several parameters:
pool
is the address of the Concentrated Liquidity Pool that the NFT is associated with.lowerOld
, lower
, upperOld
, and upper
are ticks that define the range of prices covered by the NFT.amount0Desired
and amount1Desired
are the amounts of the two tokens (token0 and token1) that the user wants to add to the NFT.native
is a boolean value that indicates whether the user's wallet/vault is a native token or not.minLiquidity
is the minimum amount of liquidity that must be added to the NFT in order to mint it.positionId
is the ID of the NFT, if it already exists. If it is set to 0, a new NFT will be minted.require(masterDeployer.pools(address(pool)), "INVALID_POOL");
cachedMsgSender = msg.sender;
cachedPool = address(pool);
The code first checks that the address of the provided liquidity pool is in the pools
mapping of the masterDeployer
contract. If it is not, the function execution is reverted with the error message "INVALID_POOL". The code then saves the caller's address in the cachedMsgSender
variable and the pool's address in the cachedPool
variable.
uint128 liquidityMinted = uint128(
pool.mint(
IConcentratedLiquidityPoolStruct.MintParams({
lowerOld: lowerOld,
lower: lower,
upperOld: upperOld,
upper: upper,
amount0Desired: amount0Desired,
amount1Desired: amount1Desired,
native: native
})
)
);
require(liquidityMinted >= minLiquidity, "TOO_LITTLE_RECEIVED");
The code first calls the mint
function on the provided liquidity pool, passing in a MintParams
struct with the input values of the mint
function as its fields. This mint
function on the liquidity pool is responsible for creating the new liquidity tokens and returning the amount of tokens minted.
The code then checks that the amount of tokens minted is greater than or equal to the minLiquidity
value provided as input to the mint
function. If it is not, the function execution is reverted with the error message "TOO_LITTLE_RECEIVED".