mirror of
https://github.com/comit-network/xmr-btc-swap.git
synced 2024-10-01 05:45:40 +00:00
Merge #391
391: asb Bitcoin withdraw and balance commands r=da-kami a=da-kami Fixes #368 Note: Balance prints both balances - which assumes that the Monero wallet RPC is running. I think that is fine for now. Co-authored-by: Daniel Karzel <daniel@comit.network>
This commit is contained in:
commit
4b9513b051
5
Cargo.lock
generated
5
Cargo.lock
generated
@ -279,9 +279,8 @@ checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bdk"
|
name = "bdk"
|
||||||
version = "0.5.0"
|
version = "0.5.2-dev"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "git+https://github.com/bitcoindevkit/bdk.git?rev=e5ecc7f#e5ecc7f5410aea9d7a108a46d01c7a2fa0822bb7"
|
||||||
checksum = "4260e70501c2f9d6fb2915cf2be2f5b8ba57743e527834de5de6e371827f1e19"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"bdk-macros",
|
"bdk-macros",
|
||||||
|
@ -15,7 +15,7 @@ async-trait = "0.1"
|
|||||||
atty = "0.2"
|
atty = "0.2"
|
||||||
backoff = { version = "0.3", features = ["tokio"] }
|
backoff = { version = "0.3", features = ["tokio"] }
|
||||||
base64 = "0.13"
|
base64 = "0.13"
|
||||||
bdk = { version = "0.5" }
|
bdk = { git = "https://github.com/bitcoindevkit/bdk.git", rev = "e5ecc7f" }
|
||||||
big-bytes = "1"
|
big-bytes = "1"
|
||||||
bitcoin = { version = "0.26", features = ["rand", "use-serde"] }
|
bitcoin = { version = "0.26", features = ["rand", "use-serde"] }
|
||||||
config = { version = "0.11", default-features = false, features = ["toml"] }
|
config = { version = "0.11", default-features = false, features = ["toml"] }
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use crate::bitcoin::Amount;
|
use crate::bitcoin::Amount;
|
||||||
use bitcoin::util::amount::ParseAmountError;
|
use bitcoin::util::amount::ParseAmountError;
|
||||||
use bitcoin::Denomination;
|
use bitcoin::{Address, Denomination};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
#[derive(structopt::StructOpt, Debug)]
|
#[derive(structopt::StructOpt, Debug)]
|
||||||
@ -29,6 +29,16 @@ pub enum Command {
|
|||||||
max_buy: Amount,
|
max_buy: Amount,
|
||||||
},
|
},
|
||||||
History,
|
History,
|
||||||
|
WithdrawBtc {
|
||||||
|
#[structopt(
|
||||||
|
long = "amount",
|
||||||
|
help = "Optionally specify the amount of Bitcoin to be withdrawn. If not specified the wallet will be drained."
|
||||||
|
)]
|
||||||
|
amount: Option<Amount>,
|
||||||
|
#[structopt(long = "address", help = "The address to receive the Bitcoin.")]
|
||||||
|
address: Address,
|
||||||
|
},
|
||||||
|
Balance,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_btc(s: &str) -> Result<Amount, ParseAmountError> {
|
fn parse_btc(s: &str) -> Result<Amount, ParseAmountError> {
|
||||||
|
@ -13,11 +13,8 @@
|
|||||||
#![allow(non_snake_case)]
|
#![allow(non_snake_case)]
|
||||||
|
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use bdk::descriptor::Segwitv0;
|
|
||||||
use bdk::keys::DerivableKey;
|
|
||||||
use libp2p::Swarm;
|
use libp2p::Swarm;
|
||||||
use prettytable::{row, Table};
|
use prettytable::{row, Table};
|
||||||
use std::path::Path;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use structopt::StructOpt;
|
use structopt::StructOpt;
|
||||||
use swap::asb::command::{Arguments, Command};
|
use swap::asb::command::{Arguments, Command};
|
||||||
@ -71,22 +68,29 @@ async fn main() -> Result<()> {
|
|||||||
let db = Database::open(config.data.dir.join(db_path).as_path())
|
let db = Database::open(config.data.dir.join(db_path).as_path())
|
||||||
.context("Could not open database")?;
|
.context("Could not open database")?;
|
||||||
|
|
||||||
let wallet_data_dir = config.data.dir.join("wallet");
|
let seed =
|
||||||
|
Seed::from_file_or_generate(&config.data.dir).expect("Could not retrieve/initialize seed");
|
||||||
|
|
||||||
|
let env_config = env::Testnet::get_config();
|
||||||
|
|
||||||
match opt.cmd {
|
match opt.cmd {
|
||||||
Command::Start { max_buy } => {
|
Command::Start { max_buy } => {
|
||||||
let seed = Seed::from_file_or_generate(&config.data.dir)
|
let bitcoin_wallet = init_bitcoin_wallet(&config, &seed, env_config).await?;
|
||||||
.expect("Could not retrieve/initialize seed");
|
let monero_wallet = init_monero_wallet(&config, env_config).await?;
|
||||||
|
|
||||||
let env_config = env::Testnet::get_config();
|
let bitcoin_balance = bitcoin_wallet.balance().await?;
|
||||||
|
info!("Bitcoin balance: {}", bitcoin_balance);
|
||||||
|
|
||||||
let (bitcoin_wallet, monero_wallet) = init_wallets(
|
let monero_balance = monero_wallet.get_balance().await?;
|
||||||
config.clone(),
|
if monero_balance == Amount::ZERO {
|
||||||
&wallet_data_dir,
|
let deposit_address = monero_wallet.get_main_address();
|
||||||
seed.derive_extended_private_key(env_config.bitcoin_network)?,
|
warn!(
|
||||||
env_config,
|
"The Monero balance is 0, make sure to deposit funds at: {}",
|
||||||
)
|
deposit_address
|
||||||
.await?;
|
)
|
||||||
|
} else {
|
||||||
|
info!("Monero balance: {}", monero_balance);
|
||||||
|
}
|
||||||
|
|
||||||
let kraken_rate_updates = kraken::connect()?;
|
let kraken_rate_updates = kraken::connect()?;
|
||||||
|
|
||||||
@ -137,50 +141,68 @@ async fn main() -> Result<()> {
|
|||||||
// Print the table to stdout
|
// Print the table to stdout
|
||||||
table.printstd();
|
table.printstd();
|
||||||
}
|
}
|
||||||
|
Command::WithdrawBtc { amount, address } => {
|
||||||
|
let bitcoin_wallet = init_bitcoin_wallet(&config, &seed, env_config).await?;
|
||||||
|
|
||||||
|
let amount = match amount {
|
||||||
|
Some(amount) => amount,
|
||||||
|
None => {
|
||||||
|
bitcoin_wallet
|
||||||
|
.max_giveable(address.script_pubkey().len())
|
||||||
|
.await?
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let psbt = bitcoin_wallet.send_to_address(address, amount).await?;
|
||||||
|
let signed_tx = bitcoin_wallet.sign_and_finalize(psbt).await?;
|
||||||
|
|
||||||
|
bitcoin_wallet.broadcast(signed_tx, "withdraw").await?;
|
||||||
|
}
|
||||||
|
Command::Balance => {
|
||||||
|
let bitcoin_wallet = init_bitcoin_wallet(&config, &seed, env_config).await?;
|
||||||
|
let monero_wallet = init_monero_wallet(&config, env_config).await?;
|
||||||
|
|
||||||
|
let bitcoin_balance = bitcoin_wallet.balance().await?;
|
||||||
|
let monero_balance = monero_wallet.get_balance().await?;
|
||||||
|
|
||||||
|
tracing::info!("Current balance: {}, {}", bitcoin_balance, monero_balance);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn init_wallets(
|
async fn init_bitcoin_wallet(
|
||||||
config: Config,
|
config: &Config,
|
||||||
bitcoin_wallet_data_dir: &Path,
|
seed: &Seed,
|
||||||
key: impl DerivableKey<Segwitv0> + Clone,
|
env_config: swap::env::Config,
|
||||||
env_config: env::Config,
|
) -> Result<bitcoin::Wallet> {
|
||||||
) -> Result<(bitcoin::Wallet, monero::Wallet)> {
|
let wallet_dir = config.data.dir.join("wallet");
|
||||||
let bitcoin_wallet = bitcoin::Wallet::new(
|
|
||||||
config.bitcoin.electrum_rpc_url,
|
let wallet = bitcoin::Wallet::new(
|
||||||
bitcoin_wallet_data_dir,
|
config.bitcoin.electrum_rpc_url.clone(),
|
||||||
key,
|
&wallet_dir,
|
||||||
|
seed.derive_extended_private_key(env_config.bitcoin_network)?,
|
||||||
env_config,
|
env_config,
|
||||||
)
|
)
|
||||||
.await?;
|
.await
|
||||||
|
.context("Failed to initialize Bitcoin wallet")?;
|
||||||
|
|
||||||
bitcoin_wallet.sync().await?;
|
wallet.sync().await?;
|
||||||
|
|
||||||
let bitcoin_balance = bitcoin_wallet.balance().await?;
|
Ok(wallet)
|
||||||
info!(
|
}
|
||||||
"Connection to Bitcoin wallet succeeded, balance: {}",
|
|
||||||
bitcoin_balance
|
|
||||||
);
|
|
||||||
|
|
||||||
let monero_wallet = monero::Wallet::open_or_create(
|
async fn init_monero_wallet(
|
||||||
|
config: &Config,
|
||||||
|
env_config: swap::env::Config,
|
||||||
|
) -> Result<monero::Wallet> {
|
||||||
|
let wallet = monero::Wallet::open_or_create(
|
||||||
config.monero.wallet_rpc_url.clone(),
|
config.monero.wallet_rpc_url.clone(),
|
||||||
DEFAULT_WALLET_NAME.to_string(),
|
DEFAULT_WALLET_NAME.to_string(),
|
||||||
env_config,
|
env_config,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let balance = monero_wallet.get_balance().await?;
|
Ok(wallet)
|
||||||
if balance == Amount::ZERO {
|
|
||||||
let deposit_address = monero_wallet.get_main_address();
|
|
||||||
warn!(
|
|
||||||
"The Monero balance is 0, make sure to deposit funds at: {}",
|
|
||||||
deposit_address
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
info!("Monero balance: {}", balance);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok((bitcoin_wallet, monero_wallet))
|
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ use bdk::database::BatchDatabase;
|
|||||||
use bdk::descriptor::Segwitv0;
|
use bdk::descriptor::Segwitv0;
|
||||||
use bdk::electrum_client::{ElectrumApi, GetHistoryRes};
|
use bdk::electrum_client::{ElectrumApi, GetHistoryRes};
|
||||||
use bdk::keys::DerivableKey;
|
use bdk::keys::DerivableKey;
|
||||||
|
use bdk::wallet::AddressIndex;
|
||||||
use bdk::{FeeRate, KeychainKind};
|
use bdk::{FeeRate, KeychainKind};
|
||||||
use bitcoin::{Network, Script};
|
use bitcoin::{Network, Script};
|
||||||
use reqwest::Url;
|
use reqwest::Url;
|
||||||
@ -255,7 +256,7 @@ where
|
|||||||
.wallet
|
.wallet
|
||||||
.lock()
|
.lock()
|
||||||
.await
|
.await
|
||||||
.get_new_address()
|
.get_address(AddressIndex::New)
|
||||||
.context("Failed to get new Bitcoin address")?;
|
.context("Failed to get new Bitcoin address")?;
|
||||||
|
|
||||||
Ok(address)
|
Ok(address)
|
||||||
|
Loading…
Reference in New Issue
Block a user