Skip to main content

tycho_simulation/price_level_stream/
config.rs

1use std::str::FromStr;
2
3use num_bigint::BigUint;
4use tycho_common::Bytes;
5
6/// Protocol system family name of components sourced from the pAMM price level stream.
7///
8/// The full protocol system of a component is `pricelevelstream:{pamm}`, where `{pamm}` is the
9/// configured venue name (e.g. `pricelevelstream:fermiswap`) or, for auto-detected venues, the
10/// venue address (e.g. `pricelevelstream:0x5979…`); see the [module documentation](super) for
11/// details.
12pub const PRICE_LEVEL_STREAM_FAMILY: &str = "pricelevelstream";
13
14/// Protocol system family of components executed through Titan's PropAMMRouter instead of the
15/// venue directly, so a stale maker quote falls back to a single-hop Uniswap V3 pool instead of
16/// reverting the route.
17///
18/// Must match `tycho-execution`'s `PROPAMM_FALLBACK_KEY`.
19pub const PROPAMM_FALLBACK_FAMILY: &str = "propammfallback";
20
21/// Configuration of a single pAMM to be served from the price level stream.
22#[derive(Debug, Clone)]
23pub struct PriceLevelStreamConfig {
24    /// Bare pAMM name (e.g. `fermiswap`); the emitted components carry
25    /// `pricelevelstream:{protocol}` as their protocol system.
26    pub protocol: String,
27    /// The pAMM venue address under which Titan streams its quotes.
28    pub address: Bytes,
29    /// Constant per-swap gas cost estimate reported for every quote of this pAMM.
30    pub gas_cost: BigUint,
31}
32
33impl PriceLevelStreamConfig {
34    pub fn new(protocol: impl Into<String>, address: Bytes, gas_cost: BigUint) -> Self {
35        Self { protocol: protocol.into(), address, gas_cost }
36    }
37
38    /// The configuration an auto-detected pAMM (streamed by Titan but not otherwise configured)
39    /// is served under: named by its full lowercase hex address, with the given per-swap gas
40    /// cost.
41    pub(super) fn auto_detected(address: Bytes, gas_cost: BigUint) -> Self {
42        let protocol = address.to_string();
43        Self::new(protocol, address, gas_cost)
44    }
45
46    /// The protocol system identifier of components emitted for this pAMM.
47    pub fn protocol_system(&self) -> String {
48        format!("{PRICE_LEVEL_STREAM_FAMILY}:{}", self.protocol)
49    }
50
51    /// The protocol system identifier when this pAMM executes through Titan's PropAMMRouter.
52    pub fn fallback_protocol_system(&self) -> String {
53        format!("{PROPAMM_FALLBACK_FAMILY}:{}", self.protocol)
54    }
55}
56
57/// Per-swap gas estimate for auto-detected pAMMs whose venue has not been measured: the maximum
58/// over the known venue profiles (see [`default_served_pamms`]), as the conservative choice.
59/// Overridable per stream via
60/// [`auto_detected_gas_cost`](super::stream::PriceLevelStreamBuilder::auto_detected_gas_cost).
61pub const DEFAULT_AUTO_DETECTED_GAS_COST: u64 = 335_000;
62
63/// The pAMMs known to be served by the Titan price level stream (as of 2026-08-13): FermiSwap,
64/// Kipseli, Metric, Bebop, and TaurusFi.
65///
66/// Registered on a builder via
67/// [`with_known_pamms`](super::stream::PriceLevelStreamBuilder::with_known_pamms), so their
68/// components carry the venue name instead of the raw address; an
69/// [`add_pamm`](super::stream::PriceLevelStreamBuilder::add_pamm) call for one of these
70/// addresses overrides the corresponding entry.
71///
72/// Only the venues' router addresses are registered — the keys the price level stream has been
73/// observed to use — because the streamed key doubles as the execution target
74/// ([`PAMM_ADDRESS_ATTRIBUTE`](super::stream::PAMM_ADDRESS_ATTRIBUTE)): unlike the state-override
75/// stream, which also publishes frames under non-executable oracle aliases, an entry here must
76/// be an address a swap can be sent to.
77pub fn default_served_pamms() -> Vec<PriceLevelStreamConfig> {
78    // The venues' `IPropAMM::swap` gas, calibrated by replaying real fills on the live venues at
79    // fresh-oracle blocks via `debug_traceCall`, plus a small headroom. Deliberately excludes
80    // router-level overhead (user/input/fee transfers): tycho-execution's gas estimator accounts
81    // for those on top of this per-swap value.
82    let pamms = [
83        // The FermiSwapper router. Measured ~177k-182k (2026-08-18).
84        ("fermiswap", "0x5979458912f80b96d30d4220af8e2e4925a33320", 185_000u64),
85        // The KipseliPropAMMWrapper router. Measured ~308k-329k (2026-08-18). Titan's venue docs
86        // list a newer Kipseli router (0x342b8458…), but the stream still keys Kipseli
87        // quotes by this address and the newer one has no activity.
88        ("kipseli", "0x71e790dd841c8a9061487cb3e78c288e75ce0b3d", 335_000u64),
89        // The Metric router (unverified; identified via its pools' pricing reads of the Metric
90        // oracle 0x28d9cced…). Measured ~225k (2026-08-18).
91        ("metric", "0xe715dc29d2c273d0fc5a03e5cca9ccb0abb1dcdb", 230_000u64),
92        // The BopAMM (Bebop) router, per Titan's venue docs. Measured ~133k-136k (2026-08-18).
93        ("bebop", "0xb09aaa5614916d7aeb59c295c52c92ca82addd76", 140_000u64),
94        // The TaurusFi router, per Titan's venue docs. Measured ~105k (2026-08-18).
95        ("taurusfi", "0x217d58931a8549ca539426aa8152e33dafc3d95a", 110_000u64),
96    ];
97    pamms
98        .into_iter()
99        .map(|(protocol, address, gas_cost)| {
100            PriceLevelStreamConfig::new(
101                protocol,
102                Bytes::from_str(address).expect("hardcoded pAMM address must parse"),
103                BigUint::from(gas_cost),
104            )
105        })
106        .collect()
107}
108
109/// The streamed venues known NOT to be executable through the generic executor, excluded from
110/// auto-detection via
111/// [`with_known_pamms`](super::stream::PriceLevelStreamBuilder::with_known_pamms): quoting them
112/// would advertise liquidity every routed swap reverts on. An
113/// [`add_pamm`](super::stream::PriceLevelStreamBuilder::add_pamm) entry for one of these
114/// addresses overrides the denial.
115pub fn default_denied_pamms() -> Vec<Bytes> {
116    // Tempest, per Titan's venue docs (unverified contract). Its `swap` enforces a taker
117    // allowlist: replays of real fills (2026-08-11) revert with `TakerNotAllowed()` (0xf774ea08)
118    // for arbitrary callers regardless of recipient and succeed only from allowlisted takers, so
119    // swaps sent by the executor would revert.
120    ["0x00000003f1ec2379e79f58e12ec6c4f51ee92149"]
121        .into_iter()
122        .map(|address| Bytes::from_str(address).expect("hardcoded pAMM address must parse"))
123        .collect()
124}