diff --git a/swap/src/asb/fixed_rate.rs b/swap/src/asb/fixed_rate.rs index bf42be53..4d0b2045 100644 --- a/swap/src/asb/fixed_rate.rs +++ b/swap/src/asb/fixed_rate.rs @@ -13,8 +13,8 @@ impl FixedRate { impl Default for FixedRate { fn default() -> Self { - Self(Rate { - ask: bitcoin::Amount::from_btc(Self::RATE).expect("Static value should never fail"), - }) + let ask = bitcoin::Amount::from_btc(Self::RATE).expect("Static value should never fail"); + + Self(Rate::new(ask)) } } diff --git a/swap/src/asb/rate.rs b/swap/src/asb/rate.rs index 08eb443d..9058f90d 100644 --- a/swap/src/asb/rate.rs +++ b/swap/src/asb/rate.rs @@ -9,7 +9,7 @@ use std::fmt::{Debug, Display, Formatter}; /// sell 1 XMR. #[derive(Debug, Clone, Copy, PartialEq)] pub struct Rate { - pub ask: bitcoin::Amount, + ask: bitcoin::Amount, } impl Rate { @@ -17,6 +17,14 @@ impl Rate { ask: bitcoin::Amount::ZERO, }; + pub fn new(ask: bitcoin::Amount) -> Self { + Self { ask } + } + + pub fn ask(&self) -> bitcoin::Amount { + self.ask + } + // This function takes the quote amount as it is what Bob sends to Alice in the // swap request pub fn sell_quote(&self, quote: bitcoin::Amount) -> Result { diff --git a/swap/src/kraken.rs b/swap/src/kraken.rs index 4bea5059..7aee6c5c 100644 --- a/swap/src/kraken.rs +++ b/swap/src/kraken.rs @@ -31,7 +31,7 @@ pub fn connect() -> Result { let mut stream = connection::new().await?; while let Some(update) = stream.try_next().await.map_err(to_backoff)? { - let send_result = rate_update.send(Ok(update)); + let send_result = rate_update.send(Ok(Rate::new(update.ask))); if send_result.is_err() { return Err(backoff::Error::Permanent(anyhow!( @@ -120,7 +120,7 @@ mod connection { use futures::stream::BoxStream; use tokio_tungstenite::tungstenite; - pub async fn new() -> Result>> { + pub async fn new() -> Result>> { let (mut rate_stream, _) = tokio_tungstenite::connect_async("wss://ws.kraken.com") .await .context("Failed to connect to Kraken websocket API")?; @@ -134,12 +134,12 @@ mod connection { Ok(stream) } - /// Parse a websocket message into a [`Rate`]. + /// Parse a websocket message into a [`wire::PriceUpdate`]. /// /// Messages which are not actually ticker updates are ignored and result in /// `None` being returned. In the context of a [`TryStream`], these will /// simply be filtered out. - async fn parse_message(msg: tungstenite::Message) -> Result, Error> { + async fn parse_message(msg: tungstenite::Message) -> Result, Error> { let msg = match msg { tungstenite::Message::Text(msg) => msg, tungstenite::Message::Close(close_frame) => { @@ -182,7 +182,7 @@ mod connection { return Ok(None); } // if the message is not an event, it is a ticker update or an unknown event - Err(_) => match serde_json::from_str::(&msg) { + Err(_) => match serde_json::from_str::(&msg) { Ok(ticker) => ticker, Err(e) => { tracing::warn!(%e, "Failed to deserialize message '{}' as ticker update", msg); @@ -192,8 +192,6 @@ mod connection { }, }; - let update = Rate::try_from(update)?; - Ok(Some(update)) } @@ -247,6 +245,13 @@ mod wire { BitcoinParseAmount(#[from] ParseAmountError), } + /// Represents an update within the price ticker. + #[derive(Debug, Deserialize)] + #[serde(try_from = "TickerUpdate")] + pub struct PriceUpdate { + pub ask: bitcoin::Amount, + } + #[derive(Debug, Deserialize)] #[serde(transparent)] pub struct TickerUpdate(Vec); @@ -273,7 +278,7 @@ mod wire { Number(u64), } - impl TryFrom for Rate { + impl TryFrom for PriceUpdate { type Error = Error; fn try_from(value: TickerUpdate) -> Result { @@ -293,7 +298,7 @@ mod wire { _ => return Err(Error::UnexpectedAskRateElementType), }; - Ok(Self { ask }) + Ok(PriceUpdate { ask }) } } diff --git a/swap/src/protocol/alice/event_loop.rs b/swap/src/protocol/alice/event_loop.rs index 2ed686fe..5179fb6f 100644 --- a/swap/src/protocol/alice/event_loop.rs +++ b/swap/src/protocol/alice/event_loop.rs @@ -278,7 +278,7 @@ where .context("Failed to get latest rate")?; Ok(BidQuote { - price: rate.ask, + price: rate.ask(), max_quantity: max_buy, }) }