Merge pull request #225 from propeller-heads/cleanup/dc/ENG-4616-refactor-tests-2
fix: Refactor tests
This commit is contained in:
@@ -1,11 +1,8 @@
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
pragma solidity ^0.8.26;
|
||||
|
||||
import "@src/executors/UniswapV4Executor.sol";
|
||||
import {TychoRouter} from "@src/TychoRouter.sol";
|
||||
import "./TychoRouterTestSetup.sol";
|
||||
import "./executors/UniswapV4Utils.sol";
|
||||
import {SafeCallback} from "@uniswap/v4-periphery/src/base/SafeCallback.sol";
|
||||
|
||||
contract TychoRouterTest is TychoRouterTestSetup {
|
||||
bytes32 public constant EXECUTOR_SETTER_ROLE =
|
||||
@@ -91,16 +88,16 @@ contract TychoRouterTest is TychoRouterTestSetup {
|
||||
}
|
||||
|
||||
function testWithdrawERC20Tokens() public {
|
||||
vm.startPrank(BOB);
|
||||
mintTokens(100 ether, tychoRouterAddr);
|
||||
vm.stopPrank();
|
||||
IERC20[] memory tokens = new IERC20[](2);
|
||||
tokens[0] = IERC20(WETH_ADDR);
|
||||
tokens[1] = IERC20(USDC_ADDR);
|
||||
for (uint256 i = 0; i < tokens.length; i++) {
|
||||
deal(address(tokens[i]), tychoRouterAddr, 100 ether);
|
||||
}
|
||||
|
||||
vm.startPrank(FUND_RESCUER);
|
||||
IERC20[] memory tokensArray = new IERC20[](3);
|
||||
tokensArray[0] = IERC20(address(tokens[0]));
|
||||
tokensArray[1] = IERC20(address(tokens[1]));
|
||||
tokensArray[2] = IERC20(address(tokens[2]));
|
||||
tychoRouter.withdraw(tokensArray, FUND_RESCUER);
|
||||
|
||||
tychoRouter.withdraw(tokens, FUND_RESCUER);
|
||||
|
||||
// Check balances after withdrawing
|
||||
for (uint256 i = 0; i < tokens.length; i++) {
|
||||
@@ -113,21 +110,22 @@ contract TychoRouterTest is TychoRouterTestSetup {
|
||||
}
|
||||
|
||||
function testWithdrawERC20TokensFailures() public {
|
||||
mintTokens(100 ether, tychoRouterAddr);
|
||||
IERC20[] memory tokensArray = new IERC20[](3);
|
||||
tokensArray[0] = IERC20(address(tokens[0]));
|
||||
tokensArray[1] = IERC20(address(tokens[1]));
|
||||
tokensArray[2] = IERC20(address(tokens[2]));
|
||||
IERC20[] memory tokens = new IERC20[](2);
|
||||
tokens[0] = IERC20(WETH_ADDR);
|
||||
tokens[1] = IERC20(USDC_ADDR);
|
||||
for (uint256 i = 0; i < tokens.length; i++) {
|
||||
deal(address(tokens[i]), tychoRouterAddr, 100 ether);
|
||||
}
|
||||
|
||||
vm.startPrank(FUND_RESCUER);
|
||||
vm.expectRevert(TychoRouter__AddressZero.selector);
|
||||
tychoRouter.withdraw(tokensArray, address(0));
|
||||
tychoRouter.withdraw(tokens, address(0));
|
||||
vm.stopPrank();
|
||||
|
||||
// Not role FUND_RESCUER
|
||||
vm.startPrank(BOB);
|
||||
vm.expectRevert();
|
||||
tychoRouter.withdraw(tokensArray, FUND_RESCUER);
|
||||
tychoRouter.withdraw(tokens, FUND_RESCUER);
|
||||
vm.stopPrank();
|
||||
}
|
||||
|
||||
|
||||
@@ -2,130 +2,9 @@
|
||||
pragma solidity ^0.8.26;
|
||||
|
||||
import "./TychoRouterTestSetup.sol";
|
||||
import "./executors/UniswapV4Utils.sol";
|
||||
import "./protocols/UniswapV4Utils.sol";
|
||||
|
||||
contract TychoRouterTestProtocolIntegration is TychoRouterTestSetup {
|
||||
function testSingleSwapUSV4CallbackPermit2() public {
|
||||
vm.startPrank(ALICE);
|
||||
uint256 amountIn = 100 ether;
|
||||
deal(USDE_ADDR, ALICE, amountIn);
|
||||
(
|
||||
IAllowanceTransfer.PermitSingle memory permitSingle,
|
||||
bytes memory signature
|
||||
) = handlePermit2Approval(USDE_ADDR, tychoRouterAddr, amountIn);
|
||||
|
||||
UniswapV4Executor.UniswapV4Pool[] memory pools =
|
||||
new UniswapV4Executor.UniswapV4Pool[](1);
|
||||
pools[0] = UniswapV4Executor.UniswapV4Pool({
|
||||
intermediaryToken: USDT_ADDR,
|
||||
fee: uint24(100),
|
||||
tickSpacing: int24(1)
|
||||
});
|
||||
|
||||
bytes memory protocolData = UniswapV4Utils.encodeExactInput(
|
||||
USDE_ADDR,
|
||||
USDT_ADDR,
|
||||
true,
|
||||
RestrictTransferFrom.TransferType.TransferFrom,
|
||||
ALICE,
|
||||
pools
|
||||
);
|
||||
|
||||
bytes memory swap =
|
||||
encodeSingleSwap(address(usv4Executor), protocolData);
|
||||
|
||||
tychoRouter.singleSwapPermit2(
|
||||
amountIn,
|
||||
USDE_ADDR,
|
||||
USDT_ADDR,
|
||||
99943850,
|
||||
false,
|
||||
false,
|
||||
ALICE,
|
||||
permitSingle,
|
||||
signature,
|
||||
swap
|
||||
);
|
||||
|
||||
assertEq(IERC20(USDT_ADDR).balanceOf(ALICE), 99963618);
|
||||
vm.stopPrank();
|
||||
}
|
||||
|
||||
function testSplitSwapMultipleUSV4Callback() public {
|
||||
// This test has two uniswap v4 hops that will be executed inside of the V4 pool manager
|
||||
// USDE -> USDT -> WBTC
|
||||
uint256 amountIn = 100 ether;
|
||||
deal(USDE_ADDR, ALICE, amountIn);
|
||||
|
||||
UniswapV4Executor.UniswapV4Pool[] memory pools =
|
||||
new UniswapV4Executor.UniswapV4Pool[](2);
|
||||
pools[0] = UniswapV4Executor.UniswapV4Pool({
|
||||
intermediaryToken: USDT_ADDR,
|
||||
fee: uint24(100),
|
||||
tickSpacing: int24(1)
|
||||
});
|
||||
pools[1] = UniswapV4Executor.UniswapV4Pool({
|
||||
intermediaryToken: WBTC_ADDR,
|
||||
fee: uint24(3000),
|
||||
tickSpacing: int24(60)
|
||||
});
|
||||
|
||||
bytes memory protocolData = UniswapV4Utils.encodeExactInput(
|
||||
USDE_ADDR,
|
||||
WBTC_ADDR,
|
||||
true,
|
||||
RestrictTransferFrom.TransferType.TransferFrom,
|
||||
ALICE,
|
||||
pools
|
||||
);
|
||||
|
||||
bytes memory swap =
|
||||
encodeSingleSwap(address(usv4Executor), protocolData);
|
||||
|
||||
vm.startPrank(ALICE);
|
||||
IERC20(USDE_ADDR).approve(tychoRouterAddr, amountIn);
|
||||
tychoRouter.singleSwap(
|
||||
amountIn,
|
||||
USDE_ADDR,
|
||||
WBTC_ADDR,
|
||||
118280,
|
||||
false,
|
||||
false,
|
||||
ALICE,
|
||||
true,
|
||||
swap
|
||||
);
|
||||
|
||||
assertEq(IERC20(WBTC_ADDR).balanceOf(ALICE), 118281);
|
||||
}
|
||||
|
||||
function testSingleUSV4IntegrationGroupedSwap() public {
|
||||
// Test created with calldata from our router encoder.
|
||||
|
||||
// Performs a single swap from USDC to PEPE though ETH using two
|
||||
// consecutive USV4 pools. It's a single swap because it is a consecutive grouped swaps
|
||||
//
|
||||
// USDC ──(USV4)──> ETH ───(USV4)──> PEPE
|
||||
//
|
||||
deal(USDC_ADDR, ALICE, 1 ether);
|
||||
uint256 balanceBefore = IERC20(PEPE_ADDR).balanceOf(ALICE);
|
||||
|
||||
// Approve permit2
|
||||
vm.startPrank(ALICE);
|
||||
IERC20(USDC_ADDR).approve(PERMIT2_ADDRESS, type(uint256).max);
|
||||
bytes memory callData = loadCallDataFromFile(
|
||||
"test_single_encoding_strategy_usv4_grouped_swap"
|
||||
);
|
||||
(bool success,) = tychoRouterAddr.call(callData);
|
||||
|
||||
vm.stopPrank();
|
||||
|
||||
uint256 balanceAfter = IERC20(PEPE_ADDR).balanceOf(ALICE);
|
||||
|
||||
assertTrue(success, "Call Failed");
|
||||
assertEq(balanceAfter - balanceBefore, 123172000092711286554274694);
|
||||
}
|
||||
|
||||
function testMultiProtocolIntegration() public {
|
||||
// Test created with calldata from our router encoder.
|
||||
//
|
||||
@@ -147,150 +26,4 @@ contract TychoRouterTestProtocolIntegration is TychoRouterTestSetup {
|
||||
assertTrue(success, "Call Failed");
|
||||
assertEq(balanceAfter - balanceBefore, 732214216964381330);
|
||||
}
|
||||
|
||||
function testSingleUSV4IntegrationInputETH() public {
|
||||
// Test created with calldata from our router encoder.
|
||||
|
||||
// Performs a single swap from ETH to PEPE without wrapping or unwrapping
|
||||
//
|
||||
// ETH ───(USV4)──> PEPE
|
||||
//
|
||||
deal(ALICE, 1 ether);
|
||||
uint256 balanceBefore = IERC20(PEPE_ADDR).balanceOf(ALICE);
|
||||
|
||||
bytes memory callData =
|
||||
loadCallDataFromFile("test_single_encoding_strategy_usv4_eth_in");
|
||||
(bool success,) = tychoRouterAddr.call{value: 1 ether}(callData);
|
||||
|
||||
vm.stopPrank();
|
||||
|
||||
uint256 balanceAfter = IERC20(PEPE_ADDR).balanceOf(ALICE);
|
||||
|
||||
assertTrue(success, "Call Failed");
|
||||
assertEq(balanceAfter - balanceBefore, 235610487387677804636755778);
|
||||
}
|
||||
|
||||
function testSingleUSV4IntegrationOutputETH() public {
|
||||
// Test created with calldata from our router encoder.
|
||||
|
||||
// Performs a single swap from USDC to ETH without wrapping or unwrapping
|
||||
//
|
||||
// USDC ───(USV4)──> ETH
|
||||
//
|
||||
deal(USDC_ADDR, ALICE, 3000_000000);
|
||||
uint256 balanceBefore = ALICE.balance;
|
||||
|
||||
// Approve permit2
|
||||
vm.startPrank(ALICE);
|
||||
IERC20(USDC_ADDR).approve(PERMIT2_ADDRESS, type(uint256).max);
|
||||
|
||||
bytes memory callData =
|
||||
loadCallDataFromFile("test_single_encoding_strategy_usv4_eth_out");
|
||||
(bool success,) = tychoRouterAddr.call(callData);
|
||||
|
||||
vm.stopPrank();
|
||||
|
||||
uint256 balanceAfter = ALICE.balance;
|
||||
|
||||
assertTrue(success, "Call Failed");
|
||||
console.logUint(balanceAfter - balanceBefore);
|
||||
assertEq(balanceAfter - balanceBefore, 1474406268748155809);
|
||||
}
|
||||
|
||||
function testSingleMaverickIntegration() public {
|
||||
deal(GHO_ADDR, ALICE, 1 ether);
|
||||
uint256 balanceBefore = IERC20(USDC_ADDR).balanceOf(ALICE);
|
||||
|
||||
vm.startPrank(ALICE);
|
||||
IERC20(GHO_ADDR).approve(tychoRouterAddr, type(uint256).max);
|
||||
|
||||
bytes memory callData =
|
||||
loadCallDataFromFile("test_single_encoding_strategy_maverick");
|
||||
(bool success,) = tychoRouterAddr.call(callData);
|
||||
|
||||
uint256 balanceAfter = IERC20(USDC_ADDR).balanceOf(ALICE);
|
||||
|
||||
assertTrue(success, "Call Failed");
|
||||
assertGe(balanceAfter - balanceBefore, 999725);
|
||||
assertEq(IERC20(WETH_ADDR).balanceOf(tychoRouterAddr), 0);
|
||||
}
|
||||
|
||||
function testSingleEkuboIntegration() public {
|
||||
vm.stopPrank();
|
||||
|
||||
deal(ALICE, 1 ether);
|
||||
uint256 balanceBefore = IERC20(USDC_ADDR).balanceOf(ALICE);
|
||||
|
||||
// Approve permit2
|
||||
vm.startPrank(ALICE);
|
||||
bytes memory callData =
|
||||
loadCallDataFromFile("test_single_encoding_strategy_ekubo");
|
||||
(bool success,) = tychoRouterAddr.call{value: 1 ether}(callData);
|
||||
|
||||
uint256 balanceAfter = IERC20(USDC_ADDR).balanceOf(ALICE);
|
||||
|
||||
assertTrue(success, "Call Failed");
|
||||
assertGe(balanceAfter - balanceBefore, 26173932);
|
||||
assertEq(IERC20(WETH_ADDR).balanceOf(tychoRouterAddr), 0);
|
||||
}
|
||||
|
||||
function testSingleCurveIntegration() public {
|
||||
deal(UWU_ADDR, ALICE, 1 ether);
|
||||
|
||||
vm.startPrank(ALICE);
|
||||
IERC20(UWU_ADDR).approve(tychoRouterAddr, type(uint256).max);
|
||||
bytes memory callData =
|
||||
loadCallDataFromFile("test_single_encoding_strategy_curve");
|
||||
(bool success,) = tychoRouterAddr.call(callData);
|
||||
|
||||
assertTrue(success, "Call Failed");
|
||||
assertEq(IERC20(WETH_ADDR).balanceOf(ALICE), 2877855391767);
|
||||
|
||||
vm.stopPrank();
|
||||
}
|
||||
|
||||
function testSingleSwapUSV3Permit2() public {
|
||||
// Trade 1 WETH for DAI with 1 swap on Uniswap V3 using Permit2
|
||||
// Tests entire USV3 flow including callback
|
||||
// 1 WETH -> DAI
|
||||
// (USV3)
|
||||
vm.startPrank(ALICE);
|
||||
uint256 amountIn = 10 ** 18;
|
||||
deal(WETH_ADDR, ALICE, amountIn);
|
||||
(
|
||||
IAllowanceTransfer.PermitSingle memory permitSingle,
|
||||
bytes memory signature
|
||||
) = handlePermit2Approval(WETH_ADDR, tychoRouterAddr, amountIn);
|
||||
|
||||
uint256 expAmountOut = 1205_128428842122129186; //Swap 1 WETH for 1205.12 DAI
|
||||
bool zeroForOne = false;
|
||||
bytes memory protocolData = encodeUniswapV3Swap(
|
||||
WETH_ADDR,
|
||||
DAI_ADDR,
|
||||
ALICE,
|
||||
DAI_WETH_USV3,
|
||||
zeroForOne,
|
||||
RestrictTransferFrom.TransferType.TransferFrom
|
||||
);
|
||||
bytes memory swap =
|
||||
encodeSingleSwap(address(usv3Executor), protocolData);
|
||||
|
||||
tychoRouter.singleSwapPermit2(
|
||||
amountIn,
|
||||
WETH_ADDR,
|
||||
DAI_ADDR,
|
||||
expAmountOut - 1,
|
||||
false,
|
||||
false,
|
||||
ALICE,
|
||||
permitSingle,
|
||||
signature,
|
||||
swap
|
||||
);
|
||||
|
||||
uint256 finalBalance = IERC20(DAI_ADDR).balanceOf(ALICE);
|
||||
assertGe(finalBalance, expAmountOut);
|
||||
|
||||
vm.stopPrank();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,8 +4,6 @@ pragma solidity ^0.8.26;
|
||||
import "@src/executors/UniswapV4Executor.sol";
|
||||
import {TychoRouter} from "@src/TychoRouter.sol";
|
||||
import "./TychoRouterTestSetup.sol";
|
||||
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) {
|
||||
|
||||
@@ -4,8 +4,6 @@ pragma solidity ^0.8.26;
|
||||
import "@src/executors/UniswapV4Executor.sol";
|
||||
import {TychoRouter} from "@src/TychoRouter.sol";
|
||||
import "./TychoRouterTestSetup.sol";
|
||||
import "./executors/UniswapV4Utils.sol";
|
||||
import {SafeCallback} from "@uniswap/v4-periphery/src/base/SafeCallback.sol";
|
||||
|
||||
contract TychoRouterSingleSwapTest is TychoRouterTestSetup {
|
||||
function testSingleSwapPermit2() public {
|
||||
|
||||
@@ -4,8 +4,6 @@ pragma solidity ^0.8.26;
|
||||
import "@src/executors/UniswapV4Executor.sol";
|
||||
import {TychoRouter, RestrictTransferFrom} from "@src/TychoRouter.sol";
|
||||
import "./TychoRouterTestSetup.sol";
|
||||
import "./executors/UniswapV4Utils.sol";
|
||||
import {SafeCallback} from "@uniswap/v4-periphery/src/base/SafeCallback.sol";
|
||||
|
||||
contract TychoRouterSplitSwapTest is TychoRouterTestSetup {
|
||||
function _getSplitSwaps(bool transferFrom)
|
||||
|
||||
@@ -1,22 +1,27 @@
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
pragma solidity ^0.8.26;
|
||||
|
||||
import "../src/executors/BalancerV2Executor.sol";
|
||||
import "../src/executors/CurveExecutor.sol";
|
||||
import "../src/executors/EkuboExecutor.sol";
|
||||
import "../src/executors/UniswapV2Executor.sol";
|
||||
import "../src/executors/UniswapV3Executor.sol";
|
||||
import "../src/executors/UniswapV4Executor.sol";
|
||||
// Executors
|
||||
import {BalancerV2Executor} from "../src/executors/BalancerV2Executor.sol";
|
||||
import {BalancerV3Executor} from "../src/executors/BalancerV3Executor.sol";
|
||||
import {CurveExecutor} from "../src/executors/CurveExecutor.sol";
|
||||
import {EkuboExecutor} from "../src/executors/EkuboExecutor.sol";
|
||||
import {MaverickV2Executor} from "../src/executors/MaverickV2Executor.sol";
|
||||
import {UniswapV2Executor} from "../src/executors/UniswapV2Executor.sol";
|
||||
import {
|
||||
UniswapV3Executor,
|
||||
IUniswapV3Pool
|
||||
} from "../src/executors/UniswapV3Executor.sol";
|
||||
import {UniswapV4Executor} from "../src/executors/UniswapV4Executor.sol";
|
||||
|
||||
// Test utilities and mocks
|
||||
import "./Constants.sol";
|
||||
import "./mock/MockERC20.sol";
|
||||
import "./TestUtils.sol";
|
||||
import {Permit2TestHelper} from "./Permit2TestHelper.sol";
|
||||
|
||||
// Core contracts and interfaces
|
||||
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";
|
||||
import "./TestUtils.sol";
|
||||
import {MaverickV2Executor} from "../src/executors/MaverickV2Executor.sol";
|
||||
import {BalancerV3Executor} from "../src/executors/BalancerV3Executor.sol";
|
||||
|
||||
contract TychoRouterExposed is TychoRouter {
|
||||
constructor(address _permit2, address weth) TychoRouter(_permit2, weth) {}
|
||||
@@ -68,7 +73,6 @@ contract TychoRouterTestSetup is Constants, Permit2TestHelper, TestUtils {
|
||||
CurveExecutor public curveExecutor;
|
||||
MaverickV2Executor public maverickv2Executor;
|
||||
BalancerV3Executor public balancerV3Executor;
|
||||
MockERC20[] tokens;
|
||||
|
||||
function getForkBlock() public view virtual returns (uint256) {
|
||||
return 22082754;
|
||||
@@ -87,12 +91,6 @@ contract TychoRouterTestSetup is Constants, Permit2TestHelper, TestUtils {
|
||||
vm.startPrank(EXECUTOR_SETTER);
|
||||
tychoRouter.setExecutors(executors);
|
||||
vm.stopPrank();
|
||||
|
||||
vm.startPrank(BOB);
|
||||
tokens.push(new MockERC20("Token A", "A"));
|
||||
tokens.push(new MockERC20("Token B", "B"));
|
||||
tokens.push(new MockERC20("Token C", "C"));
|
||||
vm.stopPrank();
|
||||
}
|
||||
|
||||
function deployRouter() public returns (TychoRouterExposed) {
|
||||
@@ -147,18 +145,6 @@ contract TychoRouterTestSetup is Constants, Permit2TestHelper, TestUtils {
|
||||
return executors;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Mints tokens to the given address
|
||||
* @param amount The amount of tokens to mint
|
||||
* @param to The address to mint tokens to
|
||||
*/
|
||||
function mintTokens(uint256 amount, address to) internal {
|
||||
for (uint256 i = 0; i < tokens.length; i++) {
|
||||
// slither-disable-next-line calls-loop
|
||||
tokens[i].mint(to, amount);
|
||||
}
|
||||
}
|
||||
|
||||
function pleEncode(bytes[] memory data)
|
||||
public
|
||||
pure
|
||||
|
||||
@@ -3,23 +3,23 @@ test_single_encoding_strategy_ekubo:5c4b639c000000000000000000000000000000000000
|
||||
test_uniswap_v3_uniswap_v3:e21dd0d30000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000d600692e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599000bb83ede3eca2a72b3aecc820e955b36f38437d01395cbcdf9626bc03e24f779434178a73a0b4bad62ed000000692e234dae75c793f67a35089c9d99245e1c58470b2260fac5e5542a773aa44fbcfedf7c193bc2c599a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb8cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc299ac8ca7087fa4a2a1fb6357269965a2014abc35010100000000000000000000
|
||||
test_balancer_v2_uniswap_v2:e21dd0d30000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000c80072c7183455a4c133ae270771860664b6b7ec320bb1c02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599a6f548df93de924d73be7d25dc02554c6bd66db500020000000000000000000e004375dff511095cc5a197a54140a24efef3a416010000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20102000000000000000000000000000000000000000000000000
|
||||
test_sequential_swap_strategy_encoder_no_permit2:e21dd0d30000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000a800525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d940004375dff511095cc5a197a54140a24efef3a416000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20102000000000000000000000000000000000000000000000000
|
||||
test_single_encoding_strategy_usv4_grouped_swap:30ace1b1000000000000000000000000000000000000000000000000000000003b9aca00000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330000000000000000000000000000000000000000005064ff624d54346285543f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000000000000000000000000000000000003b9aca0000000000000000000000000000000000000000000000000000000000686a405400000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006842ba5c00000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041e497fb5e24723b35cf1da883013e8e640fb0414c44ac4fb8ad8a69e307b4805167f6036b336255424472df199e5669771b850aad946be487d98736c657a986a01c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000086f62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb486982508145454ce325ddbe47a25d4ec3d23119330000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c6982508145454ce325ddbe47a25d4ec3d23119330061a80001f40000000000000000000000000000000000000000000000000000
|
||||
test_single_encoding_strategy_usv4_eth_out:30ace1b100000000000000000000000000000000000000000000000000000000b2d05e00000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f81490b4f29aade00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000b2d05e0000000000000000000000000000000000000000000000000000000000686a405400000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006842ba5c00000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041986db71b95d40af4bcbbb7ddf2e4d866d088152df332e39c2b1051d18c58505316f3786fc6c4cfc93249050c4a3cec37df095483225592f8ce7b27c7b43b7f431b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006cf62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c0000000000000000000000000000000000000000
|
||||
test_sequential_swap_strategy_encoder:51bcc7b60000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000686a405500000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006842ba5d00000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041328f1b72977c3d7dc15d43d58b8f6aa239c324010606ea31df41c7a526b7fed62a46fd97fe46d6da9652908684a0d63b3a2759a3076d6cfe8df35f4df5d0476a1b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a800525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d940004375dff511095cc5a197a54140a24efef3a416000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20102000000000000000000000000000000000000000000000000
|
||||
test_single_encoding_strategy_usv4_grouped_swap:30ace1b1000000000000000000000000000000000000000000000000000000003b9aca00000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330000000000000000000000000000000000000000005064ff624d54346285543f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000000000000000000000000000000000003b9aca00000000000000000000000000000000000000000000000000000000006880e4c200000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000068595eca00000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041703880857f06138ff75e5f3ffee91748471e42424ee8622b0c18f2cc503d482e1242fe95de3a98939e5fef0857b038a435ff88805f838831148b4d7c5e8d2b971b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000086f62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb486982508145454ce325ddbe47a25d4ec3d23119330000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c6982508145454ce325ddbe47a25d4ec3d23119330061a80001f40000000000000000000000000000000000000000000000000000
|
||||
test_single_encoding_strategy_usv4_eth_out:30ace1b100000000000000000000000000000000000000000000000000000000b2d05e00000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f81490b4f29aade00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000b2d05e00000000000000000000000000000000000000000000000000000000006880e4c200000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000068595eca00000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000004174be0621ea9006ddcbc7903ca8c698aadb92a057753a90ee07645108fa4330120828e3905b3b235db35c2dcc92670fe4d481f5778392d1c85f03de42e48c9bb21b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006cf62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c0000000000000000000000000000000000000000
|
||||
test_sequential_swap_strategy_encoder:51bcc7b60000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000000000006880e4c200000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000068595eca00000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041091b2d075582e94ecfbfb55385f0ba47797cafb8b149f972c2f74509e119644178265eea21103fe6fda63a49dbd769efd5785c440dbb1335c189d544bad10dfa1b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a800525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d940004375dff511095cc5a197a54140a24efef3a416000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20102000000000000000000000000000000000000000000000000
|
||||
test_single_swap_strategy_encoder_no_permit2:5c4b639c0000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000000000000000000000000058e7926ee858a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000
|
||||
test_single_swap_strategy_encoder_no_transfer_in:5c4b639c0000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000000000000000000000000058e7926ee858a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200010000000000000000000000000000
|
||||
test_single_encoding_strategy_usv4_eth_in:30ace1b10000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330000000000000000000000000000000000000000007e0a55d4322a6e93c2379c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000686a405400000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006842ba5c00000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000004192a6c559fa614c7d9a7249d7638bcabea4c78defc083b12464a4e3a6216ef04b32c7cae804e833e0643576141c5cebb71981e224c2152fb7cb4b1d9c50e04ed71b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006cf62849f9a0b5bf2913b396098f7c7019b51a820a00000000000000000000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330102cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc26982508145454ce325ddbe47a25d4ec3d23119330061a80001f40000000000000000000000000000000000000000
|
||||
test_sequential_strategy_cyclic_swap:51bcc7b60000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005ec8f6e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e10000000000000000000000000000000000000000000000000000000000686a405500000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006842ba5d00000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041f3c69f1600d565283b2376f597d795451ecbe0fc19a4cc54bc8b8706a74f24db2434c920084579c4ff7a0220f90f9dd2d1995e1739c2fd68eb6a898224a9eb721c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d600692e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f5640010000692e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb8cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc28ad599c3a0ff1de082011efddc58f1908eb6e6d8000100000000000000000000
|
||||
test_single_encoding_strategy_usv4_eth_in:30ace1b10000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330000000000000000000000000000000000000000007e0a55d4322a6e93c2379c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000000000006880e4c200000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000068595eca00000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000412a62b7a9cd647038c5133274120981d96c9f99c03026dff225f9d6135f2d9fb6015fa40d1b286328537334adf56338c71cfd464347f98c73eb2b2043a4e69eb81c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006cf62849f9a0b5bf2913b396098f7c7019b51a820a00000000000000000000000000000000000000006982508145454ce325ddbe47a25d4ec3d23119330102cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc26982508145454ce325ddbe47a25d4ec3d23119330061a80001f40000000000000000000000000000000000000000
|
||||
test_sequential_strategy_cyclic_swap:51bcc7b60000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005ec8f6e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000000000000000000000000000000000006880e4c200000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000068595eca00000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000412737daa02535466c3d6265d8a8d0e7944ce950ee9ca1fb0579b0bf5bfb0e5ce63184936a008aa0b1ad4fcae87b9ac697006ec82607e06e25e119230f67d1411e1c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d600692e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f5640010000692e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb8cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc28ad599c3a0ff1de082011efddc58f1908eb6e6d8000100000000000000000000
|
||||
test_single_encoding_strategy_curve_st_eth:5c4b639c0000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ae7ab96520de3a18e5e111b5eaab095312d7fe84000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000691d1499e622d69689cdf9004d05ec547d650ff211eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeae7ab96520de3a18e5e111b5eaab095312d7fe84dc24316b9ae028f1497c275eb9192a3ea0f670220100010002cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000
|
||||
test_single
|
||||
test_encode_uniswap_v4_sequential_swap:4c9edd5852cd905f086c759e8383e09bff1e68b32260fac5e5542a773aa44fbcfedf7c193bc2c5990101cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2dac17f958d2ee523a2206206994597c13d831ec70000640000012260fac5e5542a773aa44fbcfedf7c193bc2c599000bb800003c
|
||||
6d70b85442ed96492800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000000000006869398600000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006841b38e00000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041752ca399237fc5086ef89d5f6dabecfb4b43c0753ecfb7020a6a86045db423fd3be9565f79b511fe93f55f76f61b1ac8d786b04051110ca6cbe10bbf69901b871c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000
|
||||
test_single_encoding_strategy_curve:5c4b639c0000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000055c08ca52497e2f1534b59e2917bf524d4765257000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000691d1499e622d69689cdf9004d05ec547d650ff21155c08ca52497e2f1534b59e2917bf524d4765257c02aaa39b223fe8d0a0e5c4f27ead9083c756cc277146b0a1d08b6844376df6d9da99ba7f1b19e710201000100cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000
|
||||
test_single_swap_strategy_encoder_unwrap:30ace1b10000000000000000000000000000000000000000000000a2a15d09519be000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f0000000000000000000000000000000000000000000000a2a15d09519be0000000000000000000000000000000000000000000000000000000000000686a405500000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006842ba5d00000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041254a88ad83ac172ad1e7566ebf02752075226a044f6235aadf1d226fe742f9fd41fb89b789447131d7132c244747d709511aff5b39fb14be7b610d748ee751c61c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fa478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d0139501000000000000000000000000000000
|
||||
test_single_swap_strategy_encoder_wrap:30ace1b10000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000000000000000000000000059fb7d3830e6fc064b00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000686a405500000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006842ba5d00000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041917935f4a467322cf1123b481d57d9400f38036bf011df8963f4ab680ab558d9261015e667c3ed9556ee76b4c86fd158eb561eac78658bd0e4622374109481881b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200010000000000000000000000000000
|
||||
test_split_output_cyclic_swap:7c5538460000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005e703f4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e10000000000000000000000000000000000000000000000000000000000686a405500000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006842ba5d000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000041f3c69f1600d565283b2376f597d795451ecbe0fc19a4cc54bc8b8706a74f24db2434c920084579c4ff7a0220f90f9dd2d1995e1739c2fd68eb6a898224a9eb721c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000139005700010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48b4e16d0168e52d35cacd2c6185b44281ec28c9dc3ede3eca2a72b3aecc820e955b36f38437d013950100006e01009999992e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480001f4cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc288e6a0c2ddd26feeb64f039a2c41296fcb3f56400001006e01000000002e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb8cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc28ad599c3a0ff1de082011efddc58f1908eb6e6d8000100000000000000
|
||||
test_split_input_cyclic_swap:7c5538460000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005ef619b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e10000000000000000000000000000000000000000000000000000000000686a405500000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006842ba5d000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000041f3c69f1600d565283b2376f597d795451ecbe0fc19a4cc54bc8b8706a74f24db2434c920084579c4ff7a0220f90f9dd2d1995e1739c2fd68eb6a898224a9eb721c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000139006e00019999992e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f56400100006e00010000002e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000bb83ede3eca2a72b3aecc820e955b36f38437d013958ad599c3a0ff1de082011efddc58f1908eb6e6d80100005701000000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2b4e16d0168e52d35cacd2c6185b44281ec28c9dccd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000100000000000000
|
||||
test_split_swap_strategy_encoder:7c5538460000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000686a405500000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006842ba5d000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000041328f1b72977c3d7dc15d43d58b8f6aa239c324010606ea31df41c7a526b7fed62a46fd97fe46d6da9652908684a0d63b3a2759a3076d6cfe8df35f4df5d0476a1b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000164005700028000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d013950000005700010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d9403ede3eca2a72b3aecc820e955b36f38437d013950000005702030000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fae461ca67b15dc8dc81ce7615e0320da1a9ab8d5cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20101005701030000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2010100000000000000000000000000000000000000000000000000000000
|
||||
test_single_swap_strategy_encoder_unwrap:30ace1b10000000000000000000000000000000000000000000000a2a15d09519be000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f0000000000000000000000000000000000000000000000a2a15d09519be00000000000000000000000000000000000000000000000000000000000006880e4c300000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000068595ecb00000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000004164a080913bbb13ab52f3e16c867e5f18eec12c28e06af962797af2ef2eb67f734ea2929f3f5995eb6edb58e6ebf9e93ee4ec9b2bd79d3d72532136a05e8cabe11c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fa478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d0139501000000000000000000000000000000
|
||||
test_single_swap_strategy_encoder_wrap:30ace1b10000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000000000000000000000000059fb7d3830e6fc064b00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000000000006880e4c300000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000068595ecb00000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041f7c1be051b8991169d7947454366af484c4a4e6c2705a4e7a1ad6845024ca8ca30cfeba64faa38fa5aae609a297af1902c2992e010cb1252be052e71d3d06bb41c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200010000000000000000000000000000
|
||||
test_split_output_cyclic_swap:7c5538460000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005e703f4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000000000000000000000000000000000006880e4c300000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000068595ecb0000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000000411a1c6030e27a6b4767fa063ce5b3108122b60935ab51540e121876f3d01604642e25b2bb94b43e5e224e702ac6fb90f891f073af69bd68106ef6aa7c5c9c3b3f1b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000139005700010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48b4e16d0168e52d35cacd2c6185b44281ec28c9dc3ede3eca2a72b3aecc820e955b36f38437d013950100006e01009999992e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480001f4cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc288e6a0c2ddd26feeb64f039a2c41296fcb3f56400001006e01000000002e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000bb8cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc28ad599c3a0ff1de082011efddc58f1908eb6e6d8000100000000000000
|
||||
test_split_input_cyclic_swap:7c5538460000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005ef619b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000000000000000000000000000000000006880e4c300000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000068595ecb0000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000000411a1c6030e27a6b4767fa063ce5b3108122b60935ab51540e121876f3d01604642e25b2bb94b43e5e224e702ac6fb90f891f073af69bd68106ef6aa7c5c9c3b3f1b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000139006e00019999992e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20001f43ede3eca2a72b3aecc820e955b36f38437d0139588e6a0c2ddd26feeb64f039a2c41296fcb3f56400100006e00010000002e234dae75c793f67a35089c9d99245e1c58470ba0b86991c6218b36c1d19d4a2e9eb0ce3606eb48c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000bb83ede3eca2a72b3aecc820e955b36f38437d013958ad599c3a0ff1de082011efddc58f1908eb6e6d80100005701000000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2b4e16d0168e52d35cacd2c6185b44281ec28c9dccd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000100000000000000
|
||||
test_split_swap_strategy_encoder:7c5538460000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000018f61ec000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000000000006880e4c300000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000068595ecb00000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000004163bbe3be57a2bb85c5435cc94a715cf47a65c6b2ba072d4a8e41ee00fa9da27a51d95e9511582184f7ff85c5f9e5bbf3fc634174b11bb4df014ca08c77b5a14a1b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000164005700028000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d013950000005700010000005615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2bb2b8038a1640196fbe3e38816f3e67cba72d9403ede3eca2a72b3aecc820e955b36f38437d013950000005702030000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fae461ca67b15dc8dc81ce7615e0320da1a9ab8d5cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20101005701030000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f2260fac5e5542a773aa44fbcfedf7c193bc2c599004375dff511095cc5a197a54140a24efef3a416cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2010100000000000000000000000000000000000000000000000000000000
|
||||
test_uniswap_v3_curve:e21dd0d30000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000d600692e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599000bb83ede3eca2a72b3aecc820e955b36f38437d01395cbcdf9626bc03e24f779434178a73a0b4bad62ed000000691d1499e622d69689cdf9004d05ec547d650ff2112260fac5e5542a773aa44fbcfedf7c193bc2c599dac17f958d2ee523a2206206994597c13d831ec7d51a44d3fae010294c616388b506acda1bfaae460301000102cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000
|
||||
test_multi_protocol:51bcc7b600000000000000000000000000000000000000000000005150ae84a8cdf000000000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a2958f36da71a9200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000005150ae84a8cdf0000000000000000000000000000000000000000000000000000000000000686a405500000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006842ba5d00000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041c450ffd17649e61fb8e42524c36b4409cb8cc512fb25d01aa1018fe2c839283b046e1f386e72fc19bb9b4835fe2f7a37adf3f1764b8d38fd4bff72a7dc371c8c1c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000021400525615deb798bb3e4dfa0139dfa1b3d433cc23b72f6b175474e89094c44da98b954eedeac495271d0fa478c2975ab1ea89e8196811f51a7b7ade33eb113ede3eca2a72b3aecc820e955b36f38437d0139501000072c7183455a4c133ae270771860664b6b7ec320bb1c02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599a6f548df93de924d73be7d25dc02554c6bd66db500020000000000000000000e3ede3eca2a72b3aecc820e955b36f38437d01395010200691d1499e622d69689cdf9004d05ec547d650ff2112260fac5e5542a773aa44fbcfedf7c193bc2c599dac17f958d2ee523a2206206994597c13d831ec7d51a44d3fae010294c616388b506acda1bfaae4603010001023ede3eca2a72b3aecc820e955b36f38437d013950071a0cb889707d426a7a386870a03bc70d1b0697598013ede3eca2a72b3aecc820e955b36f38437d01395dac17f958d2ee523a2206206994597c13d831ec7a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000001a36e2eb1c43200000032006cf62849f9a0b5bf2913b396098f7c7019b51a820aa0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000001cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000bb800003c000000000000000000000000
|
||||
test_encode_balancer_v2:c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2ba100000625a3754423978a60c9317c58a424e3d5c6ee304399dbdb9c8ef030ab642b10820db8f560002000000000000000000141d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e0102
|
||||
@@ -32,4 +32,4 @@ test_encode_uniswap_v2:c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e
|
||||
test_encode_balancer_v3:7bc3485026ac48b6cf9baf0a377477fff5703af8c71ea051a5f82c67adcf634c36ffe6334793d24c85b2b559bc2d21104c4defdd6efca8a20343361d011d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e
|
||||
test_single_encoding_strategy_balancer_v3:5c4b639c0000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000097ffedb80d4b2ca6105a07a4d90eb739c45a66600000000000000000000000030881baa943777f92dc934d53d3bfdf33382cab300000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000006503a6a84cd762d9707a21605b548aaab891562aab097ffedb80d4b2ca6105a07a4d90eb739c45a66630881baa943777f92dc934d53d3bfdf33382cab3f028ac624074d6793c36dc8a06ecec0f5a39a71800cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000000000000000000000000000000000
|
||||
test_uniswap_v3_balancer_v3:e21dd0d3000000000000000000000000000000000000000000000000002386f26fc10000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000004a220e6096b25eadb88358cb44068a324825467500000000000000000000000000000000000000000000000000000000018f61ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000d200692e234dae75c793f67a35089c9d99245e1c58470bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc22260fac5e5542a773aa44fbcfedf7c193bc2c599000bb83ede3eca2a72b3aecc820e955b36f38437d01395cbcdf9626bc03e24f779434178a73a0b4bad62ed0000006503a6a84cd762d9707a21605b548aaab891562aab2260fac5e5542a773aa44fbcfedf7c193bc2c5994a220e6096b25eadb88358cb44068a3248254675571bea0e99e139cd0b6b7d9352ca872dfe0d72dd01cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc20000000000000000000000000000
|
||||
test_single_swap_strategy_encoder:30ace1b10000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000006d70b85442ed96492800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000686a405500000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d01395000000000000000000000000000000000000000000000000000000006842ba5d00000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000041328f1b72977c3d7dc15d43d58b8f6aa239c324010606ea31df41c7a526b7fed62a46fd97fe46d6da9652908684a0d63b3a2759a3076d6cfe8df35f4df5d0476a1b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000
|
||||
test_single_swap_strategy_encoder:30ace1b10000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000006b175474e89094c44da98b954eedeac495271d0f00000000000000000000000000000000000000000000006d70b85442ed96492800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000000000006880e4c300000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ede3eca2a72b3aecc820e955b36f38437d013950000000000000000000000000000000000000000000000000000000068595ecb00000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000004163bbe3be57a2bb85c5435cc94a715cf47a65c6b2ba072d4a8e41ee00fa9da27a51d95e9511582184f7ff85c5f9e5bbf3fc634174b11bb4df014ca08c77b5a14a1b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000525615deb798bb3e4dfa0139dfa1b3d433cc23b72fc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2a478c2975ab1ea89e8196811f51a7b7ade33eb11cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc200000000000000000000000000000000
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
// SPDX-License-Identifier: Unlicense
|
||||
pragma solidity ^0.8.26;
|
||||
|
||||
import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
|
||||
|
||||
contract MockERC20 is ERC20 {
|
||||
constructor(string memory name_, string memory symbol_)
|
||||
ERC20(name_, symbol_)
|
||||
{}
|
||||
|
||||
function mint(address to, uint256 amount) external {
|
||||
_mint(to, amount);
|
||||
}
|
||||
|
||||
function decimals() public view virtual override returns (uint8) {
|
||||
return 18;
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,10 @@
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
pragma solidity ^0.8.26;
|
||||
|
||||
import "../TychoRouterTestSetup.sol";
|
||||
import "@src/executors/CurveExecutor.sol";
|
||||
import {Test} from "../../lib/forge-std/src/Test.sol";
|
||||
import {Constants} from "../Constants.sol";
|
||||
import {Test} from "../../lib/forge-std/src/Test.sol";
|
||||
|
||||
interface ICurvePool {
|
||||
function coins(uint256 i) external view returns (address);
|
||||
@@ -393,3 +394,20 @@ contract CurveExecutorTest is Test, Constants {
|
||||
return (coinInIndex, coinOutIndex);
|
||||
}
|
||||
}
|
||||
|
||||
contract TychoRouterForBalancerV3Test is TychoRouterTestSetup {
|
||||
function testSingleCurveIntegration() public {
|
||||
deal(UWU_ADDR, ALICE, 1 ether);
|
||||
|
||||
vm.startPrank(ALICE);
|
||||
IERC20(UWU_ADDR).approve(tychoRouterAddr, type(uint256).max);
|
||||
bytes memory callData =
|
||||
loadCallDataFromFile("test_single_encoding_strategy_curve");
|
||||
(bool success,) = tychoRouterAddr.call(callData);
|
||||
|
||||
assertTrue(success, "Call Failed");
|
||||
assertEq(IERC20(WETH_ADDR).balanceOf(ALICE), 2877855391767);
|
||||
|
||||
vm.stopPrank();
|
||||
}
|
||||
}
|
||||
@@ -2,8 +2,9 @@
|
||||
pragma solidity ^0.8.26;
|
||||
|
||||
import "../TestUtils.sol";
|
||||
import {Constants} from "../Constants.sol";
|
||||
import "../TychoRouterTestSetup.sol";
|
||||
import "@src/executors/EkuboExecutor.sol";
|
||||
import {Constants} from "../Constants.sol";
|
||||
import {ICore} from "@ekubo/interfaces/ICore.sol";
|
||||
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
||||
import {NATIVE_TOKEN_ADDRESS} from "@ekubo/math/constants.sol";
|
||||
@@ -158,3 +159,24 @@ contract EkuboExecutorTest is Constants, TestUtils {
|
||||
multiHopSwap(loadCallDataFromFile("test_ekubo_encode_swap_multi"));
|
||||
}
|
||||
}
|
||||
|
||||
contract TychoRouterForBalancerV3Test is TychoRouterTestSetup {
|
||||
function testSingleEkuboIntegration() public {
|
||||
vm.stopPrank();
|
||||
|
||||
deal(ALICE, 1 ether);
|
||||
uint256 balanceBefore = IERC20(USDC_ADDR).balanceOf(ALICE);
|
||||
|
||||
// Approve permit2
|
||||
vm.startPrank(ALICE);
|
||||
bytes memory callData =
|
||||
loadCallDataFromFile("test_single_encoding_strategy_ekubo");
|
||||
(bool success,) = tychoRouterAddr.call{value: 1 ether}(callData);
|
||||
|
||||
uint256 balanceAfter = IERC20(USDC_ADDR).balanceOf(ALICE);
|
||||
|
||||
assertTrue(success, "Call Failed");
|
||||
assertGe(balanceAfter - balanceBefore, 26173932);
|
||||
assertEq(IERC20(WETH_ADDR).balanceOf(tychoRouterAddr), 0);
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,10 @@
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
pragma solidity ^0.8.26;
|
||||
|
||||
import "../TestUtils.sol";
|
||||
import "../TychoRouterTestSetup.sol";
|
||||
import "@src/executors/MaverickV2Executor.sol";
|
||||
import {Constants} from "../Constants.sol";
|
||||
import "../TestUtils.sol";
|
||||
|
||||
contract MaverickV2ExecutorExposed is MaverickV2Executor {
|
||||
constructor(address _factory, address _permit2)
|
||||
@@ -126,3 +127,23 @@ contract MaverickV2ExecutorTest is TestUtils, Constants {
|
||||
assertEq(balanceAfter - balanceBefore, amountOut);
|
||||
}
|
||||
}
|
||||
|
||||
contract TychoRouterForBalancerV3Test is TychoRouterTestSetup {
|
||||
function testSingleMaverickIntegration() public {
|
||||
deal(GHO_ADDR, ALICE, 1 ether);
|
||||
uint256 balanceBefore = IERC20(USDC_ADDR).balanceOf(ALICE);
|
||||
|
||||
vm.startPrank(ALICE);
|
||||
IERC20(GHO_ADDR).approve(tychoRouterAddr, type(uint256).max);
|
||||
|
||||
bytes memory callData =
|
||||
loadCallDataFromFile("test_single_encoding_strategy_maverick");
|
||||
(bool success,) = tychoRouterAddr.call(callData);
|
||||
|
||||
uint256 balanceAfter = IERC20(USDC_ADDR).balanceOf(ALICE);
|
||||
|
||||
assertTrue(success, "Call Failed");
|
||||
assertGe(balanceAfter - balanceBefore, 999725);
|
||||
assertEq(IERC20(WETH_ADDR).balanceOf(tychoRouterAddr), 0);
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,12 @@
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
pragma solidity ^0.8.26;
|
||||
|
||||
import "@src/executors/UniswapV3Executor.sol";
|
||||
import "../TychoRouterTestSetup.sol";
|
||||
import "@permit2/src/interfaces/IAllowanceTransfer.sol";
|
||||
import {Test} from "../../lib/forge-std/src/Test.sol";
|
||||
import "@src/executors/UniswapV3Executor.sol";
|
||||
import {Constants} from "../Constants.sol";
|
||||
import {Permit2TestHelper} from "../Permit2TestHelper.sol";
|
||||
import {Test} from "../../lib/forge-std/src/Test.sol";
|
||||
|
||||
contract UniswapV3ExecutorExposed is UniswapV3Executor {
|
||||
constructor(address _factory, bytes32 _initCode, address _permit2)
|
||||
@@ -43,7 +44,6 @@ contract UniswapV3ExecutorTest is Test, Constants, Permit2TestHelper {
|
||||
|
||||
UniswapV3ExecutorExposed uniswapV3Exposed;
|
||||
UniswapV3ExecutorExposed pancakeV3Exposed;
|
||||
IERC20 WETH = IERC20(WETH_ADDR);
|
||||
IERC20 DAI = IERC20(DAI_ADDR);
|
||||
IAllowanceTransfer permit2;
|
||||
|
||||
@@ -211,3 +211,50 @@ contract UniswapV3ExecutorTest is Test, Constants, Permit2TestHelper {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
contract TychoRouterForBalancerV3Test is TychoRouterTestSetup {
|
||||
function testSingleSwapUSV3Permit2() public {
|
||||
// Trade 1 WETH for DAI with 1 swap on Uniswap V3 using Permit2
|
||||
// Tests entire USV3 flow including callback
|
||||
// 1 WETH -> DAI
|
||||
// (USV3)
|
||||
vm.startPrank(ALICE);
|
||||
uint256 amountIn = 10 ** 18;
|
||||
deal(WETH_ADDR, ALICE, amountIn);
|
||||
(
|
||||
IAllowanceTransfer.PermitSingle memory permitSingle,
|
||||
bytes memory signature
|
||||
) = handlePermit2Approval(WETH_ADDR, tychoRouterAddr, amountIn);
|
||||
|
||||
uint256 expAmountOut = 1205_128428842122129186; //Swap 1 WETH for 1205.12 DAI
|
||||
bool zeroForOne = false;
|
||||
bytes memory protocolData = encodeUniswapV3Swap(
|
||||
WETH_ADDR,
|
||||
DAI_ADDR,
|
||||
ALICE,
|
||||
DAI_WETH_USV3,
|
||||
zeroForOne,
|
||||
RestrictTransferFrom.TransferType.TransferFrom
|
||||
);
|
||||
bytes memory swap =
|
||||
encodeSingleSwap(address(usv3Executor), protocolData);
|
||||
|
||||
tychoRouter.singleSwapPermit2(
|
||||
amountIn,
|
||||
WETH_ADDR,
|
||||
DAI_ADDR,
|
||||
expAmountOut - 1,
|
||||
false,
|
||||
false,
|
||||
ALICE,
|
||||
permitSingle,
|
||||
signature,
|
||||
swap
|
||||
);
|
||||
|
||||
uint256 finalBalance = IERC20(DAI_ADDR).balanceOf(ALICE);
|
||||
assertGe(finalBalance, expAmountOut);
|
||||
|
||||
vm.stopPrank();
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ pragma solidity ^0.8.26;
|
||||
|
||||
import "../../src/executors/UniswapV4Executor.sol";
|
||||
import "../TestUtils.sol";
|
||||
import "../TychoRouterTestSetup.sol";
|
||||
import "./UniswapV4Utils.sol";
|
||||
import "@src/executors/UniswapV4Executor.sol";
|
||||
import {Constants} from "../Constants.sol";
|
||||
@@ -211,3 +212,175 @@ contract UniswapV4ExecutorTest is Constants, TestUtils {
|
||||
assertTrue(IERC20(WBTC_ADDR).balanceOf(ALICE) == amountOut);
|
||||
}
|
||||
}
|
||||
|
||||
contract TychoRouterForBalancerV3Test is TychoRouterTestSetup {
|
||||
function testSingleSwapUSV4CallbackPermit2() public {
|
||||
vm.startPrank(ALICE);
|
||||
uint256 amountIn = 100 ether;
|
||||
deal(USDE_ADDR, ALICE, amountIn);
|
||||
(
|
||||
IAllowanceTransfer.PermitSingle memory permitSingle,
|
||||
bytes memory signature
|
||||
) = handlePermit2Approval(USDE_ADDR, tychoRouterAddr, amountIn);
|
||||
|
||||
UniswapV4Executor.UniswapV4Pool[] memory pools =
|
||||
new UniswapV4Executor.UniswapV4Pool[](1);
|
||||
pools[0] = UniswapV4Executor.UniswapV4Pool({
|
||||
intermediaryToken: USDT_ADDR,
|
||||
fee: uint24(100),
|
||||
tickSpacing: int24(1)
|
||||
});
|
||||
|
||||
bytes memory protocolData = UniswapV4Utils.encodeExactInput(
|
||||
USDE_ADDR,
|
||||
USDT_ADDR,
|
||||
true,
|
||||
RestrictTransferFrom.TransferType.TransferFrom,
|
||||
ALICE,
|
||||
pools
|
||||
);
|
||||
|
||||
bytes memory swap =
|
||||
encodeSingleSwap(address(usv4Executor), protocolData);
|
||||
|
||||
tychoRouter.singleSwapPermit2(
|
||||
amountIn,
|
||||
USDE_ADDR,
|
||||
USDT_ADDR,
|
||||
99943850,
|
||||
false,
|
||||
false,
|
||||
ALICE,
|
||||
permitSingle,
|
||||
signature,
|
||||
swap
|
||||
);
|
||||
|
||||
assertEq(IERC20(USDT_ADDR).balanceOf(ALICE), 99963618);
|
||||
vm.stopPrank();
|
||||
}
|
||||
|
||||
function testSplitSwapMultipleUSV4Callback() public {
|
||||
// This test has two uniswap v4 hops that will be executed inside of the V4 pool manager
|
||||
// USDE -> USDT -> WBTC
|
||||
uint256 amountIn = 100 ether;
|
||||
deal(USDE_ADDR, ALICE, amountIn);
|
||||
|
||||
UniswapV4Executor.UniswapV4Pool[] memory pools =
|
||||
new UniswapV4Executor.UniswapV4Pool[](2);
|
||||
pools[0] = UniswapV4Executor.UniswapV4Pool({
|
||||
intermediaryToken: USDT_ADDR,
|
||||
fee: uint24(100),
|
||||
tickSpacing: int24(1)
|
||||
});
|
||||
pools[1] = UniswapV4Executor.UniswapV4Pool({
|
||||
intermediaryToken: WBTC_ADDR,
|
||||
fee: uint24(3000),
|
||||
tickSpacing: int24(60)
|
||||
});
|
||||
|
||||
bytes memory protocolData = UniswapV4Utils.encodeExactInput(
|
||||
USDE_ADDR,
|
||||
WBTC_ADDR,
|
||||
true,
|
||||
RestrictTransferFrom.TransferType.TransferFrom,
|
||||
ALICE,
|
||||
pools
|
||||
);
|
||||
|
||||
bytes memory swap =
|
||||
encodeSingleSwap(address(usv4Executor), protocolData);
|
||||
|
||||
vm.startPrank(ALICE);
|
||||
IERC20(USDE_ADDR).approve(tychoRouterAddr, amountIn);
|
||||
tychoRouter.singleSwap(
|
||||
amountIn,
|
||||
USDE_ADDR,
|
||||
WBTC_ADDR,
|
||||
118280,
|
||||
false,
|
||||
false,
|
||||
ALICE,
|
||||
true,
|
||||
swap
|
||||
);
|
||||
|
||||
assertEq(IERC20(WBTC_ADDR).balanceOf(ALICE), 118281);
|
||||
}
|
||||
|
||||
function testSingleUSV4IntegrationGroupedSwap() public {
|
||||
// Test created with calldata from our router encoder.
|
||||
|
||||
// Performs a single swap from USDC to PEPE though ETH using two
|
||||
// consecutive USV4 pools. It's a single swap because it is a consecutive grouped swaps
|
||||
//
|
||||
// USDC ──(USV4)──> ETH ───(USV4)──> PEPE
|
||||
//
|
||||
deal(USDC_ADDR, ALICE, 1 ether);
|
||||
uint256 balanceBefore = IERC20(PEPE_ADDR).balanceOf(ALICE);
|
||||
|
||||
// Approve permit2
|
||||
vm.startPrank(ALICE);
|
||||
IERC20(USDC_ADDR).approve(PERMIT2_ADDRESS, type(uint256).max);
|
||||
bytes memory callData = loadCallDataFromFile(
|
||||
"test_single_encoding_strategy_usv4_grouped_swap"
|
||||
);
|
||||
(bool success,) = tychoRouterAddr.call(callData);
|
||||
|
||||
vm.stopPrank();
|
||||
|
||||
uint256 balanceAfter = IERC20(PEPE_ADDR).balanceOf(ALICE);
|
||||
|
||||
assertTrue(success, "Call Failed");
|
||||
assertEq(balanceAfter - balanceBefore, 123172000092711286554274694);
|
||||
}
|
||||
|
||||
function testSingleUSV4IntegrationInputETH() public {
|
||||
// Test created with calldata from our router encoder.
|
||||
|
||||
// Performs a single swap from ETH to PEPE without wrapping or unwrapping
|
||||
//
|
||||
// ETH ───(USV4)──> PEPE
|
||||
//
|
||||
deal(ALICE, 1 ether);
|
||||
uint256 balanceBefore = IERC20(PEPE_ADDR).balanceOf(ALICE);
|
||||
|
||||
bytes memory callData =
|
||||
loadCallDataFromFile("test_single_encoding_strategy_usv4_eth_in");
|
||||
(bool success,) = tychoRouterAddr.call{value: 1 ether}(callData);
|
||||
|
||||
vm.stopPrank();
|
||||
|
||||
uint256 balanceAfter = IERC20(PEPE_ADDR).balanceOf(ALICE);
|
||||
|
||||
assertTrue(success, "Call Failed");
|
||||
assertEq(balanceAfter - balanceBefore, 235610487387677804636755778);
|
||||
}
|
||||
|
||||
function testSingleUSV4IntegrationOutputETH() public {
|
||||
// Test created with calldata from our router encoder.
|
||||
|
||||
// Performs a single swap from USDC to ETH without wrapping or unwrapping
|
||||
//
|
||||
// USDC ───(USV4)──> ETH
|
||||
//
|
||||
deal(USDC_ADDR, ALICE, 3000_000000);
|
||||
uint256 balanceBefore = ALICE.balance;
|
||||
|
||||
// Approve permit2
|
||||
vm.startPrank(ALICE);
|
||||
IERC20(USDC_ADDR).approve(PERMIT2_ADDRESS, type(uint256).max);
|
||||
|
||||
bytes memory callData =
|
||||
loadCallDataFromFile("test_single_encoding_strategy_usv4_eth_out");
|
||||
(bool success,) = tychoRouterAddr.call(callData);
|
||||
|
||||
vm.stopPrank();
|
||||
|
||||
uint256 balanceAfter = ALICE.balance;
|
||||
|
||||
assertTrue(success, "Call Failed");
|
||||
console.logUint(balanceAfter - balanceBefore);
|
||||
assertEq(balanceAfter - balanceBefore, 1474406268748155809);
|
||||
}
|
||||
}
|
||||
@@ -92,9 +92,9 @@ impl StrategyEncoder for SingleSwapStrategyEncoder {
|
||||
|
||||
let (mut unwrap, mut wrap) = (false, false);
|
||||
if let Some(action) = &solution.native_action {
|
||||
match action {
|
||||
&NativeAction::Wrap => wrap = true,
|
||||
&NativeAction::Unwrap => unwrap = true,
|
||||
match *action {
|
||||
NativeAction::Wrap => wrap = true,
|
||||
NativeAction::Unwrap => unwrap = true,
|
||||
}
|
||||
}
|
||||
let protocol = &grouped_swap.protocol_system;
|
||||
@@ -255,7 +255,7 @@ impl StrategyEncoder for SequentialSwapStrategyEncoder {
|
||||
let transfer = self
|
||||
.transfer_optimization
|
||||
.get_transfers(
|
||||
&grouped_swap,
|
||||
grouped_swap,
|
||||
&solution.given_token,
|
||||
wrap,
|
||||
in_between_swap_optimization_allowed,
|
||||
@@ -410,9 +410,9 @@ impl StrategyEncoder for SplitSwapStrategyEncoder {
|
||||
|
||||
let (mut unwrap, mut wrap) = (false, false);
|
||||
if let Some(action) = &solution.native_action {
|
||||
match action {
|
||||
&NativeAction::Wrap => wrap = true,
|
||||
&NativeAction::Unwrap => unwrap = true,
|
||||
match *action {
|
||||
NativeAction::Wrap => wrap = true,
|
||||
NativeAction::Unwrap => unwrap = true,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -110,7 +110,7 @@ impl SwapEncoder for UniswapV3SwapEncoder {
|
||||
let zero_to_one = Self::get_zero_to_one(token_in_address, token_out_address);
|
||||
let component_id = Address::from_str(&swap.component.id)
|
||||
.map_err(|_| EncodingError::FatalError("Invalid USV3 component id".to_string()))?;
|
||||
let pool_fee_bytes = get_static_attribute(&swap, "fee")?;
|
||||
let pool_fee_bytes = get_static_attribute(swap, "fee")?;
|
||||
|
||||
let pool_fee_u24 = pad_to_fixed_size::<3>(&pool_fee_bytes)
|
||||
.map_err(|_| EncodingError::FatalError("Failed to extract fee bytes".to_string()))?;
|
||||
@@ -165,12 +165,12 @@ impl SwapEncoder for UniswapV4SwapEncoder {
|
||||
swap: &Swap,
|
||||
encoding_context: &EncodingContext,
|
||||
) -> Result<Vec<u8>, EncodingError> {
|
||||
let fee = get_static_attribute(&swap, "key_lp_fee")?;
|
||||
let fee = get_static_attribute(swap, "key_lp_fee")?;
|
||||
|
||||
let pool_fee_u24 = pad_to_fixed_size::<3>(&fee)
|
||||
.map_err(|_| EncodingError::FatalError("Failed to pad fee bytes".to_string()))?;
|
||||
|
||||
let tick_spacing = get_static_attribute(&swap, "tick_spacing")?;
|
||||
let tick_spacing = get_static_attribute(swap, "tick_spacing")?;
|
||||
|
||||
let pool_tick_spacing_u24 = pad_to_fixed_size::<3>(&tick_spacing).map_err(|_| {
|
||||
EncodingError::FatalError("Failed to pad tick spacing bytes".to_string())
|
||||
@@ -314,20 +314,20 @@ impl SwapEncoder for EkuboSwapEncoder {
|
||||
}
|
||||
|
||||
let fee = u64::from_be_bytes(
|
||||
get_static_attribute(&swap, "fee")?
|
||||
get_static_attribute(swap, "fee")?
|
||||
.try_into()
|
||||
.map_err(|_| EncodingError::FatalError("fee should be an u64".to_string()))?,
|
||||
);
|
||||
|
||||
let tick_spacing = u32::from_be_bytes(
|
||||
get_static_attribute(&swap, "tick_spacing")?
|
||||
get_static_attribute(swap, "tick_spacing")?
|
||||
.try_into()
|
||||
.map_err(|_| {
|
||||
EncodingError::FatalError("tick_spacing should be an u32".to_string())
|
||||
})?,
|
||||
);
|
||||
|
||||
let extension: Address = get_static_attribute(&swap, "extension")?
|
||||
let extension: Address = get_static_attribute(swap, "extension")?
|
||||
.as_slice()
|
||||
.try_into()
|
||||
.map_err(|_| EncodingError::FatalError("extension should be an address".to_string()))?;
|
||||
@@ -424,7 +424,7 @@ impl CurveSwapEncoder {
|
||||
token_in: Address,
|
||||
token_out: Address,
|
||||
) -> Result<(U8, U8), EncodingError> {
|
||||
let coins_bytes = get_static_attribute(&swap, "coins")?;
|
||||
let coins_bytes = get_static_attribute(swap, "coins")?;
|
||||
let coins: Vec<Address> = from_str(std::str::from_utf8(&coins_bytes)?)?;
|
||||
|
||||
let token_in = self.normalize_token(token_in, &coins)?;
|
||||
@@ -508,7 +508,7 @@ impl SwapEncoder for CurveSwapEncoder {
|
||||
approval_needed = true;
|
||||
}
|
||||
|
||||
let factory_bytes = get_static_attribute(&swap, "factory")?.to_vec();
|
||||
let factory_bytes = get_static_attribute(swap, "factory")?.to_vec();
|
||||
// the conversion to Address is necessary to checksum the address
|
||||
let factory_address =
|
||||
Address::from_str(std::str::from_utf8(&factory_bytes).map_err(|_| {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
278
tests/common/encoding.rs
Normal file
278
tests/common/encoding.rs
Normal file
@@ -0,0 +1,278 @@
|
||||
use std::str::FromStr;
|
||||
|
||||
use alloy::{
|
||||
primitives::{Address, Keccak256, U256},
|
||||
signers::{local::PrivateKeySigner, Signature, SignerSync},
|
||||
sol_types::{eip712_domain, SolStruct, SolValue},
|
||||
};
|
||||
use num_bigint::BigUint;
|
||||
use tycho_common::Bytes;
|
||||
use tycho_execution::encoding::{
|
||||
errors::EncodingError,
|
||||
evm::{
|
||||
approvals::permit2::PermitSingle,
|
||||
utils::{biguint_to_u256, bytes_to_address},
|
||||
},
|
||||
models,
|
||||
models::{EncodedSolution, NativeAction, Solution, Transaction, UserTransferType},
|
||||
};
|
||||
|
||||
/// Encodes a transaction for the Tycho Router using one of its supported swap methods.
|
||||
///
|
||||
/// # Overview
|
||||
///
|
||||
/// This function provides an **example implementation** of how to encode a call to the Tycho
|
||||
/// Router. It handles all currently supported swap selectors such as:
|
||||
/// - `singleSwap`
|
||||
/// - `singleSwapPermit2`
|
||||
/// - `sequentialSwap`
|
||||
/// - `sequentialSwapPermit2`
|
||||
/// - `splitSwap`
|
||||
/// - `splitSwapPermit2`
|
||||
///
|
||||
/// The encoding includes handling of native asset wrapping/unwrapping, permit2 support,
|
||||
/// and proper input argument formatting based on the function signature string.
|
||||
///
|
||||
/// # ⚠️ Important Responsibility Note
|
||||
///
|
||||
/// This function is intended as **an illustrative example only**. **Users must implement
|
||||
/// their own encoding logic** to ensure:
|
||||
/// - Full control of parameters passed to the router.
|
||||
/// - Proper validation and setting of critical inputs such as `minAmountOut`.
|
||||
/// - Signing of permit2 objects.
|
||||
///
|
||||
/// While Tycho is responsible for encoding the swap paths themselves, the input arguments
|
||||
/// to the router's methods act as **guardrails** for on-chain execution safety.
|
||||
/// Thus, the user must **take responsibility** for ensuring correctness of all input parameters,
|
||||
/// including `minAmountOut`, `receiver`, and permit2 logic.
|
||||
///
|
||||
/// # Min Amount Out
|
||||
///
|
||||
/// The `minAmountOut` calculation used here is just an example.
|
||||
/// You should ideally:
|
||||
/// - Query an external service (e.g., DEX aggregators, oracle, off-chain price feed).
|
||||
/// - Use your own strategy to determine an accurate and safe minimum acceptable output amount.
|
||||
///
|
||||
/// ⚠️ If `minAmountOut` is too low, your swap may be front-run or sandwiched, resulting in loss of
|
||||
/// funds.
|
||||
///
|
||||
/// # Parameters
|
||||
/// - `encoded_solution`: The solution already encoded by Tycho.
|
||||
/// - `solution`: The high-level solution including tokens, amounts, and receiver info.
|
||||
/// - `token_in_already_in_router`: Whether the input token is already present in the router.
|
||||
/// - `router_address`: The address of the Tycho Router contract.
|
||||
/// - `native_address`: The address used to represent the native token
|
||||
///
|
||||
/// # Returns
|
||||
/// A `Result<Transaction, EncodingError>` that either contains the full transaction data (to,
|
||||
/// value, data), or an error if the inputs are invalid.
|
||||
///
|
||||
/// # Errors
|
||||
/// - Returns `EncodingError::FatalError` if the function signature is unsupported or required
|
||||
/// fields (e.g., permit or signature) are missing.
|
||||
pub fn encode_tycho_router_call(
|
||||
chain_id: u64,
|
||||
encoded_solution: EncodedSolution,
|
||||
solution: &Solution,
|
||||
user_transfer_type: UserTransferType,
|
||||
native_address: Bytes,
|
||||
signer: Option<PrivateKeySigner>,
|
||||
) -> Result<Transaction, EncodingError> {
|
||||
let (mut unwrap, mut wrap) = (false, false);
|
||||
if let Some(action) = solution.native_action.clone() {
|
||||
match action {
|
||||
NativeAction::Wrap => wrap = true,
|
||||
NativeAction::Unwrap => unwrap = true,
|
||||
}
|
||||
}
|
||||
|
||||
let given_amount = biguint_to_u256(&solution.given_amount);
|
||||
let min_amount_out = biguint_to_u256(&solution.checked_amount);
|
||||
let given_token = bytes_to_address(&solution.given_token)?;
|
||||
let checked_token = bytes_to_address(&solution.checked_token)?;
|
||||
let receiver = bytes_to_address(&solution.receiver)?;
|
||||
let n_tokens = U256::from(encoded_solution.n_tokens);
|
||||
let (permit, signature) = if let Some(p) = encoded_solution.permit {
|
||||
let permit = Some(
|
||||
PermitSingle::try_from(&p)
|
||||
.map_err(|_| EncodingError::InvalidInput("Invalid permit".to_string()))?,
|
||||
);
|
||||
let signer = signer
|
||||
.ok_or(EncodingError::FatalError("Signer must be set to use permit2".to_string()))?;
|
||||
let signature = sign_permit(chain_id, &p, signer)?;
|
||||
(permit, signature.as_bytes().to_vec())
|
||||
} else {
|
||||
(None, vec![])
|
||||
};
|
||||
|
||||
let method_calldata = if encoded_solution
|
||||
.function_signature
|
||||
.contains("singleSwapPermit2")
|
||||
{
|
||||
(
|
||||
given_amount,
|
||||
given_token,
|
||||
checked_token,
|
||||
min_amount_out,
|
||||
wrap,
|
||||
unwrap,
|
||||
receiver,
|
||||
permit.ok_or(EncodingError::FatalError(
|
||||
"permit2 object must be set to use permit2".to_string(),
|
||||
))?,
|
||||
signature,
|
||||
encoded_solution.swaps,
|
||||
)
|
||||
.abi_encode()
|
||||
} else if encoded_solution
|
||||
.function_signature
|
||||
.contains("singleSwap")
|
||||
{
|
||||
(
|
||||
given_amount,
|
||||
given_token,
|
||||
checked_token,
|
||||
min_amount_out,
|
||||
wrap,
|
||||
unwrap,
|
||||
receiver,
|
||||
user_transfer_type == UserTransferType::TransferFrom,
|
||||
encoded_solution.swaps,
|
||||
)
|
||||
.abi_encode()
|
||||
} else if encoded_solution
|
||||
.function_signature
|
||||
.contains("sequentialSwapPermit2")
|
||||
{
|
||||
(
|
||||
given_amount,
|
||||
given_token,
|
||||
checked_token,
|
||||
min_amount_out,
|
||||
wrap,
|
||||
unwrap,
|
||||
receiver,
|
||||
permit.ok_or(EncodingError::FatalError(
|
||||
"permit2 object must be set to use permit2".to_string(),
|
||||
))?,
|
||||
signature,
|
||||
encoded_solution.swaps,
|
||||
)
|
||||
.abi_encode()
|
||||
} else if encoded_solution
|
||||
.function_signature
|
||||
.contains("sequentialSwap")
|
||||
{
|
||||
(
|
||||
given_amount,
|
||||
given_token,
|
||||
checked_token,
|
||||
min_amount_out,
|
||||
wrap,
|
||||
unwrap,
|
||||
receiver,
|
||||
user_transfer_type == UserTransferType::TransferFrom,
|
||||
encoded_solution.swaps,
|
||||
)
|
||||
.abi_encode()
|
||||
} else if encoded_solution
|
||||
.function_signature
|
||||
.contains("splitSwapPermit2")
|
||||
{
|
||||
(
|
||||
given_amount,
|
||||
given_token,
|
||||
checked_token,
|
||||
min_amount_out,
|
||||
wrap,
|
||||
unwrap,
|
||||
n_tokens,
|
||||
receiver,
|
||||
permit.ok_or(EncodingError::FatalError(
|
||||
"permit2 object must be set to use permit2".to_string(),
|
||||
))?,
|
||||
signature,
|
||||
encoded_solution.swaps,
|
||||
)
|
||||
.abi_encode()
|
||||
} else if encoded_solution
|
||||
.function_signature
|
||||
.contains("splitSwap")
|
||||
{
|
||||
(
|
||||
given_amount,
|
||||
given_token,
|
||||
checked_token,
|
||||
min_amount_out,
|
||||
wrap,
|
||||
unwrap,
|
||||
n_tokens,
|
||||
receiver,
|
||||
user_transfer_type == UserTransferType::TransferFrom,
|
||||
encoded_solution.swaps,
|
||||
)
|
||||
.abi_encode()
|
||||
} else {
|
||||
Err(EncodingError::FatalError("Invalid function signature for Tycho router".to_string()))?
|
||||
};
|
||||
|
||||
let contract_interaction = encode_input(&encoded_solution.function_signature, method_calldata);
|
||||
let value = if solution.given_token == native_address {
|
||||
solution.given_amount.clone()
|
||||
} else {
|
||||
BigUint::ZERO
|
||||
};
|
||||
Ok(Transaction { to: encoded_solution.interacting_with, value, data: contract_interaction })
|
||||
}
|
||||
|
||||
/// Signs a Permit2 `PermitSingle` struct using the EIP-712 signing scheme.
|
||||
///
|
||||
/// This function constructs an EIP-712 domain specific to the Permit2 contract and computes the
|
||||
/// hash of the provided `PermitSingle`. It then uses the given `PrivateKeySigner` to produce
|
||||
/// a cryptographic signature of the permit.
|
||||
///
|
||||
/// # Warning
|
||||
/// This is only an **example implementation** provided for reference purposes.
|
||||
/// **Do not rely on this in production.** You should implement your own version.
|
||||
fn sign_permit(
|
||||
chain_id: u64,
|
||||
permit_single: &models::PermitSingle,
|
||||
signer: PrivateKeySigner,
|
||||
) -> Result<Signature, EncodingError> {
|
||||
let permit2_address = Address::from_str("0x000000000022D473030F116dDEE9F6B43aC78BA3")
|
||||
.map_err(|_| EncodingError::FatalError("Permit2 address not valid".to_string()))?;
|
||||
let domain = eip712_domain! {
|
||||
name: "Permit2",
|
||||
chain_id: chain_id,
|
||||
verifying_contract: permit2_address,
|
||||
};
|
||||
let permit_single: PermitSingle = PermitSingle::try_from(permit_single)?;
|
||||
let hash = permit_single.eip712_signing_hash(&domain);
|
||||
signer
|
||||
.sign_hash_sync(&hash)
|
||||
.map_err(|e| {
|
||||
EncodingError::FatalError(format!("Failed to sign permit2 approval with error: {e}"))
|
||||
})
|
||||
}
|
||||
|
||||
/// Encodes the input data for a function call to the given function selector.
|
||||
fn encode_input(selector: &str, mut encoded_args: Vec<u8>) -> Vec<u8> {
|
||||
let mut hasher = Keccak256::new();
|
||||
hasher.update(selector.as_bytes());
|
||||
let selector_bytes = &hasher.finalize()[..4];
|
||||
let mut call_data = selector_bytes.to_vec();
|
||||
// Remove extra prefix if present (32 bytes for dynamic data)
|
||||
// Alloy encoding is including a prefix for dynamic data indicating the offset or length
|
||||
// but at this point we don't want that
|
||||
if encoded_args.len() > 32 &&
|
||||
encoded_args[..32] ==
|
||||
[0u8; 31]
|
||||
.into_iter()
|
||||
.chain([32].to_vec())
|
||||
.collect::<Vec<u8>>()
|
||||
{
|
||||
encoded_args = encoded_args[32..].to_vec();
|
||||
}
|
||||
call_data.extend(encoded_args);
|
||||
call_data
|
||||
}
|
||||
63
tests/common/mod.rs
Normal file
63
tests/common/mod.rs
Normal file
@@ -0,0 +1,63 @@
|
||||
#![allow(dead_code)]
|
||||
pub mod encoding;
|
||||
|
||||
use std::str::FromStr;
|
||||
|
||||
use alloy::{primitives::B256, signers::local::PrivateKeySigner};
|
||||
use tycho_common::{models::Chain as TychoCommonChain, Bytes};
|
||||
use tycho_execution::encoding::{
|
||||
evm::encoder_builders::TychoRouterEncoderBuilder,
|
||||
models::{Chain, UserTransferType},
|
||||
tycho_encoder::TychoEncoder,
|
||||
};
|
||||
|
||||
pub fn router_address() -> Bytes {
|
||||
Bytes::from_str("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395").unwrap()
|
||||
}
|
||||
|
||||
pub fn eth_chain() -> Chain {
|
||||
TychoCommonChain::Ethereum.into()
|
||||
}
|
||||
|
||||
pub fn eth() -> Bytes {
|
||||
Bytes::from_str("0x0000000000000000000000000000000000000000").unwrap()
|
||||
}
|
||||
|
||||
pub fn weth() -> Bytes {
|
||||
Bytes::from_str("0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2").unwrap()
|
||||
}
|
||||
|
||||
pub fn usdc() -> Bytes {
|
||||
Bytes::from_str("0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48").unwrap()
|
||||
}
|
||||
|
||||
pub fn dai() -> Bytes {
|
||||
Bytes::from_str("0x6b175474e89094c44da98b954eedeac495271d0f").unwrap()
|
||||
}
|
||||
|
||||
pub fn wbtc() -> Bytes {
|
||||
Bytes::from_str("0x2260fac5e5542a773aa44fbcfedf7c193bc2c599").unwrap()
|
||||
}
|
||||
|
||||
pub fn pepe() -> Bytes {
|
||||
Bytes::from_str("0x6982508145454Ce325dDbE47a25d4ec3d2311933").unwrap()
|
||||
}
|
||||
|
||||
pub fn get_signer() -> PrivateKeySigner {
|
||||
// Set up a mock private key for signing (Alice's pk in our contract tests)
|
||||
let private_key =
|
||||
"0x123456789abcdef123456789abcdef123456789abcdef123456789abcdef1234".to_string();
|
||||
|
||||
let pk = B256::from_str(&private_key).unwrap();
|
||||
PrivateKeySigner::from_bytes(&pk).unwrap()
|
||||
}
|
||||
|
||||
pub fn get_tycho_router_encoder(user_transfer_type: UserTransferType) -> Box<dyn TychoEncoder> {
|
||||
TychoRouterEncoderBuilder::new()
|
||||
.chain(tycho_common::models::Chain::Ethereum)
|
||||
.user_transfer_type(user_transfer_type)
|
||||
.executors_file_path("config/test_executor_addresses.json".to_string())
|
||||
.router_address(router_address())
|
||||
.build()
|
||||
.expect("Failed to build encoder")
|
||||
}
|
||||
574
tests/protocol_integration_tests.rs
Normal file
574
tests/protocol_integration_tests.rs
Normal file
@@ -0,0 +1,574 @@
|
||||
mod common;
|
||||
use std::{collections::HashMap, str::FromStr};
|
||||
|
||||
use alloy::hex::encode;
|
||||
use num_bigint::{BigInt, BigUint};
|
||||
use tycho_common::{models::protocol::ProtocolComponent, Bytes};
|
||||
use tycho_execution::encoding::{
|
||||
evm::utils::write_calldata_to_file,
|
||||
models::{Solution, Swap, UserTransferType},
|
||||
};
|
||||
|
||||
use crate::common::{
|
||||
encoding::encode_tycho_router_call, eth, eth_chain, get_signer, get_tycho_router_encoder, pepe,
|
||||
usdc, weth,
|
||||
};
|
||||
#[test]
|
||||
fn test_single_encoding_strategy_ekubo() {
|
||||
// ETH ──(EKUBO)──> USDC
|
||||
|
||||
let token_in = eth();
|
||||
let token_out = usdc(); // USDC
|
||||
|
||||
let static_attributes = HashMap::from([
|
||||
("fee".to_string(), Bytes::from(0_u64)),
|
||||
("tick_spacing".to_string(), Bytes::from(0_u32)),
|
||||
("extension".to_string(), Bytes::from("0x51d02a5948496a67827242eabc5725531342527c")), /* Oracle */
|
||||
]);
|
||||
|
||||
let component = ProtocolComponent {
|
||||
// All Ekubo swaps go through the core contract - not necessary to specify pool
|
||||
// id for test
|
||||
protocol_system: "ekubo_v2".to_string(),
|
||||
static_attributes,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let swap = Swap {
|
||||
component,
|
||||
token_in: token_in.clone(),
|
||||
token_out: token_out.clone(),
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
};
|
||||
|
||||
let encoder = get_tycho_router_encoder(UserTransferType::TransferFrom);
|
||||
|
||||
let solution = Solution {
|
||||
exact_out: false,
|
||||
given_token: token_in,
|
||||
given_amount: BigUint::from_str("1_000000000000000000").unwrap(),
|
||||
checked_token: token_out,
|
||||
checked_amount: BigUint::from_str("1000").unwrap(),
|
||||
// Alice
|
||||
sender: Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(),
|
||||
receiver: Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(),
|
||||
swaps: vec![swap],
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let encoded_solution = encoder
|
||||
.encode_solutions(vec![solution.clone()])
|
||||
.unwrap()[0]
|
||||
.clone();
|
||||
|
||||
let calldata = encode_tycho_router_call(
|
||||
eth_chain().id,
|
||||
encoded_solution,
|
||||
&solution,
|
||||
UserTransferType::TransferFrom,
|
||||
eth(),
|
||||
None,
|
||||
)
|
||||
.unwrap()
|
||||
.data;
|
||||
let hex_calldata = encode(&calldata);
|
||||
write_calldata_to_file("test_single_encoding_strategy_ekubo", hex_calldata.as_str());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_single_encoding_strategy_maverick() {
|
||||
// GHO -> (maverick) -> USDC
|
||||
let maverick_pool = ProtocolComponent {
|
||||
id: String::from("0x14Cf6D2Fe3E1B326114b07d22A6F6bb59e346c67"),
|
||||
protocol_system: String::from("vm:maverick_v2"),
|
||||
..Default::default()
|
||||
};
|
||||
let token_in = Bytes::from("0x40D16FC0246aD3160Ccc09B8D0D3A2cD28aE6C2f");
|
||||
let token_out = usdc();
|
||||
let swap = Swap {
|
||||
component: maverick_pool,
|
||||
token_in: token_in.clone(),
|
||||
token_out: token_out.clone(),
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
};
|
||||
|
||||
let encoder = get_tycho_router_encoder(UserTransferType::TransferFrom);
|
||||
|
||||
let solution = Solution {
|
||||
exact_out: false,
|
||||
given_token: token_in,
|
||||
given_amount: BigUint::from_str("1_000000000000000000").unwrap(),
|
||||
checked_token: token_out,
|
||||
checked_amount: BigUint::from_str("1000").unwrap(),
|
||||
// Alice
|
||||
sender: Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(),
|
||||
receiver: Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(),
|
||||
swaps: vec![swap],
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let encoded_solution = encoder
|
||||
.encode_solutions(vec![solution.clone()])
|
||||
.unwrap()[0]
|
||||
.clone();
|
||||
|
||||
let calldata = encode_tycho_router_call(
|
||||
eth_chain().id,
|
||||
encoded_solution,
|
||||
&solution,
|
||||
UserTransferType::TransferFrom,
|
||||
eth(),
|
||||
None,
|
||||
)
|
||||
.unwrap()
|
||||
.data;
|
||||
let hex_calldata = encode(&calldata);
|
||||
write_calldata_to_file("test_single_encoding_strategy_maverick", hex_calldata.as_str());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_single_encoding_strategy_usv4_eth_in() {
|
||||
// Performs a single swap from ETH to PEPE using a USV4 pool
|
||||
// Note: This test does not assert anything. It is only used to obtain integration
|
||||
// test data for our router solidity test.
|
||||
//
|
||||
// ETH ───(USV4)──> PEPE
|
||||
//
|
||||
let eth = eth();
|
||||
let pepe = pepe();
|
||||
|
||||
let pool_fee_eth_pepe = Bytes::from(BigInt::from(25000).to_signed_bytes_be());
|
||||
let tick_spacing_eth_pepe = Bytes::from(BigInt::from(500).to_signed_bytes_be());
|
||||
let mut static_attributes_eth_pepe: HashMap<String, Bytes> = HashMap::new();
|
||||
static_attributes_eth_pepe.insert("key_lp_fee".into(), pool_fee_eth_pepe);
|
||||
static_attributes_eth_pepe.insert("tick_spacing".into(), tick_spacing_eth_pepe);
|
||||
|
||||
let swap_eth_pepe = Swap {
|
||||
component: ProtocolComponent {
|
||||
id: "0xecd73ecbf77219f21f129c8836d5d686bbc27d264742ddad620500e3e548e2c9".to_string(),
|
||||
protocol_system: "uniswap_v4".to_string(),
|
||||
static_attributes: static_attributes_eth_pepe,
|
||||
..Default::default()
|
||||
},
|
||||
token_in: eth.clone(),
|
||||
token_out: pepe.clone(),
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
};
|
||||
let encoder = get_tycho_router_encoder(UserTransferType::TransferFromPermit2);
|
||||
|
||||
let solution = Solution {
|
||||
exact_out: false,
|
||||
given_token: eth.clone(),
|
||||
given_amount: BigUint::from_str("1_000000000000000000").unwrap(),
|
||||
checked_token: pepe,
|
||||
checked_amount: BigUint::from_str("152373460199848577067005852").unwrap(),
|
||||
sender: Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(),
|
||||
receiver: Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(),
|
||||
swaps: vec![swap_eth_pepe],
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let encoded_solution = encoder
|
||||
.encode_solutions(vec![solution.clone()])
|
||||
.unwrap()[0]
|
||||
.clone();
|
||||
|
||||
let calldata = encode_tycho_router_call(
|
||||
eth_chain().id,
|
||||
encoded_solution,
|
||||
&solution,
|
||||
UserTransferType::TransferFromPermit2,
|
||||
eth,
|
||||
Some(get_signer()),
|
||||
)
|
||||
.unwrap()
|
||||
.data;
|
||||
let hex_calldata = encode(&calldata);
|
||||
|
||||
write_calldata_to_file("test_single_encoding_strategy_usv4_eth_in", hex_calldata.as_str());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_single_encoding_strategy_usv4_eth_out() {
|
||||
// Performs a single swap from USDC to ETH using a USV4 pool
|
||||
// Note: This test does not assert anything. It is only used to obtain integration
|
||||
// test data for our router solidity test.
|
||||
//
|
||||
// USDC ───(USV4)──> ETH
|
||||
//
|
||||
let eth = eth();
|
||||
let usdc = usdc();
|
||||
|
||||
// Fee and tick spacing information for this test is obtained by querying the
|
||||
// USV4 Position Manager contract: 0xbd216513d74c8cf14cf4747e6aaa6420ff64ee9e
|
||||
// Using the poolKeys function with the first 25 bytes of the pool id
|
||||
let pool_fee_usdc_eth = Bytes::from(BigInt::from(3000).to_signed_bytes_be());
|
||||
let tick_spacing_usdc_eth = Bytes::from(BigInt::from(60).to_signed_bytes_be());
|
||||
let mut static_attributes_usdc_eth: HashMap<String, Bytes> = HashMap::new();
|
||||
static_attributes_usdc_eth.insert("key_lp_fee".into(), pool_fee_usdc_eth);
|
||||
static_attributes_usdc_eth.insert("tick_spacing".into(), tick_spacing_usdc_eth);
|
||||
|
||||
let swap_usdc_eth = Swap {
|
||||
component: ProtocolComponent {
|
||||
id: "0xdce6394339af00981949f5f3baf27e3610c76326a700af57e4b3e3ae4977f78d".to_string(),
|
||||
protocol_system: "uniswap_v4".to_string(),
|
||||
static_attributes: static_attributes_usdc_eth,
|
||||
..Default::default()
|
||||
},
|
||||
token_in: usdc.clone(),
|
||||
token_out: eth.clone(),
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
};
|
||||
|
||||
let encoder = get_tycho_router_encoder(UserTransferType::TransferFromPermit2);
|
||||
|
||||
let solution = Solution {
|
||||
exact_out: false,
|
||||
given_token: usdc,
|
||||
given_amount: BigUint::from_str("3000_000000").unwrap(),
|
||||
checked_token: eth.clone(),
|
||||
checked_amount: BigUint::from_str("1117254495486192350").unwrap(),
|
||||
sender: Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(),
|
||||
receiver: Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(),
|
||||
swaps: vec![swap_usdc_eth],
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let encoded_solution = encoder
|
||||
.encode_solutions(vec![solution.clone()])
|
||||
.unwrap()[0]
|
||||
.clone();
|
||||
|
||||
let calldata = encode_tycho_router_call(
|
||||
eth_chain().id,
|
||||
encoded_solution,
|
||||
&solution,
|
||||
UserTransferType::TransferFromPermit2,
|
||||
eth,
|
||||
Some(get_signer()),
|
||||
)
|
||||
.unwrap()
|
||||
.data;
|
||||
|
||||
let hex_calldata = encode(&calldata);
|
||||
write_calldata_to_file("test_single_encoding_strategy_usv4_eth_out", hex_calldata.as_str());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_single_encoding_strategy_usv4_grouped_swap() {
|
||||
// Performs a sequential swap from USDC to PEPE though ETH using two consecutive
|
||||
// USV4 pools
|
||||
//
|
||||
// USDC ──(USV4)──> ETH ───(USV4)──> PEPE
|
||||
//
|
||||
|
||||
let eth = eth();
|
||||
let usdc = usdc();
|
||||
let pepe = pepe();
|
||||
|
||||
// Fee and tick spacing information for this test is obtained by querying the
|
||||
// USV4 Position Manager contract: 0xbd216513d74c8cf14cf4747e6aaa6420ff64ee9e
|
||||
// Using the poolKeys function with the first 25 bytes of the pool id
|
||||
let pool_fee_usdc_eth = Bytes::from(BigInt::from(3000).to_signed_bytes_be());
|
||||
let tick_spacing_usdc_eth = Bytes::from(BigInt::from(60).to_signed_bytes_be());
|
||||
let mut static_attributes_usdc_eth: HashMap<String, Bytes> = HashMap::new();
|
||||
static_attributes_usdc_eth.insert("key_lp_fee".into(), pool_fee_usdc_eth);
|
||||
static_attributes_usdc_eth.insert("tick_spacing".into(), tick_spacing_usdc_eth);
|
||||
|
||||
let pool_fee_eth_pepe = Bytes::from(BigInt::from(25000).to_signed_bytes_be());
|
||||
let tick_spacing_eth_pepe = Bytes::from(BigInt::from(500).to_signed_bytes_be());
|
||||
let mut static_attributes_eth_pepe: HashMap<String, Bytes> = HashMap::new();
|
||||
static_attributes_eth_pepe.insert("key_lp_fee".into(), pool_fee_eth_pepe);
|
||||
static_attributes_eth_pepe.insert("tick_spacing".into(), tick_spacing_eth_pepe);
|
||||
|
||||
let swap_usdc_eth = Swap {
|
||||
component: ProtocolComponent {
|
||||
id: "0xdce6394339af00981949f5f3baf27e3610c76326a700af57e4b3e3ae4977f78d".to_string(),
|
||||
protocol_system: "uniswap_v4".to_string(),
|
||||
static_attributes: static_attributes_usdc_eth,
|
||||
..Default::default()
|
||||
},
|
||||
token_in: usdc.clone(),
|
||||
token_out: eth.clone(),
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
};
|
||||
|
||||
let swap_eth_pepe = Swap {
|
||||
component: ProtocolComponent {
|
||||
id: "0xecd73ecbf77219f21f129c8836d5d686bbc27d264742ddad620500e3e548e2c9".to_string(),
|
||||
protocol_system: "uniswap_v4".to_string(),
|
||||
static_attributes: static_attributes_eth_pepe,
|
||||
..Default::default()
|
||||
},
|
||||
token_in: eth.clone(),
|
||||
token_out: pepe.clone(),
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
};
|
||||
let encoder = get_tycho_router_encoder(UserTransferType::TransferFromPermit2);
|
||||
|
||||
let solution = Solution {
|
||||
exact_out: false,
|
||||
given_token: usdc,
|
||||
given_amount: BigUint::from_str("1000_000000").unwrap(),
|
||||
checked_token: pepe,
|
||||
checked_amount: BigUint::from_str("97191013220606467325121599").unwrap(),
|
||||
sender: Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(),
|
||||
receiver: Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(),
|
||||
swaps: vec![swap_usdc_eth, swap_eth_pepe],
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let encoded_solution = encoder
|
||||
.encode_solutions(vec![solution.clone()])
|
||||
.unwrap()[0]
|
||||
.clone();
|
||||
|
||||
let calldata = encode_tycho_router_call(
|
||||
eth_chain().id,
|
||||
encoded_solution,
|
||||
&solution,
|
||||
UserTransferType::TransferFromPermit2,
|
||||
eth,
|
||||
Some(get_signer()),
|
||||
)
|
||||
.unwrap()
|
||||
.data;
|
||||
|
||||
let expected_input = [
|
||||
"30ace1b1", // Function selector (single swap)
|
||||
"000000000000000000000000000000000000000000000000000000003b9aca00", // amount in
|
||||
"000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // token in
|
||||
"0000000000000000000000006982508145454ce325ddbe47a25d4ec3d2311933", // token out
|
||||
"0000000000000000000000000000000000000000005064ff624d54346285543f", // min amount out
|
||||
"0000000000000000000000000000000000000000000000000000000000000000", // wrap
|
||||
"0000000000000000000000000000000000000000000000000000000000000000", // unwrap
|
||||
"000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver
|
||||
]
|
||||
.join("");
|
||||
|
||||
// after this there is the permit and because of the deadlines (that depend on block
|
||||
// time) it's hard to assert
|
||||
|
||||
let expected_swaps = String::from(concat!(
|
||||
// length of ple encoded swaps without padding
|
||||
"0000000000000000000000000000000000000000000000000000000000000086",
|
||||
// Swap data header
|
||||
"f62849f9a0b5bf2913b396098f7c7019b51a820a", // executor address
|
||||
// Protocol data
|
||||
"a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // group token in
|
||||
"6982508145454ce325ddbe47a25d4ec3d2311933", // group token in
|
||||
"00", // zero2one
|
||||
"00", // transfer type TransferFrom
|
||||
"cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver
|
||||
// First pool params
|
||||
"0000000000000000000000000000000000000000", // intermediary token (ETH)
|
||||
"000bb8", // fee
|
||||
"00003c", // tick spacing
|
||||
// Second pool params
|
||||
"6982508145454ce325ddbe47a25d4ec3d2311933", // intermediary token (PEPE)
|
||||
"0061a8", // fee
|
||||
"0001f4", // tick spacing
|
||||
"0000000000000000000000000000000000000000000000000000" // padding
|
||||
));
|
||||
|
||||
let hex_calldata = encode(&calldata);
|
||||
|
||||
assert_eq!(hex_calldata[..456], expected_input);
|
||||
assert_eq!(hex_calldata[1224..], expected_swaps);
|
||||
write_calldata_to_file(
|
||||
"test_single_encoding_strategy_usv4_grouped_swap",
|
||||
hex_calldata.as_str(),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_single_encoding_strategy_curve() {
|
||||
// UWU ──(curve 2 crypto pool)──> WETH
|
||||
|
||||
let token_in = Bytes::from("0x55C08ca52497e2f1534B59E2917BF524D4765257"); // UWU
|
||||
let token_out = weth();
|
||||
|
||||
let static_attributes = HashMap::from([(
|
||||
"factory".to_string(),
|
||||
Bytes::from(
|
||||
"0x98ee851a00abee0d95d08cf4ca2bdce32aeaaf7f"
|
||||
.as_bytes()
|
||||
.to_vec(),
|
||||
)),
|
||||
("coins".to_string(), Bytes::from_str("0x5b22307863303261616133396232323366653864306130653563346632376561643930383363373536636332222c22307835356330386361353234393765326631353334623539653239313762663532346434373635323537225d").unwrap()),
|
||||
]);
|
||||
|
||||
let component = ProtocolComponent {
|
||||
id: String::from("0x77146B0a1d08B6844376dF6d9da99bA7F1b19e71"),
|
||||
protocol_system: String::from("vm:curve"),
|
||||
static_attributes,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let swap = Swap {
|
||||
component,
|
||||
token_in: token_in.clone(),
|
||||
token_out: token_out.clone(),
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
};
|
||||
|
||||
let encoder = get_tycho_router_encoder(UserTransferType::TransferFrom);
|
||||
|
||||
let solution = Solution {
|
||||
exact_out: false,
|
||||
given_token: token_in,
|
||||
given_amount: BigUint::from_str("1_000000000000000000").unwrap(),
|
||||
checked_token: token_out,
|
||||
checked_amount: BigUint::from_str("1").unwrap(),
|
||||
// Alice
|
||||
sender: Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(),
|
||||
receiver: Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(),
|
||||
swaps: vec![swap],
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let encoded_solution = encoder
|
||||
.encode_solutions(vec![solution.clone()])
|
||||
.unwrap()[0]
|
||||
.clone();
|
||||
|
||||
let calldata = encode_tycho_router_call(
|
||||
eth_chain().id,
|
||||
encoded_solution,
|
||||
&solution,
|
||||
UserTransferType::TransferFrom,
|
||||
eth(),
|
||||
None,
|
||||
)
|
||||
.unwrap()
|
||||
.data;
|
||||
|
||||
let hex_calldata = encode(&calldata);
|
||||
write_calldata_to_file("test_single_encoding_strategy_curve", hex_calldata.as_str());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_single_encoding_strategy_curve_st_eth() {
|
||||
// ETH ──(curve stETH pool)──> STETH
|
||||
|
||||
let token_in = eth();
|
||||
let token_out = Bytes::from("0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84"); // STETH
|
||||
|
||||
let static_attributes = HashMap::from([(
|
||||
"factory".to_string(),
|
||||
Bytes::from(
|
||||
"0x0000000000000000000000000000000000000000"
|
||||
.as_bytes()
|
||||
.to_vec(),
|
||||
),
|
||||
),
|
||||
("coins".to_string(), Bytes::from_str("0x5b22307865656565656565656565656565656565656565656565656565656565656565656565656565656565222c22307861653761623936353230646533613138653565313131623565616162303935333132643766653834225d").unwrap()),]);
|
||||
|
||||
let component = ProtocolComponent {
|
||||
id: String::from("0xDC24316b9AE028F1497c275EB9192a3Ea0f67022"),
|
||||
protocol_system: String::from("vm:curve"),
|
||||
static_attributes,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let swap = Swap {
|
||||
component,
|
||||
token_in: token_in.clone(),
|
||||
token_out: token_out.clone(),
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
};
|
||||
|
||||
let encoder = get_tycho_router_encoder(UserTransferType::TransferFrom);
|
||||
|
||||
let solution = Solution {
|
||||
exact_out: false,
|
||||
given_token: token_in,
|
||||
given_amount: BigUint::from_str("1_000000000000000000").unwrap(),
|
||||
checked_token: token_out,
|
||||
checked_amount: BigUint::from_str("1").unwrap(),
|
||||
// Alice
|
||||
sender: Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(),
|
||||
receiver: Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(),
|
||||
swaps: vec![swap],
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let encoded_solution = encoder
|
||||
.encode_solutions(vec![solution.clone()])
|
||||
.unwrap()[0]
|
||||
.clone();
|
||||
|
||||
let calldata = encode_tycho_router_call(
|
||||
eth_chain().id,
|
||||
encoded_solution,
|
||||
&solution,
|
||||
UserTransferType::TransferFrom,
|
||||
eth(),
|
||||
None,
|
||||
)
|
||||
.unwrap()
|
||||
.data;
|
||||
|
||||
let hex_calldata = encode(&calldata);
|
||||
write_calldata_to_file("test_single_encoding_strategy_curve_st_eth", hex_calldata.as_str());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_single_encoding_strategy_balancer_v3() {
|
||||
// steakUSDTlite -> (balancer v3) -> steakUSDR
|
||||
let balancer_pool = ProtocolComponent {
|
||||
id: String::from("0xf028ac624074d6793c36dc8a06ecec0f5a39a718"),
|
||||
protocol_system: String::from("vm:balancer_v3"),
|
||||
..Default::default()
|
||||
};
|
||||
let token_in = Bytes::from("0x097ffedb80d4b2ca6105a07a4d90eb739c45a666");
|
||||
let token_out = Bytes::from("0x30881baa943777f92dc934d53d3bfdf33382cab3");
|
||||
let swap = Swap {
|
||||
component: balancer_pool,
|
||||
token_in: token_in.clone(),
|
||||
token_out: token_out.clone(),
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
};
|
||||
|
||||
let encoder = get_tycho_router_encoder(UserTransferType::TransferFrom);
|
||||
|
||||
let solution = Solution {
|
||||
exact_out: false,
|
||||
given_token: token_in,
|
||||
given_amount: BigUint::from_str("1_000000000000000000").unwrap(),
|
||||
checked_token: token_out,
|
||||
checked_amount: BigUint::from_str("1000").unwrap(),
|
||||
// Alice
|
||||
sender: Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(),
|
||||
receiver: Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(),
|
||||
swaps: vec![swap],
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let encoded_solution = encoder
|
||||
.encode_solutions(vec![solution.clone()])
|
||||
.unwrap()[0]
|
||||
.clone();
|
||||
|
||||
let calldata = encode_tycho_router_call(
|
||||
eth_chain().id,
|
||||
encoded_solution,
|
||||
&solution,
|
||||
UserTransferType::TransferFrom,
|
||||
eth(),
|
||||
None,
|
||||
)
|
||||
.unwrap()
|
||||
.data;
|
||||
let hex_calldata = encode(&calldata);
|
||||
write_calldata_to_file("test_single_encoding_strategy_balancer_v3", hex_calldata.as_str());
|
||||
}
|
||||
312
tests/sequential_strategy_integration_tests.rs
Normal file
312
tests/sequential_strategy_integration_tests.rs
Normal file
@@ -0,0 +1,312 @@
|
||||
mod common;
|
||||
use std::{collections::HashMap, str::FromStr};
|
||||
|
||||
use alloy::hex::encode;
|
||||
use num_bigint::{BigInt, BigUint};
|
||||
use tycho_common::{models::protocol::ProtocolComponent, Bytes};
|
||||
use tycho_execution::encoding::{
|
||||
evm::utils::write_calldata_to_file,
|
||||
models::{Solution, Swap, UserTransferType},
|
||||
};
|
||||
|
||||
use crate::common::{
|
||||
encoding::encode_tycho_router_call, eth, eth_chain, get_signer, get_tycho_router_encoder, usdc,
|
||||
wbtc, weth,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn test_sequential_swap_strategy_encoder() {
|
||||
// Note: This test does not assert anything. It is only used to obtain integration
|
||||
// test data for our router solidity test.
|
||||
//
|
||||
// Performs a sequential swap from WETH to USDC though WBTC using USV2 pools
|
||||
//
|
||||
// WETH ───(USV2)──> WBTC ───(USV2)──> USDC
|
||||
|
||||
let weth = weth();
|
||||
let wbtc = wbtc();
|
||||
let usdc = usdc();
|
||||
|
||||
let swap_weth_wbtc = Swap {
|
||||
component: ProtocolComponent {
|
||||
id: "0xBb2b8038a1640196FbE3e38816F3e67Cba72D940".to_string(),
|
||||
protocol_system: "uniswap_v2".to_string(),
|
||||
..Default::default()
|
||||
},
|
||||
token_in: weth.clone(),
|
||||
token_out: wbtc.clone(),
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
};
|
||||
let swap_wbtc_usdc = Swap {
|
||||
component: ProtocolComponent {
|
||||
id: "0x004375Dff511095CC5A197A54140a24eFEF3A416".to_string(),
|
||||
protocol_system: "uniswap_v2".to_string(),
|
||||
..Default::default()
|
||||
},
|
||||
token_in: wbtc.clone(),
|
||||
token_out: usdc.clone(),
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
};
|
||||
let encoder = get_tycho_router_encoder(UserTransferType::TransferFromPermit2);
|
||||
|
||||
let solution = Solution {
|
||||
exact_out: false,
|
||||
given_token: weth,
|
||||
given_amount: BigUint::from_str("1_000000000000000000").unwrap(),
|
||||
checked_token: usdc,
|
||||
checked_amount: BigUint::from_str("26173932").unwrap(),
|
||||
sender: Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(),
|
||||
receiver: Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(),
|
||||
swaps: vec![swap_weth_wbtc, swap_wbtc_usdc],
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let encoded_solution = encoder
|
||||
.encode_solutions(vec![solution.clone()])
|
||||
.unwrap()[0]
|
||||
.clone();
|
||||
|
||||
let calldata = encode_tycho_router_call(
|
||||
eth_chain().id,
|
||||
encoded_solution,
|
||||
&solution,
|
||||
UserTransferType::TransferFromPermit2,
|
||||
eth(),
|
||||
Some(get_signer()),
|
||||
)
|
||||
.unwrap()
|
||||
.data;
|
||||
|
||||
let hex_calldata = encode(&calldata);
|
||||
write_calldata_to_file("test_sequential_swap_strategy_encoder", hex_calldata.as_str());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sequential_swap_strategy_encoder_no_permit2() {
|
||||
// Performs a sequential swap from WETH to USDC though WBTC using USV2 pools
|
||||
//
|
||||
// WETH ───(USV2)──> WBTC ───(USV2)──> USDC
|
||||
|
||||
let weth = weth();
|
||||
let wbtc = wbtc();
|
||||
let usdc = usdc();
|
||||
|
||||
let swap_weth_wbtc = Swap {
|
||||
component: ProtocolComponent {
|
||||
id: "0xBb2b8038a1640196FbE3e38816F3e67Cba72D940".to_string(),
|
||||
protocol_system: "uniswap_v2".to_string(),
|
||||
..Default::default()
|
||||
},
|
||||
token_in: weth.clone(),
|
||||
token_out: wbtc.clone(),
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
};
|
||||
let swap_wbtc_usdc = Swap {
|
||||
component: ProtocolComponent {
|
||||
id: "0x004375Dff511095CC5A197A54140a24eFEF3A416".to_string(),
|
||||
protocol_system: "uniswap_v2".to_string(),
|
||||
..Default::default()
|
||||
},
|
||||
token_in: wbtc.clone(),
|
||||
token_out: usdc.clone(),
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
};
|
||||
let encoder = get_tycho_router_encoder(UserTransferType::TransferFrom);
|
||||
|
||||
let solution = Solution {
|
||||
exact_out: false,
|
||||
given_token: weth,
|
||||
given_amount: BigUint::from_str("1_000000000000000000").unwrap(),
|
||||
checked_token: usdc,
|
||||
checked_amount: BigUint::from_str("26173932").unwrap(),
|
||||
sender: Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(),
|
||||
receiver: Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(),
|
||||
swaps: vec![swap_weth_wbtc, swap_wbtc_usdc],
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let encoded_solution = encoder
|
||||
.encode_solutions(vec![solution.clone()])
|
||||
.unwrap()[0]
|
||||
.clone();
|
||||
|
||||
let calldata = encode_tycho_router_call(
|
||||
eth_chain().id,
|
||||
encoded_solution,
|
||||
&solution,
|
||||
UserTransferType::TransferFrom,
|
||||
eth(),
|
||||
None,
|
||||
)
|
||||
.unwrap()
|
||||
.data;
|
||||
|
||||
let hex_calldata = encode(&calldata);
|
||||
|
||||
let expected = String::from(concat!(
|
||||
"e21dd0d3", /* function selector */
|
||||
"0000000000000000000000000000000000000000000000000de0b6b3a7640000", /* amount in */
|
||||
"000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // token in
|
||||
"000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // token ou
|
||||
"00000000000000000000000000000000000000000000000000000000018f61ec", /* min amount out */
|
||||
"0000000000000000000000000000000000000000000000000000000000000000", // wrap
|
||||
"0000000000000000000000000000000000000000000000000000000000000000", // unwrap
|
||||
"000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver
|
||||
"0000000000000000000000000000000000000000000000000000000000000001", /* transfer from
|
||||
* needed */
|
||||
"0000000000000000000000000000000000000000000000000000000000000120", /* length ple
|
||||
* encode */
|
||||
"00000000000000000000000000000000000000000000000000000000000000a8",
|
||||
// swap 1
|
||||
"0052", // swap length
|
||||
"5615deb798bb3e4dfa0139dfa1b3d433cc23b72f", // executor address
|
||||
"c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // token in
|
||||
"bb2b8038a1640196fbe3e38816f3e67cba72d940", // component id
|
||||
"004375dff511095cc5a197a54140a24efef3a416", // receiver (next pool)
|
||||
"00", // zero to one
|
||||
"00", // transfer type TransferFrom
|
||||
// swap 2
|
||||
"0052", // swap length
|
||||
"5615deb798bb3e4dfa0139dfa1b3d433cc23b72f", // executor address
|
||||
"2260fac5e5542a773aa44fbcfedf7c193bc2c599", // token in
|
||||
"004375dff511095cc5a197a54140a24efef3a416", // component id
|
||||
"cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver (final user)
|
||||
"01", // zero to one
|
||||
"02", // transfer type None
|
||||
"000000000000000000000000000000000000000000000000", // padding
|
||||
));
|
||||
|
||||
assert_eq!(hex_calldata, expected);
|
||||
write_calldata_to_file(
|
||||
"test_sequential_swap_strategy_encoder_no_permit2",
|
||||
hex_calldata.as_str(),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sequential_strategy_cyclic_swap() {
|
||||
// This test has start and end tokens that are the same
|
||||
// The flow is:
|
||||
// USDC -> WETH -> USDC using two pools
|
||||
|
||||
let weth = weth();
|
||||
let usdc = usdc();
|
||||
|
||||
// Create two Uniswap V3 pools for the cyclic swap
|
||||
// USDC -> WETH (Pool 1)
|
||||
let swap_usdc_weth = Swap {
|
||||
component: ProtocolComponent {
|
||||
id: "0x88e6A0c2dDD26FEEb64F039a2c41296FcB3f5640".to_string(), /* USDC-WETH USV3
|
||||
* Pool 1 */
|
||||
protocol_system: "uniswap_v3".to_string(),
|
||||
static_attributes: {
|
||||
let mut attrs = HashMap::new();
|
||||
attrs
|
||||
.insert("fee".to_string(), Bytes::from(BigInt::from(500).to_signed_bytes_be()));
|
||||
attrs
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
token_in: usdc.clone(),
|
||||
token_out: weth.clone(),
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
};
|
||||
|
||||
// WETH -> USDC (Pool 2)
|
||||
let swap_weth_usdc = Swap {
|
||||
component: ProtocolComponent {
|
||||
id: "0x8ad599c3A0ff1De082011EFDDc58f1908eb6e6D8".to_string(), /* USDC-WETH USV3
|
||||
* Pool 2 */
|
||||
protocol_system: "uniswap_v3".to_string(),
|
||||
static_attributes: {
|
||||
let mut attrs = HashMap::new();
|
||||
attrs.insert(
|
||||
"fee".to_string(),
|
||||
Bytes::from(BigInt::from(3000).to_signed_bytes_be()),
|
||||
);
|
||||
attrs
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
token_in: weth.clone(),
|
||||
token_out: usdc.clone(),
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
};
|
||||
|
||||
let encoder = get_tycho_router_encoder(UserTransferType::TransferFromPermit2);
|
||||
|
||||
let solution = Solution {
|
||||
exact_out: false,
|
||||
given_token: usdc.clone(),
|
||||
given_amount: BigUint::from_str("100000000").unwrap(), // 100 USDC (6 decimals)
|
||||
checked_token: usdc.clone(),
|
||||
checked_amount: BigUint::from_str("99389294").unwrap(), /* Expected output
|
||||
* from test */
|
||||
swaps: vec![swap_usdc_weth, swap_weth_usdc],
|
||||
sender: Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(),
|
||||
receiver: Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let encoded_solution = encoder
|
||||
.encode_solutions(vec![solution.clone()])
|
||||
.unwrap()[0]
|
||||
.clone();
|
||||
|
||||
let calldata = encode_tycho_router_call(
|
||||
eth_chain().id,
|
||||
encoded_solution,
|
||||
&solution,
|
||||
UserTransferType::TransferFromPermit2,
|
||||
eth(),
|
||||
Some(get_signer()),
|
||||
)
|
||||
.unwrap()
|
||||
.data;
|
||||
let hex_calldata = alloy::hex::encode(&calldata);
|
||||
let expected_input = [
|
||||
"51bcc7b6", // selector
|
||||
"0000000000000000000000000000000000000000000000000000000005f5e100", // given amount
|
||||
"000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // given token
|
||||
"000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // checked token
|
||||
"0000000000000000000000000000000000000000000000000000000005ec8f6e", // min amount out
|
||||
"0000000000000000000000000000000000000000000000000000000000000000", // wrap action
|
||||
"0000000000000000000000000000000000000000000000000000000000000000", // unwrap action
|
||||
"000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver
|
||||
]
|
||||
.join("");
|
||||
|
||||
let expected_swaps = [
|
||||
"00000000000000000000000000000000000000000000000000000000000000d6", // length of ple encoded swaps without padding
|
||||
"0069", // ple encoded swaps
|
||||
"2e234dae75c793f67a35089c9d99245e1c58470b", // executor address
|
||||
"a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // token in
|
||||
"c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // token out
|
||||
"0001f4", // pool fee
|
||||
"3ede3eca2a72b3aecc820e955b36f38437d01395", // receiver
|
||||
"88e6a0c2ddd26feeb64f039a2c41296fcb3f5640", // component id
|
||||
"01", // zero2one
|
||||
"00", // transfer type TransferFrom
|
||||
"0069", // ple encoded swaps
|
||||
"2e234dae75c793f67a35089c9d99245e1c58470b", // executor address
|
||||
"c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // token in
|
||||
"a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // token out
|
||||
"000bb8", // pool fee
|
||||
"cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver
|
||||
"8ad599c3a0ff1de082011efddc58f1908eb6e6d8", // component id
|
||||
"00", // zero2one
|
||||
"01", // transfer type Transfer
|
||||
"00000000000000000000", // padding
|
||||
]
|
||||
.join("");
|
||||
|
||||
assert_eq!(hex_calldata[..456], expected_input);
|
||||
assert_eq!(hex_calldata[1224..], expected_swaps);
|
||||
write_calldata_to_file("test_sequential_strategy_cyclic_swap", hex_calldata.as_str());
|
||||
}
|
||||
372
tests/single_strategy_integration_tests.rs
Normal file
372
tests/single_strategy_integration_tests.rs
Normal file
@@ -0,0 +1,372 @@
|
||||
mod common;
|
||||
|
||||
use std::str::FromStr;
|
||||
|
||||
use alloy::{hex::encode, primitives::U256, sol_types::SolValue};
|
||||
use num_bigint::BigUint;
|
||||
use tycho_common::{models::protocol::ProtocolComponent, Bytes};
|
||||
use tycho_execution::encoding::{
|
||||
evm::utils::{biguint_to_u256, write_calldata_to_file},
|
||||
models::{NativeAction, Solution, Swap, UserTransferType},
|
||||
};
|
||||
|
||||
use crate::common::{
|
||||
dai, encoding::encode_tycho_router_call, eth, eth_chain, get_signer, get_tycho_router_encoder,
|
||||
weth,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn test_single_swap_strategy_encoder() {
|
||||
// Performs a single swap from WETH to DAI on a USV2 pool, with no grouping
|
||||
// optimizations.
|
||||
let checked_amount = BigUint::from_str("2018817438608734439720").unwrap();
|
||||
let weth = weth();
|
||||
let dai = dai();
|
||||
|
||||
let swap = Swap {
|
||||
component: ProtocolComponent {
|
||||
id: "0xA478c2975Ab1Ea89e8196811F51A7B7Ade33eB11".to_string(),
|
||||
protocol_system: "uniswap_v2".to_string(),
|
||||
..Default::default()
|
||||
},
|
||||
token_in: weth.clone(),
|
||||
token_out: dai.clone(),
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
};
|
||||
|
||||
let encoder = get_tycho_router_encoder(UserTransferType::TransferFromPermit2);
|
||||
|
||||
let solution = Solution {
|
||||
exact_out: false,
|
||||
given_token: weth,
|
||||
given_amount: BigUint::from_str("1_000000000000000000").unwrap(),
|
||||
checked_token: dai,
|
||||
checked_amount: checked_amount.clone(),
|
||||
sender: Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(),
|
||||
receiver: Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(),
|
||||
swaps: vec![swap],
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let encoded_solutions = encoder
|
||||
.encode_solutions(vec![solution.clone()])
|
||||
.unwrap();
|
||||
|
||||
let calldata = encode_tycho_router_call(
|
||||
eth_chain().id,
|
||||
encoded_solutions[0].clone(),
|
||||
&solution,
|
||||
UserTransferType::TransferFromPermit2,
|
||||
eth(),
|
||||
Some(get_signer()),
|
||||
)
|
||||
.unwrap()
|
||||
.data;
|
||||
let expected_min_amount_encoded = encode(U256::abi_encode(&biguint_to_u256(&checked_amount)));
|
||||
let expected_input = [
|
||||
"30ace1b1", // Function selector
|
||||
"0000000000000000000000000000000000000000000000000de0b6b3a7640000", // amount in
|
||||
"000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // token in
|
||||
"0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f", // token out
|
||||
&expected_min_amount_encoded, // min amount out
|
||||
"0000000000000000000000000000000000000000000000000000000000000000", // wrap
|
||||
"0000000000000000000000000000000000000000000000000000000000000000", // unwrap
|
||||
"000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver
|
||||
]
|
||||
.join("");
|
||||
|
||||
// after this there is the permit and because of the deadlines (that depend on block
|
||||
// time) it's hard to assert
|
||||
|
||||
let expected_swap = String::from(concat!(
|
||||
// length of encoded swap without padding
|
||||
"0000000000000000000000000000000000000000000000000000000000000052",
|
||||
// Swap data
|
||||
"5615deb798bb3e4dfa0139dfa1b3d433cc23b72f", // executor address
|
||||
"c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // token in
|
||||
"a478c2975ab1ea89e8196811f51a7b7ade33eb11", // component id
|
||||
"cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver
|
||||
"00", // zero2one
|
||||
"00", // transfer type TransferFrom
|
||||
"0000000000000000000000000000", // padding
|
||||
));
|
||||
let hex_calldata = encode(&calldata);
|
||||
|
||||
assert_eq!(hex_calldata[..456], expected_input);
|
||||
assert_eq!(hex_calldata[1224..], expected_swap);
|
||||
write_calldata_to_file("test_single_swap_strategy_encoder", &hex_calldata.to_string());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_single_swap_strategy_encoder_no_permit2() {
|
||||
// Performs a single swap from WETH to DAI on a USV2 pool, without permit2 and no
|
||||
// grouping optimizations.
|
||||
|
||||
let weth = weth();
|
||||
let dai = dai();
|
||||
|
||||
let checked_amount = BigUint::from_str("1_640_000000000000000000").unwrap();
|
||||
let expected_min_amount = U256::from_str("1_640_000000000000000000").unwrap();
|
||||
|
||||
let swap = Swap {
|
||||
component: ProtocolComponent {
|
||||
id: "0xA478c2975Ab1Ea89e8196811F51A7B7Ade33eB11".to_string(),
|
||||
protocol_system: "uniswap_v2".to_string(),
|
||||
..Default::default()
|
||||
},
|
||||
token_in: weth.clone(),
|
||||
token_out: dai.clone(),
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
};
|
||||
let encoder = get_tycho_router_encoder(UserTransferType::TransferFrom);
|
||||
|
||||
let solution = Solution {
|
||||
exact_out: false,
|
||||
given_token: weth,
|
||||
given_amount: BigUint::from_str("1_000000000000000000").unwrap(),
|
||||
checked_token: dai,
|
||||
checked_amount,
|
||||
sender: Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(),
|
||||
receiver: Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(),
|
||||
swaps: vec![swap],
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let encoded_solution = encoder
|
||||
.encode_solutions(vec![solution.clone()])
|
||||
.unwrap()[0]
|
||||
.clone();
|
||||
let calldata = encode_tycho_router_call(
|
||||
eth_chain().id,
|
||||
encoded_solution,
|
||||
&solution,
|
||||
UserTransferType::TransferFrom,
|
||||
eth(),
|
||||
None,
|
||||
)
|
||||
.unwrap()
|
||||
.data;
|
||||
let expected_min_amount_encoded = encode(U256::abi_encode(&expected_min_amount));
|
||||
let expected_input = [
|
||||
"5c4b639c", // Function selector
|
||||
"0000000000000000000000000000000000000000000000000de0b6b3a7640000", // amount in
|
||||
"000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // token in
|
||||
"0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f", // token out
|
||||
&expected_min_amount_encoded, // min amount out
|
||||
"0000000000000000000000000000000000000000000000000000000000000000", // wrap
|
||||
"0000000000000000000000000000000000000000000000000000000000000000", // unwrap
|
||||
"000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver
|
||||
"0000000000000000000000000000000000000000000000000000000000000001", // transfer from needed
|
||||
"0000000000000000000000000000000000000000000000000000000000000120", // offset of swap bytes
|
||||
"0000000000000000000000000000000000000000000000000000000000000052", /* length of swap
|
||||
* bytes without
|
||||
* padding */
|
||||
// Swap data
|
||||
"5615deb798bb3e4dfa0139dfa1b3d433cc23b72f", // executor address
|
||||
"c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // token in
|
||||
"a478c2975ab1ea89e8196811f51a7b7ade33eb11", // component id
|
||||
"cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver
|
||||
"00", // zero2one
|
||||
"00", // transfer type TransferFrom
|
||||
"0000000000000000000000000000", // padding
|
||||
]
|
||||
.join("");
|
||||
|
||||
let hex_calldata = encode(&calldata);
|
||||
|
||||
assert_eq!(hex_calldata, expected_input);
|
||||
write_calldata_to_file("test_single_swap_strategy_encoder_no_permit2", hex_calldata.as_str());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_single_swap_strategy_encoder_no_transfer_in() {
|
||||
// Performs a single swap from WETH to DAI on a USV2 pool assuming that the tokens
|
||||
// are already in the router
|
||||
|
||||
let weth = weth();
|
||||
let dai = dai();
|
||||
|
||||
let checked_amount = BigUint::from_str("1_640_000000000000000000").unwrap();
|
||||
let expected_min_amount = U256::from_str("1_640_000000000000000000").unwrap();
|
||||
|
||||
let swap = Swap {
|
||||
component: ProtocolComponent {
|
||||
id: "0xA478c2975Ab1Ea89e8196811F51A7B7Ade33eB11".to_string(),
|
||||
protocol_system: "uniswap_v2".to_string(),
|
||||
..Default::default()
|
||||
},
|
||||
token_in: weth.clone(),
|
||||
token_out: dai.clone(),
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
};
|
||||
let encoder = get_tycho_router_encoder(UserTransferType::None);
|
||||
|
||||
let solution = Solution {
|
||||
exact_out: false,
|
||||
given_token: weth,
|
||||
given_amount: BigUint::from_str("1_000000000000000000").unwrap(),
|
||||
checked_token: dai,
|
||||
checked_amount,
|
||||
sender: Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(),
|
||||
receiver: Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(),
|
||||
swaps: vec![swap],
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let encoded_solution = encoder
|
||||
.encode_solutions(vec![solution.clone()])
|
||||
.unwrap()[0]
|
||||
.clone();
|
||||
let calldata = encode_tycho_router_call(
|
||||
eth_chain().id,
|
||||
encoded_solution,
|
||||
&solution,
|
||||
UserTransferType::None,
|
||||
eth(),
|
||||
None,
|
||||
)
|
||||
.unwrap()
|
||||
.data;
|
||||
let expected_min_amount_encoded = encode(U256::abi_encode(&expected_min_amount));
|
||||
let expected_input = [
|
||||
"5c4b639c", // Function selector
|
||||
"0000000000000000000000000000000000000000000000000de0b6b3a7640000", // amount in
|
||||
"000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // token in
|
||||
"0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f", // token out
|
||||
&expected_min_amount_encoded, // min amount out
|
||||
"0000000000000000000000000000000000000000000000000000000000000000", // wrap
|
||||
"0000000000000000000000000000000000000000000000000000000000000000", // unwrap
|
||||
"000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver
|
||||
"0000000000000000000000000000000000000000000000000000000000000000", /* transfer from not
|
||||
* needed */
|
||||
"0000000000000000000000000000000000000000000000000000000000000120", // offset of swap bytes
|
||||
"0000000000000000000000000000000000000000000000000000000000000052", /* length of swap
|
||||
* bytes without
|
||||
* padding */
|
||||
// Swap data
|
||||
"5615deb798bb3e4dfa0139dfa1b3d433cc23b72f", // executor address
|
||||
"c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // token in
|
||||
"a478c2975ab1ea89e8196811f51a7b7ade33eb11", // component id
|
||||
"cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver
|
||||
"00", // zero2one
|
||||
"01", // transfer type Transfer
|
||||
"0000000000000000000000000000", // padding
|
||||
]
|
||||
.join("");
|
||||
|
||||
let hex_calldata = encode(&calldata);
|
||||
|
||||
assert_eq!(hex_calldata, expected_input);
|
||||
write_calldata_to_file(
|
||||
"test_single_swap_strategy_encoder_no_transfer_in",
|
||||
hex_calldata.as_str(),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_single_swap_strategy_encoder_wrap() {
|
||||
// Performs a single swap from WETH to DAI on a USV2 pool, wrapping ETH
|
||||
// Note: This test does not assert anything. It is only used to obtain integration
|
||||
// test data for our router solidity test.
|
||||
|
||||
let dai = dai();
|
||||
|
||||
let swap = Swap {
|
||||
component: ProtocolComponent {
|
||||
id: "0xA478c2975Ab1Ea89e8196811F51A7B7Ade33eB11".to_string(),
|
||||
protocol_system: "uniswap_v2".to_string(),
|
||||
..Default::default()
|
||||
},
|
||||
token_in: weth(),
|
||||
token_out: dai.clone(),
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
};
|
||||
let encoder = get_tycho_router_encoder(UserTransferType::TransferFromPermit2);
|
||||
|
||||
let solution = Solution {
|
||||
exact_out: false,
|
||||
given_token: eth(),
|
||||
given_amount: BigUint::from_str("1_000000000000000000").unwrap(),
|
||||
checked_token: dai,
|
||||
checked_amount: BigUint::from_str("1659881924818443699787").unwrap(),
|
||||
sender: Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(),
|
||||
receiver: Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(),
|
||||
swaps: vec![swap],
|
||||
native_action: Some(NativeAction::Wrap),
|
||||
};
|
||||
|
||||
let encoded_solution = encoder
|
||||
.encode_solutions(vec![solution.clone()])
|
||||
.unwrap()[0]
|
||||
.clone();
|
||||
|
||||
let calldata = encode_tycho_router_call(
|
||||
eth_chain().id,
|
||||
encoded_solution,
|
||||
&solution,
|
||||
UserTransferType::TransferFromPermit2,
|
||||
eth(),
|
||||
Some(get_signer()),
|
||||
)
|
||||
.unwrap()
|
||||
.data;
|
||||
let hex_calldata = encode(&calldata);
|
||||
write_calldata_to_file("test_single_swap_strategy_encoder_wrap", hex_calldata.as_str());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_single_swap_strategy_encoder_unwrap() {
|
||||
// Performs a single swap from DAI to WETH on a USV2 pool, unwrapping ETH at the end
|
||||
// Note: This test does not assert anything. It is only used to obtain integration
|
||||
// test data for our router solidity test.
|
||||
|
||||
let dai = dai();
|
||||
|
||||
let swap = Swap {
|
||||
component: ProtocolComponent {
|
||||
id: "0xA478c2975Ab1Ea89e8196811F51A7B7Ade33eB11".to_string(),
|
||||
protocol_system: "uniswap_v2".to_string(),
|
||||
..Default::default()
|
||||
},
|
||||
token_in: dai.clone(),
|
||||
token_out: weth(),
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
};
|
||||
let encoder = get_tycho_router_encoder(UserTransferType::TransferFromPermit2);
|
||||
|
||||
let solution = Solution {
|
||||
exact_out: false,
|
||||
given_token: dai,
|
||||
given_amount: BigUint::from_str("3_000_000000000000000000").unwrap(),
|
||||
checked_token: eth(),
|
||||
checked_amount: BigUint::from_str("1_000000000000000000").unwrap(),
|
||||
sender: Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(),
|
||||
receiver: Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(),
|
||||
swaps: vec![swap],
|
||||
native_action: Some(NativeAction::Unwrap),
|
||||
};
|
||||
|
||||
let encoded_solution = encoder
|
||||
.encode_solutions(vec![solution.clone()])
|
||||
.unwrap()[0]
|
||||
.clone();
|
||||
|
||||
let calldata = encode_tycho_router_call(
|
||||
eth_chain().id,
|
||||
encoded_solution,
|
||||
&solution,
|
||||
UserTransferType::TransferFromPermit2,
|
||||
eth(),
|
||||
Some(get_signer()),
|
||||
)
|
||||
.unwrap()
|
||||
.data;
|
||||
|
||||
let hex_calldata = encode(&calldata);
|
||||
write_calldata_to_file("test_single_swap_strategy_encoder_unwrap", hex_calldata.as_str());
|
||||
}
|
||||
442
tests/split_strategy_integration_tests.rs
Normal file
442
tests/split_strategy_integration_tests.rs
Normal file
@@ -0,0 +1,442 @@
|
||||
mod common;
|
||||
|
||||
use std::{collections::HashMap, str::FromStr};
|
||||
|
||||
use alloy::hex::encode;
|
||||
use num_bigint::{BigInt, BigUint};
|
||||
use tycho_common::{models::protocol::ProtocolComponent, Bytes};
|
||||
use tycho_execution::encoding::{
|
||||
evm::utils::write_calldata_to_file,
|
||||
models::{Solution, Swap, UserTransferType},
|
||||
};
|
||||
|
||||
use crate::common::{
|
||||
dai, encoding::encode_tycho_router_call, eth, eth_chain, get_signer, get_tycho_router_encoder,
|
||||
usdc, wbtc, weth,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn test_split_swap_strategy_encoder() {
|
||||
// Note: This test does not assert anything. It is only used to obtain integration
|
||||
// test data for our router solidity test.
|
||||
//
|
||||
// Performs a split swap from WETH to USDC though WBTC and DAI using USV2 pools
|
||||
//
|
||||
// ┌──(USV2)──> WBTC ───(USV2)──> USDC
|
||||
// WETH ─┤
|
||||
// └──(USV2)──> DAI ───(USV2)──> USDC
|
||||
//
|
||||
|
||||
let weth = weth();
|
||||
let dai = dai();
|
||||
let wbtc = wbtc();
|
||||
let usdc = usdc();
|
||||
|
||||
let swap_weth_dai = Swap {
|
||||
component: ProtocolComponent {
|
||||
id: "0xA478c2975Ab1Ea89e8196811F51A7B7Ade33eB11".to_string(),
|
||||
protocol_system: "uniswap_v2".to_string(),
|
||||
..Default::default()
|
||||
},
|
||||
token_in: weth.clone(),
|
||||
token_out: dai.clone(),
|
||||
split: 0.5f64,
|
||||
user_data: None,
|
||||
};
|
||||
let swap_weth_wbtc = Swap {
|
||||
component: ProtocolComponent {
|
||||
id: "0xBb2b8038a1640196FbE3e38816F3e67Cba72D940".to_string(),
|
||||
protocol_system: "uniswap_v2".to_string(),
|
||||
..Default::default()
|
||||
},
|
||||
token_in: weth.clone(),
|
||||
token_out: wbtc.clone(),
|
||||
// This represents the remaining 50%, but to avoid any rounding errors we set
|
||||
// this to 0 to signify "the remainder of the WETH value".
|
||||
// It should still be very close to 50%
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
};
|
||||
let swap_dai_usdc = Swap {
|
||||
component: ProtocolComponent {
|
||||
id: "0xAE461cA67B15dc8dc81CE7615e0320dA1A9aB8D5".to_string(),
|
||||
protocol_system: "uniswap_v2".to_string(),
|
||||
..Default::default()
|
||||
},
|
||||
token_in: dai.clone(),
|
||||
token_out: usdc.clone(),
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
};
|
||||
let swap_wbtc_usdc = Swap {
|
||||
component: ProtocolComponent {
|
||||
id: "0x004375Dff511095CC5A197A54140a24eFEF3A416".to_string(),
|
||||
protocol_system: "uniswap_v2".to_string(),
|
||||
..Default::default()
|
||||
},
|
||||
token_in: wbtc.clone(),
|
||||
token_out: usdc.clone(),
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
};
|
||||
let encoder = get_tycho_router_encoder(UserTransferType::TransferFromPermit2);
|
||||
|
||||
let solution = Solution {
|
||||
exact_out: false,
|
||||
given_token: weth,
|
||||
given_amount: BigUint::from_str("1_000000000000000000").unwrap(),
|
||||
checked_token: usdc,
|
||||
checked_amount: BigUint::from_str("26173932").unwrap(),
|
||||
sender: Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(),
|
||||
receiver: Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(),
|
||||
swaps: vec![swap_weth_dai, swap_weth_wbtc, swap_dai_usdc, swap_wbtc_usdc],
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let encoded_solution = encoder
|
||||
.encode_solutions(vec![solution.clone()])
|
||||
.unwrap()[0]
|
||||
.clone();
|
||||
|
||||
let calldata = encode_tycho_router_call(
|
||||
eth_chain().id,
|
||||
encoded_solution,
|
||||
&solution,
|
||||
UserTransferType::TransferFromPermit2,
|
||||
eth(),
|
||||
Some(get_signer()),
|
||||
)
|
||||
.unwrap()
|
||||
.data;
|
||||
|
||||
let hex_calldata = encode(&calldata);
|
||||
write_calldata_to_file("test_split_swap_strategy_encoder", hex_calldata.as_str());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_split_input_cyclic_swap() {
|
||||
// This test has start and end tokens that are the same
|
||||
// The flow is:
|
||||
// ┌─ (USV3, 60% split) ──> WETH ─┐
|
||||
// │ │
|
||||
// USDC ──────┤ ├──(USV2)──> USDC
|
||||
// │ │
|
||||
// └─ (USV3, 40% split) ──> WETH ─┘
|
||||
|
||||
let weth = weth();
|
||||
let usdc = usdc();
|
||||
|
||||
// USDC -> WETH (Pool 1) - 60% of input
|
||||
let swap_usdc_weth_pool1 = Swap {
|
||||
component: ProtocolComponent {
|
||||
id: "0x88e6A0c2dDD26FEEb64F039a2c41296FcB3f5640".to_string(), /* USDC-WETH USV3
|
||||
* Pool 1 */
|
||||
protocol_system: "uniswap_v3".to_string(),
|
||||
static_attributes: {
|
||||
let mut attrs = HashMap::new();
|
||||
attrs
|
||||
.insert("fee".to_string(), Bytes::from(BigInt::from(500).to_signed_bytes_be()));
|
||||
attrs
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
token_in: usdc.clone(),
|
||||
token_out: weth.clone(),
|
||||
split: 0.6f64, // 60% of input
|
||||
user_data: None,
|
||||
};
|
||||
|
||||
// USDC -> WETH (Pool 2) - 40% of input (remaining)
|
||||
let swap_usdc_weth_pool2 = Swap {
|
||||
component: ProtocolComponent {
|
||||
id: "0x8ad599c3A0ff1De082011EFDDc58f1908eb6e6D8".to_string(), /* USDC-WETH USV3
|
||||
* Pool 2 */
|
||||
protocol_system: "uniswap_v3".to_string(),
|
||||
static_attributes: {
|
||||
let mut attrs = HashMap::new();
|
||||
attrs.insert(
|
||||
"fee".to_string(),
|
||||
Bytes::from(BigInt::from(3000).to_signed_bytes_be()),
|
||||
);
|
||||
attrs
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
token_in: usdc.clone(),
|
||||
token_out: weth.clone(),
|
||||
split: 0f64,
|
||||
user_data: None, // Remaining 40%
|
||||
};
|
||||
|
||||
// WETH -> USDC (Pool 2)
|
||||
let swap_weth_usdc_pool2 = Swap {
|
||||
component: ProtocolComponent {
|
||||
id: "0xB4e16d0168e52d35CaCD2c6185b44281Ec28C9Dc".to_string(), /* USDC-WETH USV2
|
||||
* Pool 2 */
|
||||
protocol_system: "uniswap_v2".to_string(),
|
||||
static_attributes: {
|
||||
let mut attrs = HashMap::new();
|
||||
attrs.insert(
|
||||
"fee".to_string(),
|
||||
Bytes::from(BigInt::from(3000).to_signed_bytes_be()),
|
||||
);
|
||||
attrs
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
token_in: weth.clone(),
|
||||
token_out: usdc.clone(),
|
||||
split: 0.0f64,
|
||||
user_data: None,
|
||||
};
|
||||
|
||||
let encoder = get_tycho_router_encoder(UserTransferType::TransferFromPermit2);
|
||||
|
||||
let solution = Solution {
|
||||
exact_out: false,
|
||||
given_token: usdc.clone(),
|
||||
given_amount: BigUint::from_str("100000000").unwrap(), // 100 USDC (6 decimals)
|
||||
checked_token: usdc.clone(),
|
||||
checked_amount: BigUint::from_str("99574171").unwrap(), /* Expected output
|
||||
* from
|
||||
* test */
|
||||
sender: Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(),
|
||||
receiver: Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(),
|
||||
swaps: vec![swap_usdc_weth_pool1, swap_usdc_weth_pool2, swap_weth_usdc_pool2],
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let encoded_solution = encoder
|
||||
.encode_solutions(vec![solution.clone()])
|
||||
.unwrap()[0]
|
||||
.clone();
|
||||
|
||||
let calldata = encode_tycho_router_call(
|
||||
eth_chain().id,
|
||||
encoded_solution,
|
||||
&solution,
|
||||
UserTransferType::TransferFromPermit2,
|
||||
eth(),
|
||||
Some(get_signer()),
|
||||
)
|
||||
.unwrap()
|
||||
.data;
|
||||
|
||||
let hex_calldata = alloy::hex::encode(&calldata);
|
||||
let expected_input = [
|
||||
"7c553846", // selector
|
||||
"0000000000000000000000000000000000000000000000000000000005f5e100", // given amount
|
||||
"000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // given token
|
||||
"000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // checked token
|
||||
"0000000000000000000000000000000000000000000000000000000005ef619b", // min amount out
|
||||
"0000000000000000000000000000000000000000000000000000000000000000", // wrap action
|
||||
"0000000000000000000000000000000000000000000000000000000000000000", // unwrap action
|
||||
"0000000000000000000000000000000000000000000000000000000000000002", // tokens length
|
||||
"000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver
|
||||
]
|
||||
.join("");
|
||||
let expected_swaps = [
|
||||
"0000000000000000000000000000000000000000000000000000000000000139", // length of ple encoded swaps without padding
|
||||
"006e", // ple encoded swaps
|
||||
"00", // token in index
|
||||
"01", // token out index
|
||||
"999999", // split
|
||||
"2e234dae75c793f67a35089c9d99245e1c58470b", // executor address
|
||||
"a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // token in
|
||||
"c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // token out
|
||||
"0001f4", // pool fee
|
||||
"3ede3eca2a72b3aecc820e955b36f38437d01395", // receiver
|
||||
"88e6a0c2ddd26feeb64f039a2c41296fcb3f5640", // component id
|
||||
"01", // zero2one
|
||||
"00", // transfer type TransferFrom
|
||||
"006e", // ple encoded swaps
|
||||
"00", // token in index
|
||||
"01", // token out index
|
||||
"000000", // split
|
||||
"2e234dae75c793f67a35089c9d99245e1c58470b", // executor address
|
||||
"a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // token in
|
||||
"c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // token out
|
||||
"000bb8", // pool fee
|
||||
"3ede3eca2a72b3aecc820e955b36f38437d01395", // receiver
|
||||
"8ad599c3a0ff1de082011efddc58f1908eb6e6d8", // component id
|
||||
"01", // zero2one
|
||||
"00", // transfer type TransferFrom
|
||||
"0057", // ple encoded swaps
|
||||
"01", // token in index
|
||||
"00", // token out index
|
||||
"000000", // split
|
||||
"5615deb798bb3e4dfa0139dfa1b3d433cc23b72f", // executor address,
|
||||
"c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // token in
|
||||
"b4e16d0168e52d35cacd2c6185b44281ec28c9dc", // component id,
|
||||
"cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver
|
||||
"00", // zero2one
|
||||
"01", // transfer type Transfer
|
||||
"00000000000000" // padding
|
||||
]
|
||||
.join("");
|
||||
assert_eq!(hex_calldata[..520], expected_input);
|
||||
assert_eq!(hex_calldata[1288..], expected_swaps);
|
||||
write_calldata_to_file("test_split_input_cyclic_swap", hex_calldata.as_str());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_split_output_cyclic_swap() {
|
||||
// This test has start and end tokens that are the same
|
||||
// The flow is:
|
||||
// ┌─── (USV3, 60% split) ───┐
|
||||
// │ │
|
||||
// USDC ──(USV2) ── WETH──| ├─> USDC
|
||||
// │ │
|
||||
// └─── (USV3, 40% split) ───┘
|
||||
|
||||
let weth = weth();
|
||||
let usdc = usdc();
|
||||
|
||||
let swap_usdc_weth_v2 = Swap {
|
||||
component: ProtocolComponent {
|
||||
id: "0xB4e16d0168e52d35CaCD2c6185b44281Ec28C9Dc".to_string(), /* USDC-WETH USV2 */
|
||||
protocol_system: "uniswap_v2".to_string(),
|
||||
static_attributes: {
|
||||
let mut attrs = HashMap::new();
|
||||
attrs
|
||||
.insert("fee".to_string(), Bytes::from(BigInt::from(500).to_signed_bytes_be()));
|
||||
attrs
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
token_in: usdc.clone(),
|
||||
token_out: weth.clone(),
|
||||
split: 0.0f64,
|
||||
user_data: None,
|
||||
};
|
||||
|
||||
let swap_weth_usdc_v3_pool1 = Swap {
|
||||
component: ProtocolComponent {
|
||||
id: "0x88e6A0c2dDD26FEEb64F039a2c41296FcB3f5640".to_string(), /* USDC-WETH USV3
|
||||
* Pool 1 */
|
||||
protocol_system: "uniswap_v3".to_string(),
|
||||
static_attributes: {
|
||||
let mut attrs = HashMap::new();
|
||||
attrs
|
||||
.insert("fee".to_string(), Bytes::from(BigInt::from(500).to_signed_bytes_be()));
|
||||
attrs
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
token_in: weth.clone(),
|
||||
token_out: usdc.clone(),
|
||||
split: 0.6f64,
|
||||
user_data: None,
|
||||
};
|
||||
|
||||
let swap_weth_usdc_v3_pool2 = Swap {
|
||||
component: ProtocolComponent {
|
||||
id: "0x8ad599c3A0ff1De082011EFDDc58f1908eb6e6D8".to_string(), /* USDC-WETH USV3
|
||||
* Pool 2 */
|
||||
protocol_system: "uniswap_v3".to_string(),
|
||||
static_attributes: {
|
||||
let mut attrs = HashMap::new();
|
||||
attrs.insert(
|
||||
"fee".to_string(),
|
||||
Bytes::from(BigInt::from(3000).to_signed_bytes_be()),
|
||||
);
|
||||
attrs
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
token_in: weth.clone(),
|
||||
token_out: usdc.clone(),
|
||||
split: 0.0f64,
|
||||
user_data: None,
|
||||
};
|
||||
|
||||
let encoder = get_tycho_router_encoder(UserTransferType::TransferFromPermit2);
|
||||
|
||||
let solution = Solution {
|
||||
exact_out: false,
|
||||
given_token: usdc.clone(),
|
||||
given_amount: BigUint::from_str("100000000").unwrap(), // 100 USDC (6 decimals)
|
||||
checked_token: usdc.clone(),
|
||||
checked_amount: BigUint::from_str("99025908").unwrap(), /* Expected output
|
||||
* from
|
||||
* test */
|
||||
sender: Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(),
|
||||
receiver: Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(),
|
||||
swaps: vec![swap_usdc_weth_v2, swap_weth_usdc_v3_pool1, swap_weth_usdc_v3_pool2],
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let encoded_solution = encoder
|
||||
.encode_solutions(vec![solution.clone()])
|
||||
.unwrap()[0]
|
||||
.clone();
|
||||
|
||||
let calldata = encode_tycho_router_call(
|
||||
eth_chain().id,
|
||||
encoded_solution,
|
||||
&solution,
|
||||
UserTransferType::TransferFromPermit2,
|
||||
eth(),
|
||||
Some(get_signer()),
|
||||
)
|
||||
.unwrap()
|
||||
.data;
|
||||
|
||||
let hex_calldata = alloy::hex::encode(&calldata);
|
||||
let expected_input = [
|
||||
"7c553846", // selector
|
||||
"0000000000000000000000000000000000000000000000000000000005f5e100", // given amount
|
||||
"000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // given token
|
||||
"000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // checked token
|
||||
"0000000000000000000000000000000000000000000000000000000005e703f4", // min amount out
|
||||
"0000000000000000000000000000000000000000000000000000000000000000", // wrap action
|
||||
"0000000000000000000000000000000000000000000000000000000000000000", // unwrap action
|
||||
"0000000000000000000000000000000000000000000000000000000000000002", // tokens length
|
||||
"000000000000000000000000cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver
|
||||
]
|
||||
.join("");
|
||||
|
||||
let expected_swaps = [
|
||||
"0000000000000000000000000000000000000000000000000000000000000139", // length of ple encoded swaps without padding
|
||||
"0057", // ple encoded swaps
|
||||
"00", // token in index
|
||||
"01", // token out index
|
||||
"000000", // split
|
||||
"5615deb798bb3e4dfa0139dfa1b3d433cc23b72f", // executor address
|
||||
"a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // token in
|
||||
"b4e16d0168e52d35cacd2c6185b44281ec28c9dc", // component id
|
||||
"3ede3eca2a72b3aecc820e955b36f38437d01395", // receiver
|
||||
"01", // zero2one
|
||||
"00", // transfer type TransferFrom
|
||||
"006e", // ple encoded swaps
|
||||
"01", // token in index
|
||||
"00", // token out index
|
||||
"999999", // split
|
||||
"2e234dae75c793f67a35089c9d99245e1c58470b", // executor address
|
||||
"c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // token in
|
||||
"a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // token out
|
||||
"0001f4", // pool fee
|
||||
"cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver
|
||||
"88e6a0c2ddd26feeb64f039a2c41296fcb3f5640", // component id
|
||||
"00", // zero2one
|
||||
"01", // transfer type Transfer
|
||||
"006e", // ple encoded swaps
|
||||
"01", // token in index
|
||||
"00", // token out index
|
||||
"000000", // split
|
||||
"2e234dae75c793f67a35089c9d99245e1c58470b", // executor address
|
||||
"c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", // token in
|
||||
"a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // token out
|
||||
"000bb8", // pool fee
|
||||
"cd09f75e2bf2a4d11f3ab23f1389fcc1621c0cc2", // receiver
|
||||
"8ad599c3a0ff1de082011efddc58f1908eb6e6d8", // component id
|
||||
"00", // zero2one
|
||||
"01", // transfer type Transfer
|
||||
"00000000000000" // padding
|
||||
]
|
||||
.join("");
|
||||
|
||||
assert_eq!(hex_calldata[..520], expected_input);
|
||||
assert_eq!(hex_calldata[1288..], expected_swaps);
|
||||
write_calldata_to_file("test_split_output_cyclic_swap", hex_calldata.as_str());
|
||||
}
|
||||
Reference in New Issue
Block a user