Skip to content

Commit

Permalink
refactor for external call and code reuse (#134)
Browse files Browse the repository at this point in the history
  • Loading branch information
saucepoint authored Jun 27, 2024
1 parent 93f012e commit cc031aa
Show file tree
Hide file tree
Showing 11 changed files with 45 additions and 127 deletions.
2 changes: 1 addition & 1 deletion .forge-snapshots/autocompound_exactUnclaimedFees.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
261480
262398
Original file line number Diff line number Diff line change
@@ -1 +1 @@
193853
194771
2 changes: 1 addition & 1 deletion .forge-snapshots/autocompound_excessFeesCredit.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
282019
282937
2 changes: 1 addition & 1 deletion .forge-snapshots/decreaseLiquidity_erc20.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
191804
193172
2 changes: 1 addition & 1 deletion .forge-snapshots/decreaseLiquidity_erc6909.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
170671
172032
2 changes: 1 addition & 1 deletion .forge-snapshots/increaseLiquidity_erc20.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
174244
175155
2 changes: 1 addition & 1 deletion .forge-snapshots/increaseLiquidity_erc6909.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
149826
150744
2 changes: 1 addition & 1 deletion .forge-snapshots/mintWithLiquidity.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
469640
600083
51 changes: 36 additions & 15 deletions contracts/NonfungiblePositionManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -39,24 +39,23 @@ contract NonfungiblePositionManager is INonfungiblePositionManager, BaseLiquidit
ERC721Permit("Uniswap V4 Positions NFT-V1", "UNI-V4-POS", "1")
{}

function unlockAndExecute(bytes[] calldata data) external {
// TODO: bubble up the return
manager.unlock(abi.encode(LiquidityOperation.EXECUTE, abi.encode(data)));
function unlockAndExecute(bytes[] memory data) public returns (BalanceDelta delta) {
delta = abi.decode(manager.unlock(abi.encode(data)), (BalanceDelta));
}

/// @param data bytes[] - array of abi.encodeWithSelector(<selector>, <arguments>)
function _execute(bytes[] memory data) internal override returns (bytes memory) {
function _unlockCallback(bytes calldata payload) internal override returns (bytes memory) {
bytes[] memory data = abi.decode(payload, (bytes[]));

bool success;
bytes memory returnData;
for (uint256 i; i < data.length; i++) {
// TODO: bubble up the return
(success,) = address(this).call(data[i]);
(success, returnData) = address(this).call(data[i]);
if (!success) revert("EXECUTE_FAILED");
}

// zeroOut();

// TODO: return something
return new bytes(0);
return returnData;
}

// NOTE: more gas efficient as LiquidityAmounts is used offchain
Expand All @@ -77,7 +76,9 @@ contract NonfungiblePositionManager is INonfungiblePositionManager, BaseLiquidit
_closeCallerDeltas(delta, range.poolKey.currency0, range.poolKey.currency1, recipient, false);
_closeThisDeltas(thisDelta, range.poolKey.currency0, range.poolKey.currency1);
} else {
delta = _unlockAndIncreaseLiquidity(recipient, range, liquidity, hookData, false);
bytes[] memory data = new bytes[](1);
data[0] = abi.encodeWithSelector(this.mint.selector, range, liquidity, deadline, recipient, hookData);
delta = unlockAndExecute(data);
}

// mint receipt token
Expand Down Expand Up @@ -122,7 +123,9 @@ contract NonfungiblePositionManager is INonfungiblePositionManager, BaseLiquidit
);
_closeThisDeltas(thisDelta, tokenPos.range.poolKey.currency0, tokenPos.range.poolKey.currency1);
} else {
delta = _unlockAndIncreaseLiquidity(tokenPos.owner, tokenPos.range, liquidity, hookData, claims);
bytes[] memory data = new bytes[](1);
data[0] = abi.encodeWithSelector(this.increaseLiquidity.selector, tokenId, liquidity, hookData, claims);
delta = unlockAndExecute(data);
}
}

Expand All @@ -133,8 +136,17 @@ contract NonfungiblePositionManager is INonfungiblePositionManager, BaseLiquidit
{
TokenPosition memory tokenPos = tokenPositions[tokenId];

// TODO: @sauce update once _decreaseLiquidity returns callerDelta/thisDelta
delta = _unlockAndDecreaseLiquidity(tokenPos.owner, tokenPos.range, liquidity, hookData, claims);
if (manager.isUnlocked()) {
delta = _decreaseLiquidity(tokenPos.owner, tokenPos.range, liquidity, hookData);
_closeCallerDeltas(
delta, tokenPos.range.poolKey.currency0, tokenPos.range.poolKey.currency1, tokenPos.owner, claims
);
_closeAllDeltas(tokenPos.range.poolKey.currency0, tokenPos.range.poolKey.currency1);
} else {
bytes[] memory data = new bytes[](1);
data[0] = abi.encodeWithSelector(this.decreaseLiquidity.selector, tokenId, liquidity, hookData, claims);
delta = unlockAndExecute(data);
}
}

function burn(uint256 tokenId, address recipient, bytes calldata hookData, bool claims)
Expand Down Expand Up @@ -163,8 +175,17 @@ contract NonfungiblePositionManager is INonfungiblePositionManager, BaseLiquidit
returns (BalanceDelta delta)
{
TokenPosition memory tokenPos = tokenPositions[tokenId];
// TODO: @sauce update once _collect returns callerDelta/thisDel
delta = _unlockAndCollect(tokenPos.owner, tokenPos.range, hookData, claims);
if (manager.isUnlocked()) {
delta = _collect(tokenPos.owner, tokenPos.range, hookData);
_closeCallerDeltas(
delta, tokenPos.range.poolKey.currency0, tokenPos.range.poolKey.currency1, tokenPos.owner, claims
);
_closeAllDeltas(tokenPos.range.poolKey.currency0, tokenPos.range.poolKey.currency1);
} else {
bytes[] memory data = new bytes[](1);
data[0] = abi.encodeWithSelector(this.collect.selector, tokenId, recipient, hookData, claims);
delta = unlockAndExecute(data);
}
}

function feesOwed(uint256 tokenId) external view returns (uint256 token0Owed, uint256 token1Owed) {
Expand Down
98 changes: 0 additions & 98 deletions contracts/base/BaseLiquidityManagement.sol
Original file line number Diff line number Diff line change
Expand Up @@ -64,29 +64,6 @@ abstract contract BaseLiquidityManagement is IBaseLiquidityManagement, SafeCallb
else if (callerDelta1 > 0) currency1.send(manager, owner, uint128(callerDelta1), claims);
}

function _execute(bytes[] memory data) internal virtual returns (bytes memory);

function _unlockCallback(bytes calldata data) internal override returns (bytes memory) {
(LiquidityOperation op, bytes memory args) = abi.decode(data, (LiquidityOperation, bytes));
if (op == LiquidityOperation.EXECUTE) {
(bytes[] memory payload) = abi.decode(args, (bytes[]));
return _execute(payload);
} else {
(address owner, LiquidityRange memory range, uint256 liquidityChange, bytes memory hookData, bool claims) =
abi.decode(args, (address, LiquidityRange, uint256, bytes, bool));

if (op == LiquidityOperation.INCREASE) {
return abi.encode(_increaseLiquidityAndZeroOut(owner, range, liquidityChange, hookData, claims));
} else if (op == LiquidityOperation.DECREASE) {
return abi.encode(_decreaseLiquidityAndZeroOut(owner, range, liquidityChange, hookData, claims));
} else if (op == LiquidityOperation.COLLECT) {
return abi.encode(_collectAndZeroOut(owner, range, 0, hookData, claims));
} else {
return new bytes(0);
}
}
}

function _modifyLiquidity(address owner, LiquidityRange memory range, int256 liquidityChange, bytes memory hookData)
internal
returns (BalanceDelta liquidityDelta, BalanceDelta totalFeesAccrued)
Expand Down Expand Up @@ -163,20 +140,6 @@ abstract contract BaseLiquidityManagement is IBaseLiquidityManagement, SafeCallb
position.updateFeeGrowthInside(feeGrowthInside0X128, feeGrowthInside1X128);
}

function _increaseLiquidityAndZeroOut(
address owner,
LiquidityRange memory range,
uint256 liquidityToAdd,
bytes memory hookData,
bool claims
) internal returns (BalanceDelta callerDelta) {
BalanceDelta thisDelta;
// TODO move callerDelta and thisDelta to transient storage?
(callerDelta, thisDelta) = _increaseLiquidity(owner, range, liquidityToAdd, hookData);
_closeCallerDeltas(callerDelta, range.poolKey.currency0, range.poolKey.currency1, owner, claims);
_closeThisDeltas(thisDelta, range.poolKey.currency0, range.poolKey.currency1);
}

// When chaining many actions, this should be called at the very end to close out any open deltas owed to or by this contract for other users on the same range.
// This is safe because any amounts the caller should not pay or take have already been accounted for in closeCallerDeltas.
function _closeThisDeltas(BalanceDelta delta, Currency currency0, Currency currency1) internal {
Expand Down Expand Up @@ -225,21 +188,6 @@ abstract contract BaseLiquidityManagement is IBaseLiquidityManagement, SafeCallb
return (tokensOwed, callerDelta, thisDelta);
}

function _unlockAndIncreaseLiquidity(
address owner,
LiquidityRange memory range,
uint256 liquidityToAdd,
bytes memory hookData,
bool claims
) internal returns (BalanceDelta) {
return abi.decode(
manager.unlock(
abi.encode(LiquidityOperation.INCREASE, abi.encode(owner, range, liquidityToAdd, hookData, claims))
),
(BalanceDelta)
);
}

function _decreaseLiquidity(
address owner,
LiquidityRange memory range,
Expand Down Expand Up @@ -277,33 +225,6 @@ abstract contract BaseLiquidityManagement is IBaseLiquidityManagement, SafeCallb
return callerFeesAccrued;
}

function _decreaseLiquidityAndZeroOut(
address owner,
LiquidityRange memory range,
uint256 liquidityToRemove,
bytes memory hookData,
bool claims
) internal returns (BalanceDelta delta) {
delta = _decreaseLiquidity(owner, range, liquidityToRemove, hookData);
_closeCallerDeltas(delta, range.poolKey.currency0, range.poolKey.currency1, owner, claims);
_closeAllDeltas(range.poolKey.currency0, range.poolKey.currency1);
}

function _unlockAndDecreaseLiquidity(
address owner,
LiquidityRange memory range,
uint256 liquidityToRemove,
bytes memory hookData,
bool claims
) internal returns (BalanceDelta) {
return abi.decode(
manager.unlock(
abi.encode(LiquidityOperation.DECREASE, abi.encode(owner, range, liquidityToRemove, hookData, claims))
),
(BalanceDelta)
);
}

function _collect(address owner, LiquidityRange memory range, bytes memory hookData)
internal
returns (BalanceDelta)
Expand Down Expand Up @@ -332,25 +253,6 @@ abstract contract BaseLiquidityManagement is IBaseLiquidityManagement, SafeCallb
return callerFeesAccrued;
}

function _collectAndZeroOut(address owner, LiquidityRange memory range, uint256, bytes memory hookData, bool claims)
internal
returns (BalanceDelta delta)
{
delta = _collect(owner, range, hookData);
_closeCallerDeltas(delta, range.poolKey.currency0, range.poolKey.currency1, owner, claims);
_closeAllDeltas(range.poolKey.currency0, range.poolKey.currency1);
}

function _unlockAndCollect(address owner, LiquidityRange memory range, bytes memory hookData, bool claims)
internal
returns (BalanceDelta)
{
return abi.decode(
manager.unlock(abi.encode(LiquidityOperation.COLLECT, abi.encode(owner, range, 0, hookData, claims))),
(BalanceDelta)
);
}

// TODO: I deprecated this bc I liked to see the accounting in line in the top level function... and I like to do all the position updates at once.
// can keep but should at at least use the position library in here.
function _updateFeeGrowth(LiquidityRange memory range, Position storage position)
Expand Down
7 changes: 1 addition & 6 deletions contracts/interfaces/IBaseLiquidityManagement.sol
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,7 @@ interface IBaseLiquidityManagement {
uint128 tokensOwed1;
}

enum LiquidityOperation {
INCREASE,
DECREASE,
COLLECT,
EXECUTE
}
error LockFailure();

/// @notice Fees owed for a given liquidity position. Includes materialized fees and uncollected fees.
/// @param owner The owner of the liquidity position
Expand Down

0 comments on commit cc031aa

Please sign in to comment.