Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft/batch midification #69

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1 +1 @@
736974
737466
Original file line number Diff line number Diff line change
@@ -1 +1 @@
693861
694305
Original file line number Diff line number Diff line change
@@ -1 +1 @@
738290
738633
Original file line number Diff line number Diff line change
@@ -1 +1 @@
793398
793890
Original file line number Diff line number Diff line change
@@ -1 +1 @@
752832
753276
Original file line number Diff line number Diff line change
@@ -1 +1 @@
794750
795093
Original file line number Diff line number Diff line change
@@ -1 +1 @@
736986
737478
Original file line number Diff line number Diff line change
@@ -1 +1 @@
693873
694317
Original file line number Diff line number Diff line change
@@ -1 +1 @@
738287
738630
Original file line number Diff line number Diff line change
@@ -1 +1 @@
791380
791872
Original file line number Diff line number Diff line change
@@ -1 +1 @@
750814
751258
Original file line number Diff line number Diff line change
@@ -1 +1 @@
792728
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 @@
722012
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
286391
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
271112
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
180614
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
165586
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
216217
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
201183
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 @@
266620
267555
Original file line number Diff line number Diff line change
@@ -1 +1 @@
160400
160950
Original file line number Diff line number Diff line change
@@ -1 +1 @@
193953
194192
2 changes: 1 addition & 1 deletion .forge-snapshots/NonfungiblePositionManager#mint.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
606838
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 @@
749006
95 changes: 82 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,46 @@ 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;
// TODO:
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 +297,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,13 +360,19 @@ 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));
if (params.liquidity == 0) {
revert InvalidLiquidityDecreaseAmount();
}
// TODO: add isAuthorizedForToken check for modifyLiquidities
Position storage nftPosition = _positions[params.tokenId];
PoolId poolId = nftPosition.poolId;
uint128 liquidity = nftPosition.liquidity;
Expand Down Expand Up @@ -387,13 +433,21 @@ 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));
// check for modifyLiquidities
if (params.amount0Max == 0 && params.amount1Max == 0) {
revert InvalidMaxCollectAmount();
}
params.recipient = params.recipient == address(0) ? address(msg.sender) : params.recipient;
// TODO: add isAuthorizedForToken check for modifyLiquidities
Position storage nftPosition = _positions[params.tokenId];
Position memory nftPositionCache = _positions[params.tokenId];
PoolId poolId = nftPositionCache.poolId;
Expand Down Expand Up @@ -459,12 +513,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
37 changes: 16 additions & 21 deletions src/pool-cl/base/LiquidityManagement.sol
Original file line number Diff line number Diff line change
Expand Up @@ -126,33 +126,28 @@ 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 {
if (delta.amount0() > 0) {
vault.take(poolKey.currency0, sender, uint128(delta.amount0()));
} else if (delta.amount0() < 0) {
if (poolKey.currency0.isNative()) {
vault.settle{value: uint256(int256(-delta.amount0()))}(poolKey.currency0);
} else {
vault.sync(poolKey.currency0);
pay(poolKey.currency0, sender, address(vault), uint256(int256(-delta.amount0())));
vault.settle(poolKey.currency0);
}
}
settleOrTake(poolKey.currency0, sender, delta.amount0());
settleOrTake(poolKey.currency1, sender, delta.amount1());
}

if (delta.amount1() > 0) {
vault.take(poolKey.currency1, sender, uint128(delta.amount1()));
} else if (delta.amount1() < 0) {
if (poolKey.currency1.isNative()) {
vault.settle{value: uint256(int256(-delta.amount1()))}(poolKey.currency1);
function settleOrTake(Currency currency, address sender, int128 amount) internal {
if (amount > 0) {
vault.take(currency, sender, uint128(amount));
} else if (amount < 0) {
if (currency.isNative()) {
vault.settle{value: uint256(int256(-amount))}(currency);
} else {
vault.sync(poolKey.currency1);
pay(poolKey.currency1, sender, address(vault), uint256(int256(-delta.amount1())));
vault.settle(poolKey.currency1);
vault.sync(currency);
pay(currency, sender, address(vault), uint256(int256(-amount)));
vault.settle(currency);
}
}
}
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
Loading