diff --git a/CHANGELOG.md b/CHANGELOG.md index ea24f3ce..c5659d4e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Printing the deposit address to the terminal as a QR code. To not break automated scripts or integrations with other software, this behaviour is disabled if `--json` is passed to the application. +- Configuration setting for the websocket URL that the ASB connects to in order to receive price ticker updates. Can be configured manually by editing the config.toml file directly. It is expected that the server behind the url follows the same protocol as the [kraken websocket api](https://docs.kraken.com/websockets/) ### Fixed diff --git a/Cargo.lock b/Cargo.lock index ffa9f6b3..ff3dc569 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3283,9 +3283,9 @@ dependencies = [ [[package]] name = "rust_decimal" -version = "1.14.2" +version = "1.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9787e62372fc0c5a0f3af64c392652db72d3ec1cc0cff1becc175d2c11e6fbcc" +checksum = "01127cb8617e5e21bcf2e19b5eb48317735ca677f1d0a94833c21c331c446582" dependencies = [ "arrayvec", "num-traits", @@ -3294,9 +3294,9 @@ dependencies = [ [[package]] name = "rust_decimal_macros" -version = "1.14.1" +version = "1.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9ac0a0a5fcc647fd50ad212f7806cc36e5551684ddb7d5d8522d788035f7893" +checksum = "a776fe1e773e2e599d7813414ca7dd1f78b7e0fa699ecbefbfd24b5584df6819" dependencies = [ "quote 1.0.9", "rust_decimal", diff --git a/swap/src/asb/config.rs b/swap/src/asb/config.rs index 984bc3ee..391e4b41 100644 --- a/swap/src/asb/config.rs +++ b/swap/src/asb/config.rs @@ -27,6 +27,7 @@ pub struct Defaults { listen_address_ws: Multiaddr, electrum_rpc_url: Url, monero_wallet_rpc_url: Url, + price_ticker_ws_url: Url, bitcoin_confirmation_target: usize, } @@ -41,6 +42,7 @@ impl GetDefaults for Testnet { listen_address_ws: Multiaddr::from_str("/ip4/0.0.0.0/tcp/9940/ws")?, electrum_rpc_url: Url::parse("ssl://electrum.blockstream.info:60002")?, monero_wallet_rpc_url: Url::parse("http://127.0.0.1:38083/json_rpc")?, + price_ticker_ws_url: Url::parse("wss://ws.kraken.com")?, bitcoin_confirmation_target: 1, }; @@ -59,6 +61,7 @@ impl GetDefaults for Mainnet { listen_address_ws: Multiaddr::from_str("/ip4/0.0.0.0/tcp/9940/ws")?, electrum_rpc_url: Url::parse("ssl://electrum.blockstream.info:50002")?, monero_wallet_rpc_url: Url::parse("http://127.0.0.1:18083/json_rpc")?, + price_ticker_ws_url: Url::parse("wss://ws.kraken.com")?, bitcoin_confirmation_target: 3, }; @@ -151,6 +154,7 @@ pub struct Maker { #[serde(with = "::bitcoin::util::amount::serde::as_btc")] pub max_buy_btc: bitcoin::Amount, pub ask_spread: Decimal, + pub price_ticker_ws_url: Url, } impl Default for TorConf { @@ -307,6 +311,7 @@ pub fn query_user_for_initial_config(testnet: bool) -> Result { min_buy_btc: min_buy, max_buy_btc: max_buy, ask_spread, + price_ticker_ws_url: defaults.price_ticker_ws_url, }, }) } @@ -347,6 +352,7 @@ mod tests { min_buy_btc: bitcoin::Amount::from_btc(DEFAULT_MIN_BUY_AMOUNT).unwrap(), max_buy_btc: bitcoin::Amount::from_btc(DEFAULT_MAX_BUY_AMOUNT).unwrap(), ask_spread: Decimal::from_f64(DEFAULT_SPREAD).unwrap(), + price_ticker_ws_url: defaults.price_ticker_ws_url, }, }; @@ -387,6 +393,7 @@ mod tests { min_buy_btc: bitcoin::Amount::from_btc(DEFAULT_MIN_BUY_AMOUNT).unwrap(), max_buy_btc: bitcoin::Amount::from_btc(DEFAULT_MAX_BUY_AMOUNT).unwrap(), ask_spread: Decimal::from_f64(DEFAULT_SPREAD).unwrap(), + price_ticker_ws_url: defaults.price_ticker_ws_url, }, }; diff --git a/swap/src/bin/asb.rs b/swap/src/bin/asb.rs index ef590dd1..052c7db1 100644 --- a/swap/src/bin/asb.rs +++ b/swap/src/bin/asb.rs @@ -125,7 +125,7 @@ async fn main() -> Result<()> { info!(%monero_balance, "Initialized Monero wallet"); } - let kraken_price_updates = kraken::connect()?; + let kraken_price_updates = kraken::connect(config.maker.price_ticker_ws_url)?; // setup Tor hidden services let tor_client = diff --git a/swap/src/bin/kraken_ticker.rs b/swap/src/bin/kraken_ticker.rs index a28bac50..3b1cc389 100644 --- a/swap/src/bin/kraken_ticker.rs +++ b/swap/src/bin/kraken_ticker.rs @@ -1,4 +1,5 @@ use anyhow::{Context, Result}; +use url::Url; #[tokio::main] async fn main() -> Result<()> { @@ -6,7 +7,9 @@ async fn main() -> Result<()> { tracing_subscriber::fmt().with_env_filter("debug").finish(), )?; - let mut ticker = swap::kraken::connect().context("Failed to connect to kraken")?; + let price_ticker_ws_url = Url::parse("wss://ws.kraken.com")?; + let mut ticker = + swap::kraken::connect(price_ticker_ws_url).context("Failed to connect to kraken")?; loop { match ticker.wait_for_next_update().await? { diff --git a/swap/src/kraken.rs b/swap/src/kraken.rs index 001696ff..4a47bf9c 100644 --- a/swap/src/kraken.rs +++ b/swap/src/kraken.rs @@ -5,11 +5,16 @@ use std::convert::{Infallible, TryFrom}; use std::sync::Arc; use std::time::Duration; use tokio::sync::watch; +use url::Url; /// Connect to Kraken websocket API for a constant stream of rate updates. /// /// If the connection fails, it will automatically be re-established. -pub fn connect() -> Result { +/// +/// price_ticker_ws_url must point to a websocket server that follows the kraken +/// price ticker protocol +/// See: https://docs.kraken.com/websockets/ +pub fn connect(price_ticker_ws_url: Url) -> Result { let (price_update, price_update_receiver) = watch::channel(Err(Error::NotYetAvailable)); let price_update = Arc::new(price_update); @@ -26,8 +31,9 @@ pub fn connect() -> Result { backoff, || { let price_update = price_update.clone(); + let price_ticker_ws_url = price_ticker_ws_url.clone(); async move { - let mut stream = connection::new().await?; + let mut stream = connection::new(price_ticker_ws_url).await?; while let Some(update) = stream.try_next().await.map_err(to_backoff)? { let send_result = price_update.send(Ok(update)); @@ -123,8 +129,8 @@ mod connection { use futures::stream::BoxStream; use tokio_tungstenite::tungstenite; - pub async fn new() -> Result>> { - let (mut rate_stream, _) = tokio_tungstenite::connect_async("wss://ws.kraken.com") + pub async fn new(ws_url: Url) -> Result>> { + let (mut rate_stream, _) = tokio_tungstenite::connect_async(ws_url) .await .context("Failed to connect to Kraken websocket API")?;