feat: Add protocol state to Swap object
- This consists of lots of necessary battles with lifetimes.
This commit is contained in:
@@ -11,20 +11,30 @@ use crate::encoding::{evm::constants::GROUPABLE_PROTOCOLS, models::Swap};
|
||||
/// * `protocol_system`: String, the protocol system of the swaps
|
||||
/// * `swaps`: Vec<Swap>, the sequence of swaps to be executed as a group
|
||||
/// * `split`: f64, the split percentage of the first swap in the group
|
||||
#[derive(Clone, PartialEq, Debug)]
|
||||
pub struct SwapGroup {
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct SwapGroup<'a> {
|
||||
pub token_in: Bytes,
|
||||
pub token_out: Bytes,
|
||||
pub protocol_system: String,
|
||||
pub swaps: Vec<Swap>,
|
||||
pub swaps: Vec<Swap<'a>>,
|
||||
pub split: f64,
|
||||
}
|
||||
|
||||
impl<'a> PartialEq for SwapGroup<'a> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.token_in == other.token_in &&
|
||||
self.token_out == other.token_out &&
|
||||
self.protocol_system == other.protocol_system &&
|
||||
self.swaps == other.swaps &&
|
||||
self.split == other.split
|
||||
}
|
||||
}
|
||||
|
||||
/// Group consecutive swaps which can be encoded into one swap execution for gas optimization.
|
||||
///
|
||||
/// An example where this applies is the case of USV4, which uses a PoolManager contract
|
||||
/// to save token transfers on consecutive swaps.
|
||||
pub fn group_swaps(swaps: &Vec<Swap>) -> Vec<SwapGroup> {
|
||||
pub fn group_swaps<'a>(swaps: &'a Vec<Swap<'a>>) -> Vec<SwapGroup<'a>> {
|
||||
let mut grouped_swaps: Vec<SwapGroup> = Vec::new();
|
||||
let mut current_group: Option<SwapGroup> = None;
|
||||
let mut last_swap_protocol = "".to_string();
|
||||
@@ -106,6 +116,7 @@ mod tests {
|
||||
// 0 to signify "the remainder of the WETH value". It should still be very close to 50%
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
};
|
||||
let swap_wbtc_usdc = Swap {
|
||||
component: ProtocolComponent {
|
||||
@@ -116,6 +127,7 @@ mod tests {
|
||||
token_out: usdc.clone(),
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
};
|
||||
let swap_usdc_dai = Swap {
|
||||
component: ProtocolComponent {
|
||||
@@ -126,12 +138,10 @@ mod tests {
|
||||
token_out: dai.clone(),
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
};
|
||||
let grouped_swaps = group_swaps(&vec![
|
||||
swap_weth_wbtc.clone(),
|
||||
swap_wbtc_usdc.clone(),
|
||||
swap_usdc_dai.clone(),
|
||||
]);
|
||||
let swaps = vec![swap_weth_wbtc.clone(), swap_wbtc_usdc.clone(), swap_usdc_dai.clone()];
|
||||
let grouped_swaps = group_swaps(&swaps);
|
||||
|
||||
assert_eq!(
|
||||
grouped_swaps,
|
||||
@@ -178,6 +188,7 @@ mod tests {
|
||||
token_out: weth.clone(),
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
};
|
||||
let swap_weth_usdc = Swap {
|
||||
component: ProtocolComponent {
|
||||
@@ -188,6 +199,7 @@ mod tests {
|
||||
token_out: usdc.clone(),
|
||||
split: 0.5f64,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
};
|
||||
let swap_weth_dai = Swap {
|
||||
component: ProtocolComponent {
|
||||
@@ -200,6 +212,7 @@ mod tests {
|
||||
// 0 to signify "the remainder of the WETH value". It should still be very close to 50%
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
};
|
||||
let swap_dai_usdc = Swap {
|
||||
component: ProtocolComponent {
|
||||
@@ -210,13 +223,15 @@ mod tests {
|
||||
token_out: usdc.clone(),
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
};
|
||||
let grouped_swaps = group_swaps(&vec![
|
||||
let swaps = vec![
|
||||
swap_wbtc_weth.clone(),
|
||||
swap_weth_usdc.clone(),
|
||||
swap_weth_dai.clone(),
|
||||
swap_dai_usdc.clone(),
|
||||
]);
|
||||
];
|
||||
let grouped_swaps = group_swaps(&swaps);
|
||||
|
||||
assert_eq!(
|
||||
grouped_swaps,
|
||||
@@ -269,6 +284,7 @@ mod tests {
|
||||
token_out: wbtc.clone(),
|
||||
split: 0.5f64,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
};
|
||||
let swap_wbtc_usdc = Swap {
|
||||
component: ProtocolComponent {
|
||||
@@ -279,6 +295,7 @@ mod tests {
|
||||
token_out: usdc.clone(),
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
};
|
||||
let swap_weth_dai = Swap {
|
||||
component: ProtocolComponent {
|
||||
@@ -291,6 +308,7 @@ mod tests {
|
||||
// 0 to signify "the remainder of the WETH value". It should still be very close to 50%
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
};
|
||||
let swap_dai_usdc = Swap {
|
||||
component: ProtocolComponent {
|
||||
@@ -301,14 +319,16 @@ mod tests {
|
||||
token_out: usdc.clone(),
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
};
|
||||
|
||||
let grouped_swaps = group_swaps(&vec![
|
||||
let swaps = vec![
|
||||
swap_weth_wbtc.clone(),
|
||||
swap_wbtc_usdc.clone(),
|
||||
swap_weth_dai.clone(),
|
||||
swap_dai_usdc.clone(),
|
||||
]);
|
||||
];
|
||||
let grouped_swaps = group_swaps(&swaps);
|
||||
|
||||
assert_eq!(
|
||||
grouped_swaps,
|
||||
|
||||
@@ -558,6 +558,7 @@ mod tests {
|
||||
token_out: dai.clone(),
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
};
|
||||
let swap_encoder_registry = get_swap_encoder_registry();
|
||||
let encoder = SingleSwapStrategyEncoder::new(
|
||||
@@ -619,6 +620,7 @@ mod tests {
|
||||
token_out: dai.clone(),
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
};
|
||||
let swap_encoder_registry = get_swap_encoder_registry();
|
||||
let encoder = SingleSwapStrategyEncoder::new(
|
||||
@@ -690,6 +692,7 @@ mod tests {
|
||||
token_out: wbtc.clone(),
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
};
|
||||
let swap_wbtc_usdc = Swap {
|
||||
component: ProtocolComponent {
|
||||
@@ -701,6 +704,7 @@ mod tests {
|
||||
token_out: usdc.clone(),
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
};
|
||||
let swap_encoder_registry = get_swap_encoder_registry();
|
||||
let encoder = SequentialSwapStrategyEncoder::new(
|
||||
@@ -793,6 +797,7 @@ mod tests {
|
||||
token_out: weth.clone(),
|
||||
split: 0.6f64, // 60% of input
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
};
|
||||
|
||||
// USDC -> WETH (Pool 2) - 40% of input (remaining)
|
||||
@@ -815,6 +820,7 @@ mod tests {
|
||||
token_out: weth.clone(),
|
||||
split: 0f64,
|
||||
user_data: None, // Remaining 40%
|
||||
protocol_state: None,
|
||||
};
|
||||
|
||||
// WETH -> USDC (Pool 2)
|
||||
@@ -837,6 +843,7 @@ mod tests {
|
||||
token_out: usdc.clone(),
|
||||
split: 0.0f64,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
};
|
||||
|
||||
let swap_encoder_registry = get_swap_encoder_registry();
|
||||
@@ -945,6 +952,7 @@ mod tests {
|
||||
token_out: weth.clone(),
|
||||
split: 0.0f64,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
};
|
||||
|
||||
let swap_weth_usdc_v3_pool1 = Swap {
|
||||
@@ -966,6 +974,7 @@ mod tests {
|
||||
token_out: usdc.clone(),
|
||||
split: 0.6f64,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
};
|
||||
|
||||
let swap_weth_usdc_v3_pool2 = Swap {
|
||||
@@ -987,6 +996,7 @@ mod tests {
|
||||
token_out: usdc.clone(),
|
||||
split: 0.0f64,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
};
|
||||
|
||||
let swap_encoder_registry = get_swap_encoder_registry();
|
||||
|
||||
@@ -215,6 +215,7 @@ mod tests {
|
||||
token_out: dai.clone(),
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
}];
|
||||
let result = validator.validate_swap_path(&swaps, &weth, &dai, &None, ð, &weth);
|
||||
assert_eq!(result, Ok(()));
|
||||
@@ -238,6 +239,7 @@ mod tests {
|
||||
token_out: dai.clone(),
|
||||
split: 0.5f64,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
},
|
||||
Swap {
|
||||
component: ProtocolComponent {
|
||||
@@ -249,6 +251,7 @@ mod tests {
|
||||
token_out: usdc.clone(),
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
},
|
||||
];
|
||||
let result = validator.validate_swap_path(&swaps, &weth, &usdc, &None, ð, &weth);
|
||||
@@ -275,6 +278,7 @@ mod tests {
|
||||
token_out: dai.clone(),
|
||||
split: 0.5,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
},
|
||||
// This swap is disconnected from the WETH->DAI path
|
||||
Swap {
|
||||
@@ -287,6 +291,7 @@ mod tests {
|
||||
token_out: usdc.clone(),
|
||||
split: 0.0,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
},
|
||||
];
|
||||
let result =
|
||||
@@ -315,6 +320,7 @@ mod tests {
|
||||
token_out: weth.clone(),
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
},
|
||||
Swap {
|
||||
component: ProtocolComponent {
|
||||
@@ -326,6 +332,7 @@ mod tests {
|
||||
token_out: usdc.clone(),
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -352,6 +359,7 @@ mod tests {
|
||||
token_out: dai.clone(),
|
||||
split: 1.0,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
}];
|
||||
let result =
|
||||
validator.validate_swap_path(&unreachable_swaps, &weth, &usdc, &None, ð, &weth);
|
||||
@@ -391,6 +399,7 @@ mod tests {
|
||||
token_out: dai.clone(),
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
}];
|
||||
let result = validator.validate_split_percentages(&swaps);
|
||||
assert_eq!(result, Ok(()));
|
||||
@@ -414,6 +423,7 @@ mod tests {
|
||||
token_out: dai.clone(),
|
||||
split: 0.5,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
},
|
||||
Swap {
|
||||
component: ProtocolComponent {
|
||||
@@ -425,6 +435,7 @@ mod tests {
|
||||
token_out: dai.clone(),
|
||||
split: 0.3,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
},
|
||||
Swap {
|
||||
component: ProtocolComponent {
|
||||
@@ -436,6 +447,7 @@ mod tests {
|
||||
token_out: dai.clone(),
|
||||
split: 0.0, // Remainder (20%)
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
},
|
||||
];
|
||||
assert!(validator
|
||||
@@ -460,6 +472,7 @@ mod tests {
|
||||
token_out: dai.clone(),
|
||||
split: 0.7,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
},
|
||||
Swap {
|
||||
component: ProtocolComponent {
|
||||
@@ -471,6 +484,7 @@ mod tests {
|
||||
token_out: dai.clone(),
|
||||
split: 0.3,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
},
|
||||
];
|
||||
assert!(matches!(
|
||||
@@ -496,6 +510,7 @@ mod tests {
|
||||
token_out: dai.clone(),
|
||||
split: 0.0,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
},
|
||||
Swap {
|
||||
component: ProtocolComponent {
|
||||
@@ -507,6 +522,7 @@ mod tests {
|
||||
token_out: dai.clone(),
|
||||
split: 0.5,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
},
|
||||
];
|
||||
assert!(matches!(
|
||||
@@ -532,6 +548,7 @@ mod tests {
|
||||
token_out: dai.clone(),
|
||||
split: 0.6,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
},
|
||||
Swap {
|
||||
component: ProtocolComponent {
|
||||
@@ -543,6 +560,7 @@ mod tests {
|
||||
token_out: dai.clone(),
|
||||
split: 0.5,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
},
|
||||
Swap {
|
||||
component: ProtocolComponent {
|
||||
@@ -554,6 +572,7 @@ mod tests {
|
||||
token_out: dai.clone(),
|
||||
split: 0.0,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
},
|
||||
];
|
||||
assert!(matches!(
|
||||
@@ -579,6 +598,7 @@ mod tests {
|
||||
token_out: usdc.clone(),
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
}];
|
||||
|
||||
let result = validator.validate_swap_path(
|
||||
@@ -609,6 +629,7 @@ mod tests {
|
||||
token_out: weth.clone(),
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
}];
|
||||
|
||||
let result = validator.validate_swap_path(
|
||||
|
||||
@@ -179,6 +179,7 @@ mod tests {
|
||||
token_out: dai(),
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
}];
|
||||
let swap = SwapGroup {
|
||||
protocol_system: protocol,
|
||||
@@ -241,6 +242,7 @@ mod tests {
|
||||
token_out: dai(),
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
}],
|
||||
})
|
||||
};
|
||||
|
||||
@@ -670,6 +670,7 @@ mod tests {
|
||||
token_out: token_out.clone(),
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
};
|
||||
let encoding_context = EncodingContext {
|
||||
receiver: Bytes::from("0x1D96F2f6BeF1202E4Ce1Ff6Dad0c2CB002861d3e"), // BOB
|
||||
@@ -730,6 +731,7 @@ mod tests {
|
||||
token_out: token_out.clone(),
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
};
|
||||
let encoding_context = EncodingContext {
|
||||
receiver: Bytes::from("0x0000000000000000000000000000000000000001"),
|
||||
@@ -791,6 +793,7 @@ mod tests {
|
||||
token_out: token_out.clone(),
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
};
|
||||
let encoding_context = EncodingContext {
|
||||
// The receiver was generated with `makeAddr("bob") using forge`
|
||||
@@ -864,6 +867,7 @@ mod tests {
|
||||
token_out: token_out.clone(),
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
};
|
||||
let encoding_context = EncodingContext {
|
||||
// The receiver is ALICE to match the solidity tests
|
||||
@@ -937,6 +941,7 @@ mod tests {
|
||||
token_out: token_out.clone(),
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
};
|
||||
|
||||
let encoding_context = EncodingContext {
|
||||
@@ -1034,6 +1039,7 @@ mod tests {
|
||||
token_out: usdt_address.clone(),
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
};
|
||||
|
||||
let second_swap = Swap {
|
||||
@@ -1042,6 +1048,7 @@ mod tests {
|
||||
token_out: wbtc_address.clone(),
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
};
|
||||
|
||||
let encoder = UniswapV4SwapEncoder::new(
|
||||
@@ -1119,6 +1126,7 @@ mod tests {
|
||||
token_out: token_out.clone(),
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
};
|
||||
|
||||
let encoding_context = EncodingContext {
|
||||
@@ -1188,6 +1196,7 @@ mod tests {
|
||||
token_out: intermediary_token.clone(),
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
};
|
||||
|
||||
let second_swap = Swap {
|
||||
@@ -1204,6 +1213,7 @@ mod tests {
|
||||
token_out: group_token_out.clone(),
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
};
|
||||
|
||||
let first_encoded_swap = encoder
|
||||
@@ -1324,6 +1334,7 @@ mod tests {
|
||||
token_out: Bytes::from(token_out),
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
};
|
||||
let encoder =
|
||||
CurveSwapEncoder::new(String::default(), Chain::Ethereum, curve_config()).unwrap();
|
||||
@@ -1364,6 +1375,7 @@ mod tests {
|
||||
token_out: token_out.clone(),
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
};
|
||||
let encoding_context = EncodingContext {
|
||||
// The receiver was generated with `makeAddr("bob") using forge`
|
||||
@@ -1436,6 +1448,7 @@ mod tests {
|
||||
token_out: token_out.clone(),
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
};
|
||||
let encoding_context = EncodingContext {
|
||||
// The receiver was generated with `makeAddr("bob") using forge`
|
||||
@@ -1509,6 +1522,7 @@ mod tests {
|
||||
token_out: token_out.clone(),
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
};
|
||||
let encoding_context = EncodingContext {
|
||||
// The receiver was generated with `makeAddr("bob") using forge`
|
||||
@@ -1583,6 +1597,7 @@ mod tests {
|
||||
token_out: token_out.clone(),
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
};
|
||||
let encoding_context = EncodingContext {
|
||||
// The receiver was generated with `makeAddr("bob") using forge`
|
||||
@@ -1641,6 +1656,7 @@ mod tests {
|
||||
token_out: token_out.clone(),
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
};
|
||||
let encoding_context = EncodingContext {
|
||||
// The receiver was generated with `makeAddr("bob") using forge`
|
||||
|
||||
@@ -422,7 +422,7 @@ mod tests {
|
||||
// Fee and tick spacing information for this test is obtained by querying the
|
||||
// USV4 Position Manager contract: 0xbd216513d74c8cf14cf4747e6aaa6420ff64ee9e
|
||||
// Using the poolKeys function with the first 25 bytes of the pool id
|
||||
fn swap_usdc_eth_univ4() -> Swap {
|
||||
fn swap_usdc_eth_univ4() -> Swap<'static> {
|
||||
let pool_fee_usdc_eth = Bytes::from(BigInt::from(3000).to_signed_bytes_be());
|
||||
let tick_spacing_usdc_eth = Bytes::from(BigInt::from(60).to_signed_bytes_be());
|
||||
let mut static_attributes_usdc_eth: HashMap<String, Bytes> = HashMap::new();
|
||||
@@ -440,10 +440,11 @@ mod tests {
|
||||
token_out: eth().clone(),
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn swap_eth_pepe_univ4() -> Swap {
|
||||
fn swap_eth_pepe_univ4() -> Swap<'static> {
|
||||
let pool_fee_eth_pepe = Bytes::from(BigInt::from(25000).to_signed_bytes_be());
|
||||
let tick_spacing_eth_pepe = Bytes::from(BigInt::from(500).to_signed_bytes_be());
|
||||
let mut static_attributes_eth_pepe: HashMap<String, Bytes> = HashMap::new();
|
||||
@@ -461,6 +462,7 @@ mod tests {
|
||||
token_out: pepe().clone(),
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -509,6 +511,7 @@ mod tests {
|
||||
token_out: dai(),
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
};
|
||||
|
||||
let solution = Solution {
|
||||
@@ -574,6 +577,7 @@ mod tests {
|
||||
token_out: dai(),
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
};
|
||||
|
||||
let swap_dai_usdc = Swap {
|
||||
@@ -586,6 +590,7 @@ mod tests {
|
||||
token_out: usdc(),
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
};
|
||||
|
||||
let solution = Solution {
|
||||
@@ -666,6 +671,7 @@ mod tests {
|
||||
token_out: dai(),
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
};
|
||||
|
||||
let solution = Solution {
|
||||
@@ -695,6 +701,7 @@ mod tests {
|
||||
token_out: dai(),
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
};
|
||||
|
||||
let solution = Solution {
|
||||
@@ -729,6 +736,7 @@ mod tests {
|
||||
token_out: dai(),
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
};
|
||||
|
||||
let solution = Solution {
|
||||
@@ -783,6 +791,7 @@ mod tests {
|
||||
token_out: weth(),
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
};
|
||||
|
||||
let solution = Solution {
|
||||
@@ -811,6 +820,7 @@ mod tests {
|
||||
token_out: weth(),
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
};
|
||||
|
||||
let solution = Solution {
|
||||
@@ -846,6 +856,7 @@ mod tests {
|
||||
token_out: eth(),
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
};
|
||||
|
||||
let solution = Solution {
|
||||
@@ -886,6 +897,7 @@ mod tests {
|
||||
token_out: weth(),
|
||||
split: 0.5f64,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
},
|
||||
Swap {
|
||||
component: ProtocolComponent {
|
||||
@@ -897,6 +909,7 @@ mod tests {
|
||||
token_out: weth(),
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
},
|
||||
Swap {
|
||||
component: ProtocolComponent {
|
||||
@@ -908,6 +921,7 @@ mod tests {
|
||||
token_out: dai(),
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -941,6 +955,7 @@ mod tests {
|
||||
token_out: weth(),
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
},
|
||||
Swap {
|
||||
component: ProtocolComponent {
|
||||
@@ -952,6 +967,7 @@ mod tests {
|
||||
token_out: usdc(),
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
},
|
||||
Swap {
|
||||
component: ProtocolComponent {
|
||||
@@ -963,6 +979,7 @@ mod tests {
|
||||
token_out: dai(),
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
},
|
||||
Swap {
|
||||
component: ProtocolComponent {
|
||||
@@ -974,6 +991,7 @@ mod tests {
|
||||
token_out: wbtc(),
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -1014,6 +1032,7 @@ mod tests {
|
||||
token_out: dai(),
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
},
|
||||
Swap {
|
||||
component: ProtocolComponent {
|
||||
@@ -1025,6 +1044,7 @@ mod tests {
|
||||
token_out: weth(),
|
||||
split: 0.5f64,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
},
|
||||
Swap {
|
||||
component: ProtocolComponent {
|
||||
@@ -1036,6 +1056,7 @@ mod tests {
|
||||
token_out: weth(),
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -1069,6 +1090,7 @@ mod tests {
|
||||
token_out: dai(),
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
},
|
||||
Swap {
|
||||
component: ProtocolComponent {
|
||||
@@ -1080,6 +1102,7 @@ mod tests {
|
||||
token_out: weth(),
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -1134,6 +1157,7 @@ mod tests {
|
||||
token_out: token_out.clone(),
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
};
|
||||
|
||||
let solution = Solution {
|
||||
@@ -1194,6 +1218,7 @@ mod tests {
|
||||
token_out: token_out.clone(),
|
||||
split: 0f64,
|
||||
user_data: None,
|
||||
protocol_state: None,
|
||||
};
|
||||
|
||||
let solution = Solution {
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
use clap::ValueEnum;
|
||||
use num_bigint::BigUint;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tycho_common::{models::protocol::ProtocolComponent, Bytes};
|
||||
use tycho_common::{
|
||||
models::protocol::ProtocolComponent, simulation::protocol_sim::ProtocolSim, Bytes,
|
||||
};
|
||||
|
||||
use crate::encoding::serde_primitives::biguint_string;
|
||||
|
||||
@@ -33,7 +35,7 @@ pub enum UserTransferType {
|
||||
/// Represents a solution containing details describing an order, and instructions for filling
|
||||
/// the order.
|
||||
#[derive(Clone, Default, Debug, Deserialize, Serialize)]
|
||||
pub struct Solution {
|
||||
pub struct Solution<'a> {
|
||||
/// Address of the sender.
|
||||
pub sender: Bytes,
|
||||
/// Address of the receiver.
|
||||
@@ -53,7 +55,7 @@ pub struct Solution {
|
||||
#[serde(with = "biguint_string")]
|
||||
pub checked_amount: BigUint,
|
||||
/// List of swaps to fulfill the solution.
|
||||
pub swaps: Vec<Swap>,
|
||||
pub swaps: Vec<Swap<'a>>,
|
||||
/// If set, the corresponding native action will be executed.
|
||||
pub native_action: Option<NativeAction>,
|
||||
}
|
||||
@@ -71,8 +73,8 @@ pub enum NativeAction {
|
||||
}
|
||||
|
||||
/// Represents a swap operation to be performed on a pool.
|
||||
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
|
||||
pub struct Swap {
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
pub struct Swap<'a> {
|
||||
/// Protocol component from tycho indexer
|
||||
pub component: ProtocolComponent,
|
||||
/// Token being input into the pool.
|
||||
@@ -84,17 +86,32 @@ pub struct Swap {
|
||||
pub split: f64,
|
||||
/// Optional user data to be passed to encoding.
|
||||
pub user_data: Option<Bytes>,
|
||||
/// Optional protocol state used to perform the swap.
|
||||
#[serde(skip)]
|
||||
pub protocol_state: Option<&'a Box<dyn ProtocolSim>>,
|
||||
}
|
||||
|
||||
impl Swap {
|
||||
impl<'a> Swap<'a> {
|
||||
pub fn new<T: Into<ProtocolComponent>>(
|
||||
component: T,
|
||||
token_in: Bytes,
|
||||
token_out: Bytes,
|
||||
split: f64,
|
||||
user_data: Option<Bytes>,
|
||||
protocol_state: Option<&'a Box<dyn ProtocolSim>>,
|
||||
) -> Self {
|
||||
Self { component: component.into(), token_in, token_out, split, user_data }
|
||||
Self { component: component.into(), token_in, token_out, split, user_data, protocol_state }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> PartialEq for Swap<'a> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.component == other.component &&
|
||||
self.token_in == other.token_in &&
|
||||
self.token_out == other.token_out &&
|
||||
self.split == other.split &&
|
||||
self.user_data == other.user_data
|
||||
// Skip protocol_state comparison since trait objects don't implement PartialEq
|
||||
}
|
||||
}
|
||||
|
||||
@@ -238,8 +255,14 @@ mod tests {
|
||||
protocol_system: "uniswap_v2".to_string(),
|
||||
};
|
||||
let user_data = Some(Bytes::from("0x1234"));
|
||||
let swap =
|
||||
Swap::new(component, Bytes::from("0x12"), Bytes::from("34"), 0.5, user_data.clone());
|
||||
let swap = Swap::new(
|
||||
component,
|
||||
Bytes::from("0x12"),
|
||||
Bytes::from("34"),
|
||||
0.5,
|
||||
user_data.clone(),
|
||||
None,
|
||||
);
|
||||
assert_eq!(swap.token_in, Bytes::from("0x12"));
|
||||
assert_eq!(swap.token_out, Bytes::from("0x34"));
|
||||
assert_eq!(swap.component.protocol_system, "uniswap_v2");
|
||||
|
||||
Reference in New Issue
Block a user