feat: Allow for token_in_already_in_router

--- don't change below this line ---
ENG-4446 Took 31 minutes


Took 26 seconds
This commit is contained in:
Diana Carvalho
2025-04-22 14:01:03 +01:00
parent 304740574b
commit df92be8875
4 changed files with 109 additions and 18 deletions

View File

@@ -21,6 +21,7 @@ pub struct TychoRouterEncoderBuilder {
chain: Option<Chain>, chain: Option<Chain>,
executors_file_path: Option<String>, executors_file_path: Option<String>,
router_address: Option<Bytes>, router_address: Option<Bytes>,
token_in_already_in_router: Option<bool>,
} }
impl Default for TychoRouterEncoderBuilder { impl Default for TychoRouterEncoderBuilder {
@@ -36,6 +37,7 @@ impl TychoRouterEncoderBuilder {
chain: None, chain: None,
executors_file_path: None, executors_file_path: None,
router_address: None, router_address: None,
token_in_already_in_router: None,
} }
} }
pub fn chain(mut self, chain: TychoCommonChain) -> Self { pub fn chain(mut self, chain: TychoCommonChain) -> Self {
@@ -62,6 +64,16 @@ impl TychoRouterEncoderBuilder {
self self
} }
// Sets the `token_in_already_in_router` flag.
// If set to true, the encoder will assume that the token in is already in the router.
// WARNING: this is an advanced feature and should be used with caution. Make sure you have
// checks to make sure that your tokens won't be lost. The Router is not considered safe to hold
// tokens, so if this is not done within the same transaction you will lose your tokens.
pub fn token_in_already_in_router(mut self, token_in_already_in_router: bool) -> Self {
self.token_in_already_in_router = Some(token_in_already_in_router);
self
}
/// Builds the `TychoRouterEncoder` instance using the configured chain. /// Builds the `TychoRouterEncoder` instance using the configured chain.
/// Returns an error if either the chain has not been set. /// Returns an error if either the chain has not been set.
pub fn build(self) -> Result<Box<dyn TychoEncoder>, EncodingError> { pub fn build(self) -> Result<Box<dyn TychoEncoder>, EncodingError> {
@@ -88,6 +100,8 @@ impl TychoRouterEncoderBuilder {
swap_encoder_registry, swap_encoder_registry,
self.swapper_pk, self.swapper_pk,
tycho_router_address, tycho_router_address,
self.token_in_already_in_router
.unwrap_or(false),
)?)) )?))
} else { } else {
Err(EncodingError::FatalError( Err(EncodingError::FatalError(

View File

@@ -49,6 +49,7 @@ impl SingleSwapStrategyEncoder {
swap_encoder_registry: SwapEncoderRegistry, swap_encoder_registry: SwapEncoderRegistry,
swapper_pk: Option<String>, swapper_pk: Option<String>,
router_address: Bytes, router_address: Bytes,
token_in_already_in_router: bool,
) -> Result<Self, EncodingError> { ) -> Result<Self, EncodingError> {
let (permit2, selector) = if let Some(swapper_pk) = swapper_pk { let (permit2, selector) = if let Some(swapper_pk) = swapper_pk {
(Some(Permit2::new(swapper_pk, chain.clone())?), "singleSwapPermit2(uint256,address,address,uint256,bool,bool,address,((address,uint160,uint48,uint48),address,uint256),bytes,bytes)".to_string()) (Some(Permit2::new(swapper_pk, chain.clone())?), "singleSwapPermit2(uint256,address,address,uint256,bool,bool,address,((address,uint160,uint48,uint48),address,uint256),bytes,bytes)".to_string())
@@ -68,6 +69,7 @@ impl SingleSwapStrategyEncoder {
chain.native_token()?, chain.native_token()?,
chain.wrapped_token()?, chain.wrapped_token()?,
permit2_is_active, permit2_is_active,
token_in_already_in_router,
), ),
}) })
} }
@@ -228,6 +230,7 @@ impl SequentialSwapStrategyEncoder {
swap_encoder_registry: SwapEncoderRegistry, swap_encoder_registry: SwapEncoderRegistry,
swapper_pk: Option<String>, swapper_pk: Option<String>,
router_address: Bytes, router_address: Bytes,
token_in_already_in_router: bool,
) -> Result<Self, EncodingError> { ) -> Result<Self, EncodingError> {
let (permit2, selector) = if let Some(swapper_pk) = swapper_pk { let (permit2, selector) = if let Some(swapper_pk) = swapper_pk {
(Some(Permit2::new(swapper_pk, chain.clone())?), "sequentialSwapPermit2(uint256,address,address,uint256,bool,bool,address,((address,uint160,uint48,uint48),address,uint256),bytes,bytes)".to_string()) (Some(Permit2::new(swapper_pk, chain.clone())?), "sequentialSwapPermit2(uint256,address,address,uint256,bool,bool,address,((address,uint160,uint48,uint48),address,uint256),bytes,bytes)".to_string())
@@ -251,6 +254,7 @@ impl SequentialSwapStrategyEncoder {
chain.native_token()?, chain.native_token()?,
chain.wrapped_token()?, chain.wrapped_token()?,
permit2_is_active, permit2_is_active,
token_in_already_in_router,
), ),
}) })
} }
@@ -440,6 +444,7 @@ impl SplitSwapStrategyEncoder {
swap_encoder_registry: SwapEncoderRegistry, swap_encoder_registry: SwapEncoderRegistry,
swapper_pk: Option<String>, swapper_pk: Option<String>,
router_address: Bytes, router_address: Bytes,
token_in_already_in_router: bool,
) -> Result<Self, EncodingError> { ) -> Result<Self, EncodingError> {
let (permit2, selector) = if let Some(swapper_pk) = swapper_pk { let (permit2, selector) = if let Some(swapper_pk) = swapper_pk {
(Some(Permit2::new(swapper_pk, chain.clone())?), "splitSwapPermit2(uint256,address,address,uint256,bool,bool,uint256,address,((address,uint160,uint48,uint48),address,uint256),bytes,bytes)".to_string()) (Some(Permit2::new(swapper_pk, chain.clone())?), "splitSwapPermit2(uint256,address,address,uint256,bool,bool,uint256,address,((address,uint160,uint48,uint48),address,uint256),bytes,bytes)".to_string())
@@ -463,6 +468,7 @@ impl SplitSwapStrategyEncoder {
chain.native_token()?, chain.native_token()?,
chain.wrapped_token()?, chain.wrapped_token()?,
permit2_is_active, permit2_is_active,
token_in_already_in_router,
), ),
}) })
} }
@@ -741,6 +747,7 @@ mod tests {
swap_encoder_registry, swap_encoder_registry,
Some(private_key), Some(private_key),
Bytes::from_str("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395").unwrap(), Bytes::from_str("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395").unwrap(),
false,
) )
.unwrap(); .unwrap();
let solution = Solution { let solution = Solution {
@@ -824,6 +831,7 @@ mod tests {
swap_encoder_registry, swap_encoder_registry,
None, None,
Bytes::from_str("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395").unwrap(), Bytes::from_str("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395").unwrap(),
false,
) )
.unwrap(); .unwrap();
let solution = Solution { let solution = Solution {
@@ -901,6 +909,7 @@ mod tests {
swap_encoder_registry, swap_encoder_registry,
Some(private_key), Some(private_key),
Bytes::from("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395"), Bytes::from("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395"),
false,
) )
.unwrap(); .unwrap();
let solution = Solution { let solution = Solution {
@@ -953,6 +962,7 @@ mod tests {
swap_encoder_registry, swap_encoder_registry,
Some(private_key), Some(private_key),
Bytes::from("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395"), Bytes::from("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395"),
false,
) )
.unwrap(); .unwrap();
let solution = Solution { let solution = Solution {
@@ -1024,6 +1034,7 @@ mod tests {
swap_encoder_registry, swap_encoder_registry,
Some(private_key), Some(private_key),
Bytes::from_str("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395").unwrap(), Bytes::from_str("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395").unwrap(),
false,
) )
.unwrap(); .unwrap();
let solution = Solution { let solution = Solution {
@@ -1083,6 +1094,7 @@ mod tests {
swap_encoder_registry, swap_encoder_registry,
None, None,
Bytes::from_str("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395").unwrap(), Bytes::from_str("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395").unwrap(),
false,
) )
.unwrap(); .unwrap();
let solution = Solution { let solution = Solution {
@@ -1201,6 +1213,7 @@ mod tests {
swap_encoder_registry, swap_encoder_registry,
Some(private_key), Some(private_key),
Bytes::from("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395"), Bytes::from("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395"),
false,
) )
.unwrap(); .unwrap();
@@ -1318,6 +1331,7 @@ mod tests {
swap_encoder_registry, swap_encoder_registry,
None, None,
Bytes::from_str("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395").unwrap(), Bytes::from_str("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395").unwrap(),
false,
) )
.unwrap(); .unwrap();
let solution = Solution { let solution = Solution {
@@ -1399,6 +1413,7 @@ mod tests {
swap_encoder_registry, swap_encoder_registry,
None, None,
Bytes::from_str("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395").unwrap(), Bytes::from_str("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395").unwrap(),
false,
) )
.unwrap(); .unwrap();
let solution = Solution { let solution = Solution {
@@ -1484,6 +1499,7 @@ mod tests {
swap_encoder_registry, swap_encoder_registry,
None, None,
Bytes::from_str("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395").unwrap(), Bytes::from_str("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395").unwrap(),
false,
) )
.unwrap(); .unwrap();
let solution = Solution { let solution = Solution {
@@ -1550,6 +1566,7 @@ mod tests {
swap_encoder_registry, swap_encoder_registry,
None, None,
Bytes::from_str("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395").unwrap(), Bytes::from_str("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395").unwrap(),
false,
) )
.unwrap(); .unwrap();
let solution = Solution { let solution = Solution {
@@ -1649,6 +1666,7 @@ mod tests {
swap_encoder_registry, swap_encoder_registry,
Some(private_key), Some(private_key),
Bytes::from("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395"), Bytes::from("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395"),
false,
) )
.unwrap(); .unwrap();
let solution = Solution { let solution = Solution {
@@ -1758,6 +1776,7 @@ mod tests {
swap_encoder_registry, swap_encoder_registry,
Some(private_key.clone()), Some(private_key.clone()),
Bytes::from("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395"), Bytes::from("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395"),
false,
) )
.unwrap(); .unwrap();
@@ -1920,6 +1939,7 @@ mod tests {
swap_encoder_registry, swap_encoder_registry,
Some(private_key.clone()), Some(private_key.clone()),
Bytes::from("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395"), Bytes::from("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395"),
false,
) )
.unwrap(); .unwrap();
@@ -2045,6 +2065,7 @@ mod tests {
swap_encoder_registry, swap_encoder_registry,
None, None,
Bytes::from_str("0xA4AD4f68d0b91CFD19687c881e50f3A00242828c").unwrap(), Bytes::from_str("0xA4AD4f68d0b91CFD19687c881e50f3A00242828c").unwrap(),
false,
) )
.unwrap(); .unwrap();
@@ -2110,6 +2131,7 @@ mod tests {
swap_encoder_registry, swap_encoder_registry,
Some(private_key), Some(private_key),
Bytes::from("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395"), Bytes::from("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395"),
false,
) )
.unwrap(); .unwrap();
@@ -2178,6 +2200,7 @@ mod tests {
swap_encoder_registry, swap_encoder_registry,
Some(private_key), Some(private_key),
Bytes::from("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395"), Bytes::from("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395"),
false,
) )
.unwrap(); .unwrap();
@@ -2265,6 +2288,7 @@ mod tests {
swap_encoder_registry, swap_encoder_registry,
Some(private_key), Some(private_key),
Bytes::from("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395"), Bytes::from("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395"),
false,
) )
.unwrap(); .unwrap();
let solution = Solution { let solution = Solution {
@@ -2367,6 +2391,7 @@ mod tests {
swap_encoder_registry, swap_encoder_registry,
None, None,
Bytes::from_str("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395").unwrap(), Bytes::from_str("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395").unwrap(),
false,
) )
.unwrap(); .unwrap();
@@ -2429,6 +2454,7 @@ mod tests {
swap_encoder_registry, swap_encoder_registry,
None, None,
Bytes::from_str("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395").unwrap(), Bytes::from_str("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395").unwrap(),
false,
) )
.unwrap(); .unwrap();

View File

@@ -11,11 +11,17 @@ pub struct TransferOptimization {
native_token: Bytes, native_token: Bytes,
wrapped_token: Bytes, wrapped_token: Bytes,
permit2: bool, permit2: bool,
token_in_already_in_router: bool,
} }
impl TransferOptimization { impl TransferOptimization {
pub fn new(native_token: Bytes, wrapped_token: Bytes, permit2: bool) -> Self { pub fn new(
TransferOptimization { native_token, wrapped_token, permit2 } native_token: Bytes,
wrapped_token: Bytes,
permit2: bool,
token_in_already_in_router: bool,
) -> Self {
TransferOptimization { native_token, wrapped_token, permit2, token_in_already_in_router }
} }
/// Returns the transfer method that should be used for the given swap and solution. /// Returns the transfer method that should be used for the given swap and solution.
pub fn get_transfer_type( pub fn get_transfer_type(
@@ -38,20 +44,29 @@ impl TransferOptimization {
TransferType::TransferToProtocol TransferType::TransferToProtocol
} else if is_first_swap { } else if is_first_swap {
if in_transfer_required { if in_transfer_required {
if self.permit2 { if self.token_in_already_in_router {
// Transfer from router to pool.
TransferType::TransferToProtocol
} else if self.permit2 {
// Transfer from swapper to pool using permit2. // Transfer from swapper to pool using permit2.
TransferType::TransferPermit2ToProtocol TransferType::TransferPermit2ToProtocol
} else { } else {
// Transfer from swapper to pool. // Transfer from swapper to pool.
TransferType::TransferFromToProtocol TransferType::TransferFromToProtocol
} }
} else if self.permit2 { // in transfer is not necessary for these protocols. Only make a transfer if the
// tokens are not already in the router
} else if !self.token_in_already_in_router {
if self.permit2 {
// Transfer from swapper to router using permit2. // Transfer from swapper to router using permit2.
TransferType::TransferPermit2ToRouter TransferType::TransferPermit2ToRouter
} else { } else {
// Transfer from swapper to router. // Transfer from swapper to router.
TransferType::TransferFromToRouter TransferType::TransferFromToRouter
} }
} else {
TransferType::None
}
// all other swaps // all other swaps
} else if !in_transfer_required || in_between_swap_optimization { } else if !in_transfer_required || in_between_swap_optimization {
// funds should already be in the router or in the next pool // funds should already be in the router or in the next pool
@@ -65,7 +80,6 @@ impl TransferOptimization {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use alloy_primitives::hex; use alloy_primitives::hex;
use tycho_common::Bytes;
use super::*; use super::*;
@@ -95,7 +109,7 @@ mod tests {
split: 0f64, split: 0f64,
swaps: vec![], swaps: vec![],
}; };
let optimization = TransferOptimization::new(eth(), weth(), true); let optimization = TransferOptimization::new(eth(), weth(), true, false);
let transfer_method = optimization.get_transfer_type(swap.clone(), weth(), false, false); let transfer_method = optimization.get_transfer_type(swap.clone(), weth(), false, false);
assert_eq!(transfer_method, TransferType::TransferPermit2ToProtocol); assert_eq!(transfer_method, TransferType::TransferPermit2ToProtocol);
} }
@@ -110,7 +124,7 @@ mod tests {
split: 0f64, split: 0f64,
swaps: vec![], swaps: vec![],
}; };
let optimization = TransferOptimization::new(eth(), weth(), false); let optimization = TransferOptimization::new(eth(), weth(), false, false);
let transfer_method = optimization.get_transfer_type(swap.clone(), weth(), false, false); let transfer_method = optimization.get_transfer_type(swap.clone(), weth(), false, false);
assert_eq!(transfer_method, TransferType::TransferFromToProtocol); assert_eq!(transfer_method, TransferType::TransferFromToProtocol);
} }
@@ -126,7 +140,7 @@ mod tests {
split: 0f64, split: 0f64,
swaps: vec![], swaps: vec![],
}; };
let optimization = TransferOptimization::new(eth(), weth(), false); let optimization = TransferOptimization::new(eth(), weth(), false, false);
let transfer_method = optimization.get_transfer_type(swap.clone(), eth(), false, false); let transfer_method = optimization.get_transfer_type(swap.clone(), eth(), false, false);
assert_eq!(transfer_method, TransferType::None); assert_eq!(transfer_method, TransferType::None);
} }
@@ -142,7 +156,7 @@ mod tests {
split: 0f64, split: 0f64,
swaps: vec![], swaps: vec![],
}; };
let optimization = TransferOptimization::new(eth(), weth(), false); let optimization = TransferOptimization::new(eth(), weth(), false, false);
let transfer_method = optimization.get_transfer_type(swap.clone(), eth(), true, false); let transfer_method = optimization.get_transfer_type(swap.clone(), eth(), true, false);
assert_eq!(transfer_method, TransferType::TransferToProtocol); assert_eq!(transfer_method, TransferType::TransferToProtocol);
} }
@@ -158,7 +172,7 @@ mod tests {
split: 0f64, split: 0f64,
swaps: vec![], swaps: vec![],
}; };
let optimization = TransferOptimization::new(eth(), weth(), false); let optimization = TransferOptimization::new(eth(), weth(), false, false);
let transfer_method = optimization.get_transfer_type(swap.clone(), weth(), false, false); let transfer_method = optimization.get_transfer_type(swap.clone(), weth(), false, false);
assert_eq!(transfer_method, TransferType::TransferToProtocol); assert_eq!(transfer_method, TransferType::TransferToProtocol);
} }
@@ -174,7 +188,7 @@ mod tests {
split: 0f64, split: 0f64,
swaps: vec![], swaps: vec![],
}; };
let optimization = TransferOptimization::new(eth(), weth(), false); let optimization = TransferOptimization::new(eth(), weth(), false, false);
let transfer_method = optimization.get_transfer_type(swap.clone(), weth(), false, false); let transfer_method = optimization.get_transfer_type(swap.clone(), weth(), false, false);
assert_eq!(transfer_method, TransferType::None); assert_eq!(transfer_method, TransferType::None);
} }
@@ -190,8 +204,40 @@ mod tests {
split: 0f64, split: 0f64,
swaps: vec![], swaps: vec![],
}; };
let optimization = TransferOptimization::new(eth(), weth(), false); let optimization = TransferOptimization::new(eth(), weth(), false, false);
let transfer_method = optimization.get_transfer_type(swap.clone(), weth(), false, true); let transfer_method = optimization.get_transfer_type(swap.clone(), weth(), false, true);
assert_eq!(transfer_method, TransferType::None); assert_eq!(transfer_method, TransferType::None);
} }
#[test]
fn test_first_swap_tokens_already_in_router_optimization() {
// It is the first swap, tokens are already in the router and the protocol requires the
// transfer in
let swap = SwapGroup {
protocol_system: "uniswap_v2".to_string(),
token_in: usdc(),
token_out: dai(),
split: 0f64,
swaps: vec![],
};
let optimization = TransferOptimization::new(eth(), weth(), false, true);
let transfer_method = optimization.get_transfer_type(swap.clone(), usdc(), false, false);
assert_eq!(transfer_method, TransferType::TransferToProtocol);
}
#[test]
fn test_first_swap_tokens_already_in_router_no_transfer_needed_optimization() {
// It is the first swap, tokens are already in the router and the protocol does not require
// the transfer in
let swap = SwapGroup {
protocol_system: "vm:curve".to_string(),
token_in: usdc(),
token_out: dai(),
split: 0f64,
swaps: vec![],
};
let optimization = TransferOptimization::new(eth(), weth(), false, true);
let transfer_method = optimization.get_transfer_type(swap.clone(), usdc(), false, false);
assert_eq!(transfer_method, TransferType::None);
}
} }

View File

@@ -39,6 +39,7 @@ impl TychoRouterEncoder {
swap_encoder_registry: SwapEncoderRegistry, swap_encoder_registry: SwapEncoderRegistry,
swapper_pk: Option<String>, swapper_pk: Option<String>,
router_address: Bytes, router_address: Bytes,
token_in_already_in_router: bool,
) -> Result<Self, EncodingError> { ) -> Result<Self, EncodingError> {
let native_address = chain.native_token()?; let native_address = chain.native_token()?;
let wrapped_address = chain.wrapped_token()?; let wrapped_address = chain.wrapped_token()?;
@@ -48,18 +49,21 @@ impl TychoRouterEncoder {
swap_encoder_registry.clone(), swap_encoder_registry.clone(),
swapper_pk.clone(), swapper_pk.clone(),
router_address.clone(), router_address.clone(),
token_in_already_in_router,
)?, )?,
sequential_swap_strategy: SequentialSwapStrategyEncoder::new( sequential_swap_strategy: SequentialSwapStrategyEncoder::new(
chain.clone(), chain.clone(),
swap_encoder_registry.clone(), swap_encoder_registry.clone(),
swapper_pk.clone(), swapper_pk.clone(),
router_address.clone(), router_address.clone(),
token_in_already_in_router,
)?, )?,
split_swap_strategy: SplitSwapStrategyEncoder::new( split_swap_strategy: SplitSwapStrategyEncoder::new(
chain, chain,
swap_encoder_registry, swap_encoder_registry,
None, None,
router_address.clone(), router_address.clone(),
token_in_already_in_router,
)?, )?,
native_address, native_address,
wrapped_address, wrapped_address,
@@ -258,8 +262,8 @@ impl TychoExecutorEncoder {
receiver: receiver.clone(), receiver: receiver.clone(),
exact_out: solution.exact_out, exact_out: solution.exact_out,
router_address: None, router_address: None,
group_token_in: grouped_swap.input_token.clone(), group_token_in: grouped_swap.token_in.clone(),
group_token_out: grouped_swap.output_token.clone(), group_token_out: grouped_swap.token_out.clone(),
transfer_type: TransferType::TransferToProtocol, transfer_type: TransferType::TransferToProtocol,
}; };
let protocol_data = swap_encoder.encode_swap(swap.clone(), encoding_context.clone())?; let protocol_data = swap_encoder.encode_swap(swap.clone(), encoding_context.clone())?;
@@ -354,6 +358,7 @@ mod tests {
get_swap_encoder_registry(), get_swap_encoder_registry(),
None, None,
Bytes::from_str("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395").unwrap(), Bytes::from_str("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395").unwrap(),
false,
) )
.unwrap() .unwrap()
} }