Cleanup, formatting, add get_seller, get_swap_start_date RPC endpoints

This commit is contained in:
binarybaron 2022-12-02 21:46:27 +01:00
parent 0df5af16b8
commit e1983d5639
10 changed files with 639 additions and 355 deletions

View File

@ -28,6 +28,24 @@
},
"query": "\n insert into peer_addresses (\n peer_id,\n address\n ) values (?, ?);\n "
},
"0d465a17ebbb5761421def759c73cad023c30705d5b41a1399ef79d8d2571d7c": {
"describe": {
"columns": [
{
"name": "start_date",
"ordinal": 0,
"type_info": "Text"
}
],
"nullable": [
true
],
"parameters": {
"Right": 1
}
},
"query": "\n SELECT min(entered_at) as start_date\n FROM swap_states\n WHERE swap_id = ?\n "
},
"1ec38c85e7679b2eb42b3df75d9098772ce44fdb8db3012d3c2410d828b74157": {
"describe": {
"columns": [
@ -62,6 +80,30 @@
},
"query": "\n insert into peers (\n swap_id,\n peer_id\n ) values (?, ?);\n "
},
"3f2bfdd2d134586ccad22171cd85a465800fc5c4fdaf191d206974e530240c87": {
"describe": {
"columns": [
{
"name": "swap_id",
"ordinal": 0,
"type_info": "Text"
},
{
"name": "state",
"ordinal": 1,
"type_info": "Text"
}
],
"nullable": [
false,
false
],
"parameters": {
"Right": 0
}
},
"query": "\n SELECT swap_id, state\n FROM swap_states\n "
},
"50a5764546f69c118fa0b64120da50f51073d36257d49768de99ff863e3511e0": {
"describe": {
"columns": [],
@ -90,24 +132,6 @@
},
"query": "\n SELECT state\n FROM swap_states\n WHERE swap_id = ?\n ORDER BY id desc\n LIMIT 1;\n\n "
},
"a0eb85d04ee3842c52291dad4d225941d1141af735922fcbc665868997fce304": {
"describe": {
"columns": [
{
"name": "address",
"ordinal": 0,
"type_info": "Text"
}
],
"nullable": [
false
],
"parameters": {
"Right": 1
}
},
"query": "\n SELECT address\n FROM peer_addresses\n WHERE peer_id = ?\n "
},
"b703032b4ddc627a1124817477e7a8e5014bdc694c36a14053ef3bb2fc0c69b0": {
"describe": {
"columns": [],
@ -135,5 +159,23 @@
}
},
"query": "\n SELECT address\n FROM monero_addresses\n WHERE swap_id = ?\n "
},
"d78acba5eb8563826dd190e0886aa665aae3c6f1e312ee444e65df1c95afe8b2": {
"describe": {
"columns": [
{
"name": "address",
"ordinal": 0,
"type_info": "Text"
}
],
"nullable": [
false
],
"parameters": {
"Right": 1
}
},
"query": "\n SELECT DISTINCT address\n FROM peer_addresses\n WHERE peer_id = ?\n "
}
}

View File

@ -1,39 +1,34 @@
use crate::bitcoin::{Amount, TxLock};
use crate::cli::command::{Bitcoin, Command, Monero, Tor};
use crate::cli::{list_sellers, EventLoop, SellerStatus};
use crate::database::open_db;
use crate::env::{Config, GetConfig, Mainnet, Testnet};
use crate::fs::system_data_dir;
use crate::libp2p_ext::MultiAddrExt;
use crate::network::quote::{BidQuote, ZeroQuoteReceived};
use crate::network::rendezvous::XmrBtcNamespace;
use crate::network::swarm;
use crate::protocol::bob::{BobState, Swap};
use crate::protocol::{bob, Database};
use crate::seed::Seed;
use crate::{bitcoin, cli, monero, rpc};
use anyhow::{bail, Context as AnyContext, Result};
use comfy_table::Table;
use libp2p::core::Multiaddr;
use qrcode::render::unicode;
use qrcode::QrCode;
use crate::env::GetConfig;
use serde::ser::{Serialize, SerializeStruct, Serializer};
use serde_json::json;
use std::cmp::min;
use crate::network::rendezvous::XmrBtcNamespace;
use std::net::SocketAddr;
use libp2p::core::Multiaddr;
use std::convert::TryInto;
use crate::bitcoin::Amount;
use std::fmt;
use std::future::Future;
use std::net::SocketAddr;
use std::path::PathBuf;
use std::sync::Arc;
use std::time::Duration;
use crate::bitcoin::TxLock;
use crate::cli::command::{Command, Bitcoin, Monero, Tor};
use crate::cli::{list_sellers, EventLoop, SellerStatus};
use crate::database::open_db;
use crate::libp2p_ext::MultiAddrExt;
use crate::network::quote::{BidQuote, ZeroQuoteReceived};
use crate::network::swarm;
use crate::protocol::bob;
use crate::protocol::bob::{BobState, Swap};
use crate::seed::Seed;
use crate::rpc;
use crate::{bitcoin, cli, monero};
use url::Url;
use uuid::Uuid;
use crate::protocol::Database;
use crate::env::{Config, Mainnet, Testnet};
use crate::fs::system_data_dir;
use serde_json::json;
use serde::ser::{Serialize, Serializer, SerializeStruct};
use std::fmt;
#[derive(PartialEq, Debug)]
pub struct Request {
@ -53,7 +48,7 @@ pub struct Params {
}
pub struct Context {
db: Arc<dyn Database + Send + Sync>,
pub db: Arc<dyn Database + Send + Sync>,
bitcoin_wallet: Option<Arc<bitcoin::Wallet>>,
monero_wallet: Option<Arc<monero::Wallet>>,
monero_rpc_process: Option<monero::WalletRpcProcess>,
@ -81,10 +76,17 @@ impl Request {
let bitcoin_change_address = self.params.bitcoin_change_address.clone().unwrap();
let bitcoin_wallet = btc;
let seller_peer_id = self.params.seller.as_ref().unwrap()
let seller_peer_id = self
.params
.seller
.as_ref()
.unwrap()
.extract_peer_id()
.context("Seller address must contain peer ID")?;
context.db.insert_address(seller_peer_id, seller.clone()).await?;
context
.db
.insert_address(seller_peer_id, seller.clone())
.await?;
let behaviour = cli::Behaviour::new(
seller_peer_id,
@ -92,8 +94,12 @@ impl Request {
bitcoin_wallet.clone(),
(seed.derive_libp2p_identity(), context.namespace),
);
let mut swarm =
swarm::cli(seed.derive_libp2p_identity(), context.tor_socks5_port.unwrap(), behaviour).await?;
let mut swarm = swarm::cli(
seed.derive_libp2p_identity(),
context.tor_socks5_port.unwrap(),
behaviour,
)
.await?;
swarm.behaviour_mut().add_address(seller_peer_id, seller);
tracing::debug!(peer_id = %swarm.local_peer_id(), "Network layer initialized");
@ -128,7 +134,9 @@ impl Request {
tracing::info!(%amount, %fees, "Determined swap amount");
context.db.insert_peer_id(swap_id, seller_peer_id).await?;
context.db.insert_monero_address(swap_id, monero_receive_address)
context
.db
.insert_monero_address(swap_id, monero_receive_address)
.await?;
let monero_wallet = context.monero_wallet.as_ref().unwrap();
@ -165,18 +173,20 @@ impl Request {
let state: BobState = state.try_into()?;
vec.push((swap_id, state.to_string()));
}
json!({
"swaps": vec
})
json!({ "swaps": vec })
}
Command::Config => {
// tracing::info!(path=%data_dir.display(), "Data directory");
// tracing::info!(path=%format!("{}/logs", data_dir.display()), "Log files directory");
// tracing::info!(path=%format!("{}/sqlite", data_dir.display()), "Sqlite file location");
// tracing::info!(path=%format!("{}/seed.pem", data_dir.display()), "Seed file location");
// tracing::info!(path=%format!("{}/monero", data_dir.display()), "Monero-wallet-rpc directory");
// tracing::info!(path=%format!("{}/wallet", data_dir.display()), "Internal bitcoin wallet directory");
// tracing::info!(path=%format!("{}/logs", data_dir.display()),
// "Log files directory");
// tracing::info!(path=%format!("{}/sqlite", data_dir.display()), "Sqlite file
// location");
// tracing::info!(path=%format!("{}/seed.pem", data_dir.display()), "Seed file
// location");
// tracing::info!(path=%format!("{}/monero", data_dir.display()),
// "Monero-wallet-rpc directory");
// tracing::info!(path=%format!("{}/wallet", data_dir.display()), "Internal
// bitcoin wallet directory");
json!({
"result": []
@ -200,7 +210,9 @@ impl Request {
.await?;
let signed_tx = bitcoin_wallet.sign_and_finalize(psbt).await?;
bitcoin_wallet.broadcast(signed_tx.clone(), "withdraw").await?;
bitcoin_wallet
.broadcast(signed_tx.clone(), "withdraw")
.await?;
json!({
"signed_tx": signed_tx,
@ -220,9 +232,7 @@ impl Request {
Some(handle)
}
};
loop {
}
loop {}
json!({
"result": []
})
@ -255,8 +265,12 @@ impl Request {
Arc::clone(context.bitcoin_wallet.as_ref().unwrap()),
(seed.clone(), context.namespace),
);
let mut swarm =
swarm::cli(seed.clone(), context.tor_socks5_port.clone().unwrap(), behaviour).await?;
let mut swarm = swarm::cli(
seed.clone(),
context.tor_socks5_port.clone().unwrap(),
behaviour,
)
.await?;
let our_peer_id = swarm.local_peer_id();
tracing::debug!(peer_id = %our_peer_id, "Network layer initialized");
@ -267,7 +281,8 @@ impl Request {
.add_address(seller_peer_id, seller_address);
}
let (event_loop, event_loop_handle) = EventLoop::new(swap_id, swarm, seller_peer_id)?;
let (event_loop, event_loop_handle) =
EventLoop::new(swap_id, swarm, seller_peer_id)?;
let handle = tokio::spawn(event_loop.run());
let monero_receive_address = context.db.get_monero_address(swap_id).await?;
@ -297,7 +312,12 @@ impl Request {
Command::Cancel => {
let bitcoin_wallet = context.bitcoin_wallet.as_ref().unwrap();
let (txid, _) = cli::cancel(self.params.swap_id.unwrap(), Arc::clone(bitcoin_wallet), Arc::clone(&context.db)).await?;
let (txid, _) = cli::cancel(
self.params.swap_id.unwrap(),
Arc::clone(bitcoin_wallet),
Arc::clone(&context.db),
)
.await?;
tracing::debug!("Cancel transaction successfully published with id {}", txid);
@ -308,11 +328,14 @@ impl Request {
Command::Refund => {
let bitcoin_wallet = context.bitcoin_wallet.as_ref().unwrap();
let state = cli::refund(self.params.swap_id.unwrap(), Arc::clone(bitcoin_wallet), Arc::clone(&context.db)).await?;
let state = cli::refund(
self.params.swap_id.unwrap(),
Arc::clone(bitcoin_wallet),
Arc::clone(&context.db),
)
.await?;
json!({
"result": state
})
json!({ "result": state })
}
Command::ListSellers => {
let rendezvous_point = self.params.rendezvous_point.clone().unwrap();
@ -328,7 +351,8 @@ impl Request {
context.namespace,
context.tor_socks5_port.unwrap(),
identity,
).await?;
)
.await?;
for seller in &sellers {
match seller.status {
@ -352,9 +376,7 @@ impl Request {
}
}
json!({
"sellers": sellers
})
json!({ "sellers": sellers })
}
Command::ExportBitcoinWallet => {
let bitcoin_wallet = context.bitcoin_wallet.as_ref().unwrap();
@ -366,7 +388,11 @@ impl Request {
})
}
Command::MoneroRecovery => {
let swap_state: BobState = context.db.get_state(self.params.swap_id.clone().unwrap()).await?.try_into()?;
let swap_state: BobState = context
.db
.get_state(self.params.swap_id.clone().unwrap())
.await?
.try_into()?;
match swap_state {
BobState::Started { .. }
@ -429,14 +455,16 @@ impl Context {
if let Some(bitcoin) = bitcoin {
let (bitcoin_electrum_rpc_url, bitcoin_target_block) =
bitcoin.apply_defaults(is_testnet)?;
Some(Arc::new(init_bitcoin_wallet(
Some(Arc::new(
init_bitcoin_wallet(
bitcoin_electrum_rpc_url,
&seed,
data_dir.clone(),
env_config,
bitcoin_target_block,
)
.await?))
.await?,
))
} else {
None
}
@ -445,18 +473,14 @@ impl Context {
let (monero_wallet, monero_rpc_process) = {
if let Some(monero) = monero {
let monero_daemon_address = monero.apply_defaults(is_testnet);
let (wlt, prc) = init_monero_wallet(
data_dir.clone(),
monero_daemon_address,
env_config,
).await?;
let (wlt, prc) =
init_monero_wallet(data_dir.clone(), monero_daemon_address, env_config).await?;
(Some(Arc::new(wlt)), Some(prc))
} else {
(None, None)
}
};
let tor_socks5_port = {
if let Some(tor) = tor {
Some(tor.tor_socks5_port)
@ -471,7 +495,7 @@ impl Context {
bitcoin_wallet,
monero_wallet,
monero_rpc_process,
tor_socks5_port: tor_socks5_port,
tor_socks5_port,
namespace: XmrBtcNamespace::from_is_testnet(is_testnet),
db: open_db(data_dir.join("sqlite")).await?,
env_config,
@ -482,10 +506,8 @@ impl Context {
server_address,
};
Ok(init)
}
}
impl Serialize for Context {
@ -503,11 +525,11 @@ impl Serialize for Context {
impl PartialEq for Context {
fn eq(&self, other: &Self) -> bool {
self.tor_socks5_port == other.tor_socks5_port &&
self.namespace == other.namespace &&
self.debug == other.debug &&
self.json == other.json &&
self.server_address == other.server_address
self.tor_socks5_port == other.tor_socks5_port
&& self.namespace == other.namespace
&& self.debug == other.debug
&& self.json == other.json
&& self.server_address == other.server_address
}
}
@ -709,26 +731,34 @@ pub mod api_test {
pub const SWAP_ID: &str = "ea030832-3be9-454f-bb98-5ea9a788406b";
impl Context {
pub async fn default(is_testnet: bool, data_dir: PathBuf, json: bool, debug: bool) -> Result<Context> {
pub async fn default(
is_testnet: bool,
data_dir: PathBuf,
json: bool,
debug: bool,
) -> Result<Context> {
Ok(Context::build(
Some(Bitcoin { bitcoin_electrum_rpc_url: None, bitcoin_target_block: None}),
Some(Monero { monero_daemon_address: None }),
Some(Tor { tor_socks5_port: DEFAULT_SOCKS5_PORT }),
Some(Bitcoin {
bitcoin_electrum_rpc_url: None,
bitcoin_target_block: None,
}),
Some(Monero {
monero_daemon_address: None,
}),
Some(Tor {
tor_socks5_port: DEFAULT_SOCKS5_PORT,
}),
Some(data_dir),
is_testnet,
debug,
json,
None
).await?)
None,
)
.await?)
}
}
impl Request {
pub fn buy_xmr(is_testnet: bool) -> Request {
let seller = Multiaddr::from_str(MULTI_ADDRESS).unwrap();
let bitcoin_change_address = {
if is_testnet {
@ -752,9 +782,8 @@ pub mod api_test {
bitcoin_change_address: Some(bitcoin_change_address),
monero_receive_address: Some(monero_receive_address),
..Default::default()
},
cmd: Command::BuyXmr
cmd: Command::BuyXmr,
}
}
@ -763,9 +792,8 @@ pub mod api_test {
params: Params {
swap_id: Some(Uuid::from_str(SWAP_ID).unwrap()),
..Default::default()
},
cmd: Command::Resume
cmd: Command::Resume,
}
}
@ -774,9 +802,8 @@ pub mod api_test {
params: Params {
swap_id: Some(Uuid::from_str(SWAP_ID).unwrap()),
..Default::default()
},
cmd: Command::Cancel
cmd: Command::Cancel,
}
}
@ -785,9 +812,8 @@ pub mod api_test {
params: Params {
swap_id: Some(Uuid::from_str(SWAP_ID).unwrap()),
..Default::default()
},
cmd: Command::Refund
cmd: Command::Refund,
}
}
}

View File

@ -14,9 +14,9 @@
use anyhow::Result;
use std::env;
use std::sync::Arc;
use swap::cli::command::{parse_args_and_apply_defaults, ParseResult};
use swap::common::check_latest_version;
use std::sync::Arc;
#[tokio::main]
async fn main() -> Result<()> {
@ -36,18 +36,16 @@ async fn main() -> Result<()> {
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
use swap::api::determine_btc_to_swap;
use ::bitcoin::Amount;
use std::sync::Mutex;
use std::time::Duration;
use swap::api::determine_btc_to_swap;
use swap::network::quote::BidQuote;
use swap::tracing_ext::capture_logs;
use tracing::level_filters::LevelFilter;
use swap::network::quote::BidQuote;
use std::time::Duration;
#[tokio::test]
async fn given_no_balance_and_transfers_less_than_max_swaps_max_giveable() {

View File

@ -1,19 +1,19 @@
use crate::api::{Context, Params, Request};
use crate::bitcoin::Amount;
use crate::fs::system_data_dir;
use crate::{env, monero};
use crate::api::{Request, Params, Context};
use anyhow::{bail, Context as AnyContext, Result};
use bitcoin::{Address, AddressType};
use libp2p::core::Multiaddr;
use serde::Serialize;
use std::ffi::OsString;
use std::net::SocketAddr;
use std::path::PathBuf;
use std::str::FromStr;
use std::sync::Arc;
use structopt::{clap, StructOpt};
use url::Url;
use uuid::Uuid;
use std::net::SocketAddr;
use std::sync::Arc;
use crate::fs::system_data_dir;
// See: https://moneroworld.com/
pub const DEFAULT_MONERO_DAEMON_ADDRESS: &str = "node.community.rino.io:18081";
@ -79,8 +79,9 @@ where
is_testnet,
debug,
json,
None
).await?;
None,
)
.await?;
let request = Request {
params: Params {
bitcoin_change_address: Some(bitcoin_change_address),
@ -93,44 +94,26 @@ where
(context, request)
}
RawCommand::History => {
let context = Context::build(
None,
None,
None,
data,
is_testnet,
debug,
json,
None
).await?;
let context =
Context::build(None, None, None, data, is_testnet, debug, json, None).await?;
let request = Request {
params: Params::default(),
cmd: Command::History,
};
(context, request)
},
}
RawCommand::Config => {
let context = Context::build(
None,
None,
None,
data,
is_testnet,
debug,
json,
None
).await?;
let context =
Context::build(None, None, None, data, is_testnet, debug, json, None).await?;
let request = Request {
params: Params::default(),
cmd: Command::Config,
};
(context, request)
},
RawCommand::Balance {
bitcoin,
} => {
}
RawCommand::Balance { bitcoin } => {
let context = Context::build(
Some(bitcoin),
None,
@ -139,8 +122,9 @@ where
is_testnet,
debug,
json,
None
).await?;
None,
)
.await?;
let request = Request {
params: Params::default(),
cmd: Command::Balance,
@ -162,7 +146,8 @@ where
debug,
json,
server_address,
).await?;
)
.await?;
let request = Request {
params: Params::default(),
cmd: Command::StartDaemon,
@ -182,11 +167,12 @@ where
is_testnet,
debug,
json,
None
).await?;
None,
)
.await?;
let request = Request {
params: Params {
amount: amount,
amount,
address: Some(address),
..Default::default()
},
@ -209,7 +195,8 @@ where
debug,
json,
None,
).await?;
)
.await?;
let request = Request {
params: Params {
swap_id: Some(swap_id),
@ -231,8 +218,9 @@ where
is_testnet,
debug,
json,
None
).await?;
None,
)
.await?;
let request = Request {
params: Params {
swap_id: Some(swap_id),
@ -254,8 +242,9 @@ where
is_testnet,
debug,
json,
None
).await?;
None,
)
.await?;
let request = Request {
params: Params {
swap_id: Some(swap_id),
@ -269,16 +258,8 @@ where
rendezvous_point,
tor,
} => {
let context = Context::build(
None,
None,
Some(tor),
data,
is_testnet,
debug,
json,
None
).await?;
let context =
Context::build(None, None, Some(tor), data, is_testnet, debug, json, None).await?;
let request = Request {
params: Params {
@ -298,25 +279,18 @@ where
is_testnet,
debug,
json,
None
).await?;
None,
)
.await?;
let request = Request {
params: Params::default(),
cmd: Command::ExportBitcoinWallet,
};
(context, request)
},
}
RawCommand::MoneroRecovery { swap_id } => {
let context = Context::build(
None,
None,
None,
data,
is_testnet,
debug,
json,
None
).await?;
let context =
Context::build(None, None, None, data, is_testnet, debug, json, None).await?;
let request = Request {
params: Params {
@ -326,7 +300,7 @@ where
cmd: Command::MoneroRecovery,
};
(context, request)
},
}
};
Ok(ParseResult::Context(Arc::new(context), Box::new(request)))
@ -347,7 +321,6 @@ pub enum Command {
StartDaemon,
}
#[derive(structopt::StructOpt, Debug)]
#[structopt(
name = "swap",
@ -443,7 +416,10 @@ enum RawCommand {
#[structopt(flatten)]
monero: Monero,
#[structopt(long="server-address", help = "The socket address the server should use")]
#[structopt(
long = "server-address",
help = "The socket address the server should use"
)]
server_address: Option<SocketAddr>,
#[structopt(flatten)]
tor: Tor,
@ -588,7 +564,6 @@ struct Seller {
seller: Multiaddr,
}
fn bitcoin_address(address: Address, is_testnet: bool) -> Result<Address> {
let network = if is_testnet {
bitcoin::Network::Testnet
@ -699,12 +674,16 @@ mod tests {
let (is_testnet, debug, json) = (false, false, false);
let data_dir = data_dir_path_cli(is_testnet);
let (expected_context, expected_request) =
(Context::default(is_testnet, data_dir, debug, json).await.unwrap(), Request::buy_xmr(is_testnet));
let (expected_context, expected_request) = (
Context::default(is_testnet, data_dir, debug, json)
.await
.unwrap(),
Request::buy_xmr(is_testnet),
);
let (actual_context, actual_request) = match args {
ParseResult::Context(context, request) => (context, request),
_ => panic!("Couldn't parse result")
_ => panic!("Couldn't parse result"),
};
assert_eq!(actual_context, Arc::new(expected_context));
@ -729,12 +708,16 @@ mod tests {
let (is_testnet, debug, json) = (true, false, false);
let data_dir = data_dir_path_cli(is_testnet);
let (expected_context, expected_request) =
(Context::default(is_testnet, data_dir, debug, json).await.unwrap(), Request::buy_xmr(is_testnet));
let (expected_context, expected_request) = (
Context::default(is_testnet, data_dir, debug, json)
.await
.unwrap(),
Request::buy_xmr(is_testnet),
);
let (actual_context, actual_request) = match args {
ParseResult::Context(context, request) => (context, request),
_ => panic!("Couldn't parse result")
_ => panic!("Couldn't parse result"),
};
assert_eq!(actual_context, Arc::new(expected_context));
@ -798,12 +781,16 @@ mod tests {
let (is_testnet, debug, json) = (false, false, false);
let data_dir = data_dir_path_cli(is_testnet);
let (expected_context, expected_request) =
(Context::default(is_testnet, data_dir, debug, json).await.unwrap(), Request::resume());
let (expected_context, expected_request) = (
Context::default(is_testnet, data_dir, debug, json)
.await
.unwrap(),
Request::resume(),
);
let (actual_context, actual_request) = match args {
ParseResult::Context(context, request) => (context, request),
_ => panic!("Couldn't parse result")
_ => panic!("Couldn't parse result"),
};
assert_eq!(actual_context, Arc::new(expected_context));
@ -818,12 +805,16 @@ mod tests {
let (is_testnet, debug, json) = (true, false, false);
let data_dir = data_dir_path_cli(is_testnet);
let (expected_context, expected_request) =
(Context::default(is_testnet, data_dir, debug, json).await.unwrap(), Request::resume());
let (expected_context, expected_request) = (
Context::default(is_testnet, data_dir, debug, json)
.await
.unwrap(),
Request::resume(),
);
let (actual_context, actual_request) = match args {
ParseResult::Context(context, request) => (context, request),
_ => panic!("Couldn't parse result")
_ => panic!("Couldn't parse result"),
};
assert_eq!(actual_context, Arc::new(expected_context));
@ -839,12 +830,16 @@ mod tests {
let (is_testnet, debug, json) = (false, false, false);
let data_dir = data_dir_path_cli(is_testnet);
let (expected_context, expected_request) =
(Context::default(is_testnet, data_dir, debug, json).await.unwrap(), Request::cancel());
let (expected_context, expected_request) = (
Context::default(is_testnet, data_dir, debug, json)
.await
.unwrap(),
Request::cancel(),
);
let (actual_context, actual_request) = match args {
ParseResult::Context(context, request) => (context, request),
_ => panic!("Couldn't parse result")
_ => panic!("Couldn't parse result"),
};
assert_eq!(actual_context, Arc::new(expected_context));
@ -859,12 +854,16 @@ mod tests {
let (is_testnet, debug, json) = (true, false, false);
let data_dir = data_dir_path_cli(is_testnet);
let (expected_context, expected_request) =
(Context::default(is_testnet, data_dir, debug, json).await.unwrap(), Request::cancel());
let (expected_context, expected_request) = (
Context::default(is_testnet, data_dir, debug, json)
.await
.unwrap(),
Request::cancel(),
);
let (actual_context, actual_request) = match args {
ParseResult::Context(context, request) => (context, request),
_ => panic!("Couldn't parse result")
_ => panic!("Couldn't parse result"),
};
assert_eq!(actual_context, Arc::new(expected_context));
@ -879,12 +878,16 @@ mod tests {
let (is_testnet, debug, json) = (false, false, false);
let data_dir = data_dir_path_cli(is_testnet);
let (expected_context, expected_request) =
(Context::default(is_testnet, data_dir, debug, json).await.unwrap(), Request::refund());
let (expected_context, expected_request) = (
Context::default(is_testnet, data_dir, debug, json)
.await
.unwrap(),
Request::refund(),
);
let (actual_context, actual_request) = match args {
ParseResult::Context(context, request) => (context, request),
_ => panic!("Couldn't parse result")
_ => panic!("Couldn't parse result"),
};
assert_eq!(actual_context, Arc::new(expected_context));
@ -899,12 +902,16 @@ mod tests {
let (is_testnet, debug, json) = (true, false, false);
let data_dir = data_dir_path_cli(is_testnet);
let (expected_context, expected_request) =
(Context::default(is_testnet, data_dir, debug, json).await.unwrap(), Request::refund());
let (expected_context, expected_request) = (
Context::default(is_testnet, data_dir, debug, json)
.await
.unwrap(),
Request::refund(),
);
let (actual_context, actual_request) = match args {
ParseResult::Context(context, request) => (context, request),
_ => panic!("Couldn't parse result")
_ => panic!("Couldn't parse result"),
};
assert_eq!(actual_context, Arc::new(expected_context));
@ -932,12 +939,16 @@ mod tests {
let (is_testnet, debug, json) = (false, false, false);
let data_dir = PathBuf::from_str(args_data_dir).unwrap();
let (expected_context, expected_request) =
(Context::default(is_testnet, data_dir.clone(), debug, json).await.unwrap(), Request::buy_xmr(is_testnet));
let (expected_context, expected_request) = (
Context::default(is_testnet, data_dir.clone(), debug, json)
.await
.unwrap(),
Request::buy_xmr(is_testnet),
);
let (actual_context, actual_request) = match args {
ParseResult::Context(context, request) => (context, request),
_ => panic!("Couldn't parse result")
_ => panic!("Couldn't parse result"),
};
assert_eq!(actual_context, Arc::new(expected_context));
@ -960,12 +971,16 @@ mod tests {
let args = parse_args_and_apply_defaults(raw_ars).await.unwrap();
let (is_testnet, debug, json) = (true, false, false);
let (expected_context, expected_request) =
(Context::default(is_testnet, data_dir.clone(), debug, json).await.unwrap(), Request::buy_xmr(is_testnet));
let (expected_context, expected_request) = (
Context::default(is_testnet, data_dir.clone(), debug, json)
.await
.unwrap(),
Request::buy_xmr(is_testnet),
);
let (actual_context, actual_request) = match args {
ParseResult::Context(context, request) => (context, request),
_ => panic!("Couldn't parse result")
_ => panic!("Couldn't parse result"),
};
assert_eq!(actual_context, Arc::new(expected_context));
@ -983,12 +998,16 @@ mod tests {
let args = parse_args_and_apply_defaults(raw_ars).await.unwrap();
let (is_testnet, debug, json) = (false, false, false);
let (expected_context, expected_request) =
(Context::default(is_testnet, data_dir.clone(), debug, json).await.unwrap(), Request::resume());
let (expected_context, expected_request) = (
Context::default(is_testnet, data_dir.clone(), debug, json)
.await
.unwrap(),
Request::resume(),
);
let (actual_context, actual_request) = match args {
ParseResult::Context(context, request) => (context, request),
_ => panic!("Couldn't parse result")
_ => panic!("Couldn't parse result"),
};
assert_eq!(actual_context, Arc::new(expected_context));
@ -1004,17 +1023,19 @@ mod tests {
SWAP_ID,
];
let args = parse_args_and_apply_defaults(raw_ars).await.unwrap();
let (is_testnet, debug, json) = (true, false, false);
let (expected_context, expected_request) =
(Context::default(is_testnet, data_dir.clone(), debug, json).await.unwrap(), Request::resume());
let (expected_context, expected_request) = (
Context::default(is_testnet, data_dir.clone(), debug, json)
.await
.unwrap(),
Request::resume(),
);
let (actual_context, actual_request) = match args {
ParseResult::Context(context, request) => (context, request),
_ => panic!("Couldn't parse result")
_ => panic!("Couldn't parse result"),
};
assert_eq!(actual_context, Arc::new(expected_context));
@ -1039,12 +1060,16 @@ mod tests {
let (is_testnet, debug, json) = (false, true, false);
let data_dir = data_dir_path_cli(is_testnet);
let (expected_context, expected_request) =
(Context::default(is_testnet, data_dir, debug, json).await.unwrap(), Request::buy_xmr(is_testnet));
let (expected_context, expected_request) = (
Context::default(is_testnet, data_dir, debug, json)
.await
.unwrap(),
Request::buy_xmr(is_testnet),
);
let (actual_context, actual_request) = match args {
ParseResult::Context(context, request) => (context, request),
_ => panic!("Couldn't parse result")
_ => panic!("Couldn't parse result"),
};
assert_eq!(actual_context, Arc::new(expected_context));
@ -1067,12 +1092,16 @@ mod tests {
let (is_testnet, debug, json) = (true, true, false);
let data_dir = data_dir_path_cli(is_testnet);
let (expected_context, expected_request) =
(Context::default(is_testnet, data_dir, debug, json).await.unwrap(), Request::buy_xmr(is_testnet));
let (expected_context, expected_request) = (
Context::default(is_testnet, data_dir, debug, json)
.await
.unwrap(),
Request::buy_xmr(is_testnet),
);
let (actual_context, actual_request) = match args {
ParseResult::Context(context, request) => (context, request),
_ => panic!("Couldn't parse result")
_ => panic!("Couldn't parse result"),
};
assert_eq!(actual_context, Arc::new(expected_context));
@ -1084,12 +1113,16 @@ mod tests {
let (is_testnet, debug, json) = (false, true, false);
let data_dir = data_dir_path_cli(is_testnet);
let (expected_context, expected_request) =
(Context::default(is_testnet, data_dir, debug, json).await.unwrap(), Request::resume());
let (expected_context, expected_request) = (
Context::default(is_testnet, data_dir, debug, json)
.await
.unwrap(),
Request::resume(),
);
let (actual_context, actual_request) = match args {
ParseResult::Context(context, request) => (context, request),
_ => panic!("Couldn't parse result")
_ => panic!("Couldn't parse result"),
};
assert_eq!(actual_context, Arc::new(expected_context));
@ -1108,12 +1141,16 @@ mod tests {
let (is_testnet, debug, json) = (true, true, false);
let data_dir = data_dir_path_cli(is_testnet);
let (expected_context, expected_request) =
(Context::default(is_testnet, data_dir, debug, json).await.unwrap(), Request::resume());
let (expected_context, expected_request) = (
Context::default(is_testnet, data_dir, debug, json)
.await
.unwrap(),
Request::resume(),
);
let (actual_context, actual_request) = match args {
ParseResult::Context(context, request) => (context, request),
_ => panic!("Couldn't parse result")
_ => panic!("Couldn't parse result"),
};
assert_eq!(actual_context, Arc::new(expected_context));
@ -1138,12 +1175,16 @@ mod tests {
let (is_testnet, debug, json) = (false, false, true);
let data_dir = data_dir_path_cli(is_testnet);
let (expected_context, expected_request) =
(Context::default(is_testnet, data_dir, debug, json).await.unwrap(), Request::buy_xmr(is_testnet));
let (expected_context, expected_request) = (
Context::default(is_testnet, data_dir, debug, json)
.await
.unwrap(),
Request::buy_xmr(is_testnet),
);
let (actual_context, actual_request) = match args {
ParseResult::Context(context, request) => (context, request),
_ => panic!("Couldn't parse result")
_ => panic!("Couldn't parse result"),
};
assert_eq!(actual_context, Arc::new(expected_context));
@ -1166,12 +1207,16 @@ mod tests {
let (is_testnet, debug, json) = (true, false, true);
let data_dir = data_dir_path_cli(is_testnet);
let (expected_context, expected_request) =
(Context::default(is_testnet, data_dir, debug, json).await.unwrap(), Request::buy_xmr(is_testnet));
let (expected_context, expected_request) = (
Context::default(is_testnet, data_dir, debug, json)
.await
.unwrap(),
Request::buy_xmr(is_testnet),
);
let (actual_context, actual_request) = match args {
ParseResult::Context(context, request) => (context, request),
_ => panic!("Couldn't parse result")
_ => panic!("Couldn't parse result"),
};
assert_eq!(actual_context, Arc::new(expected_context));
@ -1182,12 +1227,16 @@ mod tests {
let (is_testnet, debug, json) = (false, false, true);
let data_dir = data_dir_path_cli(is_testnet);
let (expected_context, expected_request) =
(Context::default(is_testnet, data_dir, debug, json).await.unwrap(), Request::resume());
let (expected_context, expected_request) = (
Context::default(is_testnet, data_dir, debug, json)
.await
.unwrap(),
Request::resume(),
);
let (actual_context, actual_request) = match args {
ParseResult::Context(context, request) => (context, request),
_ => panic!("Couldn't parse result")
_ => panic!("Couldn't parse result"),
};
assert_eq!(actual_context, Arc::new(expected_context));
@ -1206,12 +1255,16 @@ mod tests {
let (is_testnet, debug, json) = (true, false, true);
let data_dir = data_dir_path_cli(is_testnet);
let (expected_context, expected_request) =
(Context::default(is_testnet, data_dir, debug, json).await.unwrap(), Request::resume());
let (expected_context, expected_request) = (
Context::default(is_testnet, data_dir, debug, json)
.await
.unwrap(),
Request::resume(),
);
let (actual_context, actual_request) = match args {
ParseResult::Context(context, request) => (context, request),
_ => panic!("Couldn't parse result")
_ => panic!("Couldn't parse result"),
};
assert_eq!(actual_context, Arc::new(expected_context));

View File

@ -6,6 +6,7 @@ use async_trait::async_trait;
use libp2p::{Multiaddr, PeerId};
use sqlx::sqlite::Sqlite;
use sqlx::{Pool, SqlitePool};
use std::collections::HashMap;
use std::path::Path;
use std::str::FromStr;
use time::OffsetDateTime;
@ -149,7 +150,7 @@ impl Database for SqliteDatabase {
let rows = sqlx::query!(
r#"
SELECT address
SELECT DISTINCT address
FROM peer_addresses
WHERE peer_id = ?
"#,
@ -169,6 +170,24 @@ impl Database for SqliteDatabase {
addresses
}
async fn get_swap_start_date(&self, swap_id: Uuid) -> Result<String> {
let mut conn = self.pool.acquire().await?;
let swap_id = swap_id.to_string();
let row = sqlx::query!(
r#"
SELECT min(entered_at) as start_date
FROM swap_states
WHERE swap_id = ?
"#,
swap_id
)
.fetch_one(&mut conn)
.await?;
return Ok(row.start_date.unwrap());
}
async fn insert_latest_state(&self, swap_id: Uuid, state: State) -> Result<()> {
let mut conn = self.pool.acquire().await?;
let entered_at = OffsetDateTime::now_utc();
@ -249,6 +268,33 @@ impl Database for SqliteDatabase {
result
}
async fn raw_all(&self) -> Result<HashMap<Uuid, Vec<serde_json::Value>>> {
let mut conn = self.pool.acquire().await?;
let rows = sqlx::query!(
r#"
SELECT swap_id, state
FROM swap_states
"#
)
.fetch_all(&mut conn)
.await?;
let mut swaps: HashMap<Uuid, Vec<serde_json::Value>> = HashMap::new();
for row in &rows {
let swap_id = Uuid::from_str(&row.swap_id).unwrap();
let state = serde_json::from_str(&row.state).unwrap();
if swaps.contains_key(&swap_id) {
swaps.get_mut(&swap_id).unwrap().push(state);
} else {
swaps.insert(swap_id, vec![state]);
}
}
Ok(swaps)
}
}
#[cfg(test)]

View File

@ -16,6 +16,7 @@
missing_copy_implementations
)]
pub mod api;
pub mod asb;
pub mod bitcoin;
pub mod cli;
@ -24,7 +25,6 @@ pub mod database;
pub mod env;
pub mod fs;
pub mod kraken;
pub mod api;
pub mod libp2p_ext;
pub mod monero;
pub mod network;

View File

@ -11,6 +11,7 @@ use serde::{Deserialize, Serialize};
use sha2::Sha256;
use sigma_fun::ext::dl_secp256k1_ed25519_eq::{CrossCurveDLEQ, CrossCurveDLEQProof};
use sigma_fun::HashTranscript;
use std::collections::HashMap;
use std::convert::TryInto;
use uuid::Uuid;
@ -139,7 +140,9 @@ pub trait Database {
async fn get_monero_address(&self, swap_id: Uuid) -> Result<monero::Address>;
async fn insert_address(&self, peer_id: PeerId, address: Multiaddr) -> Result<()>;
async fn get_addresses(&self, peer_id: PeerId) -> Result<Vec<Multiaddr>>;
async fn get_swap_start_date(&self, swap_id: Uuid) -> Result<String>;
async fn insert_latest_state(&self, swap_id: Uuid, state: State) -> Result<()>;
async fn get_state(&self, swap_id: Uuid) -> Result<State>;
async fn all(&self) -> Result<Vec<(Uuid, State)>>;
async fn raw_all(&self) -> Result<HashMap<Uuid, Vec<serde_json::Value>>>;
}

View File

@ -1,8 +1,8 @@
use crate::api::Context;
use jsonrpsee::http_server::{HttpServerBuilder, HttpServerHandle, RpcModule};
use std::net::SocketAddr;
use jsonrpsee::http_server::{RpcModule, HttpServerBuilder, HttpServerHandle};
use thiserror::Error;
use crate::api::{Context};
use std::sync::Arc;
use thiserror::Error;
pub mod methods;
@ -12,11 +12,15 @@ pub enum Error {
ExampleError,
}
pub async fn run_server(server_address: SocketAddr, context: Arc<Context>) -> anyhow::Result<(SocketAddr, HttpServerHandle)> {
pub async fn run_server(
server_address: SocketAddr,
context: Arc<Context>,
) -> anyhow::Result<(SocketAddr, HttpServerHandle)> {
let server = HttpServerBuilder::default().build(server_address).await?;
let mut modules = RpcModule::new(());
{
modules.merge(methods::register_modules(Arc::clone(&context)))
modules
.merge(methods::register_modules(Arc::clone(&context)))
.unwrap()
}
@ -26,4 +30,3 @@ pub async fn run_server(server_address: SocketAddr, context: Arc<Context>) -> an
Ok((addr, server_handle))
}

View File

@ -1,66 +1,164 @@
use jsonrpsee::http_server::{RpcModule};
use crate::api::{Request, Context, Params};
use crate::cli::command::{Command};
use std::str::FromStr;
use crate::api::{Context, Params, Request};
use crate::cli::command::Command;
use crate::rpc::Error;
use crate::{bitcoin, monero};
use jsonrpsee::http_server::RpcModule;
use libp2p::core::Multiaddr;
use serde_json::json;
use std::collections::HashMap;
use std::str::FromStr;
use std::sync::Arc;
use uuid::Uuid;
use std::collections::HashMap;
use libp2p::core::Multiaddr;
pub fn register_modules(context: Arc<Context>) -> RpcModule<Arc<Context>> {
let mut module = RpcModule::new(context);
module
.register_async_method("get_bitcoin_balance", |_, context| async move {
get_bitcoin_balance(&context).await.map_err(|err| jsonrpsee_core::Error::Custom(err.to_string()))
},
)
get_bitcoin_balance(&context)
.await
.map_err(|err| jsonrpsee_core::Error::Custom(err.to_string()))
})
.unwrap();
module
.register_async_method("get_history", |_, context| async move {
get_history(&context).await.map_err(|err| jsonrpsee_core::Error::Custom(err.to_string()))
},
)
get_history(&context)
.await
.map_err(|err| jsonrpsee_core::Error::Custom(err.to_string()))
})
.unwrap();
module
.register_async_method("raw_get_history", |_, context| async move {
context
.db
.raw_all()
.await
.map_err(|err| jsonrpsee_core::Error::Custom(err.to_string()))
})
.unwrap();
module
.register_async_method("get_seller", |params, context| async move {
let params: HashMap<String, String> = params.parse()?;
let swap_id = Uuid::from_str(params.get("swap_id").ok_or_else(|| {
jsonrpsee_core::Error::Custom("Does not contain swap_id".to_string())
})?)
.unwrap();
let peerId = context
.db
.get_peer_id(swap_id)
.await
.map_err(|err| jsonrpsee_core::Error::Custom(err.to_string()))
.unwrap();
let addresses = context
.db
.get_addresses(peerId)
.await
.map_err(|err| jsonrpsee_core::Error::Custom(err.to_string()))
.unwrap();
Ok(json!({
"peerId": peerId.to_base58(),
"addresses": addresses
}))
})
.unwrap();
module
.register_async_method("get_swap_start_date", |params, context| async move {
let params: HashMap<String, String> = params.parse()?;
let swap_id = Uuid::from_str(params.get("swap_id").ok_or_else(|| {
jsonrpsee_core::Error::Custom("Does not contain swap_id".to_string())
})?)
.unwrap();
let start_date = context
.db
.get_swap_start_date(swap_id)
.await
.map_err(|err| jsonrpsee_core::Error::Custom(err.to_string()))
.unwrap();
Ok(json!({
"start_date": start_date,
}))
})
.unwrap();
module
.register_async_method("resume_swap", |params, context| async move {
let swap_id: HashMap<String, String> = params.parse()?;
let swap_id = Uuid::from_str(swap_id.get("swap_id").ok_or_else(|| jsonrpsee_core::Error::Custom("Does not contain swap_id".to_string()))?).unwrap();
resume_swap(swap_id, &context).await.map_err(|err| jsonrpsee_core::Error::Custom(err.to_string()))
},
)
let params: HashMap<String, String> = params.parse()?;
let swap_id = Uuid::from_str(params.get("swap_id").ok_or_else(|| {
jsonrpsee_core::Error::Custom("Does not contain swap_id".to_string())
})?)
.unwrap();
resume_swap(swap_id, &context)
.await
.map_err(|err| jsonrpsee_core::Error::Custom(err.to_string()))
})
.unwrap();
module
.register_async_method("withdraw_btc", |params, context| async move {
let map_params: HashMap<String, String> = params.parse()?;
let amount = if let Some(amount_str) = map_params.get("amount") {
Some(::bitcoin::Amount::from_str_in(amount_str, ::bitcoin::Denomination::Bitcoin).map_err(|_| jsonrpsee_core::Error::Custom("Unable to parse amount".to_string()))?)
let params: HashMap<String, String> = params.parse()?;
let amount = if let Some(amount_str) = params.get("amount") {
Some(
::bitcoin::Amount::from_str_in(amount_str, ::bitcoin::Denomination::Bitcoin)
.map_err(|_| {
jsonrpsee_core::Error::Custom("Unable to parse amount".to_string())
})?,
)
} else {
None
};
let withdraw_address = bitcoin::Address::from_str(map_params.get("address").ok_or_else(|| jsonrpsee_core::Error::Custom("Does not contain address".to_string()))?).unwrap();
withdraw_btc(withdraw_address, amount, &context).await.map_err(|err| jsonrpsee_core::Error::Custom(err.to_string()))
},
)
let withdraw_address =
bitcoin::Address::from_str(params.get("address").ok_or_else(|| {
jsonrpsee_core::Error::Custom("Does not contain address".to_string())
})?)
.unwrap();
withdraw_btc(withdraw_address, amount, &context)
.await
.map_err(|err| jsonrpsee_core::Error::Custom(err.to_string()))
})
.unwrap();
module
.register_async_method("buy_xmr", |params, context| async move {
let map_params: HashMap<String, String> = params.parse()?;
let bitcoin_change_address = bitcoin::Address::from_str(map_params.get("bitcoin_change_address").ok_or_else(|| jsonrpsee_core::Error::Custom("Does not contain bitcoin_change_address".to_string()))?).unwrap();
let monero_receive_address = monero::Address::from_str(map_params.get("monero_receive_address").ok_or_else(|| jsonrpsee_core::Error::Custom("Does not contain monero_receiveaddress".to_string()))?).unwrap();
let seller = Multiaddr::from_str(map_params.get("seller").ok_or_else(|| jsonrpsee_core::Error::Custom("Does not contain seller".to_string()))?).unwrap();
buy_xmr(bitcoin_change_address, monero_receive_address, seller, &context).await.map_err(|err| jsonrpsee_core::Error::Custom(err.to_string()))
},
let params: HashMap<String, String> = params.parse()?;
let bitcoin_change_address = bitcoin::Address::from_str(
params.get("bitcoin_change_address").ok_or_else(|| {
jsonrpsee_core::Error::Custom(
"Does not contain bitcoin_change_address".to_string(),
)
})?,
)
.unwrap();
let monero_receive_address = monero::Address::from_str(
params.get("monero_receive_address").ok_or_else(|| {
jsonrpsee_core::Error::Custom(
"Does not contain monero_receiveaddress".to_string(),
)
})?,
)
.unwrap();
let seller = Multiaddr::from_str(params.get("seller").ok_or_else(|| {
jsonrpsee_core::Error::Custom("Does not contain seller".to_string())
})?)
.unwrap();
buy_xmr(
bitcoin_change_address,
monero_receive_address,
seller,
&context,
)
.await
.map_err(|err| jsonrpsee_core::Error::Custom(err.to_string()))
})
.unwrap();
module
.register_async_method("list_sellers", |params, context| async move {
let map_params: HashMap<String, String> = params.parse()?;
let rendezvous_point = Multiaddr::from_str(map_params.get("rendezvous_point").ok_or_else(|| jsonrpsee_core::Error::Custom("Does not contain rendezvous_point".to_string()))?).unwrap();
list_sellers(rendezvous_point, &context).await.map_err(|err| jsonrpsee_core::Error::Custom(err.to_string()))
},
)
let params: HashMap<String, String> = params.parse()?;
let rendezvous_point =
Multiaddr::from_str(params.get("rendezvous_point").ok_or_else(|| {
jsonrpsee_core::Error::Custom("Does not contain rendezvous_point".to_string())
})?)
.unwrap();
list_sellers(rendezvous_point, &context)
.await
.map_err(|err| jsonrpsee_core::Error::Custom(err.to_string()))
})
.unwrap();
module
}
@ -83,7 +181,10 @@ async fn get_history(context: &Arc<Context>) -> anyhow::Result<serde_json::Value
Ok(history)
}
async fn resume_swap(swap_id: Uuid, context: &Arc<Context>) -> anyhow::Result<serde_json::Value, Error> {
async fn resume_swap(
swap_id: Uuid,
context: &Arc<Context>,
) -> anyhow::Result<serde_json::Value, Error> {
let request = Request {
params: Params {
swap_id: Some(swap_id),
@ -95,10 +196,14 @@ async fn resume_swap(swap_id: Uuid, context: &Arc<Context>) -> anyhow::Result<se
let result = request.call(Arc::clone(context)).await.unwrap();
Ok(result)
}
async fn withdraw_btc(withdraw_address: bitcoin::Address, amount: Option<bitcoin::Amount>, context: &Arc<Context>) -> anyhow::Result<serde_json::Value, Error> {
async fn withdraw_btc(
withdraw_address: bitcoin::Address,
amount: Option<bitcoin::Amount>,
context: &Arc<Context>,
) -> anyhow::Result<serde_json::Value, Error> {
let request = Request {
params: Params {
amount: amount,
amount,
address: Some(withdraw_address),
..Default::default()
},
@ -108,7 +213,12 @@ async fn withdraw_btc(withdraw_address: bitcoin::Address, amount: Option<bitcoin
Ok(result)
}
async fn buy_xmr(bitcoin_change_address: bitcoin::Address, monero_receive_address: monero::Address, seller: Multiaddr, context: &Arc<Context>) -> anyhow::Result<serde_json::Value, Error> {
async fn buy_xmr(
bitcoin_change_address: bitcoin::Address,
monero_receive_address: monero::Address,
seller: Multiaddr,
context: &Arc<Context>,
) -> anyhow::Result<serde_json::Value, Error> {
let request = Request {
params: Params {
bitcoin_change_address: Some(bitcoin_change_address),
@ -122,7 +232,10 @@ async fn buy_xmr(bitcoin_change_address: bitcoin::Address, monero_receive_addres
Ok(swap)
}
async fn list_sellers(rendezvous_point: Multiaddr, context: &Arc<Context>) -> anyhow::Result<serde_json::Value, Error> {
async fn list_sellers(
rendezvous_point: Multiaddr,
context: &Arc<Context>,
) -> anyhow::Result<serde_json::Value, Error> {
let request = Request {
params: Params {
rendezvous_point: Some(rendezvous_point),