feat: Use Arc instead of & for protocol_state in Swap

- dealing with lifetimes makes refactoring painful for our users.
This commit is contained in:
TAMARA LIPOWSKI
2025-08-20 15:25:16 -04:00
parent 2a68dd117b
commit a2a53195ed
5 changed files with 26 additions and 23 deletions

View File

@@ -12,15 +12,15 @@ use crate::encoding::{evm::constants::GROUPABLE_PROTOCOLS, models::Swap};
/// * `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, Debug)]
pub struct SwapGroup<'a> {
pub struct SwapGroup {
pub token_in: Bytes,
pub token_out: Bytes,
pub protocol_system: String,
pub swaps: Vec<Swap<'a>>,
pub swaps: Vec<Swap>,
pub split: f64,
}
impl<'a> PartialEq for SwapGroup<'a> {
impl PartialEq for SwapGroup {
fn eq(&self, other: &Self) -> bool {
self.token_in == other.token_in &&
self.token_out == other.token_out &&
@@ -34,7 +34,7 @@ impl<'a> PartialEq for SwapGroup<'a> {
///
/// 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<'a>(swaps: &'a Vec<Swap<'a>>) -> Vec<SwapGroup<'a>> {
pub fn group_swaps(swaps: &Vec<Swap>) -> Vec<SwapGroup> {
let mut grouped_swaps: Vec<SwapGroup> = Vec::new();
let mut current_group: Option<SwapGroup> = None;
let mut last_swap_protocol = "".to_string();

View File

@@ -739,7 +739,7 @@ impl SwapEncoder for BebopSwapEncoder {
}
let (partial_fill_offset, original_filled_taker_amount, bebop_calldata) =
if let Some(state) = swap.protocol_state {
if let Some(state) = &swap.protocol_state {
let indicatively_priced_state = state
.as_indicatively_priced()
.map_err(|e| {
@@ -1994,7 +1994,7 @@ mod tests {
let swap = SwapBuilder::new(bebop_component, token_in.clone(), token_out.clone())
.estimated_amount_in(BigUint::from_str("3000000000").unwrap())
.protocol_state(&bebop_state)
.protocol_state(Arc::new(bebop_state))
.build();
let encoding_context = EncodingContext {

View File

@@ -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<'static> {
fn swap_usdc_eth_univ4() -> Swap {
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();
@@ -442,7 +442,7 @@ mod tests {
.build()
}
fn swap_eth_pepe_univ4() -> Swap<'static> {
fn swap_eth_pepe_univ4() -> Swap {
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();

View File

@@ -1,3 +1,5 @@
use std::sync::Arc;
use clap::ValueEnum;
use num_bigint::BigUint;
use serde::{Deserialize, Serialize};
@@ -35,7 +37,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<'a> {
pub struct Solution {
/// Address of the sender.
pub sender: Bytes,
/// Address of the receiver.
@@ -55,7 +57,7 @@ pub struct Solution<'a> {
#[serde(with = "biguint_string")]
pub checked_amount: BigUint,
/// List of swaps to fulfill the solution.
pub swaps: Vec<Swap<'a>>,
pub swaps: Vec<Swap>,
/// If set, the corresponding native action will be executed.
pub native_action: Option<NativeAction>,
}
@@ -74,7 +76,7 @@ pub enum NativeAction {
/// Represents a swap operation to be performed on a pool.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Swap<'a> {
pub struct Swap {
/// Protocol component from tycho indexer
pub component: ProtocolComponent,
/// Token being input into the pool.
@@ -88,20 +90,20 @@ pub struct Swap<'a> {
pub user_data: Option<Bytes>,
/// Optional protocol state used to perform the swap.
#[serde(skip)]
pub protocol_state: Option<&'a dyn ProtocolSim>,
pub protocol_state: Option<Arc<dyn ProtocolSim>>,
/// Optional estimated amount in for this Swap. This is necessary for RFQ protocols. This value
/// is used to request the quote
pub estimated_amount_in: Option<BigUint>,
}
impl<'a> Swap<'a> {
impl Swap {
pub fn new<T: Into<ProtocolComponent>>(
component: T,
token_in: Bytes,
token_out: Bytes,
split: f64,
user_data: Option<Bytes>,
protocol_state: Option<&'a dyn ProtocolSim>,
protocol_state: Option<Arc<dyn ProtocolSim>>,
estimated_amount_in: Option<BigUint>,
) -> Self {
Self {
@@ -116,28 +118,29 @@ impl<'a> Swap<'a> {
}
}
impl<'a> PartialEq for Swap<'a> {
impl PartialEq for Swap {
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
self.user_data == other.user_data &&
self.estimated_amount_in == other.estimated_amount_in
// Skip protocol_state comparison since trait objects don't implement PartialEq
}
}
pub struct SwapBuilder<'a> {
pub struct SwapBuilder {
component: ProtocolComponent,
token_in: Bytes,
token_out: Bytes,
split: f64,
user_data: Option<Bytes>,
protocol_state: Option<&'a dyn ProtocolSim>,
protocol_state: Option<Arc<dyn ProtocolSim>>,
estimated_amount_in: Option<BigUint>,
}
impl<'a> SwapBuilder<'a> {
impl SwapBuilder {
pub fn new<T: Into<ProtocolComponent>>(
component: T,
token_in: Bytes,
@@ -164,7 +167,7 @@ impl<'a> SwapBuilder<'a> {
self
}
pub fn protocol_state(mut self, protocol_state: &'a dyn ProtocolSim) -> Self {
pub fn protocol_state(mut self, protocol_state: Arc<dyn ProtocolSim>) -> Self {
self.protocol_state = Some(protocol_state);
self
}
@@ -174,7 +177,7 @@ impl<'a> SwapBuilder<'a> {
self
}
pub fn build(self) -> Swap<'a> {
pub fn build(self) -> Swap {
Swap {
component: self.component,
token_in: self.token_in,

View File

@@ -1,4 +1,4 @@
use std::{collections::HashMap, str::FromStr};
use std::{collections::HashMap, str::FromStr, sync::Arc};
use alloy::hex::encode;
use num_bigint::{BigInt, BigUint};
@@ -662,7 +662,7 @@ fn test_uniswap_v3_bebop() {
let swap_usdc_wbtc = SwapBuilder::new(bebop_component, usdc.clone(), wbtc.clone())
.estimated_amount_in(BigUint::from_str("2021750881").unwrap())
.protocol_state(&bebop_state)
.protocol_state(Arc::new(bebop_state))
.build();
let encoder = get_tycho_router_encoder(UserTransferType::TransferFrom);