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

Slippage checks routing #233

Merged
merged 2 commits into from
Aug 1, 2024
Merged
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
2 changes: 1 addition & 1 deletion .forge-snapshots/V4Router_Bytecode.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
6628
6845
2 changes: 1 addition & 1 deletion .forge-snapshots/V4Router_ExactInputSingle.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
134717
134844
2 changes: 1 addition & 1 deletion .forge-snapshots/V4Router_ExactInputSingle_nativeIn.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
119848
119975
2 changes: 1 addition & 1 deletion .forge-snapshots/V4Router_ExactInputSingle_nativeOut.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
118993
119120
2 changes: 1 addition & 1 deletion .forge-snapshots/V4Router_ExactOutputSingle.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
133251
133648
Original file line number Diff line number Diff line change
@@ -1 +1 @@
125373
125770
2 changes: 1 addition & 1 deletion .forge-snapshots/V4Router_ExactOutputSingle_nativeOut.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
119636
120033
22 changes: 13 additions & 9 deletions src/V4Router.sol
Original file line number Diff line number Diff line change
Expand Up @@ -63,13 +63,14 @@ abstract contract V4Router is IV4Router, BaseActionsRouter, DeltaResolver {
}

function _swapExactInputSingle(IV4Router.ExactInputSingleParams memory params) private {
_swap(
uint128 amountOut = _swap(
params.poolKey,
params.zeroForOne,
int256(-int128(params.amountIn)),
params.sqrtPriceLimitX96,
params.hookData
);
).toUint128();
if (amountOut < params.amountOutMinimum) revert TooLittleReceived();
}

function _swapExactInput(IV4Router.ExactInputParams memory params) private {
Expand All @@ -96,13 +97,16 @@ abstract contract V4Router is IV4Router, BaseActionsRouter, DeltaResolver {
}

function _swapExactOutputSingle(IV4Router.ExactOutputSingleParams memory params) private {
_swap(
params.poolKey,
params.zeroForOne,
int256(int128(params.amountOut)),
params.sqrtPriceLimitX96,
params.hookData
);
uint128 amountIn = (
-_swap(
params.poolKey,
params.zeroForOne,
int256(int128(params.amountOut)),
params.sqrtPriceLimitX96,
params.hookData
)
).toUint128();
if (amountIn > params.amountInMaximum) revert TooMuchRequested();
}

function _swapExactOutput(IV4Router.ExactOutputParams memory params) private {
Expand Down
6 changes: 3 additions & 3 deletions test/router/V4Router.gas.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ contract V4RouterTest is RoutingTestHelpers, GasSnapshot {
uint256 amountOut = 1 ether;

IV4Router.ExactOutputSingleParams memory params =
IV4Router.ExactOutputSingleParams(key0, true, uint128(amountOut), 0, 0, bytes(""));
IV4Router.ExactOutputSingleParams(key0, true, uint128(amountOut), type(uint128).max, 0, bytes(""));

plan = plan.add(Actions.SWAP_EXACT_OUT_SINGLE, abi.encode(params));
bytes memory data = plan.finalizeSwap(key0.currency0, key0.currency1, address(this));
Expand Down Expand Up @@ -271,7 +271,7 @@ contract V4RouterTest is RoutingTestHelpers, GasSnapshot {
uint256 amountOut = 1 ether;

IV4Router.ExactOutputSingleParams memory params =
IV4Router.ExactOutputSingleParams(nativeKey, true, uint128(amountOut), 0, 0, bytes(""));
IV4Router.ExactOutputSingleParams(nativeKey, true, uint128(amountOut), type(uint128).max, 0, bytes(""));

plan = plan.add(Actions.SWAP_EXACT_OUT_SINGLE, abi.encode(params));
bytes memory data = plan.finalizeSwap(nativeKey.currency0, nativeKey.currency1, address(this));
Expand All @@ -284,7 +284,7 @@ contract V4RouterTest is RoutingTestHelpers, GasSnapshot {
uint256 amountOut = 1 ether;

IV4Router.ExactOutputSingleParams memory params =
IV4Router.ExactOutputSingleParams(nativeKey, false, uint128(amountOut), 0, 0, bytes(""));
IV4Router.ExactOutputSingleParams(nativeKey, false, uint128(amountOut), type(uint128).max, 0, bytes(""));

plan = plan.add(Actions.SWAP_EXACT_OUT_SINGLE, abi.encode(params));
bytes memory data = plan.finalizeSwap(nativeKey.currency1, nativeKey.currency0, address(this));
Expand Down
83 changes: 75 additions & 8 deletions test/router/V4Router.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,22 @@ contract V4RouterTest is RoutingTestHelpers {
ERC20 -> ERC20 EXACT INPUT
//////////////////////////////////////////////////////////////*/

function test_swapExactInputSingle_revertsForAmountOut() public {
uint256 amountIn = 1 ether;
uint256 expectedAmountOut = 992054607780215625;

// min amount out of 1 higher than the actual amount out
IV4Router.ExactInputSingleParams memory params = IV4Router.ExactInputSingleParams(
key0, true, uint128(amountIn), uint128(expectedAmountOut + 1), 0, bytes("")
);

plan = plan.add(Actions.SWAP_EXACT_IN_SINGLE, abi.encode(params));
bytes memory data = plan.finalizeSwap(key0.currency0, key0.currency1, address(this));

vm.expectRevert(IV4Router.TooLittleReceived.selector);
router.executeActions(data);
}

function test_swapExactInputSingle_zeroForOne() public {
uint256 amountIn = 1 ether;
uint256 expectedAmountOut = 992054607780215625;
Expand Down Expand Up @@ -56,6 +72,22 @@ contract V4RouterTest is RoutingTestHelpers {
assertEq(outputBalanceAfter - outputBalanceBefore, expectedAmountOut);
}

function test_swapExactInput_revertsForAmountOut() public {
uint256 amountIn = 1 ether;
uint256 expectedAmountOut = 992054607780215625;

tokenPath.push(currency0);
tokenPath.push(currency1);
IV4Router.ExactInputParams memory params = _getExactInputParams(tokenPath, amountIn);
params.amountOutMinimum = uint128(expectedAmountOut + 1);

plan = plan.add(Actions.SWAP_EXACT_IN, abi.encode(params));
bytes memory data = plan.finalizeSwap(key0.currency0, key0.currency1, address(this));

vm.expectRevert(IV4Router.TooLittleReceived.selector);
router.executeActions(data);
}

function test_swapExactIn_1Hop_zeroForOne() public {
uint256 amountIn = 1 ether;
uint256 expectedAmountOut = 992054607780215625;
Expand Down Expand Up @@ -287,12 +319,28 @@ contract V4RouterTest is RoutingTestHelpers {
ERC20 -> ERC20 EXACT OUTPUT
//////////////////////////////////////////////////////////////*/

function test_swapExactOutputSingle_revertsForAmountIn() public {
uint256 amountOut = 1 ether;
uint256 expectedAmountIn = 1008049273448486163;

IV4Router.ExactOutputSingleParams memory params = IV4Router.ExactOutputSingleParams(
key0, true, uint128(amountOut), uint128(expectedAmountIn - 1), 0, bytes("")
);

plan = plan.add(Actions.SWAP_EXACT_OUT_SINGLE, abi.encode(params));
bytes memory data = plan.finalizeSwap(key0.currency0, key0.currency1, address(this));

vm.expectRevert(IV4Router.TooMuchRequested.selector);
router.executeActions(data);
}

function test_swapExactOutputSingle_zeroForOne() public {
uint256 amountOut = 1 ether;
uint256 expectedAmountIn = 1008049273448486163;

IV4Router.ExactOutputSingleParams memory params =
IV4Router.ExactOutputSingleParams(key0, true, uint128(amountOut), 0, 0, bytes(""));
IV4Router.ExactOutputSingleParams memory params = IV4Router.ExactOutputSingleParams(
key0, true, uint128(amountOut), uint128(expectedAmountIn + 1), 0, bytes("")
);

plan = plan.add(Actions.SWAP_EXACT_OUT_SINGLE, abi.encode(params));

Expand All @@ -310,8 +358,9 @@ contract V4RouterTest is RoutingTestHelpers {
uint256 amountOut = 1 ether;
uint256 expectedAmountIn = 1008049273448486163;

IV4Router.ExactOutputSingleParams memory params =
IV4Router.ExactOutputSingleParams(key0, false, uint128(amountOut), 0, 0, bytes(""));
IV4Router.ExactOutputSingleParams memory params = IV4Router.ExactOutputSingleParams(
key0, false, uint128(amountOut), uint128(expectedAmountIn + 1), 0, bytes("")
);

plan = plan.add(Actions.SWAP_EXACT_OUT_SINGLE, abi.encode(params));

Expand All @@ -325,6 +374,22 @@ contract V4RouterTest is RoutingTestHelpers {
assertEq(outputBalanceAfter - outputBalanceBefore, amountOut);
}

function test_swapExactOut_revertsForAmountIn() public {
uint256 amountOut = 1 ether;
uint256 expectedAmountIn = 1008049273448486163;

tokenPath.push(currency0);
tokenPath.push(currency1);
IV4Router.ExactOutputParams memory params = _getExactOutputParams(tokenPath, amountOut);
params.amountInMaximum = uint128(expectedAmountIn - 1);

plan = plan.add(Actions.SWAP_EXACT_OUT, abi.encode(params));
bytes memory data = plan.finalizeSwap(key0.currency0, key0.currency1, address(this));

vm.expectRevert(IV4Router.TooMuchRequested.selector);
router.executeActions(data);
}

function test_swapExactOut_1Hop_zeroForOne() public {
uint256 amountOut = 1 ether;
uint256 expectedAmountIn = 1008049273448486163;
Expand Down Expand Up @@ -422,8 +487,9 @@ contract V4RouterTest is RoutingTestHelpers {
uint256 amountOut = 1 ether;
uint256 expectedAmountIn = 1008049273448486163;

IV4Router.ExactOutputSingleParams memory params =
IV4Router.ExactOutputSingleParams(nativeKey, true, uint128(amountOut), 0, 0, bytes(""));
IV4Router.ExactOutputSingleParams memory params = IV4Router.ExactOutputSingleParams(
nativeKey, true, uint128(amountOut), uint128(expectedAmountIn + 1), 0, bytes("")
);

plan = plan.add(Actions.SWAP_EXACT_OUT_SINGLE, abi.encode(params));

Expand All @@ -441,8 +507,9 @@ contract V4RouterTest is RoutingTestHelpers {
uint256 amountOut = 1 ether;
uint256 expectedAmountIn = 1008049273448486163;

IV4Router.ExactOutputSingleParams memory params =
IV4Router.ExactOutputSingleParams(nativeKey, false, uint128(amountOut), 0, 0, bytes(""));
IV4Router.ExactOutputSingleParams memory params = IV4Router.ExactOutputSingleParams(
nativeKey, false, uint128(amountOut), uint128(expectedAmountIn + 1), 0, bytes("")
);

plan = plan.add(Actions.SWAP_EXACT_OUT_SINGLE, abi.encode(params));

Expand Down
Loading