Skip to content

Commit

Permalink
feat: Support batch liquidity modification
Browse files Browse the repository at this point in the history
Now contact size excess limit.
| NonfungiblePositionManager                 |   27,112 |     -2,536 |

So we need to choose one solution
1. Use modifyLiquidities to support batch liquidity modification
2. use current separate function
  • Loading branch information
ChefSnoopy committed Jul 29, 2024
1 parent d600000 commit da213bc
Show file tree
Hide file tree
Showing 29 changed files with 923 additions and 32 deletions.
Original file line number Diff line number Diff line change
@@ -1 +1 @@
736812
737466
Original file line number Diff line number Diff line change
@@ -1 +1 @@
693699
694305
Original file line number Diff line number Diff line change
@@ -1 +1 @@
738015
738633
Original file line number Diff line number Diff line change
@@ -1 +1 @@
793236
793890
Original file line number Diff line number Diff line change
@@ -1 +1 @@
752670
753276
Original file line number Diff line number Diff line change
@@ -1 +1 @@
794475
795093
Original file line number Diff line number Diff line change
@@ -1 +1 @@
736824
737478
Original file line number Diff line number Diff line change
@@ -1 +1 @@
693711
694317
Original file line number Diff line number Diff line change
@@ -1 +1 @@
738012
738630
Original file line number Diff line number Diff line change
@@ -1 +1 @@
791218
791872
Original file line number Diff line number Diff line change
@@ -1 +1 @@
750652
751258
Original file line number Diff line number Diff line change
@@ -1 +1 @@
792453
793071
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
688065
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
721972
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
286231
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
270952
1 change: 1 addition & 0 deletions .forge-snapshots/NonFungiblePositionManagerBatch#mint.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
623159
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
608132
2 changes: 1 addition & 1 deletion .forge-snapshots/NonfungiblePositionManager#collect.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
266605
267387
Original file line number Diff line number Diff line change
@@ -1 +1 @@
160378
160910
Original file line number Diff line number Diff line change
@@ -1 +1 @@
193678
194192
2 changes: 1 addition & 1 deletion .forge-snapshots/NonfungiblePositionManager#mint.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
606563
607181
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
696986
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
748966
84 changes: 71 additions & 13 deletions src/pool-cl/NonfungiblePositionManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,18 @@ contract NonfungiblePositionManager is
(tick) = poolManager.initialize(poolKey, sqrtPriceX96, hookData);
}

/// @inheritdoc INonfungiblePositionManager
function modifyLiquidities(bytes calldata lockData, uint256 deadline)
external
payable
checkDeadline(deadline)
returns (bytes[] memory)
{
return abi.decode(
vault.lock(abi.encode(CallbackData(msg.sender, CallbackDataType.BatchModifyLiquidity, lockData))), (bytes[])
);
}

/// @inheritdoc INonfungiblePositionManager
function mint(MintParams calldata params)
external
Expand Down Expand Up @@ -206,20 +218,45 @@ contract NonfungiblePositionManager is
}

CallbackData memory data = abi.decode(rawData, (CallbackData));
if (data.callbackDataType == CallbackDataType.BatchModifyLiquidity) {
bytes[] memory params = abi.decode(data.params, (bytes[]));
return _dispatch(params, data.sender);
} else {
return _handleSingleAction(data, true);
}
}

function _dispatch(bytes[] memory params, address sender) internal returns (bytes memory returnDataArrayBytes) {
uint256 length = params.length;
bytes[] memory returnData = new bytes[](length);
// In order to save gas, we will set the settle flag to true if only one liquidity modification
bool shouldSettle = length == 1;
for (uint256 i; i < length; i++) {
CallbackData memory data = abi.decode(params[i], (CallbackData));
data.sender = sender;
returnData[i] = _handleSingleAction(data, shouldSettle);
}

return abi.encode(returnData);
}

function _handleSingleAction(CallbackData memory data, bool shouldSettle) internal returns (bytes memory) {
if (data.callbackDataType == CallbackDataType.Mint) {
return _handleMint(data);
return _handleMint(data, shouldSettle);
} else if (data.callbackDataType == CallbackDataType.IncreaseLiquidity) {
return _handleIncreaseLiquidity(data);
return _handleIncreaseLiquidity(data, shouldSettle);
} else if (data.callbackDataType == CallbackDataType.DecreaseLiquidity) {
return _handleDecreaseLiquidity(data);
return _handleDecreaseLiquidity(data, shouldSettle);
} else if (data.callbackDataType == CallbackDataType.Collect) {
return _handleCollect(data);
return _handleCollect(data, shouldSettle);
} else if (data.callbackDataType == CallbackDataType.CloseCurrency) {
return _close(data.params, data.sender);
} else {
revert InvalidCalldataType();
}
}

function _handleMint(CallbackData memory data) internal returns (bytes memory) {
function _handleMint(CallbackData memory data, bool shouldSettle) internal returns (bytes memory) {
INonfungiblePositionManager.MintParams memory params =
abi.decode(data.params, (INonfungiblePositionManager.MintParams));

Expand Down Expand Up @@ -259,12 +296,14 @@ contract NonfungiblePositionManager is
_poolIdToPoolKey[params.poolKey.toId()] = params.poolKey;
}

settleDeltas(data.sender, params.poolKey, delta);
if (shouldSettle) {
settleDeltas(data.sender, params.poolKey, delta);
}

return abi.encode(tokenId, liquidity, -delta.amount0(), -delta.amount1());
}

function _handleIncreaseLiquidity(CallbackData memory data) internal returns (bytes memory) {
function _handleIncreaseLiquidity(CallbackData memory data, bool shouldSettle) internal returns (bytes memory) {
IncreaseLiquidityParams memory params = abi.decode(data.params, (IncreaseLiquidityParams));
Position storage nftPosition = _positions[params.tokenId];
PoolId poolId = nftPosition.poolId;
Expand Down Expand Up @@ -320,12 +359,14 @@ contract NonfungiblePositionManager is
nftPosition.feeGrowthInside1LastX128 = poolManagerPositionInfo.feeGrowthInside1LastX128;
nftPosition.liquidity += liquidity;

settleDeltas(data.sender, poolKey, delta);
if (shouldSettle) {
settleDeltas(data.sender, poolKey, delta);
}

return abi.encode(liquidity, -delta.amount0(), -delta.amount1());
}

function _handleDecreaseLiquidity(CallbackData memory data) internal returns (bytes memory) {
function _handleDecreaseLiquidity(CallbackData memory data, bool shouldSettle) internal returns (bytes memory) {
DecreaseLiquidityParams memory params = abi.decode(data.params, (DecreaseLiquidityParams));
Position storage nftPosition = _positions[params.tokenId];
PoolId poolId = nftPosition.poolId;
Expand Down Expand Up @@ -387,12 +428,14 @@ contract NonfungiblePositionManager is
nftPosition.liquidity -= params.liquidity;
}

settleDeltas(data.sender, poolKey, delta);
if (shouldSettle) {
settleDeltas(data.sender, poolKey, delta);
}

return abi.encode(delta.amount0(), delta.amount1());
}

function _handleCollect(CallbackData memory data) internal returns (bytes memory) {
function _handleCollect(CallbackData memory data, bool shouldSettle) internal returns (bytes memory) {
CollectParams memory params = abi.decode(data.params, (CollectParams));
Position storage nftPosition = _positions[params.tokenId];
Position memory nftPositionCache = _positions[params.tokenId];
Expand Down Expand Up @@ -459,12 +502,27 @@ contract NonfungiblePositionManager is
);

// cash out from vault
burnAndTake(poolKey.currency0, params.recipient, amount0Collect);
burnAndTake(poolKey.currency1, params.recipient, amount1Collect);
burnAndTake(poolKey.currency0, params.recipient, amount0Collect, shouldSettle);
burnAndTake(poolKey.currency1, params.recipient, amount1Collect, shouldSettle);

return abi.encode(amount0Collect, amount1Collect);
}

/// @param params is an encoding of the Currency to close
/// @param sender is the msg.sender encoded by the `modifyLiquidities` function before the `lockAcquired`.
/// @return an encoding of int256 the balance of the currency being settled by this call
function _close(bytes memory params, address sender) internal returns (bytes memory) {
(Currency currency) = abi.decode(params, (Currency));
// this address has applied all deltas on behalf of the user/owner
// it is safe to close this entire delta because of slippage checks throughout the batched calls.
int256 currencyDelta = vault.currencyDelta(address(this), currency);

settleOrTake(currency, sender, int128(currencyDelta));
//TODO: add refund logic for the remaining native currency

return abi.encode(currencyDelta);
}

function tokenURI(uint256 tokenId) public view override(ERC721, IERC721Metadata) returns (string memory) {
if (!_exists(tokenId)) {
revert NonexistentToken();
Expand Down
6 changes: 4 additions & 2 deletions src/pool-cl/base/LiquidityManagement.sol
Original file line number Diff line number Diff line change
Expand Up @@ -126,9 +126,11 @@ abstract contract LiquidityManagement is CLPeripheryImmutableState, PeripheryPay
}
}

function burnAndTake(Currency currency, address to, uint256 amount) internal {
function burnAndTake(Currency currency, address to, uint256 amount, bool shouldSettle) internal {
vault.burn(address(this), currency, amount);
vault.take(currency, to, amount);
if (shouldSettle) {
vault.take(currency, to, amount);
}
}

function settleDeltas(address sender, PoolKey memory poolKey, BalanceDelta delta) internal {
Expand Down
10 changes: 9 additions & 1 deletion src/pool-cl/interfaces/INonfungiblePositionManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,9 @@ interface INonfungiblePositionManager is
Mint,
IncreaseLiquidity,
DecreaseLiquidity,
Collect
Collect,
BatchModifyLiquidity,
CloseCurrency
}

struct CallbackData {
Expand Down Expand Up @@ -139,6 +141,12 @@ interface INonfungiblePositionManager is
uint256 deadline;
}

/// @notice Batches many liquidity modification calls to pool manager
/// @param payload is an encoding of actions, and parameters for those actions
/// @param deadline is the deadline for the batched actions to be executed
/// @return returnData is the endocing of each actions return information
function modifyLiquidities(bytes calldata payload, uint256 deadline) external payable returns (bytes[] memory);

/// @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 Down
Loading

0 comments on commit da213bc

Please sign in to comment.