For removing liquidity we call the burn() function in ConcentratedLiquidityPoolManager.sol where in the msg.sender should be the owner of the tokenId.
/// @notice Burns the position
/// @param tokenId position id
/// @param amount amount to burn
/// @param recipient receipient address
/// @param unwrapVault to userwallet/vault
/// @param minimumOut0 minimum amount0 to claim
/// @param minimumOut1 minimum amount1 to claim
/// @return token0Amount actual token0 returned
/// @return token1Amount actual token1 returned
function burn(
uint256 tokenId,
uint128 amount,
address recipient,
bool unwrapVault,
uint256 minimumOut0,
uint256 minimumOut1
) external returns (uint256 token0Amount, uint256 token1Amount) {
require(msg.sender == ownerOf(tokenId), "NOT_ID_OWNER");
We get the data about the existing position from the tokenId provided. Next we compare the amount of liquidity to be burnt with the amount of liquidity in the position.
If amount to be burnt is less than entire liquidity position we burn the amount and update the feeGrowthInside and reduce the burn amount liquidity from the position. If amount to be burnt is same as the entire liquidity of the position we burn the entire position range along with the tokenId and delete the tokenId from the positions mapping
Position memory position = positions[tokenId];
(uint256 token0Fees, uint256 token1Fees, uint256 feeGrowthInside0, uint256 feeGrowthInside1) = positionFees(tokenId);
if (amount < position.liquidity) {
(token0Amount, token1Amount, , ) = position.pool.burn(position.lower, position.upper, amount);
positions[tokenId].feeGrowthInside0 = feeGrowthInside0;
positions[tokenId].feeGrowthInside1 = feeGrowthInside1;
positions[tokenId].liquidity -= amount;
} else {
amount = position.liquidity;
(token0Amount, token1Amount, , ) = position.pool.burn(position.lower, position.upper, amount);
burn(tokenId);
delete positions[tokenId];
}
Check if the received token amounts are greater than or equal to min amounts.
if yes then transfer the assets to the recipient
require(token0Amount >= minimumOut0 && token1Amount >= minimumOut1, "TOO_LITTLE_RECEIVED");
unchecked {
token0Amount += token0Fees;
token1Amount += token1Fees;
}
_transferBoth(position.pool, recipient, token0Amount, token1Amount, unwrapVault);
emit DecreaseLiquidity(address(position.pool), msg.sender, tokenId, amount);
The burn() function of ConcentratedLiquidityPoolManager.sol calls the burn() of ConentratedLiquidityPool.sol Lets take a look at that.
/// @notice Burns a position
/// @param lower lower tick
/// @param upper upper tick
/// @param amount amount to burn
function burn(
int24 lower,
int24 upper,
uint128 amount
)
public
lock
returns (
uint256 token0Amount,
uint256 token1Amount,
uint256 token0Fees,
uint256 token1Fees
)
We find the sqrtPrice at the lower and upper ticks and get the current price of the pool from price.
uint160 priceLower = TickMath.getSqrtRatioAtTick(lower);
uint160 priceUpper = TickMath.getSqrtRatioAtTick(upper);
uint160 currentPrice = price;
We update the secondsGrowthGlobal of the liquidity