diff --git a/foundry/src/RestrictTransferFrom.sol b/foundry/src/RestrictTransferFrom.sol index 8e93529..4480a1d 100644 --- a/foundry/src/RestrictTransferFrom.sol +++ b/foundry/src/RestrictTransferFrom.sol @@ -4,6 +4,7 @@ pragma solidity ^0.8.26; import "@interfaces/IExecutor.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@permit2/src/interfaces/IAllowanceTransfer.sol"; +import "@openzeppelin/contracts/utils/Address.sol"; error RestrictTransferFrom__AddressZero(); error RestrictTransferFrom__ExceededTransferFromAllowance(); @@ -57,10 +58,10 @@ contract RestrictTransferFrom { ) internal { assembly { tstore(_TOKEN_IN_SLOT, tokenIn) - tstore(_AMOUNT_IN_SLOT, amountIn) + tstore(_AMOUNT_ALLOWED_SLOT, amountIn) tstore(_IS_PERMIT2_SLOT, isPermit2) tstore(_SENDER_SLOT, caller()) - tstore(_IS_TRANSFER_EXECUTED_SLOT, false) + tstore(_AMOUNT_SPENT_SLOT, 0) } } @@ -71,18 +72,20 @@ contract RestrictTransferFrom { address tokenIn, uint256 amount ) internal { - if (transferType == TransferType.TransferFrom){ + if (transferType == TransferType.TransferFrom) { bool isPermit2; address sender; bool isTransferExecuted; + uint256 amountSpent; + uint256 amountAllowed; assembly { tokenIn := tload(_TOKEN_IN_SLOT) - amountPermitted := tload(_AMOUNT_IN_SLOT) + amountAllowed := tload(_AMOUNT_ALLOWED_SLOT) isPermit2 := tload(_IS_PERMIT2_SLOT) sender := tload(_SENDER_SLOT) - amountSpent := tload(_IS_TRANSFER_EXECUTED_SLOT) + amountSpent := tload(_AMOUNT_SPENT_SLOT) } - if (amount + amountSpent > amountPermitted) { + if (amount + amountSpent > amountAllowed) { revert RestrictTransferFrom__ExceededTransferFromAllowance(); } assembly { diff --git a/foundry/src/TychoRouter.sol b/foundry/src/TychoRouter.sol index 1b84e99..46740bf 100644 --- a/foundry/src/TychoRouter.sol +++ b/foundry/src/TychoRouter.sol @@ -71,7 +71,7 @@ contract TychoRouter is Dispatcher, Pausable, ReentrancyGuard, -RestrictTransferFrom + RestrictTransferFrom { IWETH private immutable _weth; @@ -93,7 +93,9 @@ RestrictTransferFrom address indexed token, uint256 amount, address indexed receiver ); - constructor(address _permit2, address weth) RestrictTransferFrom(_permit2) { + constructor(address _permit2, address weth) + RestrictTransferFrom(_permit2) + { if (_permit2 == address(0) || weth == address(0)) { revert TychoRouter__AddressZero(); } @@ -121,8 +123,6 @@ RestrictTransferFrom * @param unwrapEth If true, unwraps the resulting WETH into native ETH and sends it to the receiver. * @param nTokens The total number of tokens involved in the swap graph (used to initialize arrays for internal calculations). * @param receiver The address to receive the output tokens. - * @param transferFromNeeded If true, the contract will transfer the input token from the caller to the router. - * Otherwise, assume funds are already in router or will be transferred later by the executors (This is the case for executors with callback). * @param swaps Encoded swap graph data containing details of each swap. * * @return amountOut The total amount of the output token received by the receiver. @@ -136,14 +136,11 @@ RestrictTransferFrom bool unwrapEth, uint256 nTokens, address receiver, - bool transferFromNeeded, bytes calldata swaps ) public payable whenNotPaused nonReentrant returns (uint256 amountOut) { uint256 initialBalanceTokenOut = _balanceOf(tokenOut, receiver); _tstoreTransferFromInfo(tokenIn, amountIn, false); - if (transferFromNeeded) { - _transfer(address(this)); - } + return _splitSwapChecked( amountIn, tokenIn, @@ -178,8 +175,6 @@ RestrictTransferFrom * @param unwrapEth If true, unwraps the resulting WETH into native ETH and sends it to the receiver. * @param nTokens The total number of tokens involved in the swap graph (used to initialize arrays for internal calculations). * @param receiver The address to receive the output tokens. - * @param transferFromNeeded If true, the contract will transfer the input token from the caller to the router. - * Otherwise, assume funds are already in router or will be transferred later by the executors (This is the case for executors with callback). * @param permitSingle A Permit2 structure containing token approval details for the input token. 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. @@ -195,7 +190,6 @@ RestrictTransferFrom bool unwrapEth, uint256 nTokens, address receiver, - bool transferFromNeeded, IAllowanceTransfer.PermitSingle calldata permitSingle, bytes calldata signature, bytes calldata swaps @@ -206,9 +200,6 @@ RestrictTransferFrom permit2.permit(msg.sender, permitSingle, signature); } _tstoreTransferFromInfo(tokenIn, amountIn, true); - if (transferFromNeeded) { - _transfer(address(this)); - } return _splitSwapChecked( amountIn, @@ -242,9 +233,6 @@ RestrictTransferFrom * @param wrapEth If true, wraps the input token (native ETH) into WETH. * @param unwrapEth If true, unwraps the resulting WETH into native ETH and sends it to the receiver. * @param receiver The address to receive the output tokens. - * @param transferFromNeeded If true, the contract will transfer the input token from the caller to the tokenInReceiver. - * Otherwise, assume funds are already in router or will be transferred later by the executors (This is the case for executors with callback). - * @param tokenInReceiver The address to receive the input tokens. This is used when `transferFromNeeded` is true. * @param swaps Encoded swap graph data containing details of each swap. * * @return amountOut The total amount of the output token received by the receiver. @@ -257,15 +245,11 @@ RestrictTransferFrom bool wrapEth, bool unwrapEth, address receiver, - bool transferFromNeeded, - address tokenInReceiver, bytes calldata swaps ) public payable whenNotPaused nonReentrant returns (uint256 amountOut) { uint256 initialBalanceTokenOut = _balanceOf(tokenOut, receiver); _tstoreTransferFromInfo(tokenIn, amountIn, false); - if (transferFromNeeded) { - _transfer(tokenInReceiver); - } + return _sequentialSwapChecked( amountIn, tokenIn, @@ -297,8 +281,6 @@ RestrictTransferFrom * @param wrapEth If true, wraps the input token (native ETH) into WETH. * @param unwrapEth If true, unwraps the resulting WETH into native ETH and sends it to the receiver. * @param receiver The address to receive the output tokens. - * @param transferFromNeeded If true, the contract will transfer the input token from the caller to the tokenInReceiver. - * Otherwise, assume funds are already in router or will be transferred later by the executors (This is the case for executors with callback). * @param tokenInReceiver The address to receive the input tokens. This is used when `transferFromNeeded` is true. * @param permitSingle A Permit2 structure containing token approval details for the input token. 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. @@ -313,8 +295,6 @@ RestrictTransferFrom bool wrapEth, bool unwrapEth, address receiver, - bool transferFromNeeded, - address tokenInReceiver, IAllowanceTransfer.PermitSingle calldata permitSingle, bytes calldata signature, bytes calldata swaps @@ -326,9 +306,7 @@ RestrictTransferFrom } _tstoreTransferFromInfo(tokenIn, amountIn, true); - if (transferFromNeeded) { - _transfer(tokenInReceiver); - } + return _sequentialSwapChecked( amountIn, tokenIn, @@ -358,8 +336,6 @@ RestrictTransferFrom * @param wrapEth If true, wraps the input token (native ETH) into WETH. * @param unwrapEth If true, unwraps the resulting WETH into native ETH and sends it to the receiver. * @param receiver The address to receive the output tokens. - * @param transferFromNeeded If true, the contract will transfer the input token from the caller to the tokenInReceiver. - * Otherwise, assume funds are already in router or will be transferred later by the executors (This is the case for executors with callback). * @param tokenInReceiver The address to receive the input tokens. This is used when `transferFromNeeded` is true. * @param swapData Encoded swap details. * * @return amountOut The total amount of the output token received by the receiver. @@ -372,15 +348,11 @@ RestrictTransferFrom bool wrapEth, bool unwrapEth, address receiver, - bool transferFromNeeded, - address tokenInReceiver, bytes calldata swapData ) public payable whenNotPaused nonReentrant returns (uint256 amountOut) { uint256 initialBalanceTokenOut = _balanceOf(tokenOut, receiver); _tstoreTransferFromInfo(tokenIn, amountIn, false); - if (transferFromNeeded) { - _transfer(tokenInReceiver); - } + return _singleSwap( amountIn, tokenIn, @@ -412,8 +384,6 @@ RestrictTransferFrom * @param wrapEth If true, wraps the input token (native ETH) into WETH. * @param unwrapEth If true, unwraps the resulting WETH into native ETH and sends it to the receiver. * @param receiver The address to receive the output tokens. - * @param transferFromNeeded If true, the contract will transfer the input token from the caller to the tokenInReceiver. - * Otherwise, assume funds are already in router or will be transferred later by the executors (This is the case for executors with callback). * @param tokenInReceiver The address to receive the input tokens. This is used when `transferFromNeeded` is true. * @param permitSingle A Permit2 structure containing token approval details for the input token. Ignored if `wrapEth` is true. * @param signature A valid signature authorizing the Permit2 approval. Ignored if `wrapEth` is true. * @param swapData Encoded swap details. @@ -428,8 +398,6 @@ RestrictTransferFrom bool wrapEth, bool unwrapEth, address receiver, - bool transferFromNeeded, - address tokenInReceiver, IAllowanceTransfer.PermitSingle calldata permitSingle, bytes calldata signature, bytes calldata swapData @@ -440,9 +408,7 @@ RestrictTransferFrom permit2.permit(msg.sender, permitSingle, signature); } _tstoreTransferFromInfo(tokenIn, amountIn, true); - if (transferFromNeeded) { - _transfer(tokenInReceiver); - } + return _singleSwap( amountIn, tokenIn, diff --git a/foundry/src/executors/BalancerV2Executor.sol b/foundry/src/executors/BalancerV2Executor.sol index 4ecb932..3fcf343 100644 --- a/foundry/src/executors/BalancerV2Executor.sol +++ b/foundry/src/executors/BalancerV2Executor.sol @@ -12,7 +12,7 @@ import {IAsset} from "@balancer-labs/v2-interfaces/contracts/vault/IAsset.sol"; import {IVault} from "@balancer-labs/v2-interfaces/contracts/vault/IVault.sol"; import {RestrictTransferFrom} from "../RestrictTransferFrom.sol"; - error BalancerV2Executor__InvalidDataLength(); +error BalancerV2Executor__InvalidDataLength(); contract BalancerV2Executor is IExecutor, RestrictTransferFrom { using SafeERC20 for IERC20; @@ -36,7 +36,7 @@ contract BalancerV2Executor is IExecutor, RestrictTransferFrom { TransferType transferType ) = _decodeData(data); - _transfer(address(this), transferType, tokenIn, givenAmount); + _transfer(address(this), transferType, address(tokenIn), givenAmount); if (approvalNeeded) { // slither-disable-next-line unused-return @@ -73,7 +73,8 @@ contract BalancerV2Executor is IExecutor, RestrictTransferFrom { IERC20 tokenOut, bytes32 poolId, address receiver, - bool approvalNeeded + bool approvalNeeded, + TransferType transferType ) { if (data.length != 93) { @@ -85,5 +86,6 @@ contract BalancerV2Executor is IExecutor, RestrictTransferFrom { poolId = bytes32(data[40:72]); receiver = address(bytes20(data[72:92])); approvalNeeded = data[92] != 0; + transferType = TransferType(uint8(data[93])); } } diff --git a/foundry/src/executors/CurveExecutor.sol b/foundry/src/executors/CurveExecutor.sol index 6f60e87..517db9b 100644 --- a/foundry/src/executors/CurveExecutor.sol +++ b/foundry/src/executors/CurveExecutor.sol @@ -6,7 +6,7 @@ import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts/utils/Address.sol"; import {RestrictTransferFrom} from "../RestrictTransferFrom.sol"; - error CurveExecutor__AddressZero(); +error CurveExecutor__AddressZero(); error CurveExecutor__InvalidDataLength(); interface CryptoPool { @@ -40,7 +40,9 @@ contract CurveExecutor is IExecutor, RestrictTransferFrom { address public immutable nativeToken; - constructor(address _nativeToken, address _permit2) RestrictTransferFrom(_permit2) { + constructor(address _nativeToken, address _permit2) + RestrictTransferFrom(_permit2) + { if (_nativeToken == address(0)) { revert CurveExecutor__AddressZero(); } diff --git a/foundry/src/executors/EkuboExecutor.sol b/foundry/src/executors/EkuboExecutor.sol index e619fa9..5c6d9f0 100644 --- a/foundry/src/executors/EkuboExecutor.sol +++ b/foundry/src/executors/EkuboExecutor.sol @@ -11,7 +11,7 @@ import {SafeTransferLib} from "@solady/utils/SafeTransferLib.sol"; import {LibBytes} from "@solady/utils/LibBytes.sol"; import {Config, EkuboPoolKey} from "@ekubo/types/poolKey.sol"; import {MAX_SQRT_RATIO, MIN_SQRT_RATIO} from "@ekubo/types/sqrtRatio.sol"; -import "../RestrictTransferFrom.sol"; +import {RestrictTransferFrom} from "../RestrictTransferFrom.sol"; import "@openzeppelin/contracts/utils/Address.sol"; contract EkuboExecutor is @@ -19,7 +19,7 @@ contract EkuboExecutor is ILocker, IPayer, ICallback, -RestrictTransferFrom + RestrictTransferFrom { error EkuboExecutor__InvalidDataLength(); error EkuboExecutor__CoreOnly(); @@ -166,11 +166,9 @@ RestrictTransferFrom return nextAmountIn; } - function _pay( - address token, - uint128 amount, - TransferType transferType - ) internal { + function _pay(address token, uint128 amount, TransferType transferType) + internal + { address target = address(core); if (token == NATIVE_TOKEN_ADDRESS) { @@ -198,7 +196,7 @@ RestrictTransferFrom address token = address(bytes20(payData[12:32])); // This arg is abi-encoded uint128 amount = uint128(bytes16(payData[32:48])); TransferType transferType = TransferType(uint8(payData[48])); - _transfer(core, transferType, token, amount); + _transfer(address(core), transferType, token, amount); } // To receive withdrawals from Core diff --git a/foundry/src/executors/MaverickV2Executor.sol b/foundry/src/executors/MaverickV2Executor.sol index 681f133..bded021 100644 --- a/foundry/src/executors/MaverickV2Executor.sol +++ b/foundry/src/executors/MaverickV2Executor.sol @@ -6,7 +6,7 @@ import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts/utils/Address.sol"; import {RestrictTransferFrom} from "../RestrictTransferFrom.sol"; - error MaverickV2Executor__InvalidDataLength(); +error MaverickV2Executor__InvalidDataLength(); error MaverickV2Executor__InvalidTarget(); error MaverickV2Executor__InvalidFactory(); @@ -15,7 +15,9 @@ contract MaverickV2Executor is IExecutor, RestrictTransferFrom { address public immutable factory; - constructor(address _factory, address _permit2) RestrictTransferFrom(_permit2) { + constructor(address _factory, address _permit2) + RestrictTransferFrom(_permit2) + { if (_factory == address(0)) { revert MaverickV2Executor__InvalidFactory(); } @@ -48,7 +50,7 @@ contract MaverickV2Executor is IExecutor, RestrictTransferFrom { tickLimit: tickLimit }); - _transfer(target, transferType, tokenIn, givenAmount); + _transfer(target, transferType, address(tokenIn), givenAmount); // slither-disable-next-line unused-return (, calculatedAmount) = pool.swap(receiver, swapParams, ""); diff --git a/foundry/src/executors/UniswapV2Executor.sol b/foundry/src/executors/UniswapV2Executor.sol index eea95e9..50e39a4 100644 --- a/foundry/src/executors/UniswapV2Executor.sol +++ b/foundry/src/executors/UniswapV2Executor.sol @@ -6,7 +6,7 @@ import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@uniswap-v2/contracts/interfaces/IUniswapV2Pair.sol"; import {RestrictTransferFrom} from "../RestrictTransferFrom.sol"; - error UniswapV2Executor__InvalidDataLength(); +error UniswapV2Executor__InvalidDataLength(); error UniswapV2Executor__InvalidTarget(); error UniswapV2Executor__InvalidFactory(); error UniswapV2Executor__InvalidInitCode(); @@ -78,7 +78,7 @@ contract UniswapV2Executor is IExecutor, RestrictTransferFrom { address target, address receiver, bool zeroForOne, - TransferType transferType, + TransferType transferType ) { if (data.length != 62) { diff --git a/foundry/src/executors/UniswapV3Executor.sol b/foundry/src/executors/UniswapV3Executor.sol index 6b792df..b35619e 100644 --- a/foundry/src/executors/UniswapV3Executor.sol +++ b/foundry/src/executors/UniswapV3Executor.sol @@ -51,7 +51,7 @@ contract UniswapV3Executor is IExecutor, ICallback, RestrictTransferFrom { address receiver, address target, bool zeroForOne, - uint8 transferType + TransferType transferType ) = _decodeData(data); _verifyPairAddress(tokenIn, tokenOut, fee, target); @@ -60,9 +60,8 @@ contract UniswapV3Executor is IExecutor, ICallback, RestrictTransferFrom { int256 amount1; IUniswapV3Pool pool = IUniswapV3Pool(target); - bytes memory callbackData = _makeV3CallbackData( - tokenIn, tokenOut, fee, transferType - ); + bytes memory callbackData = + _makeV3CallbackData(tokenIn, tokenOut, fee, transferType); { (amount0, amount1) = pool.swap( @@ -98,7 +97,7 @@ contract UniswapV3Executor is IExecutor, ICallback, RestrictTransferFrom { abi.decode(msgData[4:68], (int256, int256)); address tokenIn = address(bytes20(msgData[132:152])); - bool transferType = TransferType(uint8(msgData[175])); + TransferType transferType = TransferType(uint8(msgData[175])); verifyCallback(msgData[132:]); @@ -136,7 +135,7 @@ contract UniswapV3Executor is IExecutor, ICallback, RestrictTransferFrom { address receiver, address target, bool zeroForOne, - uint8 transferType + TransferType transferType ) { if (data.length != 85) { @@ -148,18 +147,16 @@ contract UniswapV3Executor is IExecutor, ICallback, RestrictTransferFrom { receiver = address(bytes20(data[43:63])); target = address(bytes20(data[63:83])); zeroForOne = uint8(data[83]) > 0; - transferType = uint8(data[84]); + transferType = TransferType(uint8(data[84])); } function _makeV3CallbackData( address tokenIn, address tokenOut, uint24 fee, - uint8 transferType + TransferType transferType ) internal pure returns (bytes memory) { - return abi.encodePacked( - tokenIn, tokenOut, fee, transferType - ); + return abi.encodePacked(tokenIn, tokenOut, fee, uint8(transferType)); } function _verifyPairAddress( diff --git a/foundry/src/executors/UniswapV4Executor.sol b/foundry/src/executors/UniswapV4Executor.sol index fea689e..e57797c 100644 --- a/foundry/src/executors/UniswapV4Executor.sol +++ b/foundry/src/executors/UniswapV4Executor.sol @@ -399,7 +399,7 @@ RestrictTransferFrom _transfer( address(poolManager), transferType, - address(currency), + Currency.unwrap(currency), amount ); // slither-disable-next-line unused-return diff --git a/foundry/test/TychoRouterProtocolIntegration.t.sol b/foundry/test/TychoRouterProtocolIntegration.t.sol index a7761d3..15d073d 100644 --- a/foundry/test/TychoRouterProtocolIntegration.t.sol +++ b/foundry/test/TychoRouterProtocolIntegration.t.sol @@ -26,8 +26,7 @@ contract TychoRouterTestProtocolIntegration is TychoRouterTestSetup { USDE_ADDR, USDT_ADDR, true, - true, // permit2 transferFrom to protocol - false, // transfer to protocol + RestrictTransferFrom.TransferType.TransferFrom, ALICE, pools ); @@ -43,8 +42,6 @@ contract TychoRouterTestProtocolIntegration is TychoRouterTestSetup { false, false, ALICE, - false, - address(0), permitSingle, signature, swap @@ -77,8 +74,7 @@ contract TychoRouterTestProtocolIntegration is TychoRouterTestSetup { USDE_ADDR, WBTC_ADDR, true, - true, // transferFrom to protocol - false, // transfer to protocol + RestrictTransferFrom.TransferType.TransferFrom, ALICE, pools ); @@ -89,16 +85,7 @@ contract TychoRouterTestProtocolIntegration is TychoRouterTestSetup { vm.startPrank(ALICE); IERC20(USDE_ADDR).approve(tychoRouterAddr, amountIn); tychoRouter.singleSwap( - amountIn, - USDE_ADDR, - WBTC_ADDR, - 118280, - false, - false, - ALICE, - false, - address(0), - swap + amountIn, USDE_ADDR, WBTC_ADDR, 118280, false, false, ALICE, swap ); assertEq(IERC20(WBTC_ADDR).balanceOf(ALICE), 118281); @@ -277,8 +264,7 @@ contract TychoRouterTestProtocolIntegration is TychoRouterTestSetup { ALICE, DAI_WETH_USV3, zeroForOne, - true, // permit2 transferFrom to protocol - false // transfer to protocol + RestrictTransferFrom.TransferType.TransferFrom ); bytes memory swap = encodeSingleSwap(address(usv3Executor), protocolData); @@ -291,8 +277,6 @@ contract TychoRouterTestProtocolIntegration is TychoRouterTestSetup { false, false, ALICE, - false, - address(0), permitSingle, signature, swap diff --git a/foundry/test/TychoRouterSequentialSwap.t.sol b/foundry/test/TychoRouterSequentialSwap.t.sol index 7a0459c..390e20a 100644 --- a/foundry/test/TychoRouterSequentialSwap.t.sol +++ b/foundry/test/TychoRouterSequentialSwap.t.sol @@ -22,7 +22,7 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup { WETH_DAI_POOL, DAI_USDC_POOL, // receiver (direct to next pool) false, - false // transfer to protocol from router + RestrictTransferFrom.TransferType.None // transfer to protocol from router ) ); @@ -34,7 +34,7 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup { DAI_USDC_POOL, ALICE, true, - false // transfer to protocol from router + RestrictTransferFrom.TransferType.None // transfer to protocol from router ) ); return swaps; @@ -60,8 +60,6 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup { false, false, ALICE, - true, - WETH_DAI_POOL, permitSingle, signature, pleEncode(swaps) @@ -89,8 +87,6 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup { false, false, ALICE, - true, - WETH_DAI_POOL, pleEncode(swaps) ); @@ -117,8 +113,6 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup { false, false, ALICE, - true, - WETH_DAI_POOL, pleEncode(swaps) ); } @@ -141,8 +135,6 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup { false, false, ALICE, - true, - WETH_DAI_POOL, pleEncode(swaps) ); } @@ -177,8 +169,6 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup { false, false, ALICE, - true, - WETH_DAI_POOL, permitSingle, signature, pleEncode(swaps) @@ -208,14 +198,24 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup { swaps[0] = encodeSequentialSwap( address(usv2Executor), encodeUniswapV2Swap( - WETH_ADDR, WETH_DAI_POOL, DAI_USDC_POOL, false, true + WETH_ADDR, + WETH_DAI_POOL, + DAI_USDC_POOL, + false, + RestrictTransferFrom.TransferType.Transfer ) ); // DAI -> USDC swaps[1] = encodeSequentialSwap( address(usv2Executor), - encodeUniswapV2Swap(DAI_ADDR, DAI_USDC_POOL, ALICE, true, false) + encodeUniswapV2Swap( + DAI_ADDR, + DAI_USDC_POOL, + ALICE, + true, + RestrictTransferFrom.TransferType.None + ) ); uint256 amountOut = tychoRouter.sequentialSwapPermit2{value: amountIn}( @@ -226,8 +226,6 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup { true, false, ALICE, - false, - address(0), emptyPermitSingle, "", pleEncode(swaps) @@ -260,7 +258,11 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup { swaps[0] = encodeSequentialSwap( address(usv2Executor), encodeUniswapV2Swap( - USDC_ADDR, DAI_USDC_POOL, tychoRouterAddr, false, false + USDC_ADDR, + DAI_USDC_POOL, + tychoRouterAddr, + false, + RestrictTransferFrom.TransferType.TransferFrom ) ); @@ -268,7 +270,11 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup { swaps[1] = encodeSequentialSwap( address(usv2Executor), encodeUniswapV2Swap( - DAI_ADDR, WETH_DAI_POOL, tychoRouterAddr, true, true + DAI_ADDR, + WETH_DAI_POOL, + tychoRouterAddr, + true, + RestrictTransferFrom.TransferType.Transfer ) ); @@ -280,8 +286,6 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup { false, true, ALICE, - true, - DAI_USDC_POOL, permitSingle, signature, pleEncode(swaps) @@ -307,8 +311,7 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup { tychoRouterAddr, USDC_WETH_USV3, true, - false, - true + RestrictTransferFrom.TransferType.Transfer ); bytes memory usdcWethV3Pool2OneZeroData = encodeUniswapV3Swap( @@ -317,8 +320,7 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup { tychoRouterAddr, USDC_WETH_USV3_2, false, - false, // permit2 transferFrom to protocol - true // transfer to protocol + RestrictTransferFrom.TransferType.Transfer ); bytes[] memory swaps = new bytes[](2); diff --git a/foundry/test/TychoRouterSingleSwap.t.sol b/foundry/test/TychoRouterSingleSwap.t.sol index 97e9468..ffc65e6 100644 --- a/foundry/test/TychoRouterSingleSwap.t.sol +++ b/foundry/test/TychoRouterSingleSwap.t.sol @@ -26,7 +26,7 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup { WETH_DAI_POOL, ALICE, false, - false // funds already in WETH_DAI_POOL, no transfer necessary + RestrictTransferFrom.TransferType.None // funds already in WETH_DAI_POOL, no transfer necessary ); bytes memory swap = @@ -40,8 +40,6 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup { false, false, ALICE, - true, // transferFrom to WETH_DAI_POOL - WETH_DAI_POOL, // receiver of input tokens permitSingle, signature, swap @@ -69,7 +67,7 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup { WETH_DAI_POOL, ALICE, false, - false // funds already in WETH_DAI_POOL, no transfer necessary + RestrictTransferFrom.TransferType.None // funds already in WETH_DAI_POOL, no transfer necessary ); bytes memory swap = @@ -84,8 +82,6 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup { false, false, ALICE, - true, - WETH_DAI_POOL, swap ); @@ -107,24 +103,20 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup { vm.startPrank(ALICE); IERC20(WETH_ADDR).approve(address(tychoRouterAddr), amountIn); - bytes memory protocolData = - encodeUniswapV2Swap(WETH_ADDR, WETH_DAI_POOL, ALICE, false, false); + bytes memory protocolData = encodeUniswapV2Swap( + WETH_ADDR, + WETH_DAI_POOL, + ALICE, + false, + RestrictTransferFrom.TransferType.None + ); bytes memory swap = encodeSingleSwap(address(usv2Executor), protocolData); vm.expectRevert(TychoRouter__UndefinedMinAmountOut.selector); tychoRouter.singleSwap( - amountIn, - WETH_ADDR, - DAI_ADDR, - 0, - false, - false, - ALICE, - true, - WETH_DAI_POOL, - swap + amountIn, WETH_ADDR, DAI_ADDR, 0, false, false, ALICE, swap ); } @@ -142,7 +134,7 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup { WETH_DAI_POOL, ALICE, false, - false // funds already in WETH_DAI_POOL, no transfer necessary + RestrictTransferFrom.TransferType.None // funds already in WETH_DAI_POOL, no transfer necessary ); bytes memory swap = @@ -158,8 +150,6 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup { false, false, ALICE, - true, - WETH_DAI_POOL, swap ); } @@ -179,7 +169,7 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup { WETH_DAI_POOL, ALICE, false, - false // funds already in WETH_DAI_POOL, no transfer necessary + RestrictTransferFrom.TransferType.None // funds already in WETH_DAI_POOL, no transfer necessary ); bytes memory swap = @@ -202,8 +192,6 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup { false, false, ALICE, - true, - WETH_DAI_POOL, swap ); } @@ -225,8 +213,13 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup { sigDeadline: 0 }); - bytes memory protocolData = - encodeUniswapV2Swap(WETH_ADDR, WETH_DAI_POOL, ALICE, false, true); + bytes memory protocolData = encodeUniswapV2Swap( + WETH_ADDR, + WETH_DAI_POOL, + ALICE, + false, + RestrictTransferFrom.TransferType.None + ); bytes memory swap = encodeSingleSwap(address(usv2Executor), protocolData); @@ -239,8 +232,6 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup { true, false, ALICE, - false, - tychoRouterAddr, emptyPermitSingle, "", swap @@ -266,7 +257,11 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup { ) = handlePermit2Approval(DAI_ADDR, tychoRouterAddr, amountIn); bytes memory protocolData = encodeUniswapV2Swap( - DAI_ADDR, WETH_DAI_POOL, tychoRouterAddr, true, false + DAI_ADDR, + WETH_DAI_POOL, + tychoRouterAddr, + true, + RestrictTransferFrom.TransferType.None ); bytes memory swap = @@ -280,8 +275,6 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup { false, true, ALICE, - true, // transferFrom to WETH_DAI_POOL - WETH_DAI_POOL, // receiver of input tokens permitSingle, signature, swap diff --git a/foundry/test/TychoRouterSplitSwap.t.sol b/foundry/test/TychoRouterSplitSwap.t.sol index 582490c..21d79de 100644 --- a/foundry/test/TychoRouterSplitSwap.t.sol +++ b/foundry/test/TychoRouterSplitSwap.t.sol @@ -23,7 +23,11 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { (0xffffff * 60) / 100, // 60% address(usv2Executor), encodeUniswapV2Swap( - WETH_ADDR, WETH_WBTC_POOL, tychoRouterAddr, false, true + WETH_ADDR, + WETH_WBTC_POOL, + tychoRouterAddr, + false, + RestrictTransferFrom.TransferType.Transfer ) ); // WBTC -> USDC @@ -32,7 +36,13 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { uint8(2), uint24(0), address(usv2Executor), - encodeUniswapV2Swap(WBTC_ADDR, USDC_WBTC_POOL, ALICE, true, true) + encodeUniswapV2Swap( + WBTC_ADDR, + USDC_WBTC_POOL, + ALICE, + true, + RestrictTransferFrom.TransferType.Transfer + ) ); // WETH -> DAI swaps[2] = encodeSplitSwap( @@ -41,7 +51,11 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { uint24(0), address(usv2Executor), encodeUniswapV2Swap( - WETH_ADDR, WETH_DAI_POOL, tychoRouterAddr, false, true + WETH_ADDR, + WETH_DAI_POOL, + tychoRouterAddr, + false, + RestrictTransferFrom.TransferType.Transfer ) ); @@ -51,7 +65,13 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { uint8(2), uint24(0), address(usv2Executor), - encodeUniswapV2Swap(DAI_ADDR, DAI_USDC_POOL, ALICE, true, true) + encodeUniswapV2Swap( + DAI_ADDR, + DAI_USDC_POOL, + ALICE, + true, + RestrictTransferFrom.TransferType.Transfer + ) ); return swaps; @@ -95,7 +115,6 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { false, 4, ALICE, - true, permitSingle, signature, pleEncode(swaps) @@ -125,7 +144,6 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { false, 4, ALICE, - true, pleEncode(swaps) ); @@ -154,7 +172,6 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { false, 4, ALICE, - true, pleEncode(swaps) ); vm.stopPrank(); @@ -180,7 +197,6 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { false, 2, ALICE, - true, pleEncode(swaps) ); @@ -218,7 +234,6 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { false, 4, ALICE, - true, permitSingle, signature, pleEncode(swaps) @@ -245,8 +260,13 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { spender: address(0), sigDeadline: 0 }); - bytes memory protocolData = - encodeUniswapV2Swap(WETH_ADDR, WETH_DAI_POOL, ALICE, false, true); + bytes memory protocolData = encodeUniswapV2Swap( + WETH_ADDR, + WETH_DAI_POOL, + ALICE, + false, + RestrictTransferFrom.TransferType.Transfer + ); bytes memory swap = encodeSplitSwap( uint8(0), uint8(1), uint24(0), address(usv2Executor), protocolData @@ -263,7 +283,6 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { false, 2, ALICE, - false, emptyPermitSingle, "", pleEncode(swaps) @@ -291,7 +310,11 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { ) = handlePermit2Approval(DAI_ADDR, tychoRouterAddr, amountIn); bytes memory protocolData = encodeUniswapV2Swap( - DAI_ADDR, WETH_DAI_POOL, tychoRouterAddr, true, true + DAI_ADDR, + WETH_DAI_POOL, + tychoRouterAddr, + true, + RestrictTransferFrom.TransferType.Transfer ); bytes memory swap = encodeSplitSwap( @@ -309,7 +332,6 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { true, 2, ALICE, - true, permitSingle, signature, pleEncode(swaps) @@ -349,8 +371,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { tychoRouterAddr, USDC_WETH_USV3, true, - false, // transferFrom swapper required - true // transfer from tycho router to protocol + RestrictTransferFrom.TransferType.Transfer ); bytes memory usdcWethV3Pool2ZeroOneData = encodeUniswapV3Swap( @@ -359,8 +380,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { tychoRouterAddr, USDC_WETH_USV3_2, true, - false, // transferFrom swapper required - true // transfer from tycho router to protocol + RestrictTransferFrom.TransferType.Transfer ); bytes memory wethUsdcV2OneZeroData = encodeUniswapV2Swap( @@ -368,7 +388,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { USDC_WETH_USV2, tychoRouterAddr, false, - true // transfer from tycho router to protocol + RestrictTransferFrom.TransferType.Transfer ); bytes[] memory swaps = new bytes[](3); @@ -424,8 +444,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { tychoRouterAddr, USDC_WETH_USV3, true, - true, // transferFrom swapper required - false // transfer from tycho router to protocol + RestrictTransferFrom.TransferType.Transfer ); bytes memory usdcWethV3Pool2ZeroOneData = encodeUniswapV3Swap( @@ -434,8 +453,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { tychoRouterAddr, USDC_WETH_USV3_2, true, - true, // transferFrom swapper required - false // transfer from tycho router to protocol + RestrictTransferFrom.TransferType.Transfer ); bytes[] memory swaps = new bytes[](2); @@ -465,7 +483,6 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { false, 2, ALICE, - false, pleEncode(swaps) ); vm.stopPrank(); @@ -488,7 +505,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { USDC_WETH_USV2, tychoRouterAddr, true, - true // transfer required + RestrictTransferFrom.TransferType.Transfer ); bytes memory usdcWethV3Pool1OneZeroData = encodeUniswapV3Swap( @@ -497,8 +514,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { tychoRouterAddr, USDC_WETH_USV3, false, - false, // transferFrom required - true // transfer required + RestrictTransferFrom.TransferType.Transfer ); bytes memory usdcWethV3Pool2OneZeroData = encodeUniswapV3Swap( @@ -507,8 +523,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { tychoRouterAddr, USDC_WETH_USV3_2, false, - false, // transferFrom required - true // transfer required + RestrictTransferFrom.TransferType.Transfer ); bytes[] memory swaps = new bytes[](3); @@ -547,7 +562,11 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup { deal(BASE_USDC, tychoRouterAddr, amountIn); bytes memory protocolData = encodeUniswapV2Swap( - BASE_USDC, USDC_MAG7_POOL, tychoRouterAddr, true, true + BASE_USDC, + USDC_MAG7_POOL, + tychoRouterAddr, + true, + RestrictTransferFrom.TransferType.Transfer ); bytes memory swap = encodeSplitSwap( diff --git a/foundry/test/TychoRouterTestSetup.sol b/foundry/test/TychoRouterTestSetup.sol index 31dd507..8086535 100644 --- a/foundry/test/TychoRouterTestSetup.sol +++ b/foundry/test/TychoRouterTestSetup.sol @@ -185,11 +185,10 @@ contract TychoRouterTestSetup is Constants, Permit2TestHelper, TestUtils { address target, address receiver, bool zero2one, - bool transferNeeded + RestrictTransferFrom.TransferType transferType ) internal pure returns (bytes memory) { - return abi.encodePacked( - tokenIn, target, receiver, zero2one, transferNeeded - ); + return + abi.encodePacked(tokenIn, target, receiver, zero2one, transferType); } function encodeUniswapV3Swap( @@ -198,8 +197,7 @@ contract TychoRouterTestSetup is Constants, Permit2TestHelper, TestUtils { address receiver, address target, bool zero2one, - bool transferFromNeeded, - bool transferNeeded + RestrictTransferFrom.TransferType transferType ) internal view returns (bytes memory) { IUniswapV3Pool pool = IUniswapV3Pool(target); return abi.encodePacked( @@ -209,8 +207,7 @@ contract TychoRouterTestSetup is Constants, Permit2TestHelper, TestUtils { receiver, target, zero2one, - transferFromNeeded, - transferNeeded + transferType ); } } diff --git a/foundry/test/executors/BalancerV2Executor.t.sol b/foundry/test/executors/BalancerV2Executor.t.sol index 46b2ffd..c087945 100644 --- a/foundry/test/executors/BalancerV2Executor.t.sol +++ b/foundry/test/executors/BalancerV2Executor.t.sol @@ -16,7 +16,8 @@ contract BalancerV2ExecutorExposed is BalancerV2Executor { IERC20 tokenOut, bytes32 poolId, address receiver, - bool needsApproval + bool needsApproval, + TransferType transferType ) { return _decodeData(data); @@ -40,7 +41,12 @@ contract BalancerV2ExecutorTest is Constants, TestUtils { function testDecodeParams() public view { bytes memory params = abi.encodePacked( - WETH_ADDR, BAL_ADDR, WETH_BAL_POOL_ID, address(2), true + WETH_ADDR, + BAL_ADDR, + WETH_BAL_POOL_ID, + address(2), + true, + RestrictTransferFrom.TransferType.None ); ( @@ -48,7 +54,8 @@ contract BalancerV2ExecutorTest is Constants, TestUtils { IERC20 tokenOut, bytes32 poolId, address receiver, - bool needsApproval + bool needsApproval, + RestrictTransferFrom.TransferType transferType ) = balancerV2Exposed.decodeParams(params); assertEq(address(tokenIn), WETH_ADDR); @@ -56,6 +63,9 @@ contract BalancerV2ExecutorTest is Constants, TestUtils { assertEq(poolId, WETH_BAL_POOL_ID); assertEq(receiver, address(2)); assertEq(needsApproval, true); + assertEq( + uint8(transferType), uint8(RestrictTransferFrom.TransferType.None) + ); } function testDecodeParamsInvalidDataLength() public { @@ -89,7 +99,8 @@ contract BalancerV2ExecutorTest is Constants, TestUtils { IERC20 tokenOut, bytes32 poolId, address receiver, - bool needsApproval + bool needsApproval, + RestrictTransferFrom.TransferType transferType ) = balancerV2Exposed.decodeParams(protocolData); assertEq(address(tokenIn), WETH_ADDR); @@ -97,6 +108,9 @@ contract BalancerV2ExecutorTest is Constants, TestUtils { assertEq(poolId, WETH_BAL_POOL_ID); assertEq(receiver, BOB); assertEq(needsApproval, true); + assertEq( + uint8(transferType), uint8(RestrictTransferFrom.TransferType.None) + ); } function testSwapIntegration() public { diff --git a/foundry/test/executors/CurveExecutor.t.sol b/foundry/test/executors/CurveExecutor.t.sol index 3d5621e..d8dab35 100644 --- a/foundry/test/executors/CurveExecutor.t.sol +++ b/foundry/test/executors/CurveExecutor.t.sol @@ -37,6 +37,7 @@ contract CurveExecutorExposed is CurveExecutor { int128 i, int128 j, bool tokenApprovalNeeded, + RestrictTransferFrom.TransferType transferType, address receiver ) { @@ -67,6 +68,7 @@ contract CurveExecutorTest is Test, Constants { uint8(2), uint8(0), true, + RestrictTransferFrom.TransferType.None, ALICE ); @@ -78,6 +80,7 @@ contract CurveExecutorTest is Test, Constants { int128 i, int128 j, bool tokenApprovalNeeded, + RestrictTransferFrom.TransferType transferType, address receiver ) = curveExecutorExposed.decodeData(data); @@ -88,6 +91,9 @@ contract CurveExecutorTest is Test, Constants { assertEq(i, 2); assertEq(j, 0); assertEq(tokenApprovalNeeded, true); + assertEq( + uint8(transferType), uint8(RestrictTransferFrom.TransferType.None) + ); assertEq(receiver, ALICE); } @@ -96,7 +102,14 @@ contract CurveExecutorTest is Test, Constants { uint256 amountIn = 1 ether; deal(DAI_ADDR, address(curveExecutorExposed), amountIn); - bytes memory data = _getData(DAI_ADDR, USDC_ADDR, TRIPOOL, 1, ALICE); + bytes memory data = _getData( + DAI_ADDR, + USDC_ADDR, + TRIPOOL, + 1, + ALICE, + RestrictTransferFrom.TransferType.None + ); uint256 amountOut = curveExecutorExposed.swap(amountIn, data); @@ -109,8 +122,14 @@ contract CurveExecutorTest is Test, Constants { uint256 amountIn = 1 ether; deal(address(curveExecutorExposed), amountIn); - bytes memory data = - _getData(ETH_ADDR_FOR_CURVE, STETH_ADDR, STETH_POOL, 1, ALICE); + bytes memory data = _getData( + ETH_ADDR_FOR_CURVE, + STETH_ADDR, + STETH_POOL, + 1, + ALICE, + RestrictTransferFrom.TransferType.None + ); uint256 amountOut = curveExecutorExposed.swap(amountIn, data); @@ -126,8 +145,14 @@ contract CurveExecutorTest is Test, Constants { uint256 amountIn = 1 ether; deal(WETH_ADDR, address(curveExecutorExposed), amountIn); - bytes memory data = - _getData(WETH_ADDR, WBTC_ADDR, TRICRYPTO2_POOL, 3, ALICE); + bytes memory data = _getData( + WETH_ADDR, + WBTC_ADDR, + TRICRYPTO2_POOL, + 3, + ALICE, + RestrictTransferFrom.TransferType.None + ); uint256 amountOut = curveExecutorExposed.swap(amountIn, data); @@ -140,7 +165,14 @@ contract CurveExecutorTest is Test, Constants { uint256 amountIn = 100 * 10 ** 6; deal(USDC_ADDR, address(curveExecutorExposed), amountIn); - bytes memory data = _getData(USDC_ADDR, SUSD_ADDR, SUSD_POOL, 1, ALICE); + bytes memory data = _getData( + USDC_ADDR, + SUSD_ADDR, + SUSD_POOL, + 1, + ALICE, + RestrictTransferFrom.TransferType.None + ); uint256 amountOut = curveExecutorExposed.swap(amountIn, data); @@ -153,8 +185,14 @@ contract CurveExecutorTest is Test, Constants { uint256 amountIn = 1 ether; deal(FRAX_ADDR, address(curveExecutorExposed), amountIn); - bytes memory data = - _getData(FRAX_ADDR, USDC_ADDR, FRAX_USDC_POOL, 1, ALICE); + bytes memory data = _getData( + FRAX_ADDR, + USDC_ADDR, + FRAX_USDC_POOL, + 1, + ALICE, + RestrictTransferFrom.TransferType.None + ); uint256 amountOut = curveExecutorExposed.swap(amountIn, data); @@ -167,8 +205,14 @@ contract CurveExecutorTest is Test, Constants { uint256 amountIn = 100 * 10 ** 6; deal(USDC_ADDR, address(curveExecutorExposed), amountIn); - bytes memory data = - _getData(USDC_ADDR, USDE_ADDR, USDE_USDC_POOL, 1, ALICE); + bytes memory data = _getData( + USDC_ADDR, + USDE_ADDR, + USDE_USDC_POOL, + 1, + ALICE, + RestrictTransferFrom.TransferType.None + ); uint256 amountOut = curveExecutorExposed.swap(amountIn, data); @@ -181,8 +225,14 @@ contract CurveExecutorTest is Test, Constants { uint256 amountIn = 100 * 10 ** 6; deal(DOLA_ADDR, address(curveExecutorExposed), amountIn); - bytes memory data = - _getData(DOLA_ADDR, FRAXPYUSD_POOL, DOLA_FRAXPYUSD_POOL, 1, ALICE); + bytes memory data = _getData( + DOLA_ADDR, + FRAXPYUSD_POOL, + DOLA_FRAXPYUSD_POOL, + 1, + ALICE, + RestrictTransferFrom.TransferType.None + ); uint256 amountOut = curveExecutorExposed.swap(amountIn, data); @@ -196,8 +246,14 @@ contract CurveExecutorTest is Test, Constants { uint256 initialBalance = address(ALICE).balance; // this address already has some ETH assigned to it deal(XYO_ADDR, address(curveExecutorExposed), amountIn); - bytes memory data = - _getData(XYO_ADDR, ETH_ADDR_FOR_CURVE, ETH_XYO_POOL, 2, ALICE); + bytes memory data = _getData( + XYO_ADDR, + ETH_ADDR_FOR_CURVE, + ETH_XYO_POOL, + 2, + ALICE, + RestrictTransferFrom.TransferType.None + ); uint256 amountOut = curveExecutorExposed.swap(amountIn, data); @@ -210,8 +266,14 @@ contract CurveExecutorTest is Test, Constants { uint256 amountIn = 1000 ether; deal(BSGG_ADDR, address(curveExecutorExposed), amountIn); - bytes memory data = - _getData(BSGG_ADDR, USDT_ADDR, BSGG_USDT_POOL, 2, ALICE); + bytes memory data = _getData( + BSGG_ADDR, + USDT_ADDR, + BSGG_USDT_POOL, + 2, + ALICE, + RestrictTransferFrom.TransferType.None + ); uint256 amountOut = curveExecutorExposed.swap(amountIn, data); @@ -224,8 +286,14 @@ contract CurveExecutorTest is Test, Constants { uint256 amountIn = 1 ether; deal(WETH_ADDR, address(curveExecutorExposed), amountIn); - bytes memory data = - _getData(WETH_ADDR, USDC_ADDR, TRICRYPTO_POOL, 2, ALICE); + bytes memory data = _getData( + WETH_ADDR, + USDC_ADDR, + TRICRYPTO_POOL, + 2, + ALICE, + RestrictTransferFrom.TransferType.None + ); uint256 amountOut = curveExecutorExposed.swap(amountIn, data); @@ -238,8 +306,14 @@ contract CurveExecutorTest is Test, Constants { uint256 amountIn = 1 ether; deal(UWU_ADDR, address(curveExecutorExposed), amountIn); - bytes memory data = - _getData(UWU_ADDR, WETH_ADDR, UWU_WETH_POOL, 2, ALICE); + bytes memory data = _getData( + UWU_ADDR, + WETH_ADDR, + UWU_WETH_POOL, + 2, + ALICE, + RestrictTransferFrom.TransferType.None + ); uint256 amountOut = curveExecutorExposed.swap(amountIn, data); @@ -252,8 +326,14 @@ contract CurveExecutorTest is Test, Constants { uint256 amountIn = 1 ether; deal(USDT_ADDR, address(curveExecutorExposed), amountIn); - bytes memory data = - _getData(USDT_ADDR, CRVUSD_ADDR, CRVUSD_USDT_POOL, 1, ALICE); + bytes memory data = _getData( + USDT_ADDR, + CRVUSD_ADDR, + CRVUSD_USDT_POOL, + 1, + ALICE, + RestrictTransferFrom.TransferType.None + ); uint256 amountOut = curveExecutorExposed.swap(amountIn, data); @@ -266,8 +346,14 @@ contract CurveExecutorTest is Test, Constants { uint256 amountIn = 100 * 10 ** 9; // 9 decimals deal(WTAO_ADDR, address(curveExecutorExposed), amountIn); - bytes memory data = - _getData(WTAO_ADDR, WSTTAO_ADDR, WSTTAO_WTAO_POOL, 1, ALICE); + bytes memory data = _getData( + WTAO_ADDR, + WSTTAO_ADDR, + WSTTAO_WTAO_POOL, + 1, + ALICE, + RestrictTransferFrom.TransferType.None + ); uint256 amountOut = curveExecutorExposed.swap(amountIn, data); @@ -280,7 +366,8 @@ contract CurveExecutorTest is Test, Constants { address tokenOut, address pool, uint8 poolType, - address receiver + address receiver, + RestrictTransferFrom.TransferType transferType ) internal view returns (bytes memory data) { (int128 i, int128 j) = _getIndexes(tokenIn, tokenOut, pool); data = abi.encodePacked( @@ -291,6 +378,7 @@ contract CurveExecutorTest is Test, Constants { uint8(uint256(uint128(i))), uint8(uint256(uint128(j))), true, + transferType, receiver ); } diff --git a/foundry/test/executors/EkuboExecutor.t.sol b/foundry/test/executors/EkuboExecutor.t.sol index b46e983..7fa3eb1 100644 --- a/foundry/test/executors/EkuboExecutor.t.sol +++ b/foundry/test/executors/EkuboExecutor.t.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.26; import "../TestUtils.sol"; import {Constants} from "../Constants.sol"; -import {EkuboExecutor} from "@src/executors/EkuboExecutor.sol"; +import "@src/executors/EkuboExecutor.sol"; import {ICore} from "@ekubo/interfaces/ICore.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {NATIVE_TOKEN_ADDRESS} from "@ekubo/math/constants.sol"; @@ -45,8 +45,7 @@ contract EkuboExecutorTest is Constants, TestUtils { uint256 usdcBalanceBeforeExecutor = USDC.balanceOf(address(executor)); bytes memory data = abi.encodePacked( - false, // transferFromNeeded (transfer user to core) - true, // transferNeeded (transfer from executor to core) + uint8(RestrictTransferFrom.TransferType.Transfer), // transfer type (transfer from executor to core) address(executor), // receiver NATIVE_TOKEN_ADDRESS, // tokenIn USDC_ADDR, // tokenOut @@ -83,8 +82,7 @@ contract EkuboExecutorTest is Constants, TestUtils { uint256 ethBalanceBeforeExecutor = address(executor).balance; bytes memory data = abi.encodePacked( - false, // transferFromNeeded (transfer user to core) - true, // transferNeeded (transfer from executor to core) + uint8(RestrictTransferFrom.TransferType.Transfer), // transferNeeded (transfer from executor to core) address(executor), // receiver USDC_ADDR, // tokenIn NATIVE_TOKEN_ADDRESS, // tokenOut @@ -142,8 +140,7 @@ contract EkuboExecutorTest is Constants, TestUtils { // Same test case as in swap_encoder::tests::ekubo::test_encode_swap_multi function testMultiHopSwap() public { bytes memory data = abi.encodePacked( - false, // transferFromNeeded (transfer user to core) - true, // transferNeeded (transfer from executor to core) + uint8(RestrictTransferFrom.TransferType.Transfer), // transferNeeded (transfer from executor to core) address(executor), // receiver NATIVE_TOKEN_ADDRESS, // tokenIn USDC_ADDR, // tokenOut of 1st swap diff --git a/foundry/test/executors/MaverickV2Executor.t.sol b/foundry/test/executors/MaverickV2Executor.t.sol index 241d265..9e4bbb3 100644 --- a/foundry/test/executors/MaverickV2Executor.t.sol +++ b/foundry/test/executors/MaverickV2Executor.t.sol @@ -17,7 +17,7 @@ contract MaverickV2ExecutorExposed is MaverickV2Executor { IERC20 tokenIn, address target, address receiver, - bool transferNeeded + RestrictTransferFrom.TransferType transferType ) { return _decodeData(data); @@ -39,16 +39,28 @@ contract MaverickV2ExecutorTest is TestUtils, Constants { } function testDecodeParams() public view { - bytes memory params = - abi.encodePacked(GHO_ADDR, GHO_USDC_POOL, address(2), true); + bytes memory params = abi.encodePacked( + GHO_ADDR, + GHO_USDC_POOL, + address(2), + true, + RestrictTransferFrom.TransferType.Transfer + ); - (IERC20 tokenIn, address target, address receiver, bool transferNeeded) - = maverickV2Exposed.decodeParams(params); + ( + IERC20 tokenIn, + address target, + address receiver, + RestrictTransferFrom.TransferType transferType + ) = maverickV2Exposed.decodeParams(params); assertEq(address(tokenIn), GHO_ADDR); assertEq(target, GHO_USDC_POOL); assertEq(receiver, address(2)); - assertEq(transferNeeded, true); + assertEq( + uint8(transferType), + uint8(RestrictTransferFrom.TransferType.Transfer) + ); } function testDecodeParamsInvalidDataLength() public { @@ -61,8 +73,12 @@ contract MaverickV2ExecutorTest is TestUtils, Constants { function testSwap() public { uint256 amountIn = 10e18; - bytes memory protocolData = - abi.encodePacked(GHO_ADDR, GHO_USDC_POOL, BOB, true); + bytes memory protocolData = abi.encodePacked( + GHO_ADDR, + GHO_USDC_POOL, + BOB, + RestrictTransferFrom.TransferType.Transfer + ); deal(GHO_ADDR, address(maverickV2Exposed), amountIn); uint256 balanceBefore = USDC.balanceOf(BOB); @@ -79,13 +95,20 @@ contract MaverickV2ExecutorTest is TestUtils, Constants { bytes memory protocolData = loadCallDataFromFile("test_encode_maverick_v2"); - (IERC20 tokenIn, address pool, address receiver, bool transferNeeded) = - maverickV2Exposed.decodeParams(protocolData); + ( + IERC20 tokenIn, + address pool, + address receiver, + RestrictTransferFrom.TransferType transferType + ) = maverickV2Exposed.decodeParams(protocolData); assertEq(address(tokenIn), GHO_ADDR); assertEq(pool, GHO_USDC_POOL); assertEq(receiver, BOB); - assertEq(transferNeeded, true); + assertEq( + uint8(transferType), + uint8(RestrictTransferFrom.TransferType.Transfer) + ); } function testSwapIntegration() public { diff --git a/foundry/test/executors/UniswapV2Executor.t.sol b/foundry/test/executors/UniswapV2Executor.t.sol index a6a34bd..a509877 100644 --- a/foundry/test/executors/UniswapV2Executor.t.sol +++ b/foundry/test/executors/UniswapV2Executor.t.sol @@ -23,7 +23,7 @@ contract UniswapV2ExecutorExposed is UniswapV2Executor { address target, address receiver, bool zeroForOne, - bool transferNeeded + RestrictTransferFrom.TransferType transferType ) { return _decodeData(data); @@ -82,22 +82,30 @@ contract UniswapV2ExecutorTest is Constants, Permit2TestHelper, TestUtils { } function testDecodeParams() public view { - bytes memory params = - abi.encodePacked(WETH_ADDR, address(2), address(3), false, true); + bytes memory params = abi.encodePacked( + WETH_ADDR, + address(2), + address(3), + false, + RestrictTransferFrom.TransferType.Transfer + ); ( IERC20 tokenIn, address target, address receiver, bool zeroForOne, - bool transferNeeded + RestrictTransferFrom.TransferType transferType ) = uniswapV2Exposed.decodeParams(params); assertEq(address(tokenIn), WETH_ADDR); assertEq(target, address(2)); assertEq(receiver, address(3)); assertEq(zeroForOne, false); - assertEq(transferNeeded, true); + assertEq( + uint8(transferType), + uint8(RestrictTransferFrom.TransferType.Transfer) + ); } function testDecodeParamsInvalidDataLength() public { @@ -148,8 +156,13 @@ contract UniswapV2ExecutorTest is Constants, Permit2TestHelper, TestUtils { uint256 amountIn = 10 ** 18; uint256 amountOut = 1847751195973566072891; bool zeroForOne = false; - bytes memory protocolData = - abi.encodePacked(WETH_ADDR, WETH_DAI_POOL, BOB, zeroForOne, true); + bytes memory protocolData = abi.encodePacked( + WETH_ADDR, + WETH_DAI_POOL, + BOB, + zeroForOne, + RestrictTransferFrom.TransferType.Transfer + ); deal(WETH_ADDR, address(uniswapV2Exposed), amountIn); uniswapV2Exposed.swap(amountIn, protocolData); @@ -162,8 +175,13 @@ contract UniswapV2ExecutorTest is Constants, Permit2TestHelper, TestUtils { uint256 amountIn = 10 ** 18; uint256 amountOut = 1847751195973566072891; bool zeroForOne = false; - bytes memory protocolData = - abi.encodePacked(WETH_ADDR, WETH_DAI_POOL, BOB, zeroForOne, false); + bytes memory protocolData = abi.encodePacked( + WETH_ADDR, + WETH_DAI_POOL, + BOB, + zeroForOne, + RestrictTransferFrom.TransferType.None + ); deal(WETH_ADDR, address(this), amountIn); IERC20(WETH_ADDR).transfer(address(WETH_DAI_POOL), amountIn); @@ -175,21 +193,24 @@ contract UniswapV2ExecutorTest is Constants, Permit2TestHelper, TestUtils { function testDecodeIntegration() public view { bytes memory protocolData = - hex"c02aaa39b223fe8d0a0e5c4f27ead9083c756cc288e6a0c2ddd26feeb64f039a2c41296fcb3f564000000000000000000000000000000000000000010000"; + hex"c02aaa39b223fe8d0a0e5c4f27ead9083c756cc288e6a0c2ddd26feeb64f039a2c41296fcb3f564000000000000000000000000000000000000000010001"; ( IERC20 tokenIn, address target, address receiver, bool zeroForOne, - bool transferNeeded + RestrictTransferFrom.TransferType transferType ) = uniswapV2Exposed.decodeParams(protocolData); assertEq(address(tokenIn), WETH_ADDR); assertEq(target, 0x88e6A0c2dDD26FEEb64F039a2c41296FcB3f5640); assertEq(receiver, 0x0000000000000000000000000000000000000001); assertEq(zeroForOne, false); - assertEq(transferNeeded, false); + assertEq( + uint8(transferType), + uint8(RestrictTransferFrom.TransferType.Transfer) + ); } function testSwapIntegration() public { @@ -208,8 +229,13 @@ contract UniswapV2ExecutorTest is Constants, Permit2TestHelper, TestUtils { uint256 amountIn = 10 ** 18; bool zeroForOne = false; address fakePool = address(new FakeUniswapV2Pool(WETH_ADDR, DAI_ADDR)); - bytes memory protocolData = - abi.encodePacked(WETH_ADDR, fakePool, BOB, zeroForOne, true); + bytes memory protocolData = abi.encodePacked( + WETH_ADDR, + fakePool, + BOB, + zeroForOne, + RestrictTransferFrom.TransferType.Transfer + ); deal(WETH_ADDR, address(uniswapV2Exposed), amountIn); vm.expectRevert(UniswapV2Executor__InvalidTarget.selector); @@ -223,8 +249,13 @@ contract UniswapV2ExecutorTest is Constants, Permit2TestHelper, TestUtils { vm.rollFork(26857267); uint256 amountIn = 10 * 10 ** 6; bool zeroForOne = true; - bytes memory protocolData = - abi.encodePacked(BASE_USDC, USDC_MAG7_POOL, BOB, zeroForOne, true); + bytes memory protocolData = abi.encodePacked( + BASE_USDC, + USDC_MAG7_POOL, + BOB, + zeroForOne, + RestrictTransferFrom.TransferType.Transfer + ); deal(BASE_USDC, address(uniswapV2Exposed), amountIn); diff --git a/foundry/test/executors/UniswapV3Executor.t.sol b/foundry/test/executors/UniswapV3Executor.t.sol index b3335d4..566f4c8 100644 --- a/foundry/test/executors/UniswapV3Executor.t.sol +++ b/foundry/test/executors/UniswapV3Executor.t.sol @@ -22,8 +22,7 @@ contract UniswapV3ExecutorExposed is UniswapV3Executor { address receiver, address target, bool zeroForOne, - bool transferFromNeeded, - bool transferNeeded + RestrictTransferFrom.TransferType transferType ) { return _decodeData(data); @@ -72,8 +71,7 @@ contract UniswapV3ExecutorTest is Test, Constants, Permit2TestHelper { address(2), address(3), false, - false, - true + RestrictTransferFrom.TransferType.Transfer ); ( @@ -83,8 +81,7 @@ contract UniswapV3ExecutorTest is Test, Constants, Permit2TestHelper { address receiver, address target, bool zeroForOne, - bool transferFromNeeded, - bool transferNeeded + RestrictTransferFrom.TransferType transferType ) = uniswapV3Exposed.decodeData(data); assertEq(tokenIn, WETH_ADDR); @@ -93,8 +90,10 @@ contract UniswapV3ExecutorTest is Test, Constants, Permit2TestHelper { assertEq(receiver, address(2)); assertEq(target, address(3)); assertEq(zeroForOne, false); - assertEq(transferFromNeeded, false); - assertEq(transferNeeded, true); + assertEq( + uint8(transferType), + uint8(RestrictTransferFrom.TransferType.Transfer) + ); } function testSwapIntegration() public { @@ -110,8 +109,7 @@ contract UniswapV3ExecutorTest is Test, Constants, Permit2TestHelper { address(this), DAI_WETH_USV3, zeroForOne, - false, - true + RestrictTransferFrom.TransferType.Transfer ); uint256 amountOut = uniswapV3Exposed.swap(amountIn, data); @@ -149,7 +147,11 @@ contract UniswapV3ExecutorTest is Test, Constants, Permit2TestHelper { vm.startPrank(DAI_WETH_USV3); bytes memory protocolData = abi.encodePacked( - WETH_ADDR, DAI_ADDR, poolFee, false, true, address(uniswapV3Exposed) + WETH_ADDR, + DAI_ADDR, + poolFee, + RestrictTransferFrom.TransferType.Transfer, + address(uniswapV3Exposed) ); uint256 dataOffset = 3; // some offset uint256 dataLength = protocolData.length; @@ -182,8 +184,7 @@ contract UniswapV3ExecutorTest is Test, Constants, Permit2TestHelper { address(this), fakePool, zeroForOne, - false, - true + RestrictTransferFrom.TransferType.Transfer ); vm.expectRevert(UniswapV3Executor__InvalidTarget.selector); @@ -196,8 +197,7 @@ contract UniswapV3ExecutorTest is Test, Constants, Permit2TestHelper { address receiver, address target, bool zero2one, - bool transferFromNeeded, - bool transferNeeded + RestrictTransferFrom.TransferType transferType ) internal view returns (bytes memory) { IUniswapV3Pool pool = IUniswapV3Pool(target); return abi.encodePacked( @@ -207,8 +207,7 @@ contract UniswapV3ExecutorTest is Test, Constants, Permit2TestHelper { receiver, target, zero2one, - transferFromNeeded, - transferNeeded + transferType ); } } diff --git a/foundry/test/executors/UniswapV4Executor.t.sol b/foundry/test/executors/UniswapV4Executor.t.sol index d2918a0..21c39cc 100644 --- a/foundry/test/executors/UniswapV4Executor.t.sol +++ b/foundry/test/executors/UniswapV4Executor.t.sol @@ -21,8 +21,7 @@ contract UniswapV4ExecutorExposed is UniswapV4Executor { address tokenIn, address tokenOut, bool zeroForOne, - bool transferFromNeeded, - bool transferNeeded, + RestrictTransferFrom.TransferType transferType, address receiver, UniswapV4Pool[] memory pools ) @@ -53,8 +52,6 @@ contract UniswapV4ExecutorTest is Constants, TestUtils { int24 tickSpacing1 = 60; uint24 pool2Fee = 1000; int24 tickSpacing2 = -10; - bool transferFromNeeded = false; - bool transferNeeded = true; UniswapV4Executor.UniswapV4Pool[] memory pools = new UniswapV4Executor.UniswapV4Pool[](2); @@ -73,8 +70,7 @@ contract UniswapV4ExecutorTest is Constants, TestUtils { USDE_ADDR, USDT_ADDR, zeroForOne, - transferFromNeeded, - transferNeeded, + RestrictTransferFrom.TransferType.Transfer, ALICE, pools ); @@ -83,8 +79,7 @@ contract UniswapV4ExecutorTest is Constants, TestUtils { address tokenIn, address tokenOut, bool zeroForOneDecoded, - bool transferFromNeededDecoded, - bool transferNeededDecoded, + RestrictTransferFrom.TransferType transferType, address receiver, UniswapV4Executor.UniswapV4Pool[] memory decodedPools ) = uniswapV4Exposed.decodeData(data); @@ -92,8 +87,10 @@ contract UniswapV4ExecutorTest is Constants, TestUtils { assertEq(tokenIn, USDE_ADDR); assertEq(tokenOut, USDT_ADDR); assertEq(zeroForOneDecoded, zeroForOne); - assertEq(transferFromNeededDecoded, transferFromNeeded); - assertEq(transferNeededDecoded, transferNeeded); + assertEq( + uint8(transferType), + uint8(RestrictTransferFrom.TransferType.Transfer) + ); assertEq(receiver, ALICE); assertEq(decodedPools.length, 2); assertEq(decodedPools[0].intermediaryToken, USDT_ADDR); @@ -120,7 +117,12 @@ contract UniswapV4ExecutorTest is Constants, TestUtils { }); bytes memory data = UniswapV4Utils.encodeExactInput( - USDE_ADDR, USDT_ADDR, true, false, true, ALICE, pools + USDE_ADDR, + USDT_ADDR, + true, + RestrictTransferFrom.TransferType.Transfer, + ALICE, + pools ); uint256 amountOut = uniswapV4Exposed.swap(amountIn, data); @@ -172,7 +174,12 @@ contract UniswapV4ExecutorTest is Constants, TestUtils { }); bytes memory data = UniswapV4Utils.encodeExactInput( - USDE_ADDR, WBTC_ADDR, true, false, true, ALICE, pools + USDE_ADDR, + WBTC_ADDR, + true, + RestrictTransferFrom.TransferType.Transfer, + ALICE, + pools ); uint256 amountOut = uniswapV4Exposed.swap(amountIn, data); diff --git a/foundry/test/executors/UniswapV4Utils.sol b/foundry/test/executors/UniswapV4Utils.sol index 6746ebe..c280fcb 100644 --- a/foundry/test/executors/UniswapV4Utils.sol +++ b/foundry/test/executors/UniswapV4Utils.sol @@ -8,8 +8,7 @@ library UniswapV4Utils { address tokenIn, address tokenOut, bool zeroForOne, - bool transferFromNeeded, - bool transferNeeded, + RestrictTransferFrom.TransferType transferType, address receiver, UniswapV4Executor.UniswapV4Pool[] memory pools ) public pure returns (bytes memory) { @@ -25,13 +24,7 @@ library UniswapV4Utils { } return abi.encodePacked( - tokenIn, - tokenOut, - zeroForOne, - transferFromNeeded, - transferNeeded, - receiver, - encodedPools + tokenIn, tokenOut, zeroForOne, transferType, receiver, encodedPools ); } } diff --git a/src/encoding/evm/swap_encoder/swap_encoders.rs b/src/encoding/evm/swap_encoder/swap_encoders.rs index 4b33097..fb7b7b1 100644 --- a/src/encoding/evm/swap_encoder/swap_encoders.rs +++ b/src/encoding/evm/swap_encoder/swap_encoders.rs @@ -575,8 +575,8 @@ impl SwapEncoder for CurveSwapEncoder { i.to_be_bytes::<1>(), j.to_be_bytes::<1>(), approval_needed, - bytes_to_address(&encoding_context.receiver)?, (encoding_context.transfer as u8).to_be_bytes(), + bytes_to_address(&encoding_context.receiver)?, ); Ok(args.abi_encode_packed()) @@ -1386,10 +1386,10 @@ mod tests { "01", // approval needed "01", - // receiver, - "1d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e", // transfer type None "02", + // receiver, + "1d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e", )) ); } @@ -1456,10 +1456,10 @@ mod tests { "00", // approval needed "01", - // receiver - "1d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e", // transfer type None "02", + // receiver + "1d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e", )) ); } @@ -1536,10 +1536,10 @@ mod tests { "01", // approval needed "01", - // receiver - "1d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e", // transfer type None "02", + // receiver + "1d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e", )) ); }