Merge pull request #158 from propeller-heads/encodig/tnl/ENG-4313-transfer-in

feat: Optimize transfer to first pool in encoding
This commit is contained in:
Tamara
2025-04-15 13:45:34 -04:00
committed by Diana Carvalho
25 changed files with 768 additions and 319 deletions

View File

@@ -58,9 +58,6 @@ import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol";
error TychoRouter__AddressZero();
error TychoRouter__EmptySwaps();
error TychoRouter__NegativeSlippage(uint256 amount, uint256 minAmount);
error TychoRouter__AmountInDiffersFromConsumed(
uint256 amountIn, uint256 amountConsumed
);
error TychoRouter__MessageValueMismatch(uint256 value, uint256 amount);
error TychoRouter__InvalidDataLength();
error TychoRouter__UndefinedMinAmountOut();
@@ -99,7 +96,7 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
/**
* @notice Executes a swap operation based on a predefined swap graph, supporting internal token amount splits.
* This function enables multi-step swaps, optional ETH wrapping/unwrapping, and validates the output amount
* against a user-specified minimum. This function performs a transferFrom to retrieve tokens from the caller.
* against a user-specified minimum.
*
* @dev
* - If `wrapEth` is true, the contract wraps the provided native ETH into WETH and uses it as the sell token.
@@ -130,11 +127,6 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
address receiver,
bytes calldata swaps
) public payable whenNotPaused nonReentrant returns (uint256 amountOut) {
if (address(tokenIn) != address(0)) {
IERC20(tokenIn).safeTransferFrom(
msg.sender, address(this), amountIn
);
}
return _splitSwapChecked(
amountIn,
tokenIn,
@@ -187,15 +179,9 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
bytes calldata signature,
bytes calldata swaps
) external payable whenNotPaused nonReentrant returns (uint256 amountOut) {
// For native ETH, assume funds already in our router. Else, transfer and handle approval.
// For native ETH, assume funds already in our router. Else, handle approval.
if (tokenIn != address(0)) {
permit2.permit(msg.sender, permitSingle, signature);
permit2.transferFrom(
msg.sender,
address(this),
uint160(amountIn),
permitSingle.details.token
);
}
return _splitSwapChecked(
@@ -214,7 +200,7 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
/**
* @notice Executes a swap operation based on a predefined swap graph with no split routes.
* This function enables multi-step swaps, optional ETH wrapping/unwrapping, and validates the output amount
* against a user-specified minimum. This function performs a transferFrom to retrieve tokens from the caller.
* against a user-specified minimum.
*
* @dev
* - If `wrapEth` is true, the contract wraps the provided native ETH into WETH and uses it as the sell token.
@@ -243,7 +229,6 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
address receiver,
bytes calldata swaps
) public payable whenNotPaused nonReentrant returns (uint256 amountOut) {
IERC20(tokenIn).safeTransferFrom(msg.sender, address(this), amountIn);
return _sequentialSwapChecked(
amountIn,
tokenIn,
@@ -292,15 +277,9 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
bytes calldata signature,
bytes calldata swaps
) external payable whenNotPaused nonReentrant returns (uint256 amountOut) {
// For native ETH, assume funds already in our router. Else, transfer and handle approval.
// For native ETH, assume funds already in our router. Else, handle approval.
if (tokenIn != address(0)) {
permit2.permit(msg.sender, permitSingle, signature);
permit2.transferFrom(
msg.sender,
address(this),
uint160(amountIn),
permitSingle.details.token
);
}
return _sequentialSwapChecked(
@@ -318,7 +297,6 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
/**
* @notice Executes a single swap operation.
* This function enables optional ETH wrapping/unwrapping, and validates the output amount against a user-specified minimum.
* This function performs a transferFrom to retrieve tokens from the caller.
*
* @dev
* - If `wrapEth` is true, the contract wraps the provided native ETH into WETH and uses it as the sell token.
@@ -346,7 +324,6 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
address receiver,
bytes calldata swapData
) public payable whenNotPaused nonReentrant returns (uint256 amountOut) {
IERC20(tokenIn).safeTransferFrom(msg.sender, address(this), amountIn);
return _singleSwap(
amountIn,
tokenIn,
@@ -395,15 +372,9 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
bytes calldata signature,
bytes calldata swapData
) external payable whenNotPaused nonReentrant returns (uint256 amountOut) {
// For native ETH, assume funds already in our router. Else, transfer and handle approval.
// For native ETH, assume funds already in our router. Else, handle approval.
if (tokenIn != address(0)) {
permit2.permit(msg.sender, permitSingle, signature);
permit2.transferFrom(
msg.sender,
address(this),
uint160(amountIn),
permitSingle.details.token
);
}
return _singleSwap(
@@ -449,23 +420,7 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
_wrapETH(amountIn);
tokenIn = address(_weth);
}
uint256 initialBalance = tokenIn == address(0)
? address(this).balance
: IERC20(tokenIn).balanceOf(address(this));
amountOut = _splitSwap(amountIn, nTokens, swaps);
uint256 currentBalance = tokenIn == address(0)
? address(this).balance
: IERC20(tokenIn).balanceOf(address(this));
uint256 amountConsumed = initialBalance - currentBalance;
if (tokenIn != tokenOut && amountConsumed != amountIn) {
revert TychoRouter__AmountInDiffersFromConsumed(
amountIn, amountConsumed
);
}
if (amountOut < minAmountOut) {
revert TychoRouter__NegativeSlippage(amountOut, minAmountOut);
@@ -512,25 +467,10 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
tokenIn = address(_weth);
}
uint256 initialBalance = tokenIn == address(0)
? address(this).balance
: IERC20(tokenIn).balanceOf(address(this));
(address executor, bytes calldata protocolData) =
swap_.decodeSingleSwap();
amountOut = _callExecutor(executor, amountIn, protocolData);
uint256 currentBalance = tokenIn == address(0)
? address(this).balance
: IERC20(tokenIn).balanceOf(address(this));
uint256 amountConsumed = initialBalance - currentBalance;
if (amountConsumed != amountIn) {
revert TychoRouter__AmountInDiffersFromConsumed(
amountIn, amountConsumed
);
}
if (amountOut < minAmountOut) {
revert TychoRouter__NegativeSlippage(amountOut, minAmountOut);
@@ -577,24 +517,8 @@ contract TychoRouter is AccessControl, Dispatcher, Pausable, ReentrancyGuard {
tokenIn = address(_weth);
}
uint256 initialBalance = tokenIn == address(0)
? address(this).balance
: IERC20(tokenIn).balanceOf(address(this));
amountOut = _sequentialSwap(amountIn, swaps);
uint256 currentBalance = tokenIn == address(0)
? address(this).balance
: IERC20(tokenIn).balanceOf(address(this));
uint256 amountConsumed = initialBalance - currentBalance;
if (tokenIn != tokenOut && amountConsumed != amountIn) {
revert TychoRouter__AmountInDiffersFromConsumed(
amountIn, amountConsumed
);
}
if (amountOut < minAmountOut) {
revert TychoRouter__NegativeSlippage(amountOut, minAmountOut);
}

View File

@@ -10,14 +10,17 @@ import {
import {IAsset} from "@balancer-labs/v2-interfaces/contracts/vault/IAsset.sol";
// slither-disable-next-line solc-version
import {IVault} from "@balancer-labs/v2-interfaces/contracts/vault/IVault.sol";
import {TokenTransfer} from "./TokenTransfer.sol";
error BalancerV2Executor__InvalidDataLength();
contract BalancerV2Executor is IExecutor {
contract BalancerV2Executor is IExecutor, TokenTransfer {
using SafeERC20 for IERC20;
address private constant VAULT = 0xBA12222222228d8Ba445958a75a0704d566BF2C8;
constructor(address _permit2) TokenTransfer(_permit2) {}
// slither-disable-next-line locked-ether
function swap(uint256 givenAmount, bytes calldata data)
external
@@ -29,9 +32,20 @@ contract BalancerV2Executor is IExecutor {
IERC20 tokenOut,
bytes32 poolId,
address receiver,
bool needsApproval
bool needsApproval,
TransferType transferType
) = _decodeData(data);
_transfer(
address(tokenIn),
msg.sender,
// Receiver can never be the pool, since the pool expects funds in the router contract
// Thus, this call will only ever be used to transfer funds from the user into the router.
address(this),
givenAmount,
transferType
);
if (needsApproval) {
// slither-disable-next-line unused-return
tokenIn.approve(VAULT, type(uint256).max);
@@ -67,10 +81,11 @@ contract BalancerV2Executor is IExecutor {
IERC20 tokenOut,
bytes32 poolId,
address receiver,
bool needsApproval
bool needsApproval,
TransferType transferType
)
{
if (data.length != 93) {
if (data.length != 94) {
revert BalancerV2Executor__InvalidDataLength();
}
@@ -79,5 +94,6 @@ contract BalancerV2Executor is IExecutor {
poolId = bytes32(data[40:72]);
receiver = address(bytes20(data[72:92]));
needsApproval = uint8(data[92]) > 0;
transferType = TransferType(uint8(data[93]));
}
}

View File

@@ -3,8 +3,10 @@ pragma solidity ^0.8.26;
import "@interfaces/IExecutor.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "./TokenTransfer.sol";
error CurveExecutor__AddressZero();
error CurveExecutor__InvalidDataLength();
interface CryptoPool {
// slither-disable-next-line naming-convention
@@ -32,12 +34,14 @@ interface CryptoPoolETH {
// slither-disable-end naming-convention
}
contract CurveExecutor is IExecutor {
contract CurveExecutor is IExecutor, TokenTransfer {
using SafeERC20 for IERC20;
address public immutable nativeToken;
constructor(address _nativeToken) {
constructor(address _nativeToken, address _permit2)
TokenTransfer(_permit2)
{
if (_nativeToken == address(0)) {
revert CurveExecutor__AddressZero();
}
@@ -50,6 +54,8 @@ contract CurveExecutor is IExecutor {
payable
returns (uint256)
{
if (data.length != 65) revert CurveExecutor__InvalidDataLength();
(
address tokenIn,
address tokenOut,
@@ -57,9 +63,20 @@ contract CurveExecutor is IExecutor {
uint8 poolType,
int128 i,
int128 j,
bool tokenApprovalNeeded
bool tokenApprovalNeeded,
TransferType transferType
) = _decodeData(data);
_transfer(
tokenIn,
msg.sender,
// Receiver can never be the pool, since the pool expects funds in the router contract
// Thus, this call will only ever be used to transfer funds from the user into the router.
address(this),
amountIn,
transferType
);
if (tokenApprovalNeeded && tokenIn != nativeToken) {
// slither-disable-next-line unused-return
IERC20(tokenIn).approve(address(pool), type(uint256).max);
@@ -105,7 +122,8 @@ contract CurveExecutor is IExecutor {
uint8 poolType,
int128 i,
int128 j,
bool tokenApprovalNeeded
bool tokenApprovalNeeded,
TransferType transferType
)
{
tokenIn = address(bytes20(data[0:20]));
@@ -115,6 +133,7 @@ contract CurveExecutor is IExecutor {
i = int128(uint128(uint8(data[61])));
j = int128(uint128(uint8(data[62])));
tokenApprovalNeeded = data[63] != 0;
transferType = TransferType(uint8(data[64]));
}
receive() external payable {

View File

@@ -14,11 +14,19 @@ contract TokenTransfer {
enum TransferType {
// Assume funds are in the TychoRouter - transfer into the pool
TRANSFER,
TRANSFER_TO_PROTOCOL,
// Assume funds are in msg.sender's wallet - transferFrom into the pool
TRANSFERFROM,
TRANSFER_FROM_TO_PROTOCOL,
// Assume funds are in msg.sender's wallet - permit2TransferFrom into the pool
TRANSFERPERMIT2,
TRANSFER_PERMIT2_TO_PROTOCOL,
// Assume funds are in msg.sender's wallet - but the pool requires it to be
// in the router contract when calling swap - transferFrom into the router
// contract
TRANSFER_FROM_TO_ROUTER,
// Assume funds are in msg.sender's wallet - but the pool requires it to be
// in the router contract when calling swap - transferFrom into the router
// contract using permit2
TRANSFER_PERMIT2_TO_ROUTER,
// Assume funds have already been transferred into the pool. Do nothing.
NONE
}
@@ -31,21 +39,31 @@ contract TokenTransfer {
}
function _transfer(
IERC20 tokenIn,
address tokenIn,
address sender,
address receiver,
uint256 amount,
TransferType transferType
) internal {
if (transferType == TransferType.TRANSFER) {
tokenIn.safeTransfer(receiver, amount);
} else if (transferType == TransferType.TRANSFERFROM) {
if (transferType == TransferType.TRANSFER_TO_PROTOCOL) {
if (tokenIn == address(0)) {
payable(receiver).transfer(amount);
} else {
IERC20(tokenIn).safeTransfer(receiver, amount);
}
} else if (transferType == TransferType.TRANSFER_FROM_TO_PROTOCOL) {
// slither-disable-next-line arbitrary-send-erc20
tokenIn.safeTransferFrom(sender, receiver, amount);
} else if (transferType == TransferType.TRANSFERPERMIT2) {
IERC20(tokenIn).safeTransferFrom(sender, receiver, amount);
} else if (transferType == TransferType.TRANSFER_PERMIT2_TO_PROTOCOL) {
// Permit2.permit is already called from the TychoRouter
permit2.transferFrom(sender, receiver, uint160(amount), tokenIn);
} else if (transferType == TransferType.TRANSFER_FROM_TO_ROUTER) {
// slither-disable-next-line arbitrary-send-erc20
IERC20(tokenIn).safeTransferFrom(sender, address(this), amount);
} else if (transferType == TransferType.TRANSFER_PERMIT2_TO_ROUTER) {
// Permit2.permit is already called from the TychoRouter
permit2.transferFrom(
sender, receiver, uint160(amount), address(tokenIn)
sender, address(this), uint160(amount), tokenIn
);
}
}

View File

@@ -50,7 +50,9 @@ contract UniswapV2Executor is IExecutor, TokenTransfer {
_verifyPairAddress(target);
calculatedAmount = _getAmountOut(target, givenAmount, zeroForOne);
_transfer(tokenIn, msg.sender, target, givenAmount, transferType);
_transfer(
address(tokenIn), msg.sender, target, givenAmount, transferType
);
IUniswapV2Pair pool = IUniswapV2Pair(target);
if (zeroForOne) {

View File

@@ -111,7 +111,7 @@ contract UniswapV3Executor is IExecutor, ICallback, TokenTransfer {
uint256 amountOwed =
amount0Delta > 0 ? uint256(amount0Delta) : uint256(amount1Delta);
_transfer(IERC20(tokenIn), sender, msg.sender, amountOwed, transferType);
_transfer(tokenIn, sender, msg.sender, amountOwed, transferType);
return abi.encode(amountOwed, tokenIn);
}

View File

@@ -17,10 +17,11 @@ import {Actions} from "@uniswap/v4-periphery/src/libraries/Actions.sol";
import {IV4Router} from "@uniswap/v4-periphery/src/interfaces/IV4Router.sol";
import {PathKey} from "@uniswap/v4-periphery/src/libraries/PathKey.sol";
import {ICallback} from "@interfaces/ICallback.sol";
import {TokenTransfer} from "./TokenTransfer.sol";
error UniswapV4Executor__InvalidDataLength();
contract UniswapV4Executor is IExecutor, V4Router, ICallback {
contract UniswapV4Executor is IExecutor, V4Router, ICallback, TokenTransfer {
using SafeERC20 for IERC20;
using CurrencyLibrary for Currency;
@@ -30,7 +31,10 @@ contract UniswapV4Executor is IExecutor, V4Router, ICallback {
int24 tickSpacing;
}
constructor(IPoolManager _poolManager) V4Router(_poolManager) {}
constructor(IPoolManager _poolManager, address _permit2)
V4Router(_poolManager)
TokenTransfer(_permit2)
{}
function swap(uint256 amountIn, bytes calldata data)
external
@@ -41,9 +45,21 @@ contract UniswapV4Executor is IExecutor, V4Router, ICallback {
address tokenIn,
address tokenOut,
bool zeroForOne,
TransferType transferType,
UniswapV4Executor.UniswapV4Pool[] memory pools
) = _decodeData(data);
// TODO move this into callback when we implement callback transfer type support
_transfer(
tokenIn,
msg.sender,
// Receiver can never be the pool, since the pool expects funds in the router contract
// Thus, this call will only ever be used to transfer funds from the user into the router.
address(this),
amountIn,
transferType
);
bytes memory swapData;
if (pools.length == 1) {
PoolKey memory key = PoolKey({
@@ -138,6 +154,7 @@ contract UniswapV4Executor is IExecutor, V4Router, ICallback {
address tokenIn,
address tokenOut,
bool zeroForOne,
TransferType transferType,
UniswapV4Pool[] memory pools
)
{
@@ -148,10 +165,11 @@ contract UniswapV4Executor is IExecutor, V4Router, ICallback {
tokenIn = address(bytes20(data[0:20]));
tokenOut = address(bytes20(data[20:40]));
zeroForOne = (data[40] != 0);
transferType = TransferType(uint8(data[41]));
uint256 poolsLength = (data.length - 41) / 26; // 26 bytes per pool object
uint256 poolsLength = (data.length - 42) / 26; // 26 bytes per pool object
pools = new UniswapV4Pool[](poolsLength);
bytes memory poolsData = data[41:];
bytes memory poolsData = data[42:];
uint256 offset = 0;
for (uint256 i = 0; i < poolsLength; i++) {
address intermediaryToken;

View File

@@ -12,7 +12,7 @@ contract TychoRouterTestIntegration is TychoRouterTestSetup {
uint256 balancerBefore = IERC20(DAI_ADDR).balanceOf(ALICE);
// Encoded solution generated using `test_split_swap_strategy_encoder_no_permit2`
(bool success,) = tychoRouterAddr.call(
hex"79b9b93b0000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000008f1d5c1cae37400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000059005700010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000"
hex"79b9b93b0000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000008f1d5c1cae37400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000059005700010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d01395000100000000000000"
);
vm.stopPrank();
@@ -37,7 +37,7 @@ contract TychoRouterTestIntegration is TychoRouterTestSetup {
IERC20(USDC_ADDR).approve(PERMIT2_ADDRESS, type(uint256).max);
// Encoded solution generated using `test_split_encoding_strategy_usv4`
(bool success,) = tychoRouterAddr.call(
hex"7c553846000000000000000000000000000000000000000000000000000000003b9aca00000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330000000000000000000000000000000000000000005064ff624d54346285543f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000000000000000000000000000000000003b9aca0000000000000000000000000000000000000000000000000000000000681f1d6200000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067f7976a0000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000000416af8ab519cbe8f466aed6188c8966ca4910d72d40d2f4360f62dbe75864b77ce5ec168870bb1540673b3f720c4f2bfaa5de2a79813c857ad5cc49b20217c65041c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007800760001000000f62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb486982508145454ce325ddbe47a25d4ec3d2311933000000000000000000000000000000000000000000000bb800003c6982508145454ce325ddbe47a25d4ec3d23119330061a80001f40000000000000000"
hex"7c553846000000000000000000000000000000000000000000000000000000003b9aca00000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330000000000000000000000000000000000000000005064ff624d54346285543f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000000000000000000000000000000000003b9aca00000000000000000000000000000000000000000000000000000000006824c2ae00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067fd3cb6000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000041850e1add80e90f19d7b1ac70721b5dec8a6bdcb57999ea957f831ea57c4ce1a116bec18d2cae2559421ead48186b6985176fee7f8d2e3452c1518dc2635224b41c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007900770001000000f62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb486982508145454ce325ddbe47a25d4ec3d231193300040000000000000000000000000000000000000000000bb800003c6982508145454ce325ddbe47a25d4ec3d23119330061a80001f400000000000000"
);
vm.stopPrank();
@@ -60,7 +60,7 @@ contract TychoRouterTestIntegration is TychoRouterTestSetup {
// Encoded solution generated using `test_split_encoding_strategy_usv4_eth_in`
(bool success,) = tychoRouterAddr.call{value: 1 ether}(
hex"7c5538460000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006982508145454ce325ddbe47a25d4ec3d2311933000000000000000000000000000000000000000000c87c939ae635f92dc2379c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000681f1d7100000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067f79779000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000041c9ad125cc7c7188d1f0cd61dd8ee0d752d45c89ade1df275c5e0ce17525c6ff137bd976ebd0d17223c007e1f0a2806d086b4c7015460ebd21fef8a6caf8368d51c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005e005c0001000000f62849f9a0b5bf2913b396098f7c7019b51a820a00000000000000000000000000000000000000006982508145454ce325ddbe47a25d4ec3d2311933016982508145454ce325ddbe47a25d4ec3d23119330061a80001f40000"
hex"7c5538460000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006982508145454ce325ddbe47a25d4ec3d2311933000000000000000000000000000000000000000000c87c939ae635f92dc2379c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000000000006824c2cb00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067fd3cd3000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000041a97e156e8c7a48a968efe2f057700ce8458ecfbfb53e0319fc9223b2364aba20227d2ee00226b42e2f28aeb002a242576d75152b270d73a8926f595190828f3d1c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005f005d0001000000f62849f9a0b5bf2913b396098f7c7019b51a820a00000000000000000000000000000000000000006982508145454ce325ddbe47a25d4ec3d231193301056982508145454ce325ddbe47a25d4ec3d23119330061a80001f400"
);
vm.stopPrank();
@@ -87,7 +87,7 @@ contract TychoRouterTestIntegration is TychoRouterTestSetup {
// Encoded solution generated using `test_split_encoding_strategy_usv4_eth_out`
(bool success,) = tychoRouterAddr.call(
hex"7c55384600000000000000000000000000000000000000000000000000000000b2d05e00000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f81490b4f29aade000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000b2d05e0000000000000000000000000000000000000000000000000000000000681f1d7e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067f797860000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000000412beedebe0200a3d4ca03f34697af8ec027fe6c164e3d3b78e17d1c327dcfc8241ce8bda513f092e54b35856637e5e485a06cc8c1c6287f15f469d47e84fd91341b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005e005c0001000000f62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000000000000000000000000000000000bb800003c0000"
hex"7c55384600000000000000000000000000000000000000000000000000000000b2d05e00000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f81490b4f29aade000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000b2d05e00000000000000000000000000000000000000000000000000000000006824c2da00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067fd3ce20000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000000416b224d97fe1a35f2698380969c22854cf7ed92881ea484df7adb438f8d8e78e66c8617131f6712c5f3b4fa07725725081b2ebe27cd44acd11332a4a72bded96c1b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005f005d0001000000f62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000000000000000000000040000000000000000000000000000000000000000000bb800003c00"
);
vm.stopPrank();
@@ -109,7 +109,7 @@ contract TychoRouterTestIntegration is TychoRouterTestSetup {
vm.startPrank(ALICE);
// Encoded solution generated using `test_split_swap_strategy_encoder_wrap`
(bool success,) = tychoRouterAddr.call{value: 1 ether}(
hex"7c5538460000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f0000000000000000000000000000000000000000000000903146e5f6c59c064b000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000681e435000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067f6bd580000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000000415563c90eb0f8a79e234e300520b50879242b42622cabd5d01c19e67aba4854a723e0bd8333774062ae03a22b8c5de4a0dfd70bffd9197f56b2063f390610e5891b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000059005700020000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000"
hex"7c5538460000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f0000000000000000000000000000000000000000000000903146e5f6c59c064b000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000000000006821640400000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067f9de0c000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000041b34e1f3d4e78942b2429b776073a5dfab1420f763de7d7e2a2296ca8abf684f923f7ae7945e824d8a084b9610d33ed49246a36e8e0efbce8ae210b0474f9fe3a1b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000059005700020000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000"
);
vm.stopPrank();
@@ -131,7 +131,7 @@ contract TychoRouterTestIntegration is TychoRouterTestSetup {
IERC20(DAI_ADDR).approve(PERMIT2_ADDRESS, type(uint256).max);
// Encoded solution generated using `test_split_swap_strategy_encoder_unwrap`
(bool success,) = tychoRouterAddr.call(
hex"7c5538460000000000000000000000000000000000000000000000a2a15d09519be000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000003000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f0000000000000000000000000000000000000000000000a2a15d09519be0000000000000000000000000000000000000000000000000000000000000681e436b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067f6bd730000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000000411150ac5d21c61fcd35b486034a433e44d045950a52e991a7ad4035f3ad52beee5d9ecbc5ed9c370730cd2631a050fbe1219dd606e39c8aca40d588aa3eab03411c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000059005700010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fa478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d01395010000000000000000"
hex"7c5538460000000000000000000000000000000000000000000000a2a15d09519be000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000003000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f0000000000000000000000000000000000000000000000a2a15d09519be00000000000000000000000000000000000000000000000000000000000006821641200000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067f9de1a00000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000004181d23336d0cacd47a4d228590a825a1d92a48378cd481ff308b6d235e14b925c584f31e420682879bea58363ca4aa44a3b79557b15a9f73078a4696e00f55f911b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000059005700010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fa478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d01395010200000000000000"
);
vm.stopPrank();
@@ -183,7 +183,7 @@ contract TychoRouterTestIntegration is TychoRouterTestSetup {
IERC20(WETH_ADDR).approve(PERMIT2_ADDRESS, type(uint256).max);
// Encoded solution generated using `test_split_swap_strategy_encoder_complex`
(bool success,) = tychoRouterAddr.call(
hex"7c5538460000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000681e2d8b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067f6a793000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000041e9868ce97a4c09488710ce748362ca38418bda44148bb5faf7820445d47efaff66f8f3667a0b3091c9d67d240db4cc2c95db27bdf019e4d5ff76b7b6620514691b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000164005700028000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d013950000005700010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d9403ede3eca2a72b3aecc820e955b36f38437d013950000005702030000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fae461ca67b15dc8dc81ce7615e0320da1a9ab8d53ede3eca2a72b3aecc820e955b36f38437d013950100005701030000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a4163ede3eca2a72b3aecc820e955b36f38437d01395010000000000000000000000000000000000000000000000000000000000"
hex"7c5538460000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000000000006821643700000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067f9de3f00000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000004112f41a590796702b322fa5a9ee1602daef9b22d732e4fd8f122f072b65dda325271f630759db500db8a42bd4f41ddc18ddda63650deaf36228dca702e28eefd31b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000164005700028000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d013950002005700010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d9403ede3eca2a72b3aecc820e955b36f38437d013950002005702030000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fae461ca67b15dc8dc81ce7615e0320da1a9ab8d53ede3eca2a72b3aecc820e955b36f38437d013950100005701030000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a4163ede3eca2a72b3aecc820e955b36f38437d01395010000000000000000000000000000000000000000000000000000000000"
);
vm.stopPrank();
@@ -210,7 +210,7 @@ contract TychoRouterTestIntegration is TychoRouterTestSetup {
IERC20(WETH_ADDR).approve(PERMIT2_ADDRESS, type(uint256).max);
// Encoded solution generated using `test_sequential_swap_strategy_encoder_complex_route`
(bool success,) = tychoRouterAddr.call(
hex"51bcc7b60000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000681e493d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067f6c34500000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000004189757b528c9874627ca7ecd64bd662db5fd7855837ec98cca5cff2cbd599f9af15baff1d389b5de4ca0dc1106b9d3795a1695934cd5fa1158fffcc8d6495dfaa1b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a800525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d9403ede3eca2a72b3aecc820e955b36f38437d01395000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a4163ede3eca2a72b3aecc820e955b36f38437d013950100000000000000000000000000000000000000000000000000"
hex"51bcc7b60000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000000000006821644a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067f9de5200000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041530bdcde0c687eacb51a339f30c7b3eff7c078a3bbd4bc852519568dcdf271bb4c6ac05583f32c4a8d1a99be3a2817fe86c15ad2a06c5cf938bde9c22bc80f301c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a800525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d9403ede3eca2a72b3aecc820e955b36f38437d01395000200525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a4163ede3eca2a72b3aecc820e955b36f38437d013950100000000000000000000000000000000000000000000000000"
);
vm.stopPrank();
@@ -234,7 +234,7 @@ contract TychoRouterTestIntegration is TychoRouterTestSetup {
IERC20(WETH_ADDR).approve(tychoRouterAddr, type(uint256).max);
// Encoded solution generated using `test_sequential_swap_strategy_encoder_no_permit2`
(bool success,) = tychoRouterAddr.call(
hex"e8a980d70000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000a800525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d9403ede3eca2a72b3aecc820e955b36f38437d01395000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a4163ede3eca2a72b3aecc820e955b36f38437d013950100000000000000000000000000000000000000000000000000"
hex"e8a980d70000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000a800525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d9403ede3eca2a72b3aecc820e955b36f38437d01395000100525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a4163ede3eca2a72b3aecc820e955b36f38437d013950100000000000000000000000000000000000000000000000000"
);
vm.stopPrank();
@@ -254,9 +254,10 @@ contract TychoRouterTestIntegration is TychoRouterTestSetup {
IERC20(USDC_ADDR).approve(PERMIT2_ADDRESS, type(uint256).max);
// Encoded solution generated using `test_cyclic_sequential_swap`
(bool success,) = tychoRouterAddr.call(
hex"7c5538460000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f4308e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e10000000000000000000000000000000000000000000000000000000000681e4a0200000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067f6c40a0000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000000416a11f27f0546e9cc9d27e4383a3f860d9822f0d7d0117e73abbf03007b3e235b36c2288ff083a04f51285092ff23422b3e00a5a292d5627172dfd031308fc3a11b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e0006e00010000002e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f56400100006e01000000002e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb83ede3eca2a72b3aecc820e955b36f38437d013958ad599c3a0ff1de082011efddc58f1908eb6e6d80000"
hex"7c5538460000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f4308e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000000000000000000000000000000000006821647000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067f9de780000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000000413c8b048dc7b7614106a5aa1fa13e48c02a6a9714dfa07d2c424f68b81a5f828c39ace62f2dd57d7bfad10910ae44f77d68aec5c079fce456028b1bd7f72053151c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e0006e00010000002e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f56400102006e01000000002e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb83ede3eca2a72b3aecc820e955b36f38437d013958ad599c3a0ff1de082011efddc58f1908eb6e6d80000"
);
assertTrue(success, "Call Failed");
assertEq(IERC20(USDC_ADDR).balanceOf(ALICE), 99889294);
vm.stopPrank();
@@ -270,9 +271,10 @@ contract TychoRouterTestIntegration is TychoRouterTestSetup {
IERC20(USDC_ADDR).approve(PERMIT2_ADDRESS, type(uint256).max);
// Encoded solution generated using `test_split_input_cyclic_swap`
(bool success,) = tychoRouterAddr.call(
hex"7c5538460000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005ef619b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e10000000000000000000000000000000000000000000000000000000000681e2d1600000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067f6a71e00000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000004129478d2bffac3e378054d024ca3461f61e55552e2e8b0c7e0869f38ee834462f157f761e1a67c713f5749a6f6210dc4ac998a0521dda8dcb780b35d774250a141c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000139006e00019999992e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f56400100006e00010000002e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000bb83ede3eca2a72b3aecc820e955b36f38437d013958ad599c3a0ff1de082011efddc58f1908eb6e6d80100005701000000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2b4e16d0168e52d35cacd2c6185b44281ec28c9dc3ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000"
hex"7c5538460000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005ef619b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000000000000000000000000000000000006821659d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067f9dfa5000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000041dd84c5cdc51719e377598eccd8eac0aae036e7e0745a7c65b5d44cc817071a7460ccc73934363f33cc7af71dc07545aeff1d92f8c2f0b2973e1fc37e7b2de3551c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000139006e00019999992e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f56400102006e00010000002e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000bb83ede3eca2a72b3aecc820e955b36f38437d013958ad599c3a0ff1de082011efddc58f1908eb6e6d80102005701000000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2b4e16d0168e52d35cacd2c6185b44281ec28c9dc3ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000"
);
assertTrue(success, "Call Failed");
assertEq(IERC20(USDC_ADDR).balanceOf(ALICE), 99574171);
vm.stopPrank();
@@ -286,9 +288,10 @@ contract TychoRouterTestIntegration is TychoRouterTestSetup {
IERC20(USDC_ADDR).approve(PERMIT2_ADDRESS, type(uint256).max);
// Encoded solution generated using `test_split_output_cyclic_swap`
(bool success,) = tychoRouterAddr.call(
hex"7c5538460000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005eea514000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e10000000000000000000000000000000000000000000000000000000000681e2d3000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067f6a738000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000041196745237299bfab79f038c0c12decec9c46b264621e1f00bbef32b15a22f15543defe95694dd1616aa8785bbb6f91a1557eebc97c0f5ca968c99f250da1b2ce1c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000139005700010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48b4e16d0168e52d35cacd2c6185b44281ec28c9dc3ede3eca2a72b3aecc820e955b36f38437d013950100006e01009999992e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f56400000006e01000000002e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb83ede3eca2a72b3aecc820e955b36f38437d013958ad599c3a0ff1de082011efddc58f1908eb6e6d8000000000000000000"
hex"7c5538460000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005eea514000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e10000000000000000000000000000000000000000000000000000000000682165ac00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067f9dfb400000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000004107f2b0f9c2e4e308ab43b288d69de30d84b10c8075e4dd9a2cf66594f97a52fb34de2534b89bf1887da74c92fd03464f45baff700dd32e213e3add1a3f351e891b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000139005700010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48b4e16d0168e52d35cacd2c6185b44281ec28c9dc3ede3eca2a72b3aecc820e955b36f38437d013950102006e01009999992e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f56400000006e01000000002e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb83ede3eca2a72b3aecc820e955b36f38437d013958ad599c3a0ff1de082011efddc58f1908eb6e6d8000000000000000000"
);
assertTrue(success, "Call Failed");
assertEq(IERC20(USDC_ADDR).balanceOf(ALICE), 99525908);
vm.stopPrank();
@@ -301,9 +304,10 @@ contract TychoRouterTestIntegration is TychoRouterTestSetup {
IERC20(UWU_ADDR).approve(tychoRouterAddr, type(uint256).max);
// Encoded solution generated using `test_split_encoding_strategy_curve`
(bool success,) = tychoRouterAddr.call(
hex"79b9b93b0000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000055c08ca52497e2f1534b59e2917bf524d4765257000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000005b005900010000001d1499e622d69689cdf9004d05ec547d650ff21155c08ca52497e2f1534b59e2917bf524d4765257c02aaa39b223fe8d0a0e5c4f27ead9083c756cc277146b0a1d08b6844376df6d9da99ba7f1b19e71020100010000000000"
hex"79b9b93b0000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000055c08ca52497e2f1534b59e2917bf524d4765257000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000005c005a00010000001d1499e622d69689cdf9004d05ec547d650ff21155c08ca52497e2f1534b59e2917bf524d4765257c02aaa39b223fe8d0a0e5c4f27ead9083c756cc277146b0a1d08b6844376df6d9da99ba7f1b19e71020100010300000000"
);
assertTrue(success, "Call Failed");
assertEq(IERC20(WETH_ADDR).balanceOf(ALICE), 4691958787921);
vm.stopPrank();
@@ -315,9 +319,10 @@ contract TychoRouterTestIntegration is TychoRouterTestSetup {
vm.startPrank(ALICE);
// Encoded solution generated using `test_split_encoding_strategy_curve_st_eth`
(bool success,) = tychoRouterAddr.call{value: 1 ether}(
hex"79b9b93b0000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ae7ab96520de3a18e5e111b5eaab095312d7fe840000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000005b005900010000001d1499e622d69689cdf9004d05ec547d650ff211eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeae7ab96520de3a18e5e111b5eaab095312d7fe84dc24316b9ae028f1497c275eb9192a3ea0f67022010001000000000000"
hex"79b9b93b0000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ae7ab96520de3a18e5e111b5eaab095312d7fe840000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000005c005a00010000001d1499e622d69689cdf9004d05ec547d650ff211eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeae7ab96520de3a18e5e111b5eaab095312d7fe84dc24316b9ae028f1497c275eb9192a3ea0f67022010001000500000000"
);
assertTrue(success, "Call Failed");
assertEq(IERC20(STETH_ADDR).balanceOf(ALICE), 1000754689941529590);
vm.stopPrank();

View File

@@ -8,23 +8,38 @@ import "./executors/UniswapV4Utils.sol";
import {SafeCallback} from "@uniswap/v4-periphery/src/base/SafeCallback.sol";
contract TychoRouterSequentialSwapTest is TychoRouterTestSetup {
function _getSequentialSwaps() internal view returns (bytes[] memory) {
function _getSequentialSwaps(bool permit2)
internal
view
returns (bytes[] memory)
{
// Trade 1 WETH for USDC through DAI with 2 swaps on Uniswap V2
// 1 WETH -> DAI -> USDC
// (univ2) (univ2)
TokenTransfer.TransferType transferType = permit2
? TokenTransfer.TransferType.TRANSFER_PERMIT2_TO_PROTOCOL
: TokenTransfer.TransferType.TRANSFER_FROM_TO_PROTOCOL;
bytes[] memory swaps = new bytes[](2);
// WETH -> DAI
swaps[0] = encodeSequentialSwap(
address(usv2Executor),
encodeUniswapV2Swap(
WETH_ADDR, WETH_DAI_POOL, tychoRouterAddr, false
WETH_ADDR, WETH_DAI_POOL, tychoRouterAddr, false, transferType
)
);
// DAI -> USDC
swaps[1] = encodeSequentialSwap(
address(usv2Executor),
encodeUniswapV2Swap(DAI_ADDR, DAI_USDC_POOL, tychoRouterAddr, true)
encodeUniswapV2Swap(
DAI_ADDR,
DAI_USDC_POOL,
tychoRouterAddr,
true,
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL
)
);
return swaps;
}
@@ -32,10 +47,13 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup {
function testSequentialSwapInternalMethod() public {
// Trade 1 WETH for USDC through DAI - see _getSequentialSwaps for more info
uint256 amountIn = 1 ether;
deal(WETH_ADDR, tychoRouterAddr, amountIn);
deal(WETH_ADDR, ALICE, amountIn);
vm.startPrank(ALICE);
IERC20(WETH_ADDR).approve(tychoRouterAddr, amountIn);
bytes[] memory swaps = _getSequentialSwaps();
bytes[] memory swaps = _getSequentialSwaps(false);
tychoRouter.exposedSequentialSwap(amountIn, pleEncode(swaps));
vm.stopPrank();
uint256 usdcBalance = IERC20(USDC_ADDR).balanceOf(tychoRouterAddr);
assertEq(usdcBalance, 2644659787);
@@ -53,7 +71,7 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup {
bytes memory signature
) = handlePermit2Approval(WETH_ADDR, tychoRouterAddr, amountIn);
bytes[] memory swaps = _getSequentialSwaps();
bytes[] memory swaps = _getSequentialSwaps(true);
tychoRouter.sequentialSwapPermit2(
amountIn,
WETH_ADDR,
@@ -80,7 +98,7 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup {
vm.startPrank(ALICE);
IERC20(WETH_ADDR).approve(tychoRouterAddr, amountIn);
bytes[] memory swaps = _getSequentialSwaps();
bytes[] memory swaps = _getSequentialSwaps(false);
tychoRouter.sequentialSwap(
amountIn,
WETH_ADDR,
@@ -105,7 +123,7 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup {
vm.startPrank(ALICE);
IERC20(WETH_ADDR).approve(tychoRouterAddr, amountIn);
bytes[] memory swaps = _getSequentialSwaps();
bytes[] memory swaps = _getSequentialSwaps(false);
vm.expectRevert(TychoRouter__UndefinedMinAmountOut.selector);
tychoRouter.sequentialSwap(
amountIn,
@@ -127,7 +145,7 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup {
vm.startPrank(ALICE);
IERC20(WETH_ADDR).approve(tychoRouterAddr, amountIn - 1);
bytes[] memory swaps = _getSequentialSwaps();
bytes[] memory swaps = _getSequentialSwaps(false);
vm.expectRevert();
tychoRouter.sequentialSwap(
amountIn,
@@ -152,7 +170,7 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup {
bytes memory signature
) = handlePermit2Approval(WETH_ADDR, tychoRouterAddr, amountIn);
bytes[] memory swaps = _getSequentialSwaps();
bytes[] memory swaps = _getSequentialSwaps(true);
uint256 minAmountOut = 3000 * 1e18;
@@ -195,7 +213,30 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup {
sigDeadline: 0
});
bytes[] memory swaps = _getSequentialSwaps();
bytes[] memory swaps = new bytes[](2);
// WETH -> DAI
swaps[0] = encodeSequentialSwap(
address(usv2Executor),
encodeUniswapV2Swap(
WETH_ADDR,
WETH_DAI_POOL,
tychoRouterAddr,
false,
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL
)
);
// DAI -> USDC
swaps[1] = encodeSequentialSwap(
address(usv2Executor),
encodeUniswapV2Swap(
DAI_ADDR,
DAI_USDC_POOL,
tychoRouterAddr,
true,
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL
)
);
uint256 amountOut = tychoRouter.sequentialSwapPermit2{value: amountIn}(
amountIn,
@@ -237,14 +278,24 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup {
swaps[0] = encodeSequentialSwap(
address(usv2Executor),
encodeUniswapV2Swap(
USDC_ADDR, DAI_USDC_POOL, tychoRouterAddr, false
USDC_ADDR,
DAI_USDC_POOL,
tychoRouterAddr,
false,
TokenTransfer.TransferType.TRANSFER_PERMIT2_TO_PROTOCOL
)
);
// DAI -> WETH
swaps[1] = encodeSequentialSwap(
address(usv2Executor),
encodeUniswapV2Swap(DAI_ADDR, WETH_DAI_POOL, tychoRouterAddr, true)
encodeUniswapV2Swap(
DAI_ADDR,
WETH_DAI_POOL,
tychoRouterAddr,
true,
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL
)
);
uint256 amountOut = tychoRouter.sequentialSwapPermit2(
@@ -275,11 +326,21 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup {
deal(USDC_ADDR, tychoRouterAddr, amountIn);
bytes memory usdcWethV3Pool1ZeroOneData = encodeUniswapV3Swap(
USDC_ADDR, WETH_ADDR, tychoRouterAddr, USDC_WETH_USV3, true
USDC_ADDR,
WETH_ADDR,
tychoRouterAddr,
USDC_WETH_USV3,
true,
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL
);
bytes memory usdcWethV3Pool2OneZeroData = encodeUniswapV3Swap(
WETH_ADDR, USDC_ADDR, tychoRouterAddr, USDC_WETH_USV3_2, false
WETH_ADDR,
USDC_ADDR,
tychoRouterAddr,
USDC_WETH_USV3_2,
false,
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL
);
bytes[] memory swaps = new bytes[](2);

View File

@@ -22,7 +22,11 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup {
) = handlePermit2Approval(WETH_ADDR, tychoRouterAddr, amountIn);
bytes memory protocolData = encodeUniswapV2Swap(
WETH_ADDR, WETH_DAI_POOL, tychoRouterAddr, false
WETH_ADDR,
WETH_DAI_POOL,
tychoRouterAddr,
false,
TokenTransfer.TransferType.TRANSFER_PERMIT2_TO_PROTOCOL
);
bytes memory swap =
@@ -59,7 +63,11 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup {
IERC20(WETH_ADDR).approve(address(tychoRouterAddr), amountIn);
bytes memory protocolData = encodeUniswapV2Swap(
WETH_ADDR, WETH_DAI_POOL, tychoRouterAddr, false
WETH_ADDR,
WETH_DAI_POOL,
tychoRouterAddr,
false,
TokenTransfer.TransferType.TRANSFER_FROM_TO_PROTOCOL
);
bytes memory swap =
@@ -96,7 +104,11 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup {
IERC20(WETH_ADDR).approve(address(tychoRouterAddr), amountIn);
bytes memory protocolData = encodeUniswapV2Swap(
WETH_ADDR, WETH_DAI_POOL, tychoRouterAddr, false
WETH_ADDR,
WETH_DAI_POOL,
tychoRouterAddr,
false,
TokenTransfer.TransferType.TRANSFER_FROM_TO_PROTOCOL
);
bytes memory swap =
@@ -118,7 +130,11 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup {
IERC20(WETH_ADDR).approve(address(tychoRouterAddr), amountIn - 1);
bytes memory protocolData = encodeUniswapV2Swap(
WETH_ADDR, WETH_DAI_POOL, tychoRouterAddr, false
WETH_ADDR,
WETH_DAI_POOL,
tychoRouterAddr,
false,
TokenTransfer.TransferType.TRANSFER_FROM_TO_PROTOCOL
);
bytes memory swap =
@@ -149,7 +165,11 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup {
IERC20(WETH_ADDR).approve(address(tychoRouterAddr), amountIn);
bytes memory protocolData = encodeUniswapV2Swap(
WETH_ADDR, WETH_DAI_POOL, tychoRouterAddr, false
WETH_ADDR,
WETH_DAI_POOL,
tychoRouterAddr,
false,
TokenTransfer.TransferType.TRANSFER_FROM_TO_PROTOCOL
);
bytes memory swap =
@@ -194,7 +214,11 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup {
});
bytes memory protocolData = encodeUniswapV2Swap(
WETH_ADDR, WETH_DAI_POOL, tychoRouterAddr, false
WETH_ADDR,
WETH_DAI_POOL,
tychoRouterAddr,
false,
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL
);
bytes memory swap =
@@ -232,8 +256,13 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup {
bytes memory signature
) = handlePermit2Approval(DAI_ADDR, tychoRouterAddr, amountIn);
bytes memory protocolData =
encodeUniswapV2Swap(DAI_ADDR, WETH_DAI_POOL, tychoRouterAddr, true);
bytes memory protocolData = encodeUniswapV2Swap(
DAI_ADDR,
WETH_DAI_POOL,
tychoRouterAddr,
true,
TokenTransfer.TransferType.TRANSFER_PERMIT2_TO_PROTOCOL
);
bytes memory swap =
encodeSingleSwap(address(usv2Executor), protocolData);
@@ -267,7 +296,7 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup {
IERC20(WETH_ADDR).approve(tychoRouterAddr, type(uint256).max);
// Encoded solution generated using `test_single_swap_strategy_encoder_no_permit2`
(bool success,) = tychoRouterAddr.call(
hex"20144a070000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000008f1d5c1cae3740000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000"
hex"20144a070000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000008f1d5c1cae3740000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d0139500010000000000000000000000000000"
);
vm.stopPrank();
@@ -286,7 +315,7 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup {
IERC20(WETH_ADDR).approve(PERMIT2_ADDRESS, type(uint256).max);
// Encoded solution generated using `test_single_swap_strategy_encoder`
(bool success,) = tychoRouterAddr.call(
hex"30ace1b10000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f0000000000000000000000000000000000000000000000903146e5f6c59c064b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000000000006817833200000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067effd3a00000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000417efea09004d5d40d8d072e1ce0a425507717ea485c765eb90c170859197d362b502fb039b4f5cdce57318ecfe3ab276d1ac87771eb5d017b253a8f4107e6a20b1b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000"
hex"30ace1b10000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f0000000000000000000000000000000000000000000000903146e5f6c59c064b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000682169c100000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067f9e3c900000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000412d3f0fee3fc61987512f024f20b1448eb934f82105a91653dd169179c693aaf95d09ef666ce1d38be70b8156fa6e4ea3e8717204e02fe7ba99a1fc4e5a26e6e11b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d0139500020000000000000000000000000000"
);
vm.stopPrank();

View File

@@ -8,13 +8,22 @@ import "./executors/UniswapV4Utils.sol";
import {SafeCallback} from "@uniswap/v4-periphery/src/base/SafeCallback.sol";
contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
function _getSplitSwaps() private view returns (bytes[] memory) {
function _getSplitSwaps(bool permit2)
private
view
returns (bytes[] memory)
{
// Trade 1 WETH for USDC through DAI and WBTC with 4 swaps on Uniswap V2
// -> DAI ->
// 1 WETH USDC
// -> WBTC ->
// (univ2) (univ2)
bytes[] memory swaps = new bytes[](4);
TokenTransfer.TransferType inTransferType = permit2
? TokenTransfer.TransferType.TRANSFER_PERMIT2_TO_PROTOCOL
: TokenTransfer.TransferType.TRANSFER_FROM_TO_PROTOCOL;
// WETH -> WBTC (60%)
swaps[0] = encodeSplitSwap(
uint8(0),
@@ -22,7 +31,11 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
(0xffffff * 60) / 100, // 60%
address(usv2Executor),
encodeUniswapV2Swap(
WETH_ADDR, WETH_WBTC_POOL, tychoRouterAddr, false
WETH_ADDR,
WETH_WBTC_POOL,
tychoRouterAddr,
false,
inTransferType
)
);
// WBTC -> USDC
@@ -32,7 +45,11 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
uint24(0),
address(usv2Executor),
encodeUniswapV2Swap(
WBTC_ADDR, USDC_WBTC_POOL, tychoRouterAddr, true
WBTC_ADDR,
USDC_WBTC_POOL,
tychoRouterAddr,
true,
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL
)
);
// WETH -> DAI
@@ -42,7 +59,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
uint24(0),
address(usv2Executor),
encodeUniswapV2Swap(
WETH_ADDR, WETH_DAI_POOL, tychoRouterAddr, false
WETH_ADDR, WETH_DAI_POOL, tychoRouterAddr, false, inTransferType
)
);
@@ -52,7 +69,13 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
uint8(2),
uint24(0),
address(usv2Executor),
encodeUniswapV2Swap(DAI_ADDR, DAI_USDC_POOL, tychoRouterAddr, true)
encodeUniswapV2Swap(
DAI_ADDR,
DAI_USDC_POOL,
tychoRouterAddr,
true,
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL
)
);
return swaps;
@@ -62,9 +85,12 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
// Trade 1 WETH for USDC through DAI and WBTC - see _getSplitSwaps for more info
uint256 amountIn = 1 ether;
deal(WETH_ADDR, tychoRouterAddr, amountIn);
bytes[] memory swaps = _getSplitSwaps();
deal(WETH_ADDR, ALICE, amountIn);
vm.startPrank(ALICE);
IERC20(WETH_ADDR).approve(address(tychoRouterAddr), amountIn);
bytes[] memory swaps = _getSplitSwaps(false);
tychoRouter.exposedSplitSwap(amountIn, 4, pleEncode(swaps));
vm.stopPrank();
uint256 usdcBalance = IERC20(USDC_ADDR).balanceOf(tychoRouterAddr);
assertEq(usdcBalance, 2615491639);
@@ -83,7 +109,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
bytes memory signature
) = handlePermit2Approval(WETH_ADDR, tychoRouterAddr, amountIn);
bytes[] memory swaps = _getSplitSwaps();
bytes[] memory swaps = _getSplitSwaps(true);
tychoRouter.splitSwapPermit2(
amountIn,
@@ -112,7 +138,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
vm.startPrank(ALICE);
IERC20(WETH_ADDR).approve(address(tychoRouterAddr), amountIn);
bytes[] memory swaps = _getSplitSwaps();
bytes[] memory swaps = _getSplitSwaps(false);
tychoRouter.splitSwap(
amountIn,
@@ -139,7 +165,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
vm.startPrank(ALICE);
IERC20(WETH_ADDR).approve(address(tychoRouterAddr), amountIn);
bytes[] memory swaps = _getSplitSwaps();
bytes[] memory swaps = _getSplitSwaps(false);
vm.expectRevert(TychoRouter__UndefinedMinAmountOut.selector);
tychoRouter.splitSwap(
@@ -164,7 +190,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
vm.startPrank(ALICE);
// Approve less than the amountIn
IERC20(WETH_ADDR).approve(address(tychoRouterAddr), amountIn - 1);
bytes[] memory swaps = _getSplitSwaps();
bytes[] memory swaps = _getSplitSwaps(false);
vm.expectRevert();
tychoRouter.splitSwap(
@@ -193,7 +219,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
bytes memory signature
) = handlePermit2Approval(WETH_ADDR, tychoRouterAddr, amountIn);
bytes[] memory swaps = _getSplitSwaps();
bytes[] memory swaps = _getSplitSwaps(true);
uint256 minAmountOut = 3000 * 1e18;
@@ -240,7 +266,11 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
sigDeadline: 0
});
bytes memory protocolData = encodeUniswapV2Swap(
WETH_ADDR, WETH_DAI_POOL, tychoRouterAddr, false
WETH_ADDR,
WETH_DAI_POOL,
tychoRouterAddr,
false,
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL
);
bytes memory swap = encodeSplitSwap(
@@ -284,8 +314,13 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
bytes memory signature
) = handlePermit2Approval(DAI_ADDR, tychoRouterAddr, amountIn);
bytes memory protocolData =
encodeUniswapV2Swap(DAI_ADDR, WETH_DAI_POOL, tychoRouterAddr, true);
bytes memory protocolData = encodeUniswapV2Swap(
DAI_ADDR,
WETH_DAI_POOL,
tychoRouterAddr,
true,
TokenTransfer.TransferType.TRANSFER_PERMIT2_TO_PROTOCOL
);
bytes memory swap = encodeSplitSwap(
uint8(0), uint8(1), uint24(0), address(usv2Executor), protocolData
@@ -330,7 +365,12 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
uint256 expAmountOut = 1205_128428842122129186; //Swap 1 WETH for 1205.12 DAI
bool zeroForOne = false;
bytes memory protocolData = encodeUniswapV3Swap(
WETH_ADDR, DAI_ADDR, tychoRouterAddr, DAI_WETH_USV3, zeroForOne
WETH_ADDR,
DAI_ADDR,
tychoRouterAddr,
DAI_WETH_USV3,
zeroForOne,
TokenTransfer.TransferType.TRANSFER_PERMIT2_TO_PROTOCOL
);
bytes memory swap = encodeSplitSwap(
uint8(0), uint8(1), uint24(0), address(usv3Executor), protocolData
@@ -366,59 +406,6 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
tychoRouter.exposedSplitSwap(amountIn, 2, swaps);
}
function testSplitSwapAmountInNotFullySpent() public {
// Trade 1 WETH for DAI with 1 swap on Uniswap V2
// Has invalid data as input! There is only one swap with 60% of the input amount
uint256 amountIn = 1 ether;
deal(WETH_ADDR, ALICE, amountIn);
vm.startPrank(ALICE);
(
IAllowanceTransfer.PermitSingle memory permitSingle,
bytes memory signature
) = handlePermit2Approval(WETH_ADDR, tychoRouterAddr, amountIn);
bytes memory protocolData = encodeUniswapV2Swap(
WETH_ADDR, WETH_DAI_POOL, tychoRouterAddr, false
);
bytes memory swap = encodeSplitSwap(
uint8(0),
uint8(1),
(0xffffff * 60) / 100, // 60%
address(usv2Executor),
protocolData
);
bytes[] memory swaps = new bytes[](1);
swaps[0] = swap;
vm.expectRevert(
abi.encodeWithSelector(
TychoRouter__AmountInDiffersFromConsumed.selector,
1000000000000000000,
600000000000000000
)
);
tychoRouter.splitSwapPermit2(
amountIn,
WETH_ADDR,
DAI_ADDR,
1,
false,
false,
2,
ALICE,
permitSingle,
signature,
pleEncode(swaps)
);
vm.stopPrank();
}
function testSplitSwapSingleUSV4CallbackPermit2() public {
vm.startPrank(ALICE);
uint256 amountIn = 100 ether;
@@ -436,8 +423,13 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
tickSpacing: int24(1)
});
bytes memory protocolData =
UniswapV4Utils.encodeExactInput(USDE_ADDR, USDT_ADDR, true, pools);
bytes memory protocolData = UniswapV4Utils.encodeExactInput(
USDE_ADDR,
USDT_ADDR,
true,
TokenTransfer.TransferType.TRANSFER_PERMIT2_TO_ROUTER,
pools
);
bytes memory swap = encodeSplitSwap(
uint8(0), uint8(1), uint24(0), address(usv4Executor), protocolData
@@ -483,8 +475,9 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
tickSpacing: int24(60)
});
bytes memory protocolData =
UniswapV4Utils.encodeExactInput(USDE_ADDR, WBTC_ADDR, true, pools);
bytes memory protocolData = UniswapV4Utils.encodeExactInput(
USDE_ADDR, WBTC_ADDR, true, TokenTransfer.TransferType.NONE, pools
);
bytes memory swap = encodeSplitSwap(
uint8(0), uint8(1), uint24(0), address(usv4Executor), protocolData
@@ -507,18 +500,35 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
// │ │
// └─ (USV3, 40% split) ──> WETH ─┘
uint256 amountIn = 100 * 10 ** 6;
deal(USDC_ADDR, tychoRouterAddr, amountIn);
deal(USDC_ADDR, ALICE, amountIn);
vm.startPrank(ALICE);
// Approve the TychoRouter to spend USDC
IERC20(USDC_ADDR).approve(tychoRouterAddr, amountIn);
bytes memory usdcWethV3Pool1ZeroOneData = encodeUniswapV3Swap(
USDC_ADDR, WETH_ADDR, tychoRouterAddr, USDC_WETH_USV3, true
USDC_ADDR,
WETH_ADDR,
tychoRouterAddr,
USDC_WETH_USV3,
true,
TokenTransfer.TransferType.TRANSFER_FROM_TO_PROTOCOL
);
bytes memory usdcWethV3Pool2ZeroOneData = encodeUniswapV3Swap(
USDC_ADDR, WETH_ADDR, tychoRouterAddr, USDC_WETH_USV3_2, true
USDC_ADDR,
WETH_ADDR,
tychoRouterAddr,
USDC_WETH_USV3_2,
true,
TokenTransfer.TransferType.TRANSFER_FROM_TO_PROTOCOL
);
bytes memory wethUsdcV2OneZeroData = encodeUniswapV2Swap(
WETH_ADDR, USDC_WETH_USV2, tychoRouterAddr, false
WETH_ADDR,
USDC_WETH_USV2,
tychoRouterAddr,
false,
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL
);
bytes[] memory swaps = new bytes[](3);
@@ -547,6 +557,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
wethUsdcV2OneZeroData
);
tychoRouter.exposedSplitSwap(amountIn, 2, pleEncode(swaps));
vm.stopPrank();
assertEq(IERC20(USDC_ADDR).balanceOf(tychoRouterAddr), 99574171);
}
@@ -563,15 +574,29 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
deal(USDC_ADDR, tychoRouterAddr, amountIn);
bytes memory usdcWethV2Data = encodeUniswapV2Swap(
USDC_ADDR, USDC_WETH_USV2, tychoRouterAddr, true
USDC_ADDR,
USDC_WETH_USV2,
tychoRouterAddr,
true,
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL
);
bytes memory usdcWethV3Pool1OneZeroData = encodeUniswapV3Swap(
WETH_ADDR, USDC_ADDR, tychoRouterAddr, USDC_WETH_USV3, false
WETH_ADDR,
USDC_ADDR,
tychoRouterAddr,
USDC_WETH_USV3,
false,
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL
);
bytes memory usdcWethV3Pool2OneZeroData = encodeUniswapV3Swap(
WETH_ADDR, USDC_ADDR, tychoRouterAddr, USDC_WETH_USV3_2, false
WETH_ADDR,
USDC_ADDR,
tychoRouterAddr,
USDC_WETH_USV3_2,
false,
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL
);
bytes[] memory swaps = new bytes[](3);
@@ -610,7 +635,11 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
deal(BASE_USDC, tychoRouterAddr, amountIn);
bytes memory protocolData = encodeUniswapV2Swap(
BASE_USDC, USDC_MAG7_POOL, tychoRouterAddr, true
BASE_USDC,
USDC_MAG7_POOL,
tychoRouterAddr,
true,
TokenTransfer.TransferType.TRANSFER_FROM_TO_PROTOCOL
);
bytes memory swap = encodeSplitSwap(

View File

@@ -102,13 +102,13 @@ contract TychoRouterTestSetup is Constants, Permit2TestHelper {
new UniswapV2Executor(factoryV2, initCodeV2, PERMIT2_ADDRESS);
usv3Executor =
new UniswapV3Executor(factoryV3, initCodeV3, PERMIT2_ADDRESS);
usv4Executor = new UniswapV4Executor(poolManager);
usv4Executor = new UniswapV4Executor(poolManager, PERMIT2_ADDRESS);
pancakev3Executor = new UniswapV3Executor(
factoryPancakeV3, initCodePancakeV3, PERMIT2_ADDRESS
);
balancerv2Executor = new BalancerV2Executor();
balancerv2Executor = new BalancerV2Executor(PERMIT2_ADDRESS);
ekuboExecutor = new EkuboExecutor(ekuboCore);
curveExecutor = new CurveExecutor(ETH_ADDR_FOR_CURVE);
curveExecutor = new CurveExecutor(ETH_ADDR_FOR_CURVE, PERMIT2_ADDRESS);
address[] memory executors = new address[](7);
executors[0] = address(usv2Executor);
@@ -178,15 +178,11 @@ contract TychoRouterTestSetup is Constants, Permit2TestHelper {
address tokenIn,
address target,
address receiver,
bool zero2one
bool zero2one,
TokenTransfer.TransferType transferType
) internal pure returns (bytes memory) {
return abi.encodePacked(
tokenIn,
target,
receiver,
zero2one,
TokenTransfer.TransferType.TRANSFER
);
return
abi.encodePacked(tokenIn, target, receiver, zero2one, transferType);
}
function encodeUniswapV3Swap(
@@ -194,7 +190,8 @@ contract TychoRouterTestSetup is Constants, Permit2TestHelper {
address tokenOut,
address receiver,
address target,
bool zero2one
bool zero2one,
TokenTransfer.TransferType transferType
) internal view returns (bytes memory) {
IUniswapV3Pool pool = IUniswapV3Pool(target);
return abi.encodePacked(
@@ -204,7 +201,7 @@ contract TychoRouterTestSetup is Constants, Permit2TestHelper {
receiver,
target,
zero2one,
TokenTransfer.TransferType.TRANSFER
transferType
);
}
}

View File

@@ -6,6 +6,8 @@ import {Test} from "../../lib/forge-std/src/Test.sol";
import {Constants} from "../Constants.sol";
contract BalancerV2ExecutorExposed is BalancerV2Executor {
constructor(address _permit2) BalancerV2Executor(_permit2) {}
function decodeParams(bytes calldata data)
external
pure
@@ -14,18 +16,15 @@ contract BalancerV2ExecutorExposed is BalancerV2Executor {
IERC20 tokenOut,
bytes32 poolId,
address receiver,
bool needsApproval
bool needsApproval,
TransferType transferType
)
{
return _decodeData(data);
}
}
contract BalancerV2ExecutorTest is
BalancerV2ExecutorExposed,
Test,
Constants
{
contract BalancerV2ExecutorTest is Test, Constants {
using SafeERC20 for IERC20;
BalancerV2ExecutorExposed balancerV2Exposed;
@@ -37,12 +36,17 @@ contract BalancerV2ExecutorTest is
function setUp() public {
uint256 forkBlock = 17323404;
vm.createSelectFork(vm.rpcUrl("mainnet"), forkBlock);
balancerV2Exposed = new BalancerV2ExecutorExposed();
balancerV2Exposed = new BalancerV2ExecutorExposed(PERMIT2_ADDRESS);
}
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,
TokenTransfer.TransferType.NONE
);
(
@@ -50,7 +54,8 @@ contract BalancerV2ExecutorTest is
IERC20 tokenOut,
bytes32 poolId,
address receiver,
bool needsApproval
bool needsApproval,
TokenTransfer.TransferType transferType
) = balancerV2Exposed.decodeParams(params);
assertEq(address(tokenIn), WETH_ADDR);
@@ -58,6 +63,7 @@ contract BalancerV2ExecutorTest is
assertEq(poolId, WETH_BAL_POOL_ID);
assertEq(receiver, address(2));
assertEq(needsApproval, true);
assertEq(uint8(transferType), uint8(TokenTransfer.TransferType.NONE));
}
function testDecodeParamsInvalidDataLength() public {
@@ -70,8 +76,14 @@ contract BalancerV2ExecutorTest is
function testSwap() public {
uint256 amountIn = 10 ** 18;
bytes memory protocolData =
abi.encodePacked(WETH_ADDR, BAL_ADDR, WETH_BAL_POOL_ID, BOB, true);
bytes memory protocolData = abi.encodePacked(
WETH_ADDR,
BAL_ADDR,
WETH_BAL_POOL_ID,
BOB,
true,
TokenTransfer.TransferType.NONE
);
deal(WETH_ADDR, address(balancerV2Exposed), amountIn);
uint256 balanceBefore = BAL.balanceOf(BOB);
@@ -86,14 +98,15 @@ contract BalancerV2ExecutorTest is
function testDecodeIntegration() public view {
// Generated by the SwapEncoder - test_encode_balancer_v2
bytes memory protocolData =
hex"c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2ba100000625a3754423978a60c9317c58a424e3d5c6ee304399dbdb9c8ef030ab642b10820db8f560002000000000000000000141d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e01";
hex"c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2ba100000625a3754423978a60c9317c58a424e3d5c6ee304399dbdb9c8ef030ab642b10820db8f560002000000000000000000141d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e0105";
(
IERC20 tokenIn,
IERC20 tokenOut,
bytes32 poolId,
address receiver,
bool needsApproval
bool needsApproval,
TokenTransfer.TransferType transferType
) = balancerV2Exposed.decodeParams(protocolData);
assertEq(address(tokenIn), WETH_ADDR);
@@ -101,12 +114,13 @@ contract BalancerV2ExecutorTest is
assertEq(poolId, WETH_BAL_POOL_ID);
assertEq(receiver, BOB);
assertEq(needsApproval, true);
assertEq(uint8(transferType), uint8(TokenTransfer.TransferType.NONE));
}
function testSwapIntegration() public {
// Generated by the SwapEncoder - test_encode_balancer_v2
bytes memory protocolData =
hex"c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2ba100000625a3754423978a60c9317c58a424e3d5c6ee304399dbdb9c8ef030ab642b10820db8f560002000000000000000000141d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e01";
hex"c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2ba100000625a3754423978a60c9317c58a424e3d5c6ee304399dbdb9c8ef030ab642b10820db8f560002000000000000000000141d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e0105";
uint256 amountIn = 10 ** 18;
deal(WETH_ADDR, address(balancerV2Exposed), amountIn);

View File

@@ -22,7 +22,9 @@ interface MetaRegistry {
}
contract CurveExecutorExposed is CurveExecutor {
constructor(address _nativeToken) CurveExecutor(_nativeToken) {}
constructor(address _nativeToken, address _permit2)
CurveExecutor(_nativeToken, _permit2)
{}
function decodeData(bytes calldata data)
external
@@ -34,7 +36,8 @@ contract CurveExecutorExposed is CurveExecutor {
uint8 poolType,
int128 i,
int128 j,
bool tokenApprovalNeeded
bool tokenApprovalNeeded,
TokenTransfer.TransferType transferType
)
{
return _decodeData(data);
@@ -50,7 +53,8 @@ contract CurveExecutorTest is Test, Constants {
function setUp() public {
uint256 forkBlock = 22031795;
vm.createSelectFork(vm.rpcUrl("mainnet"), forkBlock);
curveExecutorExposed = new CurveExecutorExposed(ETH_ADDR_FOR_CURVE);
curveExecutorExposed =
new CurveExecutorExposed(ETH_ADDR_FOR_CURVE, PERMIT2_ADDRESS);
metaRegistry = MetaRegistry(CURVE_META_REGISTRY);
}
@@ -62,7 +66,8 @@ contract CurveExecutorTest is Test, Constants {
uint8(3),
uint8(2),
uint8(0),
true
true,
TokenTransfer.TransferType.NONE
);
(
@@ -72,7 +77,8 @@ contract CurveExecutorTest is Test, Constants {
uint8 poolType,
int128 i,
int128 j,
bool tokenApprovalNeeded
bool tokenApprovalNeeded,
TokenTransfer.TransferType transferType
) = curveExecutorExposed.decodeData(data);
assertEq(tokenIn, WETH_ADDR);
@@ -82,6 +88,7 @@ contract CurveExecutorTest is Test, Constants {
assertEq(i, 2);
assertEq(j, 0);
assertEq(tokenApprovalNeeded, true);
assertEq(uint8(transferType), uint8(TokenTransfer.TransferType.NONE));
}
function testTriPool() public {
@@ -311,7 +318,8 @@ contract CurveExecutorTest is Test, Constants {
poolType,
uint8(uint256(uint128(i))),
uint8(uint256(uint128(j))),
true
true,
TokenTransfer.TransferType.NONE
);
}

View File

@@ -84,7 +84,7 @@ contract UniswapV2ExecutorTest is Test, Constants, Permit2TestHelper {
address(2),
address(3),
false,
TokenTransfer.TransferType.TRANSFER
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL
);
(
@@ -100,7 +100,8 @@ contract UniswapV2ExecutorTest is Test, Constants, Permit2TestHelper {
assertEq(receiver, address(3));
assertEq(zeroForOne, false);
assertEq(
uint8(TokenTransfer.TransferType.TRANSFER), uint8(transferType)
uint8(TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL),
uint8(transferType)
);
}
@@ -157,7 +158,7 @@ contract UniswapV2ExecutorTest is Test, Constants, Permit2TestHelper {
WETH_DAI_POOL,
BOB,
zeroForOne,
uint8(TokenTransfer.TransferType.TRANSFER)
uint8(TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL)
);
deal(WETH_ADDR, address(uniswapV2Exposed), amountIn);
@@ -176,7 +177,7 @@ contract UniswapV2ExecutorTest is Test, Constants, Permit2TestHelper {
WETH_DAI_POOL,
BOB,
zeroForOne,
uint8(TokenTransfer.TransferType.TRANSFERFROM)
uint8(TokenTransfer.TransferType.TRANSFER_FROM_TO_PROTOCOL)
);
deal(WETH_ADDR, address(this), amountIn);
@@ -197,7 +198,7 @@ contract UniswapV2ExecutorTest is Test, Constants, Permit2TestHelper {
WETH_DAI_POOL,
ALICE,
zeroForOne,
uint8(TokenTransfer.TransferType.TRANSFERPERMIT2)
uint8(TokenTransfer.TransferType.TRANSFER_PERMIT2_TO_PROTOCOL)
);
deal(WETH_ADDR, ALICE, amountIn);
@@ -283,7 +284,7 @@ contract UniswapV2ExecutorTest is Test, Constants, Permit2TestHelper {
fakePool,
BOB,
zeroForOne,
uint8(TokenTransfer.TransferType.TRANSFER)
uint8(TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL)
);
deal(WETH_ADDR, address(uniswapV2Exposed), amountIn);
@@ -303,7 +304,7 @@ contract UniswapV2ExecutorTest is Test, Constants, Permit2TestHelper {
USDC_MAG7_POOL,
BOB,
zeroForOne,
uint8(TokenTransfer.TransferType.TRANSFER)
uint8(TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL)
);
deal(BASE_USDC, address(uniswapV2Exposed), amountIn);

View File

@@ -71,7 +71,7 @@ contract UniswapV3ExecutorTest is Test, Constants, Permit2TestHelper {
address(2),
address(3),
false,
TokenTransfer.TransferType.TRANSFER
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL
);
(
@@ -91,7 +91,8 @@ contract UniswapV3ExecutorTest is Test, Constants, Permit2TestHelper {
assertEq(target, address(3));
assertEq(zeroForOne, false);
assertEq(
uint8(transferType), uint8(TokenTransfer.TransferType.TRANSFER)
uint8(transferType),
uint8(TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL)
);
}
@@ -123,7 +124,11 @@ contract UniswapV3ExecutorTest is Test, Constants, Permit2TestHelper {
vm.startPrank(DAI_WETH_USV3);
bytes memory protocolData = abi.encodePacked(
WETH_ADDR, DAI_ADDR, poolFee, TokenTransfer.TransferType.TRANSFER
WETH_ADDR,
DAI_ADDR,
poolFee,
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL,
address(uniswapV3Exposed)
);
uint256 dataOffset = 3; // some offset
uint256 dataLength = protocolData.length;
@@ -134,8 +139,7 @@ contract UniswapV3ExecutorTest is Test, Constants, Permit2TestHelper {
int256(0), // amount1Delta
dataOffset,
dataLength,
protocolData,
address(uniswapV3Exposed) // transferFrom sender (irrelevant in this case)
protocolData
);
uniswapV3Exposed.handleCallback(callbackData);
vm.stopPrank();
@@ -157,7 +161,7 @@ contract UniswapV3ExecutorTest is Test, Constants, Permit2TestHelper {
address(this),
fakePool,
zeroForOne,
TokenTransfer.TransferType.TRANSFER
TokenTransfer.TransferType.TRANSFER_TO_PROTOCOL
);
vm.expectRevert(UniswapV3Executor__InvalidTarget.selector);

View File

@@ -7,9 +7,12 @@ import "@src/executors/UniswapV4Executor.sol";
import {Constants} from "../Constants.sol";
import {Test} from "../../lib/forge-std/src/Test.sol";
import {SafeCallback} from "@uniswap/v4-periphery/src/base/SafeCallback.sol";
import "@src/executors/TokenTransfer.sol";
contract UniswapV4ExecutorExposed is UniswapV4Executor {
constructor(IPoolManager _poolManager) UniswapV4Executor(_poolManager) {}
constructor(IPoolManager _poolManager, address _permit2)
UniswapV4Executor(_poolManager, _permit2)
{}
function decodeData(bytes calldata data)
external
@@ -18,6 +21,7 @@ contract UniswapV4ExecutorExposed is UniswapV4Executor {
address tokenIn,
address tokenOut,
bool zeroForOne,
TokenTransfer.TransferType transferType,
UniswapV4Pool[] memory pools
)
{
@@ -36,8 +40,9 @@ contract UniswapV4ExecutorTest is Test, Constants {
function setUp() public {
uint256 forkBlock = 21817316;
vm.createSelectFork(vm.rpcUrl("mainnet"), forkBlock);
uniswapV4Exposed =
new UniswapV4ExecutorExposed(IPoolManager(poolManager));
uniswapV4Exposed = new UniswapV4ExecutorExposed(
IPoolManager(poolManager), PERMIT2_ADDRESS
);
}
function testDecodeParams() public view {
@@ -46,6 +51,8 @@ contract UniswapV4ExecutorTest is Test, Constants {
int24 tickSpacing1 = 60;
uint24 pool2Fee = 1000;
int24 tickSpacing2 = -10;
TokenTransfer.TransferType transferType =
TokenTransfer.TransferType.TRANSFER_FROM_TO_PROTOCOL;
UniswapV4Executor.UniswapV4Pool[] memory pools =
new UniswapV4Executor.UniswapV4Pool[](2);
@@ -61,19 +68,21 @@ contract UniswapV4ExecutorTest is Test, Constants {
});
bytes memory data = UniswapV4Utils.encodeExactInput(
USDE_ADDR, USDT_ADDR, zeroForOne, pools
USDE_ADDR, USDT_ADDR, zeroForOne, transferType, pools
);
(
address tokenIn,
address tokenOut,
bool zeroForOneDecoded,
TokenTransfer.TransferType transferTypeDecoded,
UniswapV4Executor.UniswapV4Pool[] memory decodedPools
) = uniswapV4Exposed.decodeData(data);
assertEq(tokenIn, USDE_ADDR);
assertEq(tokenOut, USDT_ADDR);
assertEq(zeroForOneDecoded, zeroForOne);
assertEq(uint8(transferTypeDecoded), uint8(transferType));
assertEq(decodedPools.length, 2);
assertEq(decodedPools[0].intermediaryToken, USDT_ADDR);
assertEq(decodedPools[0].fee, pool1Fee);
@@ -98,8 +107,9 @@ contract UniswapV4ExecutorTest is Test, Constants {
tickSpacing: int24(1)
});
bytes memory data =
UniswapV4Utils.encodeExactInput(USDE_ADDR, USDT_ADDR, true, pools);
bytes memory data = UniswapV4Utils.encodeExactInput(
USDE_ADDR, USDT_ADDR, true, TokenTransfer.TransferType.NONE, pools
);
uint256 amountOut = uniswapV4Exposed.swap(amountIn, data);
assertEq(USDE.balanceOf(poolManager), usdeBalanceBeforePool + amountIn);
@@ -114,7 +124,7 @@ contract UniswapV4ExecutorTest is Test, Constants {
// USDE -> USDT
// Generated by the Tycho swap encoder - test_encode_uniswap_v4_simple_swap
bytes memory protocolData =
hex"4c9edd5852cd905f086c759e8383e09bff1e68b3dac17f958d2ee523a2206206994597c13d831ec701dac17f958d2ee523a2206206994597c13d831ec7000064000001";
hex"4c9edd5852cd905f086c759e8383e09bff1e68b3dac17f958d2ee523a2206206994597c13d831ec70100dac17f958d2ee523a2206206994597c13d831ec7000064000001";
uint256 amountIn = 100 ether;
deal(USDE_ADDR, address(uniswapV4Exposed), amountIn);
uint256 usdeBalanceBeforePool = USDE.balanceOf(poolManager);
@@ -151,8 +161,9 @@ contract UniswapV4ExecutorTest is Test, Constants {
tickSpacing: int24(60)
});
bytes memory data =
UniswapV4Utils.encodeExactInput(USDE_ADDR, WBTC_ADDR, true, pools);
bytes memory data = UniswapV4Utils.encodeExactInput(
USDE_ADDR, WBTC_ADDR, true, TokenTransfer.TransferType.NONE, pools
);
uint256 amountOut = uniswapV4Exposed.swap(amountIn, data);
assertEq(USDE.balanceOf(poolManager), usdeBalanceBeforePool + amountIn);
@@ -170,7 +181,7 @@ contract UniswapV4ExecutorTest is Test, Constants {
// Generated by the Tycho swap encoder - test_encode_uniswap_v4_sequential_swap
bytes memory protocolData =
hex"4c9edd5852cd905f086c759e8383e09bff1e68b32260fac5e5542a773aa44fbcfedf7c193bc2c59901dac17f958d2ee523a2206206994597c13d831ec70000640000012260fac5e5542a773aa44fbcfedf7c193bc2c599000bb800003c";
hex"4c9edd5852cd905f086c759e8383e09bff1e68b32260fac5e5542a773aa44fbcfedf7c193bc2c5990100dac17f958d2ee523a2206206994597c13d831ec70000640000012260fac5e5542a773aa44fbcfedf7c193bc2c599000bb800003c";
uint256 amountIn = 100 ether;
deal(USDE_ADDR, address(uniswapV4Exposed), amountIn);

View File

@@ -8,6 +8,7 @@ library UniswapV4Utils {
address tokenIn,
address tokenOut,
bool zeroForOne,
UniswapV4Executor.TransferType transferType,
UniswapV4Executor.UniswapV4Pool[] memory pools
) public pure returns (bytes memory) {
bytes memory encodedPools;
@@ -21,6 +22,8 @@ library UniswapV4Utils {
);
}
return abi.encodePacked(tokenIn, tokenOut, zeroForOne, encodedPools);
return abi.encodePacked(
tokenIn, tokenOut, zeroForOne, transferType, encodedPools
);
}
}

View File

@@ -17,3 +17,23 @@ pub static GROUPABLE_PROTOCOLS: LazyLock<HashSet<&'static str>> = LazyLock::new(
set.insert("ekubo_v2");
set
});
/// These protocols support the optimization of transferring straight from the user.
pub static IN_TRANSFER_OPTIMIZABLE_PROTOCOLS: LazyLock<HashSet<&'static str>> =
LazyLock::new(|| {
let mut set = HashSet::new();
set.insert("uniswap_v2");
set.insert("uniswap_v3");
set
});
/// These protocols expect funds to be in the router at the time of swap.
pub static PROTOCOLS_EXPECTING_FUNDS_IN_ROUTER: LazyLock<HashSet<&'static str>> =
LazyLock::new(|| {
let mut set = HashSet::new();
set.insert("vm:curve");
set.insert("balancer_v2");
// TODO remove uniswap_v4 when we add callback support for transfer optimizations
set.insert("uniswap_v4");
set
});

View File

@@ -1,2 +1,4 @@
pub mod strategy_encoders;
mod strategy_validators;
mod transfer_optimizations;

View File

@@ -9,8 +9,9 @@ use crate::encoding::{
evm::{
approvals::permit2::Permit2,
group_swaps::group_swaps,
strategy_encoder::strategy_validators::{
SequentialSwapValidator, SplitSwapValidator, SwapValidator,
strategy_encoder::{
strategy_validators::{SequentialSwapValidator, SplitSwapValidator, SwapValidator},
transfer_optimizations::TransferOptimization,
},
swap_encoder::swap_encoder_registry::SwapEncoderRegistry,
utils::{
@@ -38,6 +39,8 @@ pub struct SingleSwapStrategyEncoder {
swap_encoder_registry: SwapEncoderRegistry,
permit2: Option<Permit2>,
selector: String,
native_address: Bytes,
wrapped_address: Bytes,
router_address: Bytes,
}
@@ -56,7 +59,14 @@ impl SingleSwapStrategyEncoder {
"singleSwap(uint256,address,address,uint256,bool,bool,address,bytes)".to_string(),
)
};
Ok(Self { permit2, selector, swap_encoder_registry, router_address })
Ok(Self {
permit2,
selector,
swap_encoder_registry,
native_address: chain.native_token()?,
wrapped_address: chain.wrapped_token()?,
router_address,
})
}
/// Encodes information necessary for performing a single hop against a given executor for
@@ -69,6 +79,8 @@ impl SingleSwapStrategyEncoder {
}
}
impl TransferOptimization for SingleSwapStrategyEncoder {}
impl StrategyEncoder for SingleSwapStrategyEncoder {
fn encode_strategy(&self, solution: Solution) -> Result<(Vec<u8>, Bytes), EncodingError> {
let grouped_swaps = group_swaps(solution.clone().swaps);
@@ -111,12 +123,22 @@ impl StrategyEncoder for SingleSwapStrategyEncoder {
let mut grouped_protocol_data: Vec<u8> = vec![];
for swap in grouped_swap.swaps.iter() {
let transfer_type = self.get_transfer_type(
swap.clone(),
solution.given_token.clone(),
self.native_address.clone(),
self.wrapped_address.clone(),
self.permit2.clone().is_some(),
wrap,
);
let encoding_context = EncodingContext {
receiver: self.router_address.clone(),
exact_out: solution.exact_out,
router_address: Some(self.router_address.clone()),
group_token_in: grouped_swap.input_token.clone(),
group_token_out: grouped_swap.output_token.clone(),
transfer_type: transfer_type.clone(),
};
let protocol_data = swap_encoder.encode_swap(swap.clone(), encoding_context.clone())?;
grouped_protocol_data.extend(protocol_data);
@@ -199,6 +221,8 @@ pub struct SequentialSwapStrategyEncoder {
sequential_swap_validator: SequentialSwapValidator,
}
impl TransferOptimization for SequentialSwapStrategyEncoder {}
impl SequentialSwapStrategyEncoder {
pub fn new(
chain: Chain,
@@ -274,12 +298,22 @@ impl StrategyEncoder for SequentialSwapStrategyEncoder {
let mut grouped_protocol_data: Vec<u8> = vec![];
for swap in grouped_swap.swaps.iter() {
let transfer_type = self.get_transfer_type(
swap.clone(),
solution.given_token.clone(),
self.native_address.clone(),
self.wrapped_address.clone(),
self.permit2.clone().is_some(),
wrap,
);
let encoding_context = EncodingContext {
receiver: self.router_address.clone(),
exact_out: solution.exact_out,
router_address: Some(self.router_address.clone()),
group_token_in: grouped_swap.input_token.clone(),
group_token_out: grouped_swap.output_token.clone(),
transfer_type: transfer_type.clone(),
};
let protocol_data =
swap_encoder.encode_swap(swap.clone(), encoding_context.clone())?;
@@ -415,6 +449,8 @@ impl SplitSwapStrategyEncoder {
}
}
impl TransferOptimization for SplitSwapStrategyEncoder {}
impl StrategyEncoder for SplitSwapStrategyEncoder {
fn encode_strategy(&self, solution: Solution) -> Result<(Vec<u8>, Bytes), EncodingError> {
self.split_swap_validator
@@ -491,12 +527,22 @@ impl StrategyEncoder for SplitSwapStrategyEncoder {
let mut grouped_protocol_data: Vec<u8> = vec![];
for swap in grouped_swap.swaps.iter() {
let transfer_type = self.get_transfer_type(
swap.clone(),
solution.given_token.clone(),
self.native_address.clone(),
self.wrapped_address.clone(),
self.permit2.clone().is_some(),
wrap,
);
let encoding_context = EncodingContext {
receiver: self.router_address.clone(),
exact_out: solution.exact_out,
router_address: Some(self.router_address.clone()),
group_token_in: grouped_swap.input_token.clone(),
group_token_out: grouped_swap.output_token.clone(),
transfer_type: transfer_type.clone(),
};
let protocol_data =
swap_encoder.encode_swap(swap.clone(), encoding_context.clone())?;
@@ -722,7 +768,7 @@ mod tests {
"a478c2975ab1ea89e8196811f51a7b7ade33eb11", // component id
"3ede3eca2a72b3aecc820e955b36f38437d01395", // receiver
"00", // zero2one
"00", // transfer type
"02", // transfer type
"00000000000000", // padding
));
let hex_calldata = encode(&calldata);
@@ -825,11 +871,11 @@ mod tests {
"a478c2975ab1ea89e8196811f51a7b7ade33eb11", // component id
"3ede3eca2a72b3aecc820e955b36f38437d01395", // receiver
"00", // zero2one
"00", // exact out
"00", // transfer type
"00000000000000000000000000", // padding
"02", // transfer type
"0000000000000000000000000000", // padding
));
let hex_calldata = encode(&calldata);
println!("{}", hex_calldata);
assert_eq!(hex_calldata[..456], expected_input);
assert_eq!(hex_calldata[1224..], expected_swap);
@@ -1327,9 +1373,9 @@ mod tests {
let expected_swaps = String::from(concat!(
// length of ple encoded swaps without padding
"0000000000000000000000000000000000000000000000000000000000000078",
"0000000000000000000000000000000000000000000000000000000000000079",
// ple encoded swaps
"0076", // Swap length
"0077", // Swap length
"00", // token in index
"01", // token out index
"000000", // split
@@ -1339,6 +1385,7 @@ mod tests {
"a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // group token in
"6982508145454ce325ddbe47a25d4ec3d2311933", // group token in
"00", // zero2one
"04", // transfer type (transfer to router)
// First pool params
"0000000000000000000000000000000000000000", // intermediary token (ETH)
"000bb8", // fee
@@ -1347,7 +1394,7 @@ mod tests {
"6982508145454ce325ddbe47a25d4ec3d2311933", // intermediary token (PEPE)
"0061a8", // fee
"0001f4", // tick spacing
"0000000000000000" // padding
"00000000000000" // padding
));
let hex_calldata = encode(&calldata);
@@ -1484,9 +1531,8 @@ mod tests {
"a478c2975ab1ea89e8196811f51a7b7ade33eb11", // component id
"3ede3eca2a72b3aecc820e955b36f38437d01395", // receiver
"00", // zero2one
"00", // exact out
"00", // transfer type
"00000000000000000000000000", // padding
"01", // transfer type
"0000000000000000000000000000", // padding
]
.join("");
@@ -1568,9 +1614,8 @@ mod tests {
"a478c2975ab1ea89e8196811f51a7b7ade33eb11", // component id
"3ede3eca2a72b3aecc820e955b36f38437d01395", // receiver
"00", // zero2one
"00", // exact out
"00", // transfer type
"000000000000", // padding
"01", // transfer type
"00000000000000", // padding
]
.join("");
@@ -1821,7 +1866,7 @@ mod tests {
"3ede3eca2a72b3aecc820e955b36f38437d01395", // router address
"88e6a0c2ddd26feeb64f039a2c41296fcb3f5640", // component id
"01", // zero2one
"00", // transfer type
"02", // transfer type
"006e", // ple encoded swaps
"01", // token in index
"00000000", // split
@@ -1975,7 +2020,7 @@ mod tests {
"3ede3eca2a72b3aecc820e955b36f38437d01395", // router address
"88e6a0c2ddd26feeb64f039a2c41296fcb3f5640", // component id
"01", // zero2one
"00", // transfer type
"02", // transfer type
"006e", // ple encoded swaps
"00", // token in index
"01", // token out index
@@ -1987,7 +2032,7 @@ mod tests {
"3ede3eca2a72b3aecc820e955b36f38437d01395", // router address
"8ad599c3a0ff1de082011efddc58f1908eb6e6d8", // component id
"01", // zero2one
"00", // transfer type
"02", // transfer type
"0057", // ple encoded swaps
"01", // token in index
"00", // token out index
@@ -2135,7 +2180,7 @@ mod tests {
"b4e16d0168e52d35cacd2c6185b44281ec28c9dc", // component id
"3ede3eca2a72b3aecc820e955b36f38437d01395", // router address
"01", // zero2one
"00", // transfer type
"02", // transfer type
"006e", // ple encoded swaps
"01", // token in index
"00", // token out index

View File

@@ -0,0 +1,173 @@
use tycho_common::Bytes;
use crate::encoding::{
evm::constants::{IN_TRANSFER_OPTIMIZABLE_PROTOCOLS, PROTOCOLS_EXPECTING_FUNDS_IN_ROUTER},
models::{Swap, TransferType},
};
/// A trait that defines how the tokens will be transferred into the given pool given the solution.
pub trait TransferOptimization {
/// Returns the transfer method that should be used for the given swap and solution.
fn get_transfer_type(
&self,
swap: Swap,
given_token: Bytes,
native_token: Bytes,
wrapped_token: Bytes,
permit2: bool,
wrap: bool,
) -> TransferType {
let send_funds_to_pool: bool =
IN_TRANSFER_OPTIMIZABLE_PROTOCOLS.contains(&swap.component.protocol_system.as_str());
let funds_expected_in_router: bool =
PROTOCOLS_EXPECTING_FUNDS_IN_ROUTER.contains(&swap.component.protocol_system.as_str());
// In the case of wrapping, check if the swap's token in is the wrapped token to
// determine if it's the first swap. Otherwise, compare to the given token.
let is_first_swap =
(swap.token_in == given_token) || ((swap.token_in == wrapped_token) && wrap);
if swap.token_in == native_token {
// Funds are already in router. All protocols currently take care of native transfers.
TransferType::None
} else if is_first_swap && send_funds_to_pool {
if permit2 {
// Transfer from swapper to pool using permit2.
TransferType::TransferPermit2ToProtocol
} else {
// Transfer from swapper to pool.
TransferType::TransferFromToProtocol
}
} else if is_first_swap && funds_expected_in_router {
if permit2 {
// Transfer from swapper to router using permit2.
TransferType::TransferPermit2ToRouter
} else {
// Transfer from swapper to router.
TransferType::TransferFromToRouter
}
} else {
TransferType::TransferToProtocol
}
}
}
#[cfg(test)]
mod tests {
use alloy_primitives::hex;
use tycho_common::{models::protocol::ProtocolComponent, Bytes};
use super::*;
struct MockStrategy {}
impl TransferOptimization for MockStrategy {}
fn weth() -> Bytes {
Bytes::from(hex!("c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2").to_vec())
}
fn eth() -> Bytes {
Bytes::from(hex!("0000000000000000000000000000000000000000").to_vec())
}
fn dai() -> Bytes {
Bytes::from(hex!("6b175474e89094c44da98b954eedeac495271d0f").to_vec())
}
fn usdc() -> Bytes {
Bytes::from(hex!("0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48").to_vec())
}
#[test]
fn test_first_swap_transfer_from_permit2() {
// The swap token is the same as the given token, which is not the native token
let swap = Swap {
component: ProtocolComponent {
protocol_system: "uniswap_v2".to_string(),
..Default::default()
},
token_in: weth(),
token_out: dai(),
split: 0f64,
};
let strategy = MockStrategy {};
let transfer_method =
strategy.get_transfer_type(swap.clone(), weth(), eth(), weth(), true, false);
assert_eq!(transfer_method, TransferType::TransferPermit2ToProtocol);
}
#[test]
fn test_first_swap_transfer_from() {
// The swap token is the same as the given token, which is not the native token
let swap = Swap {
component: ProtocolComponent {
protocol_system: "uniswap_v2".to_string(),
..Default::default()
},
token_in: weth(),
token_out: dai(),
split: 0f64,
};
let strategy = MockStrategy {};
let transfer_method =
strategy.get_transfer_type(swap.clone(), weth(), eth(), weth(), false, false);
assert_eq!(transfer_method, TransferType::TransferFromToProtocol);
}
#[test]
fn test_first_swap_native() {
// The swap token is the same as the given token, and it's the native token.
// No transfer action is needed.
let swap = Swap {
component: ProtocolComponent {
protocol_system: "uniswap_v2".to_string(),
..Default::default()
},
token_in: eth(),
token_out: dai(),
split: 0f64,
};
let strategy = MockStrategy {};
let transfer_method =
strategy.get_transfer_type(swap.clone(), eth(), eth(), weth(), false, false);
assert_eq!(transfer_method, TransferType::None);
}
#[test]
fn test_first_swap_wrapped() {
// The swap token is NOT the same as the given token, but we are wrapping.
// Since the swap's token in is the wrapped token - this is the first swap.
let swap = Swap {
component: ProtocolComponent {
protocol_system: "uniswap_v2".to_string(),
..Default::default()
},
token_in: weth(),
token_out: dai(),
split: 0f64,
};
let strategy = MockStrategy {};
let transfer_method =
strategy.get_transfer_type(swap.clone(), eth(), eth(), weth(), false, true);
assert_eq!(transfer_method, TransferType::TransferFromToProtocol);
}
#[test]
fn test_not_first_swap() {
// The swap token is NOT the same as the given token, and we are NOT wrapping.
// Thus, this is not the first swap.
let swap = Swap {
component: ProtocolComponent {
protocol_system: "uniswap_v2".to_string(),
..Default::default()
},
token_in: usdc(),
token_out: dai(),
split: 0f64,
};
let strategy = MockStrategy {};
let transfer_method =
strategy.get_transfer_type(swap.clone(), weth(), eth(), weth(), false, false);
assert_eq!(transfer_method, TransferType::TransferToProtocol);
}
}

View File

@@ -22,15 +22,6 @@ use crate::encoding::{
swap_encoder::SwapEncoder,
};
#[allow(dead_code)]
#[repr(u8)]
pub enum TransferType {
Transfer = 0,
TransferFrom = 1,
Permit2Transfer = 2,
None = 3,
}
/// Encodes a swap on a Uniswap V2 pool through the given executor address.
///
/// # Fields
@@ -75,7 +66,7 @@ impl SwapEncoder for UniswapV2SwapEncoder {
component_id,
bytes_to_address(&encoding_context.receiver)?,
zero_to_one,
(TransferType::Transfer as u8).to_be_bytes(),
(encoding_context.transfer_type as u8).to_be_bytes(),
);
Ok(args.abi_encode_packed())
@@ -138,7 +129,7 @@ impl SwapEncoder for UniswapV3SwapEncoder {
bytes_to_address(&encoding_context.receiver)?,
component_id,
zero_to_one,
(TransferType::Transfer as u8).to_be_bytes(),
(encoding_context.transfer_type as u8).to_be_bytes(),
);
Ok(args.abi_encode_packed())
@@ -211,7 +202,13 @@ impl SwapEncoder for UniswapV4SwapEncoder {
let pool_params =
(token_out_address, pool_fee_u24, pool_tick_spacing_u24).abi_encode_packed();
let args = (group_token_in_address, group_token_out_address, zero_to_one, pool_params);
let args = (
group_token_in_address,
group_token_out_address,
zero_to_one,
(encoding_context.transfer_type as u8).to_be_bytes(),
pool_params,
);
Ok(args.abi_encode_packed())
}
@@ -284,6 +281,7 @@ impl SwapEncoder for BalancerV2SwapEncoder {
component_id,
bytes_to_address(&encoding_context.receiver)?,
approval_needed,
(encoding_context.transfer_type as u8).to_be_bytes(),
);
Ok(args.abi_encode_packed())
}
@@ -548,6 +546,7 @@ impl SwapEncoder for CurveSwapEncoder {
i.to_be_bytes::<1>(),
j.to_be_bytes::<1>(),
approval_needed,
(encoding_context.transfer_type as u8).to_be_bytes(),
);
Ok(args.abi_encode_packed())
@@ -573,6 +572,7 @@ mod tests {
};
use super::*;
use crate::encoding::models::TransferType;
#[test]
fn test_encode_uniswap_v2() {
@@ -595,6 +595,7 @@ mod tests {
router_address: Some(Bytes::zero(20)),
group_token_in: token_in.clone(),
group_token_out: token_out.clone(),
transfer_type: TransferType::TransferToProtocol,
};
let encoder = UniswapV2SwapEncoder::new(
String::from("0x543778987b293C7E8Cf0722BB2e935ba6f4068D4"),
@@ -648,6 +649,7 @@ mod tests {
router_address: Some(Bytes::zero(20)),
group_token_in: token_in.clone(),
group_token_out: token_out.clone(),
transfer_type: TransferType::TransferToProtocol,
};
let encoder = UniswapV3SwapEncoder::new(
String::from("0x543778987b293C7E8Cf0722BB2e935ba6f4068D4"),
@@ -702,6 +704,7 @@ mod tests {
router_address: Some(Bytes::zero(20)),
group_token_in: token_in.clone(),
group_token_out: token_out.clone(),
transfer_type: TransferType::None,
};
let encoder = BalancerV2SwapEncoder::new(
String::from("0x543778987b293C7E8Cf0722BB2e935ba6f4068D4"),
@@ -729,7 +732,9 @@ mod tests {
// receiver
"1d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e",
// approval needed
"01"
"01",
// transfer type
"05"
))
);
}
@@ -768,6 +773,7 @@ mod tests {
group_token_in: token_in.clone(),
group_token_out: token_out.clone(),
transfer_type: TransferType::TransferToProtocol,
};
let encoder = UniswapV4SwapEncoder::new(
String::from("0xF62849F9A0B5Bf2913b396098F7c7019b51A820a"),
@@ -790,6 +796,8 @@ mod tests {
"dac17f958d2ee523a2206206994597c13d831ec7",
// zero for one
"01",
// transfer type
"00",
// pool params:
// - intermediary token
"dac17f958d2ee523a2206206994597c13d831ec7",
@@ -834,6 +842,7 @@ mod tests {
group_token_in: group_token_in.clone(),
// Token out is the same as the group token out
group_token_out: token_out.clone(),
transfer_type: TransferType::TransferToProtocol,
};
let encoder = UniswapV4SwapEncoder::new(
@@ -876,6 +885,7 @@ mod tests {
router_address: Some(router_address.clone()),
group_token_in: usde_address.clone(),
group_token_out: wbtc_address.clone(),
transfer_type: TransferType::TransferToProtocol,
};
// Setup - First sequence: USDE -> USDT
@@ -944,6 +954,7 @@ mod tests {
let combined_hex =
format!("{}{}", encode(&initial_encoded_swap), encode(&second_encoded_swap));
println!("{}", combined_hex);
assert_eq!(
combined_hex,
String::from(concat!(
@@ -953,6 +964,8 @@ mod tests {
"2260fac5e5542a773aa44fbcfedf7c193bc2c599",
// zero for one
"01",
// transfer type
"00",
// pool params:
// - intermediary token USDT
"dac17f958d2ee523a2206206994597c13d831ec7",
@@ -1004,6 +1017,7 @@ mod tests {
group_token_out: token_out.clone(),
exact_out: false,
router_address: Some(Bytes::default()),
transfer_type: TransferType::TransferToProtocol,
};
let encoder =
@@ -1046,6 +1060,7 @@ mod tests {
group_token_out: group_token_out.clone(),
exact_out: false,
router_address: Some(Bytes::default()),
transfer_type: TransferType::TransferToProtocol,
};
let first_swap = Swap {
@@ -1222,6 +1237,7 @@ mod tests {
router_address: None,
group_token_in: token_in.clone(),
group_token_out: token_out.clone(),
transfer_type: TransferType::None,
};
let encoder = CurveSwapEncoder::new(
String::from("0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f"),
@@ -1251,6 +1267,8 @@ mod tests {
"01",
// approval needed
"01",
// transfer type
"05",
))
);
}
@@ -1287,6 +1305,7 @@ mod tests {
router_address: None,
group_token_in: token_in.clone(),
group_token_out: token_out.clone(),
transfer_type: TransferType::None,
};
let encoder = CurveSwapEncoder::new(
String::from("0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f"),
@@ -1316,6 +1335,8 @@ mod tests {
"00",
// approval needed
"01",
// transfer type
"05",
))
);
}
@@ -1353,6 +1374,7 @@ mod tests {
router_address: None,
group_token_in: token_in.clone(),
group_token_out: token_out.clone(),
transfer_type: TransferType::None,
};
let encoder = CurveSwapEncoder::new(
String::from("0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f"),
@@ -1391,6 +1413,8 @@ mod tests {
"01",
// approval needed
"01",
// transfer type
"05",
))
);
}

View File

@@ -12,7 +12,7 @@ use crate::encoding::{
},
swap_encoder::swap_encoder_registry::SwapEncoderRegistry,
},
models::{Chain, EncodingContext, NativeAction, Solution, Transaction},
models::{Chain, EncodingContext, NativeAction, Solution, Transaction, TransferType},
strategy_encoder::StrategyEncoder,
tycho_encoder::TychoEncoder,
};
@@ -201,9 +201,10 @@ impl TychoEncoder for TychoRouterEncoder {
}
}
/// Represents an encoder for one swap to be executed directly against an Executor. This is useful
/// when you want to bypass the Tycho Router, use your own Router contract and just need the
/// calldata for a particular swap.
/// Represents an encoder for one swap to be executed directly against an Executor.
///
/// This is useful when you want to bypass the Tycho Router, use your own Router contract and
/// just need the calldata for a particular swap.
///
/// # Fields
/// * `swap_encoder_registry`: Registry of swap encoders
@@ -259,6 +260,7 @@ impl TychoExecutorEncoder {
router_address: None,
group_token_in: grouped_swap.input_token.clone(),
group_token_out: grouped_swap.output_token.clone(),
transfer_type: TransferType::TransferToProtocol,
};
let protocol_data = swap_encoder.encode_swap(swap.clone(), encoding_context.clone())?;
grouped_protocol_data.extend(protocol_data);
@@ -1046,6 +1048,8 @@ mod tests {
"6982508145454ce325ddbe47a25d4ec3d2311933",
// zero for one
"00",
// transfer type
"00",
// first pool intermediary token (ETH)
"0000000000000000000000000000000000000000",
// fee

View File

@@ -96,6 +96,27 @@ pub struct Transaction {
pub data: Vec<u8>,
}
/// Represents the type of transfer to be performed into the pool.
///
/// # Fields
///
/// * `TransferToProtocol`: Transfer the token from the router into the protocol.
/// * `TransferFromToProtocol`: Transfer the token from the sender to the protocol.
/// * `TransferPermit2ToProtocol`: Transfer the token from the sender to the protocol using Permit2.
/// * `TransferFromToRouter`: Transfer the token from the sender to the router.
/// * `TransferPermit2ToRouter`: Transfer the token from the sender to the router using Permit2.
/// * `None`: No transfer is needed. Tokens are already in the pool.
#[repr(u8)]
#[derive(Clone, Debug, PartialEq)]
pub enum TransferType {
TransferToProtocol = 0,
TransferFromToProtocol = 1,
TransferPermit2ToProtocol = 2,
TransferFromToRouter = 3,
TransferPermit2ToRouter = 4,
None = 5,
}
/// Represents necessary attributes for encoding an order.
///
/// # Fields
@@ -113,6 +134,7 @@ pub struct EncodingContext {
pub router_address: Option<Bytes>,
pub group_token_in: Bytes,
pub group_token_out: Bytes,
pub transfer_type: TransferType,
}
#[derive(Clone, PartialEq, Eq, Hash)]