diff --git a/CHANGELOG.md b/CHANGELOG.md index 26745ad6..9690e405 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added + +- `monero-recovery` command that can be used to print the monero address, private spend and view key so one can manually recover instances where the `monero-wallet-rpc` does not pick up the Monero funds locked up by the ASB. + Related issue: https://github.com/comit-network/xmr-btc-swap/issues/537 + The command takes the swap-id as parameter. + The swap has to be in a `BtcRedeemed` state. + Use `--help` for more details. + ## [0.10.0] - 2021-10-15 ### Removed diff --git a/swap/src/bin/swap.rs b/swap/src/bin/swap.rs index c41212bb..50e1e520 100644 --- a/swap/src/bin/swap.rs +++ b/swap/src/bin/swap.rs @@ -12,7 +12,7 @@ #![forbid(unsafe_code)] #![allow(non_snake_case)] -use anyhow::{Context, Result}; +use anyhow::{bail, Context, Result}; use comfy_table::Table; use qrcode::render::unicode; use qrcode::QrCode; @@ -417,6 +417,43 @@ async fn main() -> Result<()> { let wallet_export = bitcoin_wallet.wallet_export("cli").await?; println!("{}", wallet_export.to_string()) } + Command::MoneroRecovery { swap_id } => { + let db = open_db(data_dir.join("sqlite")).await?; + + let swap_state: BobState = db.get_state(swap_id).await?.try_into()?; + + match swap_state { + BobState::Started { .. } + | BobState::SwapSetupCompleted(_) + | BobState::BtcLocked(_) + | BobState::XmrLockProofReceived { .. } + | BobState::XmrLocked(_) + | BobState::EncSigSent(_) + | BobState::CancelTimelockExpired(_) + | BobState::BtcCancelled(_) + | BobState::BtcRefunded(_) + | BobState::BtcPunished { .. } + | BobState::SafelyAborted + | BobState::XmrRedeemed { .. } => { + bail!("Cannot print monero recovery information in state {}, only possible for BtcRedeemed", swap_state) + } + BobState::BtcRedeemed(state5) => { + let (spend_key, view_key) = state5.xmr_keys(); + + let address = monero::Address::standard( + env_config.monero_network, + monero::PublicKey::from_private_key(&spend_key), + monero::PublicKey::from(view_key.public()), + ); + tracing::info!("Wallet address: {}", address.to_string()); + + let view_key = serde_json::to_string(&view_key)?; + println!("View key: {}", view_key); + + println!("Spend key: {}", spend_key); + } + } + } }; Ok(()) } diff --git a/swap/src/cli/command.rs b/swap/src/cli/command.rs index 491f3dea..2628d5f5 100644 --- a/swap/src/cli/command.rs +++ b/swap/src/cli/command.rs @@ -249,6 +249,15 @@ where }, } } + RawCommand::MoneroRecovery { swap_id } => Arguments { + env_config: env_config_from(is_testnet), + debug, + json, + data_dir: data::data_dir_from(data, is_testnet)?, + cmd: Command::MoneroRecovery { + swap_id: swap_id.swap_id, + }, + }, }; Ok(ParseResult::Arguments(arguments)) @@ -303,6 +312,9 @@ pub enum Command { bitcoin_electrum_rpc_url: Url, bitcoin_target_block: usize, }, + MoneroRecovery { + swap_id: Uuid, + }, } #[derive(structopt::StructOpt, Debug)] @@ -439,6 +451,13 @@ enum RawCommand { #[structopt(flatten)] bitcoin: Bitcoin, }, + /// Prints Monero information related to the swap in case the generated + /// wallet fails to detect the funds. This can only be used for swaps + /// that are in a `btc is redeemed` state. + MoneroRecovery { + #[structopt(flatten)] + swap_id: SwapId, + }, } #[derive(structopt::StructOpt, Debug)]