wowario 3 years ago
parent 4212504941
commit af0c7c5df8
No known key found for this signature in database
GPG Key ID: 24DCBE762DE9C111

@ -3,7 +3,7 @@ name = "swap"
version = "0.8.1"
authors = [ "The COMIT guys <hello@comit.network>" ]
edition = "2018"
description = "XMR/BTC trustless atomic swaps."
description = "WOW/BTC trustless atomic swaps."
[lib]
name = "swap"
@ -32,8 +32,8 @@ futures = { version = "0.3", default-features = false }
itertools = "0.10"
libp2p = { git = "https://github.com/comit-network/rust-libp2p", branch = "rendezvous", default-features = false, features = [ "tcp-tokio", "yamux", "mplex", "dns-tokio", "noise", "request-response", "websocket", "ping", "rendezvous" ] }
miniscript = { version = "5", features = [ "serde" ] }
monero = { version = "0.12", features = [ "serde_support" ] }
monero-rpc = { path = "../monero-rpc" }
wownero = { version = "0.12", features = [ "serde_support" ] }
wownero-rpc = { path = "../wownero-rpc" }
pem = "0.8"
proptest = "1"
qrcode = "0.12"
@ -78,7 +78,7 @@ bdk-testutils = { version = "0.4" }
bitcoin-harness = { git = "https://github.com/coblox/bitcoin-harness-rs" }
get-port = "3"
hyper = "0.14"
monero-harness = { path = "../monero-harness" }
wownero-harness = { path = "../wownero-harness" }
port_check = "0.1"
proptest = "1"
serde_cbor = "0.11"

@ -199,7 +199,7 @@ pub enum Command {
#[derive(structopt::StructOpt, Debug)]
#[structopt(
name = "asb",
about = "Automated Swap Backend for swapping XMR for BTC",
about = "Automated Swap Backend for swapping WOW for BTC",
author,
version = env!("VERGEN_GIT_SEMVER_LIGHTWEIGHT")
)]
@ -226,7 +226,7 @@ pub struct RawArguments {
}
#[derive(structopt::StructOpt, Debug)]
#[structopt(name = "xmr_btc-swap", about = "XMR BTC atomic swap")]
#[structopt(name = "wow_btc-swap", about = "WOW BTC atomic swap")]
pub enum RawCommand {
#[structopt(about = "Main command to run the ASB.")]
Start {
@ -249,7 +249,7 @@ pub enum RawCommand {
address: Address,
},
#[structopt(
about = "Prints the Bitcoin and Monero balance. Requires the monero-wallet-rpc to be running."
about = "Prints the Bitcoin and Wownero balance. Requires the wownero-wallet-rpc to be running."
)]
Balance,
#[structopt(about = "Contains sub-commands for recovering a swap manually.")]
@ -279,7 +279,7 @@ pub enum ManualRecovery {
cancel_params: RecoverCommandParams,
},
#[structopt(
about = "Publishes the Monero refund transaction. By default, a swap-state where the cancel transaction was already published will be enforced. This command requires the counterparty Bitcoin refund transaction and will error if it was not published yet. "
about = "Publishes the Wownero refund transaction. By default, a swap-state where the cancel transaction was already published will be enforced. This command requires the counterparty Bitcoin refund transaction and will error if it was not published yet. "
)]
Refund {
#[structopt(flatten)]
@ -292,7 +292,7 @@ pub enum ManualRecovery {
#[structopt(flatten)]
punish_params: RecoverCommandParams,
},
#[structopt(about = "Safely Abort requires the swap to be in a state prior to locking XMR.")]
#[structopt(about = "Safely Abort requires the swap to be in a state prior to locking WOW.")]
SafelyAbort {
#[structopt(
long = "swap-id",

@ -25,7 +25,7 @@ pub struct Defaults {
listen_address_tcp: Multiaddr,
listen_address_ws: Multiaddr,
electrum_rpc_url: Url,
monero_wallet_rpc_url: Url,
wownero_wallet_rpc_url: Url,
price_ticker_ws_url: Url,
bitcoin_confirmation_target: usize,
}
@ -40,7 +40,7 @@ impl GetDefaults for Testnet {
listen_address_tcp: Multiaddr::from_str("/ip4/0.0.0.0/tcp/9939")?,
listen_address_ws: Multiaddr::from_str("/ip4/0.0.0.0/tcp/9940/ws")?,
electrum_rpc_url: Url::parse("ssl://electrum.blockstream.info:60002")?,
monero_wallet_rpc_url: Url::parse("http://127.0.0.1:38083/json_rpc")?,
wownero_wallet_rpc_url: Url::parse("http://127.0.0.1:38083/json_rpc")?,
price_ticker_ws_url: Url::parse("wss://ws.kraken.com")?,
bitcoin_confirmation_target: 1,
};
@ -59,7 +59,7 @@ impl GetDefaults for Mainnet {
listen_address_tcp: Multiaddr::from_str("/ip4/0.0.0.0/tcp/9939")?,
listen_address_ws: Multiaddr::from_str("/ip4/0.0.0.0/tcp/9940/ws")?,
electrum_rpc_url: Url::parse("ssl://electrum.blockstream.info:50002")?,
monero_wallet_rpc_url: Url::parse("http://127.0.0.1:18083/json_rpc")?,
wownero_wallet_rpc_url: Url::parse("http://127.0.0.1:18083/json_rpc")?,
price_ticker_ws_url: Url::parse("wss://ws.kraken.com")?,
bitcoin_confirmation_target: 3,
};
@ -90,7 +90,7 @@ pub struct Config {
pub data: Data,
pub network: Network,
pub bitcoin: Bitcoin,
pub monero: Monero,
pub wownero: Wownero,
pub tor: TorConf,
pub maker: Maker,
}
@ -136,11 +136,11 @@ pub struct Bitcoin {
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct Monero {
pub struct Wownero {
pub wallet_rpc_url: Url,
pub finality_confirmations: Option<u64>,
#[serde(with = "crate::monero::network")]
pub network: monero::Network,
#[serde(with = "crate::wownero::network")]
pub network: wownero::Network,
}
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
@ -204,21 +204,21 @@ pub fn initial_setup(config_path: PathBuf, config: Config) -> Result<()> {
}
pub fn query_user_for_initial_config(testnet: bool) -> Result<Config> {
let (bitcoin_network, monero_network, defaults) = if testnet {
let (bitcoin_network, wownero_network, defaults) = if testnet {
tracing::info!("Running initial setup for testnet");
let bitcoin_network = bitcoin::Network::Testnet;
let monero_network = monero::Network::Stagenet;
let wownero_network = wownero::Network::Stagenet;
let defaults = Testnet::getConfigFileDefaults()?;
(bitcoin_network, monero_network, defaults)
(bitcoin_network, wownero_network, defaults)
} else {
tracing::info!("Running initial setup for mainnet");
let bitcoin_network = bitcoin::Network::Bitcoin;
let monero_network = monero::Network::Mainnet;
let wownero_network = wownero::Network::Mainnet;
let defaults = Mainnet::getConfigFileDefaults()?;
(bitcoin_network, monero_network, defaults)
(bitcoin_network, wownero_network, defaults)
};
println!();
@ -253,9 +253,9 @@ pub fn query_user_for_initial_config(testnet: bool) -> Result<Config> {
.default(defaults.electrum_rpc_url)
.interact_text()?;
let monero_wallet_rpc_url = Input::with_theme(&ColorfulTheme::default())
.with_prompt("Enter Monero Wallet RPC URL or hit enter to use default")
.default(defaults.monero_wallet_rpc_url)
let wownero_wallet_rpc_url = Input::with_theme(&ColorfulTheme::default())
.with_prompt("Enter Wownero Wallet RPC URL or hit enter to use default")
.default(defaults.wownero_wallet_rpc_url)
.interact_text()?;
let tor_control_port = Input::with_theme(&ColorfulTheme::default())
@ -313,10 +313,10 @@ pub fn query_user_for_initial_config(testnet: bool) -> Result<Config> {
finality_confirmations: None,
network: bitcoin_network,
},
monero: Monero {
wallet_rpc_url: monero_wallet_rpc_url,
wownero: Wownero {
wallet_rpc_url: wownero_wallet_rpc_url,
finality_confirmations: None,
network: monero_network,
network: wownero_network,
},
tor: TorConf {
control_port: tor_control_port,
@ -359,10 +359,10 @@ mod tests {
external_addresses: vec![],
},
monero: Monero {
wallet_rpc_url: defaults.monero_wallet_rpc_url,
wownero: Wownero {
wallet_rpc_url: defaults.wownero_wallet_rpc_url,
finality_confirmations: None,
network: monero::Network::Stagenet,
network: wownero::Network::Stagenet,
},
tor: Default::default(),
maker: Maker {
@ -402,10 +402,10 @@ mod tests {
external_addresses: vec![],
},
monero: Monero {
wallet_rpc_url: defaults.monero_wallet_rpc_url,
wownero: Wownero {
wallet_rpc_url: defaults.wownero_wallet_rpc_url,
finality_confirmations: None,
network: monero::Network::Mainnet,
network: wownero::Network::Mainnet,
},
tor: Default::default(),
maker: Maker {

@ -4,7 +4,7 @@ use crate::network::quote::BidQuote;
use crate::network::swap_setup::alice::WalletSnapshot;
use crate::network::transfer_proof;
use crate::protocol::alice::{AliceState, State3, Swap};
use crate::{bitcoin, env, kraken, monero};
use crate::{bitcoin, env, kraken, wownero};
use anyhow::{Context, Result};
use futures::future;
use futures::future::{BoxFuture, FutureExt};
@ -38,7 +38,7 @@ where
swarm: libp2p::Swarm<Behaviour<LR>>,
env_config: env::Config,
bitcoin_wallet: Arc<bitcoin::Wallet>,
monero_wallet: Arc<monero::Wallet>,
wownero_wallet: Arc<wownero::Wallet>,
db: Arc<Database>,
latest_rate: LR,
min_buy: bitcoin::Amount,
@ -70,7 +70,7 @@ where
swarm: Swarm<Behaviour<LR>>,
env_config: env::Config,
bitcoin_wallet: Arc<bitcoin::Wallet>,
monero_wallet: Arc<monero::Wallet>,
wownero_wallet: Arc<wownero::Wallet>,
db: Arc<Database>,
latest_rate: LR,
min_buy: bitcoin::Amount,
@ -82,7 +82,7 @@ where
swarm,
env_config,
bitcoin_wallet,
monero_wallet,
wownero_wallet,
db,
latest_rate,
swap_sender: swap_channel.sender,
@ -130,7 +130,7 @@ where
let swap = Swap {
event_loop_handle: handle,
bitcoin_wallet: self.bitcoin_wallet.clone(),
monero_wallet: self.monero_wallet.clone(),
wownero_wallet: self.wownero_wallet.clone(),
env_config: self.env_config,
db: self.db.clone(),
state: state.into(),
@ -159,7 +159,7 @@ where
}
};
let wallet_snapshot = match WalletSnapshot::capture(&self.bitcoin_wallet, &self.monero_wallet, btc).await {
let wallet_snapshot = match WalletSnapshot::capture(&self.bitcoin_wallet, &self.wownero_wallet, btc).await {
Ok(wallet_snapshot) => wallet_snapshot,
Err(error) => {
tracing::error!("Swap request will be ignored because we were unable to create wallet snapshot for swap: {:#}", error);
@ -341,7 +341,7 @@ where
let swap = Swap {
event_loop_handle: handle,
bitcoin_wallet: self.bitcoin_wallet.clone(),
monero_wallet: self.monero_wallet.clone(),
wownero_wallet: self.wownero_wallet.clone(),
env_config: self.env_config,
db: self.db.clone(),
state: initial_state,
@ -461,7 +461,7 @@ impl LatestRate for KrakenRate {
#[derive(Debug)]
pub struct EventLoopHandle {
recv_encrypted_signature: Option<bmrng::RequestReceiver<bitcoin::EncryptedSignature, ()>>,
send_transfer_proof: Option<bmrng::RequestSender<monero::TransferProof, ()>>,
send_transfer_proof: Option<bmrng::RequestSender<wownero::TransferProof, ()>>,
}
impl EventLoopHandle {
@ -480,7 +480,7 @@ impl EventLoopHandle {
Ok(tx_redeem_encsig)
}
pub async fn send_transfer_proof(&mut self, msg: monero::TransferProof) -> Result<()> {
pub async fn send_transfer_proof(&mut self, msg: wownero::TransferProof) -> Result<()> {
self.send_transfer_proof
.take()
.context("Transfer proof was already sent")?

@ -1,7 +1,7 @@
use crate::asb::event_loop::LatestRate;
use crate::env;
use crate::network::quote::BidQuote;
use crate::network::rendezvous::XmrBtcNamespace;
use crate::network::rendezvous::WowBtcNamespace;
use crate::network::swap_setup::alice;
use crate::network::swap_setup::alice::WalletSnapshot;
use crate::network::transport::authenticate_and_multiplex;
@ -98,7 +98,7 @@ pub mod behaviour {
}
}
/// A `NetworkBehaviour` that represents an XMR/BTC swap node as Alice.
/// A `NetworkBehaviour` that represents an WOW/BTC swap node as Alice.
#[derive(NetworkBehaviour)]
#[behaviour(out_event = "OutEvent", event_process = false)]
#[allow(missing_debug_implementations)]
@ -128,7 +128,7 @@ pub mod behaviour {
latest_rate: LR,
resume_only: bool,
env_config: env::Config,
rendezvous_params: Option<(identity::Keypair, PeerId, Multiaddr, XmrBtcNamespace)>,
rendezvous_params: Option<(identity::Keypair, PeerId, Multiaddr, WowBtcNamespace)>,
) -> Self {
Self {
rendezvous: libp2p::swarm::toggle::Toggle::from(rendezvous_params.map(
@ -193,7 +193,7 @@ pub mod rendezous {
inner: libp2p::rendezvous::Rendezvous,
rendezvous_point: Multiaddr,
rendezvous_peer_id: PeerId,
namespace: XmrBtcNamespace,
namespace: WowBtcNamespace,
registration_status: RegistrationStatus,
connection_status: ConnectionStatus,
registration_ttl: Option<u64>,
@ -204,7 +204,7 @@ pub mod rendezous {
identity: identity::Keypair,
rendezvous_peer_id: PeerId,
rendezvous_address: Multiaddr,
namespace: XmrBtcNamespace,
namespace: WowBtcNamespace,
registration_ttl: Option<u64>,
) -> Self {
Self {
@ -362,7 +362,7 @@ pub mod rendezous {
identity,
*rendezvous_node.local_peer_id(),
rendezvous_address,
XmrBtcNamespace::Testnet,
WowBtcNamespace::Testnet,
None,
)
});
@ -405,7 +405,7 @@ pub mod rendezous {
identity,
*rendezvous_node.local_peer_id(),
rendezvous_address,
XmrBtcNamespace::Testnet,
WowBtcNamespace::Testnet,
Some(5),
)
});

@ -1,10 +1,10 @@
use crate::{bitcoin, monero};
use crate::{bitcoin, wownero};
use anyhow::{Context, Result};
use rust_decimal::prelude::ToPrimitive;
use rust_decimal::Decimal;
use std::fmt::{Debug, Display, Formatter};
/// Represents the rate at which we are willing to trade 1 XMR.
/// Represents the rate at which we are willing to trade 1 WOW.
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Rate {
/// Represents the asking price from the market.
@ -25,7 +25,7 @@ impl Rate {
Self { ask, ask_spread }
}
/// Computes the asking price at which we are willing to sell 1 XMR.
/// Computes the asking price at which we are willing to sell 1 WOW.
///
/// This applies the spread to the market asking price.
pub fn ask(&self) -> Result<bitcoin::Amount> {
@ -43,12 +43,12 @@ impl Rate {
}
/// Calculate a sell quote for a given BTC amount.
pub fn sell_quote(&self, quote: bitcoin::Amount) -> Result<monero::Amount> {
pub fn sell_quote(&self, quote: bitcoin::Amount) -> Result<wownero::Amount> {
Self::quote(self.ask()?, quote)
}
fn quote(rate: bitcoin::Amount, quote: bitcoin::Amount) -> Result<monero::Amount> {
// quote (btc) = rate * base (xmr)
fn quote(rate: bitcoin::Amount, quote: bitcoin::Amount) -> Result<wownero::Amount> {
// quote (btc) = rate * base (wow)
// base = quote / rate
let quote_in_sats = quote.as_sat();
@ -60,16 +60,16 @@ impl Rate {
.checked_div(Decimal::from(bitcoin::Amount::ONE_BTC.as_sat()))
.context("Division overflow")?;
let base_in_xmr = quote_in_btc
let base_in_wow = quote_in_btc
.checked_div(rate_in_btc)
.context("Division overflow")?;
let base_in_piconero = base_in_xmr * Decimal::from(monero::Amount::ONE_XMR.as_piconero());
let base_in_piconero = base_in_wow * Decimal::from(wownero::Amount::ONE_WOW.as_piconero());
let base_in_piconero = base_in_piconero
.to_u64()
.context("Failed to fit piconero amount into a u64")?;
Ok(monero::Amount::from_piconero(base_in_piconero))
Ok(wownero::Amount::from_piconero(base_in_piconero))
}
}
@ -93,9 +93,9 @@ mod tests {
let btc_amount = bitcoin::Amount::from_btc(2.5).unwrap();
let xmr_amount = rate.sell_quote(btc_amount).unwrap();
let wow_amount = rate.sell_quote(btc_amount).unwrap();
assert_eq!(xmr_amount, monero::Amount::from_monero(1000.0).unwrap())
assert_eq!(wow_amount, wownero::Amount::from_wownero(1000.0).unwrap())
}
#[test]
@ -116,16 +116,16 @@ mod tests {
let rate_no_spread = Rate::new(asking_price, ZERO_SPREAD);
let rate_with_spread = Rate::new(asking_price, TWO_PERCENT);
let xmr_no_spread = rate_no_spread.sell_quote(bitcoin::Amount::ONE_BTC).unwrap();
let xmr_with_spread = rate_with_spread
let wow_no_spread = rate_no_spread.sell_quote(bitcoin::Amount::ONE_BTC).unwrap();
let wow_with_spread = rate_with_spread
.sell_quote(bitcoin::Amount::ONE_BTC)
.unwrap();
let xmr_factor =
xmr_no_spread.as_piconero_decimal() / xmr_with_spread.as_piconero_decimal() - ONE;
let wow_factor =
wow_no_spread.as_piconero_decimal() / wow_with_spread.as_piconero_decimal() - ONE;
assert!(xmr_with_spread < xmr_no_spread);
assert_eq!(xmr_factor.round_dp(8), TWO_PERCENT); // round to 8 decimal
assert!(wow_with_spread < wow_no_spread);
assert_eq!(wow_factor.round_dp(8), TWO_PERCENT); // round to 8 decimal
// places to show that
// it is really close
// to two percent

@ -19,20 +19,20 @@ pub async fn cancel(
) -> Result<Result<(Txid, AliceState), Error>> {
let state = db.get_state(swap_id)?.try_into_alice()?.into();
let (monero_wallet_restore_blockheight, transfer_proof, state3) = match state {
let (wownero_wallet_restore_blockheight, transfer_proof, state3) = match state {
// In case no XMR has been locked, move to Safely Aborted
// In case no WOW has been locked, move to Safely Aborted
AliceState::Started { .. }
| AliceState::BtcLockTransactionSeen { .. }
| AliceState::BtcLocked { .. } => bail!("Cannot cancel swap {} because it is in state {} where no XMR was locked.", swap_id, state),
| AliceState::BtcLocked { .. } => bail!("Cannot cancel swap {} because it is in state {} where no WOW was locked.", swap_id, state),
AliceState::XmrLockTransactionSent { monero_wallet_restore_blockheight, transfer_proof, state3, }
| AliceState::XmrLocked { monero_wallet_restore_blockheight, transfer_proof, state3 }
| AliceState::XmrLockTransferProofSent { monero_wallet_restore_blockheight, transfer_proof, state3 }
AliceState::WowLockTransactionSent { wownero_wallet_restore_blockheight, transfer_proof, state3, }
| AliceState::WowLocked { wownero_wallet_restore_blockheight, transfer_proof, state3 }
| AliceState::WowLockTransferProofSent { wownero_wallet_restore_blockheight, transfer_proof, state3 }
// in cancel mode we do not care about the fact that we could redeem, but always wait for cancellation (leading either refund or punish)
| AliceState::EncSigLearned { monero_wallet_restore_blockheight, transfer_proof, state3, .. }
| AliceState::CancelTimelockExpired { monero_wallet_restore_blockheight, transfer_proof, state3} => {
(monero_wallet_restore_blockheight, transfer_proof, state3)
| AliceState::EncSigLearned { wownero_wallet_restore_blockheight, transfer_proof, state3, .. }
| AliceState::CancelTimelockExpired { wownero_wallet_restore_blockheight, transfer_proof, state3} => {
(wownero_wallet_restore_blockheight, transfer_proof, state3)
}
// The redeem transaction was already published, it is not safe to cancel anymore
@ -45,7 +45,7 @@ pub async fn cancel(
// Alice already in final state
| AliceState::BtcRedeemed
| AliceState::XmrRefunded
| AliceState::WowRefunded
| AliceState::BtcPunished
| AliceState::SafelyAborted => bail!("Swap is is in state {} which is not cancelable", state),
};
@ -69,7 +69,7 @@ pub async fn cancel(
};
let state = AliceState::BtcCancelled {
monero_wallet_restore_blockheight,
wownero_wallet_restore_blockheight,
transfer_proof,
state3,
};

@ -32,15 +32,15 @@ pub async fn punish(
let state3 = if force {
match state {
// In case no XMR has been locked, move to Safely Aborted
// In case no WOW has been locked, move to Safely Aborted
AliceState::Started { .. } => bail!(Error::NoBtcLocked(state)),
// Punish potentially possible (no knowledge of cancel transaction)
AliceState::BtcLockTransactionSeen { state3 }
| AliceState::BtcLocked { state3, .. }
| AliceState::XmrLockTransactionSent {state3, ..}
| AliceState::XmrLocked {state3, ..}
| AliceState::XmrLockTransferProofSent {state3, ..}
| AliceState::WowLockTransactionSent {state3, ..}
| AliceState::WowLocked {state3, ..}
| AliceState::WowLockTransferProofSent {state3, ..}
| AliceState::EncSigLearned {state3, ..}
| AliceState::CancelTimelockExpired {state3, ..}
@ -55,7 +55,7 @@ pub async fn punish(
| AliceState::BtcRefunded {..}
// Alice already in final state
| AliceState::BtcRedeemed
| AliceState::XmrRefunded
| AliceState::WowRefunded
| AliceState::BtcPunished
| AliceState::SafelyAborted => bail!(Error::SwapNotPunishable(state)),
}
@ -71,7 +71,7 @@ pub async fn punish(
AliceState::BtcRefunded { .. }
| AliceState::BtcRedeemed
| AliceState::XmrRefunded
| AliceState::WowRefunded
| AliceState::BtcPunished
| AliceState::SafelyAborted => bail!(Error::SwapNotPunishable(state)),

@ -86,15 +86,15 @@ pub async fn redeem(
AliceState::Started { .. }
| AliceState::BtcLockTransactionSeen { .. }
| AliceState::BtcLocked { .. }
| AliceState::XmrLockTransactionSent { .. }
| AliceState::XmrLocked { .. }
| AliceState::XmrLockTransferProofSent { .. }
| AliceState::WowLockTransactionSent { .. }
| AliceState::WowLocked { .. }
| AliceState::WowLockTransferProofSent { .. }
| AliceState::CancelTimelockExpired { .. }
| AliceState::BtcCancelled { .. }
| AliceState::BtcRefunded { .. }
| AliceState::BtcPunishable { .. }
| AliceState::BtcRedeemed
| AliceState::XmrRefunded
| AliceState::WowRefunded
| AliceState::BtcPunished
| AliceState::SafelyAborted => bail!(
"Cannot redeem swap {} because it is in state {} which cannot be manually redeemed",

@ -1,6 +1,6 @@
use crate::bitcoin::{self};
use crate::database::{Database, Swap};
use crate::monero;
use crate::wownero;
use crate::protocol::alice::AliceState;
use anyhow::{bail, Result};
use libp2p::PeerId;
@ -19,8 +19,8 @@ pub enum Error {
// Errors indicating that the swap cannot be refunded because because it is in a abort/final
// state
#[error("Swap is in state {0} where no XMR was locked. Try aborting instead.")]
NoXmrLocked(AliceState),
#[error("Swap is in state {0} where no WOW was locked. Try aborting instead.")]
NoWowLocked(AliceState),
#[error("Swap is in state {0} which is not refundable")]
SwapNotRefundable(AliceState),
}
@ -28,67 +28,67 @@ pub enum Error {
pub async fn refund(
swap_id: Uuid,
bitcoin_wallet: Arc<bitcoin::Wallet>,
monero_wallet: Arc<monero::Wallet>,
wownero_wallet: Arc<wownero::Wallet>,
db: Arc<Database>,
force: bool,
) -> Result<Result<AliceState, Error>> {
let state = db.get_state(swap_id)?.try_into_alice()?.into();
let (monero_wallet_restore_blockheight, transfer_proof, state3) = if force {
let (wownero_wallet_restore_blockheight, transfer_proof, state3) = if force {
match state {
// In case no XMR has been locked, move to Safely Aborted
// In case no WOW has been locked, move to Safely Aborted
AliceState::Started { .. }
| AliceState::BtcLockTransactionSeen { .. }
| AliceState::BtcLocked { .. } => bail!(Error::NoXmrLocked(state)),
| AliceState::BtcLocked { .. } => bail!(Error::NoWowLocked(state)),
// Refund potentially possible (no knowledge of cancel transaction)
AliceState::XmrLockTransactionSent { monero_wallet_restore_blockheight, transfer_proof, state3, }
| AliceState::XmrLocked { monero_wallet_restore_blockheight, transfer_proof, state3 }
| AliceState::XmrLockTransferProofSent { monero_wallet_restore_blockheight, transfer_proof, state3 }
| AliceState::EncSigLearned { monero_wallet_restore_blockheight, transfer_proof, state3, .. }
| AliceState::CancelTimelockExpired { monero_wallet_restore_blockheight, transfer_proof, state3 }
AliceState::WowLockTransactionSent { wownero_wallet_restore_blockheight, transfer_proof, state3, }
| AliceState::WowLocked { wownero_wallet_restore_blockheight, transfer_proof, state3 }
| AliceState::WowLockTransferProofSent { wownero_wallet_restore_blockheight, transfer_proof, state3 }
| AliceState::EncSigLearned { wownero_wallet_restore_blockheight, transfer_proof, state3, .. }
| AliceState::CancelTimelockExpired { wownero_wallet_restore_blockheight, transfer_proof, state3 }
// Refund possible due to cancel transaction already being published
| AliceState::BtcCancelled { monero_wallet_restore_blockheight, transfer_proof, state3 }
| AliceState::BtcRefunded { monero_wallet_restore_blockheight, transfer_proof, state3, .. }
| AliceState::BtcPunishable { monero_wallet_restore_blockheight, transfer_proof, state3, .. } => {
(monero_wallet_restore_blockheight, transfer_proof, state3)
| AliceState::BtcCancelled { wownero_wallet_restore_blockheight, transfer_proof, state3 }
| AliceState::BtcRefunded { wownero_wallet_restore_blockheight, transfer_proof, state3, .. }
| AliceState::BtcPunishable { wownero_wallet_restore_blockheight, transfer_proof, state3, .. } => {
(wownero_wallet_restore_blockheight, transfer_proof, state3)
}
// Alice already in final state
AliceState::BtcRedeemTransactionPublished { .. }
| AliceState::BtcRedeemed
| AliceState::XmrRefunded
| AliceState::WowRefunded
| AliceState::BtcPunished
| AliceState::SafelyAborted => bail!(Error::SwapNotRefundable(state)),
}
} else {
match state {
AliceState::Started { .. } | AliceState::BtcLocked { .. } => {
bail!(Error::NoXmrLocked(state))
bail!(Error::NoWowLocked(state))
}
AliceState::BtcCancelled {
monero_wallet_restore_blockheight,
wownero_wallet_restore_blockheight,
transfer_proof,
state3,
}
| AliceState::BtcRefunded {
monero_wallet_restore_blockheight,
wownero_wallet_restore_blockheight,
transfer_proof,
state3,
..
}
| AliceState::BtcPunishable {
monero_wallet_restore_blockheight,
wownero_wallet_restore_blockheight,
transfer_proof,
state3,
..
} => (monero_wallet_restore_blockheight, transfer_proof, state3),
} => (wownero_wallet_restore_blockheight, transfer_proof, state3),
AliceState::BtcRedeemed
| AliceState::XmrRefunded
| AliceState::WowRefunded
| AliceState::BtcPunished
| AliceState::SafelyAborted => bail!(Error::SwapNotRefundable(state)),
@ -101,24 +101,24 @@ pub async fn refund(
let spend_key = if let Ok(published_refund_tx) =
state3.fetch_tx_refund(bitcoin_wallet.as_ref()).await
{
tracing::debug!(%swap_id, "Bitcoin refund transaction found, extracting key to refund Monero");
state3.extract_monero_private_key(published_refund_tx)?
tracing::debug!(%swap_id, "Bitcoin refund transaction found, extracting key to refund Wownero");
state3.extract_wownero_private_key(published_refund_tx)?
} else {
let bob_peer_id = db.get_peer_id(swap_id)?;
return Ok(Err(Error::RefundTransactionNotPublishedYet(bob_peer_id)));
};
state3
.refund_xmr(
&monero_wallet,
monero_wallet_restore_blockheight,
.refund_wow(
&wownero_wallet,
wownero_wallet_restore_blockheight,
swap_id.to_string(),
spend_key,
transfer_proof,
)
.await?;
let state = AliceState::XmrRefunded;
let state = AliceState::WowRefunded;
let db_state = (&state).into();
db.insert_latest_state(swap_id, Swap::Alice(db_state))
.await?;

@ -20,9 +20,9 @@ pub async fn safely_abort(swap_id: Uuid, db: Arc<Database>) -> Result<AliceState
Ok(state)
}
AliceState::XmrLockTransactionSent { .. }
| AliceState::XmrLocked { .. }
| AliceState::XmrLockTransferProofSent { .. }
AliceState::WowLockTransactionSent { .. }
| AliceState::WowLocked { .. }
| AliceState::WowLockTransferProofSent { .. }
| AliceState::EncSigLearned { .. }
| AliceState::BtcRedeemTransactionPublished { .. }
| AliceState::CancelTimelockExpired { .. }
@ -30,7 +30,7 @@ pub async fn safely_abort(swap_id: Uuid, db: Arc<Database>) -> Result<AliceState
| AliceState::BtcRefunded { .. }
| AliceState::BtcPunishable { .. }
| AliceState::BtcRedeemed
| AliceState::XmrRefunded
| AliceState::WowRefunded
| AliceState::BtcPunished
| AliceState::SafelyAborted => bail!(
"Cannot safely abort swap {} because it is in state {} which cannot be safely aborted",

@ -29,13 +29,13 @@ use swap::asb::config::{
};
use swap::asb::{cancel, punish, redeem, refund, safely_abort, EventLoop, Finality, KrakenRate};
use swap::database::Database;
use swap::monero::Amount;
use swap::network::rendezvous::XmrBtcNamespace;
use swap::wownero::Amount;
use swap::network::rendezvous::WowBtcNamespace;
use swap::network::swarm;
use swap::protocol::alice::run;
use swap::seed::Seed;
use swap::tor::AuthenticatedClient;
use swap::{asb, bitcoin, kraken, monero, tor};
use swap::{asb, bitcoin, kraken, wownero, tor};
use tracing_subscriber::filter::LevelFilter;
const DEFAULT_WALLET_NAME: &str = "asb-wallet";
@ -76,10 +76,10 @@ async fn main() -> Result<()> {
}
};
if config.monero.network != env_config.monero_network {
if config.wownero.network != env_config.wownero_network {
bail!(format!(
"Expected monero network in config file to be {:?} but was {:?}",
env_config.monero_network, config.monero.network
"Expected wownero network in config file to be {:?} but was {:?}",
env_config.wownero_network, config.wownero.network
));
}
if config.bitcoin.network != env_config.bitcoin_network {
@ -101,20 +101,20 @@ async fn main() -> Result<()> {
Command::Start { resume_only } => {
let bitcoin_wallet = init_bitcoin_wallet(&config, &seed, env_config).await?;
let monero_wallet = init_monero_wallet(&config, env_config).await?;
let wownero_wallet = init_wownero_wallet(&config, env_config).await?;
let bitcoin_balance = bitcoin_wallet.balance().await?;
tracing::info!(%bitcoin_balance, "Initialized Bitcoin wallet");
let monero_balance = monero_wallet.get_balance().await?;
if monero_balance == Amount::ZERO {
let monero_address = monero_wallet.get_main_address();
let wownero_balance = wownero_wallet.get_balance().await?;
if wownero_balance == Amount::ZERO {
let wownero_address = wownero_wallet.get_main_address();
tracing::warn!(
%monero_address,
"The Monero balance is 0, make sure to deposit funds at",
%wownero_address,
"The Wownero balance is 0, make sure to deposit funds at",
)
} else {
tracing::info!(%monero_balance, "Initialized Monero wallet");
tracing::info!(%wownero_balance, "Initialized Wownero wallet");
}
let kraken_price_updates = kraken::connect(config.maker.price_ticker_ws_url.clone())?;
@ -148,9 +148,9 @@ async fn main() -> Result<()> {
(
rendezvous_point,
if testnet {
XmrBtcNamespace::Testnet
WowBtcNamespace::Testnet
} else {
XmrBtcNamespace::Mainnet
WowBtcNamespace::Mainnet
},
)
}),
@ -175,7 +175,7 @@ async fn main() -> Result<()> {
swarm,
env_config,
Arc::new(bitcoin_wallet),
Arc::new(monero_wallet),
Arc::new(wownero_wallet),
Arc::new(db),
kraken_rate.clone(),
config.maker.min_buy_btc,
@ -234,14 +234,14 @@ async fn main() -> Result<()> {
}
Command::Balance => {
let bitcoin_wallet = init_bitcoin_wallet(&config, &seed, env_config).await?;
let monero_wallet = init_monero_wallet(&config, env_config).await?;
let wownero_wallet = init_wownero_wallet(&config, env_config).await?;
let bitcoin_balance = bitcoin_wallet.balance().await?;
let monero_balance = monero_wallet.get_balance().await?;
let wownero_balance = wownero_wallet.get_balance().await?;
tracing::info!(
%bitcoin_balance,
%monero_balance,
%wownero_balance,
"Current balance");
}
Command::Cancel { swap_id, force } => {
@ -254,18 +254,18 @@ async fn main() -> Result<()> {
}
Command::Refund { swap_id, force } => {
let bitcoin_wallet = init_bitcoin_wallet(&config, &seed, env_config).await?;
let monero_wallet = init_monero_wallet(&config, env_config).await?;
let wownero_wallet = init_wownero_wallet(&config, env_config).await?;
refund(
swap_id,
Arc::new(bitcoin_wallet),
Arc::new(monero_wallet),
Arc::new(wownero_wallet),
Arc::new(db),
force,
)
.await??;
tracing::info!("Monero successfully refunded");
tracing::info!("Wownero successfully refunded");
}
Command::Punish { swap_id, force } => {
let bitcoin_wallet = init_bitcoin_wallet(&config, &seed, env_config).await?;
@ -326,13 +326,13 @@ async fn init_bitcoin_wallet(
Ok(wallet)
}
async fn init_monero_wallet(
async fn init_wownero_wallet(
config: &Config,
env_config: swap::env::Config,
) -> Result<monero::Wallet> {
tracing::debug!("Opening Monero wallet");
let wallet = monero::Wallet::open_or_create(
config.monero.wallet_rpc_url.clone(),
) -> Result<wownero::Wallet> {
tracing::debug!("Opening Wownero wallet");
let wallet = wownero::Wallet::open_or_create(
config.wownero.wallet_rpc_url.clone(),
DEFAULT_WALLET_NAME.to_string(),
env_config,
)

@ -33,7 +33,7 @@ use swap::network::swarm;
use swap::protocol::bob;
use swap::protocol::bob::Swap;
use swap::seed::Seed;
use swap::{bitcoin, cli, monero};
use swap::{bitcoin, cli, wownero};
use url::Url;
use uuid::Uuid;
@ -54,13 +54,13 @@ async fn main() -> Result<()> {
};
match cmd {
Command::BuyXmr {
Command::BuyWow {
seller,
bitcoin_electrum_rpc_url,
bitcoin_target_block,
bitcoin_change_address,
monero_receive_address,
monero_daemon_address,
wownero_receive_address,
wownero_daemon_address,
tor_socks5_port,
} => {
let swap_id = Uuid::new_v4();
@ -79,8 +79,8 @@ async fn main() -> Result<()> {
bitcoin_target_block,
)
.await?;
let (monero_wallet, _process) =
init_monero_wallet(data_dir, monero_daemon_address, env_config).await?;
let (wownero_wallet, _process) =
init_wownero_wallet(data_dir, wownero_daemon_address, env_config).await?;
let bitcoin_wallet = Arc::new(bitcoin_wallet);
let seller_peer_id = seller
@ -113,17 +113,17 @@ async fn main() -> Result<()> {
tracing::info!(%amount, %fees, %swap_id, "Starting new swap");
db.insert_peer_id(swap_id, seller_peer_id).await?;
db.insert_monero_address(swap_id, monero_receive_address)
db.insert_wownero_address(swap_id, wownero_receive_address)
.await?;
let swap = Swap::new(
db,
swap_id,
bitcoin_wallet,
Arc::new(monero_wallet),
Arc::new(wownero_wallet),
env_config,
event_loop_handle,
monero_receive_address,
wownero_receive_address,
bitcoin_change_address,
amount,
);
@ -156,7 +156,7 @@ async fn main() -> Result<()> {
swap_id,
bitcoin_electrum_rpc_url,
bitcoin_target_block,
monero_daemon_address,
wownero_daemon_address,
tor_socks5_port,
} => {
cli::tracing::init(debug, json, data_dir.join("logs"), Some(swap_id))?;
@ -173,8 +173,8 @@ async fn main() -> Result<()> {
bitcoin_target_block,
)
.await?;
let (monero_wallet, _process) =
init_monero_wallet(data_dir, monero_daemon_address, env_config).await?;
let (wownero_wallet, _process) =
init_wownero_wallet(data_dir, wownero_daemon_address, env_config).await?;
let bitcoin_wallet = Arc::new(bitcoin_wallet);
let seller_peer_id = db.get_peer_id(swap_id)?;
@ -196,15 +196,15 @@ async fn main() -> Result<()> {
EventLoop::new(swap_id, swarm, seller_peer_id, env_config)?;
let handle = tokio::spawn(event_loop.run());
let monero_receive_address = db.get_monero_address(swap_id)?;
let wownero_receive_address = db.get_wownero_address(swap_id)?;
let swap = Swap::from_db(
db,
swap_id,
bitcoin_wallet,
Arc::new(monero_wallet),
Arc::new(wownero_wallet),
env_config,
event_loop_handle,
monero_receive_address,
wownero_receive_address,
)?;
tokio::select! {
@ -365,29 +365,29 @@ async fn init_bitcoin_wallet(
Ok(wallet)
}
async fn init_monero_wallet(
async fn init_wownero_wallet(
data_dir: PathBuf,
monero_daemon_address: String,
wownero_daemon_address: String,
env_config: Config,
) -> Result<(monero::Wallet, monero::WalletRpcProcess)> {
let network = env_config.monero_network;
) -> Result<(wownero::Wallet, wownero::WalletRpcProcess)> {
let network = env_config.wownero_network;
const MONERO_BLOCKCHAIN_MONITORING_WALLET_NAME: &str = "swap-tool-blockchain-monitoring-wallet";
const WOWNERO_BLOCKCHAIN_MONITORING_WALLET_NAME: &str = "swap-tool-blockchain-monitoring-wallet";
let monero_wallet_rpc = monero::WalletRpc::new(data_dir.join("monero")).await?;
let wownero_wallet_rpc = wownero::WalletRpc::new(data_dir.join("wownero")).await?;
let monero_wallet_rpc_process = monero_wallet_rpc
.run(network, monero_daemon_address.as_str())
let wownero_wallet_rpc_process = wownero_wallet_rpc
.run(network, wownero_daemon_address.as_str())
.await?;
let monero_wallet = monero::Wallet::open_or_create(
monero_wallet_rpc_process.endpoint(),
MONERO_BLOCKCHAIN_MONITORING_WALLET_NAME.to_string(),
let wownero_wallet = wownero::Wallet::open_or_create(
wownero_wallet_rpc_process.endpoint(),
WOWNERO_BLOCKCHAIN_MONITORING_WALLET_NAME.to_string(),
env_config,
)
.await?;
Ok((monero_wallet, monero_wallet_rpc_process))
Ok((wownero_wallet, wownero_wallet_rpc_process))
}
fn qr_code(value: &impl ToString) -> Result<String> {

@ -87,15 +87,15 @@ impl SecretKey {
// TxRefund encsigning explanation:
//
// A and B, are the Bitcoin Public Keys which go on the joint output for
// TxLock_Bitcoin. S_a and S_b, are the Monero Public Keys which go on the
// joint output for TxLock_Monero
// TxLock_Bitcoin. S_a and S_b, are the Wownero Public Keys which go on the
// joint output for TxLock_Wownero
// tx_refund: multisig(A, B), published by bob
// bob can produce sig on B using b
// alice sends over an encrypted signature on A encrypted with S_b
// s_b is leaked to alice when bob publishes signed tx_refund allowing her to
// recover s_b: recover(encsig, S_b, sig_tx_refund) = s_b
// alice now has s_a and s_b and can refund monero
// alice now has s_a and s_b and can refund wownero
// self = a, Y = S_b, digest = tx_refund
pub fn encsign(&self, Y: PublicKey, digest: SigHash) -> EncryptedSignature {
@ -324,7 +324,7 @@ mod tests {
let bob_wallet = WalletBuilder::new(Amount::ONE_BTC.as_sat()).build();
let spending_fee = Amount::from_sat(1_000);
let btc_amount = Amount::from_sat(500_000);
let xmr_amount = crate::monero::Amount::from_piconero(10000);
let wow_amount = crate::wownero::Amount::from_piconero(10000);
let tx_redeem_fee = alice_wallet
.estimate_fee(TxRedeem::weight(), btc_amount)
@ -340,7 +340,7 @@ mod tests {
let config = Regtest::get_config();
let alice_state0 = alice::State0::new(
btc_amount,
xmr_amount,
wow_amount,
config,
redeem_address,
punish_address,
@ -353,11 +353,11 @@ mod tests {
Uuid::new_v4(),
&mut OsRng,
btc_amount,
xmr_amount,
wow_amount,
config.bitcoin_cancel_timelock,
config.bitcoin_punish_timelock,
bob_wallet.new_address().await.unwrap(),
config.monero_finality_confirmations,
config.wownero_finality_confirmations,
spending_fee,
spending_fee,
);
@ -382,7 +382,7 @@ mod tests {
let alice_state3 = alice_state2.receive(bob_message4).unwrap();
let (bob_state3, _tx_lock) = bob_state2.lock_btc().await.unwrap();
let bob_state4 = bob_state3.xmr_locked(monero_rpc::wallet::BlockHeight { height: 0 });
let bob_state4 = bob_state3.wow_locked(wownero_rpc::wallet::BlockHeight { height: 0 });
let encrypted_signature = bob_state4.tx_redeem_encsig();
let bob_state6 = bob_state4.cancel();

@ -3,7 +3,7 @@ use crate::bitcoin::{
verify_sig, Address, Amount, EmptyWitnessStack, NoInputs, NotThreeWitnesses, PublicKey,
TooManyInputs, Transaction, TxCancel,
};
use crate::{bitcoin, monero};
use crate::{bitcoin, wownero};
use ::bitcoin::util::bip143::SigHashCache;
use ::bitcoin::{Script, SigHash, SigHashType, Txid};
use anyhow::{bail, Context, Result};
@ -77,14 +77,14 @@ impl TxRefund {
Ok(tx_refund)
}
pub fn extract_monero_private_key(
pub fn extract_wownero_private_key(
&self,
published_refund_tx: bitcoin::Transaction,
s_a: monero::Scalar,
s_a: wownero::Scalar,
a: bitcoin::SecretKey,
S_b_bitcoin: bitcoin::PublicKey,
) -> Result<monero::PrivateKey> {
let s_a = monero::PrivateKey { scalar: s_a };
) -> Result<wownero::PrivateKey> {
let s_a = wownero::PrivateKey { scalar: s_a };
let tx_refund_sig = self
.extract_signature_by_key(published_refund_tx, a.public())
@ -92,9 +92,9 @@ impl TxRefund {
let tx_refund_encsig = a.encsign(S_b_bitcoin, self.digest());
let s_b = bitcoin::recover(S_b_bitcoin, tx_refund_sig, tx_refund_encsig)
.context("Failed to recover Monero secret key from Bitcoin signature")?;
.context("Failed to recover Wownero secret key from Bitcoin signature")?;
let s_b = monero::private_key_from_secp256k1_scalar(s_b.into());
let s_b = wownero::private_key_from_secp256k1_scalar(s_b.into());
let spend_key = s_a + s_b;

@ -20,7 +20,7 @@ mod tests {
use crate::cli::list_sellers::{Seller, Status};
use crate::network::quote;
use crate::network::quote::BidQuote;
use crate::network::rendezvous::XmrBtcNamespace;
use crate::network::rendezvous::WowBtcNamespace;
use crate::network::test::{new_swarm, SwarmExt};
use futures::StreamExt;
use libp2p::multiaddr::Protocol;
@ -33,7 +33,7 @@ mod tests {
#[tokio::test]
async fn list_sellers_should_report_all_registered_asbs_with_a_quote() {
let namespace = XmrBtcNamespace::Mainnet;
let namespace = WowBtcNamespace::Mainnet;
let (rendezvous_address, rendezvous_peer_id) = setup_rendezvous_point().await;
let expected_seller_1 =
setup_asb(rendezvous_peer_id, rendezvous_address.clone(), namespace).await;
@ -81,7 +81,7 @@ mod tests {
async fn setup_asb(
rendezvous_peer_id: PeerId,
rendezvous_address: Multiaddr,
namespace: XmrBtcNamespace,
namespace: WowBtcNamespace,
) -> Seller {
let static_quote = BidQuote {
price: bitcoin::Amount::from_sat(1337),

@ -54,7 +54,7 @@ impl OutEvent {
}
}
/// A `NetworkBehaviour` that represents an XMR/BTC swap node as Bob.
/// A `NetworkBehaviour` that represents an WOW/BTC swap node as Bob.
#[derive(NetworkBehaviour)]
#[behaviour(out_event = "OutEvent", event_process = false)]
#[allow(missing_debug_implementations)]

@ -21,8 +21,8 @@ pub async fn cancel(
let state6 = match state {
BobState::BtcLocked(state3) => state3.cancel(),
BobState::XmrLockProofReceived { state, .. } => state.cancel(),
BobState::XmrLocked(state4) => state4.cancel(),
BobState::WowLockProofReceived { state, .. } => state.cancel(),
BobState::WowLocked(state4) => state4.cancel(),
BobState::EncSigSent(state4) => state4.cancel(),
BobState::CancelTimelockExpired(state6) => state6,
BobState::Started { .. }
@ -30,7 +30,7 @@ pub async fn cancel(
| BobState::BtcRedeemed(_)
| BobState::BtcCancelled(_)
| BobState::BtcRefunded(_)
| BobState::XmrRedeemed { .. }
| BobState::WowRedeemed { .. }
| BobState::BtcPunished { .. }
| BobState::SafelyAborted => bail!(
"Cannot cancel swap {} because it is in state {} which is not refundable.",

@ -1,7 +1,7 @@
use crate::env::GetConfig;
use crate::fs::system_data_dir;
use crate::network::rendezvous::XmrBtcNamespace;
use crate::{env, monero};
use crate::network::rendezvous::WowBtcNamespace;
use crate::{env, wownero};
use anyhow::{Context, Result};
use bitcoin::AddressType;
use libp2p::core::Multiaddr;
@ -12,9 +12,9 @@ use structopt::{clap, StructOpt};
use url::Url;
use uuid::Uuid;
// See: https://moneroworld.com/
pub const DEFAULT_MONERO_DAEMON_ADDRESS: &str = "node.melo.tools:18081";
pub const DEFAULT_MONERO_DAEMON_ADDRESS_STAGENET: &str = "stagenet.melo.tools:38081";
// See: https://wowneroworld.com/
pub const DEFAULT_WOWNERO_DAEMON_ADDRESS: &str = "wownero.mooo.com:34568";
pub const DEFAULT_WOWNERO_DAEMON_ADDRESS_STAGENET: &str = "stagenet.melo.tools:38081";
// See: https://1209k.com/bitcoin-eye/ele.php?chain=btc
const DEFAULT_ELECTRUM_RPC_URL: &str = "ssl://electrum.blockstream.info:50002";
@ -68,19 +68,19 @@ where
let data = args.data;
let arguments = match args.cmd {
RawCommand::BuyXmr {
RawCommand::BuyWow {
seller: Seller { seller },
bitcoin,
bitcoin_change_address,
monero,
monero_receive_address,
wownero,
wownero_receive_address,
tor: Tor { tor_socks5_port },
} => {
let (bitcoin_electrum_rpc_url, bitcoin_target_block) =
bitcoin.apply_defaults(is_testnet)?;
let monero_daemon_address = monero.apply_defaults(is_testnet);
let monero_receive_address =
validate_monero_address(monero_receive_address, is_testnet)?;
let wownero_daemon_address = wownero.apply_defaults(is_testnet);
let wownero_receive_address =
validate_wownero_address(wownero_receive_address, is_testnet)?;
let bitcoin_change_address =
validate_bitcoin_address(bitcoin_change_address, is_testnet)?;
@ -89,13 +89,13 @@ where
debug,
json,
data_dir: data::data_dir_from(data, is_testnet)?,
cmd: Command::BuyXmr {
cmd: Command::BuyWow {
seller,
bitcoin_electrum_rpc_url,
bitcoin_target_block,
bitcoin_change_address,
monero_receive_address,
monero_daemon_address,
wownero_receive_address,
wownero_daemon_address,
tor_socks5_port,
},
}
@ -110,12 +110,12 @@ where
RawCommand::Resume {
swap_id: SwapId { swap_id },
bitcoin,
monero,
wownero,
tor: Tor { tor_socks5_port },
} => {
let (bitcoin_electrum_rpc_url, bitcoin_target_block) =
bitcoin.apply_defaults(is_testnet)?;
let monero_daemon_address = monero.apply_defaults(is_testnet);
let wownero_daemon_address = wownero.apply_defaults(is_testnet);
Arguments {
env_config: env_config_from(is_testnet),
@ -126,7 +126,7 @@ where
swap_id,
bitcoin_electrum_rpc_url,
bitcoin_target_block,
monero_daemon_address,
wownero_daemon_address,
tor_socks5_port,
},
}
@ -194,13 +194,13 @@ where
#[derive(Debug, PartialEq)]
pub enum Command {
BuyXmr {
BuyWow {
seller: Multiaddr,
bitcoin_electrum_rpc_url: Url,
bitcoin_target_block: usize,
bitcoin_change_address: bitcoin::Address,
monero_receive_address: monero::Address,
monero_daemon_address: String,
wownero_receive_address: wownero::Address,
wownero_daemon_address: String,
tor_socks5_port: u16,
},
History,
@ -208,7 +208,7 @@ pub enum Command {
swap_id: Uuid,
bitcoin_electrum_rpc_url: Url,
bitcoin_target_block: usize,
monero_daemon_address: String,
wownero_daemon_address: String,
tor_socks5_port: u16,
},
Cancel {
@ -225,7 +225,7 @@ pub enum Command {
},
ListSellers {
rendezvous_point: Multiaddr,
namespace: XmrBtcNamespace,
namespace: WowBtcNamespace,
tor_socks5_port: u16,
},
}
@ -233,7 +233,7 @@ pub enum Command {
#[derive(structopt::StructOpt, Debug)]
#[structopt(
name = "swap",
about = "CLI for swapping BTC for XMR",
about = "CLI for swapping BTC for WOW",
author,
version = env!("VERGEN_GIT_SEMVER_LIGHTWEIGHT")
)]
@ -268,8 +268,8 @@ struct RawArguments {
#[derive(structopt::StructOpt, Debug)]
enum RawCommand {
/// Start a BTC for XMR swap
BuyXmr {
/// Start a BTC for WOW swap
BuyWow {
#[structopt(flatten)]
seller: Seller,
@ -283,13 +283,13 @@ enum RawCommand {
bitcoin_change_address: bitcoin::Address,
#[structopt(flatten)]
monero: Monero,
wownero: Wownero,
#[structopt(long = "receive-address",
help = "The monero address where you would like to receive monero",
parse(try_from_str = parse_monero_address)
help = "The wownero address where you would like to receive wownero",
parse(try_from_str = parse_wownero_address)
)]
monero_receive_address: monero::Address,
wownero_receive_address: wownero::Address,
#[structopt(flatten)]
tor: Tor,
@ -305,7 +305,7 @@ enum RawCommand {
bitcoin: Bitcoin,
#[structopt(flatten)]
monero: Monero,
wownero: Wownero,
#[structopt(flatten)]
tor: Tor,
@ -346,22 +346,22 @@ enum RawCommand {
}
#[derive(structopt::StructOpt, Debug)]
struct Monero {
struct Wownero {
#[structopt(
long = "monero-daemon-address",
help = "Specify to connect to a monero daemon of your choice: <host>:<port>"
long = "wownero-daemon-address",
help = "Specify to connect to a wownero daemon of your choice: <host>:<port>"
)]
monero_daemon_address: Option<String>,
wownero_daemon_address: Option<String>,
}
impl Monero {
impl Wownero {
fn apply_defaults(self, testnet: bool) -> String {
if let Some(address) = self.monero_daemon_address {
if let Some(address) = self.wownero_daemon_address {
address
} else if testnet {
DEFAULT_MONERO_DAEMON_ADDRESS_STAGENET.to_string()
DEFAULT_WOWNERO_DAEMON_ADDRESS_STAGENET.to_string()
} else {
DEFAULT_MONERO_DAEMON_ADDRESS.to_string()
DEFAULT_WOWNERO_DAEMON_ADDRESS.to_string()
}
}
}
@ -447,11 +447,11 @@ mod data {
}
}
fn rendezvous_namespace_from(is_testnet: bool) -> XmrBtcNamespace {
fn rendezvous_namespace_from(is_testnet: bool) -> WowBtcNamespace {
if is_testnet {
XmrBtcNamespace::Testnet
WowBtcNamespace::Testnet
} else {
XmrBtcNamespace::Mainnet
WowBtcNamespace::Mainnet
}
}
@ -463,18 +463,18 @@ fn env_config_from(testnet: bool) -> env::Config {
}
}
fn validate_monero_address(
address: monero::Address,
fn validate_wownero_address(
address: wownero::Address,
testnet: bool,
) -> Result<monero::Address, MoneroAddressNetworkMismatch> {
) -> Result<wownero::Address, WowneroAddressNetworkMismatch> {
let expected_network = if testnet {
monero::Network::Stagenet
wownero::Network::Stagenet
} else {
monero::Network::Mainnet
wownero::Network::Mainnet
};
if address.network != expected_network {
return Err(MoneroAddressNetworkMismatch {
return Err(WowneroAddressNetworkMismatch {
expected: expected_network,
actual: address.network,
});
@ -505,20 +505,20 @@ fn validate_bitcoin_address(address: bitcoin::Address, testnet: bool) -> Result<
Ok(address)
}
fn parse_monero_address(s: &str) -> Result<monero::Address> {
monero::Address::from_str(s).with_context(|| {
fn parse_wownero_address(s: &str) -> Result<wownero::Address> {
wownero::Address::from_str(s).with_context(|| {
format!(
"Failed to parse {} as a monero address, please make sure it is a valid address",
"Failed to parse {} as a wownero address, please make sure it is a valid address",
s
)
})
}
#[derive(thiserror::Error, Debug, Clone, Copy, PartialEq)]
#[error("Invalid monero address provided, expected address on network {expected:?} but address provided is on {actual:?}")]
pub struct MoneroAddressNetworkMismatch {
expected: monero::Network,
actual: monero::Network,
#[error("Invalid wownero address provided, expected address on network {expected:?} but address provided is on {actual:?}")]
pub struct WowneroAddressNetworkMismatch {
expected: wownero::Network,
actual: wownero::Network,
}
#[cfg(test)]
@ -531,41 +531,41 @@ mod tests {
const TESTNET: &str = "testnet";
const MAINNET: &str = "mainnet";
const MONERO_STAGENET_ADDRESS: &str = "53gEuGZUhP9JMEBZoGaFNzhwEgiG7hwQdMCqFxiyiTeFPmkbt1mAoNybEUvYBKHcnrSgxnVWgZsTvRBaHBNXPa8tHiCU51a";
const WOWNERO_STAGENET_ADDRESS: &str = "53gEuGZUhP9JMEBZoGaFNzhwEgiG7hwQdMCqFxiyiTeFPmkbt1mAoNybEUvYBKHcnrSgxnVWgZsTvRBaHBNXPa8tHiCU51a";
const BITCOIN_TESTNET_ADDRESS: &str = "tb1qr3em6k3gfnyl8r7q0v7t4tlnyxzgxma3lressv";
const MONERO_MAINNET_ADDRESS: &str = "44Ato7HveWidJYUAVw5QffEcEtSH1DwzSP3FPPkHxNAS4LX9CqgucphTisH978FLHE34YNEx7FcbBfQLQUU8m3NUC4VqsRa";
const WOWNERO_MAINNET_ADDRESS: &str = "44Ato7HveWidJYUAVw5QffEcEtSH1DwzSP3FPPkHxNAS4LX9CqgucphTisH978FLHE34YNEx7FcbBfQLQUU8m3NUC4VqsRa";
const BITCOIN_MAINNET_ADDRESS: &str = "bc1qe4epnfklcaa0mun26yz5g8k24em5u9f92hy325";
const MULTI_ADDRESS: &str =
"/ip4/127.0.0.1/tcp/9939/p2p/12D3KooWCdMKjesXMJz1SiZ7HgotrxuqhQJbP5sgBm2BwP1cqThi";
const SWAP_ID: &str = "ea030832-3be9-454f-bb98-5ea9a788406b";
#[test]
fn given_buy_xmr_on_mainnet_then_defaults_to_mainnet() {
fn given_buy_wow_on_mainnet_then_defaults_to_mainnet() {
let raw_ars = vec![
BINARY_NAME,
"buy-xmr",
"buy-wow",
"--receive-address",
MONERO_MAINNET_ADDRESS,
WOWNERO_MAINNET_ADDRESS,
"--change-address",
BITCOIN_MAINNET_ADDRESS,
"--seller",
MULTI_ADDRESS,
];
let expected_args = ParseResult::Arguments(Arguments::buy_xmr_mainnet_defaults());
let expected_args = ParseResult::Arguments(Arguments::buy_wow_mainnet_defaults());
let args = parse_args_and_apply_defaults(raw_ars).unwrap();
assert_eq!(expected_args, args);
}
#[test]
fn given_buy_xmr_on_testnet_then_defaults_to_testnet() {
fn given_buy_wow_on_testnet_then_defaults_to_testnet() {
let raw_ars = vec![
BINARY_NAME,
"--testnet",
"buy-xmr",
"buy-wow",
"--receive-address",
MONERO_STAGENET_ADDRESS,
WOWNERO_STAGENET_ADDRESS,
"--change-address",
BITCOIN_TESTNET_ADDRESS,
"--seller",
@ -576,17 +576,17 @@ mod tests {
assert_eq!(
args,
ParseResult::Arguments(Arguments::buy_xmr_testnet_defaults())
ParseResult::Arguments(Arguments::buy_wow_testnet_defaults())
);
}
#[test]
fn given_buy_xmr_on_mainnet_with_testnet_address_then_fails() {
fn given_buy_wow_on_mainnet_with_testnet_address_then_fails() {
let raw_ars = vec![
BINARY_NAME,
"buy-xmr",
"buy-wow",
"--receive-address",
MONERO_STAGENET_ADDRESS,
WOWNERO_STAGENET_ADDRESS,
"--change-address",
BITCOIN_TESTNET_ADDRESS,
"--seller",
@ -596,22 +596,22 @@ mod tests {
let err = parse_args_and_apply_defaults(raw_ars).unwrap_err();
assert_eq!(
err.downcast_ref::<MoneroAddressNetworkMismatch>().unwrap(),
&MoneroAddressNetworkMismatch {
expected: monero::Network::Mainnet,
actual: monero::Network::Stagenet
err.downcast_ref::<WowneroAddressNetworkMismatch>().unwrap(),
&WowneroAddressNetworkMismatch {
expected: wownero::Network::Mainnet,
actual: wownero::Network::Stagenet
}
);
}
#[test]
fn given_buy_xmr_on_testnet_with_mainnet_address_then_fails() {
fn given_buy_wow_on_testnet_with_mainnet_address_then_fails() {
let raw_ars = vec![
BINARY_NAME,
"--testnet",
"buy-xmr",
"buy-wow",
"--receive-address",
MONERO_MAINNET_ADDRESS,
WOWNERO_MAINNET_ADDRESS,
"--change-address",
BITCOIN_MAINNET_ADDRESS,
"--seller",
@ -621,10 +621,10 @@ mod tests {
let err = parse_args_and_apply_defaults(raw_ars).unwrap_err();
assert_eq!(
err.downcast_ref::<MoneroAddressNetworkMismatch>().unwrap(),
&MoneroAddressNetworkMismatch {
expected: monero::Network::Stagenet,
actual: monero::Network::Mainnet
err.downcast_ref::<WowneroAddressNetworkMismatch>().unwrap(),
&WowneroAddressNetworkMismatch {
expected: wownero::Network::Stagenet,
actual: wownero::Network::Mainnet
}
);
}
@ -709,11 +709,11 @@ mod tests {
BINARY_NAME,
"--data-base-dir",
data_dir,
"buy-xmr",
"buy-wow",
"--change-address",
BITCOIN_MAINNET_ADDRESS,
"--receive-address",
MONERO_MAINNET_ADDRESS,
WOWNERO_MAINNET_ADDRESS,
"--seller",
MULTI_ADDRESS,
];
@ -723,7 +723,7 @@ mod tests {
assert_eq!(
args,
ParseResult::Arguments(
Arguments::buy_xmr_mainnet_defaults()
Arguments::buy_wow_mainnet_defaults()
.with_data_dir(PathBuf::from_str(data_dir).unwrap().join("mainnet"))
)
);
@ -733,11 +733,11 @@ mod tests {
"--testnet",
"--data-base-dir",
data_dir,
"buy-xmr",
"buy-wow",
"--change-address",
BITCOIN_TESTNET_ADDRESS,
"--receive-address",
MONERO_STAGENET_ADDRESS,
WOWNERO_STAGENET_ADDRESS,
"--seller",
MULTI_ADDRESS,
];
@ -747,7 +747,7 @@ mod tests {
assert_eq!(
args,
ParseResult::Arguments(
Arguments::buy_xmr_testnet_defaults()
Arguments::buy_wow_testnet_defaults()
.with_data_dir(PathBuf::from_str(data_dir).unwrap().join("testnet"))
)
);
@ -797,11 +797,11 @@ mod tests {
let raw_ars = vec![
BINARY_NAME,
"--debug",
"buy-xmr",
"buy-wow",
"--change-address",
BITCOIN_MAINNET_ADDRESS,
"--receive-address",
MONERO_MAINNET_ADDRESS,
WOWNERO_MAINNET_ADDRESS,
"--seller",
MULTI_ADDRESS,
];
@ -809,18 +809,18 @@ mod tests {
let args = parse_args_and_apply_defaults(raw_ars).unwrap();
assert_eq!(
args,
ParseResult::Arguments(Arguments::buy_xmr_mainnet_defaults().with_debug())
ParseResult::Arguments(Arguments::buy_wow_mainnet_defaults().with_debug())
);
let raw_ars = vec![
BINARY_NAME,
"--testnet",
"--debug",
"buy-xmr",
"buy-wow",
"--change-address",
BITCOIN_TESTNET_ADDRESS,
"--receive-address",
MONERO_STAGENET_ADDRESS,
WOWNERO_STAGENET_ADDRESS,
"--seller",
MULTI_ADDRESS,
];
@ -828,7 +828,7 @@ mod tests {
let args = parse_args_and_apply_defaults(raw_ars).unwrap();
assert_eq!(
args,
ParseResult::Arguments(Arguments::buy_xmr_testnet_defaults().with_debug())
ParseResult::Arguments(Arguments::buy_wow_testnet_defaults().with_debug())
);
let raw_ars = vec![BINARY_NAME, "--debug", "resume", "--swap-id", SWAP_ID];
@ -860,11 +860,11 @@ mod tests {
let raw_ars = vec![
BINARY_NAME,
"--json",
"buy-xmr",
"buy-wow",
"--change-address",
BITCOIN_MAINNET_ADDRESS,
"--receive-address",
MONERO_MAINNET_ADDRESS,
WOWNERO_MAINNET_ADDRESS,
"--seller",
MULTI_ADDRESS,
];
@ -872,18 +872,18 @@ mod tests {
let args = parse_args_and_apply_defaults(raw_ars).unwrap();
assert_eq!(
args,
ParseResult::Arguments(Arguments::buy_xmr_mainnet_defaults().with_json())
ParseResult::Arguments(Arguments::buy_wow_mainnet_defaults().with_json())
);
let raw_ars = vec![
BINARY_NAME,
"--testnet",
"--json",
"buy-xmr",
"buy-wow",
"--change-address",
BITCOIN_TESTNET_ADDRESS,
"--receive-address",
MONERO_STAGENET_ADDRESS,
WOWNERO_STAGENET_ADDRESS,
"--seller",
MULTI_ADDRESS,
];
@ -891,7 +891,7 @@ mod tests {
let args = parse_args_and_apply_defaults(raw_ars).unwrap();
assert_eq!(
args,
ParseResult::Arguments(Arguments::buy_xmr_testnet_defaults().with_json())
ParseResult::Arguments(Arguments::buy_wow_testnet_defaults().with_json())
);
let raw_ars = vec![BINARY_NAME, "--json", "resume", "--swap-id", SWAP_ID];
@ -922,11 +922,11 @@ mod tests {
fn only_bech32_addresses_mainnet_are_allowed() {
let raw_ars = vec![
BINARY_NAME,
"buy-xmr",
"buy-wow",
"--change-address",
"1A5btpLKZjgYm8R22rJAhdbTFVXgSRA2Mp",
"--receive-address",
MONERO_MAINNET_ADDRESS,
WOWNERO_MAINNET_ADDRESS,
"--seller",
MULTI_ADDRESS,
];
@ -938,11 +938,11 @@ mod tests {
let raw_ars = vec![
BINARY_NAME,
"buy-xmr",
"buy-wow",
"--change-address",
"36vn4mFhmTXn7YcNwELFPxTXhjorw2ppu2",
"--receive-address",
MONERO_MAINNET_ADDRESS,
WOWNERO_MAINNET_ADDRESS,
"--seller",
MULTI_ADDRESS,
];
@ -954,11 +954,11 @@ mod tests {
let raw_ars = vec![
BINARY_NAME,
"buy-xmr",
"buy-wow",
"--change-address",
"bc1qh4zjxrqe3trzg7s6m7y67q2jzrw3ru5mx3z7j3",
"--receive-address",
MONERO_MAINNET_ADDRESS,
WOWNERO_MAINNET_ADDRESS,
"--seller",
MULTI_ADDRESS,
];
@ -971,11 +971,11 @@ mod tests {
let raw_ars = vec![
BINARY_NAME,
"--testnet",
"buy-xmr",
"buy-wow",
"--change-address",
"n2czxyeFCQp9e8WRyGpy4oL4YfQAeKkkUH",
"--receive-address",
MONERO_STAGENET_ADDRESS,
WOWNERO_STAGENET_ADDRESS,
"--seller",
MULTI_ADDRESS,
];
@ -988,11 +988,11 @@ mod tests {
let raw_ars = vec![
BINARY_NAME,
"--testnet",
"buy-xmr",
"buy-wow",
"--change-address",
"2ND9a4xmQG89qEWG3ETRuytjKpLmGrW7Jvf",
"--receive-address",
MONERO_STAGENET_ADDRESS,
WOWNERO_STAGENET_ADDRESS,
"--seller",
MULTI_ADDRESS,
];
@ -1005,11 +1005,11 @@ mod tests {
let raw_ars = vec![
BINARY_NAME,
"--testnet",
"buy-xmr",
"buy-wow",
"--change-address",
"tb1q958vfh3wkdp232pktq8zzvmttyxeqnj80zkz3v",
"--receive-address",
MONERO_STAGENET_ADDRESS,
WOWNERO_STAGENET_ADDRESS,
"--seller",
MULTI_ADDRESS,
];
@ -1018,40 +1018,40 @@ mod tests {
}
impl Arguments {
pub fn buy_xmr_testnet_defaults() -> Self {
pub fn buy_wow_testnet_defaults() -> Self {
Self {
env_config: env::Testnet::get_config(),
debug: false,
json: false,
data_dir: data_dir_path_cli().join(TESTNET),
cmd: Command::BuyXmr {
cmd: Command::BuyWow {
seller: Multiaddr::from_str(MULTI_ADDRESS).unwrap(),
bitcoin_electrum_rpc_url: Url::from_str(DEFAULT_ELECTRUM_RPC_URL_TESTNET)
.unwrap(),
bitcoin_target_block: DEFAULT_BITCOIN_CONFIRMATION_TARGET_TESTNET,
bitcoin_change_address: BITCOIN_TESTNET_ADDRESS.parse().unwrap(),
monero_receive_address: monero::Address::from_str(MONERO_STAGENET_ADDRESS)
wownero_receive_address: wownero::Address::from_str(WOWNERO_STAGENET_ADDRESS)
.unwrap(),
monero_daemon_address: DEFAULT_MONERO_DAEMON_ADDRESS_STAGENET.to_string(),
wownero_daemon_address: DEFAULT_WOWNERO_DAEMON_ADDRESS_STAGENET.to_string(),
tor_socks5_port: DEFAULT_SOCKS5_PORT,
},
}
}
pub fn buy_xmr_mainnet_defaults() -> Self {
pub fn buy_wow_mainnet_defaults() -> Self {
Self {
env_config: env::Mainnet::get_config(),
debug: false,
json: false,
data_dir: data_dir_path_cli().join(MAINNET),
cmd: Command::BuyXmr {
cmd: Command::BuyWow {
seller: Multiaddr::from_str(MULTI_ADDRESS).unwrap(),
bitcoin_electrum_rpc_url: Url::from_str(DEFAULT_ELECTRUM_RPC_URL).unwrap(),
bitcoin_target_block: DEFAULT_BITCOIN_CONFIRMATION_TARGET,
bitcoin_change_address: BITCOIN_MAINNET_ADDRESS.parse().unwrap(),
monero_receive_address: monero::Address::from_str(MONERO_MAINNET_ADDRESS)
wownero_receive_address: wownero::Address::from_str(WOWNERO_MAINNET_ADDRESS)
.unwrap(),
monero_daemon_address: DEFAULT_MONERO_DAEMON_ADDRESS.to_string(),
wownero_daemon_address: DEFAULT_WOWNERO_DAEMON_ADDRESS.to_string(),
tor_socks5_port: DEFAULT_SOCKS5_PORT,
},
}
@ -1068,7 +1068,7 @@ mod tests {
bitcoin_electrum_rpc_url: Url::from_str(DEFAULT_ELECTRUM_RPC_URL_TESTNET)
.unwrap(),
bitcoin_target_block: DEFAULT_BITCOIN_CONFIRMATION_TARGET_TESTNET,
monero_daemon_address: DEFAULT_MONERO_DAEMON_ADDRESS_STAGENET.to_string(),
wownero_daemon_address: DEFAULT_WOWNERO_DAEMON_ADDRESS_STAGENET.to_string(),
tor_socks5_port: DEFAULT_SOCKS5_PORT,
},
}
@ -1084,7 +1084,7 @@ mod tests {
swap_id: Uuid::from_str(SWAP_ID).unwrap(),
bitcoin_electrum_rpc_url: Url::from_str(DEFAULT_ELECTRUM_RPC_URL).unwrap(),
bitcoin_target_block: DEFAULT_BITCOIN_CONFIRMATION_TARGET,
monero_daemon_address: DEFAULT_MONERO_DAEMON_ADDRESS.to_string(),
wownero_daemon_address: DEFAULT_WOWNERO_DAEMON_ADDRESS.to_string(),
tor_socks5_port: DEFAULT_SOCKS5_PORT,
},
}

@ -4,7 +4,7 @@ use crate::network::encrypted_signature;
use crate::network::quote::BidQuote;
use crate::network::swap_setup::bob::NewSwap;
use crate::protocol::bob::State2;
use crate::{env, monero};
use crate::{env, wownero};
use anyhow::{Context, Result};
use futures::future::{BoxFuture, OptionFuture};
use futures::{FutureExt, StreamExt};
@ -34,7 +34,7 @@ pub struct EventLoop {
inflight_swap_setup: Option<bmrng::Responder<Result<State2>>>,
/// The sender we will use to relay incoming transfer proofs.
transfer_proof: bmrng::RequestSender<monero::TransferProof, ()>,
transfer_proof: bmrng::RequestSender<wownero::TransferProof, ()>,
/// The future representing the successful handling of an incoming transfer
/// proof.
///
@ -217,7 +217,7 @@ impl EventLoop {
#[derive(Debug)]
pub struct EventLoopHandle {
swap_setup: bmrng::RequestSender<NewSwap, Result<State2>>,
transfer_proof: bmrng::RequestReceiver<monero::TransferProof, ()>,
transfer_proof: bmrng::RequestReceiver<wownero::TransferProof, ()>,
encrypted_signature: bmrng::RequestSender<EncryptedSignature, ()>,
quote: bmrng::RequestSender<(), BidQuote>,
env_config: env::Config,
@ -228,7 +228,7 @@ impl EventLoopHandle {
self.swap_setup.send_receive(swap).await?
}
pub async fn recv_transfer_proof(&mut self) -> Result<monero::TransferProof> {
pub async fn recv_transfer_proof(&mut self) -> Result<wownero::TransferProof> {
let (transfer_proof, responder) = self
.transfer_proof
.recv()

@ -1,5 +1,5 @@
use crate::network::quote::BidQuote;
use crate::network::rendezvous::XmrBtcNamespace;
use crate::network::rendezvous::WowBtcNamespace;
use crate::network::{quote, swarm};
use anyhow::{Context, Result};
use futures::StreamExt;
@ -24,7 +24,7 @@ use std::time::Duration;
pub async fn list_sellers(
rendezvous_node_peer_id: PeerId,
rendezvous_node_addr: Multiaddr,
namespace: XmrBtcNamespace,
namespace: WowBtcNamespace,
tor_socks5_port: u16,
identity: identity::Keypair,
) -> Result<Vec<Seller>> {
@ -116,7 +116,7 @@ struct EventLoop {
swarm: Swarm<Behaviour>,
rendezvous_peer_id: PeerId,
rendezvous_addr: Multiaddr,
namespace: XmrBtcNamespace,
namespace: WowBtcNamespace,
reachable_asb_address: HashMap<PeerId, Multiaddr>,
unreachable_asb_address: HashMap<PeerId, Multiaddr>,
asb_quote_status: HashMap<PeerId, QuoteStatus>,
@ -128,7 +128,7 @@ impl EventLoop {
swarm: Swarm<Behaviour>,
rendezvous_peer_id: PeerId,
rendezvous_addr: Multiaddr,
namespace: XmrBtcNamespace,
namespace: WowBtcNamespace,
) -> Self {
Self {
swarm,

@ -20,8 +20,8 @@ pub async fn refund(
let state6 = if force {
match state {
BobState::BtcLocked(state3) => state3.cancel(),
BobState::XmrLockProofReceived { state, .. } => state.cancel(),
BobState::XmrLocked(state4) => state4.cancel(),
BobState::WowLockProofReceived { state, .. } => state.cancel(),
BobState::WowLocked(state4) => state4.cancel(),
BobState::EncSigSent(state4) => state4.cancel(),
BobState::CancelTimelockExpired(state6) => state6,
BobState::BtcCancelled(state6) => state6,
@ -29,7 +29,7 @@ pub async fn refund(
| BobState::SwapSetupCompleted(_)
| BobState::BtcRedeemed(_)
| BobState::BtcRefunded(_)
| BobState::XmrRedeemed { .. }
| BobState::WowRedeemed { .. }
| BobState::BtcPunished { .. }
| BobState::SafelyAborted => bail!(
"Cannot refund swap {} because it is in state {} which is not refundable.",

@ -69,7 +69,7 @@ pub struct Database {
swaps: sled::Tree,
peers: sled::Tree,
addresses: sled::Tree,
monero_addresses: sled::Tree,
wownero_addresses: sled::Tree,
}
impl Database {
@ -82,13 +82,13 @@ impl Database {
let swaps = db.open_tree("swaps")?;
let peers = db.open_tree("peers")?;
let addresses = db.open_tree("addresses")?;
let monero_addresses = db.open_tree("monero_addresses")?;
let wownero_addresses = db.open_tree("wownero_addresses")?;
Ok(Database {
swaps,
peers,
addresses,
monero_addresses,
wownero_addresses,
})
}
@ -119,37 +119,37 @@ impl Database {
Ok(PeerId::from_str(peer_id.as_str())?)
}
pub async fn insert_monero_address(
pub async fn insert_wownero_address(
&self,
swap_id: Uuid,
address: monero::Address,
address: wownero::Address,
) -> Result<()> {
let key = swap_id.as_bytes();
let value = serialize(&address)?;
self.monero_addresses.insert(key, value)?;
self.wownero_addresses.insert(key, value)?;
self.monero_addresses
self.wownero_addresses
.flush_async()
.await
.map(|_| ())
.context("Could not flush db")
}
pub fn get_monero_address(&self, swap_id: Uuid) -> Result<monero::Address> {
pub fn get_wownero_address(&self, swap_id: Uuid) -> Result<wownero::Address> {
let encoded = self
.monero_addresses
.wownero_addresses
.get(swap_id.as_bytes())?
.ok_or_else(|| {
anyhow!(
"No Monero address found for swap id {} in database",
"No Wownero address found for swap id {} in database",
swap_id
)
})?;
let monero_address = deserialize(&encoded)?;
let wownero_address = deserialize(&encoded)?;
Ok(monero_address)
Ok(wownero_address)
}
pub async fn insert_address(&self, peer_id: PeerId, address: Multiaddr) -> Result<()> {
@ -463,14 +463,14 @@ mod tests {
}
#[tokio::test]
async fn save_and_load_monero_address() -> Result<()> {
async fn save_and_load_wownero_address() -> Result<()> {
let db_dir = tempfile::tempdir()?;
let swap_id = Uuid::new_v4();
Database::open(db_dir.path())?.insert_monero_address(swap_id, "53gEuGZUhP9JMEBZoGaFNzhwEgiG7hwQdMCqFxiyiTeFPmkbt1mAoNybEUvYBKHcnrSgxnVWgZsTvRBaHBNXPa8tHiCU51a".parse()?).await?;
let loaded_monero_address = Database::open(db_dir.path())?.get_monero_address(swap_id)?;
Database::open(db_dir.path())?.insert_wownero_address(swap_id, "53gEuGZUhP9JMEBZoGaFNzhwEgiG7hwQdMCqFxiyiTeFPmkbt1mAoNybEUvYBKHcnrSgxnVWgZsTvRBaHBNXPa8tHiCU51a".parse()?).await?;
let loaded_wownero_address = Database::open(db_dir.path())?.get_wownero_address(swap_id)?;
assert_eq!(loaded_monero_address.to_string(), "53gEuGZUhP9JMEBZoGaFNzhwEgiG7hwQdMCqFxiyiTeFPmkbt1mAoNybEUvYBKHcnrSgxnVWgZsTvRBaHBNXPa8tHiCU51a");
assert_eq!(loaded_wownero_address.to_string(), "53gEuGZUhP9JMEBZoGaFNzhwEgiG7hwQdMCqFxiyiTeFPmkbt1mAoNybEUvYBKHcnrSgxnVWgZsTvRBaHBNXPa8tHiCU51a");
Ok(())
}

@ -1,9 +1,9 @@
use crate::bitcoin::EncryptedSignature;
use crate::monero;
use crate::monero::{monero_private_key, TransferProof};
use crate::wownero;
use crate::wownero::{wownero_private_key, TransferProof};
use crate::protocol::alice;
use crate::protocol::alice::AliceState;
use monero_rpc::wallet::BlockHeight;
use wownero_rpc::wallet::BlockHeight;
use serde::{Deserialize, Serialize};
use std::fmt;
@ -21,23 +21,23 @@ pub enum Alice {
BtcLocked {
state3: alice::State3,
},
XmrLockTransactionSent {
monero_wallet_restore_blockheight: BlockHeight,
WowLockTransactionSent {
wownero_wallet_restore_blockheight: BlockHeight,
transfer_proof: TransferProof,
state3: alice::State3,
},
XmrLocked {
monero_wallet_restore_blockheight: BlockHeight,
WowLocked {
wownero_wallet_restore_blockheight: BlockHeight,
transfer_proof: TransferProof,
state3: alice::State3,
},
XmrLockTransferProofSent {
monero_wallet_restore_blockheight: BlockHeight,
WowLockTransferProofSent {
wownero_wallet_restore_blockheight: BlockHeight,
transfer_proof: TransferProof,
state3: alice::State3,
},
EncSigLearned {
monero_wallet_restore_blockheight: BlockHeight,
wownero_wallet_restore_blockheight: BlockHeight,
transfer_proof: TransferProof,
encrypted_signature: EncryptedSignature,
state3: alice::State3,
@ -46,26 +46,26 @@ pub enum Alice {
state3: alice::State3,
},
CancelTimelockExpired {
monero_wallet_restore_blockheight: BlockHeight,
wownero_wallet_restore_blockheight: BlockHeight,
transfer_proof: TransferProof,
state3: alice::State3,
},
BtcCancelled {
monero_wallet_restore_blockheight: BlockHeight,
wownero_wallet_restore_blockheight: BlockHeight,
transfer_proof: TransferProof,
state3: alice::State3,
},
BtcPunishable {
monero_wallet_restore_blockheight: BlockHeight,
wownero_wallet_restore_blockheight: BlockHeight,
transfer_proof: TransferProof,
state3: alice::State3,
},
BtcRefunded {
monero_wallet_restore_blockheight: BlockHeight,
wownero_wallet_restore_blockheight: BlockHeight,
transfer_proof: TransferProof,
state3: alice::State3,
#[serde(with = "monero_private_key")]
spend_key: monero::PrivateKey,
#[serde(with = "wownero_private_key")]
spend_key: wownero::PrivateKey,
},
Done(AliceEndState),
}
@ -74,7 +74,7 @@ pub enum Alice {
pub enum AliceEndState {
SafelyAborted,
BtcRedeemed,
XmrRefunded,
WowRefunded,
BtcPunished,
}
@ -90,40 +90,40 @@ impl From<&AliceState> for Alice {
AliceState::BtcLocked { state3 } => Alice::BtcLocked {
state3: state3.as_ref().clone(),
},
AliceState::XmrLockTransactionSent {
monero_wallet_restore_blockheight,
AliceState::WowLockTransactionSent {
wownero_wallet_restore_blockheight,
transfer_proof,
state3,
} => Alice::XmrLockTransactionSent {
monero_wallet_restore_blockheight: *monero_wallet_restore_blockheight,
} => Alice::WowLockTransactionSent {
wownero_wallet_restore_blockheight: *wownero_wallet_restore_blockheight,
transfer_proof: transfer_proof.clone(),
state3: state3.as_ref().clone(),
},
AliceState::XmrLocked {
monero_wallet_restore_blockheight,
AliceState::WowLocked {
wownero_wallet_restore_blockheight,
transfer_proof,
state3,
} => Alice::XmrLocked {
monero_wallet_restore_blockheight: *monero_wallet_restore_blockheight,
} => Alice::WowLocked {
wownero_wallet_restore_blockheight: *wownero_wallet_restore_blockheight,
transfer_proof: transfer_proof.clone(),
state3: state3.as_ref().clone(),
},
AliceState::XmrLockTransferProofSent {
monero_wallet_restore_blockheight,
AliceState::WowLockTransferProofSent {
wownero_wallet_restore_blockheight,
transfer_proof,
state3,
} => Alice::XmrLockTransferProofSent {
monero_wallet_restore_blockheight: *monero_wallet_restore_blockheight,
} => Alice::WowLockTransferProofSent {
wownero_wallet_restore_blockheight: *wownero_wallet_restore_blockheight,
transfer_proof: transfer_proof.clone(),
state3: state3.as_ref().clone(),
},
AliceState::EncSigLearned {
monero_wallet_restore_blockheight,
wownero_wallet_restore_blockheight,
transfer_proof,
state3,
encrypted_signature,
} => Alice::EncSigLearned {
monero_wallet_restore_blockheight: *monero_wallet_restore_blockheight,
wownero_wallet_restore_blockheight: *wownero_wallet_restore_blockheight,
transfer_proof: transfer_proof.clone(),
state3: state3.as_ref().clone(),
encrypted_signature: *encrypted_signature.clone(),
@ -135,41 +135,41 @@ impl From<&AliceState> for Alice {
}
AliceState::BtcRedeemed => Alice::Done(AliceEndState::BtcRedeemed),
AliceState::BtcCancelled {
monero_wallet_restore_blockheight,
wownero_wallet_restore_blockheight,
transfer_proof,
state3,
} => Alice::BtcCancelled {
monero_wallet_restore_blockheight: *monero_wallet_restore_blockheight,
wownero_wallet_restore_blockheight: *wownero_wallet_restore_blockheight,
transfer_proof: transfer_proof.clone(),
state3: state3.as_ref().clone(),
},
AliceState::BtcRefunded {
monero_wallet_restore_blockheight,
wownero_wallet_restore_blockheight,
transfer_proof,
spend_key,
state3,
} => Alice::BtcRefunded {
monero_wallet_restore_blockheight: *monero_wallet_restore_blockheight,
wownero_wallet_restore_blockheight: *wownero_wallet_restore_blockheight,
transfer_proof: transfer_proof.clone(),
spend_key: *spend_key,
state3: state3.as_ref().clone(),
},
AliceState::BtcPunishable {
monero_wallet_restore_blockheight,
wownero_wallet_restore_blockheight,
transfer_proof,
state3,
} => Alice::BtcPunishable {
monero_wallet_restore_blockheight: *monero_wallet_restore_blockheight,
wownero_wallet_restore_blockheight: *wownero_wallet_restore_blockheight,
transfer_proof: transfer_proof.clone(),
state3: state3.as_ref().clone(),
},
AliceState::XmrRefunded => Alice::Done(AliceEndState::XmrRefunded),
AliceState::WowRefunded => Alice::Done(AliceEndState::WowRefunded),
AliceState::CancelTimelockExpired {
monero_wallet_restore_blockheight,
wownero_wallet_restore_blockheight,
transfer_proof,
state3,
} => Alice::CancelTimelockExpired {
monero_wallet_restore_blockheight: *monero_wallet_restore_blockheight,
wownero_wallet_restore_blockheight: *wownero_wallet_restore_blockheight,
transfer_proof: transfer_proof.clone(),
state3: state3.as_ref().clone(),
},
@ -191,40 +191,40 @@ impl From<Alice> for AliceState {
Alice::BtcLocked { state3 } => AliceState::BtcLocked {
state3: Box::new(state3),
},
Alice::XmrLockTransactionSent {
monero_wallet_restore_blockheight,
Alice::WowLockTransactionSent {
wownero_wallet_restore_blockheight,
transfer_proof,
state3,
} => AliceState::XmrLockTransactionSent {
monero_wallet_restore_blockheight,
} => AliceState::WowLockTransactionSent {
wownero_wallet_restore_blockheight,
transfer_proof,
state3: Box::new(state3),
},
Alice::XmrLocked {
monero_wallet_restore_blockheight,
Alice::WowLocked {
wownero_wallet_restore_blockheight,
transfer_proof,
state3,
} => AliceState::XmrLocked {
monero_wallet_restore_blockheight,
} => AliceState::WowLocked {
wownero_wallet_restore_blockheight,
transfer_proof,
state3: Box::new(state3),
},
Alice::XmrLockTransferProofSent {
monero_wallet_restore_blockheight,
Alice::WowLockTransferProofSent {
wownero_wallet_restore_blockheight,
transfer_proof,
state3,
} => AliceState::XmrLockTransferProofSent {
monero_wallet_restore_blockheight,
} => AliceState::WowLockTransferProofSent {
wownero_wallet_restore_blockheight,
transfer_proof,
state3: Box::new(state3),
},
Alice::EncSigLearned {
monero_wallet_restore_blockheight,
wownero_wallet_restore_blockheight,
transfer_proof,
state3: state,
encrypted_signature,
} => AliceState::EncSigLearned {
monero_wallet_restore_blockheight,
wownero_wallet_restore_blockheight,
transfer_proof,
state3: Box::new(state),
encrypted_signature: Box::new(encrypted_signature),
@ -235,40 +235,40 @@ impl From<Alice> for AliceState {
}
}
Alice::CancelTimelockExpired {
monero_wallet_restore_blockheight,
wownero_wallet_restore_blockheight,
transfer_proof,
state3,
} => AliceState::CancelTimelockExpired {
monero_wallet_restore_blockheight,
wownero_wallet_restore_blockheight,
transfer_proof,
state3: Box::new(state3),
},
Alice::BtcCancelled {
monero_wallet_restore_blockheight,
wownero_wallet_restore_blockheight,
transfer_proof,
state3,
} => AliceState::BtcCancelled {
monero_wallet_restore_blockheight,
wownero_wallet_restore_blockheight,
transfer_proof,
state3: Box::new(state3),
},
Alice::BtcPunishable {
monero_wallet_restore_blockheight,
wownero_wallet_restore_blockheight,
transfer_proof,
state3,
} => AliceState::BtcPunishable {
monero_wallet_restore_blockheight,
wownero_wallet_restore_blockheight,
transfer_proof,
state3: Box::new(state3),
},
Alice::BtcRefunded {
monero_wallet_restore_blockheight,
wownero_wallet_restore_blockheight,
transfer_proof,
spend_key,
state3,
} => AliceState::BtcRefunded {
monero_wallet_restore_blockheight,
wownero_wallet_restore_blockheight,
transfer_proof,
spend_key,
state3: Box::new(state3),
@ -276,7 +276,7 @@ impl From<Alice> for AliceState {
Alice::Done(end_state) => match end_state {
AliceEndState::SafelyAborted => AliceState::SafelyAborted,
AliceEndState::BtcRedeemed => AliceState::BtcRedeemed,
AliceEndState::XmrRefunded => AliceState::XmrRefunded,
AliceEndState::WowRefunded => AliceState::WowRefunded,
AliceEndState::BtcPunished => AliceState::BtcPunished,
},
}
@ -291,10 +291,10 @@ impl fmt::Display for Alice {
write!(f, "Bitcoin lock transaction in mempool")
}
Alice::BtcLocked { .. } => f.write_str("Bitcoin locked"),
Alice::XmrLockTransactionSent { .. } => f.write_str("Monero lock transaction sent"),
Alice::XmrLocked { .. } => f.write_str("Monero locked"),
Alice::XmrLockTransferProofSent { .. } => {
f.write_str("Monero lock transfer proof sent")
Alice::WowLockTransactionSent { .. } => f.write_str("Wownero lock transaction sent"),
Alice::WowLocked { .. } => f.write_str("Wownero locked"),
Alice::WowLockTransferProofSent { .. } => {
f.write_str("Wownero lock transfer proof sent")
}
Alice::EncSigLearned { .. } => f.write_str("Encrypted signature learned"),
Alice::BtcRedeemTransactionPublished { .. } => {
@ -303,7 +303,7 @@ impl fmt::Display for Alice {
Alice::CancelTimelockExpired { .. } => f.write_str("Cancel timelock is expired"),
Alice::BtcCancelled { .. } => f.write_str("Bitcoin cancel transaction published"),
Alice::BtcPunishable { .. } => f.write_str("Bitcoin punishable"),
Alice::BtcRefunded { .. } => f.write_str("Monero refundable"),
Alice::BtcRefunded { .. } => f.write_str("Wownero refundable"),
Alice::Done(end_state) => write!(f, "Done: {}", end_state),
}
}

@ -1,7 +1,7 @@
use crate::monero::TransferProof;
use crate::wownero::TransferProof;
use crate::protocol::bob;
use crate::protocol::bob::BobState;
use monero_rpc::wallet::BlockHeight;
use wownero_rpc::wallet::BlockHeight;
use serde::{Deserialize, Serialize};
use serde_with::{serde_as, DisplayFromStr};
use std::fmt;
@ -21,12 +21,12 @@ pub enum Bob {
BtcLocked {
state3: bob::State3,
},
XmrLockProofReceived {
WowLockProofReceived {
state: bob::State3,
lock_transfer_proof: TransferProof,
monero_wallet_restore_blockheight: BlockHeight,
wownero_wallet_restore_blockheight: BlockHeight,
},
XmrLocked {
WowLocked {
state4: bob::State4,
},
EncSigSent {
@ -41,7 +41,7 @@ pub enum Bob {
#[derive(Clone, strum::Display, Debug, Deserialize, Serialize, PartialEq)]
pub enum BobEndState {
SafelyAborted,
XmrRedeemed { tx_lock_id: bitcoin::Txid },
WowRedeemed { tx_lock_id: bitcoin::Txid },
BtcRefunded(Box<bob::State6>),
BtcPunished { tx_lock_id: bitcoin::Txid },
}
@ -58,23 +58,23 @@ impl From<BobState> for Bob {
},
BobState::SwapSetupCompleted(state2) => Bob::ExecutionSetupDone { state2 },
BobState::BtcLocked(state3) => Bob::BtcLocked { state3 },
BobState::XmrLockProofReceived {
BobState::WowLockProofReceived {
state,
lock_transfer_proof,
monero_wallet_restore_blockheight,
} => Bob::XmrLockProofReceived {
wownero_wallet_restore_blockheight,
} => Bob::WowLockProofReceived {
state,
lock_transfer_proof,
monero_wallet_restore_blockheight,
wownero_wallet_restore_blockheight,
},
BobState::XmrLocked(state4) => Bob::XmrLocked { state4 },
BobState::WowLocked(state4) => Bob::WowLocked { state4 },
BobState::EncSigSent(state4) => Bob::EncSigSent { state4 },
BobState::BtcRedeemed(state5) => Bob::BtcRedeemed(state5),
BobState::CancelTimelockExpired(state6) => Bob::CancelTimelockExpired(state6),
BobState::BtcCancelled(state6) => Bob::BtcCancelled(state6),
BobState::BtcRefunded(state6) => Bob::Done(BobEndState::BtcRefunded(Box::new(state6))),
BobState::XmrRedeemed { tx_lock_id } => {
Bob::Done(BobEndState::XmrRedeemed { tx_lock_id })
BobState::WowRedeemed { tx_lock_id } => {
Bob::Done(BobEndState::WowRedeemed { tx_lock_id })
}
BobState::BtcPunished { tx_lock_id } => {
Bob::Done(BobEndState::BtcPunished { tx_lock_id })
@ -96,23 +96,23 @@ impl From<Bob> for BobState {
},
Bob::ExecutionSetupDone { state2 } => BobState::SwapSetupCompleted(state2),
Bob::BtcLocked { state3 } => BobState::BtcLocked(state3),
Bob::XmrLockProofReceived {
Bob::WowLockProofReceived {
state,
lock_transfer_proof,
monero_wallet_restore_blockheight,
} => BobState::XmrLockProofReceived {
wownero_wallet_restore_blockheight,
} => BobState::WowLockProofReceived {
state,
lock_transfer_proof,
monero_wallet_restore_blockheight,
wownero_wallet_restore_blockheight,
},
Bob::XmrLocked { state4 } => BobState::XmrLocked(state4),
Bob::WowLocked { state4 } => BobState::WowLocked(state4),
Bob::EncSigSent { state4 } => BobState::EncSigSent(state4),
Bob::BtcRedeemed(state5) => BobState::BtcRedeemed(state5),
Bob::CancelTimelockExpired(state6) => BobState::CancelTimelockExpired(state6),
Bob::BtcCancelled(state6) => BobState::BtcCancelled(state6),
Bob::Done(end_state) => match end_state {
BobEndState::SafelyAborted => BobState::SafelyAborted,
BobEndState::XmrRedeemed { tx_lock_id } => BobState::XmrRedeemed { tx_lock_id },
BobEndState::WowRedeemed { tx_lock_id } => BobState::WowRedeemed { tx_lock_id },
BobEndState::BtcRefunded(state6) => BobState::BtcRefunded(*state6),
BobEndState::BtcPunished { tx_lock_id } => BobState::BtcPunished { tx_lock_id },
},
@ -126,13 +126,13 @@ impl fmt::Display for Bob {
Bob::Started { .. } => write!(f, "Started"),
Bob::ExecutionSetupDone { .. } => f.write_str("Execution setup done"),
Bob::BtcLocked { .. } => f.write_str("Bitcoin locked"),
Bob::XmrLockProofReceived { .. } => {
f.write_str("XMR lock transaction transfer proof received")
Bob::WowLockProofReceived { .. } => {
f.write_str("WOW lock transaction transfer proof received")
}
Bob::XmrLocked { .. } => f.write_str("Monero locked"),
Bob::WowLocked { .. } => f.write_str("Wownero locked"),
Bob::CancelTimelockExpired(_) => f.write_str("Cancel timelock is expired"),
Bob::BtcCancelled(_) => f.write_str("Bitcoin refundable"),
Bob::BtcRedeemed(_) => f.write_str("Monero redeemable"),
Bob::BtcRedeemed(_) => f.write_str("Wownero redeemable"),
Bob::Done(end_state) => write!(f, "Done: {}", end_state),
Bob::EncSigSent { .. } => f.write_str("Encrypted signature sent"),
}

@ -13,9 +13,9 @@ pub struct Config {
pub bitcoin_cancel_timelock: CancelTimelock,
pub bitcoin_punish_timelock: PunishTimelock,
pub bitcoin_network: bitcoin::Network,
pub monero_avg_block_time: Duration,
pub monero_finality_confirmations: u64,
pub monero_network: monero::Network,
pub wownero_avg_block_time: Duration,
pub wownero_finality_confirmations: u64,
pub wownero_network: wownero::Network,
}
impl Config {
@ -23,8 +23,8 @@ impl Config {
sync_interval(self.bitcoin_avg_block_time)
}
pub fn monero_sync_interval(&self) -> Duration {
sync_interval(self.monero_avg_block_time)
pub fn wownero_sync_interval(&self) -> Duration {
sync_interval(self.wownero_avg_block_time)
}
}
@ -51,9 +51,9 @@ impl GetConfig for Mainnet {
bitcoin_cancel_timelock: CancelTimelock::new(72),
bitcoin_punish_timelock: PunishTimelock::new(72),
bitcoin_network: bitcoin::Network::Bitcoin,
monero_avg_block_time: 2.minutes(),
monero_finality_confirmations: 10,
monero_network: monero::Network::Mainnet,
wownero_avg_block_time: 5.minutes(),
wownero_finality_confirmations: 4,
wownero_network: wownero::Network::Mainnet,
}
}
}
@ -68,9 +68,9 @@ impl GetConfig for Testnet {
bitcoin_cancel_timelock: CancelTimelock::new(12),
bitcoin_punish_timelock: PunishTimelock::new(6),
bitcoin_network: bitcoin::Network::Testnet,
monero_avg_block_time: 2.minutes(),
monero_finality_confirmations: 10,
monero_network: monero::Network::Stagenet,
wownero_avg_block_time: 5.minutes(),
wownero_finality_confirmations: 4,
wownero_network: wownero::Network::Stagenet,
}
}
}
@ -85,9 +85,9 @@ impl GetConfig for Regtest {
bitcoin_cancel_timelock: CancelTimelock::new(100),
bitcoin_punish_timelock: PunishTimelock::new(50),
bitcoin_network: bitcoin::Network::Regtest,
monero_avg_block_time: 1.seconds(),
monero_finality_confirmations: 10,
monero_network: monero::Network::Mainnet, // yes this is strange
wownero_avg_block_time: 1.seconds(),
wownero_finality_confirmations: 4,
wownero_network: wownero::Network::Mainnet, // yes this is strange
}
}
}
@ -113,9 +113,9 @@ pub fn new(is_testnet: bool, asb_config: &asb::config::Config) -> Config {
env_config
};
if let Some(monero_finality_confirmations) = asb_config.monero.finality_confirmations {
if let Some(wownero_finality_confirmations) = asb_config.wownero.finality_confirmations {
Config {
monero_finality_confirmations,
wownero_finality_confirmations,
..env_config
}
} else {

@ -3,19 +3,19 @@ use directories_next::ProjectDirs;
use std::path::{Path, PathBuf};
/// This is the default location for the overall config-dir specific by system
// Linux: /home/<user>/.config/xmr-btc-swap/
// OSX: /Users/<user>/Library/Preferences/xmr-btc-swap/
// Linux: /home/<user>/.config/wow-btc-swap/
// OSX: /Users/<user>/Library/Preferences/wow-btc-swap/
pub fn system_config_dir() -> Result<PathBuf> {
ProjectDirs::from("", "", "xmr-btc-swap")
ProjectDirs::from("", "", "wow-btc-swap")
.map(|proj_dirs| proj_dirs.config_dir().to_path_buf())
.context("Could not generate default system configuration dir path")
}
/// This is the default location for the overall data-dir specific by system
// Linux: /home/<user>/.local/share/xmr-btc-swap/
// OSX: /Users/<user>/Library/ApplicationSupport/xmr-btc-swap/
// Linux: /home/<user>/.local/share/wow-btc-swap/
// OSX: /Users/<user>/Library/ApplicationSupport/wow-btc-swap/
pub fn system_data_dir() -> Result<PathBuf> {
ProjectDirs::from("", "", "xmr-btc-swap")
ProjectDirs::from("", "", "wow-btc-swap")
.map(|proj_dirs| proj_dirs.data_dir().to_path_buf())
.context("Could not generate default system data-dir dir path")
}

@ -135,7 +135,7 @@ mod connection {
.context("Failed to connect to Kraken websocket API")?;
rate_stream
.send(SUBSCRIBE_XMR_BTC_TICKER_PAYLOAD.into())
.send(SUBSCRIBE_WOW_BTC_TICKER_PAYLOAD.into())
.await?;
let stream = rate_stream.err_into().try_filter_map(parse_message).boxed();
@ -213,9 +213,9 @@ mod connection {
Parse(#[from] wire::Error),
}
const SUBSCRIBE_XMR_BTC_TICKER_PAYLOAD: &str = r#"
const SUBSCRIBE_WOW_BTC_TICKER_PAYLOAD: &str = r#"
{ "event": "subscribe",
"pair": [ "XMR/XBT" ],
"pair": [ "WOW/XBT" ],
"subscription": {
"name": "ticker"
}
@ -325,7 +325,7 @@ mod wire {
#[test]
fn can_deserialize_subscription_status_event() {
let event = r#"{"channelID":980,"channelName":"ticker","event":"subscriptionStatus","pair":"XMR/XBT","status":"subscribed","subscription":{"name":"ticker"}}"#;
let event = r#"{"channelID":980,"channelName":"ticker","event":"subscriptionStatus","pair":"WOW/XBT","status":"subscribed","subscription":{"name":"ticker"}}"#;
let event = serde_json::from_str::<Event>(event).unwrap();
@ -334,7 +334,7 @@ mod wire {
#[test]
fn deserialize_ticker_update() {
let message = r#"[980,{"a":["0.00440700",7,"7.35318535"],"b":["0.00440200",7,"7.57416678"],"c":["0.00440700","0.22579000"],"v":["273.75489000","4049.91233351"],"p":["0.00446205","0.00441699"],"t":[123,1310],"l":["0.00439400","0.00429900"],"h":["0.00450000","0.00450000"],"o":["0.00449100","0.00433700"]},"ticker","XMR/XBT"]"#;
let message = r#"[980,{"a":["0.00440700",7,"7.35318535"],"b":["0.00440200",7,"7.57416678"],"c":["0.00440700","0.22579000"],"v":["273.75489000","4049.91233351"],"p":["0.00446205","0.00441699"],"t":[123,1310],"l":["0.00439400","0.00429900"],"h":["0.00450000","0.00450000"],"o":["0.00449100","0.00433700"]},"ticker","WOW/XBT"]"#;
let _ = serde_json::from_str::<TickerUpdate>(message).unwrap();
}

@ -24,14 +24,14 @@ pub mod env;
pub mod fs;
pub mod kraken;
pub mod libp2p_ext;
pub mod monero;
pub mod wownero;
pub mod network;
pub mod protocol;
pub mod seed;
pub mod tor;
pub mod tracing_ext;
mod monero_ext;
mod wownero_ext;
#[cfg(test)]
mod proptest;

@ -9,7 +9,7 @@ use libp2p::PeerId;
use serde::{Deserialize, Serialize};
use uuid::Uuid;
const PROTOCOL: &str = "/comit/xmr/btc/encrypted_signature/1.0.0";
const PROTOCOL: &str = "/comit/wow/btc/encrypted_signature/1.0.0";
type OutEvent = RequestResponseEvent<Request, ()>;
type Message = RequestResponseMessage<Request, ()>;

@ -8,7 +8,7 @@ use libp2p::request_response::{
use libp2p::PeerId;
use serde::{Deserialize, Serialize};
const PROTOCOL: &str = "/comit/xmr/btc/bid-quote/1.0.0";
const PROTOCOL: &str = "/comit/wow/btc/bid-quote/1.0.0";
pub type OutEvent = RequestResponseEvent<(), BidQuote>;
pub type Message = RequestResponseMessage<(), BidQuote>;
@ -23,7 +23,7 @@ impl ProtocolName for BidQuoteProtocol {
}
}
/// Represents a quote for buying XMR.
/// Represents a quote for buying WOW.
#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)]
pub struct BidQuote {
/// The price at which the maker is willing to buy at.

@ -2,28 +2,28 @@ use libp2p::rendezvous::Namespace;
use std::fmt;
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum XmrBtcNamespace {
pub enum WowBtcNamespace {
Mainnet,
Testnet,
}
const MAINNET: &str = "xmr-btc-swap-mainnet";
const TESTNET: &str = "xmr-btc-swap-testnet";
const MAINNET: &str = "wow-btc-swap-mainnet";
const TESTNET: &str = "wow-btc-swap-testnet";
impl fmt::Display for XmrBtcNamespace {
impl fmt::Display for WowBtcNamespace {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
XmrBtcNamespace::Mainnet => write!(f, "{}", MAINNET),
XmrBtcNamespace::Testnet => write!(f, "{}", TESTNET),
WowBtcNamespace::Mainnet => write!(f, "{}", MAINNET),
WowBtcNamespace::Testnet => write!(f, "{}", TESTNET),
}
}
}
impl From<XmrBtcNamespace> for Namespace {
fn from(namespace: XmrBtcNamespace) -> Self {
impl From<WowBtcNamespace> for Namespace {
fn from(namespace: WowBtcNamespace) -> Self {
match namespace {
XmrBtcNamespace::Mainnet => Namespace::from_static(MAINNET),
XmrBtcNamespace::Testnet => Namespace::from_static(TESTNET),
WowBtcNamespace::Mainnet => Namespace::from_static(MAINNET),
WowBtcNamespace::Testnet => Namespace::from_static(TESTNET),
}
}
}

@ -1,4 +1,4 @@
use crate::monero;
use crate::wownero;
use anyhow::{Context, Result};
use libp2p::core::upgrade;
use libp2p::swarm::NegotiatedSubstream;
@ -19,7 +19,7 @@ pub mod protocol {
pub fn new() -> SwapSetup {
from_fn(
b"/comit/xmr/btc/swap_setup/1.0.0",
b"/comit/wow/btc/swap_setup/1.0.0",
Box::new(|socket, _| future::ready(Ok(socket))),
)
}
@ -41,8 +41,8 @@ pub mod protocol {
pub struct BlockchainNetwork {
#[serde(with = "crate::bitcoin::network")]
pub bitcoin: bitcoin::Network,
#[serde(with = "crate::monero::network")]
pub monero: monero::Network,
#[serde(with = "crate::wownero::network")]
pub wownero: wownero::Network,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
@ -54,7 +54,7 @@ pub struct SpotPriceRequest {
#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum SpotPriceResponse {
Xmr(monero::Amount),
Wow(wownero::Amount),
Error(SpotPriceError),
}

@ -5,7 +5,7 @@ use crate::network::swap_setup::{
};
use crate::protocol::alice::{State0, State3};
use crate::protocol::{Message0, Message2, Message4};
use crate::{asb, bitcoin, env, monero};
use crate::{asb, bitcoin, env, wownero};
use anyhow::{anyhow, Context, Result};
use futures::future::{BoxFuture, OptionFuture};
use futures::{AsyncWriteExt, FutureExt};
@ -42,8 +42,8 @@ pub enum OutEvent {
#[derive(Debug)]
pub struct WalletSnapshot {
balance: monero::Amount,
lock_fee: monero::Amount,
balance: wownero::Amount,
lock_fee: wownero::Amount,
// TODO: Consider using the same address for punish and redeem (they are mutually exclusive, so
// effectively the address will only be used once)
@ -57,10 +57,10 @@ pub struct WalletSnapshot {
impl WalletSnapshot {
pub async fn capture(
bitcoin_wallet: &bitcoin::Wallet,
monero_wallet: &monero::Wallet,
wownero_wallet: &wownero::Wallet,
transfer_amount: bitcoin::Amount,
) -> Result<Self> {
let balance = monero_wallet.get_balance().await?;
let balance = wownero_wallet.get_balance().await?;
let redeem_address = bitcoin_wallet.new_address().await?;
let punish_address = bitcoin_wallet.new_address().await?;
let redeem_fee = bitcoin_wallet
@ -72,7 +72,7 @@ impl WalletSnapshot {
Ok(Self {
balance,
lock_fee: monero::MONERO_FEE,
lock_fee: wownero::WOWNERO_FEE,
redeem_address,
punish_address,
redeem_fee,
@ -291,7 +291,7 @@ where
let blockchain_network = BlockchainNetwork {
bitcoin: env_config.bitcoin_network,
monero: env_config.monero_network,
wownero: env_config.wownero_network,
};
if request.blockchain_network != blockchain_network {
@ -318,18 +318,18 @@ where
}
let rate = latest_rate.map_err(|e| Error::LatestRateFetchFailed(Box::new(e)))?;
let xmr = rate
let wow = rate
.sell_quote(btc)
.map_err(Error::SellQuoteCalculationFailed)?;
if wallet_snapshot.balance < xmr + wallet_snapshot.lock_fee {
if wallet_snapshot.balance < wow + wallet_snapshot.lock_fee {
return Err(Error::BalanceTooLow {
balance: wallet_snapshot.balance,
buy: btc,
});
}
Ok(xmr)
Ok(wow)
};
let result = validate.await;
@ -341,11 +341,11 @@ where
.await
.context("Failed to write spot price response")?;
let xmr = result?;
let wow = result?;
let state0 = State0::new(
request.btc,
xmr,
wow,
env_config,
wallet_snapshot.redeem_address,
wallet_snapshot.punish_address,
@ -456,9 +456,9 @@ where
}
impl SpotPriceResponse {
pub fn from_result_ref(result: &Result<monero::Amount, Error>) -> Self {
pub fn from_result_ref(result: &Result<wownero::Amount, Error>) -> Self {
match result {
Ok(amount) => SpotPriceResponse::Xmr(*amount),
Ok(amount) => SpotPriceResponse::Wow(*amount),
Err(error) => SpotPriceResponse::Error(error.to_error_response()),
}
}
@ -480,7 +480,7 @@ pub enum Error {
},
#[error("Balance {balance} too low to fulfill swapping {buy}")]
BalanceTooLow {
balance: monero::Amount,
balance: wownero::Amount,
buy: bitcoin::Amount,
},
#[error("Failed to fetch latest rate")]

@ -4,7 +4,7 @@ use crate::network::swap_setup::{
};
use crate::protocol::bob::{State0, State2};
use crate::protocol::{Message1, Message3};
use crate::{bitcoin, cli, env, monero};
use crate::{bitcoin, cli, env, wownero};
use anyhow::Result;
use futures::future::{BoxFuture, OptionFuture};
use futures::{AsyncWriteExt, FutureExt};
@ -158,22 +158,22 @@ impl ProtocolsHandler for Handler {
btc: info.btc,
blockchain_network: BlockchainNetwork {
bitcoin: env_config.bitcoin_network,
monero: env_config.monero_network,
wownero: env_config.wownero_network,
},
})
.await?;
let xmr = Result::from(read_cbor_message::<SpotPriceResponse>(&mut substream).await?)?;
let WOW = Result::from(read_cbor_message::<SpotPriceResponse>(&mut substream).await?)?;
let state0 = State0::new(
info.swap_id,
&mut rand::thread_rng(),
info.btc,
xmr,
wow,
env_config.bitcoin_cancel_timelock,
env_config.bitcoin_punish_timelock,
info.bitcoin_refund_address,
env_config.monero_finality_confirmations,
env_config.wownero_finality_confirmations,
info.tx_refund_fee,
info.tx_cancel_fee,
);
@ -248,10 +248,10 @@ impl ProtocolsHandler for Handler {
}
}
impl From<SpotPriceResponse> for Result<monero::Amount, Error> {
impl From<SpotPriceResponse> for Result<wownero::Amount, Error> {
fn from(response: SpotPriceResponse) -> Self {
match response {
SpotPriceResponse::Xmr(amount) => Ok(amount),
SpotPriceResponse::Wow(amount) => Ok(amount),
SpotPriceResponse::Error(e) => Err(e.into()),
}
}
@ -271,7 +271,7 @@ pub enum Error {
max: bitcoin::Amount,
buy: bitcoin::Amount,
},
#[error("Seller's XMR balance is currently too low to fulfill the swap request to buy {buy}, please try again later")]
#[error("Seller's WOW balance is currently too low to fulfill the swap request to buy {buy}, please try again later")]
BalanceTooLow { buy: bitcoin::Amount },
#[error("Seller blockchain network {asb:?} setup did not match your blockchain network setup {cli:?}")]

@ -1,6 +1,6 @@
use crate::asb::LatestRate;
use crate::libp2p_ext::MultiAddrExt;
use crate::network::rendezvous::XmrBtcNamespace;
use crate::network::rendezvous::WowBtcNamespace;
use crate::seed::Seed;
use crate::{asb, bitcoin, cli, env, tor};
use anyhow::{Context, Result};
@ -16,7 +16,7 @@ pub fn asb<LR>(
latest_rate: LR,
resume_only: bool,
env_config: env::Config,
rendezvous_params: Option<(Multiaddr, XmrBtcNamespace)>,
rendezvous_params: Option<(Multiaddr, WowBtcNamespace)>,
) -> Result<Swarm<asb::Behaviour<LR>>>
where
LR: LatestRate + Send + 'static + Debug + Clone,

@ -1,5 +1,5 @@
use crate::network::cbor_request_response::CborCodec;
use crate::{asb, cli, monero};
use crate::{asb, cli, wownero};
use libp2p::core::ProtocolName;
use libp2p::request_response::{
ProtocolSupport, RequestResponse, RequestResponseConfig, RequestResponseEvent,
@ -9,7 +9,7 @@ use libp2p::PeerId;
use serde::{Deserialize, Serialize};
use uuid::Uuid;
const PROTOCOL: &str = "/comit/xmr/btc/transfer_proof/1.0.0";
const PROTOCOL: &str = "/comit/wow/btc/transfer_proof/1.0.0";
type OutEvent = RequestResponseEvent<Request, ()>;
type Message = RequestResponseMessage<Request, ()>;
@ -27,7 +27,7 @@ impl ProtocolName for TransferProofProtocol {
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Request {
pub swap_id: Uuid,
pub tx_lock_proof: monero::TransferProof,
pub tx_lock_proof: wownero::TransferProof,
}
pub fn alice() -> Behaviour {

@ -1,4 +1,4 @@
use crate::{bitcoin, monero};
use crate::{bitcoin, wownero};
use conquer_once::Lazy;
use ecdsa_fun::fun::marker::Mark;
use serde::{Deserialize, Serialize};
@ -23,10 +23,10 @@ pub static CROSS_CURVE_PROOF_SYSTEM: Lazy<
pub struct Message0 {
swap_id: Uuid,
B: bitcoin::PublicKey,
S_b_monero: monero::PublicKey,
S_b_wownero: wownero::PublicKey,
S_b_bitcoin: bitcoin::PublicKey,
dleq_proof_s_b: CrossCurveDLEQProof,
v_b: monero::PrivateViewKey,
v_b: wownero::PrivateViewKey,
refund_address: bitcoin::Address,
#[serde(with = "::bitcoin::util::amount::serde::as_sat")]
tx_refund_fee: bitcoin::Amount,
@ -37,10 +37,10 @@ pub struct Message0 {
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Message1 {
A: bitcoin::PublicKey,
S_a_monero: monero::PublicKey,
S_a_wownero: wownero::PublicKey,
S_a_bitcoin: bitcoin::PublicKey,
dleq_proof_s_a: CrossCurveDLEQProof,
v_a: monero::PrivateViewKey,
v_a: wownero::PrivateViewKey,
redeem_address: bitcoin::Address,
punish_address: bitcoin::Address,
#[serde(with = "::bitcoin::util::amount::serde::as_sat")]

@ -1,8 +1,8 @@
//! Run an XMR/BTC swap in the role of Alice.
//! Alice holds XMR and wishes receive BTC.
//! Run an WOW/BTC swap in the role of Alice.
//! Alice holds WOW and wishes receive BTC.
use crate::database::Database;
use crate::env::Config;
use crate::{asb, bitcoin, monero};
use crate::{asb, bitcoin, wownero};
use std::sync::Arc;
use uuid::Uuid;
@ -16,7 +16,7 @@ pub struct Swap {
pub state: AliceState,
pub event_loop_handle: asb::EventLoopHandle,
pub bitcoin_wallet: Arc<bitcoin::Wallet>,
pub monero_wallet: Arc<monero::Wallet>,
pub wownero_wallet: Arc<wownero::Wallet>,
pub env_config: Config,
pub swap_id: Uuid,
pub db: Arc<Database>,

@ -3,13 +3,13 @@ use crate::bitcoin::{
TxPunish, TxRedeem, TxRefund, Txid,
};
use crate::env::Config;
use crate::monero::wallet::{TransferRequest, WatchRequest};
use crate::monero::TransferProof;
use crate::monero_ext::ScalarExt;
use crate::wownero::wallet::{TransferRequest, WatchRequest};
use crate::wownero::TransferProof;
use crate::wownero_ext::ScalarExt;
use crate::protocol::{Message0, Message1, Message2, Message3, Message4, CROSS_CURVE_PROOF_SYSTEM};
use crate::{bitcoin, monero};
use crate::{bitcoin, wownero};
use anyhow::{anyhow, bail, Context, Result};
use monero_rpc::wallet::BlockHeight;
use wownero_rpc::wallet::BlockHeight;
use rand::{CryptoRng, RngCore};
use serde::{Deserialize, Serialize};
use sigma_fun::ext::dl_secp256k1_ed25519_eq::CrossCurveDLEQProof;
@ -27,23 +27,23 @@ pub enum AliceState {
BtcLocked {
state3: Box<State3>,
},
XmrLockTransactionSent {
monero_wallet_restore_blockheight: BlockHeight,
WowLockTransactionSent {
wownero_wallet_restore_blockheight: BlockHeight,
transfer_proof: TransferProof,
state3: Box<State3>,
},
XmrLocked {
monero_wallet_restore_blockheight: BlockHeight,
WowLocked {
wownero_wallet_restore_blockheight: BlockHeight,
transfer_proof: TransferProof,
state3: Box<State3>,
},
XmrLockTransferProofSent {
monero_wallet_restore_blockheight: BlockHeight,
WowLockTransferProofSent {
wownero_wallet_restore_blockheight: BlockHeight,
transfer_proof: TransferProof,
state3: Box<State3>,
},
EncSigLearned {
monero_wallet_restore_blockheight: BlockHeight,
wownero_wallet_restore_blockheight: BlockHeight,
transfer_proof: TransferProof,
encrypted_signature: Box<bitcoin::EncryptedSignature>,
state3: Box<State3>,
@ -53,24 +53,24 @@ pub enum AliceState {
},
BtcRedeemed,
BtcCancelled {
monero_wallet_restore_blockheight: BlockHeight,
wownero_wallet_restore_blockheight: BlockHeight,
transfer_proof: TransferProof,
state3: Box<State3>,
},
BtcRefunded {
monero_wallet_restore_blockheight: BlockHeight,
wownero_wallet_restore_blockheight: BlockHeight,
transfer_proof: TransferProof,
spend_key: monero::PrivateKey,
spend_key: wownero::PrivateKey,
state3: Box<State3>,
},
BtcPunishable {
monero_wallet_restore_blockheight: BlockHeight,
wownero_wallet_restore_blockheight: BlockHeight,
transfer_proof: TransferProof,
state3: Box<State3>,
},
XmrRefunded,
WowRefunded,
CancelTimelockExpired {
monero_wallet_restore_blockheight: BlockHeight,
wownero_wallet_restore_blockheight: BlockHeight,
transfer_proof: TransferProof,
state3: Box<State3>,
},
@ -86,10 +86,10 @@ impl fmt::Display for AliceState {
write!(f, "bitcoin lock transaction in mempool")
}
AliceState::BtcLocked { .. } => write!(f, "btc is locked"),
AliceState::XmrLockTransactionSent { .. } => write!(f, "xmr lock transaction sent"),
AliceState::XmrLocked { .. } => write!(f, "xmr is locked"),
AliceState::XmrLockTransferProofSent { .. } => {
write!(f, "xmr lock transfer proof sent")
AliceState::WowLockTransactionSent { .. } => write!(f, "wow lock transaction sent"),
AliceState::WowLocked { .. } => write!(f, "wow is locked"),
AliceState::WowLockTransferProofSent { .. } => {
write!(f, "wow lock transfer proof sent")
}
AliceState::EncSigLearned { .. } => write!(f, "encrypted signature is learned"),
AliceState::BtcRedeemTransactionPublished { .. } => {
@ -101,7 +101,7 @@ impl fmt::Display for AliceState {
AliceState::BtcPunished => write!(f, "btc is punished"),
AliceState::SafelyAborted => write!(f, "safely aborted"),
AliceState::BtcPunishable { .. } => write!(f, "btc is punishable"),
AliceState::XmrRefunded => write!(f, "xmr is refunded"),
AliceState::WowRefunded => write!(f, "wow is refunded"),
AliceState::CancelTimelockExpired { .. } => write!(f, "cancel timelock is expired"),
}
}
@ -110,13 +110,13 @@ impl fmt::Display for AliceState {
#[derive(Clone, Debug, PartialEq)]
pub struct State0 {
a: bitcoin::SecretKey,
s_a: monero::Scalar,
v_a: monero::PrivateViewKey,
S_a_monero: monero::PublicKey,
s_a: wownero::Scalar,
v_a: wownero::PrivateViewKey,
S_a_wownero: wownero::PublicKey,
S_a_bitcoin: bitcoin::PublicKey,
dleq_proof_s_a: CrossCurveDLEQProof,
btc: bitcoin::Amount,
xmr: monero::Amount,
wow: wownero::Amount,
cancel_timelock: CancelTimelock,
punish_timelock: PunishTimelock,
redeem_address: bitcoin::Address,
@ -129,7 +129,7 @@ impl State0 {
#[allow(clippy::too_many_arguments)]
pub fn new<R>(
btc: bitcoin::Amount,
xmr: monero::Amount,
wow: wownero::Amount,
env_config: Config,
redeem_address: bitcoin::Address,
punish_address: bitcoin::Address,
@ -141,24 +141,24 @@ impl State0 {
R: RngCore + CryptoRng,
{
let a = bitcoin::SecretKey::new_random(rng);
let v_a = monero::PrivateViewKey::new_random(rng);
let v_a = wownero::PrivateViewKey::new_random(rng);
let s_a = monero::Scalar::random(rng);
let (dleq_proof_s_a, (S_a_bitcoin, S_a_monero)) = CROSS_CURVE_PROOF_SYSTEM.prove(&s_a, rng);
let s_a = wownero::Scalar::random(rng);
let (dleq_proof_s_a, (S_a_bitcoin, S_a_wownero)) = CROSS_CURVE_PROOF_SYSTEM.prove(&s_a, rng);
Self {
a,
s_a,
v_a,
S_a_bitcoin: S_a_bitcoin.into(),
S_a_monero: monero::PublicKey {
point: S_a_monero.compress(),
S_a_wownero: wownero::PublicKey {
point: S_a_wownero.compress(),
},
dleq_proof_s_a,
redeem_address,
punish_address,
btc,
xmr,
wow,
cancel_timelock: env_config.bitcoin_cancel_timelock,
punish_timelock: env_config.bitcoin_punish_timelock,
tx_redeem_fee,
@ -171,10 +171,10 @@ impl State0 {
&msg.dleq_proof_s_b,
(
msg.S_b_bitcoin.into(),
msg.S_b_monero
msg.S_b_wownero
.point
.decompress()
.ok_or_else(|| anyhow!("S_b is not a monero curve point"))?,
.ok_or_else(|| anyhow!("S_b is not a wownero curve point"))?,
),
);
@ -188,15 +188,15 @@ impl State0 {
a: self.a,
B: msg.B,
s_a: self.s_a,
S_a_monero: self.S_a_monero,
S_a_wownero: self.S_a_wownero,
S_a_bitcoin: self.S_a_bitcoin,
S_b_monero: msg.S_b_monero,
S_b_wownero: msg.S_b_wownero,
S_b_bitcoin: msg.S_b_bitcoin,
v,
v_a: self.v_a,
dleq_proof_s_a: self.dleq_proof_s_a,
btc: self.btc,
xmr: self.xmr,
wow: self.wow,
cancel_timelock: self.cancel_timelock,
punish_timelock: self.punish_timelock,
refund_address: msg.refund_address,
@ -214,16 +214,16 @@ impl State0 {
pub struct State1 {
a: bitcoin::SecretKey,
B: bitcoin::PublicKey,
s_a: monero::Scalar,
S_a_monero: monero::PublicKey,
s_a: wownero::Scalar,
S_a_wownero: wownero::PublicKey,
S_a_bitcoin: bitcoin::PublicKey,
S_b_monero: monero::PublicKey,
S_b_wownero: wownero::PublicKey,
S_b_bitcoin: bitcoin::PublicKey,
v: monero::PrivateViewKey,
v_a: monero::PrivateViewKey,
v: wownero::PrivateViewKey,
v_a: wownero::PrivateViewKey,
dleq_proof_s_a: CrossCurveDLEQProof,
btc: bitcoin::Amount,
xmr: monero::Amount,
wow: wownero::Amount,
cancel_timelock: CancelTimelock,
punish_timelock: PunishTimelock,
refund_address: bitcoin::Address,
@ -239,7 +239,7 @@ impl State1 {
pub fn next_message(&self) -> Message1 {
Message1 {
A: self.a.public(),
S_a_monero: self.S_a_monero,
S_a_wownero: self.S_a_wownero,
S_a_bitcoin: self.S_a_bitcoin,
dleq_proof_s_a: self.dleq_proof_s_a.clone(),
v_a: self.v_a,
@ -258,11 +258,11 @@ impl State1 {
a: self.a,
B: self.B,
s_a: self.s_a,
S_b_monero: self.S_b_monero,
S_b_wownero: self.S_b_wownero,
S_b_bitcoin: self.S_b_bitcoin,
v: self.v,
btc: self.btc,
xmr: self.xmr,
wow: self.wow,
cancel_timelock: self.cancel_timelock,
punish_timelock: self.punish_timelock,
refund_address: self.refund_address,
@ -281,12 +281,12 @@ impl State1 {
pub struct State2 {
a: bitcoin::SecretKey,
B: bitcoin::PublicKey,
s_a: monero::Scalar,
S_b_monero: monero::PublicKey,
s_a: wownero::Scalar,
S_b_wownero: wownero::PublicKey,
S_b_bitcoin: bitcoin::PublicKey,
v: monero::PrivateViewKey,
v: wownero::PrivateViewKey,
btc: bitcoin::Amount,
xmr: monero::Amount,
wow: wownero::Amount,
cancel_timelock: CancelTimelock,
punish_timelock: PunishTimelock,
refund_address: bitcoin::Address,
@ -311,7 +311,7 @@ impl State2 {
let tx_refund =
bitcoin::TxRefund::new(&tx_cancel, &self.refund_address, self.tx_refund_fee);
// Alice encsigns the refund transaction(bitcoin) digest with Bob's monero
// Alice encsigns the refund transaction(bitcoin) digest with Bob's wownero
// pubkey(S_b). The refund transaction spends the output of
// tx_lock_bitcoin to Bob's refund address.
// recover(encsign(a, S_b, d), sign(a, d), S_b) = s_b where d is a digest, (a,
@ -348,11 +348,11 @@ impl State2 {
a: self.a,
B: self.B,
s_a: self.s_a,
S_b_monero: self.S_b_monero,
S_b_wownero: self.S_b_wownero,
S_b_bitcoin: self.S_b_bitcoin,
v: self.v,
btc: self.btc,
xmr: self.xmr,
wow: self.wow,
cancel_timelock: self.cancel_timelock,
punish_timelock: self.punish_timelock,
refund_address: self.refund_address,
@ -373,13 +373,13 @@ impl State2 {
pub struct State3 {
a: bitcoin::SecretKey,
B: bitcoin::PublicKey,
s_a: monero::Scalar,
S_b_monero: monero::PublicKey,
s_a: wownero::Scalar,
S_b_wownero: wownero::PublicKey,
S_b_bitcoin: bitcoin::PublicKey,
pub v: monero::PrivateViewKey,
pub v: wownero::PrivateViewKey,
#[serde(with = "::bitcoin::util::amount::serde::as_sat")]
btc: bitcoin::Amount,
xmr: monero::Amount,
wow: wownero::Amount,
pub cancel_timelock: CancelTimelock,
pub punish_timelock: PunishTimelock,
refund_address: bitcoin::Address,
@ -416,34 +416,34 @@ impl State3 {
))
}
pub fn lock_xmr_transfer_request(&self) -> TransferRequest {
let S_a = monero::PublicKey::from_private_key(&monero::PrivateKey { scalar: self.s_a });
pub fn lock_wow_transfer_request(&self) -> TransferRequest {
let S_a = wownero::PublicKey::from_private_key(&wownero::PrivateKey { scalar: self.s_a });
let public_spend_key = S_a + self.S_b_monero;
let public_spend_key = S_a + self.S_b_wownero;
let public_view_key = self.v.public();
TransferRequest {
public_spend_key,
public_view_key,
amount: self.xmr,
amount: self.wow,
}
}
pub fn lock_xmr_watch_request(
pub fn lock_wow_watch_request(
&self,
transfer_proof: TransferProof,
conf_target: u64,
) -> WatchRequest {
let S_a = monero::PublicKey::from_private_key(&monero::PrivateKey { scalar: self.s_a });
let S_a = wownero::PublicKey::from_private_key(&wownero::PrivateKey { scalar: self.s_a });
let public_spend_key = S_a + self.S_b_monero;
let public_spend_key = S_a + self.S_b_wownero;
let public_view_key = self.v.public();
WatchRequest {
public_spend_key,
public_view_key,
transfer_proof,
conf_target,
expected: self.xmr,
expected: self.wow,
}
}
@ -465,11 +465,11 @@ impl State3 {
TxRedeem::new(&self.tx_lock, &self.redeem_address, self.tx_redeem_fee)
}
pub fn extract_monero_private_key(
pub fn extract_wownero_private_key(
&self,
published_refund_tx: bitcoin::Transaction,
) -> Result<monero::PrivateKey> {
self.tx_refund().extract_monero_private_key(
) -> Result<wownero::PrivateKey> {
self.tx_refund().extract_wownero_private_key(
published_refund_tx,
self.s_a,
self.a.clone(),
@ -498,28 +498,28 @@ impl State3 {
Ok(tx_id)
}
pub async fn refund_xmr(
pub async fn refund_wow(
&self,
monero_wallet: &monero::Wallet,
monero_wallet_restore_blockheight: BlockHeight,
wownero_wallet: &wownero::Wallet,
wownero_wallet_restore_blockheight: BlockHeight,
file_name: String,
spend_key: monero::PrivateKey,
spend_key: wownero::PrivateKey,
transfer_proof: TransferProof,
) -> Result<()> {
let view_key = self.v;
// Ensure that the XMR to be refunded are spendable by awaiting 10 confirmations
// Ensure that the WOW to be refunded are spendable by awaiting 10 confirmations
// on the lock transaction
monero_wallet
.watch_for_transfer(self.lock_xmr_watch_request(transfer_proof, 10))
wownero_wallet
.watch_for_transfer(self.lock_wow_watch_request(transfer_proof, 10))
.await?;
monero_wallet
wownero_wallet
.create_from(
file_name,
spend_key,
view_key,
monero_wallet_restore_blockheight,
wownero_wallet_restore_blockheight,
)
.await?;

@ -1,10 +1,10 @@
//! Run an XMR/BTC swap in the role of Alice.
//! Alice holds XMR and wishes receive BTC.
//! Run an WOW/BTC swap in the role of Alice.
//! Alice holds WOW and wishes receive BTC.
use crate::asb::{EventLoopHandle, LatestRate};
use crate::bitcoin::ExpiredTimelocks;
use crate::env::Config;
use crate::protocol::alice::{AliceState, Swap};
use crate::{bitcoin, database, monero};
use crate::{bitcoin, database, wownero};
use anyhow::{bail, Context, Result};
use tokio::select;
use tokio::time::timeout;
@ -34,7 +34,7 @@ where
current_state,
&mut swap.event_loop_handle,
swap.bitcoin_wallet.as_ref(),
swap.monero_wallet.as_ref(),
swap.wownero_wallet.as_ref(),
&swap.env_config,
rate_service.clone(),
)
@ -54,7 +54,7 @@ async fn next_state<LR>(
state: AliceState,
event_loop_handle: &mut EventLoopHandle,
bitcoin_wallet: &bitcoin::Wallet,
monero_wallet: &monero::Wallet,
wownero_wallet: &wownero::Wallet,
env_config: &Config,
mut rate_service: LR,
) -> Result<AliceState>
@ -114,16 +114,16 @@ where
AliceState::BtcLocked { state3 } => {
match state3.expired_timelocks(bitcoin_wallet).await? {
ExpiredTimelocks::None => {
// Record the current monero wallet block height so we don't have to scan from
// Record the current wownero wallet block height so we don't have to scan from
// block 0 for scenarios where we create a refund wallet.
let monero_wallet_restore_blockheight = monero_wallet.block_height().await?;
let wownero_wallet_restore_blockheight = wownero_wallet.block_height().await?;
let transfer_proof = monero_wallet
.transfer(state3.lock_xmr_transfer_request())
let transfer_proof = wownero_wallet
.transfer(state3.lock_wow_transfer_request())
.await?;
AliceState::XmrLockTransactionSent {
monero_wallet_restore_blockheight,
AliceState::WowLockTransactionSent {
wownero_wallet_restore_blockheight,
transfer_proof,
state3,
}
@ -131,36 +131,36 @@ where
_ => AliceState::SafelyAborted,
}
}
AliceState::XmrLockTransactionSent {
monero_wallet_restore_blockheight,
AliceState::WowLockTransactionSent {
wownero_wallet_restore_blockheight,
transfer_proof,
state3,
} => match state3.expired_timelocks(bitcoin_wallet).await? {
ExpiredTimelocks::None => {
monero_wallet
.watch_for_transfer(state3.lock_xmr_watch_request(transfer_proof.clone(), 1))
wownero_wallet
.watch_for_transfer(state3.lock_wow_watch_request(transfer_proof.clone(), 1))
.await
.with_context(|| {
format!(
"Failed to watch for transfer of XMR in transaction {}",
"Failed to watch for transfer of WOW in transaction {}",
transfer_proof.tx_hash()
)
})?;
AliceState::XmrLocked {
monero_wallet_restore_blockheight,
AliceState::WowLocked {
wownero_wallet_restore_blockheight,
transfer_proof,
state3,
}
}
_ => AliceState::CancelTimelockExpired {
monero_wallet_restore_blockheight,
wownero_wallet_restore_blockheight,
transfer_proof,
state3,
},
},
AliceState::XmrLocked {
monero_wallet_restore_blockheight,
AliceState::WowLocked {
wownero_wallet_restore_blockheight,
transfer_proof,
state3,
} => {
@ -170,23 +170,23 @@ where
result = event_loop_handle.send_transfer_proof(transfer_proof.clone()) => {
result?;
AliceState::XmrLockTransferProofSent {
monero_wallet_restore_blockheight,
AliceState::WowLockTransferProofSent {
wownero_wallet_restore_blockheight,
transfer_proof,
state3,
}
},
_ = tx_lock_status.wait_until_confirmed_with(state3.cancel_timelock) => {
AliceState::CancelTimelockExpired {
monero_wallet_restore_blockheight,
wownero_wallet_restore_blockheight,
transfer_proof,
state3,
}
}
}
}
AliceState::XmrLockTransferProofSent {
monero_wallet_restore_blockheight,
AliceState::WowLockTransferProofSent {
wownero_wallet_restore_blockheight,
transfer_proof,
state3,
} => {
@ -197,7 +197,7 @@ where
_ = tx_lock_status.wait_until_confirmed_with(state3.cancel_timelock) => {
AliceState::CancelTimelockExpired {
monero_wallet_restore_blockheight,
wownero_wallet_restore_blockheight,
transfer_proof,
state3,
}
@ -206,7 +206,7 @@ where
tracing::info!("Received encrypted signature");
AliceState::EncSigLearned {
monero_wallet_restore_blockheight,
wownero_wallet_restore_blockheight,
transfer_proof,
encrypted_signature: Box::new(enc_sig?),
state3,
@ -215,7 +215,7 @@ where
}
}
AliceState::EncSigLearned {
monero_wallet_restore_blockheight,
wownero_wallet_restore_blockheight,
transfer_proof,
encrypted_signature,
state3,
@ -237,7 +237,7 @@ where
.await?;
AliceState::CancelTimelockExpired {
monero_wallet_restore_blockheight,
wownero_wallet_restore_blockheight,
transfer_proof,
state3,
}
@ -255,7 +255,7 @@ where
.await?;
AliceState::CancelTimelockExpired {
monero_wallet_restore_blockheight,
wownero_wallet_restore_blockheight,
transfer_proof,
state3,
}
@ -263,7 +263,7 @@ where
}
}
_ => AliceState::CancelTimelockExpired {
monero_wallet_restore_blockheight,
wownero_wallet_restore_blockheight,
transfer_proof,
state3,
},
@ -279,7 +279,7 @@ where
}
}
AliceState::CancelTimelockExpired {
monero_wallet_restore_blockheight,
wownero_wallet_restore_blockheight,
transfer_proof,
state3,
} => {
@ -297,13 +297,13 @@ where
}
AliceState::BtcCancelled {
monero_wallet_restore_blockheight,
wownero_wallet_restore_blockheight,
transfer_proof,
state3,
}
}
AliceState::BtcCancelled {
monero_wallet_restore_blockheight,
wownero_wallet_restore_blockheight,
transfer_proof,
state3,
} => {
@ -315,10 +315,10 @@ where
seen_refund.context("Failed to monitor refund transaction")?;
let published_refund_tx = bitcoin_wallet.get_raw_transaction(state3.tx_refund().txid()).await?;
let spend_key = state3.extract_monero_private_key(published_refund_tx)?;
let spend_key = state3.extract_wownero_private_key(published_refund_tx)?;
AliceState::BtcRefunded {
monero_wallet_restore_blockheight,
wownero_wallet_restore_blockheight,
transfer_proof,
spend_key,
state3,
@ -326,7 +326,7 @@ where
}
_ = tx_cancel_status.wait_until_confirmed_with(state3.punish_timelock) => {
AliceState::BtcPunishable {
monero_wallet_restore_blockheight,
wownero_wallet_restore_blockheight,
transfer_proof,
state3,
}
@ -334,25 +334,25 @@ where
}
}
AliceState::BtcRefunded {
monero_wallet_restore_blockheight,
wownero_wallet_restore_blockheight,
transfer_proof,
spend_key,
state3,
} => {
state3
.refund_xmr(
monero_wallet,
monero_wallet_restore_blockheight,
.refund_wow(
wownero_wallet,
wownero_wallet_restore_blockheight,
swap_id.to_string(),
spend_key,
transfer_proof,
)
.await?;
AliceState::XmrRefunded
AliceState::WowRefunded
}
AliceState::BtcPunishable {
monero_wallet_restore_blockheight,
wownero_wallet_restore_blockheight,
transfer_proof,
state3,
} => {
@ -376,10 +376,10 @@ where
.get_raw_transaction(state3.tx_refund().txid())
.await?;
let spend_key = state3.extract_monero_private_key(published_refund_tx)?;
let spend_key = state3.extract_wownero_private_key(published_refund_tx)?;
AliceState::BtcRefunded {
monero_wallet_restore_blockheight,
wownero_wallet_restore_blockheight,
transfer_proof,
spend_key,
state3,
@ -387,7 +387,7 @@ where
}
}
}
AliceState::XmrRefunded => AliceState::XmrRefunded,
AliceState::WowRefunded => AliceState::WowRefunded,
AliceState::BtcRedeemed => AliceState::BtcRedeemed,
AliceState::BtcPunished => AliceState::BtcPunished,
AliceState::SafelyAborted => AliceState::SafelyAborted,
@ -397,7 +397,7 @@ where
fn is_complete(state: &AliceState) -> bool {
matches!(
state,
AliceState::XmrRefunded
AliceState::WowRefunded
| AliceState::BtcRedeemed
| AliceState::BtcPunished
| AliceState::SafelyAborted

@ -4,7 +4,7 @@ use anyhow::Result;
use uuid::Uuid;
use crate::database::Database;
use crate::{bitcoin, cli, env, monero};
use crate::{bitcoin, cli, env, wownero};
pub use self::state::*;
pub use self::swap::{run, run_until};
@ -17,10 +17,10 @@ pub struct Swap {
pub event_loop_handle: cli::EventLoopHandle,
pub db: Database,
pub bitcoin_wallet: Arc<bitcoin::Wallet>,
pub monero_wallet: Arc<monero::Wallet>,
pub wownero_wallet: Arc<wownero::Wallet>,
pub env_config: env::Config,
pub id: Uuid,
pub monero_receive_address: monero::Address,
pub wownero_receive_address: wownero::Address,
}
impl Swap {
@ -29,10 +29,10 @@ impl Swap {
db: Database,
id: Uuid,
bitcoin_wallet: Arc<bitcoin::Wallet>,
monero_wallet: Arc<monero::Wallet>,
wownero_wallet: Arc<wownero::Wallet>,
env_config: env::Config,
event_loop_handle: cli::EventLoopHandle,
monero_receive_address: monero::Address,
wownero_receive_address: wownero::Address,
bitcoin_change_address: bitcoin::Address,
btc_amount: bitcoin::Amount,
) -> Self {
@ -44,10 +44,10 @@ impl Swap {
event_loop_handle,
db,
bitcoin_wallet,
monero_wallet,
wownero_wallet,
env_config,
id,
monero_receive_address,
wownero_receive_address,
}
}
@ -56,10 +56,10 @@ impl Swap {
db: Database,
id: Uuid,
bitcoin_wallet: Arc<bitcoin::Wallet>,
monero_wallet: Arc<monero::Wallet>,
wownero_wallet: Arc<wownero::Wallet>,
env_config: env::Config,
event_loop_handle: cli::EventLoopHandle,
monero_receive_address: monero::Address,
wownero_receive_address: wownero::Address,
) -> Result<Self> {
let state = db.get_state(id)?.try_into_bob()?.into();
@ -68,10 +68,10 @@ impl Swap {
event_loop_handle,
db,
bitcoin_wallet,
monero_wallet,
wownero_wallet,
env_config,
id,
monero_receive_address,
wownero_receive_address,
})
}
}

@ -3,17 +3,17 @@ use crate::bitcoin::{
self, current_epoch, CancelTimelock, ExpiredTimelocks, PunishTimelock, Transaction, TxCancel,
TxLock, Txid,
};
use crate::monero;
use crate::monero::wallet::WatchRequest;
use crate::monero::{monero_private_key, TransferProof};
use crate::monero_ext::ScalarExt;
use crate::wownero;
use crate::wownero::wallet::WatchRequest;
use crate::wownero::{wownero_private_key, TransferProof};
use crate::wownero_ext::ScalarExt;
use crate::protocol::{Message0, Message1, Message2, Message3, Message4, CROSS_CURVE_PROOF_SYSTEM};
use anyhow::{anyhow, bail, Context, Result};
use bdk::database::BatchDatabase;
use ecdsa_fun::adaptor::{Adaptor, HashTranscript};
use ecdsa_fun::nonce::Deterministic;
use ecdsa_fun::Signature;
use monero_rpc::wallet::BlockHeight;
use wownero_rpc::wallet::BlockHeight;
use rand::{CryptoRng, RngCore};
use serde::{Deserialize, Serialize};
use sha2::Sha256;
@ -29,18 +29,18 @@ pub enum BobState {
},
SwapSetupCompleted(State2),
BtcLocked(State3),
XmrLockProofReceived {
WowLockProofReceived {
state: State3,
lock_transfer_proof: TransferProof,
monero_wallet_restore_blockheight: BlockHeight,
wownero_wallet_restore_blockheight: BlockHeight,
},
XmrLocked(State4),
WowLocked(State4),
EncSigSent(State4),
BtcRedeemed(State5),
CancelTimelockExpired(State6),
BtcCancelled(State6),
BtcRefunded(State6),
XmrRedeemed {
WowRedeemed {
tx_lock_id: bitcoin::Txid,
},
BtcPunished {
@ -55,16 +55,16 @@ impl fmt::Display for BobState {
BobState::Started { .. } => write!(f, "quote has been requested"),
BobState::SwapSetupCompleted(..) => write!(f, "execution setup done"),
BobState::BtcLocked(..) => write!(f, "btc is locked"),
BobState::XmrLockProofReceived { .. } => {
write!(f, "XMR lock transaction transfer proof received")
BobState::WowLockProofReceived { .. } => {
write!(f, "WOW lock transaction transfer proof received")
}
BobState::XmrLocked(..) => write!(f, "xmr is locked"),
BobState::WowLocked(..) => write!(f, "wow is locked"),
BobState::EncSigSent(..) => write!(f, "encrypted signature is sent"),
BobState::BtcRedeemed(..) => write!(f, "btc is redeemed"),
BobState::CancelTimelockExpired(..) => write!(f, "cancel timelock is expired"),
BobState::BtcCancelled(..) => write!(f, "btc is cancelled"),
BobState::BtcRefunded(..) => write!(f, "btc is refunded"),
BobState::XmrRedeemed { .. } => write!(f, "xmr is redeemed"),
BobState::WowRedeemed { .. } => write!(f, "wow is redeemed"),
BobState::BtcPunished { .. } => write!(f, "btc is punished"),
BobState::SafelyAborted => write!(f, "safely aborted"),
}
@ -75,17 +75,17 @@ impl fmt::Display for BobState {
pub struct State0 {
swap_id: Uuid,
b: bitcoin::SecretKey,
s_b: monero::Scalar,
S_b_monero: monero::PublicKey,
s_b: wownero::Scalar,
S_b_wownero: wownero::PublicKey,
S_b_bitcoin: bitcoin::PublicKey,
v_b: monero::PrivateViewKey,
v_b: wownero::PrivateViewKey,
dleq_proof_s_b: CrossCurveDLEQProof,
btc: bitcoin::Amount,
xmr: monero::Amount,
wow: wownero::Amount,
cancel_timelock: CancelTimelock,
punish_timelock: PunishTimelock,
refund_address: bitcoin::Address,
min_monero_confirmations: u64,
min_wownero_confirmations: u64,
tx_refund_fee: bitcoin::Amount,
tx_cancel_fee: bitcoin::Amount,
}
@ -96,20 +96,20 @@ impl State0 {
swap_id: Uuid,
rng: &mut R,
btc: bitcoin::Amount,
xmr: monero::Amount,
wow: wownero::Amount,
cancel_timelock: CancelTimelock,
punish_timelock: PunishTimelock,
refund_address: bitcoin::Address,
min_monero_confirmations: u64,
min_wownero_confirmations: u64,
tx_refund_fee: bitcoin::Amount,
tx_cancel_fee: bitcoin::Amount,
) -> Self {
let b = bitcoin::SecretKey::new_random(rng);
let s_b = monero::Scalar::random(rng);
let v_b = monero::PrivateViewKey::new_random(rng);
let s_b = wownero::Scalar::random(rng);
let v_b = wownero::PrivateViewKey::new_random(rng);
let (dleq_proof_s_b, (S_b_bitcoin, S_b_monero)) = CROSS_CURVE_PROOF_SYSTEM.prove(&s_b, rng);
let (dleq_proof_s_b, (S_b_bitcoin, S_b_wownero)) = CROSS_CURVE_PROOF_SYSTEM.prove(&s_b, rng);
Self {
swap_id,
@ -117,16 +117,16 @@ impl State0 {
s_b,
v_b,
S_b_bitcoin: bitcoin::PublicKey::from(S_b_bitcoin),
S_b_monero: monero::PublicKey {
point: S_b_monero.compress(),
S_b_wownero: wownero::PublicKey {
point: S_b_wownero.compress(),
},
btc,
xmr,
wow,
dleq_proof_s_b,
cancel_timelock,
punish_timelock,
refund_address,
min_monero_confirmations,
min_wownero_confirmations,
tx_refund_fee,
tx_cancel_fee,
}
@ -136,7 +136,7 @@ impl State0 {
Message0 {
swap_id: self.swap_id,
B: self.b.public(),
S_b_monero: self.S_b_monero,
S_b_wownero: self.S_b_wownero,
S_b_bitcoin: self.S_b_bitcoin,
dleq_proof_s_b: self.dleq_proof_s_b.clone(),
v_b: self.v_b,
@ -159,10 +159,10 @@ impl State0 {
&msg.dleq_proof_s_a,
(
msg.S_a_bitcoin.into(),
msg.S_a_monero
msg.S_a_wownero
.point
.decompress()
.ok_or_else(|| anyhow!("S_a is not a monero curve point"))?,
.ok_or_else(|| anyhow!("S_a is not a wownero curve point"))?,
),
);
@ -184,17 +184,17 @@ impl State0 {
A: msg.A,
b: self.b,
s_b: self.s_b,
S_a_monero: msg.S_a_monero,
S_a_wownero: msg.S_a_wownero,
S_a_bitcoin: msg.S_a_bitcoin,
v,
xmr: self.xmr,
wow: self.wow,
cancel_timelock: self.cancel_timelock,
punish_timelock: self.punish_timelock,
refund_address: self.refund_address,
redeem_address: msg.redeem_address,
punish_address: msg.punish_address,
tx_lock,
min_monero_confirmations: self.min_monero_confirmations,
min_wownero_confirmations: self.min_wownero_confirmations,
tx_redeem_fee: msg.tx_redeem_fee,
tx_refund_fee: self.tx_refund_fee,
tx_punish_fee: msg.tx_punish_fee,
@ -207,18 +207,18 @@ impl State0 {
pub struct State1 {
A: bitcoin::PublicKey,
b: bitcoin::SecretKey,
s_b: monero::Scalar,
S_a_monero: monero::PublicKey,
s_b: wownero::Scalar,
S_a_wownero: wownero::PublicKey,
S_a_bitcoin: bitcoin::PublicKey,
v: monero::PrivateViewKey,
xmr: monero::Amount,
v: wownero::PrivateViewKey,
wow: wownero::Amount,
cancel_timelock: CancelTimelock,
punish_timelock: PunishTimelock,
refund_address: bitcoin::Address,
redeem_address: bitcoin::Address,
punish_address: bitcoin::Address,
tx_lock: bitcoin::TxLock,
min_monero_confirmations: u64,
min_wownero_confirmations: u64,
tx_redeem_fee: bitcoin::Amount,
tx_refund_fee: bitcoin::Amount,
tx_punish_fee: bitcoin::Amount,
@ -255,10 +255,10 @@ impl State1 {
A: self.A,
b: self.b,
s_b: self.s_b,
S_a_monero: self.S_a_monero,
S_a_wownero: self.S_a_wownero,
S_a_bitcoin: self.S_a_bitcoin,
v: self.v,
xmr: self.xmr,
wow: self.wow,
cancel_timelock: self.cancel_timelock,
punish_timelock: self.punish_timelock,
refund_address: self.refund_address,
@ -267,7 +267,7 @@ impl State1 {
tx_lock: self.tx_lock,
tx_cancel_sig_a: msg.tx_cancel_sig,
tx_refund_encsig: msg.tx_refund_encsig,
min_monero_confirmations: self.min_monero_confirmations,
min_wownero_confirmations: self.min_wownero_confirmations,
tx_redeem_fee: self.tx_redeem_fee,
tx_refund_fee: self.tx_refund_fee,
tx_punish_fee: self.tx_punish_fee,
@ -280,11 +280,11 @@ impl State1 {
pub struct State2 {
A: bitcoin::PublicKey,
b: bitcoin::SecretKey,
s_b: monero::Scalar,
S_a_monero: monero::PublicKey,
s_b: wownero::Scalar,
S_a_wownero: wownero::PublicKey,
S_a_bitcoin: bitcoin::PublicKey,
v: monero::PrivateViewKey,
xmr: monero::Amount,
v: wownero::PrivateViewKey,
wow: wownero::Amount,
cancel_timelock: CancelTimelock,
punish_timelock: PunishTimelock,
refund_address: bitcoin::Address,
@ -293,7 +293,7 @@ pub struct State2 {
tx_lock: bitcoin::TxLock,
tx_cancel_sig_a: Signature,
tx_refund_encsig: bitcoin::EncryptedSignature,
min_monero_confirmations: u64,
min_wownero_confirmations: u64,
#[serde(with = "::bitcoin::util::amount::serde::as_sat")]
tx_redeem_fee: bitcoin::Amount,
#[serde(with = "::bitcoin::util::amount::serde::as_sat")]
@ -334,10 +334,10 @@ impl State2 {
A: self.A,
b: self.b,
s_b: self.s_b,
S_a_monero: self.S_a_monero,
S_a_wownero: self.S_a_wownero,
S_a_bitcoin: self.S_a_bitcoin,
v: self.v,
xmr: self.xmr,
wow: self.wow,
cancel_timelock: self.cancel_timelock,
punish_timelock: self.punish_timelock,
refund_address: self.refund_address,
@ -345,7 +345,7 @@ impl State2 {
tx_lock: self.tx_lock.clone(),
tx_cancel_sig_a: self.tx_cancel_sig_a,
tx_refund_encsig: self.tx_refund_encsig,
min_monero_confirmations: self.min_monero_confirmations,
min_wownero_confirmations: self.min_wownero_confirmations,
tx_redeem_fee: self.tx_redeem_fee,
tx_refund_fee: self.tx_refund_fee,
tx_cancel_fee: self.tx_cancel_fee,
@ -359,11 +359,11 @@ impl State2 {
pub struct State3 {
A: bitcoin::PublicKey,
b: bitcoin::SecretKey,
s_b: monero::Scalar,
S_a_monero: monero::PublicKey,
s_b: wownero::Scalar,
S_a_wownero: wownero::PublicKey,
S_a_bitcoin: bitcoin::PublicKey,
v: monero::PrivateViewKey,
xmr: monero::Amount,
v: wownero::PrivateViewKey,
wow: wownero::Amount,
pub cancel_timelock: CancelTimelock,
punish_timelock: PunishTimelock,
refund_address: bitcoin::Address,
@ -371,7 +371,7 @@ pub struct State3 {
pub tx_lock: bitcoin::TxLock,
tx_cancel_sig_a: Signature,
tx_refund_encsig: bitcoin::EncryptedSignature,
min_monero_confirmations: u64,
min_wownero_confirmations: u64,
#[serde(with = "::bitcoin::util::amount::serde::as_sat")]
tx_redeem_fee: bitcoin::Amount,
#[serde(with = "::bitcoin::util::amount::serde::as_sat")]
@ -381,21 +381,21 @@ pub struct State3 {
}
impl State3 {
pub fn lock_xmr_watch_request(&self, transfer_proof: TransferProof) -> WatchRequest {
let S_b_monero =
monero::PublicKey::from_private_key(&monero::PrivateKey::from_scalar(self.s_b));
let S = self.S_a_monero + S_b_monero;
pub fn lock_wow_watch_request(&self, transfer_proof: TransferProof) -> WatchRequest {
let S_b_wownero =
wownero::PublicKey::from_private_key(&wownero::PrivateKey::from_scalar(self.s_b));
let S = self.S_a_wownero + S_b_wownero;
WatchRequest {
public_spend_key: S,
public_view_key: self.v.public(),
transfer_proof,
conf_target: self.min_monero_confirmations,
expected: self.xmr,
conf_target: self.min_wownero_confirmations,
expected: self.wow,
}
}
pub fn xmr_locked(self, monero_wallet_restore_blockheight: BlockHeight) -> State4 {
pub fn wow_locked(self, wownero_wallet_restore_blockheight: BlockHeight) -> State4 {
State4 {
A: self.A,
b: self.b,
@ -409,7 +409,7 @@ impl State3 {
tx_lock: self.tx_lock,
tx_cancel_sig_a: self.tx_cancel_sig_a,
tx_refund_encsig: self.tx_refund_encsig,
monero_wallet_restore_blockheight,
wownero_wallet_restore_blockheight,
tx_redeem_fee: self.tx_redeem_fee,
tx_refund_fee: self.tx_refund_fee,
tx_cancel_fee: self.tx_cancel_fee,
@ -464,9 +464,9 @@ impl State3 {
pub struct State4 {
A: bitcoin::PublicKey,
b: bitcoin::SecretKey,
s_b: monero::Scalar,
s_b: wownero::Scalar,
S_a_bitcoin: bitcoin::PublicKey,
v: monero::PrivateViewKey,
v: wownero::PrivateViewKey,
pub cancel_timelock: CancelTimelock,
punish_timelock: PunishTimelock,
refund_address: bitcoin::Address,
@ -474,7 +474,7 @@ pub struct State4 {
pub tx_lock: bitcoin::TxLock,
tx_cancel_sig_a: Signature,
tx_refund_encsig: bitcoin::EncryptedSignature,
monero_wallet_restore_blockheight: BlockHeight,
wownero_wallet_restore_blockheight: BlockHeight,
#[serde(with = "::bitcoin::util::amount::serde::as_sat")]
tx_redeem_fee: bitcoin::Amount,
#[serde(with = "::bitcoin::util::amount::serde::as_sat")]
@ -506,14 +506,14 @@ impl State4 {
let tx_redeem_sig =
tx_redeem.extract_signature_by_key(tx_redeem_candidate, self.b.public())?;
let s_a = bitcoin::recover(self.S_a_bitcoin, tx_redeem_sig, tx_redeem_encsig)?;
let s_a = monero::private_key_from_secp256k1_scalar(s_a.into());
let s_a = wownero::private_key_from_secp256k1_scalar(s_a.into());
Ok(State5 {
s_a,
s_b: self.s_b,
v: self.v,
tx_lock: self.tx_lock.clone(),
monero_wallet_restore_blockheight: self.monero_wallet_restore_blockheight,
wownero_wallet_restore_blockheight: self.wownero_wallet_restore_blockheight,
})
}
@ -559,17 +559,17 @@ impl State4 {
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
pub struct State5 {
#[serde(with = "monero_private_key")]
s_a: monero::PrivateKey,
s_b: monero::Scalar,
v: monero::PrivateViewKey,
#[serde(with = "wownero_private_key")]
s_a: wownero::PrivateKey,
s_b: wownero::Scalar,
v: wownero::PrivateViewKey,
tx_lock: bitcoin::TxLock,
pub monero_wallet_restore_blockheight: BlockHeight,
pub wownero_wallet_restore_blockheight: BlockHeight,
}
impl State5 {
pub fn xmr_keys(&self) -> (monero::PrivateKey, monero::PrivateViewKey) {
let s_b = monero::PrivateKey { scalar: self.s_b };
pub fn wow_keys(&self) -> (wownero::PrivateKey, wownero::PrivateViewKey) {
let s_b = wownero::PrivateKey { scalar: self.s_b };
let s = self.s_a + s_b;
(s, self.v)
@ -584,7 +584,7 @@ impl State5 {
pub struct State6 {
A: bitcoin::PublicKey,
b: bitcoin::SecretKey,
s_b: monero::Scalar,
s_b: wownero::Scalar,
cancel_timelock: CancelTimelock,
punish_timelock: PunishTimelock,
refund_address: bitcoin::Address,

@ -4,7 +4,7 @@ use crate::database::Swap;
use crate::network::swap_setup::bob::NewSwap;
use crate::protocol::bob;
use crate::protocol::bob::state::*;
use crate::{bitcoin, monero};
use crate::{bitcoin, wownero};
use anyhow::{bail, Context, Result};
use tokio::select;
use uuid::Uuid;
@ -13,7 +13,7 @@ pub fn is_complete(state: &BobState) -> bool {
matches!(
state,
BobState::BtcRefunded(..)
| BobState::XmrRedeemed { .. }
| BobState::WowRedeemed { .. }
| BobState::BtcPunished { .. }
| BobState::SafelyAborted
)
@ -36,8 +36,8 @@ pub async fn run_until(
current_state,
&mut swap.event_loop_handle,
swap.bitcoin_wallet.as_ref(),
swap.monero_wallet.as_ref(),
swap.monero_receive_address,
swap.wownero_wallet.as_ref(),
swap.wownero_receive_address,
)
.await?;
@ -55,8 +55,8 @@ async fn next_state(
state: BobState,
event_loop_handle: &mut EventLoopHandle,
bitcoin_wallet: &bitcoin::Wallet,
monero_wallet: &monero::Wallet,
monero_receive_address: monero::Address,
wownero_wallet: &wownero::Wallet,
wownero_receive_address: wownero::Address,
) -> Result<BobState> {
tracing::trace!(%state, "Advancing state");
@ -96,7 +96,7 @@ async fn next_state(
BobState::BtcLocked(state3)
}
// Bob has locked Btc
// Watch for Alice to Lock Xmr or for cancel timelock to elapse
// Watch for Alice to Lock Wow or for cancel timelock to elapse
BobState::BtcLocked(state3) => {
let tx_lock_status = bitcoin_wallet.subscribe_to(state3.tx_lock.clone()).await;
@ -105,26 +105,26 @@ async fn next_state(
let cancel_timelock_expires =
tx_lock_status.wait_until_confirmed_with(state3.cancel_timelock);
// Record the current monero wallet block height so we don't have to scan from
// Record the current wownero wallet block height so we don't have to scan from
// block 0 once we create the redeem wallet.
let monero_wallet_restore_blockheight = monero_wallet.block_height().await?;
let wownero_wallet_restore_blockheight = wownero_wallet.block_height().await?;
tracing::info!("Waiting for Alice to lock Monero");
tracing::info!("Waiting for Alice to lock Wownero");
select! {
transfer_proof = transfer_proof_watcher => {
let transfer_proof = transfer_proof?;
tracing::info!(txid = %transfer_proof.tx_hash(), "Alice locked Monero");
tracing::info!(txid = %transfer_proof.tx_hash(), "Alice locked Wownero");
BobState::XmrLockProofReceived {
BobState::WowLockProofReceived {
state: state3,
lock_transfer_proof: transfer_proof,
monero_wallet_restore_blockheight
wownero_wallet_restore_blockheight
}
},
_ = cancel_timelock_expires => {
tracing::info!("Alice took too long to lock Monero, cancelling the swap");
tracing::info!("Alice took too long to lock Wownero, cancelling the swap");
let state4 = state3.cancel();
BobState::CancelTimelockExpired(state4)
@ -135,22 +135,22 @@ async fn next_state(
BobState::CancelTimelockExpired(state4)
}
}
BobState::XmrLockProofReceived {
BobState::WowLockProofReceived {
state,
lock_transfer_proof,
monero_wallet_restore_blockheight,
wownero_wallet_restore_blockheight,
} => {
let tx_lock_status = bitcoin_wallet.subscribe_to(state.tx_lock.clone()).await;
if let ExpiredTimelocks::None = state.current_epoch(bitcoin_wallet).await? {
let watch_request = state.lock_xmr_watch_request(lock_transfer_proof);
let watch_request = state.lock_wow_watch_request(lock_transfer_proof);
select! {
received_xmr = monero_wallet.watch_for_transfer(watch_request) => {
match received_xmr {
Ok(()) => BobState::XmrLocked(state.xmr_locked(monero_wallet_restore_blockheight)),
Err(monero::InsufficientFunds { expected, actual }) => {
tracing::warn!(%expected, %actual, "Insufficient Monero have been locked!");
received_wow = wownero_wallet.watch_for_transfer(watch_request) => {
match received_wow {
Ok(()) => BobState::WowLocked(state.wow_locked(wownero_wallet_restore_blockheight)),
Err(wownero::InsufficientFunds { expected, actual }) => {
tracing::warn!(%expected, %actual, "Insufficient Wownero have been locked!");
tracing::info!(timelock = %state.cancel_timelock, "Waiting for cancel timelock to expire");
tx_lock_status.wait_until_confirmed_with(state.cancel_timelock).await?;
@ -167,11 +167,11 @@ async fn next_state(
BobState::CancelTimelockExpired(state.cancel())
}
}
BobState::XmrLocked(state) => {
BobState::WowLocked(state) => {
let tx_lock_status = bitcoin_wallet.subscribe_to(state.tx_lock.clone()).await;
if let ExpiredTimelocks::None = state.expired_timelock(bitcoin_wallet).await? {
// Alice has locked Xmr
// Alice has locked Wow
// Bob sends Alice his key
select! {
@ -203,38 +203,38 @@ async fn next_state(
}
}
BobState::BtcRedeemed(state) => {
let (spend_key, view_key) = state.xmr_keys();
let (spend_key, view_key) = state.wow_keys();
let wallet_file_name = swap_id.to_string();
if let Err(e) = monero_wallet
if let Err(e) = wownero_wallet
.create_from_and_load(
wallet_file_name.clone(),
spend_key,
view_key,
state.monero_wallet_restore_blockheight,
state.wownero_wallet_restore_blockheight,
)
.await
{
// In case we failed to refresh/sweep, when resuming the wallet might already
// exist! This is a very unlikely scenario, but if we don't take care of it we
// might not be able to ever transfer the Monero.
tracing::warn!("Failed to generate monero wallet from keys: {:#}", e);
// might not be able to ever transfer the Wownero.
tracing::warn!("Failed to generate wownero wallet from keys: {:#}", e);
tracing::info!(%wallet_file_name,
"Falling back to trying to open the the wallet if it already exists",
);
monero_wallet.open(wallet_file_name).await?;
wownero_wallet.open(wallet_file_name).await?;
}
// Ensure that the generated wallet is synced so we have a proper balance
monero_wallet.refresh().await?;
wownero_wallet.refresh().await?;
// Sweep (transfer all funds) to the given address
let tx_hashes = monero_wallet.sweep_all(monero_receive_address).await?;
let tx_hashes = wownero_wallet.sweep_all(wownero_receive_address).await?;
for tx_hash in tx_hashes {
tracing::info!(%monero_receive_address, txid=%tx_hash.0, "Successfully transferred XMR to wallet");
tracing::info!(%wownero_receive_address, txid=%tx_hash.0, "Successfully transferred WOW to wallet");
}
BobState::XmrRedeemed {
BobState::WowRedeemed {
tx_lock_id: state.tx_lock_id(),
}
}
@ -265,6 +265,6 @@ async fn next_state(
BobState::BtcRefunded(state4) => BobState::BtcRefunded(state4),
BobState::BtcPunished { tx_lock_id } => BobState::BtcPunished { tx_lock_id },
BobState::SafelyAborted => BobState::SafelyAborted,
BobState::XmrRedeemed { tx_lock_id } => BobState::XmrRedeemed { tx_lock_id },
BobState::WowRedeemed { tx_lock_id } => BobState::WowRedeemed { tx_lock_id },
})
}

@ -1,8 +1,8 @@
pub mod wallet;
mod wallet_rpc;
pub use ::monero::network::Network;
pub use ::monero::{Address, PrivateKey, PublicKey};
pub use ::wownero::network::Network;
pub use ::wownero::{Address, PrivateKey, PublicKey};
pub use curve25519_dalek::scalar::Scalar;
pub use wallet::Wallet;
pub use wallet_rpc::{WalletRpc, WalletRpcProcess};
@ -40,7 +40,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 = "wownero_private_key")] PrivateKey);
impl PrivateViewKey {
pub fn new_random<R: RngCore + CryptoRng>(rng: &mut R) -> Self {
@ -81,16 +81,16 @@ pub struct PublicViewKey(PublicKey);
#[derive(Debug, Copy, Clone, Deserialize, Serialize, PartialEq, PartialOrd)]
pub struct Amount(u64);
// Median tx fees on Monero as found here: https://www.monero.how/monero-transaction-fees, XMR 0.000_015 * 2 (to be on the safe side)
pub const MONERO_FEE: Amount = Amount::from_piconero(30000000);
// Median tx fees on Wownero as found here: https://www.wownero.how/wownero-transaction-fees, WOW 0.000_015 * 2 (to be on the safe side)
pub const WOWNERO_FEE: Amount = Amount::from_piconero(30000000);
impl Amount {
pub const ZERO: Self = Self(0);
pub const ONE_XMR: Self = Self(PICONERO_OFFSET);
pub const ONE_WOW: Self = Self(PICONERO_OFFSET);
/// Create an [Amount] with piconero precision and the given number of
/// piconeros.
///
/// A piconero (a.k.a atomic unit) is equal to 1e-12 XMR.
/// A piconero (a.k.a atomic unit) is equal to 1e-12 WOW.
pub const fn from_piconero(amount: u64) -> Self {
Amount(amount)
}
@ -99,12 +99,12 @@ impl Amount {
self.0
}
pub fn from_monero(amount: f64) -> Result<Self> {
pub fn from_wownero(amount: f64) -> Result<Self> {
let decimal = Decimal::try_from(amount)?;
Self::from_decimal(decimal)
}
pub fn parse_monero(amount: &str) -> Result<Self> {
pub fn parse_wownero(amount: &str) -> Result<Self> {
let decimal = Decimal::from_str(amount)?;
Self::from_decimal(decimal)
}
@ -159,14 +159,14 @@ impl fmt::Display for Amount {
decimal
.set_scale(12)
.expect("12 is smaller than max precision of 28");
write!(f, "{} XMR", decimal)
write!(f, "{} WOW", decimal)
}
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub struct TransferProof {
tx_hash: TxHash,
#[serde(with = "monero_private_key")]
#[serde(with = "wownero_private_key")]
tx_key: PrivateKey,
}
@ -209,9 +209,9 @@ pub struct InsufficientFunds {
#[error("Overflow, cannot convert {0} to u64")]
pub struct OverflowError(pub String);
pub mod monero_private_key {
use monero::consensus::{Decodable, Encodable};
use monero::PrivateKey;
pub mod wownero_private_key {
use wownero::consensus::{Decodable, Encodable};
use wownero::PrivateKey;
use serde::de::Visitor;
use serde::ser::Error;
use serde::{de, Deserializer, Serializer};
@ -224,7 +224,7 @@ pub mod monero_private_key {
type Value = PrivateKey;
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(formatter, "a byte array representing a Monero private key")
write!(formatter, "a byte array representing a Wownero private key")
}
fn visit_bytes<E>(self, s: &[u8]) -> Result<Self::Value, E>
@ -257,8 +257,8 @@ pub mod monero_private_key {
}
}
pub mod monero_amount {
use crate::monero::Amount;
pub mod wownero_amount {
use crate::wownero::Amount;
use serde::{Deserialize, Deserializer, Serializer};
pub fn serialize<S>(x: &Amount, s: S) -> Result<S::Ok, S::Error>
@ -284,57 +284,57 @@ mod tests {
use super::*;
#[test]
fn display_monero_min() {
fn display_wownero_min() {
let min_pics = 1;
let amount = Amount::from_piconero(min_pics);
let monero = amount.to_string();
assert_eq!("0.000000000001 XMR", monero);
let wownero = amount.to_string();
assert_eq!("0.000000000001 WOW", wownero);
}
#[test]
fn display_monero_one() {
fn display_wownero_one() {
let min_pics = 1000000000000;
let amount = Amount::from_piconero(min_pics);
let monero = amount.to_string();
assert_eq!("1.000000000000 XMR", monero);
let wownero = amount.to_string();
assert_eq!("1.000000000000 WOW", wownero);
}
#[test]
fn display_monero_max() {
fn display_wownero_max() {
let max_pics = 18_446_744_073_709_551_615;
let amount = Amount::from_piconero(max_pics);
let monero = amount.to_string();
assert_eq!("18446744.073709551615 XMR", monero);
let wownero = amount.to_string();
assert_eq!("18446744.073709551615 WOW", wownero);
}
#[test]
fn parse_monero_min() {
let monero_min = "0.000000000001";
let amount = Amount::parse_monero(monero_min).unwrap();
fn parse_wownero_min() {
let wownero_min = "0.000000000001";
let amount = Amount::parse_wownero(wownero_min).unwrap();
let pics = amount.0;
assert_eq!(1, pics);
}
#[test]
fn parse_monero() {
let monero = "123";
let amount = Amount::parse_monero(monero).unwrap();
fn parse_wownero() {
let wownero = "123";
let amount = Amount::parse_wownero(wownero).unwrap();
let pics = amount.0;
assert_eq!(123000000000000, pics);
}
#[test]
fn parse_monero_max() {
let monero = "18446744.073709551615";
let amount = Amount::parse_monero(monero).unwrap();
fn parse_wownero_max() {
let wownero = "18446744.073709551615";
let amount = Amount::parse_wownero(wownero).unwrap();
let pics = amount.0;
assert_eq!(18446744073709551615, pics);
}
#[test]
fn parse_monero_overflows() {
fn parse_wownero_overflows() {
let overflow_pics = "18446744.073709551616";
let error = Amount::parse_monero(overflow_pics).unwrap_err();
let error = Amount::parse_wownero(overflow_pics).unwrap_err();
assert_eq!(
error.downcast_ref::<OverflowError>().unwrap(),
&OverflowError(overflow_pics.to_owned())
@ -345,26 +345,26 @@ mod tests {
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize, PartialEq)]
pub struct MoneroPrivateKey(#[serde(with = "monero_private_key")] crate::monero::PrivateKey);
pub struct WowneroPrivateKey(#[serde(with = "wownero_private_key")] crate::wownero::PrivateKey);
#[derive(Debug, Serialize, Deserialize, PartialEq)]
pub struct MoneroAmount(#[serde(with = "monero_amount")] crate::monero::Amount);
pub struct WowneroAmount(#[serde(with = "wownero_amount")] crate::wownero::Amount);
#[test]
fn serde_monero_private_key() {
let key = MoneroPrivateKey(monero::PrivateKey::from_scalar(
crate::monero::Scalar::random(&mut OsRng),
fn serde_wownero_private_key() {
let key = WowneroPrivateKey(wownero::PrivateKey::from_scalar(
crate::wownero::Scalar::random(&mut OsRng),
));
let encoded = serde_cbor::to_vec(&key).unwrap();
let decoded: MoneroPrivateKey = serde_cbor::from_slice(&encoded).unwrap();
let decoded: WowneroPrivateKey = serde_cbor::from_slice(&encoded).unwrap();
assert_eq!(key, decoded);
}
#[test]
fn serde_monero_amount() {
let amount = MoneroAmount(crate::monero::Amount::from_piconero(1000));
fn serde_wownero_amount() {
let amount = WowneroAmount(crate::wownero::Amount::from_piconero(1000));
let encoded = serde_cbor::to_vec(&amount).unwrap();
let decoded: MoneroAmount = serde_cbor::from_slice(&encoded).unwrap();
let decoded: WowneroAmount = serde_cbor::from_slice(&encoded).unwrap();
assert_eq!(amount, decoded);
}
}

@ -1,11 +1,11 @@
use crate::env::Config;
use crate::monero::{
use crate::wownero::{
Amount, InsufficientFunds, PrivateViewKey, PublicViewKey, TransferProof, TxHash,
};
use ::monero::{Address, Network, PrivateKey, PublicKey};
use ::wownero::{Address, Network, PrivateKey, PublicKey};
use anyhow::{Context, Result};
use monero_rpc::wallet;
use monero_rpc::wallet::{BlockHeight, CheckTxKey, MoneroWalletRpc as _, Refreshed};
use wownero_rpc::wallet;
use wownero_rpc::wallet::{BlockHeight, CheckTxKey, WowneroWalletRpc as _, Refreshed};
use std::future::Future;
use std::str::FromStr;
use std::time::Duration;
@ -18,7 +18,7 @@ pub struct Wallet {
inner: Mutex<wallet::Client>,
network: Network,
name: String,
main_address: monero::Address,
main_address: wownero::Address,
sync_interval: Duration,
}
@ -30,12 +30,12 @@ impl Wallet {
let open_wallet_response = client.open_wallet(name.clone()).await;
if open_wallet_response.is_err() {
client.create_wallet(name.clone(), "English".to_owned()).await.context(
"Unable to create Monero wallet, please ensure that the monero-wallet-rpc is available",
"Unable to create Wownero wallet, please ensure that the wownero-wallet-rpc is available",
)?;
tracing::debug!(monero_wallet_name = %name, "Created Monero wallet");
tracing::debug!(wownero_wallet_name = %name, "Created Wownero wallet");
} else {
tracing::debug!(monero_wallet_name = %name, "Opened Monero wallet");
tracing::debug!(wownero_wallet_name = %name, "Opened Wownero wallet");
}
Self::connect(client, name, env_config).await
@ -44,13 +44,13 @@ impl Wallet {
/// Connects to a wallet RPC where a wallet is already loaded.
pub async fn connect(client: wallet::Client, name: String, env_config: Config) -> Result<Self> {
let main_address =
monero::Address::from_str(client.get_address(0).await?.address.as_str())?;
wownero::Address::from_str(client.get_address(0).await?.address.as_str())?;
Ok(Self {
inner: Mutex::new(client),
network: env_config.monero_network,
network: env_config.wownero_network,
name,
main_address,
sync_interval: env_config.monero_sync_interval(),
sync_interval: env_config.wownero_sync_interval(),
})
}
@ -150,14 +150,14 @@ impl Wallet {
for tx in sweep_all.tx_hash_list {
tracing::info!(
%tx,
monero_address = %self.main_address,
"Monero transferred back to default wallet");
wownero_address = %self.main_address,
"Wownero transferred back to default wallet");
}
}
Err(error) => {
tracing::warn!(
address = %self.main_address,
"Failed to transfer Monero to default wallet: {:#}", error
"Failed to transfer Wownero to default wallet: {:#}", error
);
}
},
@ -192,7 +192,7 @@ impl Wallet {
%amount,
to = %public_spend_key,
tx_id = %res.tx_hash,
"Successfully initiated Monero transfer"
"Successfully initiated Wownero transfer"
);
Ok(TransferProof::new(
@ -216,7 +216,7 @@ impl Wallet {
tracing::info!(
%txid,
target_confirmations = %conf_target,
"Waiting for Monero transaction finality"
"Waiting for Wownero transaction finality"
);
let address = Address::standard(self.network, public_spend_key, public_view_key.into());
@ -338,7 +338,7 @@ where
%txid,
%seen_confirmations,
needed_confirmations = %conf_target,
"Received new confirmation for Monero lock tx"
"Received new confirmation for Wownero lock tx"
);
}
}
@ -349,7 +349,7 @@ where
#[cfg(test)]
mod tests {
use super::*;
use monero_rpc::wallet::CheckTxKey;
use wownero_rpc::wallet::CheckTxKey;
use std::sync::atomic::{AtomicU32, AtomicU64, Ordering};
use std::sync::Arc;

@ -1,8 +1,8 @@
use ::monero::Network;
use ::wownero::Network;
use anyhow::{Context, Result};
use big_bytes::BigByte;
use futures::{StreamExt, TryStreamExt};
use monero_rpc::wallet::{Client, MoneroWalletRpc as _};
use wownero_rpc::wallet::{Client, WowneroWalletRpc as _};
use reqwest::header::CONTENT_LENGTH;
use reqwest::Url;
use std::io::ErrorKind;
@ -18,26 +18,26 @@ use tokio_util::io::StreamReader;
compile_error!("unsupported operating system");
#[cfg(target_os = "macos")]
const DOWNLOAD_URL: &str = "http://downloads.getmonero.org/cli/monero-mac-x64-v0.17.2.0.tar.bz2";
const DOWNLOAD_URL: &str = "http://downloads.getwownero.org/cli/wownero-mac-x64-v0.17.2.0.tar.bz2";
#[cfg(all(target_os = "linux", target_arch = "x86_64"))]
const DOWNLOAD_URL: &str = "https://downloads.getmonero.org/cli/monero-linux-x64-v0.17.2.0.tar.bz2";
const DOWNLOAD_URL: &str = "https://downloads.getwownero.org/cli/wownero-linux-x64-v0.17.2.0.tar.bz2";
#[cfg(all(target_os = "linux", target_arch = "arm"))]
const DOWNLOAD_URL: &str =
"https://downloads.getmonero.org/cli/monero-linux-armv7-v0.17.2.0.tar.bz2";
"https://downloads.getwownero.org/cli/wownero-linux-armv7-v0.17.2.0.tar.bz2";
#[cfg(target_os = "windows")]
const DOWNLOAD_URL: &str = "https://downloads.getmonero.org/cli/monero-win-x64-v0.17.2.0.zip";
const DOWNLOAD_URL: &str = "https://downloads.getwownero.org/cli/wownero-win-x64-v0.17.2.0.zip";
#[cfg(any(target_os = "macos", target_os = "linux"))]
const PACKED_FILE: &str = "monero-wallet-rpc";
const PACKED_FILE: &str = "wownero-wallet-rpc";
#[cfg(target_os = "windows")]
const PACKED_FILE: &str = "monero-wallet-rpc.exe";
const PACKED_FILE: &str = "wownero-wallet-rpc.exe";
#[derive(Debug, Clone, Copy, thiserror::Error)]
#[error("monero wallet rpc executable not found in downloaded archive")]
#[error("wownero wallet rpc executable not found in downloaded archive")]
pub struct ExecutableNotFoundInArchive;
pub struct WalletRpcProcess {
@ -64,21 +64,21 @@ impl WalletRpc {
tokio::fs::create_dir(working_dir).await?;
}
let monero_wallet_rpc = WalletRpc {
let wownero_wallet_rpc = WalletRpc {
working_dir: working_dir.to_path_buf(),
};
if monero_wallet_rpc.archive_path().exists() {
remove_file(monero_wallet_rpc.archive_path()).await?;
if wownero_wallet_rpc.archive_path().exists() {
remove_file(wownero_wallet_rpc.archive_path()).await?;
}
if !monero_wallet_rpc.exec_path().exists() {
if !wownero_wallet_rpc.exec_path().exists() {
let mut options = OpenOptions::new();
let mut file = options
.read(true)
.write(true)
.create_new(true)
.open(monero_wallet_rpc.archive_path())
.open(wownero_wallet_rpc.archive_path())
.await?;
let response = reqwest::get(DOWNLOAD_URL).await?;
@ -89,7 +89,7 @@ impl WalletRpc {
.parse::<u64>()?;
tracing::info!(
"Downloading monero-wallet-rpc ({}) from {}",
"Downloading wownero-wallet-rpc ({}) from {}",
content_length.big_byte(2),
DOWNLOAD_URL
);
@ -115,9 +115,9 @@ impl WalletRpc {
file.flush().await?;
Self::extract_archive(&monero_wallet_rpc).await?;
Self::extract_archive(&wownero_wallet_rpc).await?;
}
Ok(monero_wallet_rpc)
Ok(wownero_wallet_rpc)
}
pub async fn run(&self, network: Network, daemon_address: &str) -> Result<WalletRpcProcess> {
@ -128,7 +128,7 @@ impl WalletRpc {
tracing::debug!(
%port,
"Starting monero-wallet-rpc"
"Starting wownero-wallet-rpc"
);
let network_flag = match network {
@ -154,13 +154,13 @@ impl WalletRpc {
.arg(format!("{}", port))
.arg("--disable-rpc-login")
.arg("--wallet-dir")
.arg(self.working_dir.join("monero-data"))
.arg(self.working_dir.join("wownero-data"))
.spawn()?;
let stdout = child
.stdout
.take()
.expect("monero wallet rpc stdout was not piped parent process");
.expect("wownero wallet rpc stdout was not piped parent process");
let mut reader = BufReader::new(stdout).lines();
@ -171,7 +171,7 @@ impl WalletRpc {
}
}
// If we do not hear from the monero_wallet_rpc process for 3 seconds we assume
// If we do not hear from the wownero_wallet_rpc process for 3 seconds we assume
// it is is ready
#[cfg(target_os = "windows")]
while let Ok(line) =
@ -180,7 +180,7 @@ impl WalletRpc {
line?;
}
// Send a json rpc request to make sure monero_wallet_rpc is ready
// Send a json rpc request to make sure wownero_wallet_rpc is ready
Client::localhost(port)?.get_version().await?;
Ok(WalletRpcProcess {
@ -190,7 +190,7 @@ impl WalletRpc {
}
fn archive_path(&self) -> PathBuf {
self.working_dir.join("monero-cli-wallet.archive")
self.working_dir.join("wownero-cli-wallet.archive")
}
fn exec_path(&self) -> PathBuf {
@ -198,14 +198,14 @@ impl WalletRpc {
}
#[cfg(not(target_os = "windows"))]
async fn extract_archive(monero_wallet_rpc: &Self) -> Result<()> {
async fn extract_archive(wownero_wallet_rpc: &Self) -> Result<()> {
use anyhow::bail;
use tokio_tar::Archive;
let mut options = OpenOptions::new();
let file = options
.read(true)
.open(monero_wallet_rpc.archive_path())
.open(wownero_wallet_rpc.archive_path())
.await?;
let mut ar = Archive::new(file);
@ -220,7 +220,7 @@ impl WalletRpc {
.context("Could not find convert path to str in tar ball")?
.contains(PACKED_FILE)
{
f.unpack(monero_wallet_rpc.exec_path()).await?;
f.unpack(wownero_wallet_rpc.exec_path()).await?;
break;
}
}
@ -228,19 +228,19 @@ impl WalletRpc {
}
}
remove_file(monero_wallet_rpc.archive_path()).await?;
remove_file(wownero_wallet_rpc.archive_path()).await?;
Ok(())
}
#[cfg(target_os = "windows")]
async fn extract_archive(monero_wallet_rpc: &Self) -> Result<()> {
async fn extract_archive(wownero_wallet_rpc: &Self) -> Result<()> {
use std::fs::File;
use tokio::task::JoinHandle;
use zip::ZipArchive;
let archive_path = monero_wallet_rpc.archive_path();
let exec_path = monero_wallet_rpc.exec_path();
let archive_path = wownero_wallet_rpc.archive_path();
let exec_path = wownero_wallet_rpc.exec_path();
let extract: JoinHandle<Result<()>> = tokio::task::spawn_blocking(|| {
let file = File::open(archive_path)?;
@ -259,7 +259,7 @@ impl WalletRpc {
});
extract.await??;
remove_file(monero_wallet_rpc.archive_path()).await?;
remove_file(wownero_wallet_rpc.archive_path()).await?;
Ok(())
}

@ -5,7 +5,7 @@ pub trait ScalarExt {
fn to_secpfun_scalar(&self) -> ecdsa_fun::fun::Scalar;
}
impl ScalarExt for crate::monero::Scalar {
impl ScalarExt for crate::wownero::Scalar {
fn to_secpfun_scalar(&self) -> Scalar<Secret, NonZero> {
let mut little_endian_bytes = self.to_bytes();

@ -1,6 +1,6 @@
pub mod harness;
use harness::alice_run_until::is_xmr_lock_transaction_sent;
use harness::alice_run_until::is_wow_lock_transaction_sent;
use harness::bob_run_until::is_btc_locked;
use harness::FastCancelConfig;
use swap::asb::FixedRate;
@ -19,7 +19,7 @@ async fn given_alice_and_bob_manually_refund_after_funds_locked_both_refund() {
let alice_swap = ctx.alice_next_swap().await;
let alice_swap = tokio::spawn(alice::run_until(
alice_swap,
is_xmr_lock_transaction_sent,
is_wow_lock_transaction_sent,
FixedRate::default(),
));
@ -29,7 +29,7 @@ async fn given_alice_and_bob_manually_refund_after_funds_locked_both_refund() {
let alice_state = alice_swap.await??;
assert!(matches!(
alice_state,
AliceState::XmrLockTransactionSent { .. }
AliceState::WowLockTransactionSent { .. }
));
let (bob_swap, bob_join_handle) = ctx
@ -72,7 +72,7 @@ async fn given_alice_and_bob_manually_refund_after_funds_locked_both_refund() {
let alice_swap = ctx.alice_next_swap().await;
assert!(matches!(
alice_swap.state,
AliceState::XmrLockTransactionSent { .. }
AliceState::WowLockTransactionSent { .. }
));
asb::cancel(
@ -90,7 +90,7 @@ async fn given_alice_and_bob_manually_refund_after_funds_locked_both_refund() {
let alice_state = asb::refund(
alice_swap.swap_id,
alice_swap.bitcoin_wallet,
alice_swap.monero_wallet,
alice_swap.wownero_wallet,
alice_swap.db,
false,
)

@ -1,6 +1,6 @@
pub mod harness;
use harness::alice_run_until::is_xmr_lock_transaction_sent;
use harness::alice_run_until::is_wow_lock_transaction_sent;
use harness::bob_run_until::is_btc_locked;
use harness::SlowCancelConfig;
use swap::asb::FixedRate;
@ -19,7 +19,7 @@ async fn given_alice_and_bob_manually_cancel_when_timelock_not_expired_errors()
let alice_swap = ctx.alice_next_swap().await;
let alice_swap = tokio::spawn(alice::run_until(
alice_swap,
is_xmr_lock_transaction_sent,
is_wow_lock_transaction_sent,
FixedRate::default(),
));
@ -34,7 +34,7 @@ async fn given_alice_and_bob_manually_cancel_when_timelock_not_expired_errors()
let alice_state = alice_swap.await??;
assert!(matches!(
alice_state,
AliceState::XmrLockTransactionSent { .. }
AliceState::WowLockTransactionSent { .. }
));
// Bob tries but fails to manually cancel
@ -50,7 +50,7 @@ async fn given_alice_and_bob_manually_cancel_when_timelock_not_expired_errors()
let alice_swap = ctx.alice_next_swap().await;
assert!(matches!(
alice_swap.state,
AliceState::XmrLockTransactionSent { .. }
AliceState::WowLockTransactionSent { .. }
));
// Alice tries but fails manual cancel
@ -87,14 +87,14 @@ async fn given_alice_and_bob_manually_cancel_when_timelock_not_expired_errors()
let alice_swap = ctx.alice_next_swap().await;
assert!(matches!(
alice_swap.state,
AliceState::XmrLockTransactionSent { .. }
AliceState::WowLockTransactionSent { .. }
));
// Alice tries but fails manual cancel
let result = asb::refund(
alice_swap.swap_id,
alice_swap.bitcoin_wallet,
alice_swap.monero_wallet,
alice_swap.wownero_wallet,
alice_swap.db,
false,
)
@ -106,7 +106,7 @@ async fn given_alice_and_bob_manually_cancel_when_timelock_not_expired_errors()
let alice_swap = ctx.alice_next_swap().await;
assert!(matches!(
alice_swap.state,
AliceState::XmrLockTransactionSent { .. }
AliceState::WowLockTransactionSent { .. }
));
Ok(())

@ -1,6 +1,6 @@
pub mod harness;
use harness::alice_run_until::is_xmr_lock_transaction_sent;
use harness::alice_run_until::is_wow_lock_transaction_sent;
use harness::bob_run_until::is_btc_locked;
use harness::SlowCancelConfig;
use swap::asb::FixedRate;
@ -19,7 +19,7 @@ async fn given_alice_and_bob_manually_force_cancel_when_timelock_not_expired_err
let alice_swap = ctx.alice_next_swap().await;
let alice_swap = tokio::spawn(alice::run_until(
alice_swap,
is_xmr_lock_transaction_sent,
is_wow_lock_transaction_sent,
FixedRate::default(),
));
@ -34,7 +34,7 @@ async fn given_alice_and_bob_manually_force_cancel_when_timelock_not_expired_err
let alice_state = alice_swap.await??;
assert!(matches!(
alice_state,
AliceState::XmrLockTransactionSent { .. }
AliceState::WowLockTransactionSent { .. }
));
// Bob tries but fails to manually cancel
@ -45,7 +45,7 @@ async fn given_alice_and_bob_manually_force_cancel_when_timelock_not_expired_err
let alice_swap = ctx.alice_next_swap().await;
assert!(matches!(
alice_swap.state,
AliceState::XmrLockTransactionSent { .. }
AliceState::WowLockTransactionSent { .. }
));
// Alice tries but fails manual cancel
@ -79,14 +79,14 @@ async fn given_alice_and_bob_manually_force_cancel_when_timelock_not_expired_err
let alice_swap = ctx.alice_next_swap().await;
assert!(matches!(
alice_swap.state,
AliceState::XmrLockTransactionSent { .. }
AliceState::WowLockTransactionSent { .. }
));
// Alice tries but fails manual cancel
let refund_tx_not_published_yet = asb::refund(
alice_swap.swap_id,
alice_swap.bitcoin_wallet,
alice_swap.monero_wallet,
alice_swap.wownero_wallet,
alice_swap.db,
true,
)
@ -101,7 +101,7 @@ async fn given_alice_and_bob_manually_force_cancel_when_timelock_not_expired_err
let alice_swap = ctx.alice_next_swap().await;
assert!(matches!(
alice_swap.state,
AliceState::XmrLockTransactionSent { .. }
AliceState::WowLockTransactionSent { .. }
));
Ok(())

@ -1,6 +1,6 @@
pub mod harness;
use harness::alice_run_until::is_xmr_lock_transaction_sent;
use harness::alice_run_until::is_wow_lock_transaction_sent;
use harness::bob_run_until::is_btc_locked;
use harness::FastPunishConfig;
use swap::asb;
@ -9,7 +9,7 @@ use swap::protocol::alice::AliceState;
use swap::protocol::bob::BobState;
use swap::protocol::{alice, bob};
/// Bob locks Btc and Alice locks Xmr. Bob does not act; he fails to send Alice
/// Bob locks Btc and Alice locks Wow. Bob does not act; he fails to send Alice
/// the encsig and fail to refund or redeem. Alice punishes using the cancel and
/// punish command.
#[tokio::test]
@ -24,7 +24,7 @@ async fn alice_manually_punishes_after_bob_dead() {
let alice_swap = tokio::spawn(alice::run_until(
alice_swap,
is_xmr_lock_transaction_sent,
is_wow_lock_transaction_sent,
FixedRate::default(),
));
@ -34,7 +34,7 @@ async fn alice_manually_punishes_after_bob_dead() {
let alice_state = alice_swap.await??;
// Ensure cancel timelock is expired
if let AliceState::XmrLockTransactionSent { state3, .. } = alice_state {
if let AliceState::WowLockTransactionSent { state3, .. } = alice_state {
alice_bitcoin_wallet
.subscribe_to(state3.tx_lock)
.await

@ -7,7 +7,7 @@ use swap::asb::{Finality, FixedRate};
use swap::protocol::alice::AliceState;
use swap::protocol::{alice, bob};
/// Bob locks Btc and Alice locks Xmr. Alice redeems using manual redeem command
/// Bob locks Btc and Alice locks Wow. Alice redeems using manual redeem command
/// after learning encsig from Bob
#[tokio::test]
async fn alice_manually_redeems_after_enc_sig_learned() {

@ -1,6 +1,6 @@
pub mod harness;
use harness::alice_run_until::is_xmr_lock_transaction_sent;
use harness::alice_run_until::is_wow_lock_transaction_sent;
use harness::bob_run_until::is_btc_locked;
use harness::FastPunishConfig;
use swap::asb::FixedRate;
@ -8,7 +8,7 @@ use swap::protocol::alice::AliceState;
use swap::protocol::bob::BobState;
use swap::protocol::{alice, bob};
/// Bob locks Btc and Alice locks Xmr. Bob does not act; he fails to send Alice
/// Bob locks Btc and Alice locks Wow. Bob does not act; he fails to send Alice
/// the encsig and fail to refund or redeem. Alice cancels and punishes.
#[tokio::test]
async fn alice_punishes_after_restart_if_bob_dead() {
@ -22,7 +22,7 @@ async fn alice_punishes_after_restart_if_bob_dead() {
let alice_swap = tokio::spawn(alice::run_until(
alice_swap,
is_xmr_lock_transaction_sent,
is_wow_lock_transaction_sent,
FixedRate::default(),
));
@ -33,7 +33,7 @@ async fn alice_punishes_after_restart_if_bob_dead() {
// Ensure cancel timelock is expired (we can only ensure that, because the
// cancel transaction is not published at this point)
if let AliceState::XmrLockTransactionSent { state3, .. } = alice_state {
if let AliceState::WowLockTransactionSent { state3, .. } = alice_state {
alice_bitcoin_wallet
.subscribe_to(state3.tx_lock)
.await

@ -1,12 +1,12 @@
pub mod harness;
use harness::alice_run_until::is_xmr_lock_transaction_sent;
use harness::alice_run_until::is_wow_lock_transaction_sent;
use harness::FastCancelConfig;
use swap::asb::FixedRate;
use swap::protocol::alice::AliceState;
use swap::protocol::{alice, bob};
/// Bob locks Btc and Alice locks Xmr. Alice does not act so Bob refunds.
/// Bob locks Btc and Alice locks Wow. Alice does not act so Bob refunds.
/// Eventually Alice comes back online and refunds as well.
#[tokio::test]
async fn alice_refunds_after_restart_if_bob_already_refunded() {
@ -17,7 +17,7 @@ async fn alice_refunds_after_restart_if_bob_already_refunded() {
let alice_swap = ctx.alice_next_swap().await;
let alice_swap = tokio::spawn(alice::run_until(
alice_swap,
is_xmr_lock_transaction_sent,
is_wow_lock_transaction_sent,
FixedRate::default(),
));
@ -27,7 +27,7 @@ async fn alice_refunds_after_restart_if_bob_already_refunded() {
let alice_state = alice_swap.await??;
assert!(matches!(
alice_state,
AliceState::XmrLockTransactionSent { .. }
AliceState::WowLockTransactionSent { .. }
));
ctx.restart_alice().await;

@ -1,6 +1,6 @@
pub mod harness;
use harness::bob_run_until::is_xmr_locked;
use harness::bob_run_until::is_wow_locked;
use harness::SlowCancelConfig;
use swap::asb::FixedRate;
use swap::protocol::alice::AliceState;
@ -8,19 +8,19 @@ use swap::protocol::bob::BobState;
use swap::protocol::{alice, bob};
#[tokio::test]
async fn concurrent_bobs_after_xmr_lock_proof_sent() {
async fn concurrent_bobs_after_wow_lock_proof_sent() {
harness::setup_test(SlowCancelConfig, |mut ctx| async move {
let (bob_swap_1, bob_join_handle_1) = ctx.bob_swap().await;
let swap_id = bob_swap_1.id;
let bob_swap_1 = tokio::spawn(bob::run_until(bob_swap_1, is_xmr_locked));
let bob_swap_1 = tokio::spawn(bob::run_until(bob_swap_1, is_wow_locked));
let alice_swap_1 = ctx.alice_next_swap().await;
let alice_swap_1 = tokio::spawn(alice::run(alice_swap_1, FixedRate::default()));
let bob_state_1 = bob_swap_1.await??;
assert!(matches!(bob_state_1, BobState::XmrLocked { .. }));
assert!(matches!(bob_state_1, BobState::WowLocked { .. }));
// make sure bob_swap_1's event loop is gone
bob_join_handle_1.abort();
@ -35,7 +35,7 @@ async fn concurrent_bobs_after_xmr_lock_proof_sent() {
// scenario
let bob_state_2 = bob_swap_2.await??;
assert!(matches!(bob_state_2, BobState::XmrRedeemed { .. }));
assert!(matches!(bob_state_2, BobState::WowRedeemed { .. }));
let alice_state_2 = alice_swap_2.await??;
assert!(matches!(alice_state_2, AliceState::BtcRedeemed { .. }));
@ -43,14 +43,14 @@ async fn concurrent_bobs_after_xmr_lock_proof_sent() {
let (bob_swap_1, _) = ctx
.stop_and_resume_bob_from_db(bob_join_handle_2, swap_id)
.await;
assert!(matches!(bob_swap_1.state, BobState::XmrLocked { .. }));
assert!(matches!(bob_swap_1.state, BobState::WowLocked { .. }));
// The 1st (paused) swap ALWAYS finishes successfully in this
// scenario, because it is ensured that Bob already received the
// transfer proof.
let bob_state_1 = bob::run(bob_swap_1).await?;
assert!(matches!(bob_state_1, BobState::XmrRedeemed { .. }));
assert!(matches!(bob_state_1, BobState::WowRedeemed { .. }));
let alice_state_1 = alice_swap_1.await??;
assert!(matches!(alice_state_1, AliceState::BtcRedeemed { .. }));

@ -8,7 +8,7 @@ use swap::protocol::bob::BobState;
use swap::protocol::{alice, bob};
#[tokio::test]
async fn concurrent_bobs_before_xmr_lock_proof_sent() {
async fn concurrent_bobs_before_wow_lock_proof_sent() {
harness::setup_test(SlowCancelConfig, |mut ctx| async move {
let (bob_swap_1, bob_join_handle_1) = ctx.bob_swap().await;
@ -36,7 +36,7 @@ async fn concurrent_bobs_before_xmr_lock_proof_sent() {
// the event loop.
let bob_state_2 = bob_swap_2.await??;
assert!(matches!(bob_state_2, BobState::XmrRedeemed { .. }));
assert!(matches!(bob_state_2, BobState::WowRedeemed { .. }));
let alice_state_2 = alice_swap_2.await??;
assert!(matches!(alice_state_2, AliceState::BtcRedeemed { .. }));
@ -54,7 +54,7 @@ async fn concurrent_bobs_before_xmr_lock_proof_sent() {
assert!(matches!(bob_state_1, BobState::BtcRefunded { .. }));
let alice_state_1 = alice_swap_1.await??;
assert!(matches!(alice_state_1, AliceState::XmrRefunded { .. }));
assert!(matches!(alice_state_1, AliceState::WowRefunded { .. }));
Ok(())
})

@ -1,13 +1,13 @@
pub mod harness;
use harness::alice_run_until::is_xmr_lock_transaction_sent;
use harness::alice_run_until::is_wow_lock_transaction_sent;
use harness::SlowCancelConfig;
use swap::asb::FixedRate;
use swap::protocol::alice::AliceState;
use swap::protocol::{alice, bob};
#[tokio::test]
async fn given_alice_restarts_after_xmr_is_locked_resume_swap() {
async fn given_alice_restarts_after_wow_is_locked_resume_swap() {
harness::setup_test(SlowCancelConfig, |mut ctx| async move {
let (bob_swap, _) = ctx.bob_swap().await;
let bob_swap = tokio::spawn(bob::run(bob_swap));
@ -15,7 +15,7 @@ async fn given_alice_restarts_after_xmr_is_locked_resume_swap() {
let alice_swap = ctx.alice_next_swap().await;
let alice_swap = tokio::spawn(alice::run_until(
alice_swap,
is_xmr_lock_transaction_sent,
is_wow_lock_transaction_sent,
FixedRate::default(),
));
@ -23,14 +23,14 @@ async fn given_alice_restarts_after_xmr_is_locked_resume_swap() {
assert!(matches!(
alice_state,
AliceState::XmrLockTransactionSent { .. }
AliceState::WowLockTransactionSent { .. }
));
ctx.restart_alice().await;
let alice_swap = ctx.alice_next_swap().await;
assert!(matches!(
alice_swap.state,
AliceState::XmrLockTransactionSent { .. }
AliceState::WowLockTransactionSent { .. }
));
let alice_state = alice::run(alice_swap, FixedRate::default()).await?;

@ -1,29 +1,29 @@
pub mod harness;
use harness::bob_run_until::is_xmr_locked;
use harness::bob_run_until::is_wow_locked;
use harness::SlowCancelConfig;
use swap::asb::FixedRate;
use swap::protocol::bob::BobState;
use swap::protocol::{alice, bob};
#[tokio::test]
async fn given_bob_restarts_after_xmr_is_locked_resume_swap() {
async fn given_bob_restarts_after_wow_is_locked_resume_swap() {
harness::setup_test(SlowCancelConfig, |mut ctx| async move {
let (bob_swap, bob_join_handle) = ctx.bob_swap().await;
let bob_swap_id = bob_swap.id;
let bob_swap = tokio::spawn(bob::run_until(bob_swap, is_xmr_locked));
let bob_swap = tokio::spawn(bob::run_until(bob_swap, is_wow_locked));
let alice_swap = ctx.alice_next_swap().await;
let alice_swap = tokio::spawn(alice::run(alice_swap, FixedRate::default()));
let bob_state = bob_swap.await??;
assert!(matches!(bob_state, BobState::XmrLocked { .. }));
assert!(matches!(bob_state, BobState::WowLocked { .. }));
let (bob_swap, _) = ctx
.stop_and_resume_bob_from_db(bob_join_handle, bob_swap_id)
.await;
assert!(matches!(bob_swap.state, BobState::XmrLocked { .. }));
assert!(matches!(bob_swap.state, BobState::WowLocked { .. }));
let bob_state = bob::run(bob_swap).await?;

@ -1,29 +1,29 @@
pub mod harness;
use harness::bob_run_until::is_xmr_locked;
use harness::bob_run_until::is_wow_locked;
use harness::SlowCancelConfig;
use swap::asb::FixedRate;
use swap::protocol::bob::BobState;
use swap::protocol::{alice, bob};
#[tokio::test]
async fn given_bob_restarts_after_xmr_is_locked_resume_swap() {
async fn given_bob_restarts_after_wow_is_locked_resume_swap() {
harness::setup_test(SlowCancelConfig, |mut ctx| async move {
let (bob_swap, bob_join_handle) = ctx.bob_swap().await;
let bob_swap_id = bob_swap.id;
let bob_swap = tokio::spawn(bob::run_until(bob_swap, is_xmr_locked));
let bob_swap = tokio::spawn(bob::run_until(bob_swap, is_wow_locked));
let alice_swap = ctx.alice_next_swap().await;
let alice_swap = tokio::spawn(alice::run(alice_swap, FixedRate::default()));
let bob_state = bob_swap.await??;
assert!(matches!(bob_state, BobState::XmrLocked { .. }));
assert!(matches!(bob_state, BobState::WowLocked { .. }));
let (bob_swap, _) = ctx
.stop_and_resume_bob_from_db(bob_join_handle, bob_swap_id)
.await;
assert!(matches!(bob_swap.state, BobState::XmrLocked { .. }));
assert!(matches!(bob_swap.state, BobState::WowLocked { .. }));
let bob_state = bob::run(bob_swap).await?;

@ -8,7 +8,7 @@ use futures::Future;
use get_port::get_port;
use libp2p::core::Multiaddr;
use libp2p::PeerId;
use monero_harness::{image, Monero};
use wownero_harness::{image, Wownero};
use std::cmp::Ordering;
use std::fmt;
use std::path::{Path, PathBuf};
@ -23,7 +23,7 @@ use swap::protocol::alice::{AliceState, Swap};
use swap::protocol::bob::BobState;
use swap::protocol::{alice, bob};
use swap::seed::Seed;
use swap::{asb, bitcoin, cli, env, monero};
use swap::{asb, bitcoin, cli, env, wownero};
use tempfile::tempdir;
use testcontainers::clients::Cli;
use testcontainers::{Container, Docker, RunArgs};
@ -44,20 +44,20 @@ where
let cli = Cli::default();
let _guard = tracing_subscriber::fmt()
.with_env_filter("warn,swap=debug,monero_harness=debug,monero_rpc=debug,bitcoin_harness=info,testcontainers=info") // add `reqwest::connect::verbose=trace` if you want to logs of the RPC clients
.with_env_filter("warn,swap=debug,wownero_harness=debug,wownero_rpc=debug,bitcoin_harness=info,testcontainers=info") // add `reqwest::connect::verbose=trace` if you want to logs of the RPC clients
.with_test_writer()
.set_default();
let env_config = C::get_config();
let (monero, containers) = init_containers(&cli).await;
monero.init_miner().await.unwrap();
let (wownero, containers) = init_containers(&cli).await;
wownero.init_miner().await.unwrap();
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 wow_amount = wownero::Amount::from_wownero(btc_amount.as_btc() / FixedRate::RATE).unwrap();
let alice_starting_balances =
StartingBalances::new(bitcoin::Amount::ZERO, xmr_amount, Some(10));
StartingBalances::new(bitcoin::Amount::ZERO, wow_amount, Some(10));
let electrs_rpc_port = containers
.electrs
@ -65,10 +65,10 @@ where
.expect("Could not map electrs rpc port");
let alice_seed = Seed::random().unwrap();
let (alice_bitcoin_wallet, alice_monero_wallet) = init_test_wallets(
MONERO_WALLET_NAME_ALICE,
let (alice_bitcoin_wallet, alice_wownero_wallet) = init_test_wallets(
WOWNERO_WALLET_NAME_ALICE,
containers.bitcoind_url.clone(),
&monero,
&wownero,
alice_starting_balances.clone(),
tempdir().unwrap().path(),
electrs_rpc_port,
@ -89,17 +89,17 @@ where
alice_listen_address.clone(),
env_config,
alice_bitcoin_wallet.clone(),
alice_monero_wallet.clone(),
alice_wownero_wallet.clone(),
)
.await;
let bob_seed = Seed::random().unwrap();
let bob_starting_balances = StartingBalances::new(btc_amount * 10, monero::Amount::ZERO, None);
let bob_starting_balances = StartingBalances::new(btc_amount * 10, wownero::Amount::ZERO, None);
let (bob_bitcoin_wallet, bob_monero_wallet) = init_test_wallets(
MONERO_WALLET_NAME_BOB,
let (bob_bitcoin_wallet, bob_wownero_wallet) = init_test_wallets(
WOWNERO_WALLET_NAME_BOB,
containers.bitcoind_url,
&monero,
&wownero,
bob_starting_balances.clone(),
tempdir().unwrap().path(),
electrs_rpc_port,
@ -112,36 +112,36 @@ where
seed: Seed::random().unwrap(),
db_path: tempdir().unwrap().path().to_path_buf(),
bitcoin_wallet: bob_bitcoin_wallet.clone(),
monero_wallet: bob_monero_wallet.clone(),
wownero_wallet: bob_wownero_wallet.clone(),
alice_address: alice_listen_address.clone(),
alice_peer_id: alice_handle.peer_id,
env_config,
};
monero.start_miner().await.unwrap();
wownero.start_miner().await.unwrap();
let test = TestContext {
env_config,
btc_amount,
xmr_amount,
wow_amount,
alice_seed,
alice_db_path,
alice_listen_address,
alice_starting_balances,
alice_bitcoin_wallet,
alice_monero_wallet,
alice_wownero_wallet,
alice_swap_handle,
alice_handle,
bob_params,
bob_starting_balances,
bob_bitcoin_wallet,
bob_monero_wallet,
bob_wownero_wallet,
};
testfn(test).await.unwrap()
}
async fn init_containers(cli: &Cli) -> (Monero, Containers<'_>) {
async fn init_containers(cli: &Cli) -> (Wownero, Containers<'_>) {
let prefix = random_prefix();
let bitcoind_name = format!("{}_{}", prefix, "bitcoind");
let (bitcoind, bitcoind_url) =
@ -151,16 +151,16 @@ async fn init_containers(cli: &Cli) -> (Monero, Containers<'_>) {
let electrs = init_electrs_container(&cli, prefix.clone(), bitcoind_name, prefix)
.await
.expect("could not init electrs");
let (monero, monerod_container, monero_wallet_rpc_containers) =
Monero::new(&cli, vec![MONERO_WALLET_NAME_ALICE, MONERO_WALLET_NAME_BOB])
let (wownero, wownerod_container, wownero_wallet_rpc_containers) =
Wownero::new(&cli, vec![WOWNERO_WALLET_NAME_ALICE, WOWNERO_WALLET_NAME_BOB])
.await
.unwrap();
(monero, Containers {
(wownero, Containers {
bitcoind_url,
bitcoind,
monerod_container,
monero_wallet_rpc_containers,
wownerod_container,
wownero_wallet_rpc_containers,
electrs,
})
}
@ -220,7 +220,7 @@ async fn start_alice(
listen_address: Multiaddr,
env_config: Config,
bitcoin_wallet: Arc<bitcoin::Wallet>,
monero_wallet: Arc<monero::Wallet>,
wownero_wallet: Arc<wownero::Wallet>,
) -> (AliceApplicationHandle, Receiver<alice::Swap>) {
let db = Arc::new(Database::open(db_path.as_path()).unwrap());
@ -245,7 +245,7 @@ async fn start_alice(
swarm,
env_config,
bitcoin_wallet,
monero_wallet,
wownero_wallet,
db,
FixedRate::default(),
min_buy,
@ -263,18 +263,18 @@ async fn start_alice(
async fn init_test_wallets(
name: &str,
bitcoind_url: Url,
monero: &Monero,
wownero: &Wownero,
starting_balances: StartingBalances,
datadir: &Path,
electrum_rpc_port: u16,
seed: &Seed,
env_config: Config,
) -> (Arc<bitcoin::Wallet>, Arc<monero::Wallet>) {
monero
) -> (Arc<bitcoin::Wallet>, Arc<wownero::Wallet>) {
wownero
.init_wallet(
name,
starting_balances
.xmr_outputs
.wow_outputs
.into_iter()
.map(|amount| amount.as_piconero())
.collect(),
@ -282,8 +282,8 @@ async fn init_test_wallets(
.await
.unwrap();
let xmr_wallet = swap::monero::Wallet::connect(
monero.wallet(name).unwrap().client().clone(),
let wow_wallet = swap::wownero::Wallet::connect(
wownero.wallet(name).unwrap().client().clone(),
name.to_string(),
env_config,
)
@ -336,52 +336,52 @@ async fn init_test_wallets(
}
}
(Arc::new(btc_wallet), Arc::new(xmr_wallet))
(Arc::new(btc_wallet), Arc::new(wow_wallet))
}
const MONERO_WALLET_NAME_BOB: &str = "bob";
const MONERO_WALLET_NAME_ALICE: &str = "alice";
const WOWNERO_WALLET_NAME_BOB: &str = "bob";
const WOWNERO_WALLET_NAME_ALICE: &str = "alice";
const BITCOIN_TEST_WALLET_NAME: &str = "testwallet";
#[derive(Debug, Clone)]
pub struct StartingBalances {
pub xmr: monero::Amount,
pub xmr_outputs: Vec<monero::Amount>,
pub wow: wownero::Amount,
pub wow_outputs: Vec<wownero::Amount>,
pub btc: bitcoin::Amount,
}
impl StartingBalances {
/// If monero_outputs is specified the monero balance will be:
/// monero_outputs * new_xmr = self_xmr
pub fn new(btc: bitcoin::Amount, xmr: monero::Amount, monero_outputs: Option<u64>) -> Self {
match monero_outputs {
/// If wownero_outputs is specified the wownero balance will be:
/// wownero_outputs * new_wow = self_wow
pub fn new(btc: bitcoin::Amount, wow: wownero::Amount, wownero_outputs: Option<u64>) -> Self {
match wownero_outputs {
None => {
if xmr == monero::Amount::ZERO {
if wow == wownero::Amount::ZERO {
return Self {
xmr,
xmr_outputs: vec![],
wow,
wow_outputs: vec![],
btc,
};
}
Self {
xmr,
xmr_outputs: vec![xmr],
wow,
wow_outputs: vec![wow],
btc,
}
}
Some(outputs) => {
let mut xmr_outputs = Vec::new();
let mut sum_xmr = monero::Amount::ZERO;
let mut wow_outputs = Vec::new();
let mut sum_wow = wownero::Amount::ZERO;
for _ in 0..outputs {
xmr_outputs.push(xmr);
sum_xmr = sum_xmr + xmr;
wow_outputs.push(wow);
sum_wow = sum_wow + wow;
}
Self {
xmr: sum_xmr,
xmr_outputs,
wow: sum_wow,
wow_outputs,
btc,
}
}
@ -393,7 +393,7 @@ struct BobParams {
seed: Seed,
db_path: PathBuf,
bitcoin_wallet: Arc<bitcoin::Wallet>,
monero_wallet: Arc<monero::Wallet>,
wownero_wallet: Arc<wownero::Wallet>,
alice_address: Multiaddr,
alice_peer_id: PeerId,
env_config: Config,
@ -408,10 +408,10 @@ impl BobParams {
db,
swap_id,
self.bitcoin_wallet.clone(),
self.monero_wallet.clone(),
self.wownero_wallet.clone(),
self.env_config,
handle,
self.monero_wallet.get_main_address(),
self.wownero_wallet.get_main_address(),
)?;
Ok((swap, event_loop))
@ -430,10 +430,10 @@ impl BobParams {
db,
swap_id,
self.bitcoin_wallet.clone(),
self.monero_wallet.clone(),
self.wownero_wallet.clone(),
self.env_config,
handle,
self.monero_wallet.get_main_address(),
self.wownero_wallet.get_main_address(),
self.bitcoin_wallet.new_address().await?,
btc_amount,
);
@ -490,7 +490,7 @@ pub struct TestContext {
env_config: Config,
btc_amount: bitcoin::Amount,
xmr_amount: monero::Amount,
wow_amount: wownero::Amount,
alice_seed: Seed,
alice_db_path: PathBuf,
@ -498,14 +498,14 @@ pub struct TestContext {
alice_starting_balances: StartingBalances,
alice_bitcoin_wallet: Arc<bitcoin::Wallet>,
alice_monero_wallet: Arc<monero::Wallet>,
alice_wownero_wallet: Arc<wownero::Wallet>,
alice_swap_handle: mpsc::Receiver<Swap>,
alice_handle: AliceApplicationHandle,
bob_params: BobParams,
bob_starting_balances: StartingBalances,
bob_bitcoin_wallet: Arc<bitcoin::Wallet>,
bob_monero_wallet: Arc<monero::Wallet>,
bob_wownero_wallet: Arc<wownero::Wallet>,
}
impl TestContext {
@ -518,7 +518,7 @@ impl TestContext {
self.alice_listen_address.clone(),
self.env_config,
self.alice_bitcoin_wallet.clone(),
self.alice_monero_wallet.clone(),
self.alice_wownero_wallet.clone(),
)
.await;
@ -570,16 +570,16 @@ impl TestContext {
.unwrap();
assert_eventual_balance(
self.alice_monero_wallet.as_ref(),
self.alice_wownero_wallet.as_ref(),
Ordering::Less,
self.alice_redeemed_xmr_balance(),
self.alice_redeemed_wow_balance(),
)
.await
.unwrap();
}
pub async fn assert_alice_refunded(&mut self, state: AliceState) {
assert!(matches!(state, AliceState::XmrRefunded));
assert!(matches!(state, AliceState::WowRefunded));
assert_eventual_balance(
self.alice_bitcoin_wallet.as_ref(),
@ -591,9 +591,9 @@ impl TestContext {
// Alice pays fees - comparison does not take exact lock fee into account
assert_eventual_balance(
self.alice_monero_wallet.as_ref(),
self.alice_wownero_wallet.as_ref(),
Ordering::Greater,
self.alice_refunded_xmr_balance(),
self.alice_refunded_wow_balance(),
)
.await
.unwrap();
@ -611,9 +611,9 @@ impl TestContext {
.unwrap();
assert_eventual_balance(
self.alice_monero_wallet.as_ref(),
self.alice_wownero_wallet.as_ref(),
Ordering::Less,
self.alice_punished_xmr_balance(),
self.alice_punished_wow_balance(),
)
.await
.unwrap();
@ -629,12 +629,12 @@ impl TestContext {
.unwrap();
// unload the generated wallet by opening the original wallet
self.bob_monero_wallet.re_open().await.unwrap();
self.bob_wownero_wallet.re_open().await.unwrap();
assert_eventual_balance(
self.bob_monero_wallet.as_ref(),
self.bob_wownero_wallet.as_ref(),
Ordering::Greater,
self.bob_redeemed_xmr_balance(),
self.bob_redeemed_wow_balance(),
)
.await
.unwrap();
@ -673,9 +673,9 @@ impl TestContext {
assert!(bob_cancelled_and_refunded);
assert_eventual_balance(
self.bob_monero_wallet.as_ref(),
self.bob_wownero_wallet.as_ref(),
Ordering::Equal,
self.bob_refunded_xmr_balance(),
self.bob_refunded_wow_balance(),
)
.await
.unwrap();
@ -691,16 +691,16 @@ impl TestContext {
.unwrap();
assert_eventual_balance(
self.bob_monero_wallet.as_ref(),
self.bob_wownero_wallet.as_ref(),
Ordering::Equal,
self.bob_punished_xmr_balance(),
self.bob_punished_wow_balance(),
)
.await
.unwrap();
}
fn alice_redeemed_xmr_balance(&self) -> monero::Amount {
self.alice_starting_balances.xmr - self.xmr_amount
fn alice_redeemed_wow_balance(&self) -> wownero::Amount {
self.alice_starting_balances.wow - self.wow_amount
}
async fn alice_redeemed_btc_balance(&self) -> bitcoin::Amount {
@ -712,17 +712,17 @@ impl TestContext {
self.alice_starting_balances.btc + self.btc_amount - fee
}
fn bob_redeemed_xmr_balance(&self) -> monero::Amount {
self.bob_starting_balances.xmr
fn bob_redeemed_wow_balance(&self) -> wownero::Amount {
self.bob_starting_balances.wow
}
async fn bob_redeemed_btc_balance(&self, state: BobState) -> Result<bitcoin::Amount> {
self.bob_bitcoin_wallet.sync().await?;
let lock_tx_id = if let BobState::XmrRedeemed { tx_lock_id } = state {
let lock_tx_id = if let BobState::WowRedeemed { tx_lock_id } = state {
tx_lock_id
} else {
bail!("Bob in not in xmr redeemed state: {:?}", state);
bail!("Bob in not in wow redeemed state: {:?}", state);
};
let lock_tx_bitcoin_fee = self.bob_bitcoin_wallet.transaction_fee(lock_tx_id).await?;
@ -730,20 +730,20 @@ impl TestContext {
Ok(self.bob_starting_balances.btc - self.btc_amount - lock_tx_bitcoin_fee)
}
fn alice_refunded_xmr_balance(&self) -> monero::Amount {
self.alice_starting_balances.xmr - self.xmr_amount
fn alice_refunded_wow_balance(&self) -> wownero::Amount {
self.alice_starting_balances.wow - self.wow_amount
}
fn alice_refunded_btc_balance(&self) -> bitcoin::Amount {
self.alice_starting_balances.btc
}
fn bob_refunded_xmr_balance(&self) -> monero::Amount {
self.bob_starting_balances.xmr
fn bob_refunded_wow_balance(&self) -> wownero::Amount {
self.bob_starting_balances.wow
}
fn alice_punished_xmr_balance(&self) -> monero::Amount {
self.alice_starting_balances.xmr - self.xmr_amount
fn alice_punished_wow_balance(&self) -> wownero::Amount {
self.alice_starting_balances.wow - self.wow_amount
}
async fn alice_punished_btc_balance(&self) -> bitcoin::Amount {
@ -760,8 +760,8 @@ impl TestContext {
self.alice_starting_balances.btc + self.btc_amount - cancel_fee - punish_fee
}
fn bob_punished_xmr_balance(&self) -> monero::Amount {
self.bob_starting_balances.xmr
fn bob_punished_wow_balance(&self) -> wownero::Amount {
self.bob_starting_balances.wow
}
async fn bob_punished_btc_balance(&self, state: BobState) -> Result<bitcoin::Amount> {
@ -836,8 +836,8 @@ trait Wallet {
}
#[async_trait]
impl Wallet for monero::Wallet {
type Amount = monero::Amount;
impl Wallet for wownero::Wallet {
type Amount = wownero::Amount;
async fn refresh(&self) -> Result<()> {
self.refresh().await?;
@ -931,16 +931,16 @@ pub async fn mint(node_url: Url, address: bitcoin::Address, amount: bitcoin::Amo
struct Containers<'a> {
bitcoind_url: Url,
bitcoind: Container<'a, Cli, bitcoind::Bitcoind>,
monerod_container: Container<'a, Cli, image::Monerod>,
monero_wallet_rpc_containers: Vec<Container<'a, Cli, image::MoneroWalletRpc>>,
wownerod_container: Container<'a, Cli, image::Wownerod>,
wownero_wallet_rpc_containers: Vec<Container<'a, Cli, image::WowneroWalletRpc>>,
electrs: Container<'a, Cli, electrs::Electrs>,
}
pub mod alice_run_until {
use swap::protocol::alice::AliceState;
pub fn is_xmr_lock_transaction_sent(state: &AliceState) -> bool {
matches!(state, AliceState::XmrLockTransactionSent { .. })
pub fn is_wow_lock_transaction_sent(state: &AliceState) -> bool {
matches!(state, AliceState::WowLockTransactionSent { .. })
}
pub fn is_encsig_learned(state: &AliceState) -> bool {
@ -956,11 +956,11 @@ pub mod bob_run_until {
}
pub fn is_lock_proof_received(state: &BobState) -> bool {
matches!(state, BobState::XmrLockProofReceived { .. })
matches!(state, BobState::WowLockProofReceived { .. })
}
pub fn is_xmr_locked(state: &BobState) -> bool {
matches!(state, BobState::XmrLocked(..))
pub fn is_wow_locked(state: &BobState) -> bool {
matches!(state, BobState::WowLocked(..))
}
pub fn is_encsig_sent(state: &BobState) -> bool {

@ -6,7 +6,7 @@ use swap::asb::FixedRate;
use swap::protocol::bob::BobState;
use swap::protocol::{alice, bob};
/// Bob locks Btc and Alice locks Xmr. Bob does not act; he fails to send Alice
/// Bob locks Btc and Alice locks Wow. Bob does not act; he fails to send Alice
/// the encsig and fail to refund or redeem. Alice punishes.
#[tokio::test]
async fn alice_punishes_if_bob_never_acts_after_fund() {

@ -1,5 +1,5 @@
[package]
name = "monero-harness"
name = "wownero-harness"
version = "0.1.0"
authors = [ "CoBloX Team <team@coblox.tech>" ]
edition = "2018"
@ -8,7 +8,7 @@ publish = false
[dependencies]
anyhow = "1"
futures = "0.3"
monero-rpc = { path = "../monero-rpc" }
wownero-rpc = { path = "../wownero-rpc" }
rand = "0.7"
spectral = "0.6"
testcontainers = "0.12"

@ -2,30 +2,30 @@ use std::collections::HashMap;
use testcontainers::core::{Container, Docker, WaitForMessage};
use testcontainers::Image;
pub const MONEROD_DAEMON_CONTAINER_NAME: &str = "monerod";
pub const MONEROD_DEFAULT_NETWORK: &str = "monero_network";
pub const WOWNEROD_DAEMON_CONTAINER_NAME: &str = "wownerod";
pub const WOWNEROD_DEFAULT_NETWORK: &str = "wownero_network";
/// The port we use for all RPC communication.
///
/// This is the default when running monerod.
/// For `monero-wallet-rpc` we always need to specify a port. To make things
/// This is the default when running wownerod.
/// For `wownero-wallet-rpc` we always need to specify a port. To make things
/// simpler, we just specify the same one. They are in different containers so
/// this doesn't matter.
pub const RPC_PORT: u16 = 18081;
pub const RPC_PORT: u16 = 34568;
#[derive(Debug)]
pub struct Monerod {
args: MonerodArgs,
pub struct Wownerod {
args: WownerodArgs,
}
impl Image for Monerod {
type Args = MonerodArgs;
impl Image for Wownerod {
type Args = WownerodArgs;
type EnvVars = HashMap<String, String>;
type Volumes = HashMap<String, String>;
type EntryPoint = str;
fn descriptor(&self) -> String {
"xmrto/monero:v0.17.2.0".to_owned()
"wownero:v0.10.1.0".to_owned()
}
fn wait_until_ready<D: Docker>(&self, container: &Container<'_, D, Self>) {
@ -58,27 +58,27 @@ impl Image for Monerod {
}
}
impl Default for Monerod {
impl Default for Wownerod {
fn default() -> Self {
Self {
args: MonerodArgs::default(),
args: WownerodArgs::default(),
}
}
}
#[derive(Debug)]
pub struct MoneroWalletRpc {
args: MoneroWalletRpcArgs,
pub struct WowneroWalletRpc {
args: WowneroWalletRpcArgs,
}
impl Image for MoneroWalletRpc {
type Args = MoneroWalletRpcArgs;
impl Image for WowneroWalletRpc {
type Args = WowneroWalletRpcArgs;
type EnvVars = HashMap<String, String>;
type Volumes = HashMap<String, String>;
type EntryPoint = str;
fn descriptor(&self) -> String {
"xmrto/monero:v0.17.2.0".to_owned()
"wownero:v0.10.1.0".to_owned()
}
fn wait_until_ready<D: Docker>(&self, container: &Container<'_, D, Self>) {
@ -111,24 +111,24 @@ impl Image for MoneroWalletRpc {
}
}
impl Default for MoneroWalletRpc {
impl Default for WowneroWalletRpc {
fn default() -> Self {
Self {
args: MoneroWalletRpcArgs::default(),
args: WowneroWalletRpcArgs::default(),
}
}
}
impl MoneroWalletRpc {
impl WowneroWalletRpc {
pub fn new(name: &str, daemon_address: String) -> Self {
Self {
args: MoneroWalletRpcArgs::new(name, daemon_address),
args: WowneroWalletRpcArgs::new(name, daemon_address),
}
}
}
#[derive(Debug, Clone)]
pub struct MonerodArgs {
pub struct WownerodArgs {
pub regtest: bool,
pub offline: bool,
pub rpc_payment_allow_free_loopback: bool,
@ -140,7 +140,7 @@ pub struct MonerodArgs {
pub data_dir: String,
}
impl Default for MonerodArgs {
impl Default for WownerodArgs {
fn default() -> Self {
Self {
regtest: true,
@ -151,18 +151,18 @@ impl Default for MonerodArgs {
hide_my_port: true,
rpc_bind_ip: "0.0.0.0".to_string(),
fixed_difficulty: 1,
data_dir: "/monero".to_string(),
data_dir: "/wownero".to_string(),
}
}
}
impl IntoIterator for MonerodArgs {
impl IntoIterator for WownerodArgs {
type Item = String;
type IntoIter = ::std::vec::IntoIter<String>;
fn into_iter(self) -> <Self as IntoIterator>::IntoIter {
let mut args = vec![
"monerod".to_string(),
"wownerod".to_string(),
"--log-level=4".to_string(),
"--non-interactive".to_string(),
];
@ -208,7 +208,7 @@ impl IntoIterator for MonerodArgs {
}
#[derive(Debug, Clone)]
pub struct MoneroWalletRpcArgs {
pub struct WowneroWalletRpcArgs {
pub disable_rpc_login: bool,
pub confirm_external_bind: bool,
pub wallet_dir: String,
@ -216,13 +216,13 @@ pub struct MoneroWalletRpcArgs {
pub daemon_address: String,
}
impl Default for MoneroWalletRpcArgs {
impl Default for WowneroWalletRpcArgs {
fn default() -> Self {
unimplemented!("A default instance for `MoneroWalletRpc` doesn't make sense because we always need to connect to a node.")
unimplemented!("A default instance for `WowneroWalletRpc` doesn't make sense because we always need to connect to a node.")
}
}
impl MoneroWalletRpcArgs {
impl WowneroWalletRpcArgs {
pub fn new(wallet_name: &str, daemon_address: String) -> Self {
Self {
disable_rpc_login: true,
@ -234,13 +234,13 @@ impl MoneroWalletRpcArgs {
}
}
impl IntoIterator for MoneroWalletRpcArgs {
impl IntoIterator for WowneroWalletRpcArgs {
type Item = String;
type IntoIter = ::std::vec::IntoIter<String>;
fn into_iter(self) -> <Self as IntoIterator>::IntoIter {
let mut args = vec![
"monero-wallet-rpc".to_string(),
"wownero-wallet-rpc".to_string(),
format!("--wallet-dir={}", self.wallet_dir),
format!("--daemon-address={}", self.daemon_address),
format!("--rpc-bind-port={}", RPC_PORT),

@ -12,21 +12,21 @@
)]
#![forbid(unsafe_code)]
//! # monero-harness
//! # wownero-harness
//!
//! A simple lib to start a monero container (incl. monerod and
//! monero-wallet-rpc). Provides initialisation methods to generate blocks,
//! A simple lib to start a wownero container (incl. wownerod and
//! wownero-wallet-rpc). Provides initialisation methods to generate blocks,
//! create and fund accounts, and start a continuous mining task mining blocks
//! every BLOCK_TIME_SECS seconds.
//!
//! Also provides standalone JSON RPC clients for monerod and monero-wallet-rpc.
//! Also provides standalone JSON RPC clients for wownerod and wownero-wallet-rpc.
pub mod image;
use crate::image::{MONEROD_DAEMON_CONTAINER_NAME, MONEROD_DEFAULT_NETWORK, RPC_PORT};
use crate::image::{WOWNEROD_DAEMON_CONTAINER_NAME, WOWNEROD_DEFAULT_NETWORK, RPC_PORT};
use anyhow::{anyhow, bail, Context, Result};
use monero_rpc::monerod;
use monero_rpc::monerod::MonerodRpc as _;
use monero_rpc::wallet::{self, GetAddress, MoneroWalletRpc as _, Refreshed, Transfer};
use wownero_rpc::wownerod;
use wownero_rpc::wownerod::WownerodRpc as _;
use wownero_rpc::wallet::{self, GetAddress, WowneroWalletRpc as _, Refreshed, Transfer};
use std::time::Duration;
use testcontainers::clients::Cli;
use testcontainers::{Container, Docker, RunArgs};
@ -35,43 +35,43 @@ use tokio::time;
/// How often we mine a block.
const BLOCK_TIME_SECS: u64 = 1;
/// Poll interval when checking if the wallet has synced with monerod.
/// Poll interval when checking if the wallet has synced with wownerod.
const WAIT_WALLET_SYNC_MILLIS: u64 = 1000;
#[derive(Clone, Debug)]
pub struct Monero {
monerod: Monerod,
wallets: Vec<MoneroWalletRpc>,
pub struct Wownero {
wownerod: Wownerod,
wallets: Vec<WowneroWalletRpc>,
}
impl<'c> Monero {
/// Starts a new regtest monero container setup consisting out of 1 monerod
impl<'c> Wownero {
/// Starts a new regtest wownero container setup consisting out of 1 wownerod
/// node and n wallets. The docker container and network will be prefixed
/// with a randomly generated `prefix`. One miner wallet is started
/// automatically.
/// monerod container name is: `prefix`_`monerod`
/// network is: `prefix`_`monero`
/// wownerod container name is: `prefix`_`wownerod`
/// network is: `prefix`_`wownero`
/// miner wallet container name is: `miner`
pub async fn new(
cli: &'c Cli,
additional_wallets: Vec<&'static str>,
) -> Result<(
Self,
Container<'c, Cli, image::Monerod>,
Vec<Container<'c, Cli, image::MoneroWalletRpc>>,
Container<'c, Cli, image::Wownerod>,
Vec<Container<'c, Cli, image::WowneroWalletRpc>>,
)> {
let prefix = format!("{}_", random_prefix());
let monerod_name = format!("{}{}", prefix, MONEROD_DAEMON_CONTAINER_NAME);
let network = format!("{}{}", prefix, MONEROD_DEFAULT_NETWORK);
let wownerod_name = format!("{}{}", prefix, WOWNEROD_DAEMON_CONTAINER_NAME);
let network = format!("{}{}", prefix, WOWNEROD_DEFAULT_NETWORK);
tracing::info!("Starting monerod: {}", monerod_name);
let (monerod, monerod_container) = Monerod::new(cli, monerod_name, network)?;
tracing::info!("Starting wownerod: {}", wownerod_name);
let (wownerod, wownerod_container) = Wownerod::new(cli, wownerod_name, network)?;
let mut containers = vec![];
let mut wallets = vec![];
let miner = "miner";
tracing::info!("Starting miner wallet: {}", miner);
let (miner_wallet, miner_container) =
MoneroWalletRpc::new(cli, &miner, &monerod, prefix.clone()).await?;
WowneroWalletRpc::new(cli, &miner, &wownerod, prefix.clone()).await?;
wallets.push(miner_wallet);
containers.push(miner_container);
@ -83,11 +83,11 @@ impl<'c> Monero {
// trying for 5 minutes
let (wallet, container) = tokio::time::timeout(Duration::from_secs(300), async {
loop {
let result = MoneroWalletRpc::new(cli, &wallet, &monerod, prefix.clone()).await;
let result = WowneroWalletRpc::new(cli, &wallet, &wownerod, prefix.clone()).await;
match result {
Ok(tuple) => { return tuple; }
Err(e) => { tracing::warn!("Monero wallet RPC emitted error {} - retrying to create wallet in 2 seconds...", e); }
Err(e) => { tracing::warn!("Wownero wallet RPC emitted error {} - retrying to create wallet in 2 seconds...", e); }
}
}
}).await.context("All retry attempts for creating a wallet exhausted")?;
@ -96,14 +96,14 @@ impl<'c> Monero {
containers.push(container);
}
Ok((Self { monerod, wallets }, monerod_container, containers))
Ok((Self { wownerod, wallets }, wownerod_container, containers))
}
pub fn monerod(&self) -> &Monerod {
&self.monerod
pub fn wownerod(&self) -> &Wownerod {
&self.wownerod
}
pub fn wallet(&self, name: &str) -> Result<&MoneroWalletRpc> {
pub fn wallet(&self, name: &str) -> Result<&WowneroWalletRpc> {
let wallet = self
.wallets
.iter()
@ -118,8 +118,8 @@ impl<'c> Monero {
let miner_address = miner_wallet.address().await?.address;
// generate the first 70 as bulk
let monerod = &self.monerod;
let res = monerod
let wownerod = &self.wownerod;
let res = wownerod
.client()
.generateblocks(70, miner_address.clone())
.await?;
@ -132,7 +132,7 @@ impl<'c> Monero {
pub async fn init_wallet(&self, name: &str, amount_in_outputs: Vec<u64>) -> Result<()> {
let miner_wallet = self.wallet("miner")?;
let miner_address = miner_wallet.address().await?.address;
let monerod = &self.monerod;
let wownerod = &self.wownerod;
let wallet = self.wallet(name)?;
let address = wallet.address().await?.address;
@ -141,7 +141,7 @@ impl<'c> Monero {
if amount > 0 {
miner_wallet.transfer(&address, amount).await?;
tracing::info!("Funded {} wallet with {}", wallet.name, amount);
monerod
wownerod
.client()
.generateblocks(10, miner_address.clone())
.await?;
@ -155,12 +155,12 @@ impl<'c> Monero {
pub async fn start_miner(&self) -> Result<()> {
let miner_wallet = self.wallet("miner")?;
let miner_address = miner_wallet.address().await?.address;
let monerod = &self.monerod;
let wownerod = &self.wownerod;
monerod.start_miner(&miner_address).await?;
wownerod.start_miner(&miner_address).await?;
tracing::info!("Waiting for miner wallet to catch up...");
let block_height = monerod.client().get_block_count().await?.count;
let block_height = wownerod.client().get_block_count().await?.count;
miner_wallet
.wait_for_wallet_height(block_height)
.await
@ -187,74 +187,74 @@ fn random_prefix() -> String {
}
#[derive(Clone, Debug)]
pub struct Monerod {
pub struct Wownerod {
rpc_port: u16,
name: String,
network: String,
client: monerod::Client,
client: wownerod::Client,
}
#[derive(Clone, Debug)]
pub struct MoneroWalletRpc {
pub struct WowneroWalletRpc {
rpc_port: u16,
name: String,
network: String,
client: wallet::Client,
}
impl<'c> Monerod {
/// Starts a new regtest monero container.
impl<'c> Wownerod {
/// Starts a new regtest wownero container.
fn new(
cli: &'c Cli,
name: String,
network: String,
) -> Result<(Self, Container<'c, Cli, image::Monerod>)> {
let image = image::Monerod::default();
) -> Result<(Self, Container<'c, Cli, image::Wownerod>)> {
let image = image::Wownerod::default();
let run_args = RunArgs::default()
.with_name(name.clone())
.with_network(network.clone());
let container = cli.run_with_args(image, run_args);
let monerod_rpc_port = container
let wownerod_rpc_port = container
.get_host_port(RPC_PORT)
.context("port not exposed")?;
Ok((
Self {
rpc_port: monerod_rpc_port,
rpc_port: wownerod_rpc_port,
name,
network,
client: monerod::Client::localhost(monerod_rpc_port)?,
client: wownerod::Client::localhost(wownerod_rpc_port)?,
},
container,
))
}
pub fn client(&self) -> &monerod::Client {
pub fn client(&self) -> &wownerod::Client {
&self.client
}
/// Spawns a task to mine blocks in a regular interval to the provided
/// address
pub async fn start_miner(&self, miner_wallet_address: &str) -> Result<()> {
let monerod = self.client().clone();
let _ = tokio::spawn(mine(monerod, miner_wallet_address.to_string()));
let wownerod = self.client().clone();
let _ = tokio::spawn(mine(wownerod, miner_wallet_address.to_string()));
Ok(())
}
}
impl<'c> MoneroWalletRpc {
impl<'c> WowneroWalletRpc {
/// Starts a new wallet container which is attached to
/// MONEROD_DEFAULT_NETWORK and MONEROD_DAEMON_CONTAINER_NAME
/// WOWNEROD_DEFAULT_NETWORK and WOWNEROD_DAEMON_CONTAINER_NAME
async fn new(
cli: &'c Cli,
name: &str,
monerod: &Monerod,
wownerod: &Wownerod,
prefix: String,
) -> Result<(Self, Container<'c, Cli, image::MoneroWalletRpc>)> {
let daemon_address = format!("{}:{}", monerod.name, RPC_PORT);
let image = image::MoneroWalletRpc::new(&name, daemon_address);
) -> Result<(Self, Container<'c, Cli, image::WowneroWalletRpc>)> {
let daemon_address = format!("{}:{}", wownerod.name, RPC_PORT);
let image = image::WowneroWalletRpc::new(&name, daemon_address);
let network = monerod.network.clone();
let network = wownerod.network.clone();
let run_args = RunArgs::default()
// prefix the container name so we can run multiple tests
.with_name(format!("{}{}", prefix, name))
@ -285,13 +285,13 @@ impl<'c> MoneroWalletRpc {
&self.client
}
// It takes a little while for the wallet to sync with monerod.
// It takes a little while for the wallet to sync with wownerod.
pub async fn wait_for_wallet_height(&self, height: u32) -> Result<()> {
let mut retry: u8 = 0;
while self.client().get_height().await?.height < height {
if retry >= 30 {
// ~30 seconds
bail!("Wallet could not catch up with monerod after 30 retries.")
bail!("Wallet could not catch up with wownerod after 30 retries.")
}
time::sleep(Duration::from_millis(WAIT_WALLET_SYNC_MILLIS)).await;
retry += 1;
@ -320,9 +320,9 @@ impl<'c> MoneroWalletRpc {
}
}
/// Mine a block ever BLOCK_TIME_SECS seconds.
async fn mine(monerod: monerod::Client, reward_address: String) -> Result<()> {
async fn mine(wownerod: wownerod::Client, reward_address: String) -> Result<()> {
loop {
time::sleep(Duration::from_secs(BLOCK_TIME_SECS)).await;
monerod.generateblocks(1, reward_address.clone()).await?;
wownerod.generateblocks(1, reward_address.clone()).await?;
}
}

@ -1,5 +1,5 @@
use monero_harness::{Monero, MoneroWalletRpc};
use monero_rpc::wallet::MoneroWalletRpc as _;
use wownero_harness::{Wownero, WowneroWalletRpc};
use wownero_rpc::wallet::WowneroWalletRpc as _;
use spectral::prelude::*;
use std::time::Duration;
use testcontainers::clients::Cli;
@ -9,7 +9,7 @@ use tracing_subscriber::util::SubscriberInitExt;
#[tokio::test]
async fn fund_transfer_and_check_tx_key() {
let _guard = tracing_subscriber::fmt()
.with_env_filter("warn,test=debug,monero_harness=debug,monero_rpc=debug")
.with_env_filter("warn,test=debug,wownero_harness=debug,wownero_rpc=debug")
.set_default();
let fund_alice: u64 = 1_000_000_000_000;
@ -17,15 +17,15 @@ async fn fund_transfer_and_check_tx_key() {
let send_to_bob = 5_000_000_000;
let tc = Cli::default();
let (monero, _monerod_container, _wallet_containers) =
Monero::new(&tc, vec!["alice", "bob"]).await.unwrap();
let alice_wallet = monero.wallet("alice").unwrap();
let bob_wallet = monero.wallet("bob").unwrap();
let (wownero, _wownerod_container, _wallet_containers) =
Wownero::new(&tc, vec!["alice", "bob"]).await.unwrap();
let alice_wallet = wownero.wallet("alice").unwrap();
let bob_wallet = wownero.wallet("bob").unwrap();
monero.init_miner().await.unwrap();
monero.init_wallet("alice", vec![fund_alice]).await.unwrap();
monero.init_wallet("bob", vec![fund_bob]).await.unwrap();
monero.start_miner().await.unwrap();
wownero.init_miner().await.unwrap();
wownero.init_wallet("alice", vec![fund_alice]).await.unwrap();
wownero.init_wallet("bob", vec![fund_bob]).await.unwrap();
wownero.start_miner().await.unwrap();
// check alice balance
let got_alice_balance = alice_wallet.balance().await.unwrap();
@ -55,7 +55,7 @@ async fn fund_transfer_and_check_tx_key() {
assert_that!(res.received).is_equal_to(send_to_bob);
}
async fn wait_for_wallet_to_catch_up(wallet: &MoneroWalletRpc, expected_balance: u64) {
async fn wait_for_wallet_to_catch_up(wallet: &WowneroWalletRpc, expected_balance: u64) {
let max_retry = 15;
let mut retry = 0;
loop {

@ -1,5 +1,5 @@
use monero_harness::Monero;
use monero_rpc::monerod::MonerodRpc as _;
use wownero_harness::Wownero;
use wownero_rpc::wownerod::WownerodRpc as _;
use spectral::prelude::*;
use std::time::Duration;
use testcontainers::clients::Cli;
@ -9,16 +9,16 @@ use tracing_subscriber::util::SubscriberInitExt;
#[tokio::test]
async fn init_miner_and_mine_to_miner_address() {
let _guard = tracing_subscriber::fmt()
.with_env_filter("warn,test=debug,monero_harness=debug,monero_rpc=debug")
.with_env_filter("warn,test=debug,wownero_harness=debug,wownero_rpc=debug")
.set_default();
let tc = Cli::default();
let (monero, _monerod_container, _wallet_containers) = Monero::new(&tc, vec![]).await.unwrap();
let (wownero, _wownerod_container, _wallet_containers) = Wownero::new(&tc, vec![]).await.unwrap();
monero.init_and_start_miner().await.unwrap();
wownero.init_and_start_miner().await.unwrap();
let monerod = monero.monerod();
let miner_wallet = monero.wallet("miner").unwrap();
let wownerod = wownero.wownerod();
let miner_wallet = wownero.wallet("miner").unwrap();
let got_miner_balance = miner_wallet.balance().await.unwrap();
assert_that!(got_miner_balance).is_greater_than(0);
@ -26,7 +26,7 @@ async fn init_miner_and_mine_to_miner_address() {
time::sleep(Duration::from_millis(1010)).await;
// after a bit more than 1 sec another block should have been mined
let block_height = monerod.client().get_block_count().await.unwrap().count;
let block_height = wownerod.client().get_block_count().await.unwrap().count;
assert_that(&block_height).is_greater_than(70);
}

@ -1,5 +1,5 @@
[package]
name = "monero-rpc"
name = "wownero-rpc"
version = "0.1.0"
authors = [ "CoBloX Team <team@coblox.tech>" ]
edition = "2018"
@ -9,8 +9,8 @@ anyhow = "1"
curve25519-dalek = "3.1"
hex = "0.4"
jsonrpc_client = { version = "0.7", features = [ "reqwest" ] }
monero = "0.12"
monero-epee-bin-serde = "1"
wownero = "0.12"
wownero-epee-bin-serde = "1"
rand = "0.7"
reqwest = { version = "0.11", default-features = false, features = [ "json" ] }
serde = { version = "1.0", features = [ "derive" ] }

@ -12,5 +12,5 @@
)]
#![forbid(unsafe_code)]
pub mod monerod;
pub mod wownerod;
pub mod wallet;

@ -3,7 +3,7 @@ use serde::de::Error;
use serde::{Deserialize, Deserializer, Serialize};
#[jsonrpc_client::api(version = "2.0")]
pub trait MoneroWalletRpc {
pub trait WowneroWalletRpc {
async fn get_address(&self, account_index: u32) -> GetAddress;
async fn get_balance(&self, account_index: u32) -> GetBalance;
async fn create_account(&self, label: String) -> CreateAccount;
@ -35,7 +35,7 @@ pub trait MoneroWalletRpc {
async fn get_version(&self) -> Version;
}
#[jsonrpc_client::implement(MoneroWalletRpc)]
#[jsonrpc_client::implement(WowneroWalletRpc)]
#[derive(Debug, Clone)]
pub struct Client {
inner: reqwest::Client,
@ -43,7 +43,7 @@ pub struct Client {
}
impl Client {
/// Constructs a monero-wallet-rpc client with localhost endpoint.
/// Constructs a wownero-wallet-rpc client with localhost endpoint.
pub fn localhost(port: u16) -> Result<Self> {
Client::new(
format!("http://127.0.0.1:{}/json_rpc", port)
@ -52,7 +52,7 @@ impl Client {
)
}
/// Constructs a monero-wallet-rpc client with `url` endpoint.
/// Constructs a wownero-wallet-rpc client with `url` endpoint.
pub fn new(url: reqwest::Url) -> Result<Self> {
Ok(Self {
inner: reqwest::ClientBuilder::new()
@ -62,7 +62,7 @@ impl Client {
})
}
/// Transfers `amount` monero from `account_index` to `address`.
/// Transfers `amount` wownero from `account_index` to `address`.
pub async fn transfer_single(
&self,
account_index: u32,
@ -129,7 +129,7 @@ pub struct Transfer {
pub tx_blob: String,
pub tx_hash: String,
#[serde(deserialize_with = "opt_key_from_blank")]
pub tx_key: Option<monero::PrivateKey>,
pub tx_key: Option<wownero::PrivateKey>,
pub tx_metadata: String,
pub unsigned_txset: String,
}
@ -154,7 +154,7 @@ struct CheckTxKeyResponse {
impl From<CheckTxKeyResponse> for CheckTxKey {
fn from(response: CheckTxKeyResponse) -> Self {
// Due to a bug in monerod that causes check_tx_key confirmations
// Due to a bug in wownerod that causes check_tx_key confirmations
// to overflow we safeguard the confirmations to avoid unwanted
// side effects.
let confirmations = if response.confirmations > u64::MAX - 1000 {
@ -205,13 +205,13 @@ pub type WalletOpened = Empty;
///
/// With `serde`, an empty JSON object (`{ }`) does not deserialize into Rust's
/// `()`. With the adoption of `jsonrpc_client`, we need to be explicit about
/// what the response of every RPC call is. Unfortunately, monerod likes to
/// what the response of every RPC call is. Unfortunately, wownerod likes to
/// return empty objects instead of `null`s in certain cases. We use this struct
/// to all the "deserialization" to happily continue.
#[derive(Debug, Copy, Clone, Deserialize)]
pub struct Empty {}
fn opt_key_from_blank<'de, D>(deserializer: D) -> Result<Option<monero::PrivateKey>, D::Error>
fn opt_key_from_blank<'de, D>(deserializer: D) -> Result<Option<wownero::PrivateKey>, D::Error>
where
D: Deserializer<'de>,
{

@ -1,12 +1,12 @@
use anyhow::{Context, Result};
use monero::cryptonote::hash::Hash;
use monero::util::ringct;
use monero::PublicKey;
use wownero::cryptonote::hash::Hash;
use wownero::util::ringct;
use wownero::PublicKey;
use serde::de::DeserializeOwned;
use serde::{Deserialize, Serialize, Serializer};
#[jsonrpc_client::api(version = "2.0")]
pub trait MonerodRpc {
pub trait WownerodRpc {
async fn generateblocks(&self, amount_of_blocks: u32, wallet_address: String)
-> GenerateBlocks;
async fn get_block_header_by_height(&self, height: u32) -> BlockHeader;
@ -14,7 +14,7 @@ pub trait MonerodRpc {
async fn get_block(&self, height: u32) -> GetBlockResponse;
}
#[jsonrpc_client::implement(MonerodRpc)]
#[jsonrpc_client::implement(WownerodRpc)]
#[derive(Debug, Clone)]
pub struct Client {
inner: reqwest::Client,
@ -24,7 +24,7 @@ pub struct Client {
}
impl Client {
/// New local host monerod RPC client.
/// New local host wownerod RPC client.
pub fn localhost(port: u16) -> Result<Self> {
Self::new("127.0.0.1".to_owned(), port)
}
@ -66,7 +66,7 @@ impl Client {
let response = self
.inner
.post(url)
.body(monero_epee_bin_serde::to_bytes(&request)?)
.body(wownero_epee_bin_serde::to_bytes(&request)?)
.send()
.await?;
@ -76,7 +76,7 @@ impl Client {
let body = response.bytes().await?;
Ok(monero_epee_bin_serde::from_bytes(body)?)
Ok(wownero_epee_bin_serde::from_bytes(body)?)
}
}
@ -91,7 +91,7 @@ pub struct BlockCount {
pub count: u32,
}
// We should be able to use monero-rs for this but it does not include all
// We should be able to use wownero-rs for this but it does not include all
// the fields.
#[derive(Clone, Debug, Deserialize)]
pub struct BlockHeader {
@ -112,8 +112,8 @@ pub struct BlockHeader {
#[derive(Debug, Deserialize)]
pub struct GetBlockResponse {
#[serde(with = "monero_serde_hex_block")]
pub blob: monero::Block,
#[serde(with = "wownero_serde_hex_block")]
pub blob: wownero::Block,
}
#[derive(Debug, Deserialize)]
@ -181,14 +181,14 @@ pub enum Status {
Failed,
}
mod monero_serde_hex_block {
mod wownero_serde_hex_block {
use super::*;
use monero::consensus::Decodable;
use wownero::consensus::Decodable;
use serde::de::Error;
use serde::{Deserialize, Deserializer};
use std::io::Cursor;
pub fn deserialize<'de, D>(deserializer: D) -> Result<monero::Block, D::Error>
pub fn deserialize<'de, D>(deserializer: D) -> Result<wownero::Block, D::Error>
where
D: Deserializer<'de>,
{
@ -197,7 +197,7 @@ mod monero_serde_hex_block {
let bytes = hex::decode(&hex).map_err(D::Error::custom)?;
let mut cursor = Cursor::new(bytes);
let block = monero::Block::consensus_decode(&mut cursor).map_err(D::Error::custom)?;
let block = wownero::Block::consensus_decode(&mut cursor).map_err(D::Error::custom)?;
Ok(block)
}

@ -1,18 +1,18 @@
[package]
name = "monero-wallet"
name = "wownero-wallet"
version = "0.1.0"
authors = [ "CoBloX Team <team@coblox.tech>" ]
edition = "2018"
[dependencies]
anyhow = "1"
monero = "0.12"
monero-rpc = { path = "../monero-rpc" }
wownero = "0.12"
wownero-rpc = { path = "../wownero-rpc" }
rand = "0.7"
[dev-dependencies]
curve25519-dalek = "3"
monero-harness = { path = "../monero-harness" }
wownero-harness = { path = "../wownero-harness" }
rand = "0.7"
testcontainers = "0.12"
tokio = { version = "1", features = [ "rt-multi-thread", "time", "macros", "sync", "process", "fs" ] }

@ -1,12 +1,12 @@
use anyhow::{Context, Result};
use monero::consensus::encode::VarInt;
use monero::cryptonote::hash::Hashable;
use monero_rpc::monerod;
use monero_rpc::monerod::{GetBlockResponse, MonerodRpc as _};
use wownero::consensus::encode::VarInt;
use wownero::cryptonote::hash::Hashable;
use wownero_rpc::wownerod;
use wownero_rpc::wownerod::{GetBlockResponse, WownerodRpc as _};
use rand::Rng;
pub struct Wallet {
client: monerod::Client,
client: wownerod::Client,
}
impl Wallet {
@ -18,7 +18,7 @@ impl Wallet {
/// possible.
pub async fn choose_ten_random_key_offsets(&self) -> Result<[VarInt; 10]> {
let latest_block = self.client.get_block_count().await?;
let latest_spendable_block = latest_block.count - 10;
let latest_spendable_block = latest_block.count - 4;
let block: GetBlockResponse = self.client.get_block(latest_spendable_block).await?;
@ -58,16 +58,16 @@ impl Wallet {
#[cfg(test)]
mod tests {
use super::*;
use monero_harness::image::Monerod;
use monero_rpc::monerod::{Client, GetOutputsOut};
use wownero_harness::image::Wownerod;
use wownero_rpc::wownerod::{Client, GetOutputsOut};
use testcontainers::clients::Cli;
use testcontainers::Docker;
#[tokio::test]
async fn get_outs_for_key_offsets() {
let cli = Cli::default();
let container = cli.run(Monerod::default());
let rpc_client = Client::localhost(container.get_host_port(18081).unwrap()).unwrap();
let container = cli.run(Wownerod::default());
let rpc_client = Client::localhost(container.get_host_port(34568).unwrap()).unwrap();
rpc_client.generateblocks(150, "498AVruCDWgP9Az9LjMm89VWjrBrSZ2W2K3HFBiyzzrRjUJWUcCVxvY1iitfuKoek2FdX6MKGAD9Qb1G1P8QgR5jPmmt3Vj".to_owned()).await.unwrap();
let wallet = Wallet {
client: rpc_client.clone(),
Loading…
Cancel
Save