diff --git a/monero-harness/src/rpc/wallet.rs b/monero-harness/src/rpc/wallet.rs index d31a8b21..cd92588c 100644 --- a/monero-harness/src/rpc/wallet.rs +++ b/monero-harness/src/rpc/wallet.rs @@ -1,6 +1,5 @@ use crate::rpc::{Request, Response}; - -use anyhow::Result; +use anyhow::{bail, Result}; use reqwest::Url; use serde::{Deserialize, Serialize}; use tracing::debug; @@ -121,6 +120,33 @@ impl Client { Ok(r.result) } + /// Opens a wallet using `filename`. + pub async fn open_wallet(&self, filename: &str) -> Result<()> { + let params = OpenWalletParams { + filename: filename.to_owned(), + }; + let request = Request::new("open_wallet", params); + + let response = self + .inner + .post(self.url.clone()) + .json(&request) + .send() + .await? + .text() + .await?; + + debug!("open wallet RPC response: {}", response); + + // TODO: Proper error handling once switching to https://github.com/thomaseizinger/rust-jsonrpc-client/ + // Currently blocked by https://github.com/thomaseizinger/rust-jsonrpc-client/issues/20 + if response.contains("error") { + bail!("Failed to open wallet") + } + + Ok(()) + } + /// Creates a wallet using `filename`. pub async fn create_wallet(&self, filename: &str) -> Result<()> { let params = CreateWalletParams { @@ -140,6 +166,10 @@ impl Client { debug!("create wallet RPC response: {}", response); + if response.contains("error") { + bail!("Failed to create wallet") + } + Ok(()) } @@ -348,6 +378,11 @@ pub struct SubAddressAccount { pub unlocked_balance: u64, } +#[derive(Serialize, Debug, Clone)] +struct OpenWalletParams { + filename: String, +} + #[derive(Serialize, Debug, Clone)] struct CreateWalletParams { filename: String, diff --git a/swap/src/main.rs b/swap/src/main.rs index a088ed5e..bd7ec818 100644 --- a/swap/src/main.rs +++ b/swap/src/main.rs @@ -18,6 +18,7 @@ use crate::{ initial_setup, query_user_for_initial_testnet_config, read_config, ConfigNotInitialized, }, execution_params::GetExecutionParams, + monero::{CreateWallet, OpenWallet}, protocol::bob::cancel::CancelError, }; use anyhow::{Context, Result}; @@ -49,9 +50,11 @@ mod serde_peer_id; #[macro_use] extern crate prettytable; +const MONERO_BLOCKCHAIN_MONITORING_WALLET_NAME: &str = "swap-tool-blockchain-monitoring-wallet"; + #[tokio::main] async fn main() -> Result<()> { - init_tracing(LevelFilter::Info).expect("initialize tracing"); + init_tracing(LevelFilter::Debug).expect("initialize tracing"); let opt = Options::from_args(); @@ -326,12 +329,35 @@ async fn init_wallets( bitcoin_balance ); - let monero_wallet = monero::Wallet::new(config.monero.wallet_rpc_url, monero_network); - let monero_balance = monero_wallet.get_balance().await?; - info!( - "Connection to Monero wallet succeeded, balance: {}", - monero_balance - ); + let monero_wallet = monero::Wallet::new(config.monero.wallet_rpc_url.clone(), monero_network); + + // Setup the temporary Monero wallet necessary for monitoring the blockchain + let open_monitoring_wallet_response = monero_wallet + .open_wallet(MONERO_BLOCKCHAIN_MONITORING_WALLET_NAME) + .await; + if open_monitoring_wallet_response.is_err() { + monero_wallet + .create_wallet(MONERO_BLOCKCHAIN_MONITORING_WALLET_NAME) + .await + .context(format!( + "Unable to create Monero wallet for blockchain monitoring.\ + Please ensure that the monero-wallet-rpc is available at {}", + config.monero.wallet_rpc_url + ))?; + + info!( + "Created Monero wallet for blockchain monitoring with name {}", + MONERO_BLOCKCHAIN_MONITORING_WALLET_NAME + ); + } else { + info!( + "Opened Monero wallet for blockchain monitoring with name {}", + MONERO_BLOCKCHAIN_MONITORING_WALLET_NAME + ); + } + + let _test_wallet_connection = monero_wallet.inner.block_height().await?; + info!("The Monero wallet RPC is set up correctly!"); Ok((bitcoin_wallet, monero_wallet)) } diff --git a/swap/src/monero.rs b/swap/src/monero.rs index caec8864..9d7bdec9 100644 --- a/swap/src/monero.rs +++ b/swap/src/monero.rs @@ -207,6 +207,16 @@ pub trait CreateWalletForOutput { ) -> anyhow::Result<()>; } +#[async_trait] +pub trait OpenWallet { + async fn open_wallet(&self, file_name: &str) -> anyhow::Result<()>; +} + +#[async_trait] +pub trait CreateWallet { + async fn create_wallet(&self, file_name: &str) -> anyhow::Result<()>; +} + #[derive(thiserror::Error, Debug, Clone, PartialEq)] #[error("Overflow, cannot convert {0} to u64")] pub struct OverflowError(pub String); diff --git a/swap/src/monero/wallet.rs b/swap/src/monero/wallet.rs index d9d7ea73..a53c06c3 100644 --- a/swap/src/monero/wallet.rs +++ b/swap/src/monero/wallet.rs @@ -1,6 +1,6 @@ use crate::monero::{ - Amount, CreateWalletForOutput, InsufficientFunds, PrivateViewKey, PublicViewKey, Transfer, - TransferProof, TxHash, WatchForTransfer, + Amount, CreateWallet, CreateWalletForOutput, InsufficientFunds, OpenWallet, PrivateViewKey, + PublicViewKey, Transfer, TransferProof, TxHash, WatchForTransfer, }; use ::monero::{Address, Network, PrivateKey, PublicKey}; use anyhow::Result; @@ -94,6 +94,22 @@ impl CreateWalletForOutput for Wallet { } } +#[async_trait] +impl OpenWallet for Wallet { + async fn open_wallet(&self, file_name: &str) -> Result<()> { + self.inner.open_wallet(file_name).await?; + Ok(()) + } +} + +#[async_trait] +impl CreateWallet for Wallet { + async fn create_wallet(&self, file_name: &str) -> Result<()> { + self.inner.create_wallet(file_name).await?; + Ok(()) + } +} + // TODO: For retry, use `backoff::ExponentialBackoff` in production as opposed // to `ConstantBackoff`. #[async_trait]