mirror of
https://github.com/comit-network/xmr-btc-swap.git
synced 2024-10-01 01:45:40 -04:00
Remove --send-btc
in favor of swapping the available balance
If the current balance is 0, we wait until the user deposits money to the given address. After that, we simply swap the full balance. Not only does this simplify the interface by removing a parameter, but it also integrates the `deposit` command into the `buy-xmr` command. Syncing a wallet that is backed by electrum includes transactions that are part of the mempool when computing the balance. As such, waiting for a deposit is a very quick action because it allows us to build our lock transaction on top of the yet to be confirmed deposit transactions. This patch introduces another function to the `bitcoin::Wallet` that relies on the currently statically encoded fee rate. To make sure future developers don't forget to adjust both, we extract a function that "selects" a fee rate and return the constant from there. Fixes #196.
This commit is contained in:
parent
32cb0eb896
commit
f472070546
@ -15,10 +15,11 @@
|
|||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use prettytable::{row, Table};
|
use prettytable::{row, Table};
|
||||||
use reqwest::Url;
|
use reqwest::Url;
|
||||||
use std::{path::Path, sync::Arc};
|
use std::{path::Path, sync::Arc, time::Duration};
|
||||||
use structopt::StructOpt;
|
use structopt::StructOpt;
|
||||||
use swap::{
|
use swap::{
|
||||||
bitcoin,
|
bitcoin,
|
||||||
|
bitcoin::Amount,
|
||||||
cli::{
|
cli::{
|
||||||
command::{Arguments, Cancel, Command, Refund, Resume},
|
command::{Arguments, Cancel, Command, Refund, Resume},
|
||||||
config::{
|
config::{
|
||||||
@ -39,7 +40,7 @@ use swap::{
|
|||||||
seed::Seed,
|
seed::Seed,
|
||||||
trace::init_tracing,
|
trace::init_tracing,
|
||||||
};
|
};
|
||||||
use tracing::{error, info, warn};
|
use tracing::{debug, error, info, warn};
|
||||||
use tracing_subscriber::filter::LevelFilter;
|
use tracing_subscriber::filter::LevelFilter;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
@ -95,7 +96,6 @@ async fn main() -> Result<()> {
|
|||||||
Command::BuyXmr {
|
Command::BuyXmr {
|
||||||
alice_peer_id,
|
alice_peer_id,
|
||||||
alice_addr,
|
alice_addr,
|
||||||
send_bitcoin,
|
|
||||||
} => {
|
} => {
|
||||||
let (bitcoin_wallet, monero_wallet) = init_wallets(
|
let (bitcoin_wallet, monero_wallet) = init_wallets(
|
||||||
config,
|
config,
|
||||||
@ -107,22 +107,30 @@ async fn main() -> Result<()> {
|
|||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let swap_id = Uuid::new_v4();
|
// TODO: Also wait for more funds if balance < dust
|
||||||
|
if bitcoin_wallet.balance().await? == Amount::ZERO {
|
||||||
|
debug!(
|
||||||
|
"Waiting for BTC at address {}",
|
||||||
|
bitcoin_wallet.new_address().await?
|
||||||
|
);
|
||||||
|
|
||||||
info!(
|
while bitcoin_wallet.balance().await? == Amount::ZERO {
|
||||||
"Swap buy XMR with {} started with ID {}",
|
bitcoin_wallet.sync_wallet().await?;
|
||||||
send_bitcoin, swap_id
|
|
||||||
);
|
|
||||||
|
|
||||||
info!(
|
tokio::time::sleep(Duration::from_secs(1)).await;
|
||||||
"BTC deposit address: {}",
|
}
|
||||||
bitcoin_wallet.new_address().await?
|
|
||||||
);
|
debug!("Received {}", bitcoin_wallet.balance().await?);
|
||||||
|
}
|
||||||
|
|
||||||
|
let send_bitcoin = bitcoin_wallet.max_giveable().await?;
|
||||||
|
|
||||||
|
info!("Swapping {} ...", send_bitcoin);
|
||||||
|
|
||||||
let bob_factory = Builder::new(
|
let bob_factory = Builder::new(
|
||||||
seed,
|
seed,
|
||||||
db,
|
db,
|
||||||
swap_id,
|
Uuid::new_v4(),
|
||||||
Arc::new(bitcoin_wallet),
|
Arc::new(bitcoin_wallet),
|
||||||
Arc::new(monero_wallet),
|
Arc::new(monero_wallet),
|
||||||
alice_addr,
|
alice_addr,
|
||||||
|
@ -16,6 +16,7 @@ use bdk::{
|
|||||||
miniscript::bitcoin::PrivateKey,
|
miniscript::bitcoin::PrivateKey,
|
||||||
FeeRate,
|
FeeRate,
|
||||||
};
|
};
|
||||||
|
use bitcoin::Script;
|
||||||
use reqwest::{Method, Url};
|
use reqwest::{Method, Url};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::{path::Path, sync::Arc, time::Duration};
|
use std::{path::Path, sync::Arc, time::Duration};
|
||||||
@ -120,15 +121,47 @@ impl Wallet {
|
|||||||
|
|
||||||
let mut tx_builder = wallet.build_tx();
|
let mut tx_builder = wallet.build_tx();
|
||||||
tx_builder.add_recipient(address.script_pubkey(), amount.as_sat());
|
tx_builder.add_recipient(address.script_pubkey(), amount.as_sat());
|
||||||
tx_builder.fee_rate(FeeRate::from_sat_per_vb(5.0)); // todo: make dynamic
|
tx_builder.fee_rate(self.select_feerate());
|
||||||
let (psbt, _details) = tx_builder.finish()?;
|
let (psbt, _details) = tx_builder.finish()?;
|
||||||
|
|
||||||
Ok(psbt)
|
Ok(psbt)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Calculates the maximum "giveable" amount of this wallet.
|
||||||
|
///
|
||||||
|
/// We define this as the maximum amount we can pay to a single output,
|
||||||
|
/// already accounting for the fees we need to spend to get the
|
||||||
|
/// transaction confirmed.
|
||||||
|
pub async fn max_giveable(&self) -> Result<Amount> {
|
||||||
|
let wallet = self.inner.lock().await;
|
||||||
|
|
||||||
|
let mut tx_builder = wallet.build_tx();
|
||||||
|
|
||||||
|
// create a dummy script to make the txbuilder pass
|
||||||
|
// we don't intend to send this transaction, we just want to know the max amount
|
||||||
|
// we can spend
|
||||||
|
let dummy_script = Script::default();
|
||||||
|
tx_builder.set_single_recipient(dummy_script);
|
||||||
|
|
||||||
|
tx_builder.drain_wallet();
|
||||||
|
tx_builder.fee_rate(self.select_feerate());
|
||||||
|
let (_, details) = tx_builder.finish()?;
|
||||||
|
|
||||||
|
let max_giveable = details.sent - details.fees;
|
||||||
|
|
||||||
|
Ok(Amount::from_sat(max_giveable))
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn get_network(&self) -> bitcoin::Network {
|
pub async fn get_network(&self) -> bitcoin::Network {
|
||||||
self.inner.lock().await.network()
|
self.inner.lock().await.network()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Selects an appropriate [`FeeRate`] to be used for getting transactions
|
||||||
|
/// confirmed within a reasonable amount of time.
|
||||||
|
fn select_feerate(&self) -> FeeRate {
|
||||||
|
// TODO: This should obviously not be a const :)
|
||||||
|
FeeRate::from_sat_per_vb(5.0)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
use crate::bitcoin;
|
|
||||||
use anyhow::Result;
|
|
||||||
use libp2p::{core::Multiaddr, PeerId};
|
use libp2p::{core::Multiaddr, PeerId};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
@ -26,9 +24,6 @@ pub enum Command {
|
|||||||
|
|
||||||
#[structopt(long = "connect-addr")]
|
#[structopt(long = "connect-addr")]
|
||||||
alice_addr: Multiaddr,
|
alice_addr: Multiaddr,
|
||||||
|
|
||||||
#[structopt(long = "send-btc", help = "Bitcoin amount as floating point nr without denomination (e.g. 1.25)", parse(try_from_str = parse_btc))]
|
|
||||||
send_bitcoin: bitcoin::Amount,
|
|
||||||
},
|
},
|
||||||
History,
|
History,
|
||||||
Resume(Resume),
|
Resume(Resume),
|
||||||
@ -85,8 +80,3 @@ pub enum Refund {
|
|||||||
force: bool,
|
force: bool,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_btc(str: &str) -> Result<bitcoin::Amount> {
|
|
||||||
let amount = bitcoin::Amount::from_str_in(str, ::bitcoin::Denomination::Bitcoin)?;
|
|
||||||
Ok(amount)
|
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user