feat: Remove router_address from Solution, set default

- The router address can be set when creating the SplitSwapStrategy, which now takes an Option<Bytes> as input during initialization (another breaking interface change)
- This change allows us to change our router address in the future with minimal effect on the users. Users should only pass the router address in the split swap initialization if they intend to use their own router for execution.
- This change also means that the router address does not need to be passed with the solution, even when using the executor strategy (which was pointless).
- I thought of having a router_address() method to set this in the encoder builder - but it seemed too messy, since we don't need the router address for execution for example. We would then potentially unnecessarily load and set the default router address when not needed. It is also not even used at the highest level EVMTychoEncoder, so it makes more sense for it to be directly associated with the swap strategy instead.
- Users will now not be able to encode for different routers without re-initializing the strategy. We assumed this use case to be very rare and not worth supporting.
This commit is contained in:
TAMARA LIPOWSKI
2025-03-26 12:42:28 +01:00
parent 3835842e88
commit d5c589d2c0
7 changed files with 103 additions and 55 deletions

View File

@@ -1,4 +1,7 @@
use std::{collections::HashSet, str::FromStr};
use std::{
collections::{HashMap, HashSet},
str::FromStr,
};
use alloy_primitives::{aliases::U24, U256, U8};
use alloy_sol_types::SolValue;
@@ -8,6 +11,7 @@ use crate::encoding::{
errors::EncodingError,
evm::{
approvals::permit2::Permit2,
constants::DEFAULT_ROUTERS_JSON,
strategy_encoder::{group_swaps::group_swaps, strategy_validators::SplitSwapValidator},
swap_encoder::swap_encoder_registry::SwapEncoderRegistry,
utils::{
@@ -68,6 +72,7 @@ pub trait EVMStrategyEncoder: StrategyEncoder {
/// * `wrapped_address`: Address of the chain's wrapped token
/// * `split_swap_validator`: SplitSwapValidator, responsible for checking validity of split swap
/// solutions
/// * `router_address`: Address of the router to be used to execute swaps
#[derive(Clone)]
pub struct SplitSwapStrategyEncoder {
swap_encoder_registry: SwapEncoderRegistry,
@@ -76,6 +81,7 @@ pub struct SplitSwapStrategyEncoder {
native_address: Bytes,
wrapped_address: Bytes,
split_swap_validator: SplitSwapValidator,
router_address: Bytes,
}
impl SplitSwapStrategyEncoder {
@@ -83,6 +89,7 @@ impl SplitSwapStrategyEncoder {
blockchain: tycho_common::models::Chain,
swap_encoder_registry: SwapEncoderRegistry,
swapper_pk: Option<String>,
router_address: Option<Bytes>,
) -> Result<Self, EncodingError> {
let chain = Chain::from(blockchain);
let (permit2, selector) = if let Some(swapper_pk) = swapper_pk {
@@ -93,6 +100,21 @@ impl SplitSwapStrategyEncoder {
"swap(uint256,address,address,uint256,bool,bool,uint256,address,bytes)".to_string(),
)
};
let tycho_router_address;
if let Some(address) = router_address {
tycho_router_address = address;
} else {
let default_routers: HashMap<String, Bytes> =
serde_json::from_str(DEFAULT_ROUTERS_JSON)?;
tycho_router_address = default_routers
.get(&chain.name)
.ok_or(EncodingError::FatalError(
"No default router address found for chain".to_string(),
))?
.to_owned();
}
Ok(Self {
permit2,
selector,
@@ -100,6 +122,7 @@ impl SplitSwapStrategyEncoder {
native_address: chain.native_token()?,
wrapped_address: chain.wrapped_token()?,
split_swap_validator: SplitSwapValidator,
router_address: tycho_router_address,
})
}
}
@@ -182,9 +205,9 @@ impl StrategyEncoder for SplitSwapStrategyEncoder {
let mut grouped_protocol_data: Vec<u8> = vec![];
for swap in grouped_swap.swaps.iter() {
let encoding_context = EncodingContext {
receiver: solution.router_address.clone(),
receiver: self.router_address.clone(),
exact_out: solution.exact_out,
router_address: solution.router_address.clone(),
router_address: self.router_address.clone(),
group_token_in: grouped_swap.input_token.clone(),
group_token_out: grouped_swap.output_token.clone(),
};
@@ -213,7 +236,7 @@ impl StrategyEncoder for SplitSwapStrategyEncoder {
};
let method_calldata = if let Some(permit2) = self.permit2.clone() {
let (permit, signature) = permit2.get_permit(
&solution.router_address,
&self.router_address,
&solution.sender,
&solution.given_token,
&solution.given_amount,
@@ -248,7 +271,7 @@ impl StrategyEncoder for SplitSwapStrategyEncoder {
};
let contract_interaction = encode_input(&self.selector, method_calldata);
Ok((contract_interaction, solution.router_address))
Ok((contract_interaction, self.router_address.clone()))
}
fn get_swap_encoder(&self, protocol_system: &str) -> Option<&Box<dyn SwapEncoder>> {
@@ -293,7 +316,6 @@ impl StrategyEncoder for ExecutorStrategyEncoder {
.ok_or_else(|| EncodingError::FatalError("Swap grouping failed".to_string()))?;
let receiver = solution.receiver;
let router_address = solution.router_address;
let swap_encoder = self
.get_swap_encoder(&grouped_swap.protocol_system)
@@ -309,7 +331,7 @@ impl StrategyEncoder for ExecutorStrategyEncoder {
let encoding_context = EncodingContext {
receiver: receiver.clone(),
exact_out: solution.exact_out,
router_address: router_address.clone(),
router_address: Bytes::from("0x0000000000000000000000000000000000000000"),
group_token_in: grouped_swap.input_token.clone(),
group_token_out: grouped_swap.output_token.clone(),
};
@@ -396,7 +418,6 @@ mod tests {
// The receiver was generated with `makeAddr("bob") using forge`
receiver: Bytes::from_str("0x1d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e").unwrap(),
swaps: vec![swap],
router_address: Bytes::from_str("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395").unwrap(),
slippage: None,
native_action: None,
};
@@ -452,7 +473,6 @@ mod tests {
sender: Bytes::from_str("0x0000000000000000000000000000000000000000").unwrap(),
receiver: Bytes::from_str("0x1d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e").unwrap(),
swaps: vec![swap.clone(), swap],
router_address: Bytes::from_str("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395").unwrap(),
slippage: None,
native_action: None,
};
@@ -521,7 +541,6 @@ mod tests {
slippage: None,
sender: Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(),
receiver: Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(),
router_address: Bytes::from_str("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395").unwrap(),
swaps: vec![swap_usdc_eth, swap_eth_pepe],
..Default::default()
};
@@ -606,9 +625,13 @@ mod tests {
split: 0f64,
};
let swap_encoder_registry = get_swap_encoder_registry();
let encoder =
SplitSwapStrategyEncoder::new(eth_chain(), swap_encoder_registry, Some(private_key))
.unwrap();
let encoder = SplitSwapStrategyEncoder::new(
eth_chain(),
swap_encoder_registry,
Some(private_key),
Some(Bytes::from("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395")),
)
.unwrap();
let solution = Solution {
exact_out: false,
given_token: weth,
@@ -619,7 +642,6 @@ mod tests {
checked_amount,
sender: Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(),
receiver: Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(),
router_address: Bytes::from_str("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395").unwrap(),
swaps: vec![swap],
..Default::default()
};
@@ -707,9 +729,13 @@ mod tests {
split: 0f64,
};
let swap_encoder_registry = get_swap_encoder_registry();
let encoder =
SplitSwapStrategyEncoder::new(eth_chain(), swap_encoder_registry, Some(private_key))
.unwrap();
let encoder = SplitSwapStrategyEncoder::new(
eth_chain(),
swap_encoder_registry,
Some(private_key),
Some(Bytes::from("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395")),
)
.unwrap();
let solution = Solution {
exact_out: false,
given_token: eth(),
@@ -719,7 +745,6 @@ mod tests {
checked_amount: Some(BigUint::from_str("2659881924818443699787").unwrap()),
sender: Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(),
receiver: Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(),
router_address: Bytes::from_str("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395").unwrap(),
swaps: vec![swap],
native_action: Some(NativeAction::Wrap),
..Default::default()
@@ -756,9 +781,13 @@ mod tests {
split: 0f64,
};
let swap_encoder_registry = get_swap_encoder_registry();
let encoder =
SplitSwapStrategyEncoder::new(eth_chain(), swap_encoder_registry, Some(private_key))
.unwrap();
let encoder = SplitSwapStrategyEncoder::new(
eth_chain(),
swap_encoder_registry,
Some(private_key),
Some(Bytes::from("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395")),
)
.unwrap();
let solution = Solution {
exact_out: false,
given_token: dai,
@@ -768,7 +797,6 @@ mod tests {
checked_amount: Some(BigUint::from_str("1_000000000000000000").unwrap()),
sender: Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(),
receiver: Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(),
router_address: Bytes::from_str("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395").unwrap(),
swaps: vec![swap],
native_action: Some(NativeAction::Unwrap),
..Default::default()
@@ -846,9 +874,13 @@ mod tests {
split: 0f64,
};
let swap_encoder_registry = get_swap_encoder_registry();
let encoder =
SplitSwapStrategyEncoder::new(eth_chain(), swap_encoder_registry, Some(private_key))
.unwrap();
let encoder = SplitSwapStrategyEncoder::new(
eth_chain(),
swap_encoder_registry,
Some(private_key),
Some(Bytes::from("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395")),
)
.unwrap();
let solution = Solution {
exact_out: false,
given_token: weth,
@@ -858,7 +890,6 @@ mod tests {
checked_amount: Some(BigUint::from_str("26173932").unwrap()),
sender: Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(),
receiver: Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(),
router_address: Bytes::from_str("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395").unwrap(),
swaps: vec![swap_weth_dai, swap_weth_wbtc, swap_dai_usdc, swap_wbtc_usdc],
..Default::default()
};
@@ -927,9 +958,13 @@ mod tests {
split: 0f64,
};
let swap_encoder_registry = get_swap_encoder_registry();
let encoder =
SplitSwapStrategyEncoder::new(eth_chain(), swap_encoder_registry, Some(private_key))
.unwrap();
let encoder = SplitSwapStrategyEncoder::new(
eth_chain(),
swap_encoder_registry,
Some(private_key),
Some(Bytes::from("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395")),
)
.unwrap();
let solution = Solution {
exact_out: false,
given_token: usdc,
@@ -940,7 +975,6 @@ mod tests {
slippage: None,
sender: Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(),
receiver: Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(),
router_address: Bytes::from_str("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395").unwrap(),
swaps: vec![swap_usdc_eth, swap_eth_pepe],
..Default::default()
};
@@ -1094,8 +1128,13 @@ mod tests {
split: 0f64,
};
let swap_encoder_registry = get_swap_encoder_registry();
let encoder =
SplitSwapStrategyEncoder::new(eth_chain(), swap_encoder_registry, None).unwrap();
let encoder = SplitSwapStrategyEncoder::new(
eth_chain(),
swap_encoder_registry,
None,
Some(Bytes::from("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395")),
)
.unwrap();
let solution = Solution {
exact_out: false,
given_token: weth,
@@ -1106,7 +1145,6 @@ mod tests {
checked_amount,
sender: Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(),
receiver: Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(),
router_address: Bytes::from_str("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395").unwrap(),
swaps: vec![swap],
..Default::default()
};
@@ -1183,9 +1221,13 @@ mod tests {
split: 0f64,
};
let swap_encoder_registry = get_swap_encoder_registry();
let encoder =
SplitSwapStrategyEncoder::new(eth_chain(), swap_encoder_registry, Some(private_key))
.unwrap();
let encoder = SplitSwapStrategyEncoder::new(
eth_chain(),
swap_encoder_registry,
Some(private_key),
Some(Bytes::from("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395")),
)
.unwrap();
let solution = Solution {
exact_out: false,
@@ -1197,7 +1239,6 @@ mod tests {
slippage: None,
sender: Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(),
receiver: Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(),
router_address: Bytes::from_str("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395").unwrap(),
swaps: vec![swap_eth_pepe],
..Default::default()
};
@@ -1247,9 +1288,13 @@ mod tests {
};
let swap_encoder_registry = get_swap_encoder_registry();
let encoder =
SplitSwapStrategyEncoder::new(eth_chain(), swap_encoder_registry, Some(private_key))
.unwrap();
let encoder = SplitSwapStrategyEncoder::new(
eth_chain(),
swap_encoder_registry,
Some(private_key),
Some(Bytes::from("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395")),
)
.unwrap();
let solution = Solution {
exact_out: false,
@@ -1261,7 +1306,6 @@ mod tests {
slippage: None,
sender: Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(),
receiver: Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(),
router_address: Bytes::from_str("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395").unwrap(),
swaps: vec![swap_usdc_eth],
..Default::default()
};
@@ -1331,9 +1375,13 @@ mod tests {
};
let swap_encoder_registry = get_swap_encoder_registry();
let encoder =
SplitSwapStrategyEncoder::new(eth_chain(), swap_encoder_registry, Some(private_key))
.unwrap();
let encoder = SplitSwapStrategyEncoder::new(
eth_chain(),
swap_encoder_registry,
Some(private_key),
Some(Bytes::from("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395")),
)
.unwrap();
let solution = Solution {
exact_out: false,
@@ -1345,7 +1393,6 @@ mod tests {
* test */
slippage: None,
swaps: vec![swap_usdc_weth, swap_weth_usdc],
router_address: Bytes::from_str("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395").unwrap(),
sender: Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(),
receiver: Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(),
..Default::default()
@@ -1483,6 +1530,7 @@ mod tests {
eth_chain(),
swap_encoder_registry,
Some(private_key.clone()),
Some(Bytes::from("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395")),
)
.unwrap();
@@ -1494,7 +1542,6 @@ mod tests {
expected_amount: None,
checked_amount: Some(BigUint::from_str("99574171").unwrap()), /* Expected output from
* test */
router_address: Bytes::from_str("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395").unwrap(),
sender: Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(),
receiver: Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(),
slippage: None,
@@ -1640,6 +1687,7 @@ mod tests {
eth_chain(),
swap_encoder_registry,
Some(private_key.clone()),
Some(Bytes::from("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395")),
)
.unwrap();
@@ -1651,7 +1699,6 @@ mod tests {
expected_amount: None,
checked_amount: Some(BigUint::from_str("99525908").unwrap()), /* Expected output from
* test */
router_address: Bytes::from_str("0x3Ede3eCa2a72B3aeCC820E955B36f38437D01395").unwrap(),
sender: Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(),
receiver: Bytes::from_str("0xcd09f75E2BF2A4d11F3AB23f1389FcC1621c0cc2").unwrap(),
slippage: None,