From 8272e1c247005dad81ccaf37d2bfbd3778e4e868 Mon Sep 17 00:00:00 2001 From: rishflab Date: Fri, 21 May 2021 15:58:41 +1000 Subject: [PATCH] WIP --- Cargo.lock | 33 +-- rust-toolchain | 2 +- swap/Cargo.toml | 1 + swap/src/bitcoin.rs | 4 +- swap/src/monero.rs | 2 +- swap/src/xmr_first_protocol.rs | 114 +++++++- swap/src/xmr_first_protocol/alice.rs | 91 ++++-- swap/src/xmr_first_protocol/bob.rs | 150 ++++++++-- .../xmr_first_protocol/state_machine/bob.rs | 10 +- swap/src/xmr_first_protocol/transactions.rs | 17 -- ...ency_refund.rs => btc_emergency_refund.rs} | 68 +---- .../transactions/btc_redeem.rs | 70 ++++- .../transactions/btc_take.rs | 0 .../xmr_first_protocol/transactions/mod.rs | 6 + .../transactions/xmr_lock.rs | 60 +++- .../transactions/xmr_redeem.rs | 58 ++++ .../transactions/xmr_refund.rs | 51 ++-- swap/tests/harness/mod.rs | 2 +- ...mr_first_bob_fails_to_act_alice_refunds.rs | 90 +++--- swap/tests/xmr_first_happy_path.rs | 264 ++++++++++-------- 20 files changed, 775 insertions(+), 318 deletions(-) delete mode 100644 swap/src/xmr_first_protocol/transactions.rs rename swap/src/xmr_first_protocol/transactions/{emergency_refund.rs => btc_emergency_refund.rs} (57%) create mode 100644 swap/src/xmr_first_protocol/transactions/btc_take.rs create mode 100644 swap/src/xmr_first_protocol/transactions/mod.rs create mode 100644 swap/src/xmr_first_protocol/transactions/xmr_redeem.rs diff --git a/Cargo.lock b/Cargo.lock index bc4679f2..0ea97a7b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3719,12 +3719,12 @@ checksum = "1e81da0851ada1f3e9d4312c704aa4f8806f0f9d69faaf8df2f3464b4a9437c2" name = "swap" version = "0.4.0" dependencies = [ - "anyhow", - "async-compression", - "async-trait", - "atty", - "backoff", - "base64 0.13.0", + "anyhow", + "async-compression", + "async-trait", + "atty", + "backoff", + "base64 0.13.0", "bdk", "bdk-testutils", "big-bytes", @@ -3739,6 +3739,7 @@ dependencies = [ "ecdsa_fun", "futures", "get-port", + "hash_edwards_to_edwards", "hyper 0.14.5", "itertools 0.10.0", "libp2p", @@ -3766,16 +3767,16 @@ dependencies = [ "strum", "tempfile", "testcontainers 0.12.0", - "thiserror", - "time 0.2.26", - "tokio 1.4.0", - "tokio-tar", - "tokio-tungstenite", - "tokio-util", - "toml", - "tracing", - "tracing-appender", - "tracing-futures", + "thiserror", + "time 0.2.26", + "tokio 1.4.0", + "tokio-tar", + "tokio-tungstenite", + "tokio-util", + "toml", + "tracing", + "tracing-appender", + "tracing-futures", "tracing-subscriber", "url 2.2.1", "uuid", diff --git a/rust-toolchain b/rust-toolchain index ade228cc..f2b15cb8 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2021-04-15" +channel = "nightly-2021-05-17" components = ["rustfmt", "clippy"] targets = ["armv7-unknown-linux-gnueabihf"] diff --git a/swap/Cargo.toml b/swap/Cargo.toml index 8303834d..b27ab358 100644 --- a/swap/Cargo.toml +++ b/swap/Cargo.toml @@ -26,6 +26,7 @@ dialoguer = "0.8" directories-next = "2" ecdsa_fun = { git = "https://github.com/LLFourn/secp256kfun", features = ["libsecp_compat", "serde"] } futures = { version = "0.3", default-features = false } +hash_edwards_to_edwards = { git = "https://github.com/comit-network/hash_edwards_to_edwards" } itertools = "0.10" libp2p = { version = "0.36", default-features = false, features = ["tcp-tokio", "yamux", "mplex", "dns-tokio", "noise", "request-response"] } libp2p-async-await = { git = "https://github.com/comit-network/rust-libp2p-async-await" } diff --git a/swap/src/bitcoin.rs b/swap/src/bitcoin.rs index 84434ffe..9f804903 100644 --- a/swap/src/bitcoin.rs +++ b/swap/src/bitcoin.rs @@ -49,7 +49,7 @@ pub const TX_FEE: u64 = 15_000; #[derive(Debug, Clone, Deserialize, Serialize, PartialEq)] pub struct SecretKey { inner: Scalar, - public: Point, + pub(crate) public: Point, } impl SecretKey { @@ -104,7 +104,7 @@ impl SecretKey { } #[derive(Debug, Copy, Clone, Serialize, Deserialize, PartialEq)] -pub struct PublicKey(Point); +pub struct PublicKey(pub(crate) Point); impl PublicKey { #[cfg(test)] diff --git a/swap/src/monero.rs b/swap/src/monero.rs index 13bb3237..8086c476 100644 --- a/swap/src/monero.rs +++ b/swap/src/monero.rs @@ -30,7 +30,7 @@ pub fn private_key_from_secp256k1_scalar(scalar: bitcoin::Scalar) -> PrivateKey } #[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq)] -pub struct PrivateViewKey(#[serde(with = "monero_private_key")] PrivateKey); +pub struct PrivateViewKey(#[serde(with = "monero_private_key")] pub PrivateKey); impl PrivateViewKey { pub fn new_random(rng: &mut R) -> Self { diff --git a/swap/src/xmr_first_protocol.rs b/swap/src/xmr_first_protocol.rs index 4994c6a5..5cbe3f06 100644 --- a/swap/src/xmr_first_protocol.rs +++ b/swap/src/xmr_first_protocol.rs @@ -1,14 +1,116 @@ use crate::bitcoin::Txid; +use crate::protocol::CROSS_CURVE_PROOF_SYSTEM; +use curve25519_dalek::constants::ED25519_BASEPOINT_POINT; +use curve25519_dalek::edwards::EdwardsPoint; +use curve25519_dalek::scalar::Scalar; +use ecdsa_fun::fun::Point; +use hash_edwards_to_edwards::hash_point_to_point; use monero_adaptor::AdaptorSignature; +use rand::rngs::OsRng; pub mod alice; pub mod bob; mod state_machine; -mod transactions; +pub mod transactions; -pub struct SeenBtcLock { - s_0_b: crate::monero::Scalar, - pub adaptor_sig: AdaptorSignature, - tx_lock_id: Txid, - tx_lock: bitcoin::Transaction, +pub struct Alice { + pub a: crate::bitcoin::SecretKey, + pub s_a: crate::monero::Scalar, + r_a: Scalar, + // private view keys + pub v_a: crate::monero::PrivateViewKey, + pub v_b: crate::monero::PrivateViewKey, + pub S_a: EdwardsPoint, + pub S_b: crate::monero::PublicKey, + pub R_a: EdwardsPoint, + pub S_prime_a: Point, + pub R_prime_a: EdwardsPoint, + pub pk_a: crate::bitcoin::PublicKey, + pub pk_b: crate::bitcoin::PublicKey, + pub K_a: crate::monero::PublicViewKey, + pub K_b: crate::monero::PublicViewKey, +} + +pub struct Bob { + b: crate::bitcoin::SecretKey, + pub s_b: crate::monero::Scalar, + // private view keys + pub v_a: crate::monero::PrivateViewKey, + pub v_b: crate::monero::PrivateViewKey, + pub S_a: EdwardsPoint, + pub S_b: crate::monero::PublicKey, + pub R_a: EdwardsPoint, + pub S_prime_a: Point, + pub R_prime_a: EdwardsPoint, + pub pk_a: crate::bitcoin::PublicKey, + pub pk_b: crate::bitcoin::PublicKey, + pub K_a: crate::monero::PublicViewKey, + pub K_b: crate::monero::PublicViewKey, +} + +pub fn setup() -> (Alice, Bob) { + let v_a = crate::monero::PrivateViewKey::new_random(&mut OsRng); + let v_b = crate::monero::PrivateViewKey::new_random(&mut OsRng); + + let a = crate::bitcoin::SecretKey::new_random(&mut OsRng); + let b = crate::bitcoin::SecretKey::new_random(&mut OsRng); + + let s_a = crate::monero::Scalar::random(&mut OsRng); + + let s_b = crate::monero::Scalar::random(&mut OsRng); + let S_b = monero::PublicKey::from_private_key(&monero::PrivateKey { scalar: s_b }); + + let (_dleq_proof_s_a, (S_prime_a, S_a)) = CROSS_CURVE_PROOF_SYSTEM.prove(&s_a, &mut OsRng); + + let (r_a, R_a, R_prime_a) = { + let r_a = Scalar::random(&mut OsRng); + let R_a = r_a * ED25519_BASEPOINT_POINT; + + let pk_hashed_to_point = hash_point_to_point(S_a); + + let R_prime_a = r_a * pk_hashed_to_point; + + (r_a, R_a, R_prime_a) + }; + + let K_a = v_a.public(); + let K_b = v_b.public(); + + let pk_a = a.public(); + let pk_b = b.public(); + + let alice = Alice { + a, + v_a, + v_b, + s_a, + S_a, + S_b, + r_a, + R_a, + S_prime_a, + R_prime_a, + pk_a, + pk_b, + K_a, + K_b, + }; + + let bob = Bob { + b, + v_a, + v_b, + s_b, + S_a, + S_b, + R_a, + S_prime_a, + R_prime_a, + pk_a, + pk_b, + K_a, + K_b, + }; + + (alice, bob) } diff --git a/swap/src/xmr_first_protocol/alice.rs b/swap/src/xmr_first_protocol/alice.rs index 8f399c8c..3a69778f 100644 --- a/swap/src/xmr_first_protocol/alice.rs +++ b/swap/src/xmr_first_protocol/alice.rs @@ -1,53 +1,68 @@ use anyhow::Result; -use monero::PublicKey; use rand::rngs::OsRng; -use monero_adaptor::alice::Alice2; -use monero_adaptor::AdaptorSignature; - -use crate::bitcoin::TxLock; -use crate::monero::{Scalar, TransferRequest}; -use curve25519_dalek::edwards::EdwardsPoint; +use crate::bitcoin::EncryptedSignature; +use crate::monero::{Scalar, TransferProof, TransferRequest}; +use crate::monero_ext::ScalarExt; +use crate::xmr_first_protocol::transactions::btc_lock::BtcLock; +use crate::xmr_first_protocol::transactions::btc_redeem::BtcRedeem; +use crate::xmr_first_protocol::transactions::xmr_refund::XmrRefund; // start pub struct Alice3 { pub xmr_swap_amount: crate::monero::Amount, pub btc_swap_amount: crate::bitcoin::Amount, // pub adaptor_sig: AdaptorSignature, + // adaptor + // pub r_a: Scalar, pub a: crate::bitcoin::SecretKey, pub B: crate::bitcoin::PublicKey, pub s_a: Scalar, - pub S_b_monero: EdwardsPoint, + pub S_b_monero: crate::monero::PublicKey, pub v_a: crate::monero::PrivateViewKey, + pub redeem_address: bitcoin::Address, } // published xmr_lock, watching for btc_lock pub struct Alice4 { - a: crate::bitcoin::SecretKey, - B: crate::bitcoin::PublicKey, + pub a: crate::bitcoin::SecretKey, + pub B: crate::bitcoin::PublicKey, + // pub r_a: Scalar, + pub s_a: Scalar, btc_swap_amount: crate::bitcoin::Amount, + pub transfer_proof: TransferProof, + pub redeem_address: bitcoin::Address, // pub adaptor_sig: AdaptorSignature, } // published seen btc_lock, published btc_redeem -pub struct Alice5; +pub struct Alice5 { + pub a: crate::bitcoin::SecretKey, + pub B: crate::bitcoin::PublicKey, + // pub r_a: Scalar, + pub s_a: Scalar, + pub redeem_address: bitcoin::Address, + btc_swap_amount: crate::bitcoin::Amount, +} impl Alice3 { pub fn new( - S_b_monero: EdwardsPoint, + S_b_monero: crate::monero::PublicKey, B: crate::bitcoin::PublicKey, xmr_swap_amount: crate::monero::Amount, btc_swap_amount: crate::bitcoin::Amount, + redeem_address: bitcoin::Address, ) -> Self { Self { xmr_swap_amount, btc_swap_amount, - // adaptor_sig: alice2.adaptor_sig, + // r_a: Default::default(), a: crate::bitcoin::SecretKey::new_random(&mut OsRng), B, s_a: Scalar::random(&mut OsRng), S_b_monero, v_a: crate::monero::PrivateViewKey::new_random(&mut OsRng), + redeem_address, } } pub async fn publish_xmr_lock(&self, wallet: &crate::monero::Wallet) -> Result { @@ -63,21 +78,61 @@ impl Alice3 { }; // we may have to send this to Bob - let _ = wallet.transfer(req).await?; + let transfer_proof = wallet.transfer(req).await?; Ok(Alice4 { a: self.a.clone(), B: self.B, - btc_swap_amount: Default::default(), + // r_a: Default::default(), + s_a: self.s_a, + btc_swap_amount: self.btc_swap_amount, + transfer_proof, // adaptor_sig: self.adaptor_sig.clone(), + redeem_address: self.redeem_address.clone(), }) } + + // pub async fn publish_xmr_refund(&self, refund_xmr: XmrRefund) -> Result<()> { + // let sig = refund_xmr.adaptor.adapt(self.r_a); + // todo!("sig"); + // Ok(()) + // } } impl Alice4 { pub async fn watch_for_btc_lock(&self, wallet: &crate::bitcoin::Wallet) -> Result { - let btc_lock = TxLock::new(wallet, self.btc_swap_amount, self.a.public(), self.B).await?; - wallet.subscribe_to(btc_lock); - Ok(Alice5) + let btc_lock = BtcLock::new(wallet, self.btc_swap_amount, self.a.public(), self.B).await?; + let btc_lock_watcher = wallet.subscribe_to(btc_lock).await; + + btc_lock_watcher.wait_until_confirmed_with(1).await?; + + Ok(Alice5 { + a: self.a.clone(), + B: self.B, + // r_a: Default::default(), + s_a: self.s_a, + redeem_address: self.redeem_address.clone(), + btc_swap_amount: self.btc_swap_amount, + }) + } +} + +impl Alice5 { + pub async fn publish_btc_redeem( + &self, + wallet: &crate::bitcoin::Wallet, + encsig: EncryptedSignature, + ) -> Result<()> { + let tx_lock = BtcLock::new(wallet, self.btc_swap_amount, self.a.public(), self.B).await?; + let tx_redeem = BtcRedeem::new(&tx_lock, &self.redeem_address); + + let signed_tx_redeem = + tx_redeem.complete(self.a.clone(), self.s_a.to_secpfun_scalar(), self.B, encsig)?; + + let (txid, sub) = wallet.broadcast(signed_tx_redeem, "lock").await?; + + let _ = sub.wait_until_confirmed_with(1).await?; + + Ok(()) } } diff --git a/swap/src/xmr_first_protocol/bob.rs b/swap/src/xmr_first_protocol/bob.rs index 0bb19a99..ee1c9d5c 100644 --- a/swap/src/xmr_first_protocol/bob.rs +++ b/swap/src/xmr_first_protocol/bob.rs @@ -1,35 +1,147 @@ +use crate::monero::wallet::{TransferRequest, WatchRequest}; +use crate::monero::TransferProof; +use crate::xmr_first_protocol::transactions::btc_lock::BtcLock; +use crate::xmr_first_protocol::transactions::btc_redeem::BtcRedeem; use anyhow::Result; -use monero::PublicKey; -use rand::rngs::OsRng; - -use monero_adaptor::alice::Alice2; -use monero_adaptor::AdaptorSignature; - -use crate::bitcoin::Txid; -use crate::monero::wallet::WatchRequest; -use crate::monero::{Scalar, TransferRequest}; -use crate::xmr_first_protocol::transactions::xmr_lock::XmrLock; +use monero_rpc::wallet::BlockHeight; +use uuid::Uuid; // watching for xmr_lock pub struct Bob3 { + pub b: crate::bitcoin::SecretKey, + pub A: crate::bitcoin::PublicKey, + pub s_b: crate::monero::Scalar, pub xmr_swap_amount: crate::monero::Amount, pub btc_swap_amount: crate::bitcoin::Amount, - pub xmr_lock: XmrLock, - v_b: crate::monero::PrivateViewKey, + pub tx_lock: BtcLock, + // public spend key + pub S: crate::monero::PublicKey, + pub S_a_bitcoin: crate::bitcoin::PublicKey, + pub v: crate::monero::PrivateViewKey, + pub alice_redeem_address: bitcoin::Address, } impl Bob3 { - pub fn watch_for_lock_xmr(&self, wallet: &crate::monero::Wallet) { + pub async fn watch_for_lock_xmr( + &self, + xmr_wallet: &crate::monero::Wallet, + btc_wallet: &crate::bitcoin::Wallet, + transfer_proof: TransferProof, + alice_redeem_address: bitcoin::Address, + ) -> Result { let req = WatchRequest { - public_spend_key: self.xmr_lock.public_spend_key, - public_view_key: self.v_b.public(), - transfer_proof: self.xmr_lock.transfer_proof.clone(), + public_spend_key: self.S, + public_view_key: self.v.public(), + transfer_proof, conf_target: 1, expected: self.xmr_swap_amount, }; - wallet.watch_for_transfer(req); + let _ = xmr_wallet.watch_for_transfer(req).await?; + + let signed_tx_lock = btc_wallet + .sign_and_finalize(self.tx_lock.clone().into()) + .await?; + + let (_txid, sub) = btc_wallet.broadcast(signed_tx_lock, "lock").await?; + + let _ = sub.wait_until_confirmed_with(1).await?; + + Ok(Bob4 { + b: self.b.clone(), + A: self.A, + s_b: self.s_b, + S_a_bitcoin: self.S_a_bitcoin, + tx_lock: self.tx_lock.clone(), + alice_redeem_address, + v: self.v, + }) + } + + pub async fn emergency_refund_if_refund_xmr_seen( + &self, + xmr_wallet: &crate::monero::Wallet, + btc_wallet: &crate::bitcoin::Wallet, + transfer_proof: TransferProof, + ) -> Result { + let req = WatchRequest { + public_spend_key: todo!(), + public_view_key: todo!(), + transfer_proof, + conf_target: 1, + expected: self.xmr_swap_amount, + }; + let _ = xmr_wallet.watch_for_transfer(req).await?; + + let emergency_refund = btc_wallet + .sign_and_finalize(self.tx_lock.clone().into()) + .await?; + + let (_txid, sub) = btc_wallet.broadcast(emergency_refund, "lock").await?; + + let _ = sub.wait_until_confirmed_with(1).await?; + + Ok(Bob4 { + b: self.b.clone(), + A: self.A, + s_b: self.s_b, + S_a_bitcoin: self.S_a_bitcoin, + tx_lock: self.tx_lock.clone(), + alice_redeem_address: self.alice_redeem_address.clone(), + v: self.v, + }) } } -// published btc_lock, watching for xmr_redeem -pub struct Bob4; +// published btc_lock, watching for btc_redeem +pub struct Bob4 { + pub b: crate::bitcoin::SecretKey, + pub A: crate::bitcoin::PublicKey, + pub s_b: crate::monero::Scalar, + pub S_a_bitcoin: crate::bitcoin::PublicKey, + pub tx_lock: BtcLock, + pub alice_redeem_address: crate::bitcoin::Address, + pub v: crate::monero::PrivateViewKey, +} + +impl Bob4 { + pub async fn redeem_xmr_when_btc_redeem_seen( + &self, + bitcoin_wallet: &crate::bitcoin::Wallet, + monero_wallet: &crate::monero::Wallet, + swap_id: Uuid, + ) -> Result<()> { + let btc_redeem = BtcRedeem::new(&self.tx_lock, &self.alice_redeem_address); + let btc_redeem_encsig = self.b.encsign(self.S_a_bitcoin, btc_redeem.digest()); + + let btc_redeem_watcher = bitcoin_wallet.subscribe_to(btc_redeem.clone()).await; + + btc_redeem_watcher.wait_until_confirmed_with(1).await?; + + let btc_redeem_candidate = bitcoin_wallet + .get_raw_transaction(btc_redeem.txid()) + .await?; + + let btc_redeem_sig = + btc_redeem.extract_signature_by_key(btc_redeem_candidate, self.b.public())?; + let s_a = crate::bitcoin::recover(self.S_a_bitcoin, btc_redeem_sig, btc_redeem_encsig)?; + let s_a = crate::monero::private_key_from_secp256k1_scalar(s_a.into()); + + let (spend_key, view_key) = { + let s_b = monero::PrivateKey { scalar: self.s_b }; + let s = s_a + s_b; + + (s, self.v) + }; + + monero_wallet + .create_from_and_load( + &swap_id.to_string(), + spend_key, + view_key, + monero_rpc::wallet::BlockHeight { height: 0 }, + ) + .await?; + + Ok(()) + } +} diff --git a/swap/src/xmr_first_protocol/state_machine/bob.rs b/swap/src/xmr_first_protocol/state_machine/bob.rs index 02c635c2..e9a23ae7 100644 --- a/swap/src/xmr_first_protocol/state_machine/bob.rs +++ b/swap/src/xmr_first_protocol/state_machine/bob.rs @@ -7,7 +7,7 @@ pub struct StateMachine { } impl StateMachine { - fn next(&mut self, event: Event) { + fn inject_event(&mut self, event: Event) { match self.state { State::WatchingForXmrLock => match event { Event::XmrConfirmed => { @@ -41,9 +41,11 @@ impl StateMachine { } } - fn run(&mut self) { - while let Some(event) = self.events.pop_front() { - self.next(event); + fn poll(&mut self) -> Poll { + if let Some(action) = self.actions.pop_front() { + Poll::Ready(action) + } else { + Poll::Pending } } } diff --git a/swap/src/xmr_first_protocol/transactions.rs b/swap/src/xmr_first_protocol/transactions.rs deleted file mode 100644 index aca84b73..00000000 --- a/swap/src/xmr_first_protocol/transactions.rs +++ /dev/null @@ -1,17 +0,0 @@ -pub mod btc_lock; -// pub mod btc_redeem; -pub mod xmr_lock; -pub mod xmr_refund; - -use crate::bitcoin::wallet::Watchable; -use crate::bitcoin::{ - build_shared_output_descriptor, Address, Amount, PartiallySignedTransaction, PublicKey, - Transaction, Txid, Wallet, TX_FEE, -}; -use anyhow::{bail, Result}; -use bdk::bitcoin::{OutPoint, Script, TxIn, TxOut}; -use bdk::database::BatchDatabase; -use bdk::descriptor::Descriptor; -use ecdsa_fun::fun::Point; -use miniscript::DescriptorTrait; -use rand::thread_rng; diff --git a/swap/src/xmr_first_protocol/transactions/emergency_refund.rs b/swap/src/xmr_first_protocol/transactions/btc_emergency_refund.rs similarity index 57% rename from swap/src/xmr_first_protocol/transactions/emergency_refund.rs rename to swap/src/xmr_first_protocol/transactions/btc_emergency_refund.rs index 8f59f4f1..81c8581b 100644 --- a/swap/src/xmr_first_protocol/transactions/emergency_refund.rs +++ b/swap/src/xmr_first_protocol/transactions/btc_emergency_refund.rs @@ -4,6 +4,7 @@ use crate::bitcoin::{ NotThreeWitnesses, PublicKey, SecretKey, TooManyInputs, Transaction, }; use crate::xmr_first_protocol::transactions::btc_lock::BtcLock; +use crate::xmr_first_protocol::transactions::btc_redeem::BtcRedeem; use ::bitcoin::util::bip143::SigHashCache; use ::bitcoin::{SigHash, SigHashType, Txid}; use anyhow::{bail, Context, Result}; @@ -17,30 +18,28 @@ use sha2::Sha256; use std::collections::HashMap; #[derive(Clone, Debug)] -pub struct EmergencyRefund { +pub struct BtcEmergencyRefund { inner: Transaction, digest: SigHash, lock_output_descriptor: Descriptor<::bitcoin::PublicKey>, watch_script: Script, } -impl EmergencyRefund { - pub fn new(tx_lock: &BtcLock, redeem_address: &Address) -> Self { - // lock_input is the shared output that is now being used as an input for the - // redeem transaction - let tx_redeem = tx_lock.build_spend_transaction(redeem_address, None); +impl BtcEmergencyRefund { + pub fn new(tx_redeem: &BtcRedeem, redeem_address: &Address) -> Self { + let tx_refund = tx_redeem.build_take_transaction(redeem_address, None); - let digest = SigHashCache::new(&tx_redeem).signature_hash( + let digest = SigHashCache::new(&tx_refund).signature_hash( 0, // Only one input: lock_input (lock transaction) - &tx_lock.output_descriptor.script_code(), - tx_lock.lock_amount().as_sat(), + &tx_refund.output_descriptor.script_code(), + tx_refund.lock_amount().as_sat(), SigHashType::All, ); Self { - inner: tx_redeem, + inner: tx_refund, digest, - lock_output_descriptor: tx_lock.output_descriptor.clone(), + lock_output_descriptor: tx_refund.output_descriptor.clone(), watch_script: redeem_address.script_pubkey(), } } @@ -53,14 +52,6 @@ impl EmergencyRefund { self.digest } - pub fn encsig( - &self, - b: SecretKey, - S_a_bitcoin: PublicKey, - ) -> crate::bitcoin::EncryptedSignature { - b.encsign(S_a_bitcoin, self.digest()) - } - pub fn complete( mut self, a: SecretKey, @@ -105,46 +96,9 @@ impl EmergencyRefund { Ok(self.inner) } - - pub fn extract_signature_by_key( - &self, - candidate_transaction: Transaction, - B: PublicKey, - ) -> Result { - let input = match candidate_transaction.input.as_slice() { - [input] => input, - [] => bail!("no inputs"), - [inputs @ ..] => bail!("too many inputs"), - }; - - let sigs = match input - .witness - .iter() - .map(|vec| vec.as_slice()) - .collect::>() - .as_slice() - { - [sig_1, sig_2, _script] => [sig_1, sig_2] - .iter() - .map(|sig| { - bitcoin::secp256k1::Signature::from_der(&sig[..sig.len() - 1]) - .map(Signature::from) - }) - .collect::, _>>(), - [] => bail!("empty witness stack"), - [witnesses @ ..] => bail!("not three witnesses"), - }?; - - let sig = sigs - .into_iter() - .find(|sig| verify_sig(&B, &self.digest(), &sig).is_ok()) - .context("Neither signature on witness stack verifies against B")?; - - Ok(sig) - } } -impl Watchable for EmergencyRefund { +impl Watchable for BtcEmergencyRefund { fn id(&self) -> Txid { self.txid() } diff --git a/swap/src/xmr_first_protocol/transactions/btc_redeem.rs b/swap/src/xmr_first_protocol/transactions/btc_redeem.rs index 30512e0d..5f72d899 100644 --- a/swap/src/xmr_first_protocol/transactions/btc_redeem.rs +++ b/swap/src/xmr_first_protocol/transactions/btc_redeem.rs @@ -1,12 +1,14 @@ use crate::bitcoin::wallet::Watchable; use crate::bitcoin::{ verify_encsig, verify_sig, Address, EmptyWitnessStack, EncryptedSignature, NoInputs, - NotThreeWitnesses, PublicKey, SecretKey, TooManyInputs, Transaction, TxLock, + NotThreeWitnesses, PublicKey, SecretKey, TooManyInputs, Transaction, TX_FEE, }; +use crate::xmr_first_protocol::transactions::btc_lock::BtcLock; use ::bitcoin::util::bip143::SigHashCache; use ::bitcoin::{SigHash, SigHashType, Txid}; use anyhow::{bail, Context, Result}; -use bitcoin::Script; +use bdk::bitcoin::Script; +use bitcoin::{PrivateKey, TxIn, TxOut}; use ecdsa_fun::adaptor::{Adaptor, HashTranscript}; use ecdsa_fun::fun::Scalar; use ecdsa_fun::nonce::Deterministic; @@ -16,15 +18,15 @@ use sha2::Sha256; use std::collections::HashMap; #[derive(Clone, Debug)] -pub struct TxRedeem { +pub struct BtcRedeem { inner: Transaction, digest: SigHash, lock_output_descriptor: Descriptor<::bitcoin::PublicKey>, watch_script: Script, } -impl TxRedeem { - pub fn new(tx_lock: &TxLock, redeem_address: &Address) -> Self { +impl BtcRedeem { + pub fn new(tx_lock: &BtcLock, redeem_address: &Address) -> Self { // lock_input is the shared output that is now being used as an input for the // redeem transaction let tx_redeem = tx_lock.build_spend_transaction(redeem_address, None); @@ -52,12 +54,20 @@ impl TxRedeem { self.digest } + pub fn encsig( + &self, + b: SecretKey, + S_a_bitcoin: PublicKey, + ) -> crate::bitcoin::EncryptedSignature { + b.encsign(S_a_bitcoin, self.digest()) + } + pub fn complete( mut self, - encrypted_signature: EncryptedSignature, a: SecretKey, s_a: Scalar, B: PublicKey, + encrypted_signature: EncryptedSignature, ) -> Result { verify_encsig( B, @@ -76,11 +86,11 @@ impl TxRedeem { let A = ::bitcoin::PublicKey { compressed: true, - key: a.public().into(), + key: a.public.into(), }; let B = ::bitcoin::PublicKey { compressed: true, - key: B.into(), + key: B.0.into(), }; // The order in which these are inserted doesn't matter @@ -104,7 +114,7 @@ impl TxRedeem { ) -> Result { let input = match candidate_transaction.input.as_slice() { [input] => input, - [] => bail!(NoInputs), + [] => bail!("no inputs"), [inputs @ ..] => bail!("too many inputs"), }; @@ -122,7 +132,7 @@ impl TxRedeem { .map(Signature::from) }) .collect::, _>>(), - [] => bail!(EmptyWitnessStack), + [] => bail!("empty witness stack"), [witnesses @ ..] => bail!("not three witnesses"), }?; @@ -133,9 +143,47 @@ impl TxRedeem { Ok(sig) } + + pub fn build_transaction( + &self, + a: SecretKey, + s_a: Scalar, + B: PublicKey, + encsig: EncryptedSignature, + ) -> Transaction { + let signed_tx_redeem = self.complete(a, s_a, B, encsig)?; + signed_tx_redeem + } + + pub fn build_take_transaction( + &self, + spend_address: &Address, + sequence: Option, + ) -> Transaction { + let previous_output = self.as_outpoint(); + + let tx_in = TxIn { + previous_output, + script_sig: Default::default(), + sequence: sequence.unwrap_or(0xFFFF_FFFF), + witness: Vec::new(), + }; + + let tx_out = TxOut { + value: self.inner.clone().extract_tx().output[self.lock_output_vout()].value - TX_FEE, + script_pubkey: spend_address.script_pubkey(), + }; + + Transaction { + version: 2, + lock_time: 0, + input: vec![tx_in], + output: vec![tx_out], + } + } } -impl Watchable for TxRedeem { +impl Watchable for BtcRedeem { fn id(&self) -> Txid { self.txid() } diff --git a/swap/src/xmr_first_protocol/transactions/btc_take.rs b/swap/src/xmr_first_protocol/transactions/btc_take.rs new file mode 100644 index 00000000..e69de29b diff --git a/swap/src/xmr_first_protocol/transactions/mod.rs b/swap/src/xmr_first_protocol/transactions/mod.rs new file mode 100644 index 00000000..f1de8920 --- /dev/null +++ b/swap/src/xmr_first_protocol/transactions/mod.rs @@ -0,0 +1,6 @@ +pub mod btc_emergency_refund; +pub mod btc_lock; +pub mod btc_redeem; +pub mod xmr_lock; +pub mod xmr_redeem; +pub mod xmr_refund; diff --git a/swap/src/xmr_first_protocol/transactions/xmr_lock.rs b/swap/src/xmr_first_protocol/transactions/xmr_lock.rs index 7a2cd732..5e0e0def 100644 --- a/swap/src/xmr_first_protocol/transactions/xmr_lock.rs +++ b/swap/src/xmr_first_protocol/transactions/xmr_lock.rs @@ -1,7 +1,59 @@ -use crate::monero::{PrivateViewKey, PublicKey, TransferProof}; +use crate::monero::wallet::{TransferRequest, WatchRequest}; +use crate::monero::{Amount, PrivateViewKey, Scalar, TransferProof}; +use curve25519_dalek::edwards::EdwardsPoint; +use monero::PublicKey; pub struct XmrLock { - pub public_spend_key: PublicKey, - pub public_view_key: PrivateViewKey, - pub transfer_proof: TransferProof, + S_a: monero::PublicKey, + S_b: monero::PublicKey, + v_a: PrivateViewKey, + v_b: PrivateViewKey, + D: EdwardsPoint, + amount: Amount, +} + +impl XmrLock { + pub fn new( + S_a: monero::PublicKey, + S_b: monero::PublicKey, + v_a: PrivateViewKey, + v_b: PrivateViewKey, + D: EdwardsPoint, + amount: Amount, + ) -> Self { + Self { + S_a, + S_b, + v_a, + v_b, + D, + amount, + } + } + pub fn transfer_request(&self) -> TransferRequest { + let vk = self.S_a + self.S_b; + let v = self.v_a + self.v_b; + + // use from KeyGenerator from monero.rs to do the H(vD) bit for the on time + // address + let one_time_address = todo!("KeyGenerator.random().one_time_key(self.D)"); + + TransferRequest { + public_spend_key: one_time_address, + public_view_key: v.public(), + amount: self.amount, + } + } + pub fn watch_request(&self, transfer_proof: TransferProof) -> WatchRequest { + let public_spend_key = self.S_a + self.S_b; + let private_view_key = self.v_a + self.v_b; + + WatchRequest { + public_spend_key, + public_view_key: private_view_key.public(), + transfer_proof, + conf_target: 1, + expected: self.amount, + } + } } diff --git a/swap/src/xmr_first_protocol/transactions/xmr_redeem.rs b/swap/src/xmr_first_protocol/transactions/xmr_redeem.rs new file mode 100644 index 00000000..d1358457 --- /dev/null +++ b/swap/src/xmr_first_protocol/transactions/xmr_redeem.rs @@ -0,0 +1,58 @@ +use crate::monero::wallet::{TransferRequest, WatchRequest}; +use crate::monero::{Amount, PrivateKey, PrivateViewKey, Scalar, TransferProof}; +use curve25519_dalek::edwards::EdwardsPoint; +use monero::PublicKey; + +pub struct XmrRedeem { + // recover s_a from btc_redeem + s_a: monero::PrivateKey, + s_b: monero::PrivateKey, + v_a: PrivateViewKey, + v_b: PrivateViewKey, + // D: EdwardsPoint, + amount: Amount, +} + +impl XmrRedeem { + pub fn new( + s_a: monero::PrivateKey, + s_b: monero::PrivateKey, + v_a: PrivateViewKey, + v_b: PrivateViewKey, + // D: EdwardsPoint, + amount: Amount, + ) -> Self { + Self { + s_a, + s_b, + v_a, + v_b, + // D, + amount, + } + } + pub fn transfer_request(&self) -> TransferRequest { + let v = self.v_a + self.v_b; + // let h = self.D * v_view; + // let private_spend_key = self.s_a + self.s_b + h; + let vk = self.s_a + self.s_b; + + TransferRequest { + public_spend_key: PublicKey::from_private_key(&vk), + public_view_key: v.public(), + amount: self.amount, + } + } + pub fn watch_request(&self, transfer_proof: TransferProof) -> WatchRequest { + let private_spend_key = self.s_a + self.s_b; + let private_view_key = self.v_a + self.v_b; + + WatchRequest { + public_spend_key: PublicKey::from_private_key(&private_spend_key), + public_view_key: private_view_key.public(), + transfer_proof, + conf_target: 1, + expected: self.amount, + } + } +} diff --git a/swap/src/xmr_first_protocol/transactions/xmr_refund.rs b/swap/src/xmr_first_protocol/transactions/xmr_refund.rs index a2c56a82..fafa530b 100644 --- a/swap/src/xmr_first_protocol/transactions/xmr_refund.rs +++ b/swap/src/xmr_first_protocol/transactions/xmr_refund.rs @@ -1,26 +1,43 @@ -use crate::monero::TransferRequest; +use crate::monero::wallet::WatchRequest; +use crate::monero::{Amount, PrivateViewKey, Scalar}; use crate::xmr_first_protocol::alice::Alice4; use anyhow::Result; -use monero_adaptor::AdaptorSignature; +use monero_adaptor::Signature; pub struct XmrRefund { - adaptor: AdaptorSignature, + signature: Signature, + amount: Amount, } +struct TransferRequest; + impl XmrRefund { - pub async fn publish_xmr_refund(&self, wallet: &crate::monero::Wallet) -> Result<()> { - let S_a = monero::PublicKey::from_private_key(&monero::PrivateKey { scalar: self.s_a }); - - let public_spend_key = S_a + self.S_b_monero; - let public_view_key = self.v_a.public(); - - let req = TransferRequest { - public_spend_key, - public_view_key, - amount: self.xmr_swap_amount, - }; - - let _ = wallet.transfer(req).await?; - Ok(()) + pub fn new(signature: Signature, amount: Amount) -> Self { + XmrRefund { + signature, + amount: xmr_swap_amount, + } + } + pub fn transfer_request(&self) -> TransferRequest { + todo!(); + TransferRequest + } + // pub fn watch_request(&self) -> WatchRequest { + // let S_a = monero::PublicKey::from_private_key(&monero::PrivateKey { + // scalar: self.s_a }); + // + // let public_spend_key = S_a + self.S_b_monero; + // let public_view_key = self.v_a.public(); + // + // WatchRequest { + // public_spend_key, + // public_view_key, + // transfer_proof: todo!("xfer without broadcasting to get xfer proof"), + // conf_target: 1, + // expected: self.amount, + // } + // } + pub fn extract_r_a(&self) -> Scalar { + self.signature.extract() } } diff --git a/swap/tests/harness/mod.rs b/swap/tests/harness/mod.rs index ef7ca4e9..deac71ce 100644 --- a/swap/tests/harness/mod.rs +++ b/swap/tests/harness/mod.rs @@ -834,7 +834,7 @@ pub async fn init_test_wallets( // This is just to keep the containers alive #[allow(dead_code)] -struct Containers<'a> { +pub struct Containers<'a> { pub bitcoind_url: Url, bitcoind: Container<'a, Cli, bitcoind::Bitcoind>, monerods: Vec>, diff --git a/swap/tests/xmr_first_bob_fails_to_act_alice_refunds.rs b/swap/tests/xmr_first_bob_fails_to_act_alice_refunds.rs index aebc24aa..a28941eb 100644 --- a/swap/tests/xmr_first_bob_fails_to_act_alice_refunds.rs +++ b/swap/tests/xmr_first_bob_fails_to_act_alice_refunds.rs @@ -1,16 +1,24 @@ pub mod harness; use rand::rngs::OsRng; -use swap::bitcoin::TxLock; +use swap::bitcoin::BtcLock; use swap::env::GetConfig; use swap::monero; +use swap::monero::TransferRequest; use swap::protocol::alice::event_loop::FixedRate; use swap::protocol::CROSS_CURVE_PROOF_SYSTEM; use swap::seed::Seed; use swap::xmr_first_protocol::alice::{publish_xmr_refund, Alice3}; use swap::xmr_first_protocol::bob::Bob3; +use swap::xmr_first_protocol::transactions::btc_lock::BtcLock; +use swap::xmr_first_protocol::transactions::xmr_lock::XmrLock; +use swap::xmr_first_protocol::transactions::xmr_refund::XmrRefund; use tempfile::tempdir; use testcontainers::clients::Cli; +use swap::xmr_first_protocol::transactions::btc_redeem::BtcRedeem; +use monero::{PublicKey, PrivateKey}; +use swap::xmr_first_protocol::setup; +use swap::xmr_first_protocol::transactions::xmr_redeem::XmrRedeem; #[tokio::test] async fn refund() { @@ -63,48 +71,60 @@ async fn refund() { &bob_seed, env_config, ) - .await; + .await; - let a = swap::bitcoin::SecretKey::new_random(&mut OsRng); - let b = swap::bitcoin::SecretKey::new_random(&mut OsRng); + let (alice, bob) = setup(); - let s_a = monero::Scalar::random(&mut OsRng); - let S_a = monero::PublicKey::from_private_key(&monero::PrivateKey { scalar: s_a }); + let btc_redeem_address = alice_bitcoin_wallet.new_address().await.unwrap(); - let s_b = monero::Scalar::random(&mut OsRng); - let S_b = monero::PublicKey::from_private_key(&monero::PrivateKey { scalar: s_b }); + // transactions + let btc_lock = + BtcLock::new(&bob_bitcoin_wallet, btc_swap_amount, a.public(), b.public()).await?; + let btc_redeem = BtcRedeem::new(&btc_lock, &btc_redeem_address); + let xmr_lock = XmrLock::new(alice.S_a.into(), alice.S_b, alice.v_a, alice.v_b, xmr_swap_amount); + //let xmr_redeem = XmrRedeem::new(s_a, PrivateKey::from_scalar(bob.s_b), alice.v_a, alice.v_b, xmr_swap_amount); + let xmr_refund = XmrRefund::new(sig, xmr_swap_amount); - let (dleq_proof_s_b, (S_b_bitcoin, S_b_monero)) = - CROSS_CURVE_PROOF_SYSTEM.prove(&s_b, &mut OsRng); + // Alice publishes xmr_lock + let xmr_lock_transfer_proof = alice_monero_wallet + .transfer(xmr_lock.transfer_request()) + .await + .unwrap(); - let v_a = monero::PrivateViewKey::new_random(&mut OsRng); - let v_b = monero::PrivateViewKey::new_random(&mut OsRng); + // Bob waits until xmr_lock is seen + let _ = bob_monero_wallet + .watch_for_transfer(xmr_lock.watch_request(xmr_lock_transfer_proof)) + .await + .unwrap(); - let tx_lock = TxLock::new(&bob_bitcoin_wallet, btc_swap_amount, a.public(), b.public()).await?; + // Bob publishes btc_lock + let signed_tx_lock = bob_bitcoin_wallet + .sign_and_finalize(btc_lock.clone().into()) + .await?; + let (_txid, sub) = bob_bitcoin_wallet.broadcast(signed_tx_lock, "lock").await.unwrap(); + let _ = sub.wait_until_confirmed_with(1).await?; - let alice = Alice3 { - xmr_swap_amount, - btc_swap_amount, - a, - B: b.public(), - s_a, - S_b_monero: monero::PublicKey { - point: S_b_monero.compress(), - }, - v_a, - redeem_address: alice_bitcoin_wallet.new_address().await?, - }; + // alice publishes xmr_refund + // let xmr_refund_transfer_proof = alice_monero_wallet + // .transfer(xmr_refund.transfer_request()) + // .await + // .unwrap(); - let bob = Bob3 { - xmr_swap_amount, - btc_swap_amount, - tx_lock, - S: S_b, - v_b, - alice_redeem_address: bob_bitcoin_wallet.new_address().await?, - }; + // alice publishes btc_redeem + btc_redeem.encsig((), ()); + let (_, btc_redeem_sub) = alice_bitcoin_wallet.broadcast(btc_redeem.build_transaction(alice.a, alice.s_a, alice.pk_b, btc_lock.), "redeem") + .await + .unwrap(); - let alice = alice.publish_xmr_lock(&alice_monero_wallet).await.unwrap(); + // bob sees xmr_refund and btc_redeem + let _ = bob_monero_wallet + .watch_for_transfer(xmr_lock.watch_request(xmr_refund_transfer_proof)) + .await + .unwrap(); + let _ = btc_redeem_sub.wait_until_seen() + .await + .unwrap(); - publish_xmr_refund(&alice_bitcoin_wallet).await.unwrap(); + // extract r_a from xmr_refund + let _ = bob_bitcoin_wallet.broadcast("redeem") } diff --git a/swap/tests/xmr_first_happy_path.rs b/swap/tests/xmr_first_happy_path.rs index 29366c35..78c4e552 100644 --- a/swap/tests/xmr_first_happy_path.rs +++ b/swap/tests/xmr_first_happy_path.rs @@ -1,109 +1,155 @@ -pub mod harness; - -use curve25519_dalek::constants::ED25519_BASEPOINT_POINT; -use curve25519_dalek::edwards::EdwardsPoint; -use monero_adaptor::alice::Alice0; -use monero_adaptor::bob::Bob0; -use rand::rngs::OsRng; -use swap::env::GetConfig; -use swap::monero; -use swap::monero::{PublicKey, Scalar}; -use swap::protocol::alice::event_loop::FixedRate; -use swap::protocol::CROSS_CURVE_PROOF_SYSTEM; -use swap::seed::Seed; -use swap::xmr_first_protocol::alice::Alice3; -use swap::xmr_first_protocol::bob::Bob3; -use swap::xmr_first_protocol::{alice, bob}; -use tempfile::tempdir; -use testcontainers::clients::Cli; - -#[tokio::test] -async fn happy_path() { - let cli = Cli::default(); - - let env_config = harness::SlowCancelConfig::get_config(); - - let (monero, containers) = harness::init_containers(&cli).await; - - let btc_amount = bitcoin::Amount::from_sat(1_000_000); - let xmr_amount = monero::Amount::from_monero(btc_amount.as_btc() / FixedRate::RATE).unwrap(); - - let alice_starting_balances = harness::StartingBalances { - xmr: xmr_amount * 10, - btc: bitcoin::Amount::ZERO, - }; - - let electrs_rpc_port = containers - .electrs - .get_host_port(harness::electrs::RPC_PORT) - .expect("Could not map electrs rpc port"); - - let alice_seed = Seed::random().unwrap(); - let (alice_bitcoin_wallet, alice_monero_wallet) = harness::init_test_wallets( - "Alice", - containers.bitcoind_url.clone(), - &monero, - alice_starting_balances.clone(), - tempdir().unwrap().path(), - electrs_rpc_port, - &alice_seed, - env_config.clone(), - ) - .await; - - let bob_seed = Seed::random().unwrap(); - let bob_starting_balances = harness::StartingBalances { - xmr: monero::Amount::ZERO, - btc: btc_amount * 10, - }; - - let (bob_bitcoin_wallet, bob_monero_wallet) = harness::init_test_wallets( - "Bob", - containers.bitcoind_url, - &monero, - bob_starting_balances.clone(), - tempdir().unwrap().path(), - electrs_rpc_port, - &bob_seed, - env_config, - ) - .await; - - let a = crate::bitcoin::SecretKey::new_random(rng); - let b = crate::bitcoin::SecretKey::new_random(rng); - - let s_a = monero::Scalar::random(rng); - let s_b = monero::Scalar::random(rng); - - let (dleq_proof_s_b, (S_b_bitcoin, S_b_monero)) = CROSS_CURVE_PROOF_SYSTEM.prove(&s_b, rng); - - let v_a = monero::PrivateViewKey::new_random(rng); - let v_b = monero::PrivateViewKey::new_random(rng); - - let alice = Alice3 { - xmr_swap_amount: xmr_amount, - btc_swap_amount: btc_amount, - a, - B: b.public(), - s_a, - S_b_monero, - v_a, - }; - - let bob = Bob3 { - xmr_swap_amount, - btc_swap_amount, - xmr_lock, - v_b, - }; - - alice.publish_xmr_lock(&alice_monero_wallet).await.unwrap(); - - bob.watch_for_lock_xmr(&bob_monero_wallet_wallet) - .await - .unwrap(); - - alice.publish_btc_redeem(&alice_btc_wallet).await.unwrap(); - - bob.publish_xmr_redeem(&alice_monero_wallet).await.unwrap(); -} +// pub mod harness; +// +// use rand::rngs::OsRng; +// use swap::env::GetConfig; +// use swap::monero; +// use swap::protocol::alice::event_loop::FixedRate; +// use swap::protocol::CROSS_CURVE_PROOF_SYSTEM; +// use swap::seed::Seed; +// use swap::xmr_first_protocol::alice::Alice3; +// use swap::xmr_first_protocol::bob::Bob3; +// use swap::xmr_first_protocol::transactions::btc_lock::BtcLock; +// use swap::xmr_first_protocol::transactions::btc_redeem::BtcRedeem; +// use tempfile::tempdir; +// use testcontainers::clients::Cli; +// use uuid::Uuid; +// +// #[tokio::test] +// async fn happy_path() { +// let cli = Cli::default(); +// +// let env_config = harness::SlowCancelConfig::get_config(); +// +// let (monero, containers) = harness::init_containers(&cli).await; +// +// let btc_swap_amount = bitcoin::Amount::from_sat(1_000_000); +// let xmr_swap_amount = +// monero::Amount::from_monero(btc_swap_amount.as_btc() / +// FixedRate::RATE).unwrap(); +// +// let alice_starting_balances = harness::StartingBalances { +// xmr: xmr_swap_amount * 10, +// btc: bitcoin::Amount::ZERO, +// }; +// +// let electrs_rpc_port = containers +// .electrs +// .get_host_port(harness::electrs::RPC_PORT) +// .expect("Could not map electrs rpc port"); +// +// let alice_seed = Seed::random().unwrap(); +// let (alice_bitcoin_wallet, alice_monero_wallet) = +// harness::init_test_wallets( "Alice", +// containers.bitcoind_url.clone(), +// &monero, +// alice_starting_balances.clone(), +// tempdir().unwrap().path(), +// electrs_rpc_port, +// &alice_seed, +// env_config.clone(), +// ) +// .await; +// +// let bob_seed = Seed::random().unwrap(); +// let bob_starting_balances = harness::StartingBalances { +// xmr: monero::Amount::ZERO, +// btc: btc_swap_amount * 10, +// }; +// +// let (bob_bitcoin_wallet, bob_monero_wallet) = harness::init_test_wallets( +// "Bob", +// containers.bitcoind_url, +// &monero, +// bob_starting_balances.clone(), +// tempdir().unwrap().path(), +// electrs_rpc_port, +// &bob_seed, +// env_config, +// ) +// .await; +// +// let a = swap::bitcoin::SecretKey::new_random(&mut OsRng); +// let b = swap::bitcoin::SecretKey::new_random(&mut OsRng); +// +// let s_a = monero::Scalar::random(&mut OsRng); +// let S_a = monero::PublicKey::from_private_key(&monero::PrivateKey { +// scalar: s_a }); +// +// let s_b = monero::Scalar::random(&mut OsRng); +// let S_b = monero::PublicKey::from_private_key(&monero::PrivateKey { +// scalar: s_b }); +// +// let (dleq_proof_s_b, (S_b_bitcoin, S_b_monero)) = +// CROSS_CURVE_PROOF_SYSTEM.prove(&s_b, &mut OsRng); +// +// let (dleq_proof_s_b, (S_a_bitcoin, S_a_monero)) = +// CROSS_CURVE_PROOF_SYSTEM.prove(&s_a, &mut OsRng); +// +// let v_a = monero::PrivateViewKey::new_random(&mut OsRng); +// let v_b = monero::PrivateViewKey::new_random(&mut OsRng); +// +// let btc_redeem_address = bob_bitcoin_wallet.new_address().await.unwrap(); +// +// let tx_lock = BtcLock::new(&bob_bitcoin_wallet, btc_swap_amount, +// a.public(), b.public()) .await +// .unwrap(); +// +// let tx_redeem = BtcRedeem::new(&tx_lock, &btc_redeem_address); +// +// let encsig = tx_redeem.encsig(b.clone(), +// swap::bitcoin::PublicKey::from(S_a_bitcoin)); +// +// let alice = Alice3 { +// xmr_swap_amount, +// btc_swap_amount, +// a: a.clone(), +// B: b.public(), +// s_a, +// S_b_monero: monero::PublicKey { +// point: S_b_monero.compress(), +// }, +// v_a, +// redeem_address: alice_bitcoin_wallet.new_address().await.unwrap(), +// }; +// +// let bob = Bob3 { +// b, +// A: a.public(), +// s_b, +// xmr_swap_amount, +// btc_swap_amount, +// tx_lock, +// S: S_b, +// S_a_bitcoin: swap::bitcoin::PublicKey::from(S_b_bitcoin), +// alice_redeem_address: +// bob_bitcoin_wallet.new_address().await.unwrap(), v: v_b, +// }; +// +// let alice = alice.publish_xmr_lock(&alice_monero_wallet).await.unwrap(); +// +// // also publishes lock btc +// let bob = bob +// .watch_for_lock_xmr( +// &bob_monero_wallet, +// &bob_bitcoin_wallet, +// alice.transfer_proof.clone(), +// btc_redeem_address, +// ) +// .await +// .unwrap(); +// +// let alice = alice +// .watch_for_btc_lock(&alice_bitcoin_wallet) +// .await +// .unwrap(); +// +// let _ = alice +// .publish_btc_redeem(&alice_bitcoin_wallet, encsig) +// .await +// .unwrap(); +// +// let swap_id = Uuid::new_v4(); +// bob.redeem_xmr_when_btc_redeem_seen(&bob_bitcoin_wallet, +// &bob_monero_wallet, swap_id) .await +// .unwrap(); +// }