Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions fynd-core/src/feed/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ pub(crate) struct TychoFeedConfig {
/// finalization, reducing effective latency at the cost of processing more frequent,
/// smaller updates.
pub(crate) partial_blocks: bool,
/// Override for the Tycho stream timeout in seconds. When unset, tycho-client derives it
/// from the chain's block time (3x block time for custom-registry chains), which can be too
/// tight for indexers that pause during catch-up bursts.
pub(crate) stream_timeout_secs: Option<u64>,
}

impl TychoFeedConfig {
Expand All @@ -78,6 +82,7 @@ impl TychoFeedConfig {
reconnect_delay: Duration::from_secs(5),
blocklisted_components: FxHashSet::default(),
partial_blocks: false,
stream_timeout_secs: None,
}
}

Expand Down Expand Up @@ -110,6 +115,11 @@ impl TychoFeedConfig {
self.partial_blocks = enabled;
self
}

pub(crate) fn stream_timeout_secs(mut self, timeout_secs: Option<u64>) -> Self {
self.stream_timeout_secs = timeout_secs;
self
}
}

/// Errors that can occur in the indexer.
Expand Down
11 changes: 11 additions & 0 deletions fynd-core/src/feed/protocol_registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,17 @@ pub(crate) fn register_exchanges(
builder =
builder.exchange::<UniswapV2State>("quickswap_v2", tvl_filter.clone(), None);
}
"blazeswap_v2" => {
builder =
builder.exchange::<UniswapV2State>("blazeswap_v2", tvl_filter.clone(), None);
}
"sparkdex_v3" => {
builder =
builder.exchange::<UniswapV3State>("sparkdex_v3", tvl_filter.clone(), None);
}
"enosys_v3" => {
builder = builder.exchange::<UniswapV3State>("enosys_v3", tvl_filter.clone(), None);
}
"lunarbase" => {
builder = builder.exchange::<LunarBaseState>("lunarbase", tvl_filter.clone(), None);
}
Expand Down
59 changes: 31 additions & 28 deletions fynd-core/src/feed/tycho_feed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,18 @@ impl TychoFeed {
Self { config, market_data, event_tx }
}

/// Base stream builder for this feed's Tycho endpoint and chain, with the configured
/// stream-timeout override applied when set.
fn stream_builder(&self) -> ProtocolStreamBuilder {
let mut stream_builder =
ProtocolStreamBuilder::new(&self.config.tycho_url, self.config.chain)
.skip_state_decode_failures(true);
if let Some(timeout_secs) = self.config.stream_timeout_secs {
stream_builder = stream_builder.latency_buffer(timeout_secs);
}
stream_builder
}

/// Returns a new subscriber for market events.
pub(crate) fn subscribe(&self) -> broadcast::Receiver<MarketEvent> {
self.event_tx.subscribe()
Expand Down Expand Up @@ -133,17 +145,13 @@ impl TychoFeed {
.clone(),
);

let mut stream_builder = register_exchanges(
ProtocolStreamBuilder::new(&self.config.tycho_url, self.config.chain)
.skip_state_decode_failures(true),
tvl_filter,
&self.config.protocols,
)?
.auth_key(self.config.tycho_api_key.clone())
.no_tls(!self.config.use_tls)
.skip_state_decode_failures(true)
.min_token_quality(self.config.min_token_quality as u32)
.add_client_metadata(fynd_client_metadata());
let mut stream_builder =
register_exchanges(self.stream_builder(), tvl_filter, &self.config.protocols)?
.auth_key(self.config.tycho_api_key.clone())
.no_tls(!self.config.use_tls)
.skip_state_decode_failures(true)
.min_token_quality(self.config.min_token_quality as u32)
.add_client_metadata(fynd_client_metadata());

if self.config.partial_blocks {
stream_builder = stream_builder.enable_partial_blocks();
Expand Down Expand Up @@ -312,8 +320,7 @@ impl TychoFeed {
debug!("Loaded {} tokens from Tycho", all_tokens.len());

let mut stream_builder = match register_exchanges(
ProtocolStreamBuilder::new(&self.config.tycho_url, self.config.chain)
.skip_state_decode_failures(true),
self.stream_builder(),
ComponentFilter::with_tvl_range(
self.config.min_tvl / self.config.tvl_buffer_ratio,
self.config.min_tvl,
Expand Down Expand Up @@ -520,22 +527,18 @@ impl TychoFeed {
.clone(),
);

let mut stream_builder = match register_exchanges(
ProtocolStreamBuilder::new(&self.config.tycho_url, self.config.chain)
.skip_state_decode_failures(true),
tvl_filter,
&self.config.protocols,
) {
Ok(sb) => sb,
Err(e) => {
let _ = controller_tx.send(Err(e.to_string()));
return Err(e);
let mut stream_builder =
match register_exchanges(self.stream_builder(), tvl_filter, &self.config.protocols) {
Ok(sb) => sb,
Err(e) => {
let _ = controller_tx.send(Err(e.to_string()));
return Err(e);
}
}
}
.auth_key(self.config.tycho_api_key.clone())
.skip_state_decode_failures(true)
.min_token_quality(self.config.min_token_quality as u32)
.add_client_metadata(fynd_client_metadata());
.auth_key(self.config.tycho_api_key.clone())
.skip_state_decode_failures(true)
.min_token_quality(self.config.min_token_quality as u32)
.add_client_metadata(fynd_client_metadata());

if self.config.partial_blocks {
stream_builder = stream_builder.enable_partial_blocks();
Expand Down
15 changes: 14 additions & 1 deletion fynd-core/src/solver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,7 @@ pub struct FyndBuilder {
reconnect_delay: Duration,
blocklisted_components: FxHashSet<String>,
partial_blocks: bool,
stream_timeout_secs: Option<u64>,
router_timeout: Duration,
router_min_responses: usize,
encoder: Option<Encoder>,
Expand Down Expand Up @@ -457,6 +458,7 @@ impl FyndBuilder {
reconnect_delay: defaults::RECONNECT_DELAY,
blocklisted_components: FxHashSet::default(),
partial_blocks: false,
stream_timeout_secs: None,
router_timeout: DEFAULT_ROUTER_TIMEOUT,
router_min_responses: defaults::ROUTER_MIN_RESPONSES,
encoder: None,
Expand Down Expand Up @@ -537,6 +539,16 @@ impl FyndBuilder {
self
}

/// Overrides the Tycho stream timeout in seconds (default: derived from the chain's block
/// time by tycho-client).
///
/// Useful when the upstream indexer can pause longer than the derived timeout, e.g. during
/// catch-up bursts, which would otherwise end the stream with a missed-block error.
pub fn stream_timeout_secs(mut self, timeout_secs: Option<u64>) -> Self {
self.stream_timeout_secs = timeout_secs;
self
}

/// Sets the worker router timeout (default: 10s).
pub fn worker_router_timeout(mut self, timeout: Duration) -> Self {
self.router_timeout = timeout;
Expand Down Expand Up @@ -715,7 +727,8 @@ impl FyndBuilder {
.min_token_quality(self.min_token_quality)
.traded_n_days_ago(self.traded_n_days_ago)
.blocklisted_components(self.blocklisted_components)
.partial_blocks(self.partial_blocks);
.partial_blocks(self.partial_blocks)
.stream_timeout_secs(self.stream_timeout_secs);

let ethereum_client = EthereumRpcClient::new(self.rpc_url.as_str())
.map_err(|e| SolverBuildError::RpcClient(e.to_string()))?;
Expand Down
9 changes: 9 additions & 0 deletions fynd-rpc/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,15 @@ impl FyndRPCBuilder {
self
}

/// Overrides the Tycho stream timeout in seconds (default: derived from the chain's block
/// time by tycho-client).
pub fn stream_timeout_secs(mut self, timeout_secs: Option<u64>) -> Self {
self.fynd_builder = self
.fynd_builder
.stream_timeout_secs(timeout_secs);
self
}

/// Overrides the default encoder with a custom one.
pub fn encoder(mut self, encoder: Encoder) -> Self {
self.fynd_builder = self.fynd_builder.encoder(encoder);
Expand Down
5 changes: 5 additions & 0 deletions src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,11 @@ pub struct ServeArgs {
#[arg(long)]
pub partial_blocks: bool,

/// Override the Tycho stream timeout in seconds. When unset, tycho-client derives it from
/// the chain's block time, which can be too tight for indexers that pause during catch-up.
#[arg(long, env = "FYND_STREAM_TIMEOUT_SECS")]
pub stream_timeout_secs: Option<u64>,

/// Enable price guard validation against external price sources.
/// Disabled by default.
#[arg(long)]
Expand Down
1 change: 1 addition & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,7 @@ async fn setup_solver(args: &cli::ServeArgs) -> Result<fynd_rpc::builder::FyndRP

builder = builder.blocklist(blocklist);
builder = builder.partial_blocks(args.partial_blocks);
builder = builder.stream_timeout_secs(args.stream_timeout_secs);
builder = builder.price_guard_enabled(args.enable_price_guard);

// Build and start solver
Expand Down