Skip to main content

tycho_simulation/rfq/protocols/hashflow/
client_builder.rs

1use std::collections::HashSet;
2
3use tokio::time::Duration;
4use tycho_common::{models::Chain, Bytes};
5
6use super::client::HashflowClient;
7use crate::rfq::{
8    errors::RFQError,
9    models::{ComponentLayout, QuoteRule},
10    protocols::utils::default_quote_tokens_for_chain,
11};
12
13/// `HashflowClientBuilder` is a builder pattern implementation for creating instances of
14/// `HashflowClient`.
15///
16/// # Example
17/// ```rust
18/// use tycho_simulation::rfq::protocols::hashflow::client_builder::HashflowClientBuilder;
19/// use tycho_common::{models::Chain, Bytes};
20/// use std::{collections::HashSet, str::FromStr, time::Duration};
21///
22/// let mut tokens = HashSet::new();
23/// tokens.insert(Bytes::from_str("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2").unwrap()); // WETH
24/// tokens.insert(Bytes::from_str("0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48").unwrap()); // USDC
25///
26/// let client = HashflowClientBuilder::new(
27///     Chain::Ethereum,
28///     "auth_user".to_string(),
29///     "auth_key".to_string()
30/// )
31/// .tokens(tokens)
32/// .tvl_threshold(500.0)
33/// .poll_time(Duration::from_secs(10))
34/// .build()
35/// .unwrap();
36/// ```
37pub struct HashflowClientBuilder {
38    chain: Chain,
39    auth_user: String,
40    auth_key: String,
41    tokens: HashSet<Bytes>,
42    tvl: f64,
43    quote_tokens: Option<HashSet<Bytes>>,
44    poll_time: Duration,
45    quote_timeout: Duration,
46    via_fallback_router: bool,
47    component_layout: ComponentLayout,
48    quote_rule: QuoteRule,
49}
50
51impl HashflowClientBuilder {
52    pub fn new(chain: Chain, auth_user: String, auth_key: String) -> Self {
53        Self {
54            chain,
55            auth_user,
56            auth_key,
57            tokens: HashSet::new(),
58            tvl: 100.0, // Default $100 minimum TVL
59            quote_tokens: None,
60            poll_time: Duration::from_secs(5), // Default 5 second polling
61            quote_timeout: Duration::from_secs(5), // Default 5 second timeout
62            via_fallback_router: false,
63            component_layout: ComponentLayout::PerPair,
64            quote_rule: HashflowClient::DEFAULT_QUOTE_RULE,
65        }
66    }
67
68    /// The components the client streams. One per pair, by default. Register a `PerPair` client
69    /// with `HashflowState` and a `AllPairs` client with `HashflowAllPairsState`.
70    pub fn component_layout(mut self, component_layout: ComponentLayout) -> Self {
71        self.component_layout = component_layout;
72        self
73    }
74
75    /// How often one route may take quotes from Hashflow, under the `AllPairs` layout. Every
76    /// maker once, by default.
77    pub fn quote_rule(mut self, quote_rule: QuoteRule) -> Self {
78        self.quote_rule = quote_rule;
79        self
80    }
81
82    /// Set the tokens for which to monitor prices
83    pub fn tokens(mut self, tokens: HashSet<Bytes>) -> Self {
84        self.tokens = tokens;
85        self
86    }
87
88    /// Set the minimum TVL threshold for pools
89    pub fn tvl_threshold(mut self, tvl: f64) -> Self {
90        self.tvl = tvl;
91        self
92    }
93
94    /// Set custom quote tokens for TVL calculation
95    /// If not set, will use chain-specific defaults
96    pub fn quote_tokens(mut self, quote_tokens: HashSet<Bytes>) -> Self {
97        self.quote_tokens = Some(quote_tokens);
98        self
99    }
100
101    /// Set the polling interval for fetching price levels
102    pub fn poll_time(mut self, poll_time: Duration) -> Self {
103        self.poll_time = poll_time;
104        self
105    }
106
107    /// Set the timeout for firm quote requests
108    pub fn quote_timeout(mut self, timeout: Duration) -> Self {
109        self.quote_timeout = timeout;
110        self
111    }
112
113    /// Executes the swaps through Tycho's `HashflowFallbackRouter`. Off by default.
114    pub fn with_fallback_router(mut self) -> Self {
115        self.via_fallback_router = true;
116        self
117    }
118
119    pub fn build(self) -> Result<HashflowClient, RFQError> {
120        let quote_tokens;
121        if let Some(tokens) = self.quote_tokens {
122            quote_tokens = tokens;
123        } else {
124            quote_tokens = default_quote_tokens_for_chain(&self.chain)?
125        }
126
127        let client = HashflowClient::new(
128            self.chain,
129            self.tokens,
130            self.tvl,
131            quote_tokens,
132            self.auth_user,
133            self.auth_key,
134            self.poll_time,
135            self.quote_timeout,
136        )?
137        .with_component_layout(self.component_layout)
138        .with_quote_rule(self.quote_rule);
139        Ok(if self.via_fallback_router { client.via_fallback_router() } else { client })
140    }
141}