Merge pull request #111 from propeller-heads/router/tnl/executor-transfer-sketch
feat: TokenTransfer helper contract
This commit is contained in:
52
foundry/src/executors/TokenTransfer.sol
Normal file
52
foundry/src/executors/TokenTransfer.sol
Normal file
@@ -0,0 +1,52 @@
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
pragma solidity ^0.8.26;
|
||||
|
||||
import "@interfaces/IExecutor.sol";
|
||||
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
|
||||
import "@permit2/src/interfaces/IAllowanceTransfer.sol";
|
||||
|
||||
error TokenTransfer__AddressZero();
|
||||
|
||||
contract TokenTransfer {
|
||||
using SafeERC20 for IERC20;
|
||||
|
||||
IAllowanceTransfer public immutable permit2;
|
||||
|
||||
enum TransferType {
|
||||
// Assume funds are in the TychoRouter - transfer into the pool
|
||||
TRANSFER,
|
||||
// Assume funds are in msg.sender's wallet - transferFrom into the pool
|
||||
TRANSFERFROM,
|
||||
// Assume funds are in msg.sender's wallet - permit2TransferFrom into the pool
|
||||
TRANSFERPERMIT2,
|
||||
// Assume funds have already been transferred into the pool. Do nothing.
|
||||
NONE
|
||||
}
|
||||
|
||||
constructor(address _permit2) {
|
||||
if (_permit2 == address(0)) {
|
||||
revert TokenTransfer__AddressZero();
|
||||
}
|
||||
permit2 = IAllowanceTransfer(_permit2);
|
||||
}
|
||||
|
||||
function _transfer(
|
||||
IERC20 tokenIn,
|
||||
address sender,
|
||||
address receiver,
|
||||
uint256 amount,
|
||||
TransferType transferType
|
||||
) internal {
|
||||
if (transferType == TransferType.TRANSFER) {
|
||||
tokenIn.safeTransfer(receiver, amount);
|
||||
} else if (transferType == TransferType.TRANSFERFROM) {
|
||||
// slither-disable-next-line arbitrary-send-erc20
|
||||
tokenIn.safeTransferFrom(sender, receiver, amount);
|
||||
} else if (transferType == TransferType.TRANSFERPERMIT2) {
|
||||
// Permit2.permit is already called from the TychoRouter
|
||||
permit2.transferFrom(
|
||||
sender, receiver, uint160(amount), address(tokenIn)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,20 +4,23 @@ pragma solidity ^0.8.26;
|
||||
import "@interfaces/IExecutor.sol";
|
||||
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
|
||||
import "@uniswap-v2/contracts/interfaces/IUniswapV2Pair.sol";
|
||||
import "./TokenTransfer.sol";
|
||||
|
||||
error UniswapV2Executor__InvalidDataLength();
|
||||
error UniswapV2Executor__InvalidTarget();
|
||||
error UniswapV2Executor__InvalidFactory();
|
||||
error UniswapV2Executor__InvalidInitCode();
|
||||
|
||||
contract UniswapV2Executor is IExecutor {
|
||||
contract UniswapV2Executor is IExecutor, TokenTransfer {
|
||||
using SafeERC20 for IERC20;
|
||||
|
||||
address public immutable factory;
|
||||
bytes32 public immutable initCode;
|
||||
address private immutable self;
|
||||
|
||||
constructor(address _factory, bytes32 _initCode) {
|
||||
constructor(address _factory, bytes32 _initCode, address _permit2)
|
||||
TokenTransfer(_permit2)
|
||||
{
|
||||
if (_factory == address(0)) {
|
||||
revert UniswapV2Executor__InvalidFactory();
|
||||
}
|
||||
@@ -35,17 +38,19 @@ contract UniswapV2Executor is IExecutor {
|
||||
payable
|
||||
returns (uint256 calculatedAmount)
|
||||
{
|
||||
IERC20 tokenIn;
|
||||
address target;
|
||||
address receiver;
|
||||
bool zeroForOne;
|
||||
IERC20 tokenIn;
|
||||
TransferType transferType;
|
||||
|
||||
(tokenIn, target, receiver, zeroForOne) = _decodeData(data);
|
||||
(tokenIn, target, receiver, zeroForOne, transferType) =
|
||||
_decodeData(data);
|
||||
|
||||
_verifyPairAddress(target);
|
||||
|
||||
calculatedAmount = _getAmountOut(target, givenAmount, zeroForOne);
|
||||
tokenIn.safeTransfer(target, givenAmount);
|
||||
_transfer(tokenIn, msg.sender, target, givenAmount, transferType);
|
||||
|
||||
IUniswapV2Pair pool = IUniswapV2Pair(target);
|
||||
if (zeroForOne) {
|
||||
@@ -62,16 +67,18 @@ contract UniswapV2Executor is IExecutor {
|
||||
IERC20 inToken,
|
||||
address target,
|
||||
address receiver,
|
||||
bool zeroForOne
|
||||
bool zeroForOne,
|
||||
TransferType transferType
|
||||
)
|
||||
{
|
||||
if (data.length != 61) {
|
||||
if (data.length != 62) {
|
||||
revert UniswapV2Executor__InvalidDataLength();
|
||||
}
|
||||
inToken = IERC20(address(bytes20(data[0:20])));
|
||||
target = address(bytes20(data[20:40]));
|
||||
receiver = address(bytes20(data[40:60]));
|
||||
zeroForOne = uint8(data[60]) > 0;
|
||||
transferType = TransferType(uint8(data[61]));
|
||||
}
|
||||
|
||||
function _getAmountOut(address target, uint256 amountIn, bool zeroForOne)
|
||||
|
||||
@@ -5,13 +5,15 @@ import "@interfaces/IExecutor.sol";
|
||||
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
|
||||
import "@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol";
|
||||
import "@interfaces/ICallback.sol";
|
||||
import {TokenTransfer} from "./TokenTransfer.sol";
|
||||
|
||||
error UniswapV3Executor__InvalidDataLength();
|
||||
error UniswapV3Executor__InvalidFactory();
|
||||
error UniswapV3Executor__InvalidTarget();
|
||||
error UniswapV3Executor__InvalidInitCode();
|
||||
error UniswapV3Executor__InvalidTransferType(uint8 transferType);
|
||||
|
||||
contract UniswapV3Executor is IExecutor, ICallback {
|
||||
contract UniswapV3Executor is IExecutor, ICallback, TokenTransfer {
|
||||
using SafeERC20 for IERC20;
|
||||
|
||||
uint160 private constant MIN_SQRT_RATIO = 4295128739;
|
||||
@@ -22,7 +24,9 @@ contract UniswapV3Executor is IExecutor, ICallback {
|
||||
bytes32 public immutable initCode;
|
||||
address private immutable self;
|
||||
|
||||
constructor(address _factory, bytes32 _initCode) {
|
||||
constructor(address _factory, bytes32 _initCode, address _permit2)
|
||||
TokenTransfer(_permit2)
|
||||
{
|
||||
if (_factory == address(0)) {
|
||||
revert UniswapV3Executor__InvalidFactory();
|
||||
}
|
||||
@@ -46,7 +50,8 @@ contract UniswapV3Executor is IExecutor, ICallback {
|
||||
uint24 fee,
|
||||
address receiver,
|
||||
address target,
|
||||
bool zeroForOne
|
||||
bool zeroForOne,
|
||||
TransferType transferType
|
||||
) = _decodeData(data);
|
||||
|
||||
_verifyPairAddress(tokenIn, tokenOut, fee, target);
|
||||
@@ -55,7 +60,8 @@ contract UniswapV3Executor is IExecutor, ICallback {
|
||||
int256 amount1;
|
||||
IUniswapV3Pool pool = IUniswapV3Pool(target);
|
||||
|
||||
bytes memory callbackData = _makeV3CallbackData(tokenIn, tokenOut, fee);
|
||||
bytes memory callbackData =
|
||||
_makeV3CallbackData(tokenIn, tokenOut, fee, transferType);
|
||||
|
||||
{
|
||||
(amount0, amount1) = pool.swap(
|
||||
@@ -92,12 +98,21 @@ contract UniswapV3Executor is IExecutor, ICallback {
|
||||
|
||||
address tokenIn = address(bytes20(msgData[132:152]));
|
||||
|
||||
// Transfer type does not exist
|
||||
if (uint8(msgData[175]) > uint8(TransferType.NONE)) {
|
||||
revert UniswapV3Executor__InvalidTransferType(uint8(msgData[175]));
|
||||
}
|
||||
|
||||
TransferType transferType = TransferType(uint8(msgData[175]));
|
||||
address sender = address(bytes20(msgData[176:196]));
|
||||
|
||||
verifyCallback(msgData[132:]);
|
||||
|
||||
uint256 amountOwed =
|
||||
amount0Delta > 0 ? uint256(amount0Delta) : uint256(amount1Delta);
|
||||
|
||||
IERC20(tokenIn).safeTransfer(msg.sender, amountOwed);
|
||||
_transfer(IERC20(tokenIn), sender, msg.sender, amountOwed, transferType);
|
||||
|
||||
return abi.encode(amountOwed, tokenIn);
|
||||
}
|
||||
|
||||
@@ -132,10 +147,11 @@ contract UniswapV3Executor is IExecutor, ICallback {
|
||||
uint24 fee,
|
||||
address receiver,
|
||||
address target,
|
||||
bool zeroForOne
|
||||
bool zeroForOne,
|
||||
TransferType transferType
|
||||
)
|
||||
{
|
||||
if (data.length != 84) {
|
||||
if (data.length != 85) {
|
||||
revert UniswapV3Executor__InvalidDataLength();
|
||||
}
|
||||
tokenIn = address(bytes20(data[0:20]));
|
||||
@@ -144,14 +160,18 @@ contract UniswapV3Executor is IExecutor, ICallback {
|
||||
receiver = address(bytes20(data[43:63]));
|
||||
target = address(bytes20(data[63:83]));
|
||||
zeroForOne = uint8(data[83]) > 0;
|
||||
transferType = TransferType(uint8(data[84]));
|
||||
}
|
||||
|
||||
function _makeV3CallbackData(address tokenIn, address tokenOut, uint24 fee)
|
||||
internal
|
||||
pure
|
||||
returns (bytes memory)
|
||||
{
|
||||
return abi.encodePacked(tokenIn, tokenOut, fee);
|
||||
function _makeV3CallbackData(
|
||||
address tokenIn,
|
||||
address tokenOut,
|
||||
uint24 fee,
|
||||
TransferType transferType
|
||||
) internal view returns (bytes memory) {
|
||||
return abi.encodePacked(
|
||||
tokenIn, tokenOut, fee, uint8(transferType), msg.sender
|
||||
);
|
||||
}
|
||||
|
||||
function _verifyPairAddress(
|
||||
|
||||
87
foundry/test/Permit2TestHelper.sol
Normal file
87
foundry/test/Permit2TestHelper.sol
Normal file
@@ -0,0 +1,87 @@
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
pragma solidity ^0.8.26;
|
||||
|
||||
import "./Constants.sol";
|
||||
import "@permit2/src/interfaces/IAllowanceTransfer.sol";
|
||||
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
||||
|
||||
contract Permit2TestHelper is Constants {
|
||||
/**
|
||||
* @dev Handles the Permit2 approval process for Alice, allowing the TychoRouter contract
|
||||
* to spend `amount_in` of `tokenIn` on her behalf.
|
||||
*
|
||||
* This function approves the Permit2 contract to transfer the specified token amount
|
||||
* and constructs a `PermitSingle` struct for the approval. It also generates a valid
|
||||
* EIP-712 signature for the approval using Alice's private key.
|
||||
*
|
||||
* @param tokenIn The address of the token being approved.
|
||||
* @param amount_in The amount of tokens to approve for transfer.
|
||||
* @return permitSingle The `PermitSingle` struct containing the approval details.
|
||||
* @return signature The EIP-712 signature for the approval.
|
||||
*/
|
||||
function handlePermit2Approval(
|
||||
address tokenIn,
|
||||
address spender,
|
||||
uint256 amount_in
|
||||
) internal returns (IAllowanceTransfer.PermitSingle memory, bytes memory) {
|
||||
IERC20(tokenIn).approve(PERMIT2_ADDRESS, amount_in);
|
||||
IAllowanceTransfer.PermitSingle memory permitSingle = IAllowanceTransfer
|
||||
.PermitSingle({
|
||||
details: IAllowanceTransfer.PermitDetails({
|
||||
token: tokenIn,
|
||||
amount: uint160(amount_in),
|
||||
expiration: uint48(block.timestamp + 1 days),
|
||||
nonce: 0
|
||||
}),
|
||||
spender: spender,
|
||||
sigDeadline: block.timestamp + 1 days
|
||||
});
|
||||
|
||||
bytes memory signature = signPermit2(permitSingle, ALICE_PK);
|
||||
return (permitSingle, signature);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Signs a Permit2 `PermitSingle` struct with the given private key.
|
||||
* @param permit The `PermitSingle` struct to sign.
|
||||
* @param privateKey The private key of the signer.
|
||||
* @return The signature as a `bytes` array.
|
||||
*/
|
||||
function signPermit2(
|
||||
IAllowanceTransfer.PermitSingle memory permit,
|
||||
uint256 privateKey
|
||||
) internal view returns (bytes memory) {
|
||||
bytes32 _PERMIT_DETAILS_TYPEHASH = keccak256(
|
||||
"PermitDetails(address token,uint160 amount,uint48 expiration,uint48 nonce)"
|
||||
);
|
||||
bytes32 _PERMIT_SINGLE_TYPEHASH = keccak256(
|
||||
"PermitSingle(PermitDetails details,address spender,uint256 sigDeadline)PermitDetails(address token,uint160 amount,uint48 expiration,uint48 nonce)"
|
||||
);
|
||||
bytes32 domainSeparator = keccak256(
|
||||
abi.encode(
|
||||
keccak256(
|
||||
"EIP712Domain(string name,uint256 chainId,address verifyingContract)"
|
||||
),
|
||||
keccak256("Permit2"),
|
||||
block.chainid,
|
||||
PERMIT2_ADDRESS
|
||||
)
|
||||
);
|
||||
bytes32 detailsHash =
|
||||
keccak256(abi.encode(_PERMIT_DETAILS_TYPEHASH, permit.details));
|
||||
bytes32 permitHash = keccak256(
|
||||
abi.encode(
|
||||
_PERMIT_SINGLE_TYPEHASH,
|
||||
detailsHash,
|
||||
permit.spender,
|
||||
permit.sigDeadline
|
||||
)
|
||||
);
|
||||
|
||||
bytes32 digest =
|
||||
keccak256(abi.encodePacked("\x19\x01", domainSeparator, permitHash));
|
||||
(uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, digest);
|
||||
|
||||
return abi.encodePacked(r, s, v);
|
||||
}
|
||||
}
|
||||
@@ -4,36 +4,15 @@ pragma solidity ^0.8.26;
|
||||
import "./TychoRouterTestSetup.sol";
|
||||
|
||||
contract TychoRouterTestIntegration is TychoRouterTestSetup {
|
||||
function testSplitSwapSingleIntegration() public {
|
||||
// Tests swapping WETH -> DAI on a USV2 pool
|
||||
deal(WETH_ADDR, ALICE, 1 ether);
|
||||
uint256 balancerBefore = IERC20(DAI_ADDR).balanceOf(ALICE);
|
||||
|
||||
// Approve permit2
|
||||
vm.startPrank(ALICE);
|
||||
IERC20(WETH_ADDR).approve(PERMIT2_ADDRESS, type(uint256).max);
|
||||
// Encoded solution generated using `test_split_swap_strategy_encoder_simple`
|
||||
(bool success,) = tychoRouterAddr.call(
|
||||
hex"7c5538460000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f0000000000000000000000000000000000000000000000903146e5f6c59c064b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000681362ea00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067ebdcf2000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000041a82e9bdde90314de4b1bf918cc2e8b27da98adcab46e8e99d4e77472a572d6381837e9453095f4cc5e9b25691b678288174e547e040a67d12b36ddfdd1e672d21b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000058005600010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000"
|
||||
);
|
||||
|
||||
vm.stopPrank();
|
||||
|
||||
uint256 balancerAfter = IERC20(DAI_ADDR).balanceOf(ALICE);
|
||||
|
||||
assertTrue(success, "Call Failed");
|
||||
assertEq(balancerAfter - balancerBefore, 2659881924818443699787);
|
||||
}
|
||||
|
||||
function testSplitSwapSingleWithoutPermit2Integration() public {
|
||||
// Tests swapping WETH -> DAI on a USV2 pool without permit2
|
||||
deal(WETH_ADDR, ALICE, 1 ether);
|
||||
vm.startPrank(ALICE);
|
||||
IERC20(WETH_ADDR).approve(address(tychoRouterAddr), 1 ether);
|
||||
uint256 balancerBefore = IERC20(DAI_ADDR).balanceOf(ALICE);
|
||||
// Encoded solution generated using `test_split_swap_strategy_encoder_simple_route_no_permit2`
|
||||
// Encoded solution generated using `test_split_swap_strategy_encoder_no_permit2`
|
||||
(bool success,) = tychoRouterAddr.call(
|
||||
hex"79b9b93b0000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000008f1d5c1cae37400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000058005600010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000"
|
||||
hex"79b9b93b0000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000008f1d5c1cae37400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000059005700010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000"
|
||||
);
|
||||
|
||||
vm.stopPrank();
|
||||
@@ -128,9 +107,9 @@ contract TychoRouterTestIntegration is TychoRouterTestSetup {
|
||||
|
||||
// Approve permit2
|
||||
vm.startPrank(ALICE);
|
||||
// Encoded solution generated using `test_split_swap_strategy_encoder_simple_route_wrap`
|
||||
// Encoded solution generated using `test_split_swap_strategy_encoder_wrap`
|
||||
(bool success,) = tychoRouterAddr.call{value: 1 ether}(
|
||||
hex"7c5538460000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f0000000000000000000000000000000000000000000000903146e5f6c59c064b000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000000000006813638900000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067ebdd91000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000041f6ff7411a7ec76cb7dcafecf5e7f11121b1aa88af505635dc7faae6057e4f44e2859712f58331a14a1624f1e5edf2af80ddd2d90b5453d74df1b1fea10b9a2f91c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000058005600020000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000"
|
||||
hex"7c5538460000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f0000000000000000000000000000000000000000000000903146e5f6c59c064b000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000681e435000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067f6bd580000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000000415563c90eb0f8a79e234e300520b50879242b42622cabd5d01c19e67aba4854a723e0bd8333774062ae03a22b8c5de4a0dfd70bffd9197f56b2063f390610e5891b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000059005700020000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000"
|
||||
);
|
||||
|
||||
vm.stopPrank();
|
||||
@@ -150,9 +129,9 @@ contract TychoRouterTestIntegration is TychoRouterTestSetup {
|
||||
// Approve permit2
|
||||
vm.startPrank(ALICE);
|
||||
IERC20(DAI_ADDR).approve(PERMIT2_ADDRESS, type(uint256).max);
|
||||
// Encoded solution generated using `test_split_swap_strategy_encoder_simple_route_unwrap`
|
||||
// Encoded solution generated using `test_split_swap_strategy_encoder_unwrap`
|
||||
(bool success,) = tychoRouterAddr.call(
|
||||
hex"7c5538460000000000000000000000000000000000000000000000a2a15d09519be000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000003000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f0000000000000000000000000000000000000000000000a2a15d09519be00000000000000000000000000000000000000000000000000000000000006813615200000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067ebdb5a000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000041a7da748b04674485a5da185055affefc85b6d8fe412accce55b6f67842116f0f7f7130de5d74c68c20e1cedcdf93b8741b9171de2e6a3f2567887382a0712e3f1b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000058005600010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fa478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d01395010000000000000000"
|
||||
hex"7c5538460000000000000000000000000000000000000000000000a2a15d09519be000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000003000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f0000000000000000000000000000000000000000000000a2a15d09519be0000000000000000000000000000000000000000000000000000000000000681e436b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067f6bd730000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000000411150ac5d21c61fcd35b486034a433e44d045950a52e991a7ad4035f3ad52beee5d9ecbc5ed9c370730cd2631a050fbe1219dd606e39c8aca40d588aa3eab03411c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000059005700010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fa478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d01395010000000000000000"
|
||||
);
|
||||
|
||||
vm.stopPrank();
|
||||
@@ -204,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"7c5538460000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000681363a300000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067ebddab0000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000000415b7ff43991de10c4c3a0372653891d27eb305ce04228bfe46a7d84a0978063fc4cb05183f19b83511bcb689b002d4f8e170f1d3cd77cf18c638229ccb67e0cac1c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000160005600028000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d0139500005600010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d9403ede3eca2a72b3aecc820e955b36f38437d0139500005602030000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fae461ca67b15dc8dc81ce7615e0320da1a9ab8d53ede3eca2a72b3aecc820e955b36f38437d0139501005601030000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a4163ede3eca2a72b3aecc820e955b36f38437d0139501"
|
||||
hex"7c5538460000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000681e2d8b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067f6a793000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000041e9868ce97a4c09488710ce748362ca38418bda44148bb5faf7820445d47efaff66f8f3667a0b3091c9d67d240db4cc2c95db27bdf019e4d5ff76b7b6620514691b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000164005700028000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d013950000005700010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d9403ede3eca2a72b3aecc820e955b36f38437d013950000005702030000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fae461ca67b15dc8dc81ce7615e0320da1a9ab8d53ede3eca2a72b3aecc820e955b36f38437d013950100005701030000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a4163ede3eca2a72b3aecc820e955b36f38437d01395010000000000000000000000000000000000000000000000000000000000"
|
||||
);
|
||||
|
||||
vm.stopPrank();
|
||||
@@ -231,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"51bcc7b60000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000068168aea00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067ef04f200000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000004154956683effd126a9182e2d82ebd3d778e5283b93d571b13cdbc9dfbf3d9f655057a2332ed566f79bed7514a22ef1c52969132bc71a5a2ef125d78e39ec264511c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a600515615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d9403ede3eca2a72b3aecc820e955b36f38437d013950000515615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a4163ede3eca2a72b3aecc820e955b36f38437d01395010000000000000000000000000000000000000000000000000000"
|
||||
hex"51bcc7b60000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000681e493d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067f6c34500000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000004189757b528c9874627ca7ecd64bd662db5fd7855837ec98cca5cff2cbd599f9af15baff1d389b5de4ca0dc1106b9d3795a1695934cd5fa1158fffcc8d6495dfaa1b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a800525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d9403ede3eca2a72b3aecc820e955b36f38437d01395000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a4163ede3eca2a72b3aecc820e955b36f38437d013950100000000000000000000000000000000000000000000000000"
|
||||
);
|
||||
|
||||
vm.stopPrank();
|
||||
@@ -255,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"e8a980d70000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000a600515615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d9403ede3eca2a72b3aecc820e955b36f38437d013950000515615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a4163ede3eca2a72b3aecc820e955b36f38437d01395010000000000000000000000000000000000000000000000000000"
|
||||
hex"e8a980d70000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000a800525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d9403ede3eca2a72b3aecc820e955b36f38437d01395000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a4163ede3eca2a72b3aecc820e955b36f38437d013950100000000000000000000000000000000000000000000000000"
|
||||
);
|
||||
|
||||
vm.stopPrank();
|
||||
@@ -275,7 +254,7 @@ 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"7c5538460000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f4308e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e10000000000000000000000000000000000000000000000000000000000681363d200000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067ebddda0000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000000418d58a54a3b8afc5d2e228ce6c5a1ab6b342cb5bfd9a00d57b869a4703ca2bb084d10d21f6842be9652a9ff2392673fbdcb961439ccc962de09f6bc64e5e665fe1c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de006d00010000002e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f564001006d01000000002e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb83ede3eca2a72b3aecc820e955b36f38437d013958ad599c3a0ff1de082011efddc58f1908eb6e6d8000000"
|
||||
hex"7c5538460000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f4308e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e10000000000000000000000000000000000000000000000000000000000681e4a0200000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067f6c40a0000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000000416a11f27f0546e9cc9d27e4383a3f860d9822f0d7d0117e73abbf03007b3e235b36c2288ff083a04f51285092ff23422b3e00a5a292d5627172dfd031308fc3a11b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e0006e00010000002e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f56400100006e01000000002e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb83ede3eca2a72b3aecc820e955b36f38437d013958ad599c3a0ff1de082011efddc58f1908eb6e6d80000"
|
||||
);
|
||||
|
||||
assertEq(IERC20(USDC_ADDR).balanceOf(ALICE), 99889294);
|
||||
@@ -291,7 +270,7 @@ 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"7c5538460000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005ef619b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000000000000000000000000000000000006816408300000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067eeba8b0000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000000416de253b927fdcf110d157372e620e70c7220d3c01f04e01cdffb076edbb8b42052d281dd6c55a2349502742a0a8de58d2d1dbdc452f6c9d695b1c732c023d0561c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000136006d00019999992e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f564001006d00010000002e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000bb83ede3eca2a72b3aecc820e955b36f38437d013958ad599c3a0ff1de082011efddc58f1908eb6e6d801005601000000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2b4e16d0168e52d35cacd2c6185b44281ec28c9dc3ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000"
|
||||
hex"7c5538460000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005ef619b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e10000000000000000000000000000000000000000000000000000000000681e2d1600000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067f6a71e00000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000004129478d2bffac3e378054d024ca3461f61e55552e2e8b0c7e0869f38ee834462f157f761e1a67c713f5749a6f6210dc4ac998a0521dda8dcb780b35d774250a141c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000139006e00019999992e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f56400100006e00010000002e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000bb83ede3eca2a72b3aecc820e955b36f38437d013958ad599c3a0ff1de082011efddc58f1908eb6e6d80100005701000000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2b4e16d0168e52d35cacd2c6185b44281ec28c9dc3ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000"
|
||||
);
|
||||
|
||||
assertEq(IERC20(USDC_ADDR).balanceOf(ALICE), 99574171);
|
||||
@@ -307,7 +286,7 @@ 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"7c5538460000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005eea514000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000000000000000000000000000000000006816418400000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067eebb8c0000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000000412c44c7de8f7eaaea61e49dbdefdc5606925db6f93db0789e632899ac88d3c7677cc8b69719603ab1b5ecef07d659b7254881d0667a49ebccbf43949b760b041a1b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000136005600010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48b4e16d0168e52d35cacd2c6185b44281ec28c9dc3ede3eca2a72b3aecc820e955b36f38437d0139501006d01009999992e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f564000006d01000000002e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb83ede3eca2a72b3aecc820e955b36f38437d013958ad599c3a0ff1de082011efddc58f1908eb6e6d80000000000000000000000"
|
||||
hex"7c5538460000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005eea514000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e10000000000000000000000000000000000000000000000000000000000681e2d3000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067f6a738000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000041196745237299bfab79f038c0c12decec9c46b264621e1f00bbef32b15a22f15543defe95694dd1616aa8785bbb6f91a1557eebc97c0f5ca968c99f250da1b2ce1c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000139005700010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48b4e16d0168e52d35cacd2c6185b44281ec28c9dc3ede3eca2a72b3aecc820e955b36f38437d013950100006e01009999992e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f56400000006e01000000002e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb83ede3eca2a72b3aecc820e955b36f38437d013958ad599c3a0ff1de082011efddc58f1908eb6e6d8000000000000000000"
|
||||
);
|
||||
|
||||
assertEq(IERC20(USDC_ADDR).balanceOf(ALICE), 99525908);
|
||||
|
||||
@@ -51,7 +51,7 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup {
|
||||
(
|
||||
IAllowanceTransfer.PermitSingle memory permitSingle,
|
||||
bytes memory signature
|
||||
) = handlePermit2Approval(WETH_ADDR, amountIn);
|
||||
) = handlePermit2Approval(WETH_ADDR, tychoRouterAddr, amountIn);
|
||||
|
||||
bytes[] memory swaps = _getSequentialSwaps();
|
||||
tychoRouter.sequentialSwapPermit2(
|
||||
@@ -150,7 +150,7 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup {
|
||||
(
|
||||
IAllowanceTransfer.PermitSingle memory permitSingle,
|
||||
bytes memory signature
|
||||
) = handlePermit2Approval(WETH_ADDR, amountIn);
|
||||
) = handlePermit2Approval(WETH_ADDR, tychoRouterAddr, amountIn);
|
||||
|
||||
bytes[] memory swaps = _getSequentialSwaps();
|
||||
|
||||
@@ -229,7 +229,7 @@ contract TychoRouterSequentialSwapTest is TychoRouterTestSetup {
|
||||
(
|
||||
IAllowanceTransfer.PermitSingle memory permitSingle,
|
||||
bytes memory signature
|
||||
) = handlePermit2Approval(USDC_ADDR, amountIn);
|
||||
) = handlePermit2Approval(USDC_ADDR, tychoRouterAddr, amountIn);
|
||||
|
||||
bytes[] memory swaps = new bytes[](2);
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup {
|
||||
(
|
||||
IAllowanceTransfer.PermitSingle memory permitSingle,
|
||||
bytes memory signature
|
||||
) = handlePermit2Approval(WETH_ADDR, amountIn);
|
||||
) = handlePermit2Approval(WETH_ADDR, tychoRouterAddr, amountIn);
|
||||
|
||||
bytes memory protocolData = encodeUniswapV2Swap(
|
||||
WETH_ADDR, WETH_DAI_POOL, tychoRouterAddr, false
|
||||
@@ -230,7 +230,7 @@ contract TychoRouterSingleSwapTest is TychoRouterTestSetup {
|
||||
(
|
||||
IAllowanceTransfer.PermitSingle memory permitSingle,
|
||||
bytes memory signature
|
||||
) = handlePermit2Approval(DAI_ADDR, amountIn);
|
||||
) = handlePermit2Approval(DAI_ADDR, tychoRouterAddr, amountIn);
|
||||
|
||||
bytes memory protocolData =
|
||||
encodeUniswapV2Swap(DAI_ADDR, WETH_DAI_POOL, tychoRouterAddr, true);
|
||||
@@ -267,7 +267,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"20144a070000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000008f1d5c1cae3740000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000515615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000"
|
||||
hex"20144a070000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000008f1d5c1cae3740000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000"
|
||||
);
|
||||
|
||||
vm.stopPrank();
|
||||
@@ -286,7 +286,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"30ace1b10000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f0000000000000000000000000000000000000000000000903146e5f6c59c064b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000000000006817833200000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067effd3a00000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000417efea09004d5d40d8d072e1ce0a425507717ea485c765eb90c170859197d362b502fb039b4f5cdce57318ecfe3ab276d1ac87771eb5d017b253a8f4107e6a20b1b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000515615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000"
|
||||
hex"30ace1b10000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f0000000000000000000000000000000000000000000000903146e5f6c59c064b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000000000006817833200000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000067effd3a00000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000417efea09004d5d40d8d072e1ce0a425507717ea485c765eb90c170859197d362b502fb039b4f5cdce57318ecfe3ab276d1ac87771eb5d017b253a8f4107e6a20b1b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d0139500000000000000000000000000000000"
|
||||
);
|
||||
|
||||
vm.stopPrank();
|
||||
|
||||
@@ -81,7 +81,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
|
||||
(
|
||||
IAllowanceTransfer.PermitSingle memory permitSingle,
|
||||
bytes memory signature
|
||||
) = handlePermit2Approval(WETH_ADDR, amountIn);
|
||||
) = handlePermit2Approval(WETH_ADDR, tychoRouterAddr, amountIn);
|
||||
|
||||
bytes[] memory swaps = _getSplitSwaps();
|
||||
|
||||
@@ -191,7 +191,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
|
||||
(
|
||||
IAllowanceTransfer.PermitSingle memory permitSingle,
|
||||
bytes memory signature
|
||||
) = handlePermit2Approval(WETH_ADDR, amountIn);
|
||||
) = handlePermit2Approval(WETH_ADDR, tychoRouterAddr, amountIn);
|
||||
|
||||
bytes[] memory swaps = _getSplitSwaps();
|
||||
|
||||
@@ -282,7 +282,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
|
||||
(
|
||||
IAllowanceTransfer.PermitSingle memory permitSingle,
|
||||
bytes memory signature
|
||||
) = handlePermit2Approval(DAI_ADDR, amountIn);
|
||||
) = handlePermit2Approval(DAI_ADDR, tychoRouterAddr, amountIn);
|
||||
|
||||
bytes memory protocolData =
|
||||
encodeUniswapV2Swap(DAI_ADDR, WETH_DAI_POOL, tychoRouterAddr, true);
|
||||
@@ -325,7 +325,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
|
||||
(
|
||||
IAllowanceTransfer.PermitSingle memory permitSingle,
|
||||
bytes memory signature
|
||||
) = handlePermit2Approval(WETH_ADDR, amountIn);
|
||||
) = handlePermit2Approval(WETH_ADDR, tychoRouterAddr, amountIn);
|
||||
|
||||
uint256 expAmountOut = 1205_128428842122129186; //Swap 1 WETH for 1205.12 DAI
|
||||
bool zeroForOne = false;
|
||||
@@ -377,7 +377,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
|
||||
(
|
||||
IAllowanceTransfer.PermitSingle memory permitSingle,
|
||||
bytes memory signature
|
||||
) = handlePermit2Approval(WETH_ADDR, amountIn);
|
||||
) = handlePermit2Approval(WETH_ADDR, tychoRouterAddr, amountIn);
|
||||
|
||||
bytes memory protocolData = encodeUniswapV2Swap(
|
||||
WETH_ADDR, WETH_DAI_POOL, tychoRouterAddr, false
|
||||
@@ -426,7 +426,7 @@ contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
|
||||
(
|
||||
IAllowanceTransfer.PermitSingle memory permitSingle,
|
||||
bytes memory signature
|
||||
) = handlePermit2Approval(USDE_ADDR, amountIn);
|
||||
) = handlePermit2Approval(USDE_ADDR, tychoRouterAddr, amountIn);
|
||||
|
||||
UniswapV4Executor.UniswapV4Pool[] memory pools =
|
||||
new UniswapV4Executor.UniswapV4Pool[](1);
|
||||
|
||||
@@ -13,6 +13,7 @@ import "@src/TychoRouter.sol";
|
||||
import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol";
|
||||
import {PoolManager} from "@uniswap/v4-core/src/PoolManager.sol";
|
||||
import {WETH} from "../lib/permit2/lib/solmate/src/tokens/WETH.sol";
|
||||
import {Permit2TestHelper} from "./Permit2TestHelper.sol";
|
||||
|
||||
contract TychoRouterExposed is TychoRouter {
|
||||
constructor(address _permit2, address weth) TychoRouter(_permit2, weth) {}
|
||||
@@ -41,7 +42,7 @@ contract TychoRouterExposed is TychoRouter {
|
||||
}
|
||||
}
|
||||
|
||||
contract TychoRouterTestSetup is Constants {
|
||||
contract TychoRouterTestSetup is Constants, Permit2TestHelper {
|
||||
TychoRouterExposed tychoRouter;
|
||||
address tychoRouterAddr;
|
||||
UniswapV2Executor public usv2Executor;
|
||||
@@ -97,11 +98,14 @@ contract TychoRouterTestSetup is Constants {
|
||||
address ekuboCore = 0xe0e0e08A6A4b9Dc7bD67BCB7aadE5cF48157d444;
|
||||
|
||||
IPoolManager poolManager = IPoolManager(poolManagerAddress);
|
||||
usv2Executor = new UniswapV2Executor(factoryV2, initCodeV2);
|
||||
usv3Executor = new UniswapV3Executor(factoryV3, initCodeV3);
|
||||
usv2Executor =
|
||||
new UniswapV2Executor(factoryV2, initCodeV2, PERMIT2_ADDRESS);
|
||||
usv3Executor =
|
||||
new UniswapV3Executor(factoryV3, initCodeV3, PERMIT2_ADDRESS);
|
||||
usv4Executor = new UniswapV4Executor(poolManager);
|
||||
pancakev3Executor =
|
||||
new UniswapV3Executor(factoryPancakeV3, initCodePancakeV3);
|
||||
pancakev3Executor = new UniswapV3Executor(
|
||||
factoryPancakeV3, initCodePancakeV3, PERMIT2_ADDRESS
|
||||
);
|
||||
balancerv2Executor = new BalancerV2Executor();
|
||||
ekuboExecutor = new EkuboExecutor(ekuboCore);
|
||||
curveExecutor = new CurveExecutor(ETH_ADDR_FOR_CURVE);
|
||||
@@ -129,84 +133,6 @@ contract TychoRouterTestSetup is Constants {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Handles the Permit2 approval process for Alice, allowing the TychoRouter contract
|
||||
* to spend `amount_in` of `tokenIn` on her behalf.
|
||||
*
|
||||
* This function approves the Permit2 contract to transfer the specified token amount
|
||||
* and constructs a `PermitSingle` struct for the approval. It also generates a valid
|
||||
* EIP-712 signature for the approval using Alice's private key.
|
||||
*
|
||||
* @param tokenIn The address of the token being approved.
|
||||
* @param amount_in The amount of tokens to approve for transfer.
|
||||
* @return permitSingle The `PermitSingle` struct containing the approval details.
|
||||
* @return signature The EIP-712 signature for the approval.
|
||||
*/
|
||||
function handlePermit2Approval(address tokenIn, uint256 amount_in)
|
||||
internal
|
||||
returns (IAllowanceTransfer.PermitSingle memory, bytes memory)
|
||||
{
|
||||
IERC20(tokenIn).approve(PERMIT2_ADDRESS, amount_in);
|
||||
IAllowanceTransfer.PermitSingle memory permitSingle = IAllowanceTransfer
|
||||
.PermitSingle({
|
||||
details: IAllowanceTransfer.PermitDetails({
|
||||
token: tokenIn,
|
||||
amount: uint160(amount_in),
|
||||
expiration: uint48(block.timestamp + 1 days),
|
||||
nonce: 0
|
||||
}),
|
||||
spender: tychoRouterAddr,
|
||||
sigDeadline: block.timestamp + 1 days
|
||||
});
|
||||
|
||||
bytes memory signature = signPermit2(permitSingle, ALICE_PK);
|
||||
return (permitSingle, signature);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Signs a Permit2 `PermitSingle` struct with the given private key.
|
||||
* @param permit The `PermitSingle` struct to sign.
|
||||
* @param privateKey The private key of the signer.
|
||||
* @return The signature as a `bytes` array.
|
||||
*/
|
||||
function signPermit2(
|
||||
IAllowanceTransfer.PermitSingle memory permit,
|
||||
uint256 privateKey
|
||||
) internal view returns (bytes memory) {
|
||||
bytes32 _PERMIT_DETAILS_TYPEHASH = keccak256(
|
||||
"PermitDetails(address token,uint160 amount,uint48 expiration,uint48 nonce)"
|
||||
);
|
||||
bytes32 _PERMIT_SINGLE_TYPEHASH = keccak256(
|
||||
"PermitSingle(PermitDetails details,address spender,uint256 sigDeadline)PermitDetails(address token,uint160 amount,uint48 expiration,uint48 nonce)"
|
||||
);
|
||||
bytes32 domainSeparator = keccak256(
|
||||
abi.encode(
|
||||
keccak256(
|
||||
"EIP712Domain(string name,uint256 chainId,address verifyingContract)"
|
||||
),
|
||||
keccak256("Permit2"),
|
||||
block.chainid,
|
||||
PERMIT2_ADDRESS
|
||||
)
|
||||
);
|
||||
bytes32 detailsHash =
|
||||
keccak256(abi.encode(_PERMIT_DETAILS_TYPEHASH, permit.details));
|
||||
bytes32 permitHash = keccak256(
|
||||
abi.encode(
|
||||
_PERMIT_SINGLE_TYPEHASH,
|
||||
detailsHash,
|
||||
permit.spender,
|
||||
permit.sigDeadline
|
||||
)
|
||||
);
|
||||
|
||||
bytes32 digest =
|
||||
keccak256(abi.encodePacked("\x19\x01", domainSeparator, permitHash));
|
||||
(uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, digest);
|
||||
|
||||
return abi.encodePacked(r, s, v);
|
||||
}
|
||||
|
||||
function pleEncode(bytes[] memory data)
|
||||
public
|
||||
pure
|
||||
@@ -254,7 +180,13 @@ contract TychoRouterTestSetup is Constants {
|
||||
address receiver,
|
||||
bool zero2one
|
||||
) internal pure returns (bytes memory) {
|
||||
return abi.encodePacked(tokenIn, target, receiver, zero2one);
|
||||
return abi.encodePacked(
|
||||
tokenIn,
|
||||
target,
|
||||
receiver,
|
||||
zero2one,
|
||||
TokenTransfer.TransferType.TRANSFER
|
||||
);
|
||||
}
|
||||
|
||||
function encodeUniswapV3Swap(
|
||||
@@ -266,7 +198,13 @@ contract TychoRouterTestSetup is Constants {
|
||||
) internal view returns (bytes memory) {
|
||||
IUniswapV3Pool pool = IUniswapV3Pool(target);
|
||||
return abi.encodePacked(
|
||||
tokenIn, tokenOut, pool.fee(), receiver, target, zero2one
|
||||
tokenIn,
|
||||
tokenOut,
|
||||
pool.fee(),
|
||||
receiver,
|
||||
target,
|
||||
zero2one,
|
||||
TokenTransfer.TransferType.TRANSFER
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,12 +2,14 @@
|
||||
pragma solidity ^0.8.26;
|
||||
|
||||
import "@src/executors/UniswapV2Executor.sol";
|
||||
import "@src/executors/TokenTransfer.sol";
|
||||
import {Test} from "../../lib/forge-std/src/Test.sol";
|
||||
import {Constants} from "../Constants.sol";
|
||||
import {Permit2TestHelper} from "../Permit2TestHelper.sol";
|
||||
|
||||
contract UniswapV2ExecutorExposed is UniswapV2Executor {
|
||||
constructor(address _factory, bytes32 _initCode)
|
||||
UniswapV2Executor(_factory, _initCode)
|
||||
constructor(address _factory, bytes32 _initCode, address _permit2)
|
||||
UniswapV2Executor(_factory, _initCode, _permit2)
|
||||
{}
|
||||
|
||||
function decodeParams(bytes calldata data)
|
||||
@@ -17,7 +19,8 @@ contract UniswapV2ExecutorExposed is UniswapV2Executor {
|
||||
IERC20 inToken,
|
||||
address target,
|
||||
address receiver,
|
||||
bool zeroForOne
|
||||
bool zeroForOne,
|
||||
TransferType transferType
|
||||
)
|
||||
{
|
||||
return _decodeData(data);
|
||||
@@ -46,7 +49,7 @@ contract FakeUniswapV2Pool {
|
||||
}
|
||||
}
|
||||
|
||||
contract UniswapV2ExecutorTest is Test, Constants {
|
||||
contract UniswapV2ExecutorTest is Test, Constants, Permit2TestHelper {
|
||||
using SafeERC20 for IERC20;
|
||||
|
||||
UniswapV2ExecutorExposed uniswapV2Exposed;
|
||||
@@ -54,32 +57,51 @@ contract UniswapV2ExecutorTest is Test, Constants {
|
||||
UniswapV2ExecutorExposed pancakeswapV2Exposed;
|
||||
IERC20 WETH = IERC20(WETH_ADDR);
|
||||
IERC20 DAI = IERC20(DAI_ADDR);
|
||||
IAllowanceTransfer permit2;
|
||||
|
||||
function setUp() public {
|
||||
uint256 forkBlock = 17323404;
|
||||
vm.createSelectFork(vm.rpcUrl("mainnet"), forkBlock);
|
||||
uniswapV2Exposed = new UniswapV2ExecutorExposed(
|
||||
USV2_FACTORY_ETHEREUM, USV2_POOL_CODE_INIT_HASH
|
||||
USV2_FACTORY_ETHEREUM, USV2_POOL_CODE_INIT_HASH, PERMIT2_ADDRESS
|
||||
);
|
||||
sushiswapV2Exposed = new UniswapV2ExecutorExposed(
|
||||
SUSHISWAPV2_FACTORY_ETHEREUM, SUSHIV2_POOL_CODE_INIT_HASH
|
||||
SUSHISWAPV2_FACTORY_ETHEREUM,
|
||||
SUSHIV2_POOL_CODE_INIT_HASH,
|
||||
PERMIT2_ADDRESS
|
||||
);
|
||||
pancakeswapV2Exposed = new UniswapV2ExecutorExposed(
|
||||
PANCAKESWAPV2_FACTORY_ETHEREUM, PANCAKEV2_POOL_CODE_INIT_HASH
|
||||
PANCAKESWAPV2_FACTORY_ETHEREUM,
|
||||
PANCAKEV2_POOL_CODE_INIT_HASH,
|
||||
PERMIT2_ADDRESS
|
||||
);
|
||||
permit2 = IAllowanceTransfer(PERMIT2_ADDRESS);
|
||||
}
|
||||
|
||||
function testDecodeParams() public view {
|
||||
bytes memory params =
|
||||
abi.encodePacked(WETH_ADDR, address(2), address(3), false);
|
||||
bytes memory params = abi.encodePacked(
|
||||
WETH_ADDR,
|
||||
address(2),
|
||||
address(3),
|
||||
false,
|
||||
TokenTransfer.TransferType.TRANSFER
|
||||
);
|
||||
|
||||
(IERC20 tokenIn, address target, address receiver, bool zeroForOne) =
|
||||
uniswapV2Exposed.decodeParams(params);
|
||||
(
|
||||
IERC20 tokenIn,
|
||||
address target,
|
||||
address receiver,
|
||||
bool zeroForOne,
|
||||
TokenTransfer.TransferType transferType
|
||||
) = uniswapV2Exposed.decodeParams(params);
|
||||
|
||||
assertEq(address(tokenIn), WETH_ADDR);
|
||||
assertEq(target, address(2));
|
||||
assertEq(receiver, address(3));
|
||||
assertEq(zeroForOne, false);
|
||||
assertEq(
|
||||
uint8(TokenTransfer.TransferType.TRANSFER), uint8(transferType)
|
||||
);
|
||||
}
|
||||
|
||||
function testDecodeParamsInvalidDataLength() public {
|
||||
@@ -126,12 +148,17 @@ contract UniswapV2ExecutorTest is Test, Constants {
|
||||
assertGe(amountOut, 0);
|
||||
}
|
||||
|
||||
function testSwap() public {
|
||||
function testSwapWithTransfer() public {
|
||||
uint256 amountIn = 10 ** 18;
|
||||
uint256 amountOut = 1847751195973566072891;
|
||||
bool zeroForOne = false;
|
||||
bytes memory protocolData =
|
||||
abi.encodePacked(WETH_ADDR, WETH_DAI_POOL, BOB, zeroForOne);
|
||||
bytes memory protocolData = abi.encodePacked(
|
||||
WETH_ADDR,
|
||||
WETH_DAI_POOL,
|
||||
BOB,
|
||||
zeroForOne,
|
||||
uint8(TokenTransfer.TransferType.TRANSFER)
|
||||
);
|
||||
|
||||
deal(WETH_ADDR, address(uniswapV2Exposed), amountIn);
|
||||
uniswapV2Exposed.swap(amountIn, protocolData);
|
||||
@@ -140,24 +167,104 @@ contract UniswapV2ExecutorTest is Test, Constants {
|
||||
assertGe(finalBalance, amountOut);
|
||||
}
|
||||
|
||||
function testSwapWithTransferFrom() public {
|
||||
uint256 amountIn = 10 ** 18;
|
||||
uint256 amountOut = 1847751195973566072891;
|
||||
bool zeroForOne = false;
|
||||
bytes memory protocolData = abi.encodePacked(
|
||||
WETH_ADDR,
|
||||
WETH_DAI_POOL,
|
||||
BOB,
|
||||
zeroForOne,
|
||||
uint8(TokenTransfer.TransferType.TRANSFERFROM)
|
||||
);
|
||||
|
||||
deal(WETH_ADDR, address(this), amountIn);
|
||||
IERC20(WETH_ADDR).approve(address(uniswapV2Exposed), amountIn);
|
||||
|
||||
uniswapV2Exposed.swap(amountIn, protocolData);
|
||||
|
||||
uint256 finalBalance = DAI.balanceOf(BOB);
|
||||
assertGe(finalBalance, amountOut);
|
||||
}
|
||||
|
||||
function testSwapWithPermit2TransferFrom() public {
|
||||
uint256 amountIn = 10 ** 18;
|
||||
uint256 amountOut = 1847751195973566072891;
|
||||
bool zeroForOne = false;
|
||||
bytes memory protocolData = abi.encodePacked(
|
||||
WETH_ADDR,
|
||||
WETH_DAI_POOL,
|
||||
ALICE,
|
||||
zeroForOne,
|
||||
uint8(TokenTransfer.TransferType.TRANSFERPERMIT2)
|
||||
);
|
||||
|
||||
deal(WETH_ADDR, ALICE, amountIn);
|
||||
vm.startPrank(ALICE);
|
||||
(
|
||||
IAllowanceTransfer.PermitSingle memory permitSingle,
|
||||
bytes memory signature
|
||||
) = handlePermit2Approval(
|
||||
WETH_ADDR, address(uniswapV2Exposed), amountIn
|
||||
);
|
||||
|
||||
// Assume the permit2.approve method will be called from the TychoRouter
|
||||
// Replicate this scenario in this test.
|
||||
permit2.permit(ALICE, permitSingle, signature);
|
||||
|
||||
uniswapV2Exposed.swap(amountIn, protocolData);
|
||||
vm.stopPrank();
|
||||
|
||||
uint256 finalBalance = DAI.balanceOf(ALICE);
|
||||
assertGe(finalBalance, amountOut);
|
||||
}
|
||||
|
||||
function testSwapNoTransfer() public {
|
||||
uint256 amountIn = 10 ** 18;
|
||||
uint256 amountOut = 1847751195973566072891;
|
||||
bool zeroForOne = false;
|
||||
bytes memory protocolData = abi.encodePacked(
|
||||
WETH_ADDR,
|
||||
WETH_DAI_POOL,
|
||||
BOB,
|
||||
zeroForOne,
|
||||
uint8(TokenTransfer.TransferType.NONE)
|
||||
);
|
||||
|
||||
deal(WETH_ADDR, address(this), amountIn);
|
||||
IERC20(WETH_ADDR).transfer(address(WETH_DAI_POOL), amountIn);
|
||||
uniswapV2Exposed.swap(amountIn, protocolData);
|
||||
|
||||
uint256 finalBalance = DAI.balanceOf(BOB);
|
||||
assertGe(finalBalance, amountOut);
|
||||
}
|
||||
|
||||
function testDecodeIntegration() public view {
|
||||
// Generated by the ExecutorStrategyEncoder - test_executor_strategy_encode
|
||||
bytes memory protocolData =
|
||||
hex"c02aaa39b223fe8d0a0e5c4f27ead9083c756cc288e6a0c2ddd26feeb64f039a2c41296fcb3f5640000000000000000000000000000000000000000100";
|
||||
hex"c02aaa39b223fe8d0a0e5c4f27ead9083c756cc288e6a0c2ddd26feeb64f039a2c41296fcb3f564000000000000000000000000000000000000000010000";
|
||||
|
||||
(IERC20 tokenIn, address target, address receiver, bool zeroForOne) =
|
||||
uniswapV2Exposed.decodeParams(protocolData);
|
||||
(
|
||||
IERC20 tokenIn,
|
||||
address target,
|
||||
address receiver,
|
||||
bool zeroForOne,
|
||||
TokenTransfer.TransferType transferType
|
||||
) = uniswapV2Exposed.decodeParams(protocolData);
|
||||
|
||||
assertEq(address(tokenIn), WETH_ADDR);
|
||||
assertEq(target, 0x88e6A0c2dDD26FEEb64F039a2c41296FcB3f5640);
|
||||
assertEq(receiver, 0x0000000000000000000000000000000000000001);
|
||||
assertEq(zeroForOne, false);
|
||||
// TRANSFER = 0
|
||||
assertEq(0, uint8(transferType));
|
||||
}
|
||||
|
||||
function testSwapIntegration() public {
|
||||
// Generated by the ExecutorStrategyEncoder - test_executor_strategy_encode
|
||||
bytes memory protocolData =
|
||||
hex"c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb111d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e00";
|
||||
hex"c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb111d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e0000";
|
||||
uint256 amountIn = 10 ** 18;
|
||||
uint256 amountOut = 1847751195973566072891;
|
||||
deal(WETH_ADDR, address(uniswapV2Exposed), amountIn);
|
||||
@@ -171,8 +278,13 @@ contract UniswapV2ExecutorTest is Test, Constants {
|
||||
uint256 amountIn = 10 ** 18;
|
||||
bool zeroForOne = false;
|
||||
address fakePool = address(new FakeUniswapV2Pool(WETH_ADDR, DAI_ADDR));
|
||||
bytes memory protocolData =
|
||||
abi.encodePacked(WETH_ADDR, fakePool, BOB, zeroForOne);
|
||||
bytes memory protocolData = abi.encodePacked(
|
||||
WETH_ADDR,
|
||||
fakePool,
|
||||
BOB,
|
||||
zeroForOne,
|
||||
uint8(TokenTransfer.TransferType.TRANSFER)
|
||||
);
|
||||
|
||||
deal(WETH_ADDR, address(uniswapV2Exposed), amountIn);
|
||||
vm.expectRevert(UniswapV2Executor__InvalidTarget.selector);
|
||||
@@ -186,8 +298,13 @@ contract UniswapV2ExecutorTest is Test, Constants {
|
||||
vm.rollFork(26857267);
|
||||
uint256 amountIn = 10 * 10 ** 6;
|
||||
bool zeroForOne = true;
|
||||
bytes memory protocolData =
|
||||
abi.encodePacked(BASE_USDC, USDC_MAG7_POOL, BOB, zeroForOne);
|
||||
bytes memory protocolData = abi.encodePacked(
|
||||
BASE_USDC,
|
||||
USDC_MAG7_POOL,
|
||||
BOB,
|
||||
zeroForOne,
|
||||
uint8(TokenTransfer.TransferType.TRANSFER)
|
||||
);
|
||||
|
||||
deal(BASE_USDC, address(uniswapV2Exposed), amountIn);
|
||||
|
||||
|
||||
@@ -2,12 +2,14 @@
|
||||
pragma solidity ^0.8.26;
|
||||
|
||||
import "@src/executors/UniswapV3Executor.sol";
|
||||
import "@permit2/src/interfaces/IAllowanceTransfer.sol";
|
||||
import {Test} from "../../lib/forge-std/src/Test.sol";
|
||||
import {Constants} from "../Constants.sol";
|
||||
import {Permit2TestHelper} from "../Permit2TestHelper.sol";
|
||||
|
||||
contract UniswapV3ExecutorExposed is UniswapV3Executor {
|
||||
constructor(address _factory, bytes32 _initCode)
|
||||
UniswapV3Executor(_factory, _initCode)
|
||||
constructor(address _factory, bytes32 _initCode, address _permit2)
|
||||
UniswapV3Executor(_factory, _initCode, _permit2)
|
||||
{}
|
||||
|
||||
function decodeData(bytes calldata data)
|
||||
@@ -19,7 +21,8 @@ contract UniswapV3ExecutorExposed is UniswapV3Executor {
|
||||
uint24 fee,
|
||||
address receiver,
|
||||
address target,
|
||||
bool zeroForOne
|
||||
bool zeroForOne,
|
||||
TransferType transferType
|
||||
)
|
||||
{
|
||||
return _decodeData(data);
|
||||
@@ -35,30 +38,40 @@ contract UniswapV3ExecutorExposed is UniswapV3Executor {
|
||||
}
|
||||
}
|
||||
|
||||
contract UniswapV3ExecutorTest is Test, Constants {
|
||||
contract UniswapV3ExecutorTest is Test, Constants, Permit2TestHelper {
|
||||
using SafeERC20 for IERC20;
|
||||
|
||||
UniswapV3ExecutorExposed uniswapV3Exposed;
|
||||
UniswapV3ExecutorExposed pancakeV3Exposed;
|
||||
IERC20 WETH = IERC20(WETH_ADDR);
|
||||
IERC20 DAI = IERC20(DAI_ADDR);
|
||||
IAllowanceTransfer permit2;
|
||||
|
||||
function setUp() public {
|
||||
uint256 forkBlock = 17323404;
|
||||
vm.createSelectFork(vm.rpcUrl("mainnet"), forkBlock);
|
||||
|
||||
uniswapV3Exposed = new UniswapV3ExecutorExposed(
|
||||
USV3_FACTORY_ETHEREUM, USV3_POOL_CODE_INIT_HASH
|
||||
USV3_FACTORY_ETHEREUM, USV3_POOL_CODE_INIT_HASH, PERMIT2_ADDRESS
|
||||
);
|
||||
pancakeV3Exposed = new UniswapV3ExecutorExposed(
|
||||
PANCAKESWAPV3_DEPLOYER_ETHEREUM, PANCAKEV3_POOL_CODE_INIT_HASH
|
||||
PANCAKESWAPV3_DEPLOYER_ETHEREUM,
|
||||
PANCAKEV3_POOL_CODE_INIT_HASH,
|
||||
PERMIT2_ADDRESS
|
||||
);
|
||||
permit2 = IAllowanceTransfer(PERMIT2_ADDRESS);
|
||||
}
|
||||
|
||||
function testDecodeParams() public view {
|
||||
uint24 expectedPoolFee = 500;
|
||||
bytes memory data = abi.encodePacked(
|
||||
WETH_ADDR, DAI_ADDR, expectedPoolFee, address(2), address(3), false
|
||||
WETH_ADDR,
|
||||
DAI_ADDR,
|
||||
expectedPoolFee,
|
||||
address(2),
|
||||
address(3),
|
||||
false,
|
||||
TokenTransfer.TransferType.TRANSFER
|
||||
);
|
||||
|
||||
(
|
||||
@@ -67,7 +80,8 @@ contract UniswapV3ExecutorTest is Test, Constants {
|
||||
uint24 fee,
|
||||
address receiver,
|
||||
address target,
|
||||
bool zeroForOne
|
||||
bool zeroForOne,
|
||||
TokenTransfer.TransferType transferType
|
||||
) = uniswapV3Exposed.decodeData(data);
|
||||
|
||||
assertEq(tokenIn, WETH_ADDR);
|
||||
@@ -76,6 +90,9 @@ contract UniswapV3ExecutorTest is Test, Constants {
|
||||
assertEq(receiver, address(2));
|
||||
assertEq(target, address(3));
|
||||
assertEq(zeroForOne, false);
|
||||
assertEq(
|
||||
uint8(transferType), uint8(TokenTransfer.TransferType.TRANSFER)
|
||||
);
|
||||
}
|
||||
|
||||
function testDecodeParamsInvalidDataLength() public {
|
||||
@@ -105,8 +122,9 @@ contract UniswapV3ExecutorTest is Test, Constants {
|
||||
uint256 initialPoolReserve = IERC20(WETH_ADDR).balanceOf(DAI_WETH_USV3);
|
||||
|
||||
vm.startPrank(DAI_WETH_USV3);
|
||||
bytes memory protocolData =
|
||||
abi.encodePacked(WETH_ADDR, DAI_ADDR, poolFee);
|
||||
bytes memory protocolData = abi.encodePacked(
|
||||
WETH_ADDR, DAI_ADDR, poolFee, TokenTransfer.TransferType.TRANSFER
|
||||
);
|
||||
uint256 dataOffset = 3; // some offset
|
||||
uint256 dataLength = protocolData.length;
|
||||
|
||||
@@ -116,7 +134,8 @@ contract UniswapV3ExecutorTest is Test, Constants {
|
||||
int256(0), // amount1Delta
|
||||
dataOffset,
|
||||
dataLength,
|
||||
protocolData
|
||||
protocolData,
|
||||
address(uniswapV3Exposed) // transferFrom sender (irrelevant in this case)
|
||||
);
|
||||
uniswapV3Exposed.handleCallback(callbackData);
|
||||
vm.stopPrank();
|
||||
@@ -137,7 +156,8 @@ contract UniswapV3ExecutorTest is Test, Constants {
|
||||
uint24(3000),
|
||||
address(this),
|
||||
fakePool,
|
||||
zeroForOne
|
||||
zeroForOne,
|
||||
TokenTransfer.TransferType.TRANSFER
|
||||
);
|
||||
|
||||
vm.expectRevert(UniswapV3Executor__InvalidTarget.selector);
|
||||
@@ -149,11 +169,18 @@ contract UniswapV3ExecutorTest is Test, Constants {
|
||||
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(
|
||||
tokenIn, tokenOut, pool.fee(), receiver, target, zero2one
|
||||
tokenIn,
|
||||
tokenOut,
|
||||
pool.fee(),
|
||||
receiver,
|
||||
target,
|
||||
zero2one,
|
||||
transferType
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -709,9 +709,9 @@ mod tests {
|
||||
|
||||
let expected_swaps = String::from(concat!(
|
||||
// length of ple encoded swaps without padding
|
||||
"0000000000000000000000000000000000000000000000000000000000000058",
|
||||
"0000000000000000000000000000000000000000000000000000000000000059",
|
||||
// ple encoded swaps
|
||||
"0056",
|
||||
"0057",
|
||||
// Swap header
|
||||
"00", // token in index
|
||||
"01", // token out index
|
||||
@@ -722,7 +722,7 @@ mod tests {
|
||||
"a478c2975ab1ea89e8196811f51a7b7ade33eb11", // component id
|
||||
"3ede3eca2a72b3aecc820e955b36f38437d01395", // receiver
|
||||
"00", // zero2one
|
||||
"00", // exact out
|
||||
"00", // transfer type
|
||||
"00000000000000", // padding
|
||||
));
|
||||
let hex_calldata = encode(&calldata);
|
||||
@@ -817,8 +817,8 @@ mod tests {
|
||||
// it's hard to assert
|
||||
|
||||
let expected_swap = String::from(concat!(
|
||||
// length of ple encoded swaps without padding
|
||||
"0000000000000000000000000000000000000000000000000000000000000051",
|
||||
// length of encoded swap without padding
|
||||
"0000000000000000000000000000000000000000000000000000000000000052",
|
||||
// Swap data
|
||||
"5615deb798bb3e4dfa0139dfa1b3d433cc23b72f", // executor address
|
||||
"c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // token in
|
||||
@@ -826,7 +826,8 @@ mod tests {
|
||||
"3ede3eca2a72b3aecc820e955b36f38437d01395", // receiver
|
||||
"00", // zero2one
|
||||
"00", // exact out
|
||||
"0000000000000000000000000000", // padding
|
||||
"00", // transfer type
|
||||
"00000000000000000000000000", // padding
|
||||
));
|
||||
let hex_calldata = encode(&calldata);
|
||||
|
||||
@@ -1475,7 +1476,7 @@ mod tests {
|
||||
"0000000000000000000000000000000000000000000000000000000000000000", // unwrap
|
||||
"000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver
|
||||
"0000000000000000000000000000000000000000000000000000000000000100", // offset of swap bytes
|
||||
"0000000000000000000000000000000000000000000000000000000000000051", // length of swap bytes without padding
|
||||
"0000000000000000000000000000000000000000000000000000000000000052", // length of swap bytes without padding
|
||||
|
||||
// Swap data
|
||||
"5615deb798bb3e4dfa0139dfa1b3d433cc23b72f", // executor address
|
||||
@@ -1484,7 +1485,8 @@ mod tests {
|
||||
"3ede3eca2a72b3aecc820e955b36f38437d01395", // receiver
|
||||
"00", // zero2one
|
||||
"00", // exact out
|
||||
"0000000000000000000000000000", // padding
|
||||
"00", // transfer type
|
||||
"00000000000000000000000000", // padding
|
||||
]
|
||||
.join("");
|
||||
|
||||
@@ -1554,8 +1556,8 @@ mod tests {
|
||||
"0000000000000000000000000000000000000000000000000000000000000002", // tokens length
|
||||
"000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver
|
||||
"0000000000000000000000000000000000000000000000000000000000000120", // offset of ple encoded swaps
|
||||
"0000000000000000000000000000000000000000000000000000000000000058", // length of ple encoded swaps without padding
|
||||
"0056", // ple encoded swaps
|
||||
"0000000000000000000000000000000000000000000000000000000000000059", // length of ple encoded swaps without padding
|
||||
"0057", // ple encoded swaps
|
||||
// Swap header
|
||||
"00", // token in index
|
||||
"01", // token out index
|
||||
@@ -1567,7 +1569,8 @@ mod tests {
|
||||
"3ede3eca2a72b3aecc820e955b36f38437d01395", // receiver
|
||||
"00", // zero2one
|
||||
"00", // exact out
|
||||
"00000000000000", // padding
|
||||
"00", // transfer type
|
||||
"000000000000", // padding
|
||||
]
|
||||
.join("");
|
||||
|
||||
@@ -1806,8 +1809,8 @@ mod tests {
|
||||
.join("");
|
||||
|
||||
let expected_swaps = [
|
||||
"00000000000000000000000000000000000000000000000000000000000000de", // length of ple encoded swaps without padding
|
||||
"006d", // ple encoded swaps
|
||||
"00000000000000000000000000000000000000000000000000000000000000e0", // length of ple encoded swaps without padding
|
||||
"006e", // ple encoded swaps
|
||||
"00", // token in index
|
||||
"01", // token out index
|
||||
"000000", // split
|
||||
@@ -1818,7 +1821,8 @@ mod tests {
|
||||
"3ede3eca2a72b3aecc820e955b36f38437d01395", // router address
|
||||
"88e6a0c2ddd26feeb64f039a2c41296fcb3f5640", // component id
|
||||
"01", // zero2one
|
||||
"006d", // ple encoded swaps
|
||||
"00", // transfer type
|
||||
"006e", // ple encoded swaps
|
||||
"01", // token in index
|
||||
"00000000", // split
|
||||
"2e234dae75c793f67a35089c9d99245e1c58470b", // executor address
|
||||
@@ -1827,7 +1831,8 @@ mod tests {
|
||||
"000bb8", // pool fee
|
||||
"3ede3eca2a72b3aecc820e955b36f38437d01395", // router address
|
||||
"8ad599c3a0ff1de082011efddc58f1908eb6e6d8", // component id
|
||||
"000000", // zero2one
|
||||
"00", // zero2one
|
||||
"00", // transfer type
|
||||
]
|
||||
.join("");
|
||||
|
||||
@@ -1958,8 +1963,8 @@ mod tests {
|
||||
]
|
||||
.join("");
|
||||
let expected_swaps = [
|
||||
"0000000000000000000000000000000000000000000000000000000000000136", // length of ple encoded swaps without padding
|
||||
"006d", // ple encoded swaps
|
||||
"0000000000000000000000000000000000000000000000000000000000000139", // length of ple encoded swaps without padding
|
||||
"006e", // ple encoded swaps
|
||||
"00", // token in index
|
||||
"01", // token out index
|
||||
"999999", // split
|
||||
@@ -1970,7 +1975,8 @@ mod tests {
|
||||
"3ede3eca2a72b3aecc820e955b36f38437d01395", // router address
|
||||
"88e6a0c2ddd26feeb64f039a2c41296fcb3f5640", // component id
|
||||
"01", // zero2one
|
||||
"006d", // ple encoded swaps
|
||||
"00", // transfer type
|
||||
"006e", // ple encoded swaps
|
||||
"00", // token in index
|
||||
"01", // token out index
|
||||
"000000", // split
|
||||
@@ -1981,7 +1987,8 @@ mod tests {
|
||||
"3ede3eca2a72b3aecc820e955b36f38437d01395", // router address
|
||||
"8ad599c3a0ff1de082011efddc58f1908eb6e6d8", // component id
|
||||
"01", // zero2one
|
||||
"0056", // ple encoded swaps
|
||||
"00", // transfer type
|
||||
"0057", // ple encoded swaps
|
||||
"01", // token in index
|
||||
"00", // token out index
|
||||
"000000", // split
|
||||
@@ -1990,7 +1997,8 @@ mod tests {
|
||||
"b4e16d0168e52d35cacd2c6185b44281ec28c9dc", // component id,
|
||||
"3ede3eca2a72b3aecc820e955b36f38437d01395", // router address
|
||||
"00", // zero2one
|
||||
"00000000000000000000" // padding
|
||||
"00", // transfer type
|
||||
"00000000000000" // padding
|
||||
]
|
||||
.join("");
|
||||
assert_eq!(hex_calldata[..520], expected_input);
|
||||
@@ -2117,8 +2125,8 @@ mod tests {
|
||||
.join("");
|
||||
|
||||
let expected_swaps = [
|
||||
"0000000000000000000000000000000000000000000000000000000000000136", // length of ple encoded swaps without padding
|
||||
"0056", // ple encoded swaps
|
||||
"0000000000000000000000000000000000000000000000000000000000000139", // length of ple encoded swaps without padding
|
||||
"0057", // ple encoded swaps
|
||||
"00", // token in index
|
||||
"01", // token out index
|
||||
"000000", // split
|
||||
@@ -2127,7 +2135,8 @@ mod tests {
|
||||
"b4e16d0168e52d35cacd2c6185b44281ec28c9dc", // component id
|
||||
"3ede3eca2a72b3aecc820e955b36f38437d01395", // router address
|
||||
"01", // zero2one
|
||||
"006d", // ple encoded swaps
|
||||
"00", // transfer type
|
||||
"006e", // ple encoded swaps
|
||||
"01", // token in index
|
||||
"00", // token out index
|
||||
"999999", // split
|
||||
@@ -2138,7 +2147,8 @@ mod tests {
|
||||
"3ede3eca2a72b3aecc820e955b36f38437d01395", // router address
|
||||
"88e6a0c2ddd26feeb64f039a2c41296fcb3f5640", // component id
|
||||
"00", // zero2one
|
||||
"006d", // ple encoded swaps
|
||||
"00", // transfer type
|
||||
"006e", // ple encoded swaps
|
||||
"01", // token in index
|
||||
"00", // token out index
|
||||
"000000", // split
|
||||
@@ -2149,7 +2159,8 @@ mod tests {
|
||||
"3ede3eca2a72b3aecc820e955b36f38437d01395", // router address
|
||||
"8ad599c3a0ff1de082011efddc58f1908eb6e6d8", // component id
|
||||
"00", // zero2one
|
||||
"00000000000000000000" // padding
|
||||
"00", // transfer type
|
||||
"00000000000000" // padding
|
||||
]
|
||||
.join("");
|
||||
|
||||
|
||||
@@ -22,6 +22,15 @@ 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
|
||||
@@ -66,6 +75,7 @@ impl SwapEncoder for UniswapV2SwapEncoder {
|
||||
component_id,
|
||||
bytes_to_address(&encoding_context.receiver)?,
|
||||
zero_to_one,
|
||||
(TransferType::Transfer as u8).to_be_bytes(),
|
||||
);
|
||||
|
||||
Ok(args.abi_encode_packed())
|
||||
@@ -128,6 +138,7 @@ impl SwapEncoder for UniswapV3SwapEncoder {
|
||||
bytes_to_address(&encoding_context.receiver)?,
|
||||
component_id,
|
||||
zero_to_one,
|
||||
(TransferType::Transfer as u8).to_be_bytes(),
|
||||
);
|
||||
|
||||
Ok(args.abi_encode_packed())
|
||||
@@ -606,6 +617,8 @@ mod tests {
|
||||
"0000000000000000000000000000000000000001",
|
||||
// zero for one
|
||||
"00",
|
||||
// transfer type (transfer)
|
||||
"00",
|
||||
))
|
||||
);
|
||||
}
|
||||
@@ -661,6 +674,8 @@ mod tests {
|
||||
"88e6a0c2ddd26feeb64f039a2c41296fcb3f5640",
|
||||
// zero for one
|
||||
"00",
|
||||
// transfer type (transfer)
|
||||
"00",
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
@@ -916,6 +916,8 @@ mod tests {
|
||||
"1d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e",
|
||||
// zero for one
|
||||
"00",
|
||||
// transfer type
|
||||
"00",
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user