use std::time::{Duration, Instant};
use num_bigint::{BigInt, BigUint};
use petgraph::graph::NodeIndex;
use rustc_hash::FxHashSet;
use tycho_simulation::tycho_common::{models::Address, simulation::protocol_sim::ProtocolSim};
use crate::{
algorithm::{
most_liquid::DepthAndPrice,
sim_meter,
swap_cache::{SwapCache, SwapResult},
WaterFillAlgorithm,
},
derived::TokenGasPrices,
feed::market_data::{MarketDataView, MarketState},
graph::{EdgeData, GraphQueryFilter, Path, TopologyGraph},
types::RouteResult,
ComponentId, Order, Route,
};
pub struct SplitCandidate {
pub route: Route,
pub gross: BigUint,
pub gas: BigUint,
}
impl SplitCandidate {
pub(crate) fn net(&self, input: &SolveInput<'_, '_>) -> BigInt {
let cost = WaterFillAlgorithm::gas_cost_in_token(
&self.gas,
&input.gas_price,
input.token_prices.as_ref(),
input.order.token_out(),
);
match cost {
Some(c) => BigInt::from(self.gross.clone()) - BigInt::from(c),
None => BigInt::from(self.gross.clone()),
}
}
}
pub struct ExchangeMove {
pub donor: usize,
pub recipient: usize,
pub donor_net: BigInt,
pub recip_net: BigInt,
pub gain: BigInt,
}
pub struct StepResult {
pub amount_out: BigUint,
pub gas: BigUint,
pub new_states: Vec<(ComponentId, Box<dyn ProtocolSim>)>,
}
#[derive(Clone)]
pub enum FullAmountOutcome {
Filled(SwapResult),
Unfilled,
}
pub struct FullAmountRanking {
pub by_output: Vec<usize>,
pub by_output_net_gas: Vec<usize>,
}
pub struct SolveInput<'o, 'g> {
pub ordered: Vec<Path<'g, DepthAndPrice>>,
pub market: MarketState,
pub gas_price: BigUint,
pub token_prices: Option<TokenGasPrices>,
pub order: &'o Order,
pub deadline: Deadline,
}
pub struct SetupResult<'o, 'g> {
pub input: SolveInput<'o, 'g>,
pub best_single: Option<RouteResult>,
pub cache: SwapCache<'g>,
}
#[derive(Clone)]
pub struct CandidatePathState<'a, W> {
pub node: NodeIndex,
pub path: Path<'a, W>,
pub amount_out: BigUint,
}
pub struct ScoredEdge<'a, W> {
pub target: NodeIndex,
pub edge: &'a EdgeData<W>,
pub amount_out: BigUint,
pub priority: u8,
}
#[derive(Clone, Copy)]
pub struct CandidateSearchConfig<'a> {
pub query: &'a GraphQueryFilter,
pub max_candidates: usize,
pub anchor_tokens: &'a FxHashSet<Address>,
pub source_token: &'a Address,
pub deadline: Deadline,
}
pub struct Discovery<'a, 'r, W> {
pub graph: &'a TopologyGraph<W>,
pub market: &'r MarketDataView<'r>,
pub cfg: &'r CandidateSearchConfig<'r>,
pub cache: &'r mut SwapCache<'a>,
}
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub(crate) enum SolveStage {
Discovery,
Ranking,
SetSelection,
Exchange,
Chunking,
Assembly,
}
impl SolveStage {
pub(crate) fn label(self) -> sim_meter::StageLabel {
match self {
SolveStage::Discovery => "discovery",
SolveStage::Ranking => "ranking",
SolveStage::SetSelection => "set-selection",
SolveStage::Exchange => "exchange",
SolveStage::Chunking => "chunking",
SolveStage::Assembly => "assembly",
}
}
pub(crate) fn may_interpolate(self) -> bool {
match self {
SolveStage::Ranking | SolveStage::SetSelection => true,
SolveStage::Discovery |
SolveStage::Exchange |
SolveStage::Chunking |
SolveStage::Assembly => false,
}
}
}
#[derive(Clone, Copy)]
pub struct Deadline {
pub start: Instant,
pub timeout: Duration,
}
impl Deadline {
pub(crate) fn new(start: Instant, timeout: Duration) -> Self {
Self { start, timeout }
}
pub(crate) fn expired(&self) -> bool {
self.start.elapsed() > self.timeout
}
pub(crate) fn elapsed(&self) -> Duration {
self.start.elapsed()
}
}