mirror of
https://github.com/comit-network/xmr-btc-swap.git
synced 2024-10-01 01:45:40 -04:00
Merge pull request #53 from D4nte/rishflab-automated
This commit is contained in:
commit
fa6b696c45
55
Cargo.lock
generated
55
Cargo.lock
generated
@ -124,6 +124,17 @@ dependencies = [
|
||||
"syn 1.0.48",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-recursion"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5444eec77a9ec2bfe4524139e09195862e981400c4358d3b760cae634e4c4ee"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.24",
|
||||
"quote 1.0.7",
|
||||
"syn 1.0.48",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-trait"
|
||||
version = "0.1.41"
|
||||
@ -241,6 +252,26 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitcoin-harness"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/d4nte/bitcoin-harness-rs?rev=2869620689f7e54bdb8ab3d1838560cb9bc8fd60#2869620689f7e54bdb8ab3d1838560cb9bc8fd60"
|
||||
dependencies = [
|
||||
"base64 0.12.3",
|
||||
"bitcoin",
|
||||
"bitcoincore-rpc-json",
|
||||
"futures",
|
||||
"hex 0.4.2",
|
||||
"reqwest",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"testcontainers",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"tracing",
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitcoin-harness"
|
||||
version = "0.1.0"
|
||||
@ -534,6 +565,21 @@ dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "conquer-once"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5cb45322099323eefa1b48850ce6c148f5b510894c531e038539f6370c887214"
|
||||
dependencies = [
|
||||
"conquer-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "conquer-util"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e763eef8846b13b380f37dfecda401770b0ca4e56e95170237bd7c25c7db3582"
|
||||
|
||||
[[package]]
|
||||
name = "const_fn"
|
||||
version = "0.4.3"
|
||||
@ -1975,10 +2021,8 @@ name = "monero-harness"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"curve25519-dalek 2.1.0",
|
||||
"digest_auth",
|
||||
"futures",
|
||||
"monero",
|
||||
"port_check",
|
||||
"rand 0.7.3",
|
||||
"reqwest",
|
||||
@ -3339,12 +3383,14 @@ name = "swap"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-recursion",
|
||||
"async-trait",
|
||||
"atty",
|
||||
"backoff",
|
||||
"base64 0.12.3",
|
||||
"bitcoin",
|
||||
"bitcoin-harness",
|
||||
"bitcoin-harness 0.1.0 (git+https://github.com/d4nte/bitcoin-harness-rs?rev=2869620689f7e54bdb8ab3d1838560cb9bc8fd60)",
|
||||
"conquer-once",
|
||||
"derivative",
|
||||
"ecdsa_fun",
|
||||
"futures",
|
||||
@ -4121,7 +4167,8 @@ dependencies = [
|
||||
"backoff",
|
||||
"base64 0.12.3",
|
||||
"bitcoin",
|
||||
"bitcoin-harness",
|
||||
"bitcoin-harness 0.1.0 (git+https://github.com/coblox/bitcoin-harness-rs?rev=3be644cd9512c157d3337a189298b8257ed54d04)",
|
||||
"conquer-once",
|
||||
"cross-curve-dleq",
|
||||
"curve25519-dalek 2.1.0",
|
||||
"ecdsa_fun",
|
||||
|
@ -13,7 +13,7 @@ atty = "0.2"
|
||||
backoff = { version = "0.2", features = ["tokio"] }
|
||||
base64 = "0.12"
|
||||
bitcoin = { version = "0.23", features = ["rand", "use-serde"] } # TODO: Upgrade other crates in this repo to use this version.
|
||||
bitcoin-harness = { git = "https://github.com/coblox/bitcoin-harness-rs", rev = "3be644cd9512c157d3337a189298b8257ed54d04" }
|
||||
bitcoin-harness = { git = "https://github.com/d4nte/bitcoin-harness-rs", rev = "2869620689f7e54bdb8ab3d1838560cb9bc8fd60" }
|
||||
conquer-once = "0.3"
|
||||
derivative = "2"
|
||||
ecdsa_fun = { git = "https://github.com/LLFourn/secp256kfun", rev = "510d48ef6a2b19805f7f5c70c598e5b03f668e7a", features = ["libsecp_compat", "serde", "serialization"] }
|
||||
|
@ -15,6 +15,7 @@ use libp2p::request_response::ResponseChannel;
|
||||
use sha2::Sha256;
|
||||
use std::{sync::Arc, time::Duration};
|
||||
use tokio::time::timeout;
|
||||
use tracing::trace;
|
||||
use xmr_btc::{
|
||||
alice,
|
||||
alice::{State0, State3},
|
||||
@ -23,13 +24,11 @@ use xmr_btc::{
|
||||
EncryptedSignature, GetRawTransaction, TransactionBlockHeight, TxCancel, TxLock, TxRefund,
|
||||
WaitForTransactionFinality, WatchForRawTransaction,
|
||||
},
|
||||
config::Config,
|
||||
cross_curve_dleq,
|
||||
monero::Transfer,
|
||||
};
|
||||
|
||||
// For each step, we are giving Bob 10 minutes to act.
|
||||
static BOB_TIME_TO_ACT: Lazy<Duration> = Lazy::new(|| Duration::from_secs(10 * 60));
|
||||
|
||||
// The maximum we assume we need to wait from the moment the monero transaction
|
||||
// is mined to the moment it reaches finality. We set 15 confirmations for now
|
||||
// (based on Kraken). 1.5 multiplier in case the blockchain is slower than
|
||||
@ -44,8 +43,10 @@ pub async fn negotiate(
|
||||
v_a: monero::PrivateViewKey,
|
||||
swarm: &mut Swarm,
|
||||
bitcoin_wallet: Arc<bitcoin::Wallet>,
|
||||
config: Config,
|
||||
) -> Result<(ResponseChannel<AliceToBob>, State3)> {
|
||||
let event = timeout(*BOB_TIME_TO_ACT, swarm.next())
|
||||
trace!("Starting negotiate");
|
||||
let event = timeout(config.bob_time_to_act, swarm.next())
|
||||
.await
|
||||
.context("Failed to receive dial connection from Bob")?;
|
||||
match event {
|
||||
@ -53,7 +54,7 @@ pub async fn negotiate(
|
||||
other => bail!("Unexpected event received: {:?}", other),
|
||||
}
|
||||
|
||||
let event = timeout(*BOB_TIME_TO_ACT, swarm.next())
|
||||
let event = timeout(config.bob_time_to_act, swarm.next())
|
||||
.await
|
||||
.context("Failed to receive amounts from Bob")?;
|
||||
let (btc, channel) = match event {
|
||||
@ -89,7 +90,7 @@ pub async fn negotiate(
|
||||
// TODO(Franck): Understand why this is needed.
|
||||
swarm.set_state0(state0.clone());
|
||||
|
||||
let event = timeout(*BOB_TIME_TO_ACT, swarm.next())
|
||||
let event = timeout(config.bob_time_to_act, swarm.next())
|
||||
.await
|
||||
.context("Failed to receive message 0 from Bob")?;
|
||||
let message0 = match event {
|
||||
@ -99,7 +100,7 @@ pub async fn negotiate(
|
||||
|
||||
let state1 = state0.receive(message0)?;
|
||||
|
||||
let event = timeout(*BOB_TIME_TO_ACT, swarm.next())
|
||||
let event = timeout(config.bob_time_to_act, swarm.next())
|
||||
.await
|
||||
.context("Failed to receive message 1 from Bob")?;
|
||||
let (msg, channel) = match event {
|
||||
@ -112,7 +113,7 @@ pub async fn negotiate(
|
||||
let message1 = state2.next_message();
|
||||
swarm.send_message1(channel, message1);
|
||||
|
||||
let event = timeout(*BOB_TIME_TO_ACT, swarm.next())
|
||||
let event = timeout(config.bob_time_to_act, swarm.next())
|
||||
.await
|
||||
.context("Failed to receive message 2 from Bob")?;
|
||||
let (msg, channel) = match event {
|
||||
@ -128,13 +129,14 @@ pub async fn negotiate(
|
||||
pub async fn wait_for_locked_bitcoin<W>(
|
||||
lock_bitcoin_txid: bitcoin::Txid,
|
||||
bitcoin_wallet: Arc<W>,
|
||||
config: Config,
|
||||
) -> Result<()>
|
||||
where
|
||||
W: WatchForRawTransaction + WaitForTransactionFinality,
|
||||
{
|
||||
// We assume we will see Bob's transaction in the mempool first.
|
||||
timeout(
|
||||
*BOB_TIME_TO_ACT,
|
||||
config.bob_time_to_act,
|
||||
bitcoin_wallet.watch_for_raw_transaction(lock_bitcoin_txid),
|
||||
)
|
||||
.await
|
||||
@ -142,7 +144,7 @@ where
|
||||
|
||||
// // We saw the transaction in the mempool, waiting for it to be confirmed.
|
||||
// bitcoin_wallet
|
||||
// .wait_for_transaction_finality(lock_bitcoin_txid)
|
||||
// .wait_for_transaction_finality(lock_bitcoin_txid, config)
|
||||
// .await;
|
||||
|
||||
Ok(())
|
||||
@ -225,17 +227,18 @@ pub fn build_bitcoin_redeem_transaction(
|
||||
pub async fn publish_bitcoin_redeem_transaction<W>(
|
||||
redeem_tx: bitcoin::Transaction,
|
||||
bitcoin_wallet: Arc<W>,
|
||||
config: Config,
|
||||
) -> Result<()>
|
||||
where
|
||||
W: BroadcastSignedTransaction + WaitForTransactionFinality,
|
||||
{
|
||||
let _tx_id = bitcoin_wallet
|
||||
let tx_id = bitcoin_wallet
|
||||
.broadcast_signed_transaction(redeem_tx)
|
||||
.await?;
|
||||
|
||||
// // TODO(Franck): Not sure if we wait for finality here or just mined
|
||||
// bitcoin_wallet.wait_for_transaction_finality(tx_id).await;
|
||||
Ok(())
|
||||
bitcoin_wallet
|
||||
.wait_for_transaction_finality(tx_id, config)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn publish_cancel_transaction<W>(
|
||||
@ -364,6 +367,7 @@ pub fn build_bitcoin_punish_transaction(
|
||||
pub async fn publish_bitcoin_punish_transaction<W>(
|
||||
punish_tx: bitcoin::Transaction,
|
||||
bitcoin_wallet: Arc<W>,
|
||||
config: Config,
|
||||
) -> Result<bitcoin::Txid>
|
||||
where
|
||||
W: BroadcastSignedTransaction + WaitForTransactionFinality,
|
||||
@ -372,8 +376,9 @@ where
|
||||
.broadcast_signed_transaction(punish_tx)
|
||||
.await?;
|
||||
|
||||
// todo: enable this once trait is implemented
|
||||
// bitcoin_wallet.wait_for_transaction_finality(txid).await;
|
||||
bitcoin_wallet
|
||||
.wait_for_transaction_finality(txid, config)
|
||||
.await?;
|
||||
|
||||
Ok(txid)
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ use std::sync::Arc;
|
||||
use xmr_btc::{
|
||||
alice::State3,
|
||||
bitcoin::{TransactionBlockHeight, TxCancel, TxRefund, WatchForRawTransaction},
|
||||
config::Config,
|
||||
cross_curve_dleq,
|
||||
monero::CreateWalletForOutput,
|
||||
};
|
||||
@ -92,6 +93,7 @@ pub async fn swap(
|
||||
mut swarm: Swarm,
|
||||
bitcoin_wallet: Arc<crate::bitcoin::Wallet>,
|
||||
monero_wallet: Arc<crate::monero::Wallet>,
|
||||
config: Config,
|
||||
) -> Result<AliceState> {
|
||||
match state {
|
||||
AliceState::Started {
|
||||
@ -100,8 +102,16 @@ pub async fn swap(
|
||||
s_a,
|
||||
v_a,
|
||||
} => {
|
||||
let (channel, state3) =
|
||||
negotiate(amounts, a, s_a, v_a, &mut swarm, bitcoin_wallet.clone()).await?;
|
||||
let (channel, state3) = negotiate(
|
||||
amounts,
|
||||
a,
|
||||
s_a,
|
||||
v_a,
|
||||
&mut swarm,
|
||||
bitcoin_wallet.clone(),
|
||||
config,
|
||||
)
|
||||
.await?;
|
||||
|
||||
swap(
|
||||
AliceState::Negotiated {
|
||||
@ -112,6 +122,7 @@ pub async fn swap(
|
||||
swarm,
|
||||
bitcoin_wallet,
|
||||
monero_wallet,
|
||||
config,
|
||||
)
|
||||
.await
|
||||
}
|
||||
@ -120,7 +131,8 @@ pub async fn swap(
|
||||
channel,
|
||||
amounts,
|
||||
} => {
|
||||
let _ = wait_for_locked_bitcoin(state3.tx_lock.txid(), bitcoin_wallet.clone()).await?;
|
||||
let _ = wait_for_locked_bitcoin(state3.tx_lock.txid(), bitcoin_wallet.clone(), config)
|
||||
.await?;
|
||||
|
||||
swap(
|
||||
AliceState::BtcLocked {
|
||||
@ -131,6 +143,7 @@ pub async fn swap(
|
||||
swarm,
|
||||
bitcoin_wallet,
|
||||
monero_wallet,
|
||||
config,
|
||||
)
|
||||
.await
|
||||
}
|
||||
@ -153,6 +166,7 @@ pub async fn swap(
|
||||
swarm,
|
||||
bitcoin_wallet,
|
||||
monero_wallet,
|
||||
config,
|
||||
)
|
||||
.await
|
||||
}
|
||||
@ -169,6 +183,7 @@ pub async fn swap(
|
||||
swarm,
|
||||
bitcoin_wallet,
|
||||
monero_wallet,
|
||||
config,
|
||||
)
|
||||
.await
|
||||
}
|
||||
@ -178,6 +193,7 @@ pub async fn swap(
|
||||
swarm,
|
||||
bitcoin_wallet,
|
||||
monero_wallet,
|
||||
config,
|
||||
)
|
||||
.await
|
||||
}
|
||||
@ -202,6 +218,7 @@ pub async fn swap(
|
||||
swarm,
|
||||
bitcoin_wallet,
|
||||
monero_wallet,
|
||||
config,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
@ -210,13 +227,15 @@ pub async fn swap(
|
||||
// TODO(Franck): Error handling is delicate here.
|
||||
// If Bob sees this transaction he can redeem Monero
|
||||
// e.g. If the Bitcoin node is down then the user needs to take action.
|
||||
publish_bitcoin_redeem_transaction(signed_tx_redeem, bitcoin_wallet.clone()).await?;
|
||||
publish_bitcoin_redeem_transaction(signed_tx_redeem, bitcoin_wallet.clone(), config)
|
||||
.await?;
|
||||
|
||||
swap(
|
||||
AliceState::BtcRedeemed,
|
||||
swarm,
|
||||
bitcoin_wallet,
|
||||
monero_wallet,
|
||||
config,
|
||||
)
|
||||
.await
|
||||
}
|
||||
@ -236,6 +255,7 @@ pub async fn swap(
|
||||
swarm,
|
||||
bitcoin_wallet,
|
||||
monero_wallet,
|
||||
config,
|
||||
)
|
||||
.await
|
||||
}
|
||||
@ -261,6 +281,7 @@ pub async fn swap(
|
||||
swarm,
|
||||
bitcoin_wallet.clone(),
|
||||
monero_wallet,
|
||||
config,
|
||||
)
|
||||
.await
|
||||
}
|
||||
@ -274,6 +295,7 @@ pub async fn swap(
|
||||
swarm,
|
||||
bitcoin_wallet.clone(),
|
||||
monero_wallet,
|
||||
config,
|
||||
)
|
||||
.await
|
||||
}
|
||||
@ -310,8 +332,11 @@ pub async fn swap(
|
||||
state3.B.clone(),
|
||||
)?;
|
||||
|
||||
let punish_tx_finalised =
|
||||
publish_bitcoin_punish_transaction(signed_tx_punish, bitcoin_wallet.clone());
|
||||
let punish_tx_finalised = publish_bitcoin_punish_transaction(
|
||||
signed_tx_punish,
|
||||
bitcoin_wallet.clone(),
|
||||
config,
|
||||
);
|
||||
|
||||
let refund_tx_seen = bitcoin_wallet.watch_for_raw_transaction(tx_refund.txid());
|
||||
|
||||
@ -325,6 +350,7 @@ pub async fn swap(
|
||||
swarm,
|
||||
bitcoin_wallet.clone(),
|
||||
monero_wallet,
|
||||
config,
|
||||
)
|
||||
.await
|
||||
}
|
||||
@ -338,6 +364,7 @@ pub async fn swap(
|
||||
swarm,
|
||||
bitcoin_wallet.clone(),
|
||||
monero_wallet,
|
||||
config,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
@ -6,9 +6,13 @@ use backoff::{backoff::Constant as ConstantBackoff, future::FutureOperation as _
|
||||
use bitcoin::util::psbt::PartiallySignedTransaction;
|
||||
use bitcoin_harness::bitcoind_rpc::PsbtBase64;
|
||||
use reqwest::Url;
|
||||
use xmr_btc::bitcoin::{
|
||||
BlockHeight, BroadcastSignedTransaction, BuildTxLockPsbt, SignTxLock, TransactionBlockHeight,
|
||||
WatchForRawTransaction,
|
||||
use tokio::time::interval;
|
||||
use xmr_btc::{
|
||||
bitcoin::{
|
||||
BlockHeight, BroadcastSignedTransaction, BuildTxLockPsbt, SignTxLock,
|
||||
TransactionBlockHeight, WatchForRawTransaction,
|
||||
},
|
||||
config::Config,
|
||||
};
|
||||
|
||||
pub use ::bitcoin::{Address, Transaction};
|
||||
@ -148,7 +152,23 @@ impl TransactionBlockHeight for Wallet {
|
||||
|
||||
#[async_trait]
|
||||
impl WaitForTransactionFinality for Wallet {
|
||||
async fn wait_for_transaction_finality(&self, _txid: Txid) {
|
||||
todo!()
|
||||
async fn wait_for_transaction_finality(&self, txid: Txid, config: Config) -> Result<()> {
|
||||
// TODO(Franck): This assumes that bitcoind runs with txindex=1
|
||||
|
||||
// Divide by 4 to not check too often yet still be aware of the new block early
|
||||
// on.
|
||||
let mut interval = interval(config.bitcoin_avg_block_time / 4);
|
||||
|
||||
loop {
|
||||
let tx = self.0.client.get_raw_transaction_verbose(txid).await?;
|
||||
if let Some(confirmations) = tx.confirmations {
|
||||
if confirmations >= config.bitcoin_finality_confirmations {
|
||||
break;
|
||||
}
|
||||
}
|
||||
interval.tick().await;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -202,11 +202,13 @@ async fn happy_path_recursive_executor() {
|
||||
};
|
||||
let alice_swarm =
|
||||
alice::new_swarm(alice_multiaddr.clone(), alice_transport, alice_behaviour).unwrap();
|
||||
let config = xmr_btc::config::Config::regtest();
|
||||
let alice_swap = alice::swap::swap(
|
||||
alice_state,
|
||||
alice_swarm,
|
||||
alice_btc_wallet.clone(),
|
||||
alice_xmr_wallet.clone(),
|
||||
config,
|
||||
);
|
||||
|
||||
let bob_db_dir = tempdir().unwrap();
|
||||
|
@ -10,6 +10,7 @@ edition = "2018"
|
||||
anyhow = "1"
|
||||
async-trait = "0.1"
|
||||
bitcoin = { version = "0.23", features = ["rand", "serde"] }
|
||||
conquer-once = "0.3"
|
||||
cross-curve-dleq = { git = "https://github.com/comit-network/cross-curve-dleq", rev = "a19608734da1e8803cb4c806022483df4e7d5588", features = ["serde"] }
|
||||
curve25519-dalek = "2"
|
||||
ecdsa_fun = { git = "https://github.com/LLFourn/secp256kfun", rev = "510d48ef6a2b19805f7f5c70c598e5b03f668e7a", features = ["libsecp_compat", "serde", "serialization"] }
|
||||
|
@ -1,5 +1,6 @@
|
||||
pub mod transactions;
|
||||
|
||||
use crate::config::Config;
|
||||
use anyhow::{anyhow, bail, Result};
|
||||
use async_trait::async_trait;
|
||||
use bitcoin::hashes::{hex::ToHex, Hash};
|
||||
@ -188,7 +189,7 @@ pub trait WatchForRawTransaction {
|
||||
|
||||
#[async_trait]
|
||||
pub trait WaitForTransactionFinality {
|
||||
async fn wait_for_transaction_finality(&self, txid: Txid);
|
||||
async fn wait_for_transaction_finality(&self, txid: Txid, config: Config) -> Result<()>;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
|
49
xmr-btc/src/config.rs
Normal file
49
xmr-btc/src/config.rs
Normal file
@ -0,0 +1,49 @@
|
||||
use conquer_once::Lazy;
|
||||
use std::time::Duration;
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct Config {
|
||||
pub bob_time_to_act: Duration,
|
||||
pub bitcoin_finality_confirmations: u32,
|
||||
pub bitcoin_avg_block_time: Duration,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
pub fn mainnet() -> Self {
|
||||
Self {
|
||||
bob_time_to_act: *mainnet::BOB_TIME_TO_ACT,
|
||||
bitcoin_finality_confirmations: mainnet::BITCOIN_FINALITY_CONFIRMATIONS,
|
||||
bitcoin_avg_block_time: *mainnet::BITCOIN_AVG_BLOCK_TIME,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn regtest() -> Self {
|
||||
Self {
|
||||
bob_time_to_act: *regtest::BOB_TIME_TO_ACT,
|
||||
bitcoin_finality_confirmations: regtest::BITCOIN_FINALITY_CONFIRMATIONS,
|
||||
bitcoin_avg_block_time: *regtest::BITCOIN_AVG_BLOCK_TIME,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mod mainnet {
|
||||
use super::*;
|
||||
|
||||
// For each step, we are giving Bob 10 minutes to act.
|
||||
pub static BOB_TIME_TO_ACT: Lazy<Duration> = Lazy::new(|| Duration::from_secs(10 * 60));
|
||||
|
||||
pub static BITCOIN_FINALITY_CONFIRMATIONS: u32 = 3;
|
||||
|
||||
pub static BITCOIN_AVG_BLOCK_TIME: Lazy<Duration> = Lazy::new(|| Duration::from_secs(10 * 60));
|
||||
}
|
||||
|
||||
mod regtest {
|
||||
use super::*;
|
||||
|
||||
// In test, set to 5 seconds to fail fast
|
||||
pub static BOB_TIME_TO_ACT: Lazy<Duration> = Lazy::new(|| Duration::from_secs(5));
|
||||
|
||||
pub static BITCOIN_FINALITY_CONFIRMATIONS: u32 = 1;
|
||||
|
||||
pub static BITCOIN_AVG_BLOCK_TIME: Lazy<Duration> = Lazy::new(|| Duration::from_secs(1));
|
||||
}
|
@ -48,6 +48,7 @@ mod utils {
|
||||
pub mod alice;
|
||||
pub mod bitcoin;
|
||||
pub mod bob;
|
||||
pub mod config;
|
||||
pub mod monero;
|
||||
pub mod serde;
|
||||
pub mod transport;
|
||||
|
Loading…
Reference in New Issue
Block a user