mirror of
https://github.com/lux-amm/v4-periphery.git
synced 2026-10-30 20:54:39 +00:00
190 lines
8.5 KiB
Solidity
190 lines
8.5 KiB
Solidity
// SPDX-License-Identifier: UNLICENSED
|
|
pragma solidity ^0.8.19;
|
|
|
|
import {Currency} from "@luxamm/v4-core/src/types/Currency.sol";
|
|
|
|
import {IV4Router} from "../../src/interfaces/IV4Router.sol";
|
|
import {RoutingTestHelpers} from "../shared/RoutingTestHelpers.sol";
|
|
import {Planner} from "../shared/Planner.sol";
|
|
import {Actions} from "../../src/libraries/Actions.sol";
|
|
import {ActionConstants} from "../../src/libraries/ActionConstants.sol";
|
|
import {BipsLibrary} from "../../src/libraries/BipsLibrary.sol";
|
|
|
|
contract PaymentsTests is RoutingTestHelpers {
|
|
address bob = makeAddr("BOB");
|
|
|
|
function setUp() public {
|
|
setupRouterCurrenciesAndPoolsWithLiquidity();
|
|
plan = Planner.init();
|
|
}
|
|
|
|
function test_exactIn_settleAll_revertsSlippage() public {
|
|
uint256 amountIn = 1 ether;
|
|
IV4Router.ExactInputSingleParams memory params =
|
|
IV4Router.ExactInputSingleParams(key0, true, uint128(amountIn), 0, 0, bytes(""));
|
|
|
|
plan = plan.add(Actions.SWAP_EXACT_IN_SINGLE, abi.encode(params));
|
|
plan = plan.add(Actions.SETTLE_ALL, abi.encode(key0.currency0, amountIn - 1));
|
|
plan = plan.add(Actions.TAKE_ALL, abi.encode(key0.currency0, MIN_TAKE_AMOUNT));
|
|
|
|
bytes memory data = plan.encode();
|
|
vm.expectRevert(abi.encodeWithSelector(IV4Router.V4TooMuchRequested.selector, amountIn - 1, amountIn));
|
|
router.executeActions(data);
|
|
}
|
|
|
|
function test_exactIn_takeAll_revertsSlippage() public {
|
|
uint256 amountIn = 1 ether;
|
|
uint256 expectedAmountOut = 992054607780215625;
|
|
IV4Router.ExactInputSingleParams memory params =
|
|
IV4Router.ExactInputSingleParams(key0, true, uint128(amountIn), 0, 0, bytes(""));
|
|
|
|
plan = plan.add(Actions.SWAP_EXACT_IN_SINGLE, abi.encode(params));
|
|
plan = plan.add(Actions.SETTLE_ALL, abi.encode(key0.currency0, MAX_SETTLE_AMOUNT));
|
|
plan = plan.add(Actions.TAKE_ALL, abi.encode(key0.currency1, expectedAmountOut + 1));
|
|
|
|
bytes memory data = plan.encode();
|
|
vm.expectRevert(
|
|
abi.encodeWithSelector(IV4Router.V4TooLittleReceived.selector, expectedAmountOut + 1, expectedAmountOut)
|
|
);
|
|
router.executeActions(data);
|
|
}
|
|
|
|
function test_exactOut_settleAll_revertsSlippage() public {
|
|
uint256 amountOut = 1 ether;
|
|
uint256 expectedAmountIn = 1008049273448486163;
|
|
|
|
IV4Router.ExactOutputSingleParams memory params =
|
|
IV4Router.ExactOutputSingleParams(key0, true, uint128(amountOut), uint128(expectedAmountIn), 0, bytes(""));
|
|
|
|
plan = plan.add(Actions.SWAP_EXACT_OUT_SINGLE, abi.encode(params));
|
|
plan = plan.add(Actions.SETTLE_ALL, abi.encode(key0.currency0, expectedAmountIn - 1));
|
|
plan = plan.add(Actions.TAKE_ALL, abi.encode(key0.currency0, MIN_TAKE_AMOUNT));
|
|
|
|
bytes memory data = plan.encode();
|
|
vm.expectRevert(
|
|
abi.encodeWithSelector(IV4Router.V4TooMuchRequested.selector, expectedAmountIn - 1, expectedAmountIn)
|
|
);
|
|
router.executeActions(data);
|
|
}
|
|
|
|
function test_exactOut_takeAll_revertsSlippage() public {
|
|
uint256 amountOut = 1 ether;
|
|
uint256 expectedAmountIn = 1008049273448486163;
|
|
|
|
IV4Router.ExactOutputSingleParams memory params =
|
|
IV4Router.ExactOutputSingleParams(key0, true, uint128(amountOut), uint128(expectedAmountIn), 0, bytes(""));
|
|
|
|
plan = plan.add(Actions.SWAP_EXACT_OUT_SINGLE, abi.encode(params));
|
|
plan = plan.add(Actions.SETTLE_ALL, abi.encode(key0.currency0, MAX_SETTLE_AMOUNT));
|
|
plan = plan.add(Actions.TAKE_ALL, abi.encode(key0.currency1, amountOut + 1));
|
|
|
|
bytes memory data = plan.encode();
|
|
vm.expectRevert(abi.encodeWithSelector(IV4Router.V4TooLittleReceived.selector, amountOut + 1, amountOut));
|
|
router.executeActions(data);
|
|
}
|
|
|
|
function test_exactOut_takeAll_settleAll_succeedsExactAmount() public {
|
|
uint256 amountOut = 1 ether;
|
|
uint256 expectedAmountIn = 1008049273448486163;
|
|
|
|
IV4Router.ExactOutputSingleParams memory params =
|
|
IV4Router.ExactOutputSingleParams(key0, true, uint128(amountOut), uint128(expectedAmountIn), 0, bytes(""));
|
|
|
|
plan = plan.add(Actions.SWAP_EXACT_OUT_SINGLE, abi.encode(params));
|
|
plan = plan.add(Actions.SETTLE_ALL, abi.encode(key0.currency0, expectedAmountIn));
|
|
plan = plan.add(Actions.TAKE_ALL, abi.encode(key0.currency1, amountOut));
|
|
|
|
bytes memory data = plan.encode();
|
|
router.executeActions(data);
|
|
}
|
|
|
|
function test_settleFromRouter_takeAll() public {
|
|
uint256 amountIn = 1 ether;
|
|
uint256 expectedAmountOut = 992054607780215625;
|
|
IV4Router.ExactInputSingleParams memory params =
|
|
IV4Router.ExactInputSingleParams(key0, true, uint128(amountIn), 0, 0, bytes(""));
|
|
|
|
// seed the router with tokens
|
|
key0.currency0.transfer(address(router), amountIn);
|
|
|
|
uint256 inputBalanceBefore = key0.currency0.balanceOfSelf();
|
|
uint256 outputBalanceBefore = key0.currency1.balanceOfSelf();
|
|
|
|
// seeded tokens are in the router
|
|
assertEq(currency0.balanceOf(address(router)), amountIn);
|
|
assertEq(currency1.balanceOf(address(router)), 0);
|
|
|
|
plan = plan.add(Actions.SWAP_EXACT_IN_SINGLE, abi.encode(params));
|
|
plan = plan.add(Actions.SETTLE, abi.encode(key0.currency0, ActionConstants.CONTRACT_BALANCE, false));
|
|
plan = plan.add(Actions.TAKE_ALL, abi.encode(key0.currency1, MIN_TAKE_AMOUNT));
|
|
|
|
bytes memory data = plan.encode();
|
|
router.executeActions(data);
|
|
|
|
uint256 inputBalanceAfter = key0.currency0.balanceOfSelf();
|
|
uint256 outputBalanceAfter = key0.currency1.balanceOfSelf();
|
|
|
|
// router is empty
|
|
assertEq(currency0.balanceOf(address(router)), 0);
|
|
assertEq(currency1.balanceOf(address(router)), 0);
|
|
// callers input balance didnt change, but output balance did
|
|
assertEq(inputBalanceBefore, inputBalanceAfter);
|
|
assertEq(outputBalanceAfter - outputBalanceBefore, expectedAmountOut);
|
|
}
|
|
|
|
function test_settle_takePortion_takeAll() public {
|
|
uint256 amountIn = 1 ether;
|
|
uint256 expectedAmountOut = 992054607780215625;
|
|
IV4Router.ExactInputSingleParams memory params =
|
|
IV4Router.ExactInputSingleParams(key0, true, uint128(amountIn), 0, 0, bytes(""));
|
|
|
|
plan = plan.add(Actions.SWAP_EXACT_IN_SINGLE, abi.encode(params));
|
|
plan = plan.add(Actions.SETTLE, abi.encode(key0.currency0, amountIn, true));
|
|
// take 15 bips to Bob
|
|
plan = plan.add(Actions.TAKE_PORTION, abi.encode(key0.currency1, bob, 15));
|
|
plan = plan.add(Actions.TAKE_ALL, abi.encode(key0.currency1, 0));
|
|
|
|
uint256 inputBalanceBefore = key0.currency0.balanceOfSelf();
|
|
uint256 outputBalanceBefore = key0.currency1.balanceOfSelf();
|
|
uint256 bobBalanceBefore = key0.currency1.balanceOf(bob);
|
|
|
|
// router is empty before
|
|
assertEq(currency0.balanceOf(address(router)), 0);
|
|
assertEq(currency1.balanceOf(address(router)), 0);
|
|
|
|
bytes memory data = plan.encode();
|
|
router.executeActions(data);
|
|
|
|
uint256 inputBalanceAfter = key0.currency0.balanceOfSelf();
|
|
uint256 outputBalanceAfter = key0.currency1.balanceOfSelf();
|
|
uint256 bobBalanceAfter = key0.currency1.balanceOf(bob);
|
|
|
|
uint256 expectedFee = expectedAmountOut * 15 / BipsLibrary.BPS_DENOMINATOR;
|
|
|
|
// router is empty
|
|
assertEq(currency0.balanceOf(address(router)), 0);
|
|
assertEq(currency1.balanceOf(address(router)), 0);
|
|
// Bob got expectedFee, and the caller got the rest of the output
|
|
assertEq(inputBalanceBefore - inputBalanceAfter, amountIn);
|
|
assertEq(outputBalanceAfter - outputBalanceBefore, expectedAmountOut - expectedFee);
|
|
assertEq(bobBalanceAfter - bobBalanceBefore, expectedFee);
|
|
}
|
|
|
|
function test_settle_takePortion_reverts() public {
|
|
uint256 amountIn = 1 ether;
|
|
IV4Router.ExactInputSingleParams memory params =
|
|
IV4Router.ExactInputSingleParams(key0, true, uint128(amountIn), 0, 0, bytes(""));
|
|
|
|
plan = plan.add(Actions.SWAP_EXACT_IN_SINGLE, abi.encode(params));
|
|
plan = plan.add(Actions.SETTLE, abi.encode(key0.currency0, amountIn, true));
|
|
// bips is larger than maximum bips
|
|
plan = plan.add(Actions.TAKE_PORTION, abi.encode(key0.currency1, bob, BipsLibrary.BPS_DENOMINATOR + 1));
|
|
plan = plan.add(Actions.TAKE_ALL, abi.encode(key0.currency1, 0));
|
|
|
|
bytes memory data = plan.encode();
|
|
|
|
vm.expectRevert(BipsLibrary.InvalidBips.selector);
|
|
router.executeActions(data);
|
|
}
|
|
}
|