Merge branch 'refs/heads/main' into feature/gas-optimization
# Conflicts: # foundry/src/Dispatcher.sol # foundry/test/executors/CurveExecutor.t.sol Took 4 minutes Took 12 seconds
This commit is contained in:
34
CHANGELOG.md
34
CHANGELOG.md
@@ -1,3 +1,37 @@
|
||||
## [0.81.0](https://github.com/propeller-heads/tycho-execution/compare/0.80.0...0.81.0) (2025-04-18)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* update tycho-common version to 0.66.4 ([134c73e](https://github.com/propeller-heads/tycho-execution/commit/134c73e82be74fb5590e19c3d9b27304043bbbd8))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* add slither disable after slither actions update ([20573cb](https://github.com/propeller-heads/tycho-execution/commit/20573cbaf320ba99aa721e6e76a69447ab3f9694))
|
||||
|
||||
## [0.80.0](https://github.com/propeller-heads/tycho-execution/compare/0.79.0...0.80.0) (2025-04-14)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Redeploy balancer with forceApprove fix for USDT ([a6b0f8d](https://github.com/propeller-heads/tycho-execution/commit/a6b0f8d1f67a49848e90d2c4102195c4ac40c5a8))
|
||||
|
||||
## [0.79.0](https://github.com/propeller-heads/tycho-execution/compare/0.78.1...0.79.0) (2025-04-11)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Add new CurveExecutor address ([916c2b7](https://github.com/propeller-heads/tycho-execution/commit/916c2b7dba2c1c424efcbf884932a05427816cf8))
|
||||
* Deploy Curve Executor ([5d4d6d1](https://github.com/propeller-heads/tycho-execution/commit/5d4d6d1ff891766c067e3ff6355ffbb5c50bbf16))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Checksum curve pool addresses ([9e68ab8](https://github.com/propeller-heads/tycho-execution/commit/9e68ab8b0127831ee9dbc1f168e8aac9e28991c0))
|
||||
* Support pools that hold ETH but the coin is WETH ([2e8392a](https://github.com/propeller-heads/tycho-execution/commit/2e8392ab40c6c0e99089fae71873755dedb6e925))
|
||||
* Use forceApprove instead of regular Approve ([c963f3b](https://github.com/propeller-heads/tycho-execution/commit/c963f3b2f61e9d1a6e333149b091c3df90fd857b))
|
||||
|
||||
## [0.78.1](https://github.com/propeller-heads/tycho-execution/compare/0.78.0...0.78.1) (2025-04-09)
|
||||
|
||||
|
||||
|
||||
6
Cargo.lock
generated
6
Cargo.lock
generated
@@ -4317,9 +4317,9 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
|
||||
|
||||
[[package]]
|
||||
name = "tycho-common"
|
||||
version = "0.64.1"
|
||||
version = "0.66.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e318a43fab79199deaab2391c83c75724780151c0337b67914ed835ff04b52f"
|
||||
checksum = "5131fdb21cbd754822b0947fc6c763494531837ba8bb34123f6c7f4f89cb69f7"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@@ -4341,7 +4341,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tycho-execution"
|
||||
version = "0.78.1"
|
||||
version = "0.81.0"
|
||||
dependencies = [
|
||||
"alloy",
|
||||
"alloy-primitives",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "tycho-execution"
|
||||
version = "0.78.1"
|
||||
version = "0.81.0"
|
||||
edition = "2021"
|
||||
description = "Provides tools for encoding and executing swaps against Tycho router and protocol executors."
|
||||
repository = "https://github.com/propeller-heads/tycho-execution"
|
||||
@@ -32,7 +32,7 @@ clap = { version = "4.5.3", features = ["derive"] }
|
||||
alloy = { version = "0.9.2", features = ["providers", "rpc-types-eth", "eip712", "signer-local"], optional = true }
|
||||
alloy-sol-types = { version = "0.8.14", optional = true }
|
||||
alloy-primitives = { version = "0.8.9", optional = true }
|
||||
tycho-common = "0.64.1"
|
||||
tycho-common = "^0.66.4"
|
||||
once_cell = "1.20.2"
|
||||
|
||||
[dev-dependencies]
|
||||
|
||||
@@ -6,9 +6,9 @@
|
||||
"uniswap_v3": "0xdD8559c917393FC8DD2b4dD289c52Ff445fDE1B0",
|
||||
"pancakeswap_v3": "0x4929B619A8F0D9c06ed0FfD497636580D823F65d",
|
||||
"uniswap_v4": "0x042C0ebBEAb9d9987c2f64Ee05f2B3aeB86eAf70",
|
||||
"vm:balancer_v2": "0x00BE8EfAE40219Ff76287b0F9b9e497942f5BC91",
|
||||
"vm:balancer_v2": "0x2380a9ff20565191b67cd66914cf5151434d71f5",
|
||||
"ekubo_v2": "0x4f88f6630a33dB05BEa1FeF7Dc7ff7508D1c531D",
|
||||
"vm:curve": "0x1d1499e622D69689cdf9004d05Ec547d650Ff211"
|
||||
"vm:curve": "0x2751999a30A0026c909c4f1EB92d123254CABa7F"
|
||||
},
|
||||
"tenderly_ethereum": {
|
||||
"uniswap_v2": "0x00C1b81e3C8f6347E69e2DDb90454798A6Be975E",
|
||||
|
||||
@@ -4,84 +4,116 @@ const hre = require("hardhat");
|
||||
|
||||
// Comment out the executors you don't want to deploy
|
||||
const executors_to_deploy = {
|
||||
"ethereum":[
|
||||
// USV2 - Args: Factory, Pool Init Code Hash
|
||||
{exchange: "UniswapV2Executor", args: [
|
||||
"0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f",
|
||||
"0x96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f"
|
||||
]},
|
||||
// SUSHISWAP - Args: Factory, Pool Init Code Hash
|
||||
{exchange: "UniswapV2Executor", args: [
|
||||
"0xC0AEe478e3658e2610c5F7A4A2E1777cE9e4f2Ac",
|
||||
"0xe18a34eb0e04b04f7a0ac29a6e80748dca96319b42c54d679cb821dca90c6303"
|
||||
]},
|
||||
// PANCAKESWAP V2 - Args: Factory, Pool Init Code Hash
|
||||
{exchange: "UniswapV2Executor", args: [
|
||||
"0x1097053Fd2ea711dad45caCcc45EfF7548fCB362",
|
||||
"0x57224589c67f3f30a6b0d7a1b54cf3153ab84563bc609ef41dfb34f8b2974d2d"
|
||||
]},
|
||||
// USV3 -Args: Factory, Pool Init Code Hash
|
||||
{exchange: "UniswapV3Executor", args: [
|
||||
"0x1F98431c8aD98523631AE4a59f267346ea31F984",
|
||||
"0xe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54"
|
||||
]},
|
||||
// PANCAKESWAP V3 - Args: Deployer, Pool Init Code Hash
|
||||
{exchange: "UniswapV3Executor", args: [
|
||||
"0x41ff9AA7e16B8B1a8a8dc4f0eFacd93D02d071c9",
|
||||
"0x6ce8eb472fa82df5469c6ab6d485f17c3ad13c8cd7af59b3d4a8026c5ce0f7e2"
|
||||
]},
|
||||
// Args: Pool manager
|
||||
{exchange: "UniswapV4Executor", args: ["0x000000000004444c5dc75cB358380D2e3dE08A90"]},
|
||||
{exchange: "BalancerV2Executor", args: []},
|
||||
// Args: Ekubo core contract
|
||||
{exchange: "EkuboExecutor", args: [
|
||||
"0xe0e0e08A6A4b9Dc7bD67BCB7aadE5cF48157d444"
|
||||
]}
|
||||
],
|
||||
"base":[
|
||||
// Args: Factory, Pool Init Code Hash
|
||||
{exchange: "UniswapV2Executor", args: [
|
||||
"0x8909Dc15e40173Ff4699343b6eB8132c65e18eC6",
|
||||
"0x96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f"
|
||||
]},
|
||||
// SUSHISWAP V2 - Args: Factory, Pool Init Code Hash
|
||||
{exchange: "UniswapV2Executor", args: [
|
||||
"0x71524B4f93c58fcbF659783284E38825f0622859",
|
||||
"0xe18a34eb0e04b04f7a0ac29a6e80748dca96319b42c54d679cb821dca90c6303"
|
||||
]},
|
||||
// PANCAKESWAP V2 - Args: Factory, Pool Init Code Hash
|
||||
{exchange: "UniswapV2Executor", args: [
|
||||
"0x02a84c1b3BBD7401a5f7fa98a384EBC70bB5749E",
|
||||
"0x57224589c67f3f30a6b0d7a1b54cf3153ab84563bc609ef41dfb34f8b2974d2d"
|
||||
]},
|
||||
// USV3 - Args: Factory, Pool Init Code Hash
|
||||
{exchange: "UniswapV3Executor", args: [
|
||||
"0x33128a8fC17869897dcE68Ed026d694621f6FDfD",
|
||||
"0xe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54"
|
||||
]},
|
||||
// PANCAKESWAP V3 - Args: Deployer, Pool Init Code Hash
|
||||
{exchange: "UniswapV3Executor", args: [
|
||||
"0x41ff9AA7e16B8B1a8a8dc4f0eFacd93D02d071c9",
|
||||
"0x6ce8eb472fa82df5469c6ab6d485f17c3ad13c8cd7af59b3d4a8026c5ce0f7e2"
|
||||
]},
|
||||
// Args: Pool manager
|
||||
{exchange: "UniswapV4Executor", args: ["0x498581ff718922c3f8e6a244956af099b2652b2b"]},
|
||||
{exchange: "BalancerV2Executor", args: []},
|
||||
],
|
||||
"unichain":[
|
||||
// Args: Factory, Pool Init Code Hash
|
||||
{exchange: "UniswapV2Executor", args: [
|
||||
"0x1f98400000000000000000000000000000000002",
|
||||
"0x96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f"
|
||||
]},
|
||||
// USV3 - Args: Factory, Pool Init Code Hash
|
||||
{exchange: "UniswapV3Executor", args: [
|
||||
"0x1f98400000000000000000000000000000000003",
|
||||
"0xe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54"
|
||||
]},
|
||||
// Args: Pool manager
|
||||
{exchange: "UniswapV4Executor", args: ["0x1f98400000000000000000000000000000000004"]},
|
||||
],
|
||||
"ethereum": [
|
||||
// USV2 - Args: Factory, Pool Init Code Hash
|
||||
{
|
||||
exchange: "UniswapV2Executor", args: [
|
||||
"0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f",
|
||||
"0x96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f"
|
||||
]
|
||||
},
|
||||
// SUSHISWAP - Args: Factory, Pool Init Code Hash
|
||||
{
|
||||
exchange: "UniswapV2Executor", args: [
|
||||
"0xC0AEe478e3658e2610c5F7A4A2E1777cE9e4f2Ac",
|
||||
"0xe18a34eb0e04b04f7a0ac29a6e80748dca96319b42c54d679cb821dca90c6303"
|
||||
]
|
||||
},
|
||||
// PANCAKESWAP V2 - Args: Factory, Pool Init Code Hash
|
||||
{
|
||||
exchange: "UniswapV2Executor", args: [
|
||||
"0x1097053Fd2ea711dad45caCcc45EfF7548fCB362",
|
||||
"0x57224589c67f3f30a6b0d7a1b54cf3153ab84563bc609ef41dfb34f8b2974d2d"
|
||||
]
|
||||
},
|
||||
// USV3 -Args: Factory, Pool Init Code Hash
|
||||
{
|
||||
exchange: "UniswapV3Executor", args: [
|
||||
"0x1F98431c8aD98523631AE4a59f267346ea31F984",
|
||||
"0xe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54"
|
||||
]
|
||||
},
|
||||
// PANCAKESWAP V3 - Args: Deployer, Pool Init Code Hash
|
||||
{
|
||||
exchange: "UniswapV3Executor", args: [
|
||||
"0x41ff9AA7e16B8B1a8a8dc4f0eFacd93D02d071c9",
|
||||
"0x6ce8eb472fa82df5469c6ab6d485f17c3ad13c8cd7af59b3d4a8026c5ce0f7e2"
|
||||
]
|
||||
},
|
||||
// Args: Pool manager
|
||||
{exchange: "UniswapV4Executor", args: ["0x000000000004444c5dc75cB358380D2e3dE08A90"]},
|
||||
{exchange: "BalancerV2Executor", args: []},
|
||||
// Args: Ekubo core contract
|
||||
{
|
||||
exchange: "EkuboExecutor", args: [
|
||||
"0xe0e0e08A6A4b9Dc7bD67BCB7aadE5cF48157d444"
|
||||
]
|
||||
},
|
||||
// Args: ETH address in curve pools
|
||||
{
|
||||
exchange: "CurveExecutor", args: [
|
||||
"0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE"
|
||||
]
|
||||
}
|
||||
],
|
||||
"base": [
|
||||
// Args: Factory, Pool Init Code Hash
|
||||
{
|
||||
exchange: "UniswapV2Executor", args: [
|
||||
"0x8909Dc15e40173Ff4699343b6eB8132c65e18eC6",
|
||||
"0x96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f"
|
||||
]
|
||||
},
|
||||
// SUSHISWAP V2 - Args: Factory, Pool Init Code Hash
|
||||
{
|
||||
exchange: "UniswapV2Executor", args: [
|
||||
"0x71524B4f93c58fcbF659783284E38825f0622859",
|
||||
"0xe18a34eb0e04b04f7a0ac29a6e80748dca96319b42c54d679cb821dca90c6303"
|
||||
]
|
||||
},
|
||||
// PANCAKESWAP V2 - Args: Factory, Pool Init Code Hash
|
||||
{
|
||||
exchange: "UniswapV2Executor", args: [
|
||||
"0x02a84c1b3BBD7401a5f7fa98a384EBC70bB5749E",
|
||||
"0x57224589c67f3f30a6b0d7a1b54cf3153ab84563bc609ef41dfb34f8b2974d2d"
|
||||
]
|
||||
},
|
||||
// USV3 - Args: Factory, Pool Init Code Hash
|
||||
{
|
||||
exchange: "UniswapV3Executor", args: [
|
||||
"0x33128a8fC17869897dcE68Ed026d694621f6FDfD",
|
||||
"0xe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54"
|
||||
]
|
||||
},
|
||||
// PANCAKESWAP V3 - Args: Deployer, Pool Init Code Hash
|
||||
{
|
||||
exchange: "UniswapV3Executor", args: [
|
||||
"0x41ff9AA7e16B8B1a8a8dc4f0eFacd93D02d071c9",
|
||||
"0x6ce8eb472fa82df5469c6ab6d485f17c3ad13c8cd7af59b3d4a8026c5ce0f7e2"
|
||||
]
|
||||
},
|
||||
// Args: Pool manager
|
||||
{exchange: "UniswapV4Executor", args: ["0x498581ff718922c3f8e6a244956af099b2652b2b"]},
|
||||
{exchange: "BalancerV2Executor", args: []},
|
||||
],
|
||||
"unichain": [
|
||||
// Args: Factory, Pool Init Code Hash
|
||||
{
|
||||
exchange: "UniswapV2Executor", args: [
|
||||
"0x1f98400000000000000000000000000000000002",
|
||||
"0x96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f"
|
||||
]
|
||||
},
|
||||
// USV3 - Args: Factory, Pool Init Code Hash
|
||||
{
|
||||
exchange: "UniswapV3Executor", args: [
|
||||
"0x1f98400000000000000000000000000000000003",
|
||||
"0xe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54"
|
||||
]
|
||||
},
|
||||
// Args: Pool manager
|
||||
{exchange: "UniswapV4Executor", args: ["0x1f98400000000000000000000000000000000004"]},
|
||||
],
|
||||
}
|
||||
|
||||
async function main() {
|
||||
|
||||
@@ -48,7 +48,7 @@ contract BalancerV2Executor is IExecutor, TokenTransfer {
|
||||
|
||||
if (needsApproval) {
|
||||
// slither-disable-next-line unused-return
|
||||
tokenIn.approve(VAULT, type(uint256).max);
|
||||
tokenIn.forceApprove(VAULT, type(uint256).max);
|
||||
}
|
||||
|
||||
IVault.SingleSwap memory singleSwap = IVault.SingleSwap({
|
||||
|
||||
@@ -81,7 +81,7 @@ contract CurveExecutor is IExecutor, TokenTransfer {
|
||||
|
||||
if (tokenApprovalNeeded && tokenIn != nativeToken) {
|
||||
// slither-disable-next-line unused-return
|
||||
IERC20(tokenIn).approve(address(pool), type(uint256).max);
|
||||
IERC20(tokenIn).forceApprove(address(pool), type(uint256).max);
|
||||
}
|
||||
|
||||
/// Inspired by Curve's router contract: https://github.com/curvefi/curve-router-ng/blob/9ab006ca848fc7f1995b6fbbecfecc1e0eb29e2a/contracts/Router.vy#L44
|
||||
|
||||
@@ -254,15 +254,15 @@ contract CurveExecutorTest is Test, Constants {
|
||||
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);
|
||||
deal(USDT_ADDR, address(curveExecutorExposed), amountIn);
|
||||
|
||||
bytes memory data =
|
||||
_getData(CRVUSD_ADDR, USDT_ADDR, CRVUSD_USDT_POOL, 1, ALICE);
|
||||
_getData(USDT_ADDR, CRVUSD_ADDR, CRVUSD_USDT_POOL, 1, ALICE);
|
||||
|
||||
uint256 amountOut = curveExecutorExposed.swap(amountIn, data);
|
||||
|
||||
assertEq(amountOut, 999910);
|
||||
assertEq(IERC20(USDT_ADDR).balanceOf(ALICE), amountOut);
|
||||
assertEq(amountOut, 10436946786333182306400100);
|
||||
assertEq(IERC20(CRVUSD_ADDR).balanceOf(ALICE), amountOut);
|
||||
}
|
||||
|
||||
function testMetaPool() public {
|
||||
|
||||
@@ -378,6 +378,7 @@ pub struct CurveSwapEncoder {
|
||||
meta_registry_address: String,
|
||||
native_token_curve_address: String,
|
||||
native_token_address: Bytes,
|
||||
wrapped_native_token_address: Bytes,
|
||||
}
|
||||
|
||||
impl CurveSwapEncoder {
|
||||
@@ -450,10 +451,34 @@ impl CurveSwapEncoder {
|
||||
let j = U8::from(j_256);
|
||||
Ok((i, j))
|
||||
}
|
||||
Err(err) => Err(EncodingError::RecoverableError(format!(
|
||||
"Curve meta registry call failed with error: {:?}",
|
||||
err
|
||||
))),
|
||||
Err(err) => {
|
||||
// Temporary until we get the coin indexes from the indexer
|
||||
// This is because some curve pools hold ETH but the coin is defined as WETH
|
||||
// Our indexer reports this pool as holding ETH but then here we need to use WETH
|
||||
// This is valid only for some pools, that's why we are doing the trial and error
|
||||
// approach
|
||||
let native_token_curve_address =
|
||||
Address::from_str(&self.native_token_curve_address).map_err(|_| {
|
||||
EncodingError::FatalError(
|
||||
"Invalid Curve native token curve address".to_string(),
|
||||
)
|
||||
})?;
|
||||
if token_in != native_token_curve_address && token_out != native_token_curve_address
|
||||
{
|
||||
Err(EncodingError::RecoverableError(format!(
|
||||
"Curve meta registry call failed with error: {:?}",
|
||||
err
|
||||
)))
|
||||
} else {
|
||||
let wrapped_token = bytes_to_address(&self.wrapped_native_token_address)?;
|
||||
let (i, j) = if token_in == native_token_curve_address {
|
||||
self.get_coin_indexes(pool_id, wrapped_token, token_out)?
|
||||
} else {
|
||||
self.get_coin_indexes(pool_id, token_in, wrapped_token)?
|
||||
};
|
||||
Ok((i, j))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -483,6 +508,7 @@ impl SwapEncoder for CurveSwapEncoder {
|
||||
executor_address,
|
||||
meta_registry_address,
|
||||
native_token_address: chain.native_token()?,
|
||||
wrapped_native_token_address: chain.wrapped_token()?,
|
||||
native_token_curve_address,
|
||||
})
|
||||
}
|
||||
@@ -536,7 +562,10 @@ impl SwapEncoder for CurveSwapEncoder {
|
||||
})?)
|
||||
.map_err(|_| EncodingError::FatalError("Invalid curve factory address".to_string()))?;
|
||||
|
||||
let pool_type = self.get_pool_type(&swap.component.id, &factory_address.to_string())?;
|
||||
let pool_address = Address::from_str(&swap.component.id)
|
||||
.map_err(|_| EncodingError::FatalError("Invalid curve pool address".to_string()))?;
|
||||
let pool_type =
|
||||
self.get_pool_type(&pool_address.to_string(), &factory_address.to_string())?;
|
||||
|
||||
let (i, j) = self.get_coin_indexes(component_address, token_in, token_out)?;
|
||||
|
||||
@@ -1210,6 +1239,22 @@ mod tests {
|
||||
2,
|
||||
0
|
||||
)]
|
||||
// Pool that holds ETH but coin is WETH
|
||||
#[case(
|
||||
"0x7F86Bf177Dd4F3494b841a37e810A34dD56c829B",
|
||||
"0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE",
|
||||
"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
||||
2,
|
||||
0
|
||||
)]
|
||||
// Pool that holds ETH but coin is WETH
|
||||
#[case(
|
||||
"0x7F86Bf177Dd4F3494b841a37e810A34dD56c829B",
|
||||
"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
||||
"0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE",
|
||||
0,
|
||||
2
|
||||
)]
|
||||
fn test_curve_get_coin_indexes(
|
||||
#[case] pool: &str,
|
||||
#[case] token_in: &str,
|
||||
|
||||
Reference in New Issue
Block a user