Merge pull request #268 from propeller-heads/sdk-testing/dc/ENG-4831-upgrade-tycho-deps
feat: Add historical_trade option to encoding
This commit is contained in:
12
Cargo.toml
12
Cargo.toml
@@ -11,12 +11,12 @@ license = "MIT"
|
|||||||
categories = ["finance", "cryptography::cryptocurrencies"]
|
categories = ["finance", "cryptography::cryptocurrencies"]
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
exclude = [
|
exclude = [
|
||||||
"foundry/*",
|
"foundry/*",
|
||||||
"foundry",
|
"foundry",
|
||||||
"tests/*",
|
"tests/*",
|
||||||
"tests/common",
|
"tests/common",
|
||||||
".github/*",
|
".github/*",
|
||||||
".gitmodules",
|
".gitmodules",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
|
|||||||
@@ -1,9 +1,13 @@
|
|||||||
use std::io::{self, Read};
|
use std::{
|
||||||
|
fs,
|
||||||
|
io::{self, Read},
|
||||||
|
};
|
||||||
|
|
||||||
use alloy::sol_types::SolValue;
|
use alloy::sol_types::SolValue;
|
||||||
use clap::{Parser, Subcommand};
|
use clap::{Parser, Subcommand};
|
||||||
use tycho_common::{hex_bytes::Bytes, models::Chain};
|
use tycho_common::{hex_bytes::Bytes, models::Chain};
|
||||||
use tycho_execution::encoding::{
|
use tycho_execution::encoding::{
|
||||||
|
errors::EncodingError,
|
||||||
evm::{
|
evm::{
|
||||||
approvals::permit2::PermitSingle,
|
approvals::permit2::PermitSingle,
|
||||||
encoder_builders::{TychoExecutorEncoderBuilder, TychoRouterEncoderBuilder},
|
encoder_builders::{TychoExecutorEncoderBuilder, TychoRouterEncoderBuilder},
|
||||||
@@ -83,7 +87,12 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
Commands::TychoRouter => {
|
Commands::TychoRouter => {
|
||||||
let mut builder = TychoRouterEncoderBuilder::new().chain(chain);
|
let mut builder = TychoRouterEncoderBuilder::new().chain(chain);
|
||||||
if let Some(config_path) = cli.executors_file_path {
|
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 {
|
if let Some(router_address) = cli.router_address {
|
||||||
builder = builder.router_address(router_address);
|
builder = builder.router_address(router_address);
|
||||||
|
|||||||
@@ -20,9 +20,10 @@ use crate::encoding::{
|
|||||||
pub struct TychoRouterEncoderBuilder {
|
pub struct TychoRouterEncoderBuilder {
|
||||||
chain: Option<Chain>,
|
chain: Option<Chain>,
|
||||||
user_transfer_type: Option<UserTransferType>,
|
user_transfer_type: Option<UserTransferType>,
|
||||||
executors_file_path: Option<String>,
|
executors_addresses: Option<String>,
|
||||||
router_address: Option<Bytes>,
|
router_address: Option<Bytes>,
|
||||||
swapper_pk: Option<String>,
|
swapper_pk: Option<String>,
|
||||||
|
historical_trade: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for TychoRouterEncoderBuilder {
|
impl Default for TychoRouterEncoderBuilder {
|
||||||
@@ -35,10 +36,11 @@ impl TychoRouterEncoderBuilder {
|
|||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
TychoRouterEncoderBuilder {
|
TychoRouterEncoderBuilder {
|
||||||
chain: None,
|
chain: None,
|
||||||
executors_file_path: None,
|
executors_addresses: None,
|
||||||
router_address: None,
|
router_address: None,
|
||||||
swapper_pk: None,
|
swapper_pk: None,
|
||||||
user_transfer_type: None,
|
user_transfer_type: None,
|
||||||
|
historical_trade: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn chain(mut self, chain: Chain) -> Self {
|
pub fn chain(mut self, chain: Chain) -> Self {
|
||||||
@@ -51,10 +53,10 @@ impl TychoRouterEncoderBuilder {
|
|||||||
self
|
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)
|
/// If it's not set, the default value will be used (contents of config/executor_addresses.json)
|
||||||
pub fn executors_file_path(mut self, executors_file_path: String) -> Self {
|
pub fn executors_addresses(mut self, executors_addresses: String) -> Self {
|
||||||
self.executors_file_path = Some(executors_file_path);
|
self.executors_addresses = Some(executors_addresses);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,6 +67,15 @@ impl TychoRouterEncoderBuilder {
|
|||||||
self
|
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
|
/// 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
|
/// 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
|
/// using this option, you should sign and create the function calldata entirely on your
|
||||||
@@ -96,7 +107,7 @@ impl TychoRouterEncoderBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let swap_encoder_registry =
|
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 signer = if let Some(pk) = self.swapper_pk {
|
||||||
let pk = B256::from_str(&pk).map_err(|_| {
|
let pk = B256::from_str(&pk).map_err(|_| {
|
||||||
@@ -115,6 +126,7 @@ impl TychoRouterEncoderBuilder {
|
|||||||
tycho_router_address,
|
tycho_router_address,
|
||||||
user_transfer_type,
|
user_transfer_type,
|
||||||
signer,
|
signer,
|
||||||
|
self.historical_trade,
|
||||||
)?))
|
)?))
|
||||||
} else {
|
} else {
|
||||||
Err(EncodingError::FatalError(
|
Err(EncodingError::FatalError(
|
||||||
@@ -128,7 +140,7 @@ impl TychoRouterEncoderBuilder {
|
|||||||
/// Builder pattern for constructing a `TychoExecutorEncoder` with customizable options.
|
/// Builder pattern for constructing a `TychoExecutorEncoder` with customizable options.
|
||||||
pub struct TychoExecutorEncoderBuilder {
|
pub struct TychoExecutorEncoderBuilder {
|
||||||
chain: Option<Chain>,
|
chain: Option<Chain>,
|
||||||
executors_file_path: Option<String>,
|
executors_addresses: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for TychoExecutorEncoderBuilder {
|
impl Default for TychoExecutorEncoderBuilder {
|
||||||
@@ -139,17 +151,17 @@ impl Default for TychoExecutorEncoderBuilder {
|
|||||||
|
|
||||||
impl TychoExecutorEncoderBuilder {
|
impl TychoExecutorEncoderBuilder {
|
||||||
pub fn new() -> Self {
|
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 {
|
pub fn chain(mut self, chain: Chain) -> Self {
|
||||||
self.chain = Some(chain);
|
self.chain = Some(chain);
|
||||||
self
|
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)
|
/// 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 {
|
pub fn executors_addresses(mut self, executors_addresses: String) -> Self {
|
||||||
self.executors_file_path = Some(executors_file_path);
|
self.executors_addresses = Some(executors_addresses);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -158,7 +170,7 @@ impl TychoExecutorEncoderBuilder {
|
|||||||
pub fn build(self) -> Result<Box<dyn TychoEncoder>, EncodingError> {
|
pub fn build(self) -> Result<Box<dyn TychoEncoder>, EncodingError> {
|
||||||
if let Some(chain) = self.chain {
|
if let Some(chain) = self.chain {
|
||||||
let swap_encoder_registry =
|
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)?))
|
Ok(Box::new(TychoExecutorEncoder::new(swap_encoder_registry)?))
|
||||||
} else {
|
} else {
|
||||||
Err(EncodingError::FatalError(
|
Err(EncodingError::FatalError(
|
||||||
|
|||||||
@@ -58,11 +58,12 @@ use crate::encoding::{
|
|||||||
/// funds.
|
/// funds.
|
||||||
///
|
///
|
||||||
/// # Parameters
|
/// # Parameters
|
||||||
|
/// - `chain_id`: Chain ID
|
||||||
/// - `encoded_solution`: The solution already encoded by Tycho.
|
/// - `encoded_solution`: The solution already encoded by Tycho.
|
||||||
/// - `solution`: The high-level solution including tokens, amounts, and receiver info.
|
/// - `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.
|
/// - `user_transfer_type`: The desired transfer method.
|
||||||
/// - `router_address`: The address of the Tycho Router contract.
|
|
||||||
/// - `native_address`: The address used to represent the native token
|
/// - `native_address`: The address used to represent the native token
|
||||||
|
/// - `signer`: Optional signer for permit2
|
||||||
///
|
///
|
||||||
/// # Returns
|
/// # Returns
|
||||||
/// A `Result<Transaction, EncodingError>` that either contains the full transaction data (to,
|
/// A `Result<Transaction, EncodingError>` that either contains the full transaction data (to,
|
||||||
|
|||||||
@@ -26,12 +26,15 @@ use crate::encoding::{
|
|||||||
/// * `function_signature`: String, the signature for the swap function in the router contract
|
/// * `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
|
/// * `router_address`: Address of the router to be used to execute swaps
|
||||||
/// * `transfer_optimization`: TransferOptimization, responsible for optimizing the token transfers
|
/// * `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)]
|
#[derive(Clone)]
|
||||||
pub struct SingleSwapStrategyEncoder {
|
pub struct SingleSwapStrategyEncoder {
|
||||||
swap_encoder_registry: SwapEncoderRegistry,
|
swap_encoder_registry: SwapEncoderRegistry,
|
||||||
function_signature: String,
|
function_signature: String,
|
||||||
router_address: Bytes,
|
router_address: Bytes,
|
||||||
transfer_optimization: TransferOptimization,
|
transfer_optimization: TransferOptimization,
|
||||||
|
historical_trade: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SingleSwapStrategyEncoder {
|
impl SingleSwapStrategyEncoder {
|
||||||
@@ -40,6 +43,7 @@ impl SingleSwapStrategyEncoder {
|
|||||||
swap_encoder_registry: SwapEncoderRegistry,
|
swap_encoder_registry: SwapEncoderRegistry,
|
||||||
user_transfer_type: UserTransferType,
|
user_transfer_type: UserTransferType,
|
||||||
router_address: Bytes,
|
router_address: Bytes,
|
||||||
|
historical_trade: bool,
|
||||||
) -> Result<Self, EncodingError> {
|
) -> Result<Self, EncodingError> {
|
||||||
let function_signature = if user_transfer_type == UserTransferType::TransferFromPermit2 {
|
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)"
|
"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,
|
user_transfer_type,
|
||||||
router_address,
|
router_address,
|
||||||
),
|
),
|
||||||
|
historical_trade,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,6 +124,7 @@ impl StrategyEncoder for SingleSwapStrategyEncoder {
|
|||||||
group_token_in: grouped_swap.token_in.clone(),
|
group_token_in: grouped_swap.token_in.clone(),
|
||||||
group_token_out: grouped_swap.token_out.clone(),
|
group_token_out: grouped_swap.token_out.clone(),
|
||||||
transfer_type: transfer,
|
transfer_type: transfer,
|
||||||
|
historical_trade: self.historical_trade,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut grouped_protocol_data: Vec<Vec<u8>> = vec![];
|
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_validator`: SequentialSwapValidator, responsible for checking validity of
|
||||||
/// sequential swap solutions
|
/// sequential swap solutions
|
||||||
/// * `transfer_optimization`: TransferOptimization, responsible for optimizing the token transfers
|
/// * `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)]
|
#[derive(Clone)]
|
||||||
pub struct SequentialSwapStrategyEncoder {
|
pub struct SequentialSwapStrategyEncoder {
|
||||||
swap_encoder_registry: SwapEncoderRegistry,
|
swap_encoder_registry: SwapEncoderRegistry,
|
||||||
@@ -180,6 +188,7 @@ pub struct SequentialSwapStrategyEncoder {
|
|||||||
wrapped_address: Bytes,
|
wrapped_address: Bytes,
|
||||||
sequential_swap_validator: SequentialSwapValidator,
|
sequential_swap_validator: SequentialSwapValidator,
|
||||||
transfer_optimization: TransferOptimization,
|
transfer_optimization: TransferOptimization,
|
||||||
|
historical_trade: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SequentialSwapStrategyEncoder {
|
impl SequentialSwapStrategyEncoder {
|
||||||
@@ -188,6 +197,7 @@ impl SequentialSwapStrategyEncoder {
|
|||||||
swap_encoder_registry: SwapEncoderRegistry,
|
swap_encoder_registry: SwapEncoderRegistry,
|
||||||
user_transfer_type: UserTransferType,
|
user_transfer_type: UserTransferType,
|
||||||
router_address: Bytes,
|
router_address: Bytes,
|
||||||
|
historical_trade: bool,
|
||||||
) -> Result<Self, EncodingError> {
|
) -> Result<Self, EncodingError> {
|
||||||
let function_signature = if user_transfer_type == UserTransferType::TransferFromPermit2 {
|
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)"
|
"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,
|
user_transfer_type,
|
||||||
router_address,
|
router_address,
|
||||||
),
|
),
|
||||||
|
historical_trade,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -279,6 +290,7 @@ impl StrategyEncoder for SequentialSwapStrategyEncoder {
|
|||||||
group_token_in: grouped_swap.token_in.clone(),
|
group_token_in: grouped_swap.token_in.clone(),
|
||||||
group_token_out: grouped_swap.token_out.clone(),
|
group_token_out: grouped_swap.token_out.clone(),
|
||||||
transfer_type: transfer,
|
transfer_type: transfer,
|
||||||
|
historical_trade: self.historical_trade,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut grouped_protocol_data: Vec<Vec<u8>> = vec![];
|
let mut grouped_protocol_data: Vec<Vec<u8>> = vec![];
|
||||||
@@ -336,6 +348,8 @@ impl StrategyEncoder for SequentialSwapStrategyEncoder {
|
|||||||
/// solutions
|
/// solutions
|
||||||
/// * `router_address`: Address of the router to be used to execute swaps
|
/// * `router_address`: Address of the router to be used to execute swaps
|
||||||
/// * `transfer_optimization`: TransferOptimization, responsible for optimizing the token transfers
|
/// * `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)]
|
#[derive(Clone)]
|
||||||
pub struct SplitSwapStrategyEncoder {
|
pub struct SplitSwapStrategyEncoder {
|
||||||
swap_encoder_registry: SwapEncoderRegistry,
|
swap_encoder_registry: SwapEncoderRegistry,
|
||||||
@@ -345,6 +359,7 @@ pub struct SplitSwapStrategyEncoder {
|
|||||||
split_swap_validator: SplitSwapValidator,
|
split_swap_validator: SplitSwapValidator,
|
||||||
router_address: Bytes,
|
router_address: Bytes,
|
||||||
transfer_optimization: TransferOptimization,
|
transfer_optimization: TransferOptimization,
|
||||||
|
historical_trade: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SplitSwapStrategyEncoder {
|
impl SplitSwapStrategyEncoder {
|
||||||
@@ -353,6 +368,7 @@ impl SplitSwapStrategyEncoder {
|
|||||||
swap_encoder_registry: SwapEncoderRegistry,
|
swap_encoder_registry: SwapEncoderRegistry,
|
||||||
user_transfer_type: UserTransferType,
|
user_transfer_type: UserTransferType,
|
||||||
router_address: Bytes,
|
router_address: Bytes,
|
||||||
|
historical_trade: bool,
|
||||||
) -> Result<Self, EncodingError> {
|
) -> Result<Self, EncodingError> {
|
||||||
let function_signature = if user_transfer_type == UserTransferType::TransferFromPermit2 {
|
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)"
|
"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,
|
user_transfer_type,
|
||||||
router_address,
|
router_address,
|
||||||
),
|
),
|
||||||
|
historical_trade,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -479,6 +496,7 @@ impl StrategyEncoder for SplitSwapStrategyEncoder {
|
|||||||
group_token_in: grouped_swap.token_in.clone(),
|
group_token_in: grouped_swap.token_in.clone(),
|
||||||
group_token_out: grouped_swap.token_out.clone(),
|
group_token_out: grouped_swap.token_out.clone(),
|
||||||
transfer_type: transfer,
|
transfer_type: transfer,
|
||||||
|
historical_trade: self.historical_trade,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut grouped_protocol_data: Vec<Vec<u8>> = vec![];
|
let mut grouped_protocol_data: Vec<Vec<u8>> = vec![];
|
||||||
@@ -535,7 +553,7 @@ impl StrategyEncoder for SplitSwapStrategyEncoder {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use std::{collections::HashMap, str::FromStr};
|
use std::{collections::HashMap, fs, str::FromStr};
|
||||||
|
|
||||||
use alloy::{hex::encode, primitives::hex};
|
use alloy::{hex::encode, primitives::hex};
|
||||||
use num_bigint::{BigInt, BigUint};
|
use num_bigint::{BigInt, BigUint};
|
||||||
@@ -555,9 +573,10 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn get_swap_encoder_registry() -> SwapEncoderRegistry {
|
fn get_swap_encoder_registry() -> SwapEncoderRegistry {
|
||||||
|
let executors_addresses =
|
||||||
|
fs::read_to_string("config/test_executor_addresses.json").unwrap();
|
||||||
let eth_chain = eth_chain();
|
let eth_chain = eth_chain();
|
||||||
SwapEncoderRegistry::new(Some("config/test_executor_addresses.json".to_string()), eth_chain)
|
SwapEncoderRegistry::new(Some(executors_addresses), eth_chain).unwrap()
|
||||||
.unwrap()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn router_address() -> Bytes {
|
fn router_address() -> Bytes {
|
||||||
@@ -591,6 +610,7 @@ mod tests {
|
|||||||
swap_encoder_registry,
|
swap_encoder_registry,
|
||||||
UserTransferType::TransferFromPermit2,
|
UserTransferType::TransferFromPermit2,
|
||||||
router_address(),
|
router_address(),
|
||||||
|
false,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let solution = Solution {
|
let solution = Solution {
|
||||||
@@ -651,6 +671,7 @@ mod tests {
|
|||||||
swap_encoder_registry,
|
swap_encoder_registry,
|
||||||
UserTransferType::None,
|
UserTransferType::None,
|
||||||
router_address(),
|
router_address(),
|
||||||
|
false,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let solution = Solution {
|
let solution = Solution {
|
||||||
@@ -732,6 +753,7 @@ mod tests {
|
|||||||
swap_encoder_registry,
|
swap_encoder_registry,
|
||||||
UserTransferType::TransferFrom,
|
UserTransferType::TransferFrom,
|
||||||
router_address(),
|
router_address(),
|
||||||
|
false,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let solution = Solution {
|
let solution = Solution {
|
||||||
@@ -867,6 +889,7 @@ mod tests {
|
|||||||
swap_encoder_registry,
|
swap_encoder_registry,
|
||||||
UserTransferType::TransferFromPermit2,
|
UserTransferType::TransferFromPermit2,
|
||||||
Bytes::from("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395"),
|
Bytes::from("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395"),
|
||||||
|
false,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
@@ -1015,6 +1038,7 @@ mod tests {
|
|||||||
swap_encoder_registry,
|
swap_encoder_registry,
|
||||||
UserTransferType::TransferFrom,
|
UserTransferType::TransferFrom,
|
||||||
Bytes::from("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395"),
|
Bytes::from("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395"),
|
||||||
|
false,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use std::{collections::HashMap, fs};
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use tycho_common::models::Chain;
|
use tycho_common::models::Chain;
|
||||||
|
|
||||||
@@ -21,13 +21,9 @@ pub struct SwapEncoderRegistry {
|
|||||||
impl SwapEncoderRegistry {
|
impl SwapEncoderRegistry {
|
||||||
/// Populates the registry with the `SwapEncoders` for the given blockchain by parsing the
|
/// Populates the registry with the `SwapEncoders` for the given blockchain by parsing the
|
||||||
/// executors' addresses in the file at the given path.
|
/// executors' addresses in the file at the given path.
|
||||||
pub fn new(executors_file_path: Option<String>, chain: Chain) -> Result<Self, EncodingError> {
|
pub fn new(executors_addresses: Option<String>, chain: Chain) -> Result<Self, EncodingError> {
|
||||||
let config_str = if let Some(ref path) = executors_file_path {
|
let config_str = if let Some(addresses) = executors_addresses {
|
||||||
fs::read_to_string(path).map_err(|e| {
|
addresses
|
||||||
EncodingError::FatalError(format!(
|
|
||||||
"Error reading executors file from {executors_file_path:?}: {e}",
|
|
||||||
))
|
|
||||||
})?
|
|
||||||
} else {
|
} else {
|
||||||
DEFAULT_EXECUTORS_JSON.to_string()
|
DEFAULT_EXECUTORS_JSON.to_string()
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -280,19 +280,20 @@ impl SwapEncoder for BalancerV2SwapEncoder {
|
|||||||
) -> Result<Vec<u8>, EncodingError> {
|
) -> Result<Vec<u8>, EncodingError> {
|
||||||
let token_approvals_manager = ProtocolApprovalsManager::new()?;
|
let token_approvals_manager = ProtocolApprovalsManager::new()?;
|
||||||
let token = bytes_to_address(&swap.token_in)?;
|
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 let Some(router_address) = &encoding_context.router_address {
|
||||||
let tycho_router_address = bytes_to_address(router_address)?;
|
if !encoding_context.historical_trade {
|
||||||
approval_needed = token_approvals_manager.approval_needed(
|
let tycho_router_address = bytes_to_address(router_address)?;
|
||||||
token,
|
approval_needed = token_approvals_manager.approval_needed(
|
||||||
tycho_router_address,
|
token,
|
||||||
Address::from_str(&self.vault_address)
|
tycho_router_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)
|
let component_id = AlloyBytes::from_str(&swap.component.id)
|
||||||
.map_err(|_| EncodingError::FatalError("Invalid component ID".to_string()))?;
|
.map_err(|_| EncodingError::FatalError("Invalid component ID".to_string()))?;
|
||||||
@@ -1026,6 +1027,7 @@ mod tests {
|
|||||||
group_token_in: token_in.clone(),
|
group_token_in: token_in.clone(),
|
||||||
group_token_out: token_out.clone(),
|
group_token_out: token_out.clone(),
|
||||||
transfer_type: TransferType::Transfer,
|
transfer_type: TransferType::Transfer,
|
||||||
|
historical_trade: false,
|
||||||
};
|
};
|
||||||
let encoder = UniswapV2SwapEncoder::new(
|
let encoder = UniswapV2SwapEncoder::new(
|
||||||
String::from("0x543778987b293C7E8Cf0722BB2e935ba6f4068D4"),
|
String::from("0x543778987b293C7E8Cf0722BB2e935ba6f4068D4"),
|
||||||
@@ -1081,6 +1083,7 @@ mod tests {
|
|||||||
group_token_in: token_in.clone(),
|
group_token_in: token_in.clone(),
|
||||||
group_token_out: token_out.clone(),
|
group_token_out: token_out.clone(),
|
||||||
transfer_type: TransferType::Transfer,
|
transfer_type: TransferType::Transfer,
|
||||||
|
historical_trade: false,
|
||||||
};
|
};
|
||||||
let encoder = UniswapV3SwapEncoder::new(
|
let encoder = UniswapV3SwapEncoder::new(
|
||||||
String::from("0x543778987b293C7E8Cf0722BB2e935ba6f4068D4"),
|
String::from("0x543778987b293C7E8Cf0722BB2e935ba6f4068D4"),
|
||||||
@@ -1138,6 +1141,7 @@ mod tests {
|
|||||||
group_token_in: token_in.clone(),
|
group_token_in: token_in.clone(),
|
||||||
group_token_out: token_out.clone(),
|
group_token_out: token_out.clone(),
|
||||||
transfer_type: TransferType::None,
|
transfer_type: TransferType::None,
|
||||||
|
historical_trade: true,
|
||||||
};
|
};
|
||||||
let encoder = BalancerV2SwapEncoder::new(
|
let encoder = BalancerV2SwapEncoder::new(
|
||||||
String::from("0x543778987b293C7E8Cf0722BB2e935ba6f4068D4"),
|
String::from("0x543778987b293C7E8Cf0722BB2e935ba6f4068D4"),
|
||||||
@@ -1207,6 +1211,7 @@ mod tests {
|
|||||||
group_token_in: token_in.clone(),
|
group_token_in: token_in.clone(),
|
||||||
group_token_out: token_out.clone(),
|
group_token_out: token_out.clone(),
|
||||||
transfer_type: TransferType::Transfer,
|
transfer_type: TransferType::Transfer,
|
||||||
|
historical_trade: false,
|
||||||
};
|
};
|
||||||
let encoder = UniswapV4SwapEncoder::new(
|
let encoder = UniswapV4SwapEncoder::new(
|
||||||
String::from("0xF62849F9A0B5Bf2913b396098F7c7019b51A820a"),
|
String::from("0xF62849F9A0B5Bf2913b396098F7c7019b51A820a"),
|
||||||
@@ -1275,6 +1280,7 @@ mod tests {
|
|||||||
// Token out is the same as the group token out
|
// Token out is the same as the group token out
|
||||||
group_token_out: token_out.clone(),
|
group_token_out: token_out.clone(),
|
||||||
transfer_type: TransferType::Transfer,
|
transfer_type: TransferType::Transfer,
|
||||||
|
historical_trade: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
let encoder = UniswapV4SwapEncoder::new(
|
let encoder = UniswapV4SwapEncoder::new(
|
||||||
@@ -1318,6 +1324,7 @@ mod tests {
|
|||||||
group_token_in: usde_address.clone(),
|
group_token_in: usde_address.clone(),
|
||||||
group_token_out: wbtc_address.clone(),
|
group_token_out: wbtc_address.clone(),
|
||||||
transfer_type: TransferType::Transfer,
|
transfer_type: TransferType::Transfer,
|
||||||
|
historical_trade: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Setup - First sequence: USDE -> USDT
|
// Setup - First sequence: USDE -> USDT
|
||||||
@@ -1448,6 +1455,7 @@ mod tests {
|
|||||||
exact_out: false,
|
exact_out: false,
|
||||||
router_address: Some(Bytes::default()),
|
router_address: Some(Bytes::default()),
|
||||||
transfer_type: TransferType::Transfer,
|
transfer_type: TransferType::Transfer,
|
||||||
|
historical_trade: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
let encoder = EkuboSwapEncoder::new(String::default(), Chain::Ethereum, None).unwrap();
|
let encoder = EkuboSwapEncoder::new(String::default(), Chain::Ethereum, None).unwrap();
|
||||||
@@ -1490,6 +1498,7 @@ mod tests {
|
|||||||
exact_out: false,
|
exact_out: false,
|
||||||
router_address: Some(Bytes::default()),
|
router_address: Some(Bytes::default()),
|
||||||
transfer_type: TransferType::Transfer,
|
transfer_type: TransferType::Transfer,
|
||||||
|
historical_trade: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
let first_swap = SwapBuilder::new(
|
let first_swap = SwapBuilder::new(
|
||||||
@@ -1687,6 +1696,7 @@ mod tests {
|
|||||||
group_token_in: token_in.clone(),
|
group_token_in: token_in.clone(),
|
||||||
group_token_out: token_out.clone(),
|
group_token_out: token_out.clone(),
|
||||||
transfer_type: TransferType::None,
|
transfer_type: TransferType::None,
|
||||||
|
historical_trade: false,
|
||||||
};
|
};
|
||||||
let encoder = CurveSwapEncoder::new(
|
let encoder = CurveSwapEncoder::new(
|
||||||
String::from("0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f"),
|
String::from("0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f"),
|
||||||
@@ -1753,6 +1763,7 @@ mod tests {
|
|||||||
group_token_in: token_in.clone(),
|
group_token_in: token_in.clone(),
|
||||||
group_token_out: token_out.clone(),
|
group_token_out: token_out.clone(),
|
||||||
transfer_type: TransferType::None,
|
transfer_type: TransferType::None,
|
||||||
|
historical_trade: false,
|
||||||
};
|
};
|
||||||
let encoder = CurveSwapEncoder::new(
|
let encoder = CurveSwapEncoder::new(
|
||||||
String::from("0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f"),
|
String::from("0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f"),
|
||||||
@@ -1820,6 +1831,7 @@ mod tests {
|
|||||||
group_token_in: token_in.clone(),
|
group_token_in: token_in.clone(),
|
||||||
group_token_out: token_out.clone(),
|
group_token_out: token_out.clone(),
|
||||||
transfer_type: TransferType::None,
|
transfer_type: TransferType::None,
|
||||||
|
historical_trade: false,
|
||||||
};
|
};
|
||||||
let encoder = CurveSwapEncoder::new(
|
let encoder = CurveSwapEncoder::new(
|
||||||
String::from("0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f"),
|
String::from("0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f"),
|
||||||
@@ -1888,6 +1900,7 @@ mod tests {
|
|||||||
group_token_in: token_in.clone(),
|
group_token_in: token_in.clone(),
|
||||||
group_token_out: token_out.clone(),
|
group_token_out: token_out.clone(),
|
||||||
transfer_type: TransferType::Transfer,
|
transfer_type: TransferType::Transfer,
|
||||||
|
historical_trade: false,
|
||||||
};
|
};
|
||||||
let encoder = BalancerV3SwapEncoder::new(
|
let encoder = BalancerV3SwapEncoder::new(
|
||||||
String::from("0x543778987b293C7E8Cf0722BB2e935ba6f4068D4"),
|
String::from("0x543778987b293C7E8Cf0722BB2e935ba6f4068D4"),
|
||||||
@@ -1940,6 +1953,7 @@ mod tests {
|
|||||||
group_token_in: token_in.clone(),
|
group_token_in: token_in.clone(),
|
||||||
group_token_out: token_out.clone(),
|
group_token_out: token_out.clone(),
|
||||||
transfer_type: TransferType::Transfer,
|
transfer_type: TransferType::Transfer,
|
||||||
|
historical_trade: false,
|
||||||
};
|
};
|
||||||
let encoder = MaverickV2SwapEncoder::new(
|
let encoder = MaverickV2SwapEncoder::new(
|
||||||
String::from("0x543778987b293C7E8Cf0722BB2e935ba6f4068D4"),
|
String::from("0x543778987b293C7E8Cf0722BB2e935ba6f4068D4"),
|
||||||
@@ -2033,6 +2047,7 @@ mod tests {
|
|||||||
group_token_in: token_in.clone(),
|
group_token_in: token_in.clone(),
|
||||||
group_token_out: token_out.clone(),
|
group_token_out: token_out.clone(),
|
||||||
transfer_type: TransferType::Transfer,
|
transfer_type: TransferType::Transfer,
|
||||||
|
historical_trade: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
let encoder = BebopSwapEncoder::new(
|
let encoder = BebopSwapEncoder::new(
|
||||||
@@ -2107,6 +2122,7 @@ mod tests {
|
|||||||
group_token_in: token_in.clone(),
|
group_token_in: token_in.clone(),
|
||||||
group_token_out: token_out.clone(),
|
group_token_out: token_out.clone(),
|
||||||
transfer_type: TransferType::Transfer,
|
transfer_type: TransferType::Transfer,
|
||||||
|
historical_trade: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
let encoder = HashflowSwapEncoder::new(
|
let encoder = HashflowSwapEncoder::new(
|
||||||
@@ -2200,6 +2216,7 @@ mod tests {
|
|||||||
group_token_in: token_in.clone(),
|
group_token_in: token_in.clone(),
|
||||||
group_token_out: token_out.clone(),
|
group_token_out: token_out.clone(),
|
||||||
transfer_type: TransferType::Transfer,
|
transfer_type: TransferType::Transfer,
|
||||||
|
historical_trade: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
let encoder = HashflowSwapEncoder::new(
|
let encoder = HashflowSwapEncoder::new(
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ impl TychoRouterEncoder {
|
|||||||
router_address: Bytes,
|
router_address: Bytes,
|
||||||
user_transfer_type: UserTransferType,
|
user_transfer_type: UserTransferType,
|
||||||
signer: Option<PrivateKeySigner>,
|
signer: Option<PrivateKeySigner>,
|
||||||
|
historical_trade: bool,
|
||||||
) -> Result<Self, EncodingError> {
|
) -> Result<Self, EncodingError> {
|
||||||
let permit2 = if user_transfer_type == UserTransferType::TransferFromPermit2 {
|
let permit2 = if user_transfer_type == UserTransferType::TransferFromPermit2 {
|
||||||
Some(Permit2::new()?)
|
Some(Permit2::new()?)
|
||||||
@@ -66,18 +67,21 @@ impl TychoRouterEncoder {
|
|||||||
swap_encoder_registry.clone(),
|
swap_encoder_registry.clone(),
|
||||||
user_transfer_type.clone(),
|
user_transfer_type.clone(),
|
||||||
router_address.clone(),
|
router_address.clone(),
|
||||||
|
historical_trade,
|
||||||
)?,
|
)?,
|
||||||
sequential_swap_strategy: SequentialSwapStrategyEncoder::new(
|
sequential_swap_strategy: SequentialSwapStrategyEncoder::new(
|
||||||
chain,
|
chain,
|
||||||
swap_encoder_registry.clone(),
|
swap_encoder_registry.clone(),
|
||||||
user_transfer_type.clone(),
|
user_transfer_type.clone(),
|
||||||
router_address.clone(),
|
router_address.clone(),
|
||||||
|
historical_trade,
|
||||||
)?,
|
)?,
|
||||||
split_swap_strategy: SplitSwapStrategyEncoder::new(
|
split_swap_strategy: SplitSwapStrategyEncoder::new(
|
||||||
chain,
|
chain,
|
||||||
swap_encoder_registry,
|
swap_encoder_registry,
|
||||||
user_transfer_type.clone(),
|
user_transfer_type.clone(),
|
||||||
router_address.clone(),
|
router_address.clone(),
|
||||||
|
historical_trade,
|
||||||
)?,
|
)?,
|
||||||
router_address,
|
router_address,
|
||||||
permit2,
|
permit2,
|
||||||
@@ -331,6 +335,7 @@ impl TychoExecutorEncoder {
|
|||||||
group_token_in: grouped_swap.token_in.clone(),
|
group_token_in: grouped_swap.token_in.clone(),
|
||||||
group_token_out: grouped_swap.token_out.clone(),
|
group_token_out: grouped_swap.token_out.clone(),
|
||||||
transfer_type: transfer,
|
transfer_type: transfer,
|
||||||
|
historical_trade: false,
|
||||||
};
|
};
|
||||||
let mut grouped_protocol_data: Vec<Vec<u8>> = vec![];
|
let mut grouped_protocol_data: Vec<Vec<u8>> = vec![];
|
||||||
let mut initial_protocol_data: Vec<u8> = vec![];
|
let mut initial_protocol_data: Vec<u8> = vec![];
|
||||||
@@ -400,7 +405,7 @@ impl TychoEncoder for TychoExecutorEncoder {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use std::{collections::HashMap, str::FromStr};
|
use std::{collections::HashMap, fs, str::FromStr};
|
||||||
|
|
||||||
use num_bigint::{BigInt, BigUint};
|
use num_bigint::{BigInt, BigUint};
|
||||||
use tycho_common::models::{protocol::ProtocolComponent, Chain};
|
use tycho_common::models::{protocol::ProtocolComponent, Chain};
|
||||||
@@ -484,11 +489,9 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn get_swap_encoder_registry() -> SwapEncoderRegistry {
|
fn get_swap_encoder_registry() -> SwapEncoderRegistry {
|
||||||
SwapEncoderRegistry::new(
|
let executors_addresses =
|
||||||
Some("config/test_executor_addresses.json".to_string()),
|
fs::read_to_string("config/test_executor_addresses.json").unwrap();
|
||||||
eth_chain(),
|
SwapEncoderRegistry::new(Some(executors_addresses), eth_chain()).unwrap()
|
||||||
)
|
|
||||||
.unwrap()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_tycho_router_encoder(user_transfer_type: UserTransferType) -> TychoRouterEncoder {
|
fn get_tycho_router_encoder(user_transfer_type: UserTransferType) -> TychoRouterEncoder {
|
||||||
@@ -498,6 +501,7 @@ mod tests {
|
|||||||
router_address(),
|
router_address(),
|
||||||
user_transfer_type,
|
user_transfer_type,
|
||||||
None,
|
None,
|
||||||
|
false,
|
||||||
)
|
)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -273,6 +273,8 @@ impl PartialEq for PermitDetails {
|
|||||||
/// * `group_token_in`: Token to be used as the input for the group swap.
|
/// * `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.
|
/// * `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.
|
/// * `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)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct EncodingContext {
|
pub struct EncodingContext {
|
||||||
pub receiver: Bytes,
|
pub receiver: Bytes,
|
||||||
@@ -281,6 +283,7 @@ pub struct EncodingContext {
|
|||||||
pub group_token_in: Bytes,
|
pub group_token_in: Bytes,
|
||||||
pub group_token_out: Bytes,
|
pub group_token_out: Bytes,
|
||||||
pub transfer_type: TransferType,
|
pub transfer_type: TransferType,
|
||||||
|
pub historical_trade: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents the type of transfer to be performed into the pool.
|
/// Represents the type of transfer to be performed into the pool.
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
pub mod encoding;
|
pub mod encoding;
|
||||||
|
|
||||||
use std::str::FromStr;
|
use std::{fs, str::FromStr};
|
||||||
|
|
||||||
use alloy::{
|
use alloy::{
|
||||||
primitives::{B256, U256},
|
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> {
|
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()
|
TychoRouterEncoderBuilder::new()
|
||||||
.chain(Chain::Ethereum)
|
.chain(Chain::Ethereum)
|
||||||
.user_transfer_type(user_transfer_type)
|
.user_transfer_type(user_transfer_type)
|
||||||
.executors_file_path("config/test_executor_addresses.json".to_string())
|
.executors_addresses(executors_addresses)
|
||||||
.router_address(router_address())
|
.router_address(router_address())
|
||||||
.build()
|
.build()
|
||||||
.expect("Failed to build encoder")
|
.expect("Failed to build encoder")
|
||||||
|
|||||||
Reference in New Issue
Block a user