chore: Remove old execution and encoding files (#221)

They are unused now. See https://github.com/propeller-heads/tycho-execution for the new workflow
This commit is contained in:
greendianasaur
2025-06-24 14:37:00 +01:00
committed by GitHub
parent d4670d4312
commit cfbf6812bd
21 changed files with 0 additions and 1506 deletions

View File

@@ -1,132 +0,0 @@
// SPDX-License-Identifier: UNLICENCED
pragma solidity ^0.8.0;
import "../interfaces/ISwapExecutor.sol";
contract BalancerSwapExecutor is ISwapExecutor {
address private constant vaultAddress =
0xBA12222222228d8Ba445958a75a0704d566BF2C8;
bytes32 private constant swapSelector =
0x52bbbe2900000000000000000000000000000000000000000000000000000000;
bytes32 private constant maxUint256 =
0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
/**
* @dev Executes a Balancer swap.
* @param givenAmount how much of to swap, depending on exactOut either in-
* or outAmount.
* @param data the parameters of the swap. This data is roughly the packed
* encoding of
* the struct below:
* ```
* struct Params {
* // the token that the caller is selling
* IERC20 tokenIn;
*
* // the token that the caller is receiving in exchange
* IERC20 tokenOut;
*
* // the target pool id
* bytes32 poolId;
*
* // the receiver of `tokenOut`
* address receiver;
*
* // whether we want exactOut semantics
* bool exactOut;
*
* // whether we need to approve the pool to spend `tokenIn`
* bool tokenApprovalNeeded;
*
* }
* ```
*/
function swap(uint256 givenAmount, bytes calldata data)
external
payable
returns (uint256 calculatedAmount)
{
IERC20 tokenIn;
IERC20 tokenOut;
bytes32 poolId;
address receiver;
bool exactOut;
bool tokenApprovalNeeded;
assembly {
tokenIn := shr(96, calldataload(data.offset))
tokenOut := shr(96, calldataload(add(data.offset, 20)))
poolId := calldataload(add(data.offset, 40))
let dataLoad := calldataload(add(data.offset, 72))
receiver := shr(96, dataLoad)
exactOut := and(shr(88, dataLoad), 0xff)
tokenApprovalNeeded := and(shr(80, dataLoad), 0xff)
// Check if token approval is needed and perform the approval
if tokenApprovalNeeded {
// Prepare approve call
let approveCalldata := mload(0x40)
mstore(
approveCalldata,
0x095ea7b300000000000000000000000000000000000000000000000000000000
) // approve selector
mstore(add(approveCalldata, 4), vaultAddress) // spender
mstore(add(approveCalldata, 36), maxUint256) // value
// (maxUint256)
let success :=
call(gas(), tokenIn, 0, approveCalldata, 68, 0, 0)
if iszero(success) {
returndatacopy(0, 0, returndatasize())
revert(0, returndatasize())
}
}
let ptr := mload(0x40)
mstore(ptr, swapSelector)
//limit: as it is always recalculated during the swap, we use the
// extremums 0 tokenOut or max(uint256) tokenIn.
let limit := 0
if exactOut { limit := maxUint256 }
// as the singleSwap struct contains a bytes, it's considered as
// dynamic.
// dynamic values are encoded at the end of the calldata and have a
// corresponding offset at the beginning
// we first need to encode the offset of the singleSwap struct
mstore(add(ptr, 4), 0xe0)
// fundManagement.sender: is always address(this)
mstore(add(ptr, 36), address())
// fundManagement.fromInternalBalance
mstore(add(ptr, 68), 0)
// fundManagement.receiver
mstore(add(ptr, 100), receiver)
// fundManagement.toInternalBalance
mstore(add(ptr, 132), 0)
// limit
mstore(add(ptr, 164), limit)
// deadline
mstore(add(ptr, 196), timestamp())
// singleSwap.poolId
mstore(add(ptr, 228), poolId)
// singleSwap.exactOut
mstore(add(ptr, 260), exactOut)
// singleSwap.assetIn
mstore(add(ptr, 292), tokenIn)
// singleSwap.assetOut
mstore(add(ptr, 324), tokenOut)
// singleSwap.amount
mstore(add(ptr, 356), givenAmount)
// singleSwap.userData offset
mstore(add(ptr, 388), 0xc0)
// singleSwap.userData lenght
mstore(add(ptr, 420), 0)
let success := call(gas(), vaultAddress, 0, ptr, 452, ptr, 32)
switch success
case 0 {
returndatacopy(0, 0, returndatasize())
revert(0, returndatasize())
}
default { calculatedAmount := mload(ptr) }
}
}
}

View File

@@ -1,174 +0,0 @@
// SPDX-License-Identifier: UNLICENCED
pragma solidity ^0.8.0;
import "../interfaces/ISwapExecutor.sol";
import "./interfaces/ICurvePool.sol";
import "./interfaces/ICurvePoolNoReturn.sol";
import "./interfaces/ICurveCryptoPool.sol";
import "./interfaces/ICurvePoolNoReturn.sol";
import "./interfaces/ICurvePoolWithReturn.sol";
import {
IERC20,
SafeERC20
} from "openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol";
import "src/libraries/EfficientERC20.sol";
interface IWETH is IERC20 {
function deposit() external payable;
function withdraw(uint256) external;
}
contract CurveSwapExecutor is ISwapExecutor, ISwapExecutorErrors {
using EfficientERC20 for IERC20;
IWETH private constant weth =
IWETH(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);
address private constant ETH = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
function _decodeParams(bytes calldata data)
internal
pure
returns (
IERC20 tokenOut,
address target,
address receiver,
uint8 poolType,
int128 i,
int128 j,
bool tokenApprovalNeeded
)
{
tokenOut = IERC20(address(bytes20(data[0:20])));
target = address(bytes20(data[20:40]));
receiver = address(bytes20(data[40:60]));
poolType = uint8(data[60]);
i = int128(uint128(uint8(data[61])));
j = int128(uint128(uint8(data[62])));
tokenApprovalNeeded = data[63] != 0;
}
function swap(uint256 amountIn, bytes calldata data)
external
payable
returns (uint256 res)
{
(
IERC20 tokenOut,
address target,
address receiver,
uint8 poolType,
int128 i,
int128 j,
bool tokenApprovalNeeded
) = _decodeParams(data);
// Approve the token for the pool's address if `tokenApprovalNeeded` is
// true
if (tokenApprovalNeeded) {
address tokenIn;
// pool type 6 has a different function signature to get the coins
if (poolType == 6) {
tokenIn = ICurvePoolNoReturn(target).underlying_coins(int128(i));
} else {
tokenIn = ICurvePool(target).coins(uint256(uint128(i)));
}
IERC20(tokenIn).forceApprove(target, type(uint256).max);
}
if (poolType == 0) {
// simple exchange with int128
// e.g. AAVE, EURS
res = ICurvePoolWithReturn(target).exchange(i, j, amountIn, 0);
if (receiver != address(this)) {
tokenOut.safeTransfer(receiver, res);
}
} else if (poolType == 1) {
// simple exchange with int128 but no amountOut,
// e.g. BUSD, HBTC, PAX, renBTC, sBTC, SUSD, USDT, Y, 3pool
uint256 tokenOutBalanceBeforeSwap =
tokenOut.balanceOf(address(this));
ICurvePoolNoReturn(target).exchange(i, j, amountIn, 0);
uint256 tokenOutBalanceAfterSwap = tokenOut.balanceOf(address(this));
res = tokenOutBalanceAfterSwap - tokenOutBalanceBeforeSwap;
if (receiver != address(this)) {
tokenOut.safeTransfer(receiver, res);
}
} else if (poolType == 3) {
// tricrypto case
uint256 tokenOutBalanceBeforeSwap =
tokenOut.balanceOf(address(this));
ICurveCryptoPool(target).exchange(
uint256(uint128(i)),
uint256(uint128(j)),
amountIn,
0,
false //TODO: Check if we can call the entrypoint without
// 'use_eth' as it's false by default.
);
uint256 tokenOutBalanceAfterSwap = tokenOut.balanceOf(address(this));
res = tokenOutBalanceAfterSwap - tokenOutBalanceBeforeSwap;
if (receiver != address(this)) {
tokenOut.safeTransfer(receiver, res);
}
} else if (poolType == 4) {
// (payable) ether based stableswaps - so far no liquidity
// e.g. sETH, stETH, rETH, etc
ICurveCryptoPool pool = ICurveCryptoPool(target);
if (pool.coins(uint256(uint128(i))) == ETH) {
weth.withdraw(amountIn);
res = pool.exchange{value: amountIn}(i, j, amountIn, 0);
} else {
res = pool.exchange(i, j, amountIn, 0);
}
if (pool.coins(uint256(uint128(j))) == ETH) {
weth.deposit{value: res}();
}
if (receiver != address(this)) {
tokenOut.safeTransfer(receiver, res);
}
} else if (poolType == 5) {
// metapool or lending pool interface using int128
// e.g. AAVE
res = ICurvePoolWithReturn(target).exchange_underlying(
i, j, amountIn, 0
);
if (receiver != address(this)) {
tokenOut.safeTransfer(receiver, res);
}
} else if (poolType == 6) {
// metapool or lending pool interface using int128 no amountOut
// returned
// e.g. Y, Compound
uint256 tokenOutBalanceBeforeSwap =
tokenOut.balanceOf(address(this));
ICurvePoolNoReturn(target).exchange_underlying(i, j, amountIn, 0);
uint256 tokenOutBalanceAfterSwap = tokenOut.balanceOf(address(this));
res = tokenOutBalanceAfterSwap - tokenOutBalanceBeforeSwap;
if (receiver != address(this)) {
tokenOut.safeTransfer(receiver, res);
}
} else if (poolType == 7) {
// cryptov2 pool with two tokens
// e.g. LDO/ETH
res = ICurvePoolWithReturn(target).exchange(
uint256(uint128(i)),
uint256(uint128(j)),
amountIn,
0,
false,
receiver
);
} else if (poolType == 8) {
// cryptov2 two tokens not factory pools ETH/CRV and ETH/CVX
res = ICurvePoolWithReturn(target).exchange(
uint256(uint128(i)), uint256(uint128(j)), amountIn, 0, false
);
if (receiver != address(this)) {
tokenOut.safeTransfer(receiver, res);
}
} else {
revert UnknownPoolType(poolType);
}
}
}

View File

@@ -1,26 +0,0 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.0;
interface ICurveCryptoPool {
function get_dy(uint256 i, uint256 j, uint256 dx)
external
view
returns (uint256);
// tricrypto
function exchange(
uint256 i,
uint256 j,
uint256 dx,
uint256 min_dy,
bool use_eth
) external payable;
// eth accepting pools
function exchange(int128 i, int128 j, uint256 dx, uint256 min_dy)
external
payable
returns (uint256);
function coins(uint256 i) external view returns (address);
}

View File

@@ -1,174 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.4.0;
interface ICurvePool {
function initialize(
string memory _name,
string memory _symbol,
address _coin,
uint256 _decimals,
uint256 _A,
uint256 _fee,
address _admin
) external;
function decimals() external view returns (uint256);
function transfer(address _to, uint256 _value) external returns (bool);
function transferFrom(address _from, address _to, uint256 _value)
external
returns (bool);
function approve(address _spender, uint256 _value)
external
returns (bool);
function get_previous_balances()
external
view
returns (uint256[2] memory);
function get_balances() external view returns (uint256[2] memory);
function get_twap_balances(
uint256[2] memory _first_balances,
uint256[2] memory _last_balances,
uint256 _time_elapsed
) external view returns (uint256[2] memory);
function get_price_cumulative_last()
external
view
returns (uint256[2] memory);
function admin_fee() external view returns (uint256);
function A() external view returns (uint256);
function A_precise() external view returns (uint256);
function get_virtual_price() external view returns (uint256);
function calc_token_amount(uint256[2] memory _amounts, bool _is_deposit)
external
view
returns (uint256);
function calc_token_amount(
uint256[2] memory _amounts,
bool _is_deposit,
bool _previous
) external view returns (uint256);
function add_liquidity(uint256[2] memory _amounts, uint256 _min_mint_amount)
external
returns (uint256);
function add_liquidity(
uint256[2] memory _amounts,
uint256 _min_mint_amount,
address _receiver
) external returns (uint256);
function get_dy(int128 i, int128 j, uint256 dx)
external
view
returns (uint256);
function get_dy(int128 i, int128 j, uint256 dx, uint256[2] memory _balances)
external
view
returns (uint256);
function get_dy_underlying(int128 i, int128 j, uint256 dx)
external
view
returns (uint256);
function get_dy_underlying(
int128 i,
int128 j,
uint256 dx,
uint256[2] memory _balances
) external view returns (uint256);
function exchange(uint256 i, uint256 j, uint256 dx, uint256 min_dy)
external;
function exchange(
uint256 i,
uint256 j,
uint256 dx,
uint256 min_dy,
address _receiver
) external;
function exchange(int128 i, int128 j, uint256 dx, uint256 min_dy)
external;
function exchange(
int128 i,
int128 j,
uint256 dx,
uint256 min_dy,
address _receiver
) external;
function exchange_underlying(
uint256 i,
uint256 j,
uint256 dx,
uint256 min_dy
) external;
function exchange_underlying(
uint256 i,
uint256 j,
uint256 dx,
uint256 min_dy,
address _receiver
) external;
function exchange_underlying(int128 i, int128 j, uint256 dx, uint256 min_dy)
external;
function exchange_underlying(
int128 i,
int128 j,
uint256 dx,
uint256 min_dy,
address _receiver
) external;
function remove_liquidity(
uint256 _burn_amount,
uint256[2] memory _min_amounts
) external returns (uint256[2] memory);
function remove_liquidity(
uint256 _burn_amount,
uint256[2] memory _min_amounts,
address _receiver
) external returns (uint256[2] memory);
function remove_liquidity_imbalance(
uint256[2] memory _amounts,
uint256 _max_burn_amount
) external returns (uint256);
function remove_liquidity_imbalance(
uint256[2] memory _amounts,
uint256 _max_burn_amount,
address _receiver
) external returns (uint256);
function calc_withdraw_one_coin(uint256 _burn_amount, int128 i)
external
view
returns (uint256);
function calc_withdraw_one_coin(
uint256 _burn_amount,
int128 i,
bool _previous
) external view returns (uint256);
function remove_liquidity_one_coin(
uint256 _burn_amount,
int128 i,
uint256 _min_received
) external returns (uint256);
function remove_liquidity_one_coin(
uint256 _burn_amount,
int128 i,
uint256 _min_received,
address _receiver
) external returns (uint256);
function ramp_A(uint256 _future_A, uint256 _future_time) external;
function stop_ramp_A() external;
function admin_balances(uint256 i) external view returns (uint256);
function withdraw_admin_fees() external;
function admin() external view returns (address);
function coins(uint256 arg0) external view returns (address);
function balances(uint256 arg0) external view returns (uint256);
function fee() external view returns (uint256);
function block_timestamp_last() external view returns (uint256);
function initial_A() external view returns (uint256);
function future_A() external view returns (uint256);
function initial_A_time() external view returns (uint256);
function future_A_time() external view returns (uint256);
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function balanceOf(address arg0) external view returns (uint256);
function allowance(address arg0, address arg1)
external
view
returns (uint256);
function totalSupply() external view returns (uint256);
}

View File

@@ -1,22 +0,0 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.0;
interface ICurvePoolNoReturn {
function get_dy(int128 i, int128 j, uint256 dx)
external
view
returns (uint256);
function get_dy_underlying(int128 i, int128 j, uint256 dx)
external
view
returns (uint256);
function exchange(int128 i, int128 j, uint256 dx, uint256 min_dy)
external;
function exchange_underlying(int128 i, int128 j, uint256 dx, uint256 min_dy)
external;
function coins(int128 arg0) external view returns (address);
function underlying_coins(int128 arg0) external view returns (address);
}

View File

@@ -1,39 +0,0 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.0;
interface ICurvePoolWithReturn {
function get_dy(int128 i, int128 j, uint256 dx)
external
view
returns (uint256);
function get_dy_underlying(int128 i, int128 j, uint256 dx)
external
view
returns (uint256);
function exchange(int128 i, int128 j, uint256 dx, uint256 min_dy)
external
returns (uint256);
function exchange_underlying(int128 i, int128 j, uint256 dx, uint256 min_dy)
external
returns (uint256);
function exchange(
uint256 i,
uint256 j,
uint256 dx,
uint256 min_dy,
bool use_eth,
address receiver
) external returns (uint256);
function exchange(
uint256 i,
uint256 j,
uint256 dx,
uint256 min_dy,
bool use_eth
) external returns (uint256);
}

View File

@@ -1,81 +0,0 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;
import "./SwapExecutor.t.sol";
import "../src/balancer-v2/BalancerSwapExecutor.sol";
contract TestBalancerSwapExecutor is SwapExecutorTest {
BalancerSwapExecutor balancer;
IERC20 USDC = IERC20(USDC_ADDR);
IERC20 USDT = IERC20(USDT_ADDR);
constructor() {}
function setUp() public {
//Fork
uint256 forkBlock = 16000000;
vm.createSelectFork(vm.rpcUrl("mainnet"), forkBlock);
//Setup
balancer = new BalancerSwapExecutor();
}
function testBalancerSwap() public {
//Set up
uint256 sellAmount = 1000_000000;
uint256 expectedAmount = 998_919380; //Swap 1k USDT for 998 USDC
bool exactOut = false;
// This is required because balancer does a transferFrom sender.
// That also means we need to do this approval with our swapRouter.
bool tokenApprovalNeeded = true;
bytes memory protocolData = abi.encodePacked(
USDT_ADDR,
USDC_ADDR,
DAI_USDC_USDT_balancer,
bob,
exactOut,
tokenApprovalNeeded
);
// Logic
vm.prank(address(balancer));
deal(USDT_ADDR, address(balancer), sellAmount);
vm.prank(executor);
uint256 responseAmount = balancer.swap(sellAmount, protocolData);
//Assertions
assertEq(responseAmount, expectedAmount);
assertEq(USDC.balanceOf(bob), expectedAmount);
assertEq(USDT.balanceOf(address(balancer)), 0);
}
function testBalancerExactOutSwap() public {
//Set up
uint256 buyAmount = 1000_979168;
uint256 expectedSellAmount = 1000 * 10 ** 6;
bool exactOut = true;
bool tokenApprovalNeeded = true;
bytes memory protocolData = abi.encodePacked(
USDC_ADDR,
USDT_ADDR,
DAI_USDC_USDT_balancer,
bob,
exactOut,
tokenApprovalNeeded
);
//Logic
// This is required because balancer does a transferFrom sender.
// That also means we need to do this approval with our swapRouter.
vm.prank(address(balancer));
deal(USDC_ADDR, address(balancer), expectedSellAmount);
vm.prank(executor);
uint256 responseAmount = balancer.swap(buyAmount, protocolData);
// //Assertions
assertEq(responseAmount, expectedSellAmount);
assertEq(USDT.balanceOf(bob), buyAmount);
assertEq(USDC.balanceOf(address(balancer)), 0);
}
}

View File

@@ -1,303 +0,0 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;
import "./SwapExecutor.t.sol";
import "../src/curve/CurveSwapExecutor.sol";
contract CurveSwapExecutorExposed is CurveSwapExecutor {
function decodeParams(bytes calldata data)
external
pure
returns (
IERC20 tokenOut,
address target,
address receiver,
uint8 poolType,
int128 i,
int128 j,
bool tokenApprovalNeeded
)
{
return _decodeParams(data);
}
}
contract CurveSwapExecutorPayable is CurveSwapExecutor {
receive() external payable {}
}
interface ILendingPool {
function deposit(
address asset,
uint256 amount,
address onBehalfOf,
uint16 referralCode
) external;
function withdraw(address asset, uint256 amount, address to)
external
returns (uint256);
}
contract TestCurveSwapExecutor is SwapExecutorTest {
CurveSwapExecutor swapMethod;
address swapMethodAddress;
// type 0 pool
address aDAI_ADDR = 0x028171bCA77440897B824Ca71D1c56caC55b68A3;
address aUSDC_ADDR = 0xBcca60bB61934080951369a648Fb03DF4F96263C;
IERC20 aDAI = IERC20(aDAI_ADDR);
IERC20 aUSDC = IERC20(aUSDC_ADDR);
address AAVE_POOL = 0xDeBF20617708857ebe4F679508E7b7863a8A8EeE;
// type 1 - 3pool
IERC20 DAI = IERC20(DAI_ADDR);
IERC20 USDC = IERC20(USDC_ADDR);
address THREE_POOL = 0xbEbc44782C7dB0a1A60Cb6fe97d0b483032FF1C7;
// type 3 - tricrypto case
IERC20 WETH = IERC20(WETH_ADDR);
IERC20 WBTC = IERC20(WBTC_ADDR);
address TRICRYPTO_POOL = 0xD51a44d3FaE010294C616388b506AcdA1bfAAE46;
// type 4 - stETH
address stETH_ADDR = 0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84;
IERC20 stETH = IERC20(stETH_ADDR);
address stETH_POOL = 0xDC24316b9AE028F1497c275EB9192a3Ea0f67022;
// type 5 - LUSD
address LUSD_ADDR = 0x5f98805A4E8be255a32880FDeC7F6728C6568bA0;
IERC20 LUSD = IERC20(LUSD_ADDR);
IERC20 USDT = IERC20(USDT_ADDR);
address LUSD_POOL = 0xEd279fDD11cA84bEef15AF5D39BB4d4bEE23F0cA;
// type 6 - compound
address CPOOL = 0xA2B47E3D5c44877cca798226B7B8118F9BFb7A56;
// type 7
address LDO_POOL = 0x9409280DC1e6D33AB7A8C6EC03e5763FB61772B5;
IERC20 LDO = IERC20(LDO_ADDR);
// type 8
address CRV_POOL = 0x8301AE4fc9c624d1D396cbDAa1ed877821D7C511;
IERC20 CRV = IERC20(CRV_ADDR);
function setUp() public {
//Fork
uint256 forkBlock = 16000000;
vm.createSelectFork(vm.rpcUrl("mainnet"), forkBlock);
//Setup
swapMethod = new CurveSwapExecutor();
swapMethodAddress = address(swapMethod);
vm.makePersistent(swapMethodAddress);
}
// foundry deal doesn't work with the atokens:
// https://github.com/foundry-rs/forge-std/issues/140
function dealAaveDai() internal {
deal(DAI_ADDR, swapMethodAddress, 100_000 * 10 ** 18);
ILendingPool aave =
ILendingPool(0x7d2768dE32b0b80b7a3454c06BdAc94A69DDc7A9);
vm.startPrank(swapMethodAddress);
DAI.approve(address(aave), type(uint256).max);
aave.deposit(DAI_ADDR, 100_000 * 10 ** 18, swapMethodAddress, 0);
vm.stopPrank();
}
function testSwapType0() public {
dealAaveDai();
IERC20[] memory tokens = twoTokens(aDAI_ADDR, aUSDC_ADDR);
uint256 expAmountOut = 999647;
address receiver = bob;
bytes memory data =
getDataCurve(tokens[1], AAVE_POOL, receiver, 1, 0, 1, true);
uint256 amountOut = swapMethod.swap(10 ** 18, data);
uint256 finalBalance = aUSDC.balanceOf(receiver);
assertGe(finalBalance, expAmountOut);
assertEq(amountOut, expAmountOut);
}
// 3pool
function testSwapType1() public {
deal(DAI_ADDR, swapMethodAddress, 10_000 * 10 ** 18);
IERC20[] memory tokens = twoTokens(DAI_ADDR, USDC_ADDR);
uint256 expAmountOut = 999963;
address receiver = bob;
bytes memory data =
getDataCurve(tokens[1], THREE_POOL, receiver, 1, 0, 1, true);
uint256 amountOut = swapMethod.swap(10 ** 18, data);
uint256 finalBalance = USDC.balanceOf(receiver);
assertGe(finalBalance, expAmountOut);
assertEq(amountOut, expAmountOut);
}
// tricrypto
function testSwapType3() public {
deal(USDT_ADDR, swapMethodAddress, 10_000 * 10 ** 6);
IERC20[] memory tokens = twoTokens(USDT_ADDR, WBTC_ADDR);
uint256 expAmountOut = 60232482;
address receiver = bob;
bytes memory data =
getDataCurve(tokens[1], TRICRYPTO_POOL, receiver, 3, 0, 1, true);
uint256 amountOut = swapMethod.swap(10_000 * 10 ** 6, data);
uint256 finalBalance = WBTC.balanceOf(receiver);
assertGe(finalBalance, expAmountOut);
assertEq(amountOut, expAmountOut);
}
// stETH/ETH pool
function testSwapType4() public {
CurveSwapExecutorPayable swapMethodPayable =
new CurveSwapExecutorPayable();
address swapMethodPayableAddress = address(swapMethodPayable);
deal(WETH_ADDR, swapMethodPayableAddress, 100 * 10 ** 18);
IERC20[] memory tokens = twoTokens(WETH_ADDR, stETH_ADDR);
uint256 expAmountOut = 1011264689661846353;
bytes memory data = getDataCurve(
tokens[1], stETH_POOL, swapMethodPayableAddress, 4, 0, 1, false
);
vm.prank(swapMethodPayableAddress);
uint256 amountOut = swapMethodPayable.swap(10 ** 18, data);
uint256 finalBalance = stETH.balanceOf(swapMethodPayableAddress);
assertGe(finalBalance, expAmountOut);
// There is something weird with
// stETH that it gives me 1 Wei more here sometimes
assertGe(amountOut, expAmountOut);
// part 2 swap back stETH
tokens = twoTokens(stETH_ADDR, WETH_ADDR);
expAmountOut = 988069860569702379;
address receiver = bob;
data = getDataCurve(tokens[1], stETH_POOL, receiver, 4, 1, 0, true);
uint256 initialBalance = WETH.balanceOf(receiver);
amountOut = swapMethodPayable.swap(10 ** 18, data);
finalBalance = WETH.balanceOf(receiver) - initialBalance;
assertGe(finalBalance, expAmountOut);
assertEq(amountOut, expAmountOut);
}
// // metapool - LUSD
function testSwapType5() public {
deal(LUSD_ADDR, swapMethodAddress, 10_000 * 10 ** 18);
IERC20[] memory tokens = twoTokens(LUSD_ADDR, USDT_ADDR);
uint256 expAmountOut = 1035119;
address receiver = bob;
bytes memory data =
getDataCurve(tokens[1], LUSD_POOL, receiver, 5, 0, 3, true);
uint256 amountOut = swapMethod.swap(10 ** 18, data);
uint256 finalBalance = USDT.balanceOf(receiver);
assertGe(finalBalance, expAmountOut);
assertEq(amountOut, expAmountOut);
}
// Compound
function testSwapType6() public {
deal(DAI_ADDR, swapMethodAddress, 10_000 * 10 ** 18);
IERC20[] memory tokens = twoTokens(DAI_ADDR, USDC_ADDR);
uint256 expAmountOut = 999430;
address receiver = bob;
bytes memory data =
getDataCurve(tokens[1], CPOOL, receiver, 6, 0, 1, true);
uint256 amountOut = swapMethod.swap(10 ** 18, data);
uint256 finalBalance = USDC.balanceOf(receiver);
assertGe(finalBalance, expAmountOut);
assertEq(amountOut, expAmountOut);
}
// Curve v2
function testSwapType7() public {
vm.rollFork(17_000_000); //change block because this pool wasn't
// deployed at block 16M
uint256 amountIn = 10 ** 18;
uint256 expAmountOut = 743676671921315909289;
address receiver = bob;
deal(WETH_ADDR, swapMethodAddress, amountIn);
bytes memory data = abi.encodePacked(
getDataCurve(LDO, LDO_POOL, receiver, 7, 0, 1, true), receiver
);
uint256 amountOut = swapMethod.swap(amountIn, data);
uint256 finalBalance = LDO.balanceOf(bob);
assertGe(finalBalance, expAmountOut);
assertEq(amountOut, expAmountOut);
}
// Curve v2 2 token not factory pool
function testSwapType8() public {
vm.rollFork(17_000_000); //change block because this pool wasn't
// deployed at block 16M
uint256 amountIn = 10 ** 18;
uint256 expAmountOut = 1831110768300490995125;
address receiver = bob;
deal(WETH_ADDR, swapMethodAddress, amountIn);
bytes memory data = abi.encodePacked(
getDataCurve(CRV, CRV_POOL, receiver, 8, 0, 1, true), receiver
);
uint256 amountOut = swapMethod.swap(amountIn, data);
uint256 finalBalance = CRV.balanceOf(bob);
assertGe(finalBalance, expAmountOut);
assertEq(amountOut, expAmountOut);
}
function testDecodeParams() public {
CurveSwapExecutorExposed swapMethodExposed =
new CurveSwapExecutorExposed();
//Logic
bytes memory data = getDataCurve(LDO, LDO_POOL, bob, 7, 0, 1, true);
(
IERC20 tokenOut,
address target,
address receiver,
uint8 poolType,
int128 i,
int128 j,
bool tokenApprovalNeeded
) = swapMethodExposed.decodeParams(data);
//Assertions
assertEq(address(tokenOut), LDO_ADDR);
assertEq(address(target), LDO_POOL);
assertEq(address(receiver), bob);
assertEq(poolType, 7);
assertEq(i, 0);
assertEq(j, 1);
assertEq(tokenApprovalNeeded, true);
}
function getDataCurve(
IERC20 tokenOut,
address pool,
address receiver,
uint8 poolType,
uint8 i,
uint8 j,
bool tokenApprovalNeeded
) internal pure returns (bytes memory data) {
data = abi.encodePacked(
tokenOut, pool, receiver, poolType, i, j, tokenApprovalNeeded
);
}
}

View File

@@ -1,18 +0,0 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;
import "forge-std/Test.sol";
import "openzeppelin-contracts/contracts/interfaces/IERC20.sol";
import "./Constants.sol";
contract SwapExecutorTest is Test, Constants {
function twoTokens(address token0, address token1)
internal
pure
returns (IERC20[] memory tokens)
{
tokens = new IERC20[](2);
tokens[0] = IERC20(token0);
tokens[1] = IERC20(token1);
}
}