Skip to content

Commit

Permalink
ABDK 46, 47, 48 (#327)
Browse files Browse the repository at this point in the history
* CVF 48

* CVF 47

* CVF 46

* remove 1 comment
hensha256 authored Sep 3, 2024

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
1 parent 0f0b6b6 commit 9cb77ca
Showing 36 changed files with 122 additions and 75 deletions.
Original file line number Diff line number Diff line change
@@ -1 +1 @@
123968
123966
Original file line number Diff line number Diff line change
@@ -1 +1 @@
123465
123464
Original file line number Diff line number Diff line change
@@ -1 +1 @@
131046
131044
Original file line number Diff line number Diff line change
@@ -1 +1 @@
130544
130542
2 changes: 1 addition & 1 deletion .forge-snapshots/PositionManager_collect_native.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
142433
142431
2 changes: 1 addition & 1 deletion .forge-snapshots/PositionManager_collect_sameRange.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
151281
151279
2 changes: 1 addition & 1 deletion .forge-snapshots/PositionManager_collect_withClose.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
151281
151279
2 changes: 1 addition & 1 deletion .forge-snapshots/PositionManager_collect_withTakePair.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
150641
150639
Original file line number Diff line number Diff line change
@@ -1 +1 @@
109421
109420
Original file line number Diff line number Diff line change
@@ -1 +1 @@
116824
116822
Original file line number Diff line number Diff line change
@@ -1 +1 @@
116184
116182
2 changes: 1 addition & 1 deletion .forge-snapshots/PositionManager_decrease_burnEmpty.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
135121
135120
Original file line number Diff line number Diff line change
@@ -1 +1 @@
127860
127859
Original file line number Diff line number Diff line change
@@ -1 +1 @@
129540
129538
2 changes: 1 addition & 1 deletion .forge-snapshots/PositionManager_decrease_take_take.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
117357
117355
Original file line number Diff line number Diff line change
@@ -1 +1 @@
155531
155504
Original file line number Diff line number Diff line change
@@ -1 +1 @@
154533
154506
Original file line number Diff line number Diff line change
@@ -1 +1 @@
137331
137304
Original file line number Diff line number Diff line change
@@ -1 +1 @@
133676
133649
Original file line number Diff line number Diff line change
@@ -1 +1 @@
174592
174565
Original file line number Diff line number Diff line change
@@ -1 +1 @@
144548
144521
2 changes: 1 addition & 1 deletion .forge-snapshots/PositionManager_mint_native.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
341053
341026
Original file line number Diff line number Diff line change
@@ -1 +1 @@
349545
349518
Original file line number Diff line number Diff line change
@@ -1 +1 @@
348847
348820
2 changes: 1 addition & 1 deletion .forge-snapshots/PositionManager_mint_onSameTickLower.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
319035
319008
2 changes: 1 addition & 1 deletion .forge-snapshots/PositionManager_mint_onSameTickUpper.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
319677
319650
2 changes: 1 addition & 1 deletion .forge-snapshots/PositionManager_mint_sameRange.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
245259
245232
Original file line number Diff line number Diff line change
@@ -1 +1 @@
375077
375050
Original file line number Diff line number Diff line change
@@ -1 +1 @@
325053
325026
2 changes: 1 addition & 1 deletion .forge-snapshots/PositionManager_mint_withClose.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
376353
376326
2 changes: 1 addition & 1 deletion .forge-snapshots/PositionManager_mint_withSettlePair.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
375493
375466
Original file line number Diff line number Diff line change
@@ -1 +1 @@
420802
420775
4 changes: 2 additions & 2 deletions src/PositionManager.sol
Original file line number Diff line number Diff line change
@@ -24,7 +24,7 @@ import {Actions} from "./libraries/Actions.sol";
import {Notifier} from "./base/Notifier.sol";
import {CalldataDecoder} from "./libraries/CalldataDecoder.sol";
import {Permit2Forwarder} from "./base/Permit2Forwarder.sol";
import {SlippageCheckLibrary} from "./libraries/SlippageCheck.sol";
import {SlippageCheck} from "./libraries/SlippageCheck.sol";
import {PositionConfigId, PositionConfigIdLibrary} from "./libraries/PositionConfigId.sol";

// 444444444
@@ -111,7 +111,7 @@ contract PositionManager is
using SafeCast for uint256;
using SafeCast for int256;
using CalldataDecoder for bytes;
using SlippageCheckLibrary for BalanceDelta;
using SlippageCheck for BalanceDelta;
using PositionConfigIdLibrary for PositionConfigId;

/// @inheritdoc IPositionManager
21 changes: 12 additions & 9 deletions src/libraries/SlippageCheck.sol
Original file line number Diff line number Diff line change
@@ -6,11 +6,11 @@ import {SafeCastTemp} from "./SafeCast.sol";

/// @title Slippage Check Library
/// @notice a library for checking if a delta exceeds a maximum ceiling or fails to meet a minimum floor
library SlippageCheckLibrary {
library SlippageCheck {
using SafeCastTemp for int128;

error MaximumAmountExceeded();
error MinimumAmountInsufficient();
error MaximumAmountExceeded(uint128 maximumAmount, uint128 amountRequested);
error MinimumAmountInsufficient(uint128 minimumAmount, uint128 amountReceived);

/// @notice Revert if one or both deltas does not meet a minimum output
/// @param delta The principal amount of tokens to be removed, does not include any fees accrued
@@ -22,8 +22,11 @@ library SlippageCheckLibrary {
// However, on pools where hooks can return deltas on modify liquidity, it is possible for a returned delta to be negative.
// Because we use SafeCast, this will revert in those cases when the delta is negative.
// This means this contract will NOT support pools where the hook returns a negative delta on burn/decrease.
if (delta.amount0().toUint128() < amount0Min || delta.amount1().toUint128() < amount1Min) {
revert MinimumAmountInsufficient();
if (delta.amount0().toUint128() < amount0Min) {
revert MinimumAmountInsufficient(amount0Min, delta.amount0().toUint128());
}
if (delta.amount1().toUint128() < amount1Min) {
revert MinimumAmountInsufficient(amount1Min, delta.amount1().toUint128());
}
}

@@ -38,9 +41,9 @@ library SlippageCheckLibrary {
// Thus, we only cast the delta if it is guaranteed to be negative.
// And we do NOT revert in the positive delta case. Since a positive delta means the hook is crediting tokens to the user for minting/increasing liquidity, we do not check slippage.
// This means this contract will NOT support _positive_ slippage checks (minAmountOut checks) on pools where the hook returns a positive delta on mint/increase.
if (
delta.amount0() < 0 && amount0Max < uint128(-delta.amount0())
|| delta.amount1() < 0 && amount1Max < uint128(-delta.amount1())
) revert MaximumAmountExceeded();
int128 amount0 = delta.amount0();
int128 amount1 = delta.amount1();
if (amount0 < 0 && amount0Max < uint128(-amount0)) revert MaximumAmountExceeded(amount0Max, uint128(-amount0));
if (amount1 < 0 && amount1Max < uint128(-amount1)) revert MaximumAmountExceeded(amount1Max, uint128(-amount1));
}
}
28 changes: 22 additions & 6 deletions test/position-managers/IncreaseLiquidity.t.sol
Original file line number Diff line number Diff line change
@@ -22,7 +22,7 @@ import {IERC20} from "forge-std/interfaces/IERC20.sol";
import {PositionManager} from "../../src/PositionManager.sol";
import {DeltaResolver} from "../../src/base/DeltaResolver.sol";
import {PositionConfig} from "../../src/libraries/PositionConfig.sol";
import {SlippageCheckLibrary} from "../../src/libraries/SlippageCheck.sol";
import {SlippageCheck} from "../../src/libraries/SlippageCheck.sol";
import {IPositionManager} from "../../src/interfaces/IPositionManager.sol";
import {Actions} from "../../src/libraries/Actions.sol";
import {Planner, Plan} from "../shared/Planner.sol";
@@ -540,9 +540,16 @@ contract IncreaseLiquidityTest is Test, PosmTestSetup, Fuzzers {
uint256 tokenId = lpm.nextTokenId();
mint(config, 100e18, ActionConstants.MSG_SENDER, ZERO_BYTES);

uint128 newLiquidity = 100e18;
(uint256 amount0,) = LiquidityAmounts.getAmountsForLiquidity(
SQRT_PRICE_1_1,
TickMath.getSqrtPriceAtTick(config.tickLower),
TickMath.getSqrtPriceAtTick(config.tickUpper),
newLiquidity
);
// revert since amount0Max is too low
bytes memory calls = getIncreaseEncoded(tokenId, config, 100e18, 1 wei, type(uint128).max, ZERO_BYTES);
vm.expectRevert(SlippageCheckLibrary.MaximumAmountExceeded.selector);
bytes memory calls = getIncreaseEncoded(tokenId, config, newLiquidity, 1 wei, type(uint128).max, ZERO_BYTES);
vm.expectRevert(abi.encodeWithSelector(SlippageCheck.MaximumAmountExceeded.selector, 1 wei, amount0 + 1));
lpm.modifyLiquidities(calls, _deadline);
}

@@ -551,9 +558,16 @@ contract IncreaseLiquidityTest is Test, PosmTestSetup, Fuzzers {
uint256 tokenId = lpm.nextTokenId();
mint(config, 100e18, ActionConstants.MSG_SENDER, ZERO_BYTES);

uint128 newLiquidity = 100e18;
(, uint256 amount1) = LiquidityAmounts.getAmountsForLiquidity(
SQRT_PRICE_1_1,
TickMath.getSqrtPriceAtTick(config.tickLower),
TickMath.getSqrtPriceAtTick(config.tickUpper),
newLiquidity
);
// revert since amount1Max is too low
bytes memory calls = getIncreaseEncoded(tokenId, config, 100e18, type(uint128).max, 1 wei, ZERO_BYTES);
vm.expectRevert(SlippageCheckLibrary.MaximumAmountExceeded.selector);
bytes memory calls = getIncreaseEncoded(tokenId, config, newLiquidity, type(uint128).max, 1 wei, ZERO_BYTES);
vm.expectRevert(abi.encodeWithSelector(SlippageCheck.MaximumAmountExceeded.selector, 1 wei, amount1 + 1));
lpm.modifyLiquidities(calls, _deadline);
}

@@ -601,7 +615,9 @@ contract IncreaseLiquidityTest is Test, PosmTestSetup, Fuzzers {
swap(key, true, -10e18, ZERO_BYTES);

bytes memory calls = getIncreaseEncoded(tokenId, config, newLiquidity, slippage, slippage, ZERO_BYTES);
vm.expectRevert(SlippageCheckLibrary.MaximumAmountExceeded.selector);
vm.expectRevert(
abi.encodeWithSelector(SlippageCheck.MaximumAmountExceeded.selector, slippage, 299996249439153403)
);
lpm.modifyLiquidities(calls, _deadline);
}

80 changes: 54 additions & 26 deletions test/position-managers/PositionManager.t.sol
Original file line number Diff line number Diff line change
@@ -25,7 +25,7 @@ import {Actions} from "../../src/libraries/Actions.sol";
import {PositionManager} from "../../src/PositionManager.sol";
import {DeltaResolver} from "../../src/base/DeltaResolver.sol";
import {PositionConfig} from "../../src/libraries/PositionConfig.sol";
import {SlippageCheckLibrary} from "../../src/libraries/SlippageCheck.sol";
import {SlippageCheck} from "../../src/libraries/SlippageCheck.sol";
import {BaseActionsRouter} from "../../src/base/BaseActionsRouter.sol";
import {ActionConstants} from "../../src/libraries/ActionConstants.sol";

@@ -258,18 +258,33 @@ contract PositionManagerTest is Test, PosmTestSetup, LiquidityFuzzers {
function test_mint_slippage_revertAmount0() public {
PositionConfig memory config = PositionConfig({poolKey: key, tickLower: -120, tickUpper: 120});

uint256 liquidity = 1e18;
(uint256 amount0,) = LiquidityAmounts.getAmountsForLiquidity(
SQRT_PRICE_1_1,
TickMath.getSqrtPriceAtTick(config.tickLower),
TickMath.getSqrtPriceAtTick(config.tickUpper),
uint128(liquidity)
);

bytes memory calls =
getMintEncoded(config, 1e18, 1 wei, MAX_SLIPPAGE_INCREASE, ActionConstants.MSG_SENDER, ZERO_BYTES);
vm.expectRevert(SlippageCheckLibrary.MaximumAmountExceeded.selector);
getMintEncoded(config, liquidity, 1 wei, MAX_SLIPPAGE_INCREASE, ActionConstants.MSG_SENDER, ZERO_BYTES);
vm.expectRevert(abi.encodeWithSelector(SlippageCheck.MaximumAmountExceeded.selector, 1 wei, amount0 + 1));
lpm.modifyLiquidities(calls, _deadline);
}

function test_mint_slippage_revertAmount1() public {
PositionConfig memory config = PositionConfig({poolKey: key, tickLower: -120, tickUpper: 120});

uint256 liquidity = 1e18;
(, uint256 amount1) = LiquidityAmounts.getAmountsForLiquidity(
SQRT_PRICE_1_1,
TickMath.getSqrtPriceAtTick(config.tickLower),
TickMath.getSqrtPriceAtTick(config.tickUpper),
uint128(liquidity)
);
bytes memory calls =
getMintEncoded(config, 1e18, MAX_SLIPPAGE_INCREASE, 1 wei, ActionConstants.MSG_SENDER, ZERO_BYTES);
vm.expectRevert(SlippageCheckLibrary.MaximumAmountExceeded.selector);
getMintEncoded(config, liquidity, MAX_SLIPPAGE_INCREASE, 1 wei, ActionConstants.MSG_SENDER, ZERO_BYTES);
vm.expectRevert(abi.encodeWithSelector(SlippageCheck.MaximumAmountExceeded.selector, 1 wei, amount1 + 1));
lpm.modifyLiquidities(calls, _deadline);
}

@@ -314,7 +329,9 @@ contract PositionManagerTest is Test, PosmTestSetup, LiquidityFuzzers {
// swap to move the price and cause a slippage revert
swap(key, true, -1e18, ZERO_BYTES);

vm.expectRevert(SlippageCheckLibrary.MaximumAmountExceeded.selector);
vm.expectRevert(
abi.encodeWithSelector(SlippageCheck.MaximumAmountExceeded.selector, slippage, 1199947202932782783)
);
lpm.modifyLiquidities(calls, _deadline);
}

@@ -418,10 +435,12 @@ contract PositionManagerTest is Test, PosmTestSetup, LiquidityFuzzers {
uint256 tokenId = lpm.nextTokenId();
mint(config, 1e18, ActionConstants.MSG_SENDER, ZERO_BYTES);
BalanceDelta delta = getLastDelta();
uint128 amount0 = uint128(-delta.amount0());

bytes memory calls =
getBurnEncoded(tokenId, config, uint128(-delta.amount0()) + 1 wei, MIN_SLIPPAGE_DECREASE, ZERO_BYTES);
vm.expectRevert(SlippageCheckLibrary.MinimumAmountInsufficient.selector);
bytes memory calls = getBurnEncoded(tokenId, config, amount0 + 1 wei, MIN_SLIPPAGE_DECREASE, ZERO_BYTES);
vm.expectRevert(
abi.encodeWithSelector(SlippageCheck.MinimumAmountInsufficient.selector, amount0 + 1, amount0 - 1)
);
lpm.modifyLiquidities(calls, _deadline);
}

@@ -430,10 +449,14 @@ contract PositionManagerTest is Test, PosmTestSetup, LiquidityFuzzers {
uint256 tokenId = lpm.nextTokenId();
mint(config, 1e18, ActionConstants.MSG_SENDER, ZERO_BYTES);
BalanceDelta delta = getLastDelta();
uint128 amount1 = uint128(-delta.amount1());

bytes memory calls =
getBurnEncoded(tokenId, config, MIN_SLIPPAGE_DECREASE, uint128(-delta.amount1()) + 1 wei, ZERO_BYTES);
vm.expectRevert(SlippageCheckLibrary.MinimumAmountInsufficient.selector);
bytes memory calls = getBurnEncoded(tokenId, config, MIN_SLIPPAGE_DECREASE, amount1 + 1 wei, ZERO_BYTES);

// reverts on amount1, because the swap sent token0 into the pool and took token1
vm.expectRevert(
abi.encodeWithSelector(SlippageCheck.MinimumAmountInsufficient.selector, amount1 + 1, amount1 - 1)
);
lpm.modifyLiquidities(calls, _deadline);
}

@@ -460,15 +483,15 @@ contract PositionManagerTest is Test, PosmTestSetup, LiquidityFuzzers {
uint256 tokenId = lpm.nextTokenId();
mint(config, 1e18, ActionConstants.MSG_SENDER, ZERO_BYTES);
BalanceDelta delta = getLastDelta();
uint128 amount1 = uint128(-delta.amount1());

bytes memory calls = getBurnEncoded(
tokenId, config, uint128(-delta.amount0()) - 1 wei, uint128(-delta.amount1()) - 1 wei, ZERO_BYTES
);
bytes memory calls =
getBurnEncoded(tokenId, config, uint128(-delta.amount0()) - 1 wei, amount1 - 1 wei, ZERO_BYTES);

// swap to move the price and cause a slippage revert
swap(key, true, -1e18, ZERO_BYTES);

vm.expectRevert(SlippageCheckLibrary.MinimumAmountInsufficient.selector);
vm.expectRevert(abi.encodeWithSelector(SlippageCheck.MinimumAmountInsufficient.selector, amount1 - 1, 0));
lpm.modifyLiquidities(calls, _deadline);
}

@@ -620,11 +643,13 @@ contract PositionManagerTest is Test, PosmTestSetup, LiquidityFuzzers {
uint256 tokenId = lpm.nextTokenId();
mint(config, 1e18, ActionConstants.MSG_SENDER, ZERO_BYTES);
BalanceDelta delta = getLastDelta();
uint128 amount0Delta = uint128(-delta.amount0());

bytes memory calls = getDecreaseEncoded(
tokenId, config, 1e18, uint128(-delta.amount0()) + 1 wei, MIN_SLIPPAGE_DECREASE, ZERO_BYTES
bytes memory calls =
getDecreaseEncoded(tokenId, config, 1e18, amount0Delta + 1, MIN_SLIPPAGE_DECREASE, ZERO_BYTES);
vm.expectRevert(
abi.encodeWithSelector(SlippageCheck.MinimumAmountInsufficient.selector, amount0Delta + 1, amount0Delta - 1)
);
vm.expectRevert(SlippageCheckLibrary.MinimumAmountInsufficient.selector);
lpm.modifyLiquidities(calls, _deadline);
}

@@ -633,11 +658,13 @@ contract PositionManagerTest is Test, PosmTestSetup, LiquidityFuzzers {
uint256 tokenId = lpm.nextTokenId();
mint(config, 1e18, ActionConstants.MSG_SENDER, ZERO_BYTES);
BalanceDelta delta = getLastDelta();
uint128 amount1Delta = uint128(-delta.amount0());

bytes memory calls = getDecreaseEncoded(
tokenId, config, 1e18, MIN_SLIPPAGE_DECREASE, uint128(-delta.amount1()) + 1 wei, ZERO_BYTES
bytes memory calls =
getDecreaseEncoded(tokenId, config, 1e18, MIN_SLIPPAGE_DECREASE, amount1Delta + 1 wei, ZERO_BYTES);
vm.expectRevert(
abi.encodeWithSelector(SlippageCheck.MinimumAmountInsufficient.selector, amount1Delta + 1, amount1Delta - 1)
);
vm.expectRevert(SlippageCheckLibrary.MinimumAmountInsufficient.selector);
lpm.modifyLiquidities(calls, _deadline);
}

@@ -665,15 +692,16 @@ contract PositionManagerTest is Test, PosmTestSetup, LiquidityFuzzers {
uint256 tokenId = lpm.nextTokenId();
mint(config, 1e18, ActionConstants.MSG_SENDER, ZERO_BYTES);
BalanceDelta delta = getLastDelta();
uint128 amount1 = uint128(-delta.amount1());

bytes memory calls = getDecreaseEncoded(
tokenId, config, 1e18, uint128(-delta.amount0()) - 1 wei, uint128(-delta.amount1()) - 1 wei, ZERO_BYTES
);
bytes memory calls =
getDecreaseEncoded(tokenId, config, 1e18, uint128(-delta.amount0()) - 1 wei, amount1 - 1 wei, ZERO_BYTES);

// swap to move the price and cause a slippage revert
swap(key, true, -1e18, ZERO_BYTES);

vm.expectRevert(SlippageCheckLibrary.MinimumAmountInsufficient.selector);
// reverts on amount1, because the swap sent token0 into the pool and took token1
vm.expectRevert(abi.encodeWithSelector(SlippageCheck.MinimumAmountInsufficient.selector, amount1 - 1, 0));
lpm.modifyLiquidities(calls, _deadline);
}

0 comments on commit 9cb77ca

Please sign in to comment.