Merge branch 'master' into libp2p_upgrade

This commit is contained in:
Byron Hambly 2022-08-03 22:07:24 +02:00 committed by GitHub
commit ec169916d6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 307 additions and 161 deletions

View file

@ -326,11 +326,13 @@ where
.ask()
.context("Failed to compute asking price")?;
let max_bitcoin_for_monero = self
.monero_wallet
.get_balance()
.await?
.max_bitcoin_for_price(ask_price);
let xmr = self.monero_wallet.get_balance().await?;
let max_bitcoin_for_monero = xmr.max_bitcoin_for_price(ask_price).ok_or_else(|| {
anyhow::anyhow!("Bitcoin price ({}) x Monero ({}) overflow", ask_price, xmr)
})?;
tracing::debug!(%ask_price, %xmr, %max_bitcoin_for_monero);
if min_buy > max_bitcoin_for_monero {
tracing::warn!(

View file

@ -1,6 +1,6 @@
use anyhow::Result;
use tracing_subscriber::filter::LevelFilter;
use tracing_subscriber::fmt::time::ChronoLocal;
use tracing_subscriber::fmt::time::UtcTime;
use tracing_subscriber::FmtSubscriber;
pub fn init(level: LevelFilter, json_format: bool, timestamp: bool) -> Result<()> {
@ -14,7 +14,7 @@ pub fn init(level: LevelFilter, json_format: bool, timestamp: bool) -> Result<()
.with_env_filter(format!("asb={},swap={}", level, level))
.with_writer(std::io::stderr)
.with_ansi(is_terminal)
.with_timer(ChronoLocal::with_format("%F %T".to_owned()))
.with_timer(UtcTime::rfc_3339())
.with_target(false);
match (json_format, timestamp) {

View file

@ -105,6 +105,8 @@ async fn main() -> Result<()> {
let event_loop = tokio::spawn(event_loop.run());
let max_givable = || bitcoin_wallet.max_giveable(TxLock::script_size());
let estimate_fee = |amount| bitcoin_wallet.estimate_fee(TxLock::weight(), amount);
let (amount, fees) = match determine_btc_to_swap(
json,
event_loop_handle.request_quote(),
@ -112,6 +114,7 @@ async fn main() -> Result<()> {
|| bitcoin_wallet.balance(),
max_givable,
|| bitcoin_wallet.sync(),
estimate_fee,
)
.await
{
@ -558,13 +561,14 @@ fn qr_code(value: &impl ToString) -> Result<String> {
Ok(qr_code)
}
async fn determine_btc_to_swap<FB, TB, FMG, TMG, FS, TS>(
async fn determine_btc_to_swap<FB, TB, FMG, TMG, FS, TS, FFE, TFE>(
json: bool,
bid_quote: impl Future<Output = Result<BidQuote>>,
get_new_address: impl Future<Output = Result<bitcoin::Address>>,
balance: FB,
max_giveable_fn: FMG,
sync: FS,
estimate_fee: FFE,
) -> Result<(bitcoin::Amount, bitcoin::Amount)>
where
TB: Future<Output = Result<bitcoin::Amount>>,
@ -573,6 +577,8 @@ where
FMG: Fn() -> TMG,
TS: Future<Output = Result<()>>,
FS: Fn() -> TS,
FFE: Fn(bitcoin::Amount) -> TFE,
TFE: Future<Output = Result<bitcoin::Amount>>,
{
tracing::debug!("Requesting quote");
let bid_quote = bid_quote.await?;
@ -600,8 +606,17 @@ where
}
loop {
let min_outstanding = bid_quote.min_quantity - max_giveable;
let min_fee = estimate_fee(min_outstanding).await?;
let min_deposit = min_outstanding + min_fee;
tracing::info!(
"Deposit at least {} to cover the min quantity with fee!",
min_deposit
);
tracing::info!(
%deposit_address,
%min_deposit,
%max_giveable,
%minimum_amount,
%maximum_amount,
@ -633,9 +648,7 @@ where
let balance = balance().await?;
let fees = balance - max_giveable;
let max_accepted = bid_quote.max_quantity;
let btc_swap_amount = min(max_giveable, max_accepted);
Ok((btc_swap_amount, fees))
@ -668,6 +681,7 @@ mod tests {
result.give()
},
|| async { Ok(()) },
|_| async { Ok(Amount::from_sat(1000)) },
)
.await
.unwrap();
@ -679,7 +693,8 @@ mod tests {
assert_eq!(
writer.captured(),
r" INFO swap: Received quote price=0.00100000 BTC minimum_amount=0.00000000 BTC maximum_amount=0.01000000 BTC
INFO swap: Waiting for Bitcoin deposit deposit_address=1PdfytjS7C8wwd9Lq5o4x9aXA2YRqaCpH6 max_giveable=0.00000000 BTC minimum_amount=0.00000000 BTC maximum_amount=0.01000000 BTC
INFO swap: Deposit at least 0.00001000 BTC to cover the min quantity with fee!
INFO swap: Waiting for Bitcoin deposit deposit_address=1PdfytjS7C8wwd9Lq5o4x9aXA2YRqaCpH6 min_deposit=0.00001000 BTC max_giveable=0.00000000 BTC minimum_amount=0.00000000 BTC maximum_amount=0.01000000 BTC
INFO swap: Received Bitcoin new_balance=0.00100000 BTC max_giveable=0.00090000 BTC
"
);
@ -703,6 +718,7 @@ mod tests {
result.give()
},
|| async { Ok(()) },
|_| async { Ok(Amount::from_sat(1000)) },
)
.await
.unwrap();
@ -714,14 +730,15 @@ mod tests {
assert_eq!(
writer.captured(),
r" INFO swap: Received quote price=0.00100000 BTC minimum_amount=0.00000000 BTC maximum_amount=0.01000000 BTC
INFO swap: Waiting for Bitcoin deposit deposit_address=1PdfytjS7C8wwd9Lq5o4x9aXA2YRqaCpH6 max_giveable=0.00000000 BTC minimum_amount=0.00000000 BTC maximum_amount=0.01000000 BTC
INFO swap: Deposit at least 0.00001000 BTC to cover the min quantity with fee!
INFO swap: Waiting for Bitcoin deposit deposit_address=1PdfytjS7C8wwd9Lq5o4x9aXA2YRqaCpH6 min_deposit=0.00001000 BTC max_giveable=0.00000000 BTC minimum_amount=0.00000000 BTC maximum_amount=0.01000000 BTC
INFO swap: Received Bitcoin new_balance=0.10010000 BTC max_giveable=0.10000000 BTC
"
);
}
#[tokio::test]
async fn given_initial_balance_below_max_quantity_swaps_max_givable() {
async fn given_initial_balance_below_max_quantity_swaps_max_giveable() {
let writer = capture_logs(LevelFilter::INFO);
let givable = Arc::new(Mutex::new(MaxGiveable::new(vec![
Amount::from_btc(0.0049).unwrap(),
@ -738,6 +755,7 @@ mod tests {
result.give()
},
|| async { Ok(()) },
|_| async { Ok(Amount::from_sat(1000)) },
)
.await
.unwrap();
@ -748,8 +766,7 @@ mod tests {
assert_eq!((amount, fees), (expected_amount, expected_fees));
assert_eq!(
writer.captured(),
r" INFO swap: Received quote price=0.00100000 BTC minimum_amount=0.00000000 BTC maximum_amount=0.01000000 BTC
"
" INFO swap: Received quote price=0.00100000 BTC minimum_amount=0.00000000 BTC maximum_amount=0.01000000 BTC\n"
);
}
@ -771,6 +788,7 @@ mod tests {
result.give()
},
|| async { Ok(()) },
|_| async { Ok(Amount::from_sat(1000)) },
)
.await
.unwrap();
@ -781,8 +799,7 @@ mod tests {
assert_eq!((amount, fees), (expected_amount, expected_fees));
assert_eq!(
writer.captured(),
r" INFO swap: Received quote price=0.00100000 BTC minimum_amount=0.00000000 BTC maximum_amount=0.01000000 BTC
"
" INFO swap: Received quote price=0.00100000 BTC minimum_amount=0.00000000 BTC maximum_amount=0.01000000 BTC\n"
);
}
@ -804,6 +821,7 @@ mod tests {
result.give()
},
|| async { Ok(()) },
|_| async { Ok(Amount::from_sat(1000)) },
)
.await
.unwrap();
@ -815,7 +833,8 @@ mod tests {
assert_eq!(
writer.captured(),
r" INFO swap: Received quote price=0.00100000 BTC minimum_amount=0.01000000 BTC maximum_amount=184467440737.09551615 BTC
INFO swap: Waiting for Bitcoin deposit deposit_address=1PdfytjS7C8wwd9Lq5o4x9aXA2YRqaCpH6 max_giveable=0.00000000 BTC minimum_amount=0.01000000 BTC maximum_amount=184467440737.09551615 BTC
INFO swap: Deposit at least 0.01001000 BTC to cover the min quantity with fee!
INFO swap: Waiting for Bitcoin deposit deposit_address=1PdfytjS7C8wwd9Lq5o4x9aXA2YRqaCpH6 min_deposit=0.01001000 BTC max_giveable=0.00000000 BTC minimum_amount=0.01000000 BTC maximum_amount=184467440737.09551615 BTC
INFO swap: Received Bitcoin new_balance=0.01010000 BTC max_giveable=0.01000000 BTC
"
);
@ -839,6 +858,7 @@ mod tests {
result.give()
},
|| async { Ok(()) },
|_| async { Ok(Amount::from_sat(1000)) },
)
.await
.unwrap();
@ -850,7 +870,8 @@ mod tests {
assert_eq!(
writer.captured(),
r" INFO swap: Received quote price=0.00100000 BTC minimum_amount=0.01000000 BTC maximum_amount=184467440737.09551615 BTC
INFO swap: Waiting for Bitcoin deposit deposit_address=1PdfytjS7C8wwd9Lq5o4x9aXA2YRqaCpH6 max_giveable=0.00010000 BTC minimum_amount=0.01000000 BTC maximum_amount=184467440737.09551615 BTC
INFO swap: Deposit at least 0.00991000 BTC to cover the min quantity with fee!
INFO swap: Waiting for Bitcoin deposit deposit_address=1PdfytjS7C8wwd9Lq5o4x9aXA2YRqaCpH6 min_deposit=0.00991000 BTC max_giveable=0.00010000 BTC minimum_amount=0.01000000 BTC maximum_amount=184467440737.09551615 BTC
INFO swap: Received Bitcoin new_balance=0.01010000 BTC max_giveable=0.01000000 BTC
"
);
@ -879,6 +900,7 @@ mod tests {
result.give()
},
|| async { Ok(()) },
|_| async { Ok(Amount::from_sat(1000)) },
),
)
.await
@ -888,10 +910,12 @@ mod tests {
assert_eq!(
writer.captured(),
r" INFO swap: Received quote price=0.00100000 BTC minimum_amount=0.10000000 BTC maximum_amount=184467440737.09551615 BTC
INFO swap: Waiting for Bitcoin deposit deposit_address=1PdfytjS7C8wwd9Lq5o4x9aXA2YRqaCpH6 max_giveable=0.00000000 BTC minimum_amount=0.10000000 BTC maximum_amount=184467440737.09551615 BTC
INFO swap: Deposit at least 0.10001000 BTC to cover the min quantity with fee!
INFO swap: Waiting for Bitcoin deposit deposit_address=1PdfytjS7C8wwd9Lq5o4x9aXA2YRqaCpH6 min_deposit=0.10001000 BTC max_giveable=0.00000000 BTC minimum_amount=0.10000000 BTC maximum_amount=184467440737.09551615 BTC
INFO swap: Received Bitcoin new_balance=0.01010000 BTC max_giveable=0.01000000 BTC
INFO swap: Deposited amount is less than `min_quantity`
INFO swap: Waiting for Bitcoin deposit deposit_address=1PdfytjS7C8wwd9Lq5o4x9aXA2YRqaCpH6 max_giveable=0.01000000 BTC minimum_amount=0.10000000 BTC maximum_amount=184467440737.09551615 BTC
INFO swap: Deposit at least 0.09001000 BTC to cover the min quantity with fee!
INFO swap: Waiting for Bitcoin deposit deposit_address=1PdfytjS7C8wwd9Lq5o4x9aXA2YRqaCpH6 min_deposit=0.09001000 BTC max_giveable=0.01000000 BTC minimum_amount=0.10000000 BTC maximum_amount=184467440737.09551615 BTC
"
);
}
@ -925,6 +949,7 @@ mod tests {
result.give()
},
|| async { Ok(()) },
|_| async { Ok(Amount::from_sat(1000)) },
),
)
.await
@ -934,14 +959,15 @@ mod tests {
assert_eq!(
writer.captured(),
r" INFO swap: Received quote price=0.00100000 BTC minimum_amount=0.10000000 BTC maximum_amount=184467440737.09551615 BTC
INFO swap: Waiting for Bitcoin deposit deposit_address=1PdfytjS7C8wwd9Lq5o4x9aXA2YRqaCpH6 max_giveable=0.00000000 BTC minimum_amount=0.10000000 BTC maximum_amount=184467440737.09551615 BTC
INFO swap: Deposit at least 0.10001000 BTC to cover the min quantity with fee!
INFO swap: Waiting for Bitcoin deposit deposit_address=1PdfytjS7C8wwd9Lq5o4x9aXA2YRqaCpH6 min_deposit=0.10001000 BTC max_giveable=0.00000000 BTC minimum_amount=0.10000000 BTC maximum_amount=184467440737.09551615 BTC
INFO swap: Received Bitcoin new_balance=0.21000000 BTC max_giveable=0.20000000 BTC
"
);
}
#[tokio::test]
async fn given_bid_quote_max_amount_0_return_errorq() {
async fn given_bid_quote_max_amount_0_return_error() {
let givable = Arc::new(Mutex::new(MaxGiveable::new(vec![
Amount::from_btc(0.0001).unwrap(),
Amount::from_btc(0.01).unwrap(),
@ -957,6 +983,7 @@ mod tests {
result.give()
},
|| async { Ok(()) },
|_| async { Ok(Amount::from_sat(1000)) },
)
.await
.err()

View file

@ -11,6 +11,7 @@ use bitcoin::Script;
use serde::{Deserialize, Serialize};
const SCRIPT_SIZE: usize = 34;
const TX_LOCK_WEIGHT: usize = 485;
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct TxLock {
@ -161,6 +162,10 @@ impl TxLock {
output: vec![tx_out],
}
}
pub fn weight() -> usize {
TX_LOCK_WEIGHT
}
}
impl From<TxLock> for PartiallySignedTransaction {

View file

@ -1,10 +1,11 @@
use anyhow::Result;
use std::option::Option::Some;
use std::path::Path;
use time::format_description::well_known::Rfc3339;
use tracing::subscriber::set_global_default;
use tracing::{Event, Level, Subscriber};
use tracing_subscriber::fmt::format::{DefaultFields, Format, JsonFields};
use tracing_subscriber::fmt::time::ChronoLocal;
use tracing_subscriber::fmt::time::UtcTime;
use tracing_subscriber::layer::{Context, SubscriberExt};
use tracing_subscriber::{fmt, EnvFilter, FmtSubscriber, Layer, Registry};
use uuid::Uuid;
@ -15,7 +16,8 @@ pub fn init(debug: bool, json: bool, dir: impl AsRef<Path>, swap_id: Option<Uuid
let registry = Registry::default().with(level_filter);
let appender = tracing_appender::rolling::never(dir, format!("swap-{}.log", swap_id));
let appender =
tracing_appender::rolling::never(dir.as_ref(), format!("swap-{}.log", swap_id));
let (appender, guard) = tracing_appender::non_blocking(appender);
std::mem::forget(guard);
@ -37,8 +39,6 @@ pub fn init(debug: bool, json: bool, dir: impl AsRef<Path>, swap_id: Option<Uuid
} else {
set_global_default(file_logger.with(info_terminal_printer()))?;
}
Ok(())
} else {
let level = if debug { Level::DEBUG } else { Level::INFO };
let is_terminal = atty::is(atty::Stream::Stderr);
@ -47,7 +47,7 @@ pub fn init(debug: bool, json: bool, dir: impl AsRef<Path>, swap_id: Option<Uuid
.with_env_filter(format!("swap={}", level))
.with_writer(std::io::stderr)
.with_ansi(is_terminal)
.with_timer(ChronoLocal::with_format("%F %T".to_owned()))
.with_timer(UtcTime::rfc_3339())
.with_target(false);
if json {
@ -55,9 +55,10 @@ pub fn init(debug: bool, json: bool, dir: impl AsRef<Path>, swap_id: Option<Uuid
} else {
builder.init();
}
};
Ok(())
}
tracing::info!("Logging initialized to {}", dir.as_ref().display());
Ok(())
}
pub struct StdErrPrinter<L> {
@ -79,25 +80,25 @@ type StdErrJsonLayer<S, T> = tracing_subscriber::fmt::Layer<
fn() -> std::io::Stderr,
>;
fn debug_terminal_printer<S>() -> StdErrPrinter<StdErrLayer<S, ChronoLocal>> {
fn debug_terminal_printer<S>() -> StdErrPrinter<StdErrLayer<S, UtcTime<Rfc3339>>> {
let is_terminal = atty::is(atty::Stream::Stderr);
StdErrPrinter {
inner: fmt::layer()
.with_ansi(is_terminal)
.with_target(false)
.with_timer(ChronoLocal::with_format("%F %T".to_owned()))
.with_timer(UtcTime::rfc_3339())
.with_writer(std::io::stderr),
level: Level::DEBUG,
}
}
fn debug_json_terminal_printer<S>() -> StdErrPrinter<StdErrJsonLayer<S, ChronoLocal>> {
fn debug_json_terminal_printer<S>() -> StdErrPrinter<StdErrJsonLayer<S, UtcTime<Rfc3339>>> {
let is_terminal = atty::is(atty::Stream::Stderr);
StdErrPrinter {
inner: fmt::layer()
.with_ansi(is_terminal)
.with_target(false)
.with_timer(ChronoLocal::with_format("%F %T".to_owned()))
.with_timer(UtcTime::rfc_3339())
.json()
.with_writer(std::io::stderr),
level: Level::DEBUG,

View file

@ -81,8 +81,8 @@ pub struct PublicViewKey(PublicKey);
#[derive(Debug, Copy, Clone, Deserialize, Serialize, PartialEq, PartialOrd)]
pub struct Amount(u64);
// Median tx fees on Monero as found here: https://www.monero.how/monero-transaction-fees, XMR 0.000_015 * 2 (to be on the safe side)
pub const MONERO_FEE: Amount = Amount::from_piconero(30000000);
// Median tx fees on Monero as found here: https://www.monero.how/monero-transaction-fees, XMR 0.000_008 * 2 (to be on the safe side)
pub const MONERO_FEE: Amount = Amount::from_piconero(16_000_000);
impl Amount {
pub const ZERO: Self = Self(0);
@ -95,22 +95,30 @@ impl Amount {
Amount(amount)
}
/// Return Monero Amount as Piconero.
pub fn as_piconero(&self) -> u64 {
self.0
}
pub fn max_bitcoin_for_price(&self, ask_price: bitcoin::Amount) -> bitcoin::Amount {
let piconero_minus_fee = self.as_piconero().saturating_sub(MONERO_FEE.as_piconero());
/// Calculate the maximum amount of Bitcoin that can be bought at a given
/// asking price for this amount of Monero including the median fee.
pub fn max_bitcoin_for_price(&self, ask_price: bitcoin::Amount) -> Option<bitcoin::Amount> {
let pico_minus_fee = self.as_piconero().saturating_sub(MONERO_FEE.as_piconero());
if piconero_minus_fee == 0 {
return bitcoin::Amount::ZERO;
if pico_minus_fee == 0 {
return Some(bitcoin::Amount::ZERO);
}
// There needs to be an offset for difference in zeroes beetween Piconeros and
// Satoshis
let piconero_calc = (piconero_minus_fee * ask_price.as_sat()) / PICONERO_OFFSET;
// safely convert the BTC/XMR rate to sat/pico
let ask_sats = Decimal::from(ask_price.as_sat());
let pico_per_xmr = Decimal::from(PICONERO_OFFSET);
let ask_sats_per_pico = ask_sats / pico_per_xmr;
bitcoin::Amount::from_sat(piconero_calc)
let pico = Decimal::from(pico_minus_fee);
let max_sats = pico.checked_mul(ask_sats_per_pico)?;
let satoshi = max_sats.to_u64()?;
Some(bitcoin::Amount::from_sat(satoshi))
}
pub fn from_monero(amount: f64) -> Result<Self> {
@ -375,27 +383,88 @@ mod tests {
}
#[test]
fn geting_max_bitcoin_to_trade() {
let amount = Amount::parse_monero("10").unwrap();
let bitcoin_price_sats = bitcoin::Amount::from_sat(382_900);
fn max_bitcoin_to_trade() {
// sanity check: if the asking price is 1 BTC / 1 XMR
// and we have μ XMR + fee
// then max BTC we can buy is μ
let ask = bitcoin::Amount::from_btc(1.0).unwrap();
let monero_max_from_bitcoin = amount.max_bitcoin_for_price(bitcoin_price_sats);
let xmr = Amount::parse_monero("1.0").unwrap() + MONERO_FEE;
let btc = xmr.max_bitcoin_for_price(ask).unwrap();
assert_eq!(
bitcoin::Amount::from_sat(3_828_988),
monero_max_from_bitcoin
);
assert_eq!(btc, bitcoin::Amount::from_btc(1.0).unwrap());
let xmr = Amount::parse_monero("0.5").unwrap() + MONERO_FEE;
let btc = xmr.max_bitcoin_for_price(ask).unwrap();
assert_eq!(btc, bitcoin::Amount::from_btc(0.5).unwrap());
let xmr = Amount::parse_monero("2.5").unwrap() + MONERO_FEE;
let btc = xmr.max_bitcoin_for_price(ask).unwrap();
assert_eq!(btc, bitcoin::Amount::from_btc(2.5).unwrap());
let xmr = Amount::parse_monero("420").unwrap() + MONERO_FEE;
let btc = xmr.max_bitcoin_for_price(ask).unwrap();
assert_eq!(btc, bitcoin::Amount::from_btc(420.0).unwrap());
let xmr = Amount::parse_monero("0.00001").unwrap() + MONERO_FEE;
let btc = xmr.max_bitcoin_for_price(ask).unwrap();
assert_eq!(btc, bitcoin::Amount::from_btc(0.00001).unwrap());
// other ask prices
let ask = bitcoin::Amount::from_btc(0.5).unwrap();
let xmr = Amount::parse_monero("2").unwrap() + MONERO_FEE;
let btc = xmr.max_bitcoin_for_price(ask).unwrap();
assert_eq!(btc, bitcoin::Amount::from_btc(1.0).unwrap());
let ask = bitcoin::Amount::from_btc(2.0).unwrap();
let xmr = Amount::parse_monero("1").unwrap() + MONERO_FEE;
let btc = xmr.max_bitcoin_for_price(ask).unwrap();
assert_eq!(btc, bitcoin::Amount::from_btc(2.0).unwrap());
let ask = bitcoin::Amount::from_sat(382_900);
let xmr = Amount::parse_monero("10").unwrap();
let btc = xmr.max_bitcoin_for_price(ask).unwrap();
assert_eq!(btc, bitcoin::Amount::from_sat(3_828_993));
// example from https://github.com/comit-network/xmr-btc-swap/issues/1084
// with rate from kraken at that time
let ask = bitcoin::Amount::from_sat(685_800);
let xmr = Amount::parse_monero("0.826286435921").unwrap();
let btc = xmr.max_bitcoin_for_price(ask).unwrap();
assert_eq!(btc, bitcoin::Amount::from_sat(566_656));
}
#[test]
fn max_bitcoin_to_trade_overflow() {
let xmr = Amount::from_monero(30.0).unwrap();
let ask = bitcoin::Amount::from_sat(728_688);
let btc = xmr.max_bitcoin_for_price(ask).unwrap();
assert_eq!(bitcoin::Amount::from_sat(21_860_628), btc);
let xmr = Amount::from_piconero(u64::MAX);
let ask = bitcoin::Amount::from_sat(u64::MAX);
let btc = xmr.max_bitcoin_for_price(ask);
assert!(btc.is_none());
}
#[test]
fn geting_max_bitcoin_to_trade_with_balance_smaller_than_locking_fee() {
let monero = "0.00001";
let amount = Amount::parse_monero(monero).unwrap();
let bitcoin_price_sats = bitcoin::Amount::from_sat(382_900);
let ask = bitcoin::Amount::from_sat(382_900);
let xmr = Amount::parse_monero("0.00001").unwrap();
let btc = xmr.max_bitcoin_for_price(ask).unwrap();
let monero_max_from_bitcoin = amount.max_bitcoin_for_price(bitcoin_price_sats);
assert_eq!(bitcoin::Amount::ZERO, monero_max_from_bitcoin);
assert_eq!(bitcoin::Amount::ZERO, btc);
}
use rand::rngs::OsRng;

View file

@ -314,8 +314,13 @@ async fn wait_for_confirmations<C: monero_rpc::wallet::MoneroWalletRpc<reqwest::
.await
{
Ok(proof) => proof,
Err(jsonrpc::Error::JsonRpc(jsonrpc::JsonRpcError { code: -1, .. })) => {
tracing::warn!(%txid, "`monero-wallet-rpc` failed to fetch transaction, may need to be restarted");
Err(jsonrpc::Error::JsonRpc(jsonrpc::JsonRpcError {
code: -1,
message,
data,
})) => {
tracing::debug!(message, ?data);
tracing::warn!(%txid, message, "`monero-wallet-rpc` failed to fetch transaction, may need to be restarted");
continue;
}
// TODO: Implement this using a generic proxy for each function call once https://github.com/thomaseizinger/rust-jsonrpc-client/issues/47 is fixed.

View file

@ -41,7 +41,7 @@ impl MakeCapturingWriter {
}
}
impl MakeWriter for MakeCapturingWriter {
impl<'a> MakeWriter<'a> for MakeCapturingWriter {
type Writer = CapturingWriter;
fn make_writer(&self) -> Self::Writer {