feat: No more fee taking

- This required an extra transfer into the router at the end of the swap sequence, costing an unnecessary 40k gas or more for certain protocols.
This commit is contained in:
TAMARA LIPOWSKI
2025-04-11 23:36:20 -04:00
committed by Diana Carvalho
parent 5fe2c2715c
commit 6f2e5ac10e
7 changed files with 6 additions and 242 deletions

View File

@@ -76,8 +76,6 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
//keccak256("NAME_OF_ROLE") : save gas on deployment //keccak256("NAME_OF_ROLE") : save gas on deployment
bytes32 public constant EXECUTOR_SETTER_ROLE = bytes32 public constant EXECUTOR_SETTER_ROLE =
0x6a1dd52dcad5bd732e45b6af4e7344fa284e2d7d4b23b5b09cb55d36b0685c87; 0x6a1dd52dcad5bd732e45b6af4e7344fa284e2d7d4b23b5b09cb55d36b0685c87;
bytes32 public constant FEE_SETTER_ROLE =
0xe6ad9a47fbda1dc18de1eb5eeb7d935e5e81b4748f3cfc61e233e64f88182060;
bytes32 public constant PAUSER_ROLE = bytes32 public constant PAUSER_ROLE =
0x65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a; 0x65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a;
bytes32 public constant UNPAUSER_ROLE = bytes32 public constant UNPAUSER_ROLE =
@@ -85,19 +83,9 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
bytes32 public constant FUND_RESCUER_ROLE = bytes32 public constant FUND_RESCUER_ROLE =
0x912e45d663a6f4cc1d0491d8f046e06c616f40352565ea1cdb86a0e1aaefa41b; 0x912e45d663a6f4cc1d0491d8f046e06c616f40352565ea1cdb86a0e1aaefa41b;
address public feeReceiver;
// Fee should be expressed in basis points (1/100th of a percent)
// For example, 100 = 1%, 500 = 5%, 1000 = 10%
uint256 public fee;
event Withdrawal( event Withdrawal(
address indexed token, uint256 amount, address indexed receiver address indexed token, uint256 amount, address indexed receiver
); );
event FeeReceiverSet(
address indexed oldFeeReceiver, address indexed newFeeReceiver
);
event FeeSet(uint256 indexed oldFee, uint256 indexed newFee);
constructor(address _permit2, address weth) { constructor(address _permit2, address weth) {
if (_permit2 == address(0) || weth == address(0)) { if (_permit2 == address(0) || weth == address(0)) {
@@ -117,7 +105,6 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
* - If `wrapEth` is true, the contract wraps the provided native ETH into WETH and uses it as the sell token. * - If `wrapEth` is true, the contract wraps the provided native ETH into WETH and uses it as the sell token.
* - If `unwrapEth` is true, the contract converts the resulting WETH back into native ETH before sending it to the receiver. * - If `unwrapEth` is true, the contract converts the resulting WETH back into native ETH before sending it to the receiver.
* - Swaps are executed sequentially using the `_swap` function. * - Swaps are executed sequentially using the `_swap` function.
* - A fee is deducted from the output token if `fee > 0`, and the remaining amount is sent to the receiver.
* - Reverts with `TychoRouter__NegativeSlippage` if the output amount is less than `minAmountOut` and `minAmountOut` is greater than 0. * - Reverts with `TychoRouter__NegativeSlippage` if the output amount is less than `minAmountOut` and `minAmountOut` is greater than 0.
* *
* @param amountIn The input token amount to be swapped. * @param amountIn The input token amount to be swapped.
@@ -130,7 +117,7 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
* @param receiver The address to receive the output tokens. * @param receiver The address to receive the output tokens.
* @param swaps Encoded swap graph data containing details of each swap. * @param swaps Encoded swap graph data containing details of each swap.
* *
* @return amountOut The total amount of the output token received by the receiver, after deducting fees if applicable. * @return amountOut The total amount of the output token received by the receiver.
*/ */
function splitSwap( function splitSwap(
uint256 amountIn, uint256 amountIn,
@@ -171,7 +158,6 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
* - If `unwrapEth` is true, the contract converts the resulting WETH back into native ETH before sending it to the receiver. * - If `unwrapEth` is true, the contract converts the resulting WETH back into native ETH before sending it to the receiver.
* - For ERC20 tokens, Permit2 is used to approve and transfer tokens from the caller to the router. * - For ERC20 tokens, Permit2 is used to approve and transfer tokens from the caller to the router.
* - Swaps are executed sequentially using the `_swap` function. * - Swaps are executed sequentially using the `_swap` function.
* - A fee is deducted from the output token if `fee > 0`, and the remaining amount is sent to the receiver.
* - Reverts with `TychoRouter__NegativeSlippage` if the output amount is less than `minAmountOut` and `minAmountOut` is greater than 0. * - Reverts with `TychoRouter__NegativeSlippage` if the output amount is less than `minAmountOut` and `minAmountOut` is greater than 0.
* *
* @param amountIn The input token amount to be swapped. * @param amountIn The input token amount to be swapped.
@@ -186,7 +172,7 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
* @param signature A valid signature authorizing the Permit2 approval. Ignored if `wrapEth` is true. * @param signature A valid signature authorizing the Permit2 approval. Ignored if `wrapEth` is true.
* @param swaps Encoded swap graph data containing details of each swap. * @param swaps Encoded swap graph data containing details of each swap.
* *
* @return amountOut The total amount of the output token received by the receiver, after deducting fees if applicable. * @return amountOut The total amount of the output token received by the receiver.
*/ */
function splitSwapPermit2( function splitSwapPermit2(
uint256 amountIn, uint256 amountIn,
@@ -234,7 +220,6 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
* - If `wrapEth` is true, the contract wraps the provided native ETH into WETH and uses it as the sell token. * - If `wrapEth` is true, the contract wraps the provided native ETH into WETH and uses it as the sell token.
* - If `unwrapEth` is true, the contract converts the resulting WETH back into native ETH before sending it to the receiver. * - If `unwrapEth` is true, the contract converts the resulting WETH back into native ETH before sending it to the receiver.
* - Swaps are executed sequentially using the `_swap` function. * - Swaps are executed sequentially using the `_swap` function.
* - A fee is deducted from the output token if `fee > 0`, and the remaining amount is sent to the receiver.
* - Reverts with `TychoRouter__NegativeSlippage` if the output amount is less than `minAmountOut` and `minAmountOut` is greater than 0. * - Reverts with `TychoRouter__NegativeSlippage` if the output amount is less than `minAmountOut` and `minAmountOut` is greater than 0.
* *
* @param amountIn The input token amount to be swapped. * @param amountIn The input token amount to be swapped.
@@ -246,7 +231,7 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
* @param receiver The address to receive the output tokens. * @param receiver The address to receive the output tokens.
* @param swaps Encoded swap graph data containing details of each swap. * @param swaps Encoded swap graph data containing details of each swap.
* *
* @return amountOut The total amount of the output token received by the receiver, after deducting fees if applicable. * @return amountOut The total amount of the output token received by the receiver.
*/ */
function sequentialSwap( function sequentialSwap(
uint256 amountIn, uint256 amountIn,
@@ -280,7 +265,6 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
* - If `wrapEth` is true, the contract wraps the provided native ETH into WETH and uses it as the sell token. * - If `wrapEth` is true, the contract wraps the provided native ETH into WETH and uses it as the sell token.
* - If `unwrapEth` is true, the contract converts the resulting WETH back into native ETH before sending it to the receiver. * - If `unwrapEth` is true, the contract converts the resulting WETH back into native ETH before sending it to the receiver.
* - For ERC20 tokens, Permit2 is used to approve and transfer tokens from the caller to the router. * - For ERC20 tokens, Permit2 is used to approve and transfer tokens from the caller to the router.
* - A fee is deducted from the output token if `fee > 0`, and the remaining amount is sent to the receiver.
* - Reverts with `TychoRouter__NegativeSlippage` if the output amount is less than `minAmountOut` and `minAmountOut` is greater than 0. * - Reverts with `TychoRouter__NegativeSlippage` if the output amount is less than `minAmountOut` and `minAmountOut` is greater than 0.
* *
* @param amountIn The input token amount to be swapped. * @param amountIn The input token amount to be swapped.
@@ -294,7 +278,7 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
* @param signature A valid signature authorizing the Permit2 approval. Ignored if `wrapEth` is true. * @param signature A valid signature authorizing the Permit2 approval. Ignored if `wrapEth` is true.
* @param swaps Encoded swap graph data containing details of each swap. * @param swaps Encoded swap graph data containing details of each swap.
* *
* @return amountOut The total amount of the output token received by the receiver, after deducting fees if applicable. * @return amountOut The total amount of the output token received by the receiver.
*/ */
function sequentialSwapPermit2( function sequentialSwapPermit2(
uint256 amountIn, uint256 amountIn,
@@ -339,7 +323,6 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
* @dev * @dev
* - If `wrapEth` is true, the contract wraps the provided native ETH into WETH and uses it as the sell token. * - If `wrapEth` is true, the contract wraps the provided native ETH into WETH and uses it as the sell token.
* - If `unwrapEth` is true, the contract converts the resulting WETH back into native ETH before sending it to the receiver. * - If `unwrapEth` is true, the contract converts the resulting WETH back into native ETH before sending it to the receiver.
* - A fee is deducted from the output token if `fee > 0`, and the remaining amount is sent to the receiver.
* - Reverts with `TychoRouter__NegativeSlippage` if the output amount is less than `minAmountOut` and `minAmountOut` is greater than 0. * - Reverts with `TychoRouter__NegativeSlippage` if the output amount is less than `minAmountOut` and `minAmountOut` is greater than 0.
* *
* @param amountIn The input token amount to be swapped. * @param amountIn The input token amount to be swapped.
@@ -351,7 +334,7 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
* @param receiver The address to receive the output tokens. * @param receiver The address to receive the output tokens.
* @param swapData Encoded swap details. * @param swapData Encoded swap details.
* *
* @return amountOut The total amount of the output token received by the receiver, after deducting fees if applicable. * @return amountOut The total amount of the output token received by the receiver.
*/ */
function singleSwap( function singleSwap(
uint256 amountIn, uint256 amountIn,
@@ -385,7 +368,6 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
* - If `wrapEth` is true, the contract wraps the provided native ETH into WETH and uses it as the sell token. * - If `wrapEth` is true, the contract wraps the provided native ETH into WETH and uses it as the sell token.
* - If `unwrapEth` is true, the contract converts the resulting WETH back into native ETH before sending it to the receiver. * - If `unwrapEth` is true, the contract converts the resulting WETH back into native ETH before sending it to the receiver.
* - For ERC20 tokens, Permit2 is used to approve and transfer tokens from the caller to the router. * - For ERC20 tokens, Permit2 is used to approve and transfer tokens from the caller to the router.
* - A fee is deducted from the output token if `fee > 0`, and the remaining amount is sent to the receiver.
* - Reverts with `TychoRouter__NegativeSlippage` if the output amount is less than `minAmountOut` and `minAmountOut` is greater than 0. * - Reverts with `TychoRouter__NegativeSlippage` if the output amount is less than `minAmountOut` and `minAmountOut` is greater than 0.
* *
* @param amountIn The input token amount to be swapped. * @param amountIn The input token amount to be swapped.
@@ -399,7 +381,7 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
* @param signature A valid signature authorizing the Permit2 approval. Ignored if `wrapEth` is true. * @param signature A valid signature authorizing the Permit2 approval. Ignored if `wrapEth` is true.
* @param swapData Encoded swap details. * @param swapData Encoded swap details.
* *
* @return amountOut The total amount of the output token received by the receiver, after deducting fees if applicable. * @return amountOut The total amount of the output token received by the receiver.
*/ */
function singleSwapPermit2( function singleSwapPermit2(
uint256 amountIn, uint256 amountIn,
@@ -485,12 +467,6 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
); );
} }
if (fee > 0) {
uint256 feeAmount = (amountOut * fee) / 10000;
amountOut -= feeAmount;
IERC20(tokenOut).safeTransfer(feeReceiver, feeAmount);
}
if (amountOut < minAmountOut) { if (amountOut < minAmountOut) {
revert TychoRouter__NegativeSlippage(amountOut, minAmountOut); revert TychoRouter__NegativeSlippage(amountOut, minAmountOut);
} }
@@ -556,12 +532,6 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
); );
} }
if (fee > 0) {
uint256 feeAmount = (amountOut * fee) / 10000;
amountOut -= feeAmount;
IERC20(tokenOut).safeTransfer(feeReceiver, feeAmount);
}
if (amountOut < minAmountOut) { if (amountOut < minAmountOut) {
revert TychoRouter__NegativeSlippage(amountOut, minAmountOut); revert TychoRouter__NegativeSlippage(amountOut, minAmountOut);
} }
@@ -625,12 +595,6 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
); );
} }
if (fee > 0) {
uint256 feeAmount = (amountOut * fee) / 10000;
amountOut -= feeAmount;
IERC20(tokenOut).safeTransfer(feeReceiver, feeAmount);
}
if (amountOut < minAmountOut) { if (amountOut < minAmountOut) {
revert TychoRouter__NegativeSlippage(amountOut, minAmountOut); revert TychoRouter__NegativeSlippage(amountOut, minAmountOut);
} }
@@ -803,26 +767,6 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
_removeExecutor(target); _removeExecutor(target);
} }
/**
* @dev Allows setting the fee receiver.
*/
function setFeeReceiver(address newfeeReceiver)
external
onlyRole(FEE_SETTER_ROLE)
{
if (newfeeReceiver == address(0)) revert TychoRouter__AddressZero();
emit FeeReceiverSet(feeReceiver, newfeeReceiver);
feeReceiver = newfeeReceiver;
}
/**
* @dev Allows setting the fee.
*/
function setFee(uint256 newFee) external onlyRole(FEE_SETTER_ROLE) {
emit FeeSet(fee, newFee);
fee = newFee;
}
/** /**
* @dev Allows withdrawing any ERC20 funds if funds get stuck in case of a bug. * @dev Allows withdrawing any ERC20 funds if funds get stuck in case of a bug.
*/ */

View File

@@ -15,8 +15,6 @@ contract Constants is Test, BaseConstants {
address ADMIN = makeAddr("admin"); //admin=us address ADMIN = makeAddr("admin"); //admin=us
address BOB = makeAddr("bob"); //bob=someone!=us address BOB = makeAddr("bob"); //bob=someone!=us
address FUND_RESCUER = makeAddr("fundRescuer"); address FUND_RESCUER = makeAddr("fundRescuer");
address FEE_SETTER = makeAddr("feeSetter");
address FEE_RECEIVER = makeAddr("feeReceiver");
address EXECUTOR_SETTER = makeAddr("executorSetter"); address EXECUTOR_SETTER = makeAddr("executorSetter");
address ALICE = 0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2; address ALICE = 0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2;
uint256 ALICE_PK = uint256 ALICE_PK =

View File

@@ -10,8 +10,6 @@ import {SafeCallback} from "@uniswap/v4-periphery/src/base/SafeCallback.sol";
contract TychoRouterTest is TychoRouterTestSetup { contract TychoRouterTest is TychoRouterTestSetup {
bytes32 public constant EXECUTOR_SETTER_ROLE = bytes32 public constant EXECUTOR_SETTER_ROLE =
0x6a1dd52dcad5bd732e45b6af4e7344fa284e2d7d4b23b5b09cb55d36b0685c87; 0x6a1dd52dcad5bd732e45b6af4e7344fa284e2d7d4b23b5b09cb55d36b0685c87;
bytes32 public constant FEE_SETTER_ROLE =
0xe6ad9a47fbda1dc18de1eb5eeb7d935e5e81b4748f3cfc61e233e64f88182060;
bytes32 public constant PAUSER_ROLE = bytes32 public constant PAUSER_ROLE =
0x65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a; 0x65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a;
bytes32 public constant FUND_RESCUER_ROLE = bytes32 public constant FUND_RESCUER_ROLE =
@@ -133,32 +131,6 @@ contract TychoRouterTest is TychoRouterTestSetup {
vm.stopPrank(); vm.stopPrank();
} }
function testFeeSetting() public {
vm.startPrank(FEE_SETTER);
assertEq(tychoRouter.fee(), 0);
tychoRouter.setFee(100);
assertEq(tychoRouter.fee(), 100);
vm.stopPrank();
vm.startPrank(BOB);
vm.expectRevert();
tychoRouter.setFee(200);
vm.stopPrank();
}
function testFeeReceiverSetting() public {
vm.startPrank(FEE_SETTER);
assertEq(tychoRouter.feeReceiver(), address(0));
tychoRouter.setFeeReceiver(FEE_RECEIVER);
assertEq(tychoRouter.feeReceiver(), FEE_RECEIVER);
vm.stopPrank();
vm.startPrank(BOB);
vm.expectRevert();
tychoRouter.setFeeReceiver(FEE_RECEIVER);
vm.stopPrank();
}
function testPause() public { function testPause() public {
vm.startPrank(PAUSER); vm.startPrank(PAUSER);
assertEq(tychoRouter.paused(), false); assertEq(tychoRouter.paused(), false);

View File

@@ -8,9 +8,6 @@ import "./executors/UniswapV4Utils.sol";
import {SafeCallback} from "@uniswap/v4-periphery/src/base/SafeCallback.sol"; import {SafeCallback} from "@uniswap/v4-periphery/src/base/SafeCallback.sol";
contract TychoRouterSequentialSwapTest is TychoRouterTestSetup { contract TychoRouterSequentialSwapTest is TychoRouterTestSetup {
bytes32 public constant FEE_SETTER_ROLE =
0xe6ad9a47fbda1dc18de1eb5eeb7d935e5e81b4748f3cfc61e233e64f88182060;
function _getSequentialSwaps() internal view returns (bytes[] memory) { function _getSequentialSwaps() internal view returns (bytes[] memory) {
// Trade 1 WETH for USDC through DAI with 2 swaps on Uniswap V2 // Trade 1 WETH for USDC through DAI with 2 swaps on Uniswap V2
// 1 WETH -> DAI -> USDC // 1 WETH -> DAI -> USDC
@@ -181,49 +178,6 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup {
vm.stopPrank(); vm.stopPrank();
} }
function testSequentialSwapFee() public {
// Trade 1 WETH for USDC
// Takes 1% fee at the end
vm.startPrank(FEE_SETTER);
tychoRouter.setFee(100);
tychoRouter.setFeeReceiver(FEE_RECEIVER);
vm.stopPrank();
uint256 amountIn = 1 ether;
deal(WETH_ADDR, ALICE, amountIn);
vm.startPrank(ALICE);
(
IAllowanceTransfer.PermitSingle memory permitSingle,
bytes memory signature
) = handlePermit2Approval(WETH_ADDR, amountIn);
bytes[] memory swaps = _getSequentialSwaps();
uint256 amountOut = tychoRouter.sequentialSwapPermit2(
amountIn,
WETH_ADDR,
USDC_ADDR,
1000_000000,
false,
false,
ALICE,
permitSingle,
signature,
pleEncode(swaps)
);
uint256 expectedAmount = 2618213190;
assertEq(amountOut, expectedAmount);
uint256 usdcBalance = IERC20(USDC_ADDR).balanceOf(ALICE);
assertEq(usdcBalance, expectedAmount);
assertEq(IERC20(USDC_ADDR).balanceOf(FEE_RECEIVER), 26446597);
vm.stopPrank();
}
function testSequentialSwapWrapETH() public { function testSequentialSwapWrapETH() public {
uint256 amountIn = 1 ether; uint256 amountIn = 1 ether;
deal(ALICE, amountIn); deal(ALICE, amountIn);

View File

@@ -8,9 +8,6 @@ import "./executors/UniswapV4Utils.sol";
import {SafeCallback} from "@uniswap/v4-periphery/src/base/SafeCallback.sol"; import {SafeCallback} from "@uniswap/v4-periphery/src/base/SafeCallback.sol";
contract TychoRouterSingleSwapTest is TychoRouterTestSetup { contract TychoRouterSingleSwapTest is TychoRouterTestSetup {
bytes32 public constant FEE_SETTER_ROLE =
0xe6ad9a47fbda1dc18de1eb5eeb7d935e5e81b4748f3cfc61e233e64f88182060;
function testSingleSwapPermit2() public { function testSingleSwapPermit2() public {
// Trade 1 WETH for DAI with 1 swap on Uniswap V2 using Permit2 // Trade 1 WETH for DAI with 1 swap on Uniswap V2 using Permit2
// 1 WETH -> DAI // 1 WETH -> DAI
@@ -179,50 +176,6 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup {
); );
} }
function testSingleSwapFee() public {
// Trade 1 WETH for DAI with 1 swap on Uniswap V2
// Takes 1% fee at the end
vm.startPrank(FEE_SETTER);
tychoRouter.setFee(100);
tychoRouter.setFeeReceiver(FEE_RECEIVER);
vm.stopPrank();
uint256 amountIn = 1 ether;
deal(WETH_ADDR, ALICE, amountIn);
vm.startPrank(ALICE);
// Approve the tokenIn to be transferred to the router
IERC20(WETH_ADDR).approve(address(tychoRouterAddr), amountIn);
bytes memory protocolData = encodeUniswapV2Swap(
WETH_ADDR, WETH_DAI_POOL, tychoRouterAddr, false
);
bytes memory swap =
encodeSingleSwap(address(usv2Executor), protocolData);
uint256 minAmountOut = 2600 * 1e18;
uint256 amountOut = tychoRouter.singleSwap(
amountIn,
WETH_ADDR,
DAI_ADDR,
minAmountOut,
false,
false,
ALICE,
swap
);
uint256 expectedAmount = 2633283105570259262790;
assertEq(amountOut, expectedAmount);
uint256 usdcBalance = IERC20(DAI_ADDR).balanceOf(ALICE);
assertEq(usdcBalance, expectedAmount);
assertEq(IERC20(DAI_ADDR).balanceOf(FEE_RECEIVER), 26598819248184436997);
vm.stopPrank();
}
function testSingleSwapWrapETH() public { function testSingleSwapWrapETH() public {
uint256 amountIn = 1 ether; uint256 amountIn = 1 ether;
deal(ALICE, amountIn); deal(ALICE, amountIn);

View File

@@ -8,9 +8,6 @@ import "./executors/UniswapV4Utils.sol";
import {SafeCallback} from "@uniswap/v4-periphery/src/base/SafeCallback.sol"; import {SafeCallback} from "@uniswap/v4-periphery/src/base/SafeCallback.sol";
contract TychoRouterSplitSwapTest is TychoRouterTestSetup { contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
bytes32 public constant FEE_SETTER_ROLE =
0xe6ad9a47fbda1dc18de1eb5eeb7d935e5e81b4748f3cfc61e233e64f88182060;
function _getSplitSwaps() private view returns (bytes[] memory) { function _getSplitSwaps() private view returns (bytes[] memory) {
// Trade 1 WETH for USDC through DAI and WBTC with 4 swaps on Uniswap V2 // Trade 1 WETH for USDC through DAI and WBTC with 4 swaps on Uniswap V2
// -> DAI -> // -> DAI ->
@@ -223,59 +220,6 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
vm.stopPrank(); vm.stopPrank();
} }
function testSplitSwapFee() public {
// Trade 1 WETH for DAI with 1 swap on Uniswap V2
// Does permit2 token approval and transfer
// Takes fee at the end
vm.startPrank(FEE_SETTER);
tychoRouter.setFee(100);
tychoRouter.setFeeReceiver(FEE_RECEIVER);
vm.stopPrank();
uint256 amountIn = 1 ether;
deal(WETH_ADDR, ALICE, amountIn);
vm.startPrank(ALICE);
(
IAllowanceTransfer.PermitSingle memory permitSingle,
bytes memory signature
) = handlePermit2Approval(WETH_ADDR, amountIn);
bytes memory protocolData = encodeUniswapV2Swap(
WETH_ADDR, WETH_DAI_POOL, tychoRouterAddr, false
);
bytes memory swap = encodeSplitSwap(
uint8(0), uint8(1), uint24(0), address(usv2Executor), protocolData
);
bytes[] memory swaps = new bytes[](1);
swaps[0] = swap;
uint256 amountOut = tychoRouter.splitSwapPermit2(
amountIn,
WETH_ADDR,
DAI_ADDR,
2633283105570259262780,
false,
false,
2,
ALICE,
permitSingle,
signature,
pleEncode(swaps)
);
uint256 expectedAmount = 2633283105570259262790;
assertEq(amountOut, expectedAmount);
uint256 daiBalance = IERC20(DAI_ADDR).balanceOf(ALICE);
assertEq(daiBalance, expectedAmount);
assertEq(IERC20(DAI_ADDR).balanceOf(FEE_RECEIVER), 26598819248184436997);
vm.stopPrank();
}
function testSplitSwapWrapETH() public { function testSplitSwapWrapETH() public {
// Trade 1 ETH (and wrap it) for DAI with 1 swap on Uniswap V2 // Trade 1 ETH (and wrap it) for DAI with 1 swap on Uniswap V2

View File

@@ -78,7 +78,6 @@ contract TychoRouterTestSetup is Constants {
tychoRouter = new TychoRouterExposed(PERMIT2_ADDRESS, WETH_ADDR); tychoRouter = new TychoRouterExposed(PERMIT2_ADDRESS, WETH_ADDR);
tychoRouterAddr = address(tychoRouter); tychoRouterAddr = address(tychoRouter);
tychoRouter.grantRole(keccak256("FUND_RESCUER_ROLE"), FUND_RESCUER); tychoRouter.grantRole(keccak256("FUND_RESCUER_ROLE"), FUND_RESCUER);
tychoRouter.grantRole(keccak256("FEE_SETTER_ROLE"), FEE_SETTER);
tychoRouter.grantRole(keccak256("PAUSER_ROLE"), PAUSER); tychoRouter.grantRole(keccak256("PAUSER_ROLE"), PAUSER);
tychoRouter.grantRole(keccak256("UNPAUSER_ROLE"), UNPAUSER); tychoRouter.grantRole(keccak256("UNPAUSER_ROLE"), UNPAUSER);
tychoRouter.grantRole( tychoRouter.grantRole(