mirror of
https://github.com/comit-network/xmr-btc-swap.git
synced 2025-04-21 16:29:20 -04:00
Explicitly set the network in the wallet when creating the wallet.rs
Implement trait on the wallet to enforce Network can be retrieved, for the test wallets always just return Regtest, for the wallets created in main currently always set to Bitcoin (mainnet).
This commit is contained in:
parent
aa0a2e326c
commit
2e1d10c457
@ -269,7 +269,7 @@ mod test {
|
||||
//
|
||||
// let psbt = {
|
||||
// let partial_signed_bitcoin_transaction =
|
||||
//
|
||||
//
|
||||
// PartiallySignedTransaction::from_unsigned_tx(transaction).unwrap();
|
||||
// let hex_vec =
|
||||
// bitcoin::consensus::serialize(&partial_signed_bitcoin_transaction);
|
||||
|
@ -16,7 +16,10 @@ use anyhow::Result;
|
||||
use libp2p::Multiaddr;
|
||||
use prettytable::{row, Table};
|
||||
use rand::rngs::OsRng;
|
||||
use std::sync::Arc;
|
||||
use std::{
|
||||
sync::Arc,
|
||||
time::{SystemTime, UNIX_EPOCH},
|
||||
};
|
||||
use structopt::StructOpt;
|
||||
use swap::{
|
||||
alice,
|
||||
@ -45,10 +48,18 @@ extern crate prettytable;
|
||||
async fn main() -> Result<()> {
|
||||
init_tracing(LevelFilter::Trace).expect("initialize tracing");
|
||||
|
||||
let opt = Options::from_args();
|
||||
let now = SystemTime::now();
|
||||
let timestamp = now
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.expect("time to move forward");
|
||||
|
||||
let opt = Options::from_args();
|
||||
// This currently creates the directory if it's not there in the first place
|
||||
let db = Database::open(std::path::Path::new("./.swap-db/")).unwrap();
|
||||
let db = Database::open(std::path::Path::new(&format!(
|
||||
"./.swap-db/{}/",
|
||||
timestamp.as_millis()
|
||||
)))
|
||||
.unwrap();
|
||||
let rng = &mut OsRng;
|
||||
|
||||
match opt {
|
||||
@ -97,9 +108,14 @@ async fn main() -> Result<()> {
|
||||
xmr: send_monero,
|
||||
};
|
||||
|
||||
let bitcoin_wallet = bitcoin::Wallet::new(bitcoin_wallet_name.as_str(), bitcoind_url)
|
||||
.await
|
||||
.expect("failed to create bitcoin wallet");
|
||||
// TODO: network should be configurable through CLI defaulting to mainnet
|
||||
let bitcoin_wallet = bitcoin::Wallet::new(
|
||||
bitcoin_wallet_name.as_str(),
|
||||
bitcoind_url,
|
||||
::bitcoin::Network::Bitcoin,
|
||||
)
|
||||
.await
|
||||
.expect("failed to create bitcoin wallet");
|
||||
|
||||
let bitcoin_balance = bitcoin_wallet.balance().await?;
|
||||
info!(
|
||||
@ -164,9 +180,13 @@ async fn main() -> Result<()> {
|
||||
xmr: receive_monero,
|
||||
};
|
||||
|
||||
let bitcoin_wallet = bitcoin::Wallet::new(bitcoin_wallet_name.as_str(), bitcoind_url)
|
||||
.await
|
||||
.expect("failed to create bitcoin wallet");
|
||||
let bitcoin_wallet = bitcoin::Wallet::new(
|
||||
bitcoin_wallet_name.as_str(),
|
||||
bitcoind_url,
|
||||
::bitcoin::Network::Bitcoin,
|
||||
)
|
||||
.await
|
||||
.expect("failed to create bitcoin wallet");
|
||||
let bitcoin_balance = bitcoin_wallet.balance().await?;
|
||||
info!(
|
||||
"Connection to Bitcoin wallet succeeded, balance: {}",
|
||||
@ -231,9 +251,13 @@ async fn main() -> Result<()> {
|
||||
bitcoin_wallet_name,
|
||||
} => {
|
||||
let state = db.get_state(swap_id)?;
|
||||
let bitcoin_wallet = bitcoin::Wallet::new(bitcoin_wallet_name.as_ref(), bitcoind_url)
|
||||
.await
|
||||
.expect("failed to create bitcoin wallet");
|
||||
let bitcoin_wallet = bitcoin::Wallet::new(
|
||||
bitcoin_wallet_name.as_ref(),
|
||||
bitcoind_url,
|
||||
::bitcoin::Network::Bitcoin,
|
||||
)
|
||||
.await
|
||||
.expect("failed to create bitcoin wallet");
|
||||
let monero_wallet = monero::Wallet::new(monerod_url);
|
||||
|
||||
recover(bitcoin_wallet, monero_wallet, state).await?;
|
||||
@ -271,7 +295,10 @@ pub fn init_tracing(level: log::LevelFilter) -> anyhow::Result<()> {
|
||||
|
||||
let is_terminal = atty::is(atty::Stream::Stderr);
|
||||
let subscriber = FmtSubscriber::builder()
|
||||
.with_env_filter(format!("swap={},http=info,warp=info", level,))
|
||||
.with_env_filter(format!(
|
||||
"swap={},xmr-btc={},http=info,warp=info",
|
||||
level, level
|
||||
))
|
||||
.with_writer(std::io::stderr)
|
||||
.with_ansi(is_terminal)
|
||||
.finish();
|
||||
|
@ -16,22 +16,28 @@ pub use xmr_btc::bitcoin::*;
|
||||
pub const TX_LOCK_MINE_TIMEOUT: u64 = 3600;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Wallet(pub bitcoin_harness::Wallet);
|
||||
pub struct Wallet {
|
||||
pub inner: bitcoin_harness::Wallet,
|
||||
pub network: bitcoin::Network,
|
||||
}
|
||||
|
||||
impl Wallet {
|
||||
pub async fn new(name: &str, url: Url) -> Result<Self> {
|
||||
pub async fn new(name: &str, url: Url, network: bitcoin::Network) -> Result<Self> {
|
||||
let wallet = bitcoin_harness::Wallet::new(name, url).await?;
|
||||
|
||||
Ok(Self(wallet))
|
||||
Ok(Self {
|
||||
inner: wallet,
|
||||
network,
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn balance(&self) -> Result<Amount> {
|
||||
let balance = self.0.balance().await?;
|
||||
let balance = self.inner.balance().await?;
|
||||
Ok(balance)
|
||||
}
|
||||
|
||||
pub async fn new_address(&self) -> Result<Address> {
|
||||
self.0.new_address().await.map_err(Into::into)
|
||||
self.inner.new_address().await.map_err(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
@ -42,7 +48,7 @@ impl BuildTxLockPsbt for Wallet {
|
||||
output_address: Address,
|
||||
output_amount: Amount,
|
||||
) -> Result<PartiallySignedTransaction> {
|
||||
let psbt = self.0.fund_psbt(output_address, output_amount).await?;
|
||||
let psbt = self.inner.fund_psbt(output_address, output_amount).await?;
|
||||
let as_hex = base64::decode(psbt)?;
|
||||
|
||||
let psbt = bitcoin::consensus::deserialize(&as_hex)?;
|
||||
@ -59,7 +65,10 @@ impl SignTxLock for Wallet {
|
||||
let psbt = bitcoin::consensus::serialize(&psbt);
|
||||
let as_base64 = base64::encode(psbt);
|
||||
|
||||
let psbt = self.0.wallet_process_psbt(PsbtBase64(as_base64)).await?;
|
||||
let psbt = self
|
||||
.inner
|
||||
.wallet_process_psbt(PsbtBase64(as_base64))
|
||||
.await?;
|
||||
let PsbtBase64(signed_psbt) = PsbtBase64::from(psbt);
|
||||
|
||||
let as_hex = base64::decode(signed_psbt)?;
|
||||
@ -74,7 +83,9 @@ impl SignTxLock for Wallet {
|
||||
#[async_trait]
|
||||
impl BroadcastSignedTransaction for Wallet {
|
||||
async fn broadcast_signed_transaction(&self, transaction: Transaction) -> Result<Txid> {
|
||||
Ok(self.0.send_raw_transaction(transaction).await?)
|
||||
let txid = self.inner.send_raw_transaction(transaction).await?;
|
||||
tracing::debug!("Bitcoin tx broadcasted! TXID = {}", txid);
|
||||
Ok(txid)
|
||||
}
|
||||
}
|
||||
|
||||
@ -83,7 +94,7 @@ impl BroadcastSignedTransaction for Wallet {
|
||||
#[async_trait]
|
||||
impl WatchForRawTransaction for Wallet {
|
||||
async fn watch_for_raw_transaction(&self, txid: Txid) -> Transaction {
|
||||
(|| async { Ok(self.0.get_raw_transaction(txid).await?) })
|
||||
(|| async { Ok(self.inner.get_raw_transaction(txid).await?) })
|
||||
.retry(ConstantBackoff::new(Duration::from_secs(1)))
|
||||
.await
|
||||
.expect("transient errors to be retried")
|
||||
@ -94,14 +105,14 @@ impl WatchForRawTransaction for Wallet {
|
||||
impl GetRawTransaction for Wallet {
|
||||
// todo: potentially replace with option
|
||||
async fn get_raw_transaction(&self, txid: Txid) -> Result<Transaction> {
|
||||
Ok(self.0.get_raw_transaction(txid).await?)
|
||||
Ok(self.inner.get_raw_transaction(txid).await?)
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl BlockHeight for Wallet {
|
||||
async fn block_height(&self) -> u32 {
|
||||
(|| async { Ok(self.0.block_height().await?) })
|
||||
(|| async { Ok(self.inner.block_height().await?) })
|
||||
.retry(ConstantBackoff::new(Duration::from_secs(1)))
|
||||
.await
|
||||
.expect("transient errors to be retried")
|
||||
@ -119,7 +130,7 @@ impl TransactionBlockHeight for Wallet {
|
||||
|
||||
(|| async {
|
||||
let block_height = self
|
||||
.0
|
||||
.inner
|
||||
.transaction_block_height(txid)
|
||||
.await
|
||||
.map_err(|_| backoff::Error::Transient(Error::Io))?;
|
||||
@ -141,3 +152,9 @@ impl WaitForTransactionFinality for Wallet {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl Network for Wallet {
|
||||
fn get_network(&self) -> bitcoin::Network {
|
||||
self.network
|
||||
}
|
||||
}
|
||||
|
@ -14,8 +14,9 @@ pub mod state;
|
||||
pub mod storage;
|
||||
pub mod tor;
|
||||
|
||||
// REFUND_TIMELOCK determines the interval between lock-time until TX_cancel is allowed,
|
||||
// PUNISH_TIMELOCK determines the interval between TX_cancel and TX_punish being allowed.
|
||||
// REFUND_TIMELOCK determines the interval between lock-time until TX_cancel is
|
||||
// allowed, PUNISH_TIMELOCK determines the interval between TX_cancel and
|
||||
// TX_punish being allowed.
|
||||
//
|
||||
// *[1]
|
||||
// |----REFUND_TIMELOCK--|
|
||||
|
@ -60,7 +60,7 @@ pub async fn alice_recover(
|
||||
|
||||
info!("Checking if the Bitcoin cancel transaction has been published");
|
||||
if bitcoin_wallet
|
||||
.0
|
||||
.inner
|
||||
.get_raw_transaction(tx_cancel.txid())
|
||||
.await
|
||||
.is_err()
|
||||
@ -169,7 +169,7 @@ pub async fn alice_recover(
|
||||
.transaction_block_height(state.tx_lock.txid())
|
||||
.await;
|
||||
|
||||
let block_height = bitcoin_wallet.0.block_height().await?;
|
||||
let block_height = bitcoin_wallet.inner.block_height().await?;
|
||||
let refund_absolute_expiry = tx_lock_height + state.refund_timelock;
|
||||
|
||||
info!("Checking refund timelock");
|
||||
@ -192,7 +192,7 @@ pub async fn alice_recover(
|
||||
|
||||
info!("Checking if the Bitcoin cancel transaction has been published");
|
||||
if bitcoin_wallet
|
||||
.0
|
||||
.inner
|
||||
.get_raw_transaction(tx_cancel.txid())
|
||||
.await
|
||||
.is_err()
|
||||
@ -300,7 +300,11 @@ pub async fn alice_recover(
|
||||
|
||||
// TODO: Protect against transient errors so that we can correctly decide if the
|
||||
// bitcoin has been refunded
|
||||
match bitcoin_wallet.0.get_raw_transaction(tx_refund.txid()).await {
|
||||
match bitcoin_wallet
|
||||
.inner
|
||||
.get_raw_transaction(tx_refund.txid())
|
||||
.await
|
||||
{
|
||||
Ok(tx_refund_published) => {
|
||||
info!("Bitcoin already refunded");
|
||||
|
||||
@ -387,7 +391,7 @@ pub async fn bob_recover(
|
||||
|
||||
info!("Checking if the Bitcoin cancel transaction has been published");
|
||||
if bitcoin_wallet
|
||||
.0
|
||||
.inner
|
||||
.get_raw_transaction(tx_cancel.txid())
|
||||
.await
|
||||
.is_err()
|
||||
@ -451,7 +455,7 @@ pub async fn bob_recover(
|
||||
|
||||
let tx_redeem = bitcoin::TxRedeem::new(&state.tx_lock, &state.redeem_address);
|
||||
let tx_redeem_published = bitcoin_wallet
|
||||
.0
|
||||
.inner
|
||||
.get_raw_transaction(tx_redeem.txid())
|
||||
.await?;
|
||||
|
||||
|
@ -42,17 +42,25 @@ async fn swap() {
|
||||
let xmr_bob = 0;
|
||||
|
||||
let alice_btc_wallet = Arc::new(
|
||||
swap::bitcoin::Wallet::new("alice", bitcoind.node_url.clone())
|
||||
.await
|
||||
.unwrap(),
|
||||
swap::bitcoin::Wallet::new(
|
||||
"alice",
|
||||
bitcoind.node_url.clone(),
|
||||
::bitcoin::Network::Regtest,
|
||||
)
|
||||
.await
|
||||
.unwrap(),
|
||||
);
|
||||
let bob_btc_wallet = Arc::new(
|
||||
swap::bitcoin::Wallet::new("bob", bitcoind.node_url.clone())
|
||||
.await
|
||||
.unwrap(),
|
||||
swap::bitcoin::Wallet::new(
|
||||
"bob",
|
||||
bitcoind.node_url.clone(),
|
||||
::bitcoin::Network::Regtest,
|
||||
)
|
||||
.await
|
||||
.unwrap(),
|
||||
);
|
||||
bitcoind
|
||||
.mint(bob_btc_wallet.0.new_address().await.unwrap(), btc_bob)
|
||||
.mint(bob_btc_wallet.inner.new_address().await.unwrap(), btc_bob)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@ -152,17 +160,25 @@ async fn happy_path_recursive_executor() {
|
||||
let xmr_bob = 0;
|
||||
|
||||
let alice_btc_wallet = Arc::new(
|
||||
swap::bitcoin::Wallet::new("alice", bitcoind.node_url.clone())
|
||||
.await
|
||||
.unwrap(),
|
||||
swap::bitcoin::Wallet::new(
|
||||
"alice",
|
||||
bitcoind.node_url.clone(),
|
||||
::bitcoin::Network::Regtest,
|
||||
)
|
||||
.await
|
||||
.unwrap(),
|
||||
);
|
||||
let bob_btc_wallet = Arc::new(
|
||||
swap::bitcoin::Wallet::new("bob", bitcoind.node_url.clone())
|
||||
.await
|
||||
.unwrap(),
|
||||
swap::bitcoin::Wallet::new(
|
||||
"bob",
|
||||
bitcoind.node_url.clone(),
|
||||
::bitcoin::Network::Regtest,
|
||||
)
|
||||
.await
|
||||
.unwrap(),
|
||||
);
|
||||
bitcoind
|
||||
.mint(bob_btc_wallet.0.new_address().await.unwrap(), btc_bob)
|
||||
.mint(bob_btc_wallet.inner.new_address().await.unwrap(), btc_bob)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
|
@ -14,13 +14,13 @@ pub use bitcoin::{util::psbt::PartiallySignedTransaction, *};
|
||||
pub use ecdsa_fun::{adaptor::EncryptedSignature, fun::Scalar, Signature};
|
||||
pub use transactions::{TxCancel, TxLock, TxPunish, TxRedeem, TxRefund};
|
||||
|
||||
|
||||
// TODO: Configurable tx-fee (note: the parties have to agree on it prior to swapping)
|
||||
// Current reasoning:
|
||||
// tx with largest weight (as determined by get_weight() upon broadcast in e2e test) = 609
|
||||
// assuming segwit and 60 sat/vB:
|
||||
// TODO: Configurable tx-fee (note: the parties have to agree on it prior to
|
||||
// swapping) Current reasoning:
|
||||
// tx with largest weight (as determined by get_weight() upon broadcast in e2e
|
||||
// test) = 609 assuming segwit and 60 sat/vB:
|
||||
// (609 / 4) * 60 (sat/vB) = 9135 sats
|
||||
// Recommended: Overpay a bit to ensure we don't have to wait too long for test runs.
|
||||
// Recommended: Overpay a bit to ensure we don't have to wait too long for test
|
||||
// runs.
|
||||
pub const TX_FEE: u64 = 15_000;
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
|
||||
@ -218,6 +218,11 @@ pub trait GetRawTransaction {
|
||||
async fn get_raw_transaction(&self, txid: Txid) -> Result<Transaction>;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait Network {
|
||||
fn get_network(&self) -> bitcoin::Network;
|
||||
}
|
||||
|
||||
pub fn recover(S: PublicKey, sig: Signature, encsig: EncryptedSignature) -> Result<SecretKey> {
|
||||
let adaptor = Adaptor::<Sha256, Deterministic<Sha256>>::default();
|
||||
|
||||
|
@ -1,10 +1,11 @@
|
||||
use crate::bitcoin::{
|
||||
build_shared_output_descriptor, verify_sig, BuildTxLockPsbt, OutPoint, PublicKey, Txid, TX_FEE,
|
||||
build_shared_output_descriptor, verify_sig, BuildTxLockPsbt, Network, OutPoint, PublicKey,
|
||||
Txid, TX_FEE,
|
||||
};
|
||||
use anyhow::{bail, Context, Result};
|
||||
use bitcoin::{
|
||||
util::{bip143::SighashComponents, psbt::PartiallySignedTransaction},
|
||||
Address, Amount, Network, SigHash, Transaction, TxIn, TxOut,
|
||||
Address, Amount, SigHash, Transaction, TxIn, TxOut,
|
||||
};
|
||||
use ecdsa_fun::Signature;
|
||||
use miniscript::Descriptor;
|
||||
@ -20,11 +21,11 @@ pub struct TxLock {
|
||||
impl TxLock {
|
||||
pub async fn new<W>(wallet: &W, amount: Amount, A: PublicKey, B: PublicKey) -> Result<Self>
|
||||
where
|
||||
W: BuildTxLockPsbt,
|
||||
W: BuildTxLockPsbt + Network,
|
||||
{
|
||||
let lock_output_descriptor = build_shared_output_descriptor(A.0, B.0);
|
||||
let address = lock_output_descriptor
|
||||
.address(Network::Regtest)
|
||||
.address(wallet.get_network())
|
||||
.expect("can derive address from descriptor");
|
||||
|
||||
// We construct a psbt for convenience
|
||||
|
@ -33,7 +33,7 @@ use tracing::error;
|
||||
|
||||
pub mod message;
|
||||
use crate::{
|
||||
bitcoin::{BlockHeight, GetRawTransaction, TransactionBlockHeight},
|
||||
bitcoin::{BlockHeight, GetRawTransaction, Network, TransactionBlockHeight},
|
||||
monero::{CreateWalletForOutput, WatchForTransfer},
|
||||
};
|
||||
use ::bitcoin::{Transaction, Txid};
|
||||
@ -268,7 +268,7 @@ where
|
||||
// send to one receive in the correct order.
|
||||
pub async fn next_state<
|
||||
R: RngCore + CryptoRng,
|
||||
B: WatchForRawTransaction + SignTxLock + BuildTxLockPsbt + BroadcastSignedTransaction,
|
||||
B: WatchForRawTransaction + SignTxLock + BuildTxLockPsbt + BroadcastSignedTransaction + Network,
|
||||
M: CreateWalletForOutput + WatchForTransfer,
|
||||
T: SendMessage<Message> + ReceiveMessage<alice::Message>,
|
||||
>(
|
||||
@ -402,7 +402,7 @@ impl State0 {
|
||||
|
||||
pub async fn receive<W>(self, wallet: &W, msg: alice::Message0) -> anyhow::Result<State1>
|
||||
where
|
||||
W: BuildTxLockPsbt,
|
||||
W: BuildTxLockPsbt + Network,
|
||||
{
|
||||
msg.dleq_proof_s_a.verify(
|
||||
msg.S_a_bitcoin.clone().into(),
|
||||
|
@ -7,8 +7,8 @@ use reqwest::Url;
|
||||
use std::time::Duration;
|
||||
use tokio::time;
|
||||
use xmr_btc::bitcoin::{
|
||||
BlockHeight, BroadcastSignedTransaction, BuildTxLockPsbt, SignTxLock, TransactionBlockHeight,
|
||||
TxLock, WatchForRawTransaction,
|
||||
BlockHeight, BroadcastSignedTransaction, BuildTxLockPsbt, Network, SignTxLock,
|
||||
TransactionBlockHeight, TxLock, WatchForRawTransaction,
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -152,3 +152,9 @@ impl TransactionBlockHeight for Wallet {
|
||||
.expect("transient errors to be retried")
|
||||
}
|
||||
}
|
||||
|
||||
impl Network for Wallet {
|
||||
fn get_network(&self) -> bitcoin::Network {
|
||||
bitcoin::Network::Regtest
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user