price_levels/
price_levels.rs1use std::sync::Arc;
12
13use propamm::common::helpers::{format_units, parse_address};
14use propamm::common::pamms::PAMMS;
15use propamm::common::tokens::{USDC, USDT, WETH};
16use propamm::prices::{PriceLevels, PriceLevelsRpcSource};
17use propamm::{Address, U256};
18
19#[tokio::main(flavor = "current_thread")]
20async fn main() -> Result<(), Box<dyn std::error::Error>> {
21 let prices = match std::env::var("PRICE_LEVELS_URL") {
24 Ok(url) => PriceLevels::with_source(Arc::new(PriceLevelsRpcSource::new(url))),
25 Err(_) => PriceLevels::new(),
26 };
27
28 let snapshot = prices.get_price_levels().await?;
30 println!(
31 "snapshot @ block {} — {} pAMM(s)",
32 snapshot
33 .block_number
34 .map_or_else(|| "?".to_string(), |b| b.to_string()),
35 snapshot.pamms.len()
36 );
37
38 let Some((pamm, pair)) = snapshot.pamms.iter().find_map(|entry| {
40 entry
41 .pairs
42 .iter()
43 .find(|pair| !pair.order_book.is_empty())
44 .map(|pair| (entry.pamm, pair))
45 }) else {
46 return Err("snapshot carried no order books".into());
47 };
48
49 println!(
50 "\n{} order book: {} -> {}",
51 venue_name(pamm),
52 token_symbol(pair.token_in),
53 token_symbol(pair.token_out),
54 );
55 for level in &pair.order_book {
56 println!(
57 " {} -> {} [{:?}]",
58 fmt(level.amount_in, pair.token_in),
59 fmt(level.amount_out, pair.token_out),
60 level.variant,
61 );
62 }
63
64 let size = pair.order_book[pair.order_book.len() / 2].amount_in;
67
68 let best = prices
69 .get_quote(pair.token_in, pair.token_out, size)
70 .await?;
71 println!(
72 "\nbest quote: {} -> {} via {}",
73 fmt(best.amount_in, best.token_in),
74 fmt(best.amount_out, best.token_out),
75 venue_name(best.pamm),
76 );
77
78 let pinned = prices
79 .get_quote_venue(pamm, pair.token_in, pair.token_out, size)
80 .await?;
81 println!(
82 "{} quote: {} -> {}",
83 venue_name(pamm),
84 fmt(pinned.amount_in, pinned.token_in),
85 fmt(pinned.amount_out, pinned.token_out),
86 );
87
88 Ok(())
89}
90
91fn token_info(token: Address) -> (String, u32) {
93 let wbtc = parse_address("0x2260fac5e5542a773aa44fbcfedf7c193bc2c599").unwrap();
94 if token == USDC {
95 ("USDC".into(), 6)
96 } else if token == USDT {
97 ("USDT".into(), 6)
98 } else if token == WETH {
99 ("WETH".into(), 18)
100 } else if token == wbtc {
101 ("WBTC".into(), 8)
102 } else {
103 (format!("{token:#x}"), 0)
104 }
105}
106
107fn token_symbol(token: Address) -> String {
108 token_info(token).0
109}
110
111fn fmt(amount: U256, token: Address) -> String {
112 let (symbol, decimals) = token_info(token);
113 format!("{} {}", format_units(amount, decimals), symbol)
114}
115
116fn venue_name(address: Address) -> String {
118 PAMMS
119 .iter()
120 .find(|(_, a)| *a == address)
121 .map_or_else(|| format!("{address:#x}"), |(name, _)| name.to_string())
122}