Merge branch 'cyclic-route-0.123.0'

This commit is contained in:
johnwhitton
2025-09-29 06:46:22 -07:00
23 changed files with 228 additions and 62 deletions

29
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@@ -0,0 +1,29 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. ..
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Desktop (please complete the following information):**
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
**Full error traceback**
Please provide the full error traceback/failed transaction/failed tenderly simulation

View File

@@ -1,3 +1,40 @@
## [0.128.0](https://github.com/propeller-heads/tycho-execution/compare/0.127.0...0.128.0) (2025-09-25)
### Features
* Use tycho-common from crates.io ([89435b5](https://github.com/propeller-heads/tycho-execution/commit/89435b5c76bbd1fbf2c946686ede442c4647cd29))
## [0.127.0](https://github.com/propeller-heads/tycho-execution/compare/0.126.0...0.127.0) (2025-09-25)
### Features
* Use tycho-common from github ([5d73e3b](https://github.com/propeller-heads/tycho-execution/commit/5d73e3b47c5cbff4fa0c88e71f15f48f3831f199))
## [0.126.0](https://github.com/propeller-heads/tycho-execution/compare/0.125.0...0.126.0) (2025-09-25)
### Features
* Add historical_trade option to encoding ([c51c6f5](https://github.com/propeller-heads/tycho-execution/commit/c51c6f52a5c1a7e47caab3bfa721f7c373a8229e))
* Pass the file contents instead of the file path for executors ([e78a362](https://github.com/propeller-heads/tycho-execution/commit/e78a362894955a8b0e676bbcb189195d00815aad))
* Update tycho common to point to hooks feature branch ([a98e8d2](https://github.com/propeller-heads/tycho-execution/commit/a98e8d21ccd2eafeb42805acb6ce157b60374a0c))
## [0.125.0](https://github.com/propeller-heads/tycho-execution/compare/0.124.0...0.125.0) (2025-09-25)
### Features
* bump tycho-common version ([fa3bb6d](https://github.com/propeller-heads/tycho-execution/commit/fa3bb6daf74c6df254a4b65718663ec0ca7339d6))
## [0.124.0](https://github.com/propeller-heads/tycho-execution/compare/0.123.0...0.124.0) (2025-09-11)
### Features
* bump tycho-common version ([bbd732d](https://github.com/propeller-heads/tycho-execution/commit/bbd732d15a4405fc358eedbb3cbb3b98ec3f61b5))
## [0.123.0](https://github.com/propeller-heads/tycho-execution/compare/0.122.0...0.123.0) (2025-09-02)

6
Cargo.lock generated
View File

@@ -4634,9 +4634,9 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
[[package]]
name = "tycho-common"
version = "0.82.0"
version = "0.88.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "096c87ebe011785fcd7ed59ec501ac12b465a64fbd2914b8c0c57125c253682b"
checksum = "ac0c309443e15797f3b713f10b8f00e79067abe91ea7c58421e4ce345b022e0d"
dependencies = [
"anyhow",
"async-trait",
@@ -4659,7 +4659,7 @@ dependencies = [
[[package]]
name = "tycho-execution"
version = "0.123.0"
version = "0.128.0"
dependencies = [
"alloy",
"async-trait",

View File

@@ -1,6 +1,6 @@
[package]
name = "tycho-execution"
version = "0.123.0"
version = "0.128.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"
@@ -37,7 +37,7 @@ tokio = { version = "1.38.0", features = ["full"] }
chrono = "0.4.39"
clap = { version = "4.5.3", features = ["derive"] }
once_cell = "1.20.2"
tycho-common = "0.82.0"
tycho-common = "0.88.0"
alloy = { version = "1.0.6", features = ["providers", "rpc-types-eth", "eip712", "signer-local", "node-bindings"], optional = true }
async-trait = { version = "0.1.88", optional = true }

1
foundry/test/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
*.runtime.json

View File

@@ -136,7 +136,6 @@ contract BalancerV2ExecutorTest is Constants, TestUtils {
}
function testExportContract() public {
vm.skip(true);
exportRuntimeBytecode(address(balancerV2Exposed), "BalancerV2");
}
}

View File

@@ -119,6 +119,10 @@ contract BalancerV3ExecutorTest is Constants, TestUtils {
assertGt(balanceAfter, balanceBefore);
assertEq(balanceAfter - balanceBefore, amountOut);
}
function testExportContract() public {
exportRuntimeBytecode(address(balancerV3Exposed), "BalancerV3");
}
}
contract TychoRouterForBalancerV3Test is TychoRouterTestSetup {

View File

@@ -46,7 +46,7 @@ contract CurveExecutorExposed is CurveExecutor {
}
}
contract CurveExecutorTest is Test, Constants {
contract CurveExecutorTest is Test, TestUtils, Constants {
using SafeERC20 for IERC20;
CurveExecutorExposed curveExecutorExposed;
@@ -393,6 +393,10 @@ contract CurveExecutorTest is Test, Constants {
metaRegistry.get_coin_indices(pool, tokenIn, tokenOut);
return (coinInIndex, coinOutIndex);
}
function testExportContract() public {
exportRuntimeBytecode(address(curveExecutorExposed), "Curve");
}
}
contract TychoRouterForBalancerV3Test is TychoRouterTestSetup {

View File

@@ -202,6 +202,10 @@ contract EkuboExecutorTest is Constants, TestUtils {
function testMultiHopSwapIntegration() public setUpFork(22082754) {
multiHopSwap(loadCallDataFromFile("test_ekubo_encode_swap_multi"));
}
function testExportContract() public {
exportRuntimeBytecode(address(executor), "Ekubo");
}
}
contract TychoRouterForBalancerV3Test is TychoRouterTestSetup {

View File

@@ -41,7 +41,7 @@ contract HashflowUtils is Test {
}
}
contract HashflowExecutorECR20Test is Constants, HashflowUtils {
contract HashflowExecutorECR20Test is Constants, TestUtils, HashflowUtils {
using SafeERC20 for IERC20;
HashflowExecutorExposed executor;

View File

@@ -126,6 +126,10 @@ contract MaverickV2ExecutorTest is TestUtils, Constants {
assertGt(balanceAfter, balanceBefore);
assertEq(balanceAfter - balanceBefore, amountOut);
}
function testExportContract() public {
exportRuntimeBytecode(address(maverickV2Exposed), "MaverickV2");
}
}
contract TychoRouterForBalancerV3Test is TychoRouterTestSetup {

View File

@@ -263,4 +263,8 @@ contract UniswapV2ExecutorTest is Constants, Permit2TestHelper, TestUtils {
assertEq(IERC20(BASE_MAG7).balanceOf(BOB), 1379830606);
}
function testExportContract() public {
exportRuntimeBytecode(address(uniswapV2Exposed), "UniswapV2");
}
}

View File

@@ -39,7 +39,12 @@ contract UniswapV3ExecutorExposed is UniswapV3Executor {
}
}
contract UniswapV3ExecutorTest is Test, Constants, Permit2TestHelper {
contract UniswapV3ExecutorTest is
Test,
TestUtils,
Constants,
Permit2TestHelper
{
using SafeERC20 for IERC20;
UniswapV3ExecutorExposed uniswapV3Exposed;
@@ -210,6 +215,10 @@ contract UniswapV3ExecutorTest is Test, Constants, Permit2TestHelper {
transferType
);
}
function testExportContract() public {
exportRuntimeBytecode(address(uniswapV3Exposed), "UniswapV3");
}
}
contract TychoRouterForBalancerV3Test is TychoRouterTestSetup {

View File

@@ -261,6 +261,10 @@ contract UniswapV4ExecutorTest is Constants, TestUtils {
);
assertTrue(IERC20(WETH_ADDR).balanceOf(ALICE) == amountOut);
}
function testExportContract() public {
exportRuntimeBytecode(address(uniswapV4Exposed), "UniswapV4");
}
}
contract TychoRouterForBalancerV3Test is TychoRouterTestSetup {

View File

@@ -1,9 +1,13 @@
use std::io::{self, Read};
use std::{
fs,
io::{self, Read},
};
use alloy::sol_types::SolValue;
use clap::{Parser, Subcommand};
use tycho_common::{hex_bytes::Bytes, models::Chain};
use tycho_execution::encoding::{
errors::EncodingError,
evm::{
approvals::permit2::PermitSingle,
encoder_builders::{TychoExecutorEncoderBuilder, TychoRouterEncoderBuilder},
@@ -83,7 +87,12 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
Commands::TychoRouter => {
let mut builder = TychoRouterEncoderBuilder::new().chain(chain);
if let Some(config_path) = cli.executors_file_path {
builder = builder.executors_file_path(config_path);
let executors_addresses = fs::read_to_string(&config_path).map_err(|e| {
EncodingError::FatalError(format!(
"Error reading executors file from {config_path:?}: {e}",
))
})?;
builder = builder.executors_addresses(executors_addresses);
}
if let Some(router_address) = cli.router_address {
builder = builder.router_address(router_address);

View File

@@ -20,9 +20,10 @@ use crate::encoding::{
pub struct TychoRouterEncoderBuilder {
chain: Option<Chain>,
user_transfer_type: Option<UserTransferType>,
executors_file_path: Option<String>,
executors_addresses: Option<String>,
router_address: Option<Bytes>,
swapper_pk: Option<String>,
historical_trade: bool,
}
impl Default for TychoRouterEncoderBuilder {
@@ -35,10 +36,11 @@ impl TychoRouterEncoderBuilder {
pub fn new() -> Self {
TychoRouterEncoderBuilder {
chain: None,
executors_file_path: None,
executors_addresses: None,
router_address: None,
swapper_pk: None,
user_transfer_type: None,
historical_trade: false,
}
}
pub fn chain(mut self, chain: Chain) -> Self {
@@ -51,10 +53,10 @@ impl TychoRouterEncoderBuilder {
self
}
/// Sets the `executors_file_path` manually.
/// If it's not set, the default path will be used (config/executor_addresses.json)
pub fn executors_file_path(mut self, executors_file_path: String) -> Self {
self.executors_file_path = Some(executors_file_path);
/// Sets the `executors_addresses` manually.
/// If it's not set, the default value will be used (contents of config/executor_addresses.json)
pub fn executors_addresses(mut self, executors_addresses: String) -> Self {
self.executors_addresses = Some(executors_addresses);
self
}
@@ -65,6 +67,15 @@ impl TychoRouterEncoderBuilder {
self
}
/// Sets the `historical_trade` manually to true.
/// If set to true, it means that the encoded trade will be used in an historical block (as a
/// test) and not in the current one. This is relevant for checking token approvals in some
/// protocols (like Balancer v2).
pub fn historical_trade(mut self) -> Self {
self.historical_trade = true;
self
}
/// Sets the `swapper_pk` for the encoder. This is used to sign permit2 objects. This is only
/// needed if you intend to get the full calldata for the transfer. We do not recommend
/// using this option, you should sign and create the function calldata entirely on your
@@ -96,7 +107,7 @@ impl TychoRouterEncoderBuilder {
}
let swap_encoder_registry =
SwapEncoderRegistry::new(self.executors_file_path.clone(), chain)?;
SwapEncoderRegistry::new(self.executors_addresses.clone(), chain)?;
let signer = if let Some(pk) = self.swapper_pk {
let pk = B256::from_str(&pk).map_err(|_| {
@@ -115,6 +126,7 @@ impl TychoRouterEncoderBuilder {
tycho_router_address,
user_transfer_type,
signer,
self.historical_trade,
)?))
} else {
Err(EncodingError::FatalError(
@@ -128,7 +140,7 @@ impl TychoRouterEncoderBuilder {
/// Builder pattern for constructing a `TychoExecutorEncoder` with customizable options.
pub struct TychoExecutorEncoderBuilder {
chain: Option<Chain>,
executors_file_path: Option<String>,
executors_addresses: Option<String>,
}
impl Default for TychoExecutorEncoderBuilder {
@@ -139,17 +151,17 @@ impl Default for TychoExecutorEncoderBuilder {
impl TychoExecutorEncoderBuilder {
pub fn new() -> Self {
TychoExecutorEncoderBuilder { chain: None, executors_file_path: None }
TychoExecutorEncoderBuilder { chain: None, executors_addresses: None }
}
pub fn chain(mut self, chain: Chain) -> Self {
self.chain = Some(chain);
self
}
/// Sets the `executors_file_path` manually.
/// Sets the `executors_addresses` manually.
/// If it's not set, the default path will be used (config/executor_addresses.json)
pub fn executors_file_path(mut self, executors_file_path: String) -> Self {
self.executors_file_path = Some(executors_file_path);
pub fn executors_addresses(mut self, executors_addresses: String) -> Self {
self.executors_addresses = Some(executors_addresses);
self
}
@@ -158,7 +170,7 @@ impl TychoExecutorEncoderBuilder {
pub fn build(self) -> Result<Box<dyn TychoEncoder>, EncodingError> {
if let Some(chain) = self.chain {
let swap_encoder_registry =
SwapEncoderRegistry::new(self.executors_file_path.clone(), chain)?;
SwapEncoderRegistry::new(self.executors_addresses.clone(), chain)?;
Ok(Box::new(TychoExecutorEncoder::new(swap_encoder_registry)?))
} else {
Err(EncodingError::FatalError(

View File

@@ -58,11 +58,12 @@ use crate::encoding::{
/// funds.
///
/// # Parameters
/// - `chain_id`: Chain ID
/// - `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.
/// - `user_transfer_type`: The desired transfer method.
/// - `native_address`: The address used to represent the native token
/// - `signer`: Optional signer for permit2
///
/// # Returns
/// A `Result<Transaction, EncodingError>` that either contains the full transaction data (to,

View File

@@ -26,12 +26,15 @@ use crate::encoding::{
/// * `function_signature`: String, the signature for the swap function in the router contract
/// * `router_address`: Address of the router to be used to execute swaps
/// * `transfer_optimization`: TransferOptimization, responsible for optimizing the token transfers
/// * `historical_trade`: Whether the swap is to be done in the current block or in an historical
/// one. This is relevant for checking token approvals in some protocols (like Balancer v2).
#[derive(Clone)]
pub struct SingleSwapStrategyEncoder {
swap_encoder_registry: SwapEncoderRegistry,
function_signature: String,
router_address: Bytes,
transfer_optimization: TransferOptimization,
historical_trade: bool,
}
impl SingleSwapStrategyEncoder {
@@ -40,6 +43,7 @@ impl SingleSwapStrategyEncoder {
swap_encoder_registry: SwapEncoderRegistry,
user_transfer_type: UserTransferType,
router_address: Bytes,
historical_trade: bool,
) -> Result<Self, EncodingError> {
let function_signature = if user_transfer_type == UserTransferType::TransferFromPermit2 {
"singleSwapPermit2(uint256,address,address,uint256,bool,bool,address,((address,uint160,uint48,uint48),address,uint256),bytes,bytes)"
@@ -57,6 +61,7 @@ impl SingleSwapStrategyEncoder {
user_transfer_type,
router_address,
),
historical_trade,
})
}
@@ -119,6 +124,7 @@ impl StrategyEncoder for SingleSwapStrategyEncoder {
group_token_in: grouped_swap.token_in.clone(),
group_token_out: grouped_swap.token_out.clone(),
transfer_type: transfer,
historical_trade: self.historical_trade,
};
let mut grouped_protocol_data: Vec<Vec<u8>> = vec![];
@@ -171,6 +177,8 @@ impl StrategyEncoder for SingleSwapStrategyEncoder {
/// * `sequential_swap_validator`: SequentialSwapValidator, responsible for checking validity of
/// sequential swap solutions
/// * `transfer_optimization`: TransferOptimization, responsible for optimizing the token transfers
/// * `historical_trade`: Whether the swap is to be done in the current block or in an historical
/// one. This is relevant for checking token approvals in some protocols (like Balancer v2).
#[derive(Clone)]
pub struct SequentialSwapStrategyEncoder {
swap_encoder_registry: SwapEncoderRegistry,
@@ -180,6 +188,7 @@ pub struct SequentialSwapStrategyEncoder {
wrapped_address: Bytes,
sequential_swap_validator: SequentialSwapValidator,
transfer_optimization: TransferOptimization,
historical_trade: bool,
}
impl SequentialSwapStrategyEncoder {
@@ -188,6 +197,7 @@ impl SequentialSwapStrategyEncoder {
swap_encoder_registry: SwapEncoderRegistry,
user_transfer_type: UserTransferType,
router_address: Bytes,
historical_trade: bool,
) -> Result<Self, EncodingError> {
let function_signature = if user_transfer_type == UserTransferType::TransferFromPermit2 {
"sequentialSwapPermit2(uint256,address,address,uint256,bool,bool,address,((address,uint160,uint48,uint48),address,uint256),bytes,bytes)"
@@ -210,6 +220,7 @@ impl SequentialSwapStrategyEncoder {
user_transfer_type,
router_address,
),
historical_trade,
})
}
@@ -279,6 +290,7 @@ impl StrategyEncoder for SequentialSwapStrategyEncoder {
group_token_in: grouped_swap.token_in.clone(),
group_token_out: grouped_swap.token_out.clone(),
transfer_type: transfer,
historical_trade: self.historical_trade,
};
let mut grouped_protocol_data: Vec<Vec<u8>> = vec![];
@@ -336,6 +348,8 @@ impl StrategyEncoder for SequentialSwapStrategyEncoder {
/// solutions
/// * `router_address`: Address of the router to be used to execute swaps
/// * `transfer_optimization`: TransferOptimization, responsible for optimizing the token transfers
/// * `historical_trade`: Whether the swap is to be done in the current block or in an historical
/// one. This is relevant for checking token approvals in some protocols (like Balancer v2).
#[derive(Clone)]
pub struct SplitSwapStrategyEncoder {
swap_encoder_registry: SwapEncoderRegistry,
@@ -345,6 +359,7 @@ pub struct SplitSwapStrategyEncoder {
split_swap_validator: SplitSwapValidator,
router_address: Bytes,
transfer_optimization: TransferOptimization,
historical_trade: bool,
}
impl SplitSwapStrategyEncoder {
@@ -353,6 +368,7 @@ impl SplitSwapStrategyEncoder {
swap_encoder_registry: SwapEncoderRegistry,
user_transfer_type: UserTransferType,
router_address: Bytes,
historical_trade: bool,
) -> Result<Self, EncodingError> {
let function_signature = if user_transfer_type == UserTransferType::TransferFromPermit2 {
"splitSwapPermit2(uint256,address,address,uint256,bool,bool,uint256,address,((address,uint160,uint48,uint48),address,uint256),bytes,bytes)"
@@ -374,6 +390,7 @@ impl SplitSwapStrategyEncoder {
user_transfer_type,
router_address,
),
historical_trade,
})
}
@@ -479,6 +496,7 @@ impl StrategyEncoder for SplitSwapStrategyEncoder {
group_token_in: grouped_swap.token_in.clone(),
group_token_out: grouped_swap.token_out.clone(),
transfer_type: transfer,
historical_trade: self.historical_trade,
};
let mut grouped_protocol_data: Vec<Vec<u8>> = vec![];
@@ -535,7 +553,7 @@ impl StrategyEncoder for SplitSwapStrategyEncoder {
#[cfg(test)]
mod tests {
use std::{collections::HashMap, str::FromStr};
use std::{collections::HashMap, fs, str::FromStr};
use alloy::{hex::encode, primitives::hex};
use num_bigint::{BigInt, BigUint};
@@ -555,9 +573,10 @@ mod tests {
}
fn get_swap_encoder_registry() -> SwapEncoderRegistry {
let executors_addresses =
fs::read_to_string("config/test_executor_addresses.json").unwrap();
let eth_chain = eth_chain();
SwapEncoderRegistry::new(Some("config/test_executor_addresses.json".to_string()), eth_chain)
.unwrap()
SwapEncoderRegistry::new(Some(executors_addresses), eth_chain).unwrap()
}
fn router_address() -> Bytes {
@@ -591,6 +610,7 @@ mod tests {
swap_encoder_registry,
UserTransferType::TransferFromPermit2,
router_address(),
false,
)
.unwrap();
let solution = Solution {
@@ -651,6 +671,7 @@ mod tests {
swap_encoder_registry,
UserTransferType::None,
router_address(),
false,
)
.unwrap();
let solution = Solution {
@@ -732,6 +753,7 @@ mod tests {
swap_encoder_registry,
UserTransferType::TransferFrom,
router_address(),
false,
)
.unwrap();
let solution = Solution {
@@ -867,6 +889,7 @@ mod tests {
swap_encoder_registry,
UserTransferType::TransferFromPermit2,
Bytes::from("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395"),
false,
)
.unwrap();
@@ -1015,6 +1038,7 @@ mod tests {
swap_encoder_registry,
UserTransferType::TransferFrom,
Bytes::from("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395"),
false,
)
.unwrap();

View File

@@ -1,4 +1,4 @@
use std::{collections::HashMap, fs};
use std::collections::HashMap;
use tycho_common::models::Chain;
@@ -21,13 +21,9 @@ pub struct SwapEncoderRegistry {
impl SwapEncoderRegistry {
/// Populates the registry with the `SwapEncoders` for the given blockchain by parsing the
/// executors' addresses in the file at the given path.
pub fn new(executors_file_path: Option<String>, chain: Chain) -> Result<Self, EncodingError> {
let config_str = if let Some(ref path) = executors_file_path {
fs::read_to_string(path).map_err(|e| {
EncodingError::FatalError(format!(
"Error reading executors file from {executors_file_path:?}: {e}",
))
})?
pub fn new(executors_addresses: Option<String>, chain: Chain) -> Result<Self, EncodingError> {
let config_str = if let Some(addresses) = executors_addresses {
addresses
} else {
DEFAULT_EXECUTORS_JSON.to_string()
};

View File

@@ -280,19 +280,20 @@ impl SwapEncoder for BalancerV2SwapEncoder {
) -> Result<Vec<u8>, EncodingError> {
let token_approvals_manager = ProtocolApprovalsManager::new()?;
let token = bytes_to_address(&swap.token_in)?;
let approval_needed: bool;
let mut approval_needed: bool = true;
if let Some(router_address) = &encoding_context.router_address {
if !encoding_context.historical_trade {
let tycho_router_address = bytes_to_address(router_address)?;
approval_needed = token_approvals_manager.approval_needed(
token,
tycho_router_address,
Address::from_str(&self.vault_address)
.map_err(|_| EncodingError::FatalError("Invalid vault address".to_string()))?,
Address::from_str(&self.vault_address).map_err(|_| {
EncodingError::FatalError("Invalid vault address".to_string())
})?,
)?;
} else {
approval_needed = true;
}
};
let component_id = AlloyBytes::from_str(&swap.component.id)
.map_err(|_| EncodingError::FatalError("Invalid component ID".to_string()))?;
@@ -1026,6 +1027,7 @@ mod tests {
group_token_in: token_in.clone(),
group_token_out: token_out.clone(),
transfer_type: TransferType::Transfer,
historical_trade: false,
};
let encoder = UniswapV2SwapEncoder::new(
String::from("0x543778987b293C7E8Cf0722BB2e935ba6f4068D4"),
@@ -1081,6 +1083,7 @@ mod tests {
group_token_in: token_in.clone(),
group_token_out: token_out.clone(),
transfer_type: TransferType::Transfer,
historical_trade: false,
};
let encoder = UniswapV3SwapEncoder::new(
String::from("0x543778987b293C7E8Cf0722BB2e935ba6f4068D4"),
@@ -1138,6 +1141,7 @@ mod tests {
group_token_in: token_in.clone(),
group_token_out: token_out.clone(),
transfer_type: TransferType::None,
historical_trade: true,
};
let encoder = BalancerV2SwapEncoder::new(
String::from("0x543778987b293C7E8Cf0722BB2e935ba6f4068D4"),
@@ -1207,6 +1211,7 @@ mod tests {
group_token_in: token_in.clone(),
group_token_out: token_out.clone(),
transfer_type: TransferType::Transfer,
historical_trade: false,
};
let encoder = UniswapV4SwapEncoder::new(
String::from("0xF62849F9A0B5Bf2913b396098F7c7019b51A820a"),
@@ -1275,6 +1280,7 @@ mod tests {
// Token out is the same as the group token out
group_token_out: token_out.clone(),
transfer_type: TransferType::Transfer,
historical_trade: false,
};
let encoder = UniswapV4SwapEncoder::new(
@@ -1318,6 +1324,7 @@ mod tests {
group_token_in: usde_address.clone(),
group_token_out: wbtc_address.clone(),
transfer_type: TransferType::Transfer,
historical_trade: false,
};
// Setup - First sequence: USDE -> USDT
@@ -1448,6 +1455,7 @@ mod tests {
exact_out: false,
router_address: Some(Bytes::default()),
transfer_type: TransferType::Transfer,
historical_trade: false,
};
let encoder = EkuboSwapEncoder::new(String::default(), Chain::Ethereum, None).unwrap();
@@ -1490,6 +1498,7 @@ mod tests {
exact_out: false,
router_address: Some(Bytes::default()),
transfer_type: TransferType::Transfer,
historical_trade: false,
};
let first_swap = SwapBuilder::new(
@@ -1687,6 +1696,7 @@ mod tests {
group_token_in: token_in.clone(),
group_token_out: token_out.clone(),
transfer_type: TransferType::None,
historical_trade: false,
};
let encoder = CurveSwapEncoder::new(
String::from("0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f"),
@@ -1753,6 +1763,7 @@ mod tests {
group_token_in: token_in.clone(),
group_token_out: token_out.clone(),
transfer_type: TransferType::None,
historical_trade: false,
};
let encoder = CurveSwapEncoder::new(
String::from("0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f"),
@@ -1820,6 +1831,7 @@ mod tests {
group_token_in: token_in.clone(),
group_token_out: token_out.clone(),
transfer_type: TransferType::None,
historical_trade: false,
};
let encoder = CurveSwapEncoder::new(
String::from("0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f"),
@@ -1888,6 +1900,7 @@ mod tests {
group_token_in: token_in.clone(),
group_token_out: token_out.clone(),
transfer_type: TransferType::Transfer,
historical_trade: false,
};
let encoder = BalancerV3SwapEncoder::new(
String::from("0x543778987b293C7E8Cf0722BB2e935ba6f4068D4"),
@@ -1940,6 +1953,7 @@ mod tests {
group_token_in: token_in.clone(),
group_token_out: token_out.clone(),
transfer_type: TransferType::Transfer,
historical_trade: false,
};
let encoder = MaverickV2SwapEncoder::new(
String::from("0x543778987b293C7E8Cf0722BB2e935ba6f4068D4"),
@@ -2033,6 +2047,7 @@ mod tests {
group_token_in: token_in.clone(),
group_token_out: token_out.clone(),
transfer_type: TransferType::Transfer,
historical_trade: false,
};
let encoder = BebopSwapEncoder::new(
@@ -2107,6 +2122,7 @@ mod tests {
group_token_in: token_in.clone(),
group_token_out: token_out.clone(),
transfer_type: TransferType::Transfer,
historical_trade: false,
};
let encoder = HashflowSwapEncoder::new(
@@ -2200,6 +2216,7 @@ mod tests {
group_token_in: token_in.clone(),
group_token_out: token_out.clone(),
transfer_type: TransferType::Transfer,
historical_trade: false,
};
let encoder = HashflowSwapEncoder::new(

View File

@@ -54,6 +54,7 @@ impl TychoRouterEncoder {
router_address: Bytes,
user_transfer_type: UserTransferType,
signer: Option<PrivateKeySigner>,
historical_trade: bool,
) -> Result<Self, EncodingError> {
let permit2 = if user_transfer_type == UserTransferType::TransferFromPermit2 {
Some(Permit2::new()?)
@@ -66,18 +67,21 @@ impl TychoRouterEncoder {
swap_encoder_registry.clone(),
user_transfer_type.clone(),
router_address.clone(),
historical_trade,
)?,
sequential_swap_strategy: SequentialSwapStrategyEncoder::new(
chain,
swap_encoder_registry.clone(),
user_transfer_type.clone(),
router_address.clone(),
historical_trade,
)?,
split_swap_strategy: SplitSwapStrategyEncoder::new(
chain,
swap_encoder_registry,
user_transfer_type.clone(),
router_address.clone(),
historical_trade,
)?,
router_address,
permit2,
@@ -333,6 +337,7 @@ impl TychoExecutorEncoder {
group_token_in: grouped_swap.token_in.clone(),
group_token_out: grouped_swap.token_out.clone(),
transfer_type: transfer,
historical_trade: false,
};
let mut grouped_protocol_data: Vec<Vec<u8>> = vec![];
let mut initial_protocol_data: Vec<u8> = vec![];
@@ -402,7 +407,7 @@ impl TychoEncoder for TychoExecutorEncoder {
#[cfg(test)]
mod tests {
use std::{collections::HashMap, str::FromStr};
use std::{collections::HashMap, fs, str::FromStr};
use num_bigint::{BigInt, BigUint};
use tycho_common::models::{protocol::ProtocolComponent, Chain};
@@ -486,11 +491,9 @@ mod tests {
}
fn get_swap_encoder_registry() -> SwapEncoderRegistry {
SwapEncoderRegistry::new(
Some("config/test_executor_addresses.json".to_string()),
eth_chain(),
)
.unwrap()
let executors_addresses =
fs::read_to_string("config/test_executor_addresses.json").unwrap();
SwapEncoderRegistry::new(Some(executors_addresses), eth_chain()).unwrap()
}
fn get_tycho_router_encoder(user_transfer_type: UserTransferType) -> TychoRouterEncoder {
@@ -500,6 +503,7 @@ mod tests {
router_address(),
user_transfer_type,
None,
false,
)
.unwrap()
}

View File

@@ -273,6 +273,8 @@ impl PartialEq for PermitDetails {
/// * `group_token_in`: Token to be used as the input for the group swap.
/// * `group_token_out`: Token to be used as the output for the group swap.
/// * `transfer`: Type of transfer to be performed. See `TransferType` for more details.
/// * `historical_trade`: Whether the swap is to be done in the current block or in an historical
/// one. This is relevant for checking token approvals in some protocols (like Balancer v2).
#[derive(Clone, Debug)]
pub struct EncodingContext {
pub receiver: Bytes,
@@ -281,6 +283,7 @@ pub struct EncodingContext {
pub group_token_in: Bytes,
pub group_token_out: Bytes,
pub transfer_type: TransferType,
pub historical_trade: bool,
}
/// Represents the type of transfer to be performed into the pool.

View File

@@ -1,7 +1,7 @@
#![allow(dead_code)]
pub mod encoding;
use std::str::FromStr;
use std::{fs, str::FromStr};
use alloy::{
primitives::{B256, U256},
@@ -71,10 +71,11 @@ pub fn get_signer() -> PrivateKeySigner {
}
pub fn get_tycho_router_encoder(user_transfer_type: UserTransferType) -> Box<dyn TychoEncoder> {
let executors_addresses = fs::read_to_string("config/test_executor_addresses.json").unwrap();
TychoRouterEncoderBuilder::new()
.chain(Chain::Ethereum)
.user_transfer_type(user_transfer_type)
.executors_file_path("config/test_executor_addresses.json".to_string())
.executors_addresses(executors_addresses)
.router_address(router_address())
.build()
.expect("Failed to build encoder")