mirror of
https://github.com/comit-network/xmr-btc-swap.git
synced 2024-12-24 23:19:34 -05:00
Merge #236
236: Some wallet cleanup + watch for deposit r=thomaseizinger a=thomaseizinger Co-authored-by: Thomas Eizinger <thomas@eizinger.io>
This commit is contained in:
commit
9a32f7d405
@ -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::{read_config, Config},
|
config::{read_config, Config},
|
||||||
@ -35,7 +36,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;
|
||||||
|
|
||||||
@ -82,7 +83,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,
|
||||||
@ -94,22 +94,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,
|
||||||
|
@ -22,9 +22,7 @@ pub use wallet::Wallet;
|
|||||||
use crate::execution_params::ExecutionParams;
|
use crate::execution_params::ExecutionParams;
|
||||||
use ::bitcoin::{
|
use ::bitcoin::{
|
||||||
hashes::{hex::ToHex, Hash},
|
hashes::{hex::ToHex, Hash},
|
||||||
secp256k1,
|
secp256k1, SigHash,
|
||||||
util::psbt::PartiallySignedTransaction,
|
|
||||||
SigHash,
|
|
||||||
};
|
};
|
||||||
use anyhow::{anyhow, bail, Result};
|
use anyhow::{anyhow, bail, Result};
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
@ -203,15 +201,6 @@ pub fn build_shared_output_descriptor(A: Point, B: Point) -> Descriptor<bitcoin:
|
|||||||
Descriptor::Wsh(Wsh::new(miniscript).expect("a valid descriptor"))
|
Descriptor::Wsh(Wsh::new(miniscript).expect("a valid descriptor"))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
pub trait BuildTxLockPsbt {
|
|
||||||
async fn build_tx_lock_psbt(
|
|
||||||
&self,
|
|
||||||
output_address: Address,
|
|
||||||
output_amount: Amount,
|
|
||||||
) -> Result<PartiallySignedTransaction>;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
pub trait SignTxLock {
|
pub trait SignTxLock {
|
||||||
async fn sign_tx_lock(&self, tx_lock: TxLock) -> Result<Transaction>;
|
async fn sign_tx_lock(&self, tx_lock: TxLock) -> Result<Transaction>;
|
||||||
@ -251,11 +240,6 @@ pub trait GetRawTransaction {
|
|||||||
async fn get_raw_transaction(&self, txid: Txid) -> Result<Transaction>;
|
async fn get_raw_transaction(&self, txid: Txid) -> Result<Transaction>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
pub trait GetNetwork {
|
|
||||||
async fn get_network(&self) -> Network;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn recover(S: PublicKey, sig: Signature, encsig: EncryptedSignature) -> Result<SecretKey> {
|
pub fn recover(S: PublicKey, sig: Signature, encsig: EncryptedSignature) -> Result<SecretKey> {
|
||||||
let adaptor = Adaptor::<HashTranscript<Sha256>, Deterministic<Sha256>>::default();
|
let adaptor = Adaptor::<HashTranscript<Sha256>, Deterministic<Sha256>>::default();
|
||||||
|
|
||||||
|
@ -58,6 +58,7 @@ pub struct TxCancel {
|
|||||||
inner: Transaction,
|
inner: Transaction,
|
||||||
digest: SigHash,
|
digest: SigHash,
|
||||||
pub(in crate::bitcoin) output_descriptor: Descriptor<::bitcoin::PublicKey>,
|
pub(in crate::bitcoin) output_descriptor: Descriptor<::bitcoin::PublicKey>,
|
||||||
|
lock_output_descriptor: Descriptor<::bitcoin::PublicKey>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TxCancel {
|
impl TxCancel {
|
||||||
@ -99,6 +100,7 @@ impl TxCancel {
|
|||||||
inner: transaction,
|
inner: transaction,
|
||||||
digest,
|
digest,
|
||||||
output_descriptor: cancel_output_descriptor,
|
output_descriptor: cancel_output_descriptor,
|
||||||
|
lock_output_descriptor: tx_lock.output_descriptor.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,7 +122,6 @@ impl TxCancel {
|
|||||||
|
|
||||||
pub fn add_signatures(
|
pub fn add_signatures(
|
||||||
self,
|
self,
|
||||||
tx_lock: &TxLock,
|
|
||||||
(A, sig_a): (PublicKey, Signature),
|
(A, sig_a): (PublicKey, Signature),
|
||||||
(B, sig_b): (PublicKey, Signature),
|
(B, sig_b): (PublicKey, Signature),
|
||||||
) -> Result<Transaction> {
|
) -> Result<Transaction> {
|
||||||
@ -144,8 +145,7 @@ impl TxCancel {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let mut tx_cancel = self.inner;
|
let mut tx_cancel = self.inner;
|
||||||
tx_lock
|
self.lock_output_descriptor
|
||||||
.output_descriptor
|
|
||||||
.satisfy(&mut tx_cancel.input[0], satisfier)?;
|
.satisfy(&mut tx_cancel.input[0], satisfier)?;
|
||||||
|
|
||||||
Ok(tx_cancel)
|
Ok(tx_cancel)
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
use crate::bitcoin::{
|
use crate::bitcoin::{
|
||||||
build_shared_output_descriptor, Address, Amount, BuildTxLockPsbt, GetNetwork, PublicKey,
|
build_shared_output_descriptor, Address, Amount, PublicKey, Transaction, Wallet, TX_FEE,
|
||||||
Transaction, TX_FEE,
|
|
||||||
};
|
};
|
||||||
use ::bitcoin::{util::psbt::PartiallySignedTransaction, OutPoint, TxIn, TxOut, Txid};
|
use ::bitcoin::{util::psbt::PartiallySignedTransaction, OutPoint, TxIn, TxOut, Txid};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
@ -14,16 +13,13 @@ pub struct TxLock {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl TxLock {
|
impl TxLock {
|
||||||
pub async fn new<W>(wallet: &W, amount: Amount, A: PublicKey, B: PublicKey) -> Result<Self>
|
pub async fn new(wallet: &Wallet, amount: Amount, A: PublicKey, B: PublicKey) -> Result<Self> {
|
||||||
where
|
|
||||||
W: BuildTxLockPsbt + GetNetwork,
|
|
||||||
{
|
|
||||||
let lock_output_descriptor = build_shared_output_descriptor(A.0, B.0);
|
let lock_output_descriptor = build_shared_output_descriptor(A.0, B.0);
|
||||||
let address = lock_output_descriptor
|
let address = lock_output_descriptor
|
||||||
.address(wallet.get_network().await)
|
.address(wallet.get_network().await)
|
||||||
.expect("can derive address from descriptor");
|
.expect("can derive address from descriptor");
|
||||||
|
|
||||||
let psbt = wallet.build_tx_lock_psbt(address, amount).await?;
|
let psbt = wallet.send_to_address(address, amount).await?;
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
inner: psbt,
|
inner: psbt,
|
||||||
|
@ -2,13 +2,14 @@ use crate::bitcoin::{Address, PublicKey, PunishTimelock, Transaction, TxCancel};
|
|||||||
use ::bitcoin::{util::bip143::SigHashCache, SigHash, SigHashType};
|
use ::bitcoin::{util::bip143::SigHashCache, SigHash, SigHashType};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use ecdsa_fun::Signature;
|
use ecdsa_fun::Signature;
|
||||||
use miniscript::DescriptorTrait;
|
use miniscript::{Descriptor, DescriptorTrait};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct TxPunish {
|
pub struct TxPunish {
|
||||||
inner: Transaction,
|
inner: Transaction,
|
||||||
digest: SigHash,
|
digest: SigHash,
|
||||||
|
cancel_output_descriptor: Descriptor<::bitcoin::PublicKey>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TxPunish {
|
impl TxPunish {
|
||||||
@ -29,6 +30,7 @@ impl TxPunish {
|
|||||||
Self {
|
Self {
|
||||||
inner: tx_punish,
|
inner: tx_punish,
|
||||||
digest,
|
digest,
|
||||||
|
cancel_output_descriptor: tx_cancel.output_descriptor.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,7 +40,6 @@ impl TxPunish {
|
|||||||
|
|
||||||
pub fn add_signatures(
|
pub fn add_signatures(
|
||||||
self,
|
self,
|
||||||
tx_cancel: &TxCancel,
|
|
||||||
(A, sig_a): (PublicKey, Signature),
|
(A, sig_a): (PublicKey, Signature),
|
||||||
(B, sig_b): (PublicKey, Signature),
|
(B, sig_b): (PublicKey, Signature),
|
||||||
) -> Result<Transaction> {
|
) -> Result<Transaction> {
|
||||||
@ -62,8 +63,7 @@ impl TxPunish {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let mut tx_punish = self.inner;
|
let mut tx_punish = self.inner;
|
||||||
tx_cancel
|
self.cancel_output_descriptor
|
||||||
.output_descriptor
|
|
||||||
.satisfy(&mut tx_punish.input[0], satisfier)?;
|
.satisfy(&mut tx_punish.input[0], satisfier)?;
|
||||||
|
|
||||||
Ok(tx_punish)
|
Ok(tx_punish)
|
||||||
|
@ -5,13 +5,14 @@ use crate::bitcoin::{
|
|||||||
use ::bitcoin::{util::bip143::SigHashCache, SigHash, SigHashType, Txid};
|
use ::bitcoin::{util::bip143::SigHashCache, SigHash, SigHashType, Txid};
|
||||||
use anyhow::{bail, Context, Result};
|
use anyhow::{bail, Context, Result};
|
||||||
use ecdsa_fun::Signature;
|
use ecdsa_fun::Signature;
|
||||||
use miniscript::DescriptorTrait;
|
use miniscript::{Descriptor, DescriptorTrait};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct TxRedeem {
|
pub struct TxRedeem {
|
||||||
inner: Transaction,
|
inner: Transaction,
|
||||||
digest: SigHash,
|
digest: SigHash,
|
||||||
|
lock_output_descriptor: Descriptor<::bitcoin::PublicKey>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TxRedeem {
|
impl TxRedeem {
|
||||||
@ -30,6 +31,7 @@ impl TxRedeem {
|
|||||||
Self {
|
Self {
|
||||||
inner: tx_redeem,
|
inner: tx_redeem,
|
||||||
digest,
|
digest,
|
||||||
|
lock_output_descriptor: tx_lock.output_descriptor.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,7 +45,6 @@ impl TxRedeem {
|
|||||||
|
|
||||||
pub fn add_signatures(
|
pub fn add_signatures(
|
||||||
self,
|
self,
|
||||||
tx_lock: &TxLock,
|
|
||||||
(A, sig_a): (PublicKey, Signature),
|
(A, sig_a): (PublicKey, Signature),
|
||||||
(B, sig_b): (PublicKey, Signature),
|
(B, sig_b): (PublicKey, Signature),
|
||||||
) -> Result<Transaction> {
|
) -> Result<Transaction> {
|
||||||
@ -67,8 +68,7 @@ impl TxRedeem {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let mut tx_redeem = self.inner;
|
let mut tx_redeem = self.inner;
|
||||||
tx_lock
|
self.lock_output_descriptor
|
||||||
.output_descriptor
|
|
||||||
.satisfy(&mut tx_redeem.input[0], satisfier)?;
|
.satisfy(&mut tx_redeem.input[0], satisfier)?;
|
||||||
|
|
||||||
Ok(tx_redeem)
|
Ok(tx_redeem)
|
||||||
|
@ -5,13 +5,14 @@ use crate::bitcoin::{
|
|||||||
use ::bitcoin::{util::bip143::SigHashCache, SigHash, SigHashType, Txid};
|
use ::bitcoin::{util::bip143::SigHashCache, SigHash, SigHashType, Txid};
|
||||||
use anyhow::{bail, Context, Result};
|
use anyhow::{bail, Context, Result};
|
||||||
use ecdsa_fun::Signature;
|
use ecdsa_fun::Signature;
|
||||||
use miniscript::DescriptorTrait;
|
use miniscript::{Descriptor, DescriptorTrait};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct TxRefund {
|
pub struct TxRefund {
|
||||||
inner: Transaction,
|
inner: Transaction,
|
||||||
digest: SigHash,
|
digest: SigHash,
|
||||||
|
cancel_output_descriptor: Descriptor<::bitcoin::PublicKey>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TxRefund {
|
impl TxRefund {
|
||||||
@ -28,6 +29,7 @@ impl TxRefund {
|
|||||||
Self {
|
Self {
|
||||||
inner: tx_punish,
|
inner: tx_punish,
|
||||||
digest,
|
digest,
|
||||||
|
cancel_output_descriptor: tx_cancel.output_descriptor.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,7 +43,6 @@ impl TxRefund {
|
|||||||
|
|
||||||
pub fn add_signatures(
|
pub fn add_signatures(
|
||||||
self,
|
self,
|
||||||
tx_cancel: &TxCancel,
|
|
||||||
(A, sig_a): (PublicKey, Signature),
|
(A, sig_a): (PublicKey, Signature),
|
||||||
(B, sig_b): (PublicKey, Signature),
|
(B, sig_b): (PublicKey, Signature),
|
||||||
) -> Result<Transaction> {
|
) -> Result<Transaction> {
|
||||||
@ -65,8 +66,7 @@ impl TxRefund {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let mut tx_refund = self.inner;
|
let mut tx_refund = self.inner;
|
||||||
tx_cancel
|
self.cancel_output_descriptor
|
||||||
.output_descriptor
|
|
||||||
.satisfy(&mut tx_refund.input[0], satisfier)?;
|
.satisfy(&mut tx_refund.input[0], satisfier)?;
|
||||||
|
|
||||||
Ok(tx_refund)
|
Ok(tx_refund)
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
bitcoin::{
|
bitcoin::{
|
||||||
timelocks::BlockHeight, Address, Amount, BroadcastSignedTransaction, BuildTxLockPsbt,
|
timelocks::BlockHeight, Address, Amount, BroadcastSignedTransaction, GetBlockHeight,
|
||||||
GetBlockHeight, GetNetwork, GetRawTransaction, SignTxLock, Transaction,
|
GetRawTransaction, SignTxLock, Transaction, TransactionBlockHeight, TxLock,
|
||||||
TransactionBlockHeight, TxLock, WaitForTransactionFinality, WatchForRawTransaction,
|
WaitForTransactionFinality, WatchForRawTransaction,
|
||||||
},
|
},
|
||||||
execution_params::ExecutionParams,
|
execution_params::ExecutionParams,
|
||||||
};
|
};
|
||||||
@ -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};
|
||||||
@ -38,10 +39,9 @@ enum Error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct Wallet {
|
pub struct Wallet {
|
||||||
pub inner: Arc<Mutex<bdk::Wallet<ElectrumBlockchain, bdk::sled::Tree>>>,
|
inner: Arc<Mutex<bdk::Wallet<ElectrumBlockchain, bdk::sled::Tree>>>,
|
||||||
pub network: bitcoin::Network,
|
http_url: Url,
|
||||||
pub http_url: Url,
|
rpc_url: Url,
|
||||||
pub rpc_url: Url,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Wallet {
|
impl Wallet {
|
||||||
@ -70,7 +70,6 @@ impl Wallet {
|
|||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
inner: Arc::new(Mutex::new(bdk_wallet)),
|
inner: Arc::new(Mutex::new(bdk_wallet)),
|
||||||
network,
|
|
||||||
http_url: electrum_http_url,
|
http_url: electrum_http_url,
|
||||||
rpc_url: electrum_rpc_url,
|
rpc_url: electrum_rpc_url,
|
||||||
})
|
})
|
||||||
@ -82,11 +81,9 @@ impl Wallet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn new_address(&self) -> Result<Address> {
|
pub async fn new_address(&self) -> Result<Address> {
|
||||||
self.inner
|
let address = self.inner.lock().await.get_new_address()?;
|
||||||
.lock()
|
|
||||||
.await
|
Ok(address)
|
||||||
.get_new_address()
|
|
||||||
.map_err(Into::into)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_tx(&self, txid: Txid) -> Result<Option<Transaction>> {
|
pub async fn get_tx(&self, txid: Txid) -> Result<Option<Transaction>> {
|
||||||
@ -111,29 +108,60 @@ impl Wallet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn sync_wallet(&self) -> Result<()> {
|
pub async fn sync_wallet(&self) -> Result<()> {
|
||||||
tracing::debug!("syncing wallet");
|
|
||||||
self.inner.lock().await.sync(noop_progress(), None)?;
|
self.inner.lock().await.sync(noop_progress(), None)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait]
|
pub async fn send_to_address(
|
||||||
impl BuildTxLockPsbt for Wallet {
|
|
||||||
async fn build_tx_lock_psbt(
|
|
||||||
&self,
|
&self,
|
||||||
output_address: Address,
|
address: Address,
|
||||||
output_amount: Amount,
|
amount: Amount,
|
||||||
) -> Result<PartiallySignedTransaction> {
|
) -> Result<PartiallySignedTransaction> {
|
||||||
tracing::debug!("building tx lock");
|
|
||||||
let wallet = self.inner.lock().await;
|
let wallet = self.inner.lock().await;
|
||||||
|
|
||||||
let mut tx_builder = wallet.build_tx();
|
let mut tx_builder = wallet.build_tx();
|
||||||
tx_builder.add_recipient(output_address.script_pubkey(), output_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: get actual fee
|
tx_builder.fee_rate(self.select_feerate());
|
||||||
let (psbt, _details) = tx_builder.finish()?;
|
let (psbt, _details) = tx_builder.finish()?;
|
||||||
tracing::debug!("tx lock built");
|
|
||||||
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 {
|
||||||
|
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]
|
||||||
@ -288,13 +316,6 @@ impl WaitForTransactionFinality for Wallet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
impl GetNetwork for Wallet {
|
|
||||||
async fn get_network(&self) -> bitcoin::Network {
|
|
||||||
self.inner.lock().await.network()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn tx_status_url(txid: Txid, base_url: &Url) -> Result<Url> {
|
fn tx_status_url(txid: Txid, base_url: &Url) -> Result<Url> {
|
||||||
let url = base_url.join(&format!("tx/{}/status", txid))?;
|
let url = base_url.join(&format!("tx/{}/status", txid))?;
|
||||||
Ok(url)
|
Ok(url)
|
||||||
|
@ -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;
|
||||||
@ -32,9 +30,6 @@ pub enum Command {
|
|||||||
default_value = DEFAULT_ALICE_MULTIADDR
|
default_value = DEFAULT_ALICE_MULTIADDR
|
||||||
)]
|
)]
|
||||||
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),
|
||||||
@ -102,8 +97,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)
|
|
||||||
}
|
|
||||||
|
@ -205,7 +205,7 @@ impl From<Alice> for AliceState {
|
|||||||
let tx_refund = TxRefund::new(&tx_cancel, &state3.refund_address);
|
let tx_refund = TxRefund::new(&tx_cancel, &state3.refund_address);
|
||||||
AliceState::BtcPunishable {
|
AliceState::BtcPunishable {
|
||||||
monero_wallet_restore_blockheight,
|
monero_wallet_restore_blockheight,
|
||||||
tx_refund,
|
tx_refund: Box::new(tx_refund),
|
||||||
state3: Box::new(state3),
|
state3: Box::new(state3),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,7 +53,7 @@ pub enum AliceState {
|
|||||||
},
|
},
|
||||||
BtcPunishable {
|
BtcPunishable {
|
||||||
monero_wallet_restore_blockheight: BlockHeight,
|
monero_wallet_restore_blockheight: BlockHeight,
|
||||||
tx_refund: TxRefund,
|
tx_refund: Box<TxRefund>,
|
||||||
state3: Box<State3>,
|
state3: Box<State3>,
|
||||||
},
|
},
|
||||||
XmrRefunded,
|
XmrRefunded,
|
||||||
|
@ -124,7 +124,7 @@ pub fn build_bitcoin_redeem_transaction(
|
|||||||
let sig_b = adaptor.decrypt_signature(&s_a, encrypted_signature);
|
let sig_b = adaptor.decrypt_signature(&s_a, encrypted_signature);
|
||||||
|
|
||||||
let tx = tx_redeem
|
let tx = tx_redeem
|
||||||
.add_signatures(&tx_lock, (a.public(), sig_a), (B, sig_b))
|
.add_signatures((a.public(), sig_a), (B, sig_b))
|
||||||
.context("sig_{a,b} are invalid for tx_redeem")?;
|
.context("sig_{a,b} are invalid for tx_redeem")?;
|
||||||
|
|
||||||
Ok(tx)
|
Ok(tx)
|
||||||
@ -179,7 +179,7 @@ where
|
|||||||
|
|
||||||
let tx_cancel = tx_cancel
|
let tx_cancel = tx_cancel
|
||||||
.clone()
|
.clone()
|
||||||
.add_signatures(&tx_lock, (a.public(), sig_a), (B, sig_b))
|
.add_signatures((a.public(), sig_a), (B, sig_b))
|
||||||
.expect("sig_{a,b} to be valid signatures for tx_cancel");
|
.expect("sig_{a,b} to be valid signatures for tx_cancel");
|
||||||
|
|
||||||
// TODO(Franck): Error handling is delicate, why can't we broadcast?
|
// TODO(Franck): Error handling is delicate, why can't we broadcast?
|
||||||
@ -224,7 +224,7 @@ where
|
|||||||
|
|
||||||
pub fn extract_monero_private_key(
|
pub fn extract_monero_private_key(
|
||||||
published_refund_tx: bitcoin::Transaction,
|
published_refund_tx: bitcoin::Transaction,
|
||||||
tx_refund: TxRefund,
|
tx_refund: &TxRefund,
|
||||||
s_a: monero::Scalar,
|
s_a: monero::Scalar,
|
||||||
a: bitcoin::SecretKey,
|
a: bitcoin::SecretKey,
|
||||||
S_b_bitcoin: bitcoin::PublicKey,
|
S_b_bitcoin: bitcoin::PublicKey,
|
||||||
@ -261,7 +261,7 @@ pub fn build_bitcoin_punish_transaction(
|
|||||||
let sig_b = tx_punish_sig_bob;
|
let sig_b = tx_punish_sig_bob;
|
||||||
|
|
||||||
let signed_tx_punish = tx_punish
|
let signed_tx_punish = tx_punish
|
||||||
.add_signatures(&tx_cancel, (a.public(), sig_a), (B, sig_b))
|
.add_signatures((a.public(), sig_a), (B, sig_b))
|
||||||
.expect("sig_{a,b} to be valid signatures for tx_cancel");
|
.expect("sig_{a,b} to be valid signatures for tx_cancel");
|
||||||
|
|
||||||
Ok(signed_tx_punish)
|
Ok(signed_tx_punish)
|
||||||
|
@ -343,7 +343,7 @@ async fn run_until_internal(
|
|||||||
match published_refund_tx {
|
match published_refund_tx {
|
||||||
None => {
|
None => {
|
||||||
let state = AliceState::BtcPunishable {
|
let state = AliceState::BtcPunishable {
|
||||||
tx_refund,
|
tx_refund: Box::new(tx_refund),
|
||||||
state3,
|
state3,
|
||||||
monero_wallet_restore_blockheight,
|
monero_wallet_restore_blockheight,
|
||||||
};
|
};
|
||||||
@ -366,7 +366,7 @@ async fn run_until_internal(
|
|||||||
Some(published_refund_tx) => {
|
Some(published_refund_tx) => {
|
||||||
let spend_key = extract_monero_private_key(
|
let spend_key = extract_monero_private_key(
|
||||||
published_refund_tx,
|
published_refund_tx,
|
||||||
tx_refund,
|
&tx_refund,
|
||||||
state3.s_a,
|
state3.s_a,
|
||||||
state3.a.clone(),
|
state3.a.clone(),
|
||||||
state3.S_b_bitcoin,
|
state3.S_b_bitcoin,
|
||||||
@ -445,7 +445,7 @@ async fn run_until_internal(
|
|||||||
Either::Left((published_refund_tx, _)) => {
|
Either::Left((published_refund_tx, _)) => {
|
||||||
let spend_key = extract_monero_private_key(
|
let spend_key = extract_monero_private_key(
|
||||||
published_refund_tx?,
|
published_refund_tx?,
|
||||||
tx_refund,
|
&tx_refund,
|
||||||
state3.s_a,
|
state3.s_a,
|
||||||
state3.a.clone(),
|
state3.a.clone(),
|
||||||
state3.S_b_bitcoin,
|
state3.S_b_bitcoin,
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
bitcoin::{
|
bitcoin::{
|
||||||
self, current_epoch, wait_for_cancel_timelock_to_expire, BroadcastSignedTransaction,
|
self, current_epoch, wait_for_cancel_timelock_to_expire, BroadcastSignedTransaction,
|
||||||
BuildTxLockPsbt, CancelTimelock, ExpiredTimelocks, GetBlockHeight, GetNetwork,
|
CancelTimelock, ExpiredTimelocks, GetBlockHeight, GetRawTransaction, PunishTimelock,
|
||||||
GetRawTransaction, PunishTimelock, Transaction, TransactionBlockHeight, TxCancel, Txid,
|
Transaction, TransactionBlockHeight, TxCancel, Txid, WatchForRawTransaction,
|
||||||
WatchForRawTransaction,
|
|
||||||
},
|
},
|
||||||
execution_params::ExecutionParams,
|
execution_params::ExecutionParams,
|
||||||
monero,
|
monero,
|
||||||
@ -140,10 +139,7 @@ impl State0 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn receive<W>(self, wallet: &W, msg: Message1) -> Result<State1>
|
pub async fn receive(self, wallet: &bitcoin::Wallet, msg: Message1) -> Result<State1> {
|
||||||
where
|
|
||||||
W: BuildTxLockPsbt + GetNetwork,
|
|
||||||
{
|
|
||||||
let valid = CROSS_CURVE_PROOF_SYSTEM.verify(
|
let valid = CROSS_CURVE_PROOF_SYSTEM.verify(
|
||||||
&msg.dleq_proof_s_a,
|
&msg.dleq_proof_s_a,
|
||||||
(
|
(
|
||||||
@ -459,7 +455,7 @@ impl State4 {
|
|||||||
|
|
||||||
let tx_cancel = tx_cancel
|
let tx_cancel = tx_cancel
|
||||||
.clone()
|
.clone()
|
||||||
.add_signatures(&self.tx_lock, (self.A, sig_a), (self.b.public(), sig_b))
|
.add_signatures((self.A, sig_a), (self.b.public(), sig_b))
|
||||||
.expect(
|
.expect(
|
||||||
"sig_{a,b} to be valid signatures for
|
"sig_{a,b} to be valid signatures for
|
||||||
tx_cancel",
|
tx_cancel",
|
||||||
@ -482,7 +478,7 @@ impl State4 {
|
|||||||
|
|
||||||
let tx_cancel = tx_cancel
|
let tx_cancel = tx_cancel
|
||||||
.clone()
|
.clone()
|
||||||
.add_signatures(&self.tx_lock, (self.A, sig_a), (self.b.public(), sig_b))
|
.add_signatures((self.A, sig_a), (self.b.public(), sig_b))
|
||||||
.expect(
|
.expect(
|
||||||
"sig_{a,b} to be valid signatures for
|
"sig_{a,b} to be valid signatures for
|
||||||
tx_cancel",
|
tx_cancel",
|
||||||
@ -562,11 +558,8 @@ impl State4 {
|
|||||||
let sig_a =
|
let sig_a =
|
||||||
adaptor.decrypt_signature(&self.s_b.to_secpfun_scalar(), self.tx_refund_encsig.clone());
|
adaptor.decrypt_signature(&self.s_b.to_secpfun_scalar(), self.tx_refund_encsig.clone());
|
||||||
|
|
||||||
let signed_tx_refund = tx_refund.add_signatures(
|
let signed_tx_refund =
|
||||||
&tx_cancel.clone(),
|
tx_refund.add_signatures((self.A, sig_a), (self.b.public(), sig_b))?;
|
||||||
(self.A, sig_a),
|
|
||||||
(self.b.public(), sig_b),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
let txid = bitcoin_wallet
|
let txid = bitcoin_wallet
|
||||||
.broadcast_signed_transaction(signed_tx_refund)
|
.broadcast_signed_transaction(signed_tx_refund)
|
||||||
|
@ -16,7 +16,7 @@ pub fn init_tracing(level: LevelFilter) -> Result<()> {
|
|||||||
let subscriber = FmtSubscriber::builder()
|
let subscriber = FmtSubscriber::builder()
|
||||||
.with_env_filter(format!(
|
.with_env_filter(format!(
|
||||||
"swap={},monero_harness={},bitcoin_harness={},http=warn,warp=warn",
|
"swap={},monero_harness={},bitcoin_harness={},http=warn,warp=warn",
|
||||||
level, level, level,
|
level, level, level
|
||||||
))
|
))
|
||||||
.with_writer(std::io::stderr)
|
.with_writer(std::io::stderr)
|
||||||
.with_ansi(is_terminal)
|
.with_ansi(is_terminal)
|
||||||
|
Loading…
Reference in New Issue
Block a user