Merge branch 'main' into feature/gas-optimization
This commit is contained in:
2
.github/workflows/slither.yml
vendored
2
.github/workflows/slither.yml
vendored
@@ -17,4 +17,4 @@ jobs:
|
|||||||
- uses: crytic/slither-action@f197989dea5b53e986d0f88c60a034ddd77ec9a8
|
- uses: crytic/slither-action@f197989dea5b53e986d0f88c60a034ddd77ec9a8
|
||||||
with:
|
with:
|
||||||
target: 'foundry/'
|
target: 'foundry/'
|
||||||
slither-args: '--filter-paths foundry/lib/'
|
slither-args: '--filter-paths foundry/lib/'
|
||||||
17
CHANGELOG.md
17
CHANGELOG.md
@@ -1,3 +1,20 @@
|
|||||||
|
## [0.77.0](https://github.com/propeller-heads/tycho-execution/compare/0.76.0...0.77.0) (2025-04-07)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* add curve executor with router tests ([7cde513](https://github.com/propeller-heads/tycho-execution/commit/7cde5130d6038916dcb4a6a96c723c366b90da12))
|
||||||
|
* allow executor to do native swaps, add diff pool type tests ([93bdc86](https://github.com/propeller-heads/tycho-execution/commit/93bdc86dc665e02d877bec1b749ee5cf7a399e32))
|
||||||
|
* Refactor Curve Executor not to use the router ([9f21842](https://github.com/propeller-heads/tycho-execution/commit/9f2184258aab968f7d83df8a443c1a77b87a3e4c))
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* fix slither CI action ([42d1ab3](https://github.com/propeller-heads/tycho-execution/commit/42d1ab36fd71af7a10d17120e5f14edce9f6422a))
|
||||||
|
* Improve curve executor tests and docstrings ([f468a78](https://github.com/propeller-heads/tycho-execution/commit/f468a7831a86eef96682504bc93207f33b28cf17))
|
||||||
|
* Remove unnecessary test method ([49aefc8](https://github.com/propeller-heads/tycho-execution/commit/49aefc8c2ab25864b4056f44738a96c3905f8396))
|
||||||
|
* resolve pr comments ([9e2a9f5](https://github.com/propeller-heads/tycho-execution/commit/9e2a9f5329f798990d4dde3e7e76af4896aef6f6))
|
||||||
|
|
||||||
## [0.76.0](https://github.com/propeller-heads/tycho-execution/compare/0.75.1...0.76.0) (2025-04-03)
|
## [0.76.0](https://github.com/propeller-heads/tycho-execution/compare/0.75.1...0.76.0) (2025-04-03)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -4341,7 +4341,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tycho-execution"
|
name = "tycho-execution"
|
||||||
version = "0.76.0"
|
version = "0.77.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"alloy",
|
"alloy",
|
||||||
"alloy-primitives",
|
"alloy-primitives",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "tycho-execution"
|
name = "tycho-execution"
|
||||||
version = "0.76.0"
|
version = "0.77.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
description = "Provides tools for encoding and executing swaps against Tycho router and protocol executors."
|
description = "Provides tools for encoding and executing swaps against Tycho router and protocol executors."
|
||||||
repository = "https://github.com/propeller-heads/tycho-execution"
|
repository = "https://github.com/propeller-heads/tycho-execution"
|
||||||
|
|||||||
133
foundry/src/executors/CurveExecutor.sol
Normal file
133
foundry/src/executors/CurveExecutor.sol
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
// SPDX-License-Identifier: BUSL-1.1
|
||||||
|
pragma solidity ^0.8.26;
|
||||||
|
|
||||||
|
import "@interfaces/IExecutor.sol";
|
||||||
|
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
|
||||||
|
|
||||||
|
error CurveExecutor__InvalidAddresses();
|
||||||
|
|
||||||
|
interface CryptoPool {
|
||||||
|
// slither-disable-next-line naming-convention
|
||||||
|
function exchange(uint256 i, uint256 j, uint256 dx, uint256 min_dy)
|
||||||
|
external
|
||||||
|
payable;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface StablePool {
|
||||||
|
// slither-disable-next-line naming-convention
|
||||||
|
function exchange(int128 i, int128 j, uint256 dx, uint256 min_dy)
|
||||||
|
external
|
||||||
|
payable;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CryptoPoolETH {
|
||||||
|
// slither-disable-start naming-convention
|
||||||
|
function exchange(
|
||||||
|
uint256 i,
|
||||||
|
uint256 j,
|
||||||
|
uint256 dx,
|
||||||
|
uint256 min_dy,
|
||||||
|
bool use_eth
|
||||||
|
) external payable;
|
||||||
|
// slither-disable-end naming-convention
|
||||||
|
}
|
||||||
|
|
||||||
|
contract CurveExecutor is IExecutor {
|
||||||
|
using SafeERC20 for IERC20;
|
||||||
|
|
||||||
|
address public immutable nativeToken;
|
||||||
|
|
||||||
|
constructor(address _nativeToken) {
|
||||||
|
if (_nativeToken == address(0)) {
|
||||||
|
revert CurveExecutor__InvalidAddresses();
|
||||||
|
}
|
||||||
|
nativeToken = _nativeToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
// slither-disable-next-line locked-ether
|
||||||
|
function swap(uint256 amountIn, bytes calldata data)
|
||||||
|
external
|
||||||
|
payable
|
||||||
|
returns (uint256)
|
||||||
|
{
|
||||||
|
(
|
||||||
|
address tokenIn,
|
||||||
|
address tokenOut,
|
||||||
|
address pool,
|
||||||
|
uint8 poolType,
|
||||||
|
int128 i,
|
||||||
|
int128 j,
|
||||||
|
bool tokenApprovalNeeded
|
||||||
|
) = _decodeData(data);
|
||||||
|
|
||||||
|
if (tokenApprovalNeeded && tokenIn != nativeToken) {
|
||||||
|
// slither-disable-next-line unused-return
|
||||||
|
IERC20(tokenIn).approve(address(pool), type(uint256).max);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Inspired by Curve's router contract: https://github.com/curvefi/curve-router-ng/blob/9ab006ca848fc7f1995b6fbbecfecc1e0eb29e2a/contracts/Router.vy#L44
|
||||||
|
uint256 balanceBefore = _balanceOf(tokenOut);
|
||||||
|
|
||||||
|
uint256 ethAmount = 0;
|
||||||
|
if (tokenIn == nativeToken) {
|
||||||
|
ethAmount = amountIn;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (poolType == 1 || poolType == 10) {
|
||||||
|
// stable and stable_ng
|
||||||
|
// slither-disable-next-line arbitrary-send-eth
|
||||||
|
StablePool(pool).exchange{value: ethAmount}(i, j, amountIn, 0);
|
||||||
|
} else {
|
||||||
|
// crypto or llamma
|
||||||
|
if (tokenIn == nativeToken || tokenOut == nativeToken) {
|
||||||
|
// slither-disable-next-line arbitrary-send-eth
|
||||||
|
CryptoPoolETH(pool).exchange{value: ethAmount}(
|
||||||
|
uint256(int256(i)), uint256(int256(j)), amountIn, 0, true
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
CryptoPool(pool).exchange(
|
||||||
|
uint256(int256(i)), uint256(int256(j)), amountIn, 0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint256 balanceAfter = _balanceOf(tokenOut);
|
||||||
|
return balanceAfter - balanceBefore;
|
||||||
|
}
|
||||||
|
|
||||||
|
function _decodeData(bytes calldata data)
|
||||||
|
internal
|
||||||
|
pure
|
||||||
|
returns (
|
||||||
|
address tokenIn,
|
||||||
|
address tokenOut,
|
||||||
|
address pool,
|
||||||
|
uint8 poolType,
|
||||||
|
int128 i,
|
||||||
|
int128 j,
|
||||||
|
bool tokenApprovalNeeded
|
||||||
|
)
|
||||||
|
{
|
||||||
|
tokenIn = address(bytes20(data[0:20]));
|
||||||
|
tokenOut = address(bytes20(data[20:40]));
|
||||||
|
pool = 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
receive() external payable {
|
||||||
|
require(msg.sender.code.length != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function _balanceOf(address token)
|
||||||
|
internal
|
||||||
|
view
|
||||||
|
returns (uint256 balance)
|
||||||
|
{
|
||||||
|
balance = token == nativeToken
|
||||||
|
? address(this).balance
|
||||||
|
: IERC20(token).balanceOf(address(this));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -30,6 +30,7 @@ contract Constants is Test, BaseConstants {
|
|||||||
address UNPAUSER = makeAddr("unpauser");
|
address UNPAUSER = makeAddr("unpauser");
|
||||||
|
|
||||||
// Assets
|
// Assets
|
||||||
|
address ETH_ADDR = address(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE);
|
||||||
address WETH_ADDR = address(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);
|
address WETH_ADDR = address(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);
|
||||||
address DAI_ADDR = address(0x6B175474E89094C44Da98b954EedeAC495271d0F);
|
address DAI_ADDR = address(0x6B175474E89094C44Da98b954EedeAC495271d0F);
|
||||||
address BAL_ADDR = address(0xba100000625a3754423978a60c9317c58a424e3D);
|
address BAL_ADDR = address(0xba100000625a3754423978a60c9317c58a424e3D);
|
||||||
@@ -39,7 +40,21 @@ contract Constants is Test, BaseConstants {
|
|||||||
address USDE_ADDR = address(0x4c9EDD5852cd905f086C759E8383e09bff1E68B3);
|
address USDE_ADDR = address(0x4c9EDD5852cd905f086C759E8383e09bff1E68B3);
|
||||||
address USDT_ADDR = address(0xdAC17F958D2ee523a2206206994597C13D831ec7);
|
address USDT_ADDR = address(0xdAC17F958D2ee523a2206206994597C13D831ec7);
|
||||||
address PEPE_ADDR = address(0x6982508145454Ce325dDbE47a25d4ec3d2311933);
|
address PEPE_ADDR = address(0x6982508145454Ce325dDbE47a25d4ec3d2311933);
|
||||||
|
address STETH_ADDR = address(0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84);
|
||||||
|
address LUSD_ADDR = address(0x5f98805A4E8be255a32880FDeC7F6728C6568bA0);
|
||||||
|
address LDO_ADDR = address(0x5A98FcBEA516Cf06857215779Fd812CA3beF1B32);
|
||||||
|
address CRV_ADDR = address(0xD533a949740bb3306d119CC777fa900bA034cd52);
|
||||||
|
address ADAI_ADDR = address(0x028171bCA77440897B824Ca71D1c56caC55b68A3);
|
||||||
|
address AUSDC_ADDR = address(0xBcca60bB61934080951369a648Fb03DF4F96263C);
|
||||||
|
address SUSD_ADDR = address(0x57Ab1ec28D129707052df4dF418D58a2D46d5f51);
|
||||||
|
address FRAX_ADDR = address(0x853d955aCEf822Db058eb8505911ED77F175b99e);
|
||||||
|
address DOLA_ADDR = address(0x865377367054516e17014CcdED1e7d814EDC9ce4);
|
||||||
|
address XYO_ADDR = address(0x55296f69f40Ea6d20E478533C15A6B08B654E758);
|
||||||
|
address UWU_ADDR = address(0x55C08ca52497e2f1534B59E2917BF524D4765257);
|
||||||
|
address CRVUSD_ADDR = address(0xf939E0A03FB07F59A73314E73794Be0E57ac1b4E);
|
||||||
|
address WSTTAO_ADDR = address(0xe9633C52f4c8B7BDeb08c4A7fE8a5c1B84AFCf67);
|
||||||
|
address WTAO_ADDR = address(0x77E06c9eCCf2E797fd462A92B6D7642EF85b0A44);
|
||||||
|
address BSGG_ADDR = address(0xdA16Cf041E2780618c49Dbae5d734B89a6Bac9b3);
|
||||||
// Uniswap v2
|
// Uniswap v2
|
||||||
address WETH_DAI_POOL = 0xA478c2975Ab1Ea89e8196811F51A7B7Ade33eB11;
|
address WETH_DAI_POOL = 0xA478c2975Ab1Ea89e8196811F51A7B7Ade33eB11;
|
||||||
address DAI_USDC_POOL = 0xAE461cA67B15dc8dc81CE7615e0320dA1A9aB8D5;
|
address DAI_USDC_POOL = 0xAE461cA67B15dc8dc81CE7615e0320dA1A9aB8D5;
|
||||||
@@ -76,6 +91,27 @@ contract Constants is Test, BaseConstants {
|
|||||||
address PANCAKESWAPV3_DEPLOYER_ETHEREUM =
|
address PANCAKESWAPV3_DEPLOYER_ETHEREUM =
|
||||||
0x41ff9AA7e16B8B1a8a8dc4f0eFacd93D02d071c9;
|
0x41ff9AA7e16B8B1a8a8dc4f0eFacd93D02d071c9;
|
||||||
|
|
||||||
|
// Curve
|
||||||
|
address TRIPOOL = 0xbEbc44782C7dB0a1A60Cb6fe97d0b483032FF1C7;
|
||||||
|
address TRICRYPTO_POOL = 0x7F86Bf177Dd4F3494b841a37e810A34dD56c829B;
|
||||||
|
address STETH_POOL = 0xDC24316b9AE028F1497c275EB9192a3Ea0f67022;
|
||||||
|
address LUSD_POOL = 0xEd279fDD11cA84bEef15AF5D39BB4d4bEE23F0cA;
|
||||||
|
address CPOOL = 0xA2B47E3D5c44877cca798226B7B8118F9BFb7A56;
|
||||||
|
address LDO_POOL = 0x9409280DC1e6D33AB7A8C6EC03e5763FB61772B5;
|
||||||
|
address CRV_POOL = 0x8301AE4fc9c624d1D396cbDAa1ed877821D7C511;
|
||||||
|
address AAVE_POOL = 0xDeBF20617708857ebe4F679508E7b7863a8A8EeE;
|
||||||
|
address FRAXPYUSD_POOL = address(0xA5588F7cdf560811710A2D82D3C9c99769DB1Dcb);
|
||||||
|
address TRICRYPTO2_POOL = 0xD51a44d3FaE010294C616388b506AcdA1bfAAE46;
|
||||||
|
address SUSD_POOL = 0xA5407eAE9Ba41422680e2e00537571bcC53efBfD;
|
||||||
|
address FRAX_USDC_POOL = 0xDcEF968d416a41Cdac0ED8702fAC8128A64241A2;
|
||||||
|
address USDE_USDC_POOL = 0x02950460E2b9529D0E00284A5fA2d7bDF3fA4d72;
|
||||||
|
address DOLA_FRAXPYUSD_POOL = 0xef484de8C07B6e2d732A92B5F78e81B38f99f95E;
|
||||||
|
address ETH_XYO_POOL = 0x99e09ee2d6Bb16c0F5ADDfEA649dbB2C1d524624;
|
||||||
|
address UWU_WETH_POOL = 0x77146B0a1d08B6844376dF6d9da99bA7F1b19e71;
|
||||||
|
address CRVUSD_USDT_POOL = 0x390f3595bCa2Df7d23783dFd126427CCeb997BF4;
|
||||||
|
address WSTTAO_WTAO_POOL = 0xf2DCf6336D8250754B4527f57b275b19c8D5CF88;
|
||||||
|
address BSGG_USDT_POOL = 0x5500307Bcf134E5851FB4D7D8D1Dc556dCdB84B4;
|
||||||
|
|
||||||
// Uniswap universal router
|
// Uniswap universal router
|
||||||
address UNIVERSAL_ROUTER = 0x66a9893cC07D91D95644AEDD05D03f95e1dBA8Af;
|
address UNIVERSAL_ROUTER = 0x66a9893cC07D91D95644AEDD05D03f95e1dBA8Af;
|
||||||
|
|
||||||
@@ -94,6 +130,9 @@ contract Constants is Test, BaseConstants {
|
|||||||
bytes32 PANCAKEV3_POOL_CODE_INIT_HASH =
|
bytes32 PANCAKEV3_POOL_CODE_INIT_HASH =
|
||||||
0x6ce8eb472fa82df5469c6ab6d485f17c3ad13c8cd7af59b3d4a8026c5ce0f7e2;
|
0x6ce8eb472fa82df5469c6ab6d485f17c3ad13c8cd7af59b3d4a8026c5ce0f7e2;
|
||||||
|
|
||||||
|
// Curve meta registry
|
||||||
|
address CURVE_META_REGISTRY = 0xF98B45FA17DE75FB1aD0e7aFD971b0ca00e379fC;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dev Deploys a dummy contract with non-empty bytecode
|
* @dev Deploys a dummy contract with non-empty bytecode
|
||||||
*/
|
*/
|
||||||
|
|||||||
338
foundry/test/executors/CurveExecutor.t.sol
Normal file
338
foundry/test/executors/CurveExecutor.t.sol
Normal file
@@ -0,0 +1,338 @@
|
|||||||
|
// SPDX-License-Identifier: BUSL-1.1
|
||||||
|
pragma solidity ^0.8.26;
|
||||||
|
|
||||||
|
import "@src/executors/CurveExecutor.sol";
|
||||||
|
import {Test} from "../../lib/forge-std/src/Test.sol";
|
||||||
|
import {Constants} from "../Constants.sol";
|
||||||
|
|
||||||
|
interface ICurvePool {
|
||||||
|
function coins(uint256 i) external view returns (address);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Curve pool registry
|
||||||
|
// This is the registry that contains the information about the pool
|
||||||
|
// The naming convention is different because it is in vyper
|
||||||
|
interface MetaRegistry {
|
||||||
|
function get_n_coins(address pool) external view returns (uint256);
|
||||||
|
|
||||||
|
function get_coin_indices(address pool, address from, address to)
|
||||||
|
external
|
||||||
|
view
|
||||||
|
returns (int128, int128, bool);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IAaveLendingPool {
|
||||||
|
function deposit(
|
||||||
|
address asset,
|
||||||
|
uint256 amount,
|
||||||
|
address onBehalfOf,
|
||||||
|
uint16 referralCode
|
||||||
|
) external;
|
||||||
|
|
||||||
|
function withdraw(address asset, uint256 amount, address to)
|
||||||
|
external
|
||||||
|
returns (uint256);
|
||||||
|
}
|
||||||
|
|
||||||
|
contract CurveExecutorExposed is CurveExecutor {
|
||||||
|
constructor(address _nativeToken) CurveExecutor(_nativeToken) {}
|
||||||
|
|
||||||
|
function decodeData(bytes calldata data)
|
||||||
|
external
|
||||||
|
pure
|
||||||
|
returns (
|
||||||
|
address tokenIn,
|
||||||
|
address tokenOut,
|
||||||
|
address pool,
|
||||||
|
uint8 poolType,
|
||||||
|
int128 i,
|
||||||
|
int128 j,
|
||||||
|
bool tokenApprovalNeeded
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return _decodeData(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
contract CurveExecutorTest is Test, Constants {
|
||||||
|
using SafeERC20 for IERC20;
|
||||||
|
|
||||||
|
CurveExecutorExposed curveExecutorExposed;
|
||||||
|
MetaRegistry metaRegistry;
|
||||||
|
|
||||||
|
function setUp() public {
|
||||||
|
uint256 forkBlock = 22031795;
|
||||||
|
vm.createSelectFork(vm.rpcUrl("mainnet"), forkBlock);
|
||||||
|
curveExecutorExposed = new CurveExecutorExposed(ETH_ADDR);
|
||||||
|
metaRegistry = MetaRegistry(CURVE_META_REGISTRY);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testDecodeParams() public view {
|
||||||
|
bytes memory data = abi.encodePacked(
|
||||||
|
WETH_ADDR,
|
||||||
|
USDC_ADDR,
|
||||||
|
TRICRYPTO_POOL,
|
||||||
|
uint8(3),
|
||||||
|
uint8(2),
|
||||||
|
uint8(0),
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
(
|
||||||
|
address tokenIn,
|
||||||
|
address tokenOut,
|
||||||
|
address pool,
|
||||||
|
uint8 poolType,
|
||||||
|
int128 i,
|
||||||
|
int128 j,
|
||||||
|
bool tokenApprovalNeeded
|
||||||
|
) = curveExecutorExposed.decodeData(data);
|
||||||
|
|
||||||
|
assertEq(tokenIn, WETH_ADDR);
|
||||||
|
assertEq(tokenOut, USDC_ADDR);
|
||||||
|
assertEq(pool, TRICRYPTO_POOL);
|
||||||
|
assertEq(poolType, 3);
|
||||||
|
assertEq(i, 2);
|
||||||
|
assertEq(j, 0);
|
||||||
|
assertEq(tokenApprovalNeeded, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testTriPool() public {
|
||||||
|
// Swapping DAI -> USDC on TriPool 0xbEbc44782C7dB0a1A60Cb6fe97d0b483032FF1C7
|
||||||
|
uint256 amountIn = 1 ether;
|
||||||
|
deal(DAI_ADDR, address(curveExecutorExposed), amountIn);
|
||||||
|
|
||||||
|
bytes memory data = _getData(DAI_ADDR, USDC_ADDR, TRIPOOL, 1);
|
||||||
|
|
||||||
|
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
||||||
|
|
||||||
|
assertEq(amountOut, 999797);
|
||||||
|
assertEq(
|
||||||
|
IERC20(USDC_ADDR).balanceOf(address(curveExecutorExposed)),
|
||||||
|
amountOut
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testStEthPool() public {
|
||||||
|
// Swapping ETH -> stETH on StEthPool 0xDC24316b9AE028F1497c275EB9192a3Ea0f67022
|
||||||
|
uint256 amountIn = 1 ether;
|
||||||
|
deal(address(curveExecutorExposed), amountIn);
|
||||||
|
|
||||||
|
bytes memory data = _getData(ETH_ADDR, STETH_ADDR, STETH_POOL, 1);
|
||||||
|
|
||||||
|
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
||||||
|
|
||||||
|
assertEq(amountOut, 1001072414418410897);
|
||||||
|
assertEq(
|
||||||
|
IERC20(STETH_ADDR).balanceOf(address(curveExecutorExposed)),
|
||||||
|
amountOut
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testTricrypto2Pool() public {
|
||||||
|
// Swapping WETH -> WBTC on Tricrypto2Pool 0xD51a44d3FaE010294C616388b506AcdA1bfAAE46
|
||||||
|
uint256 amountIn = 1 ether;
|
||||||
|
deal(WETH_ADDR, address(curveExecutorExposed), amountIn);
|
||||||
|
|
||||||
|
bytes memory data = _getData(WETH_ADDR, WBTC_ADDR, TRICRYPTO2_POOL, 3);
|
||||||
|
|
||||||
|
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
||||||
|
|
||||||
|
assertEq(amountOut, 2279618);
|
||||||
|
assertEq(
|
||||||
|
IERC20(WBTC_ADDR).balanceOf(address(curveExecutorExposed)),
|
||||||
|
amountOut
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testSUSDPool() public {
|
||||||
|
// Swapping USDC -> SUSD on SUSDPool 0xA5407eAE9Ba41422680e2e00537571bcC53efBfD
|
||||||
|
uint256 amountIn = 100 * 10 ** 6;
|
||||||
|
deal(USDC_ADDR, address(curveExecutorExposed), amountIn);
|
||||||
|
|
||||||
|
bytes memory data = _getData(USDC_ADDR, SUSD_ADDR, SUSD_POOL, 1);
|
||||||
|
|
||||||
|
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
||||||
|
|
||||||
|
assertEq(amountOut, 100488101605550214590);
|
||||||
|
assertEq(
|
||||||
|
IERC20(SUSD_ADDR).balanceOf(address(curveExecutorExposed)),
|
||||||
|
amountOut
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testFraxUsdcPool() public {
|
||||||
|
// Swapping FRAX -> USDC on FraxUsdcPool 0xDcEF968d416a41Cdac0ED8702fAC8128A64241A2
|
||||||
|
uint256 amountIn = 1 ether;
|
||||||
|
deal(FRAX_ADDR, address(curveExecutorExposed), amountIn);
|
||||||
|
|
||||||
|
bytes memory data = _getData(FRAX_ADDR, USDC_ADDR, FRAX_USDC_POOL, 1);
|
||||||
|
|
||||||
|
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
||||||
|
|
||||||
|
assertEq(amountOut, 998097);
|
||||||
|
assertEq(
|
||||||
|
IERC20(USDC_ADDR).balanceOf(address(curveExecutorExposed)),
|
||||||
|
amountOut
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testUsdeUsdcPool() public {
|
||||||
|
// Swapping USDC -> USDE on a CryptoSwapNG, deployed by factory 0x6A8cbed756804B16E05E741eDaBd5cB544AE21bf (plain pool)
|
||||||
|
uint256 amountIn = 100 * 10 ** 6;
|
||||||
|
deal(USDC_ADDR, address(curveExecutorExposed), amountIn);
|
||||||
|
|
||||||
|
bytes memory data = _getData(USDC_ADDR, USDE_ADDR, USDE_USDC_POOL, 1);
|
||||||
|
|
||||||
|
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
||||||
|
|
||||||
|
assertEq(amountOut, 100064812138999986170);
|
||||||
|
assertEq(
|
||||||
|
IERC20(USDE_ADDR).balanceOf(address(curveExecutorExposed)),
|
||||||
|
amountOut
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testDolaFraxPyusdPool() public {
|
||||||
|
// Swapping DOLA -> FRAXPYUSD on a CryptoSwapNG, deployed by factory 0x6A8cbed756804B16E05E741eDaBd5cB544AE21bf (meta pool)
|
||||||
|
uint256 amountIn = 100 * 10 ** 6;
|
||||||
|
deal(DOLA_ADDR, address(curveExecutorExposed), amountIn);
|
||||||
|
|
||||||
|
bytes memory data =
|
||||||
|
_getData(DOLA_ADDR, FRAXPYUSD_POOL, DOLA_FRAXPYUSD_POOL, 1);
|
||||||
|
|
||||||
|
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
||||||
|
|
||||||
|
assertEq(amountOut, 99688992);
|
||||||
|
assertEq(
|
||||||
|
IERC20(FRAXPYUSD_POOL).balanceOf(address(curveExecutorExposed)),
|
||||||
|
amountOut
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testCryptoPoolWithETH() public {
|
||||||
|
// Swapping XYO -> ETH on a CryptoPool, deployed by factory 0xF18056Bbd320E96A48e3Fbf8bC061322531aac99
|
||||||
|
uint256 amountIn = 1 ether;
|
||||||
|
uint256 initialBalance = address(curveExecutorExposed).balance; // this address already has some ETH assigned to it
|
||||||
|
deal(XYO_ADDR, address(curveExecutorExposed), amountIn);
|
||||||
|
|
||||||
|
bytes memory data = _getData(XYO_ADDR, ETH_ADDR, ETH_XYO_POOL, 2);
|
||||||
|
|
||||||
|
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
||||||
|
|
||||||
|
assertEq(amountOut, 6081816039338);
|
||||||
|
assertEq(
|
||||||
|
address(curveExecutorExposed).balance, initialBalance + amountOut
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testCryptoPool() public {
|
||||||
|
// Swapping BSGG -> USDT on a CryptoPool, deployed by factory 0xF18056Bbd320E96A48e3Fbf8bC061322531aac99
|
||||||
|
uint256 amountIn = 1000 ether;
|
||||||
|
deal(BSGG_ADDR, address(curveExecutorExposed), amountIn);
|
||||||
|
|
||||||
|
bytes memory data = _getData(BSGG_ADDR, USDT_ADDR, BSGG_USDT_POOL, 2);
|
||||||
|
|
||||||
|
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
||||||
|
|
||||||
|
assertEq(amountOut, 23429);
|
||||||
|
assertEq(
|
||||||
|
IERC20(USDT_ADDR).balanceOf(address(curveExecutorExposed)),
|
||||||
|
amountOut
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testTricryptoPool() public {
|
||||||
|
// Swapping WETH -> USDC on a Tricrypto pool, deployed by factory 0x0c0e5f2fF0ff18a3be9b835635039256dC4B4963
|
||||||
|
uint256 amountIn = 1 ether;
|
||||||
|
deal(WETH_ADDR, address(curveExecutorExposed), amountIn);
|
||||||
|
|
||||||
|
bytes memory data = _getData(WETH_ADDR, USDC_ADDR, TRICRYPTO_POOL, 2);
|
||||||
|
|
||||||
|
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
||||||
|
|
||||||
|
assertEq(amountOut, 1861130974);
|
||||||
|
assertEq(
|
||||||
|
IERC20(USDC_ADDR).balanceOf(address(curveExecutorExposed)),
|
||||||
|
amountOut
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testTwoCryptoPool() public {
|
||||||
|
// Swapping UWU -> WETH on a Twocrypto pool, deployed by factory 0x98ee851a00abee0d95d08cf4ca2bdce32aeaaf7f
|
||||||
|
uint256 amountIn = 1 ether;
|
||||||
|
deal(UWU_ADDR, address(curveExecutorExposed), amountIn);
|
||||||
|
|
||||||
|
bytes memory data = _getData(UWU_ADDR, WETH_ADDR, UWU_WETH_POOL, 2);
|
||||||
|
|
||||||
|
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
||||||
|
|
||||||
|
assertEq(amountOut, 2873786684675);
|
||||||
|
assertEq(
|
||||||
|
IERC20(WETH_ADDR).balanceOf(address(curveExecutorExposed)),
|
||||||
|
amountOut
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testStableSwapPool() public {
|
||||||
|
// Swapping CRVUSD -> USDT on a StableSwap pool, deployed by factory 0x4F8846Ae9380B90d2E71D5e3D042dff3E7ebb40d (plain pool)
|
||||||
|
uint256 amountIn = 1 ether;
|
||||||
|
deal(CRVUSD_ADDR, address(curveExecutorExposed), amountIn);
|
||||||
|
|
||||||
|
bytes memory data =
|
||||||
|
_getData(CRVUSD_ADDR, USDT_ADDR, CRVUSD_USDT_POOL, 1);
|
||||||
|
|
||||||
|
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
||||||
|
|
||||||
|
assertEq(amountOut, 999910);
|
||||||
|
assertEq(
|
||||||
|
IERC20(USDT_ADDR).balanceOf(address(curveExecutorExposed)),
|
||||||
|
amountOut
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testMetaPool() public {
|
||||||
|
// Swapping WTAO -> WSTTAO on a MetaPool deployed by factory 0xB9fC157394Af804a3578134A6585C0dc9cc990d4 (plain pool)
|
||||||
|
uint256 amountIn = 100 * 10 ** 9; // 9 decimals
|
||||||
|
deal(WTAO_ADDR, address(curveExecutorExposed), amountIn);
|
||||||
|
|
||||||
|
bytes memory data =
|
||||||
|
_getData(WTAO_ADDR, WSTTAO_ADDR, WSTTAO_WTAO_POOL, 1);
|
||||||
|
|
||||||
|
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
||||||
|
|
||||||
|
assertEq(amountOut, 32797923610);
|
||||||
|
assertEq(
|
||||||
|
IERC20(WSTTAO_ADDR).balanceOf(address(curveExecutorExposed)),
|
||||||
|
amountOut
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function _getData(
|
||||||
|
address tokenIn,
|
||||||
|
address tokenOut,
|
||||||
|
address pool,
|
||||||
|
uint8 poolType
|
||||||
|
) internal view returns (bytes memory data) {
|
||||||
|
(int128 i, int128 j) = _getIndexes(tokenIn, tokenOut, pool);
|
||||||
|
data = abi.encodePacked(
|
||||||
|
tokenIn,
|
||||||
|
tokenOut,
|
||||||
|
pool,
|
||||||
|
poolType,
|
||||||
|
uint8(uint256(uint128(i))),
|
||||||
|
uint8(uint256(uint128(j))),
|
||||||
|
true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function _getIndexes(address tokenIn, address tokenOut, address pool)
|
||||||
|
internal
|
||||||
|
view
|
||||||
|
returns (int128, int128)
|
||||||
|
{
|
||||||
|
(int128 coinInIndex, int128 coinOutIndex,) =
|
||||||
|
metaRegistry.get_coin_indices(pool, tokenIn, tokenOut);
|
||||||
|
return (coinInIndex, coinOutIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user