mirror of
https://github.com/comit-network/xmr-btc-swap.git
synced 2025-08-08 22:42:35 -04:00
Cleanup, formatting, add get_seller
, get_swap_start_date
RPC endpoints
This commit is contained in:
parent
0df5af16b8
commit
e1983d5639
10 changed files with 639 additions and 355 deletions
|
@ -28,6 +28,24 @@
|
||||||
},
|
},
|
||||||
"query": "\n insert into peer_addresses (\n peer_id,\n address\n ) values (?, ?);\n "
|
"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": {
|
"1ec38c85e7679b2eb42b3df75d9098772ce44fdb8db3012d3c2410d828b74157": {
|
||||||
"describe": {
|
"describe": {
|
||||||
"columns": [
|
"columns": [
|
||||||
|
@ -62,6 +80,30 @@
|
||||||
},
|
},
|
||||||
"query": "\n insert into peers (\n swap_id,\n peer_id\n ) values (?, ?);\n "
|
"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": {
|
"50a5764546f69c118fa0b64120da50f51073d36257d49768de99ff863e3511e0": {
|
||||||
"describe": {
|
"describe": {
|
||||||
"columns": [],
|
"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 "
|
"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": {
|
"b703032b4ddc627a1124817477e7a8e5014bdc694c36a14053ef3bb2fc0c69b0": {
|
||||||
"describe": {
|
"describe": {
|
||||||
"columns": [],
|
"columns": [],
|
||||||
|
@ -135,5 +159,23 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"query": "\n SELECT address\n FROM monero_addresses\n WHERE swap_id = ?\n "
|
"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 "
|
||||||
}
|
}
|
||||||
}
|
}
|
208
swap/src/api.rs
208
swap/src/api.rs
|
@ -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 anyhow::{bail, Context as AnyContext, Result};
|
||||||
use comfy_table::Table;
|
use comfy_table::Table;
|
||||||
|
use libp2p::core::Multiaddr;
|
||||||
use qrcode::render::unicode;
|
use qrcode::render::unicode;
|
||||||
use qrcode::QrCode;
|
use qrcode::QrCode;
|
||||||
use crate::env::GetConfig;
|
use serde::ser::{Serialize, SerializeStruct, Serializer};
|
||||||
|
use serde_json::json;
|
||||||
use std::cmp::min;
|
use std::cmp::min;
|
||||||
use crate::network::rendezvous::XmrBtcNamespace;
|
|
||||||
use std::net::SocketAddr;
|
|
||||||
use libp2p::core::Multiaddr;
|
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
use crate::bitcoin::Amount;
|
use std::fmt;
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
|
use std::net::SocketAddr;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
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 url::Url;
|
||||||
use uuid::Uuid;
|
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)]
|
#[derive(PartialEq, Debug)]
|
||||||
pub struct Request {
|
pub struct Request {
|
||||||
|
@ -53,7 +48,7 @@ pub struct Params {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Context {
|
pub struct Context {
|
||||||
db: Arc<dyn Database + Send + Sync>,
|
pub db: Arc<dyn Database + Send + Sync>,
|
||||||
bitcoin_wallet: Option<Arc<bitcoin::Wallet>>,
|
bitcoin_wallet: Option<Arc<bitcoin::Wallet>>,
|
||||||
monero_wallet: Option<Arc<monero::Wallet>>,
|
monero_wallet: Option<Arc<monero::Wallet>>,
|
||||||
monero_rpc_process: Option<monero::WalletRpcProcess>,
|
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_change_address = self.params.bitcoin_change_address.clone().unwrap();
|
||||||
|
|
||||||
let bitcoin_wallet = btc;
|
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()
|
.extract_peer_id()
|
||||||
.context("Seller address must contain 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(
|
let behaviour = cli::Behaviour::new(
|
||||||
seller_peer_id,
|
seller_peer_id,
|
||||||
|
@ -92,8 +94,12 @@ impl Request {
|
||||||
bitcoin_wallet.clone(),
|
bitcoin_wallet.clone(),
|
||||||
(seed.derive_libp2p_identity(), context.namespace),
|
(seed.derive_libp2p_identity(), context.namespace),
|
||||||
);
|
);
|
||||||
let mut swarm =
|
let mut swarm = swarm::cli(
|
||||||
swarm::cli(seed.derive_libp2p_identity(), context.tor_socks5_port.unwrap(), behaviour).await?;
|
seed.derive_libp2p_identity(),
|
||||||
|
context.tor_socks5_port.unwrap(),
|
||||||
|
behaviour,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
swarm.behaviour_mut().add_address(seller_peer_id, seller);
|
swarm.behaviour_mut().add_address(seller_peer_id, seller);
|
||||||
|
|
||||||
tracing::debug!(peer_id = %swarm.local_peer_id(), "Network layer initialized");
|
tracing::debug!(peer_id = %swarm.local_peer_id(), "Network layer initialized");
|
||||||
|
@ -128,7 +134,9 @@ impl Request {
|
||||||
tracing::info!(%amount, %fees, "Determined swap amount");
|
tracing::info!(%amount, %fees, "Determined swap amount");
|
||||||
|
|
||||||
context.db.insert_peer_id(swap_id, seller_peer_id).await?;
|
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?;
|
.await?;
|
||||||
let monero_wallet = context.monero_wallet.as_ref().unwrap();
|
let monero_wallet = context.monero_wallet.as_ref().unwrap();
|
||||||
|
|
||||||
|
@ -165,18 +173,20 @@ impl Request {
|
||||||
let state: BobState = state.try_into()?;
|
let state: BobState = state.try_into()?;
|
||||||
vec.push((swap_id, state.to_string()));
|
vec.push((swap_id, state.to_string()));
|
||||||
}
|
}
|
||||||
json!({
|
json!({ "swaps": vec })
|
||||||
"swaps": vec
|
|
||||||
})
|
|
||||||
|
|
||||||
}
|
}
|
||||||
Command::Config => {
|
Command::Config => {
|
||||||
// tracing::info!(path=%data_dir.display(), "Data directory");
|
// tracing::info!(path=%data_dir.display(), "Data directory");
|
||||||
// tracing::info!(path=%format!("{}/logs", data_dir.display()), "Log files directory");
|
// tracing::info!(path=%format!("{}/logs", data_dir.display()),
|
||||||
// tracing::info!(path=%format!("{}/sqlite", data_dir.display()), "Sqlite file location");
|
// "Log files directory");
|
||||||
// tracing::info!(path=%format!("{}/seed.pem", data_dir.display()), "Seed file location");
|
// tracing::info!(path=%format!("{}/sqlite", data_dir.display()), "Sqlite file
|
||||||
// tracing::info!(path=%format!("{}/monero", data_dir.display()), "Monero-wallet-rpc directory");
|
// location");
|
||||||
// tracing::info!(path=%format!("{}/wallet", data_dir.display()), "Internal bitcoin wallet directory");
|
// 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!({
|
json!({
|
||||||
"result": []
|
"result": []
|
||||||
|
@ -200,7 +210,9 @@ impl Request {
|
||||||
.await?;
|
.await?;
|
||||||
let signed_tx = bitcoin_wallet.sign_and_finalize(psbt).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!({
|
json!({
|
||||||
"signed_tx": signed_tx,
|
"signed_tx": signed_tx,
|
||||||
|
@ -220,9 +232,7 @@ impl Request {
|
||||||
Some(handle)
|
Some(handle)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
loop {
|
loop {}
|
||||||
|
|
||||||
}
|
|
||||||
json!({
|
json!({
|
||||||
"result": []
|
"result": []
|
||||||
})
|
})
|
||||||
|
@ -255,8 +265,12 @@ impl Request {
|
||||||
Arc::clone(context.bitcoin_wallet.as_ref().unwrap()),
|
Arc::clone(context.bitcoin_wallet.as_ref().unwrap()),
|
||||||
(seed.clone(), context.namespace),
|
(seed.clone(), context.namespace),
|
||||||
);
|
);
|
||||||
let mut swarm =
|
let mut swarm = swarm::cli(
|
||||||
swarm::cli(seed.clone(), context.tor_socks5_port.clone().unwrap(), behaviour).await?;
|
seed.clone(),
|
||||||
|
context.tor_socks5_port.clone().unwrap(),
|
||||||
|
behaviour,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
let our_peer_id = swarm.local_peer_id();
|
let our_peer_id = swarm.local_peer_id();
|
||||||
|
|
||||||
tracing::debug!(peer_id = %our_peer_id, "Network layer initialized");
|
tracing::debug!(peer_id = %our_peer_id, "Network layer initialized");
|
||||||
|
@ -267,7 +281,8 @@ impl Request {
|
||||||
.add_address(seller_peer_id, seller_address);
|
.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 handle = tokio::spawn(event_loop.run());
|
||||||
|
|
||||||
let monero_receive_address = context.db.get_monero_address(swap_id).await?;
|
let monero_receive_address = context.db.get_monero_address(swap_id).await?;
|
||||||
|
@ -297,7 +312,12 @@ impl Request {
|
||||||
Command::Cancel => {
|
Command::Cancel => {
|
||||||
let bitcoin_wallet = context.bitcoin_wallet.as_ref().unwrap();
|
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);
|
tracing::debug!("Cancel transaction successfully published with id {}", txid);
|
||||||
|
|
||||||
|
@ -308,11 +328,14 @@ impl Request {
|
||||||
Command::Refund => {
|
Command::Refund => {
|
||||||
let bitcoin_wallet = context.bitcoin_wallet.as_ref().unwrap();
|
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!({
|
json!({ "result": state })
|
||||||
"result": state
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
Command::ListSellers => {
|
Command::ListSellers => {
|
||||||
let rendezvous_point = self.params.rendezvous_point.clone().unwrap();
|
let rendezvous_point = self.params.rendezvous_point.clone().unwrap();
|
||||||
|
@ -328,7 +351,8 @@ impl Request {
|
||||||
context.namespace,
|
context.namespace,
|
||||||
context.tor_socks5_port.unwrap(),
|
context.tor_socks5_port.unwrap(),
|
||||||
identity,
|
identity,
|
||||||
).await?;
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
for seller in &sellers {
|
for seller in &sellers {
|
||||||
match seller.status {
|
match seller.status {
|
||||||
|
@ -352,9 +376,7 @@ impl Request {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
json!({
|
json!({ "sellers": sellers })
|
||||||
"sellers": sellers
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
Command::ExportBitcoinWallet => {
|
Command::ExportBitcoinWallet => {
|
||||||
let bitcoin_wallet = context.bitcoin_wallet.as_ref().unwrap();
|
let bitcoin_wallet = context.bitcoin_wallet.as_ref().unwrap();
|
||||||
|
@ -366,7 +388,11 @@ impl Request {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
Command::MoneroRecovery => {
|
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 {
|
match swap_state {
|
||||||
BobState::Started { .. }
|
BobState::Started { .. }
|
||||||
|
@ -429,14 +455,16 @@ impl Context {
|
||||||
if let Some(bitcoin) = bitcoin {
|
if let Some(bitcoin) = bitcoin {
|
||||||
let (bitcoin_electrum_rpc_url, bitcoin_target_block) =
|
let (bitcoin_electrum_rpc_url, bitcoin_target_block) =
|
||||||
bitcoin.apply_defaults(is_testnet)?;
|
bitcoin.apply_defaults(is_testnet)?;
|
||||||
Some(Arc::new(init_bitcoin_wallet(
|
Some(Arc::new(
|
||||||
|
init_bitcoin_wallet(
|
||||||
bitcoin_electrum_rpc_url,
|
bitcoin_electrum_rpc_url,
|
||||||
&seed,
|
&seed,
|
||||||
data_dir.clone(),
|
data_dir.clone(),
|
||||||
env_config,
|
env_config,
|
||||||
bitcoin_target_block,
|
bitcoin_target_block,
|
||||||
)
|
)
|
||||||
.await?))
|
.await?,
|
||||||
|
))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
@ -445,18 +473,14 @@ impl Context {
|
||||||
let (monero_wallet, monero_rpc_process) = {
|
let (monero_wallet, monero_rpc_process) = {
|
||||||
if let Some(monero) = monero {
|
if let Some(monero) = monero {
|
||||||
let monero_daemon_address = monero.apply_defaults(is_testnet);
|
let monero_daemon_address = monero.apply_defaults(is_testnet);
|
||||||
let (wlt, prc) = init_monero_wallet(
|
let (wlt, prc) =
|
||||||
data_dir.clone(),
|
init_monero_wallet(data_dir.clone(), monero_daemon_address, env_config).await?;
|
||||||
monero_daemon_address,
|
|
||||||
env_config,
|
|
||||||
).await?;
|
|
||||||
(Some(Arc::new(wlt)), Some(prc))
|
(Some(Arc::new(wlt)), Some(prc))
|
||||||
} else {
|
} else {
|
||||||
(None, None)
|
(None, None)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
let tor_socks5_port = {
|
let tor_socks5_port = {
|
||||||
if let Some(tor) = tor {
|
if let Some(tor) = tor {
|
||||||
Some(tor.tor_socks5_port)
|
Some(tor.tor_socks5_port)
|
||||||
|
@ -471,7 +495,7 @@ impl Context {
|
||||||
bitcoin_wallet,
|
bitcoin_wallet,
|
||||||
monero_wallet,
|
monero_wallet,
|
||||||
monero_rpc_process,
|
monero_rpc_process,
|
||||||
tor_socks5_port: tor_socks5_port,
|
tor_socks5_port,
|
||||||
namespace: XmrBtcNamespace::from_is_testnet(is_testnet),
|
namespace: XmrBtcNamespace::from_is_testnet(is_testnet),
|
||||||
db: open_db(data_dir.join("sqlite")).await?,
|
db: open_db(data_dir.join("sqlite")).await?,
|
||||||
env_config,
|
env_config,
|
||||||
|
@ -482,10 +506,8 @@ impl Context {
|
||||||
server_address,
|
server_address,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
Ok(init)
|
Ok(init)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Serialize for Context {
|
impl Serialize for Context {
|
||||||
|
@ -503,11 +525,11 @@ impl Serialize for Context {
|
||||||
|
|
||||||
impl PartialEq for Context {
|
impl PartialEq for Context {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
self.tor_socks5_port == other.tor_socks5_port &&
|
self.tor_socks5_port == other.tor_socks5_port
|
||||||
self.namespace == other.namespace &&
|
&& self.namespace == other.namespace
|
||||||
self.debug == other.debug &&
|
&& self.debug == other.debug
|
||||||
self.json == other.json &&
|
&& self.json == other.json
|
||||||
self.server_address == other.server_address
|
&& self.server_address == other.server_address
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -709,26 +731,34 @@ pub mod api_test {
|
||||||
pub const SWAP_ID: &str = "ea030832-3be9-454f-bb98-5ea9a788406b";
|
pub const SWAP_ID: &str = "ea030832-3be9-454f-bb98-5ea9a788406b";
|
||||||
|
|
||||||
impl Context {
|
impl Context {
|
||||||
|
pub async fn default(
|
||||||
pub async fn default(is_testnet: bool, data_dir: PathBuf, json: bool, debug: bool) -> Result<Context> {
|
is_testnet: bool,
|
||||||
|
data_dir: PathBuf,
|
||||||
|
json: bool,
|
||||||
|
debug: bool,
|
||||||
|
) -> Result<Context> {
|
||||||
Ok(Context::build(
|
Ok(Context::build(
|
||||||
Some(Bitcoin { bitcoin_electrum_rpc_url: None, bitcoin_target_block: None}),
|
Some(Bitcoin {
|
||||||
Some(Monero { monero_daemon_address: None }),
|
bitcoin_electrum_rpc_url: None,
|
||||||
Some(Tor { tor_socks5_port: DEFAULT_SOCKS5_PORT }),
|
bitcoin_target_block: None,
|
||||||
|
}),
|
||||||
|
Some(Monero {
|
||||||
|
monero_daemon_address: None,
|
||||||
|
}),
|
||||||
|
Some(Tor {
|
||||||
|
tor_socks5_port: DEFAULT_SOCKS5_PORT,
|
||||||
|
}),
|
||||||
Some(data_dir),
|
Some(data_dir),
|
||||||
is_testnet,
|
is_testnet,
|
||||||
debug,
|
debug,
|
||||||
json,
|
json,
|
||||||
None
|
None,
|
||||||
).await?)
|
)
|
||||||
|
.await?)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
impl Request {
|
impl Request {
|
||||||
|
|
||||||
pub fn buy_xmr(is_testnet: bool) -> Request {
|
pub fn buy_xmr(is_testnet: bool) -> Request {
|
||||||
|
|
||||||
let seller = Multiaddr::from_str(MULTI_ADDRESS).unwrap();
|
let seller = Multiaddr::from_str(MULTI_ADDRESS).unwrap();
|
||||||
let bitcoin_change_address = {
|
let bitcoin_change_address = {
|
||||||
if is_testnet {
|
if is_testnet {
|
||||||
|
@ -752,9 +782,8 @@ pub mod api_test {
|
||||||
bitcoin_change_address: Some(bitcoin_change_address),
|
bitcoin_change_address: Some(bitcoin_change_address),
|
||||||
monero_receive_address: Some(monero_receive_address),
|
monero_receive_address: Some(monero_receive_address),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
|
|
||||||
},
|
},
|
||||||
cmd: Command::BuyXmr
|
cmd: Command::BuyXmr,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -763,9 +792,8 @@ pub mod api_test {
|
||||||
params: Params {
|
params: Params {
|
||||||
swap_id: Some(Uuid::from_str(SWAP_ID).unwrap()),
|
swap_id: Some(Uuid::from_str(SWAP_ID).unwrap()),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
|
|
||||||
},
|
},
|
||||||
cmd: Command::Resume
|
cmd: Command::Resume,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -774,9 +802,8 @@ pub mod api_test {
|
||||||
params: Params {
|
params: Params {
|
||||||
swap_id: Some(Uuid::from_str(SWAP_ID).unwrap()),
|
swap_id: Some(Uuid::from_str(SWAP_ID).unwrap()),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
|
|
||||||
},
|
},
|
||||||
cmd: Command::Cancel
|
cmd: Command::Cancel,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -785,9 +812,8 @@ pub mod api_test {
|
||||||
params: Params {
|
params: Params {
|
||||||
swap_id: Some(Uuid::from_str(SWAP_ID).unwrap()),
|
swap_id: Some(Uuid::from_str(SWAP_ID).unwrap()),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
|
|
||||||
},
|
},
|
||||||
cmd: Command::Refund
|
cmd: Command::Refund,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,9 +14,9 @@
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use std::env;
|
use std::env;
|
||||||
|
use std::sync::Arc;
|
||||||
use swap::cli::command::{parse_args_and_apply_defaults, ParseResult};
|
use swap::cli::command::{parse_args_and_apply_defaults, ParseResult};
|
||||||
use swap::common::check_latest_version;
|
use swap::common::check_latest_version;
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> Result<()> {
|
async fn main() -> Result<()> {
|
||||||
|
@ -36,18 +36,16 @@ async fn main() -> Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use swap::api::determine_btc_to_swap;
|
|
||||||
use ::bitcoin::Amount;
|
use ::bitcoin::Amount;
|
||||||
use std::sync::Mutex;
|
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 swap::tracing_ext::capture_logs;
|
||||||
use tracing::level_filters::LevelFilter;
|
use tracing::level_filters::LevelFilter;
|
||||||
use swap::network::quote::BidQuote;
|
|
||||||
use std::time::Duration;
|
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn given_no_balance_and_transfers_less_than_max_swaps_max_giveable() {
|
async fn given_no_balance_and_transfers_less_than_max_swaps_max_giveable() {
|
||||||
|
|
|
@ -1,19 +1,19 @@
|
||||||
|
use crate::api::{Context, Params, Request};
|
||||||
use crate::bitcoin::Amount;
|
use crate::bitcoin::Amount;
|
||||||
|
use crate::fs::system_data_dir;
|
||||||
use crate::{env, monero};
|
use crate::{env, monero};
|
||||||
use crate::api::{Request, Params, Context};
|
|
||||||
use anyhow::{bail, Context as AnyContext, Result};
|
use anyhow::{bail, Context as AnyContext, Result};
|
||||||
use bitcoin::{Address, AddressType};
|
use bitcoin::{Address, AddressType};
|
||||||
use libp2p::core::Multiaddr;
|
use libp2p::core::Multiaddr;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use std::ffi::OsString;
|
use std::ffi::OsString;
|
||||||
|
use std::net::SocketAddr;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
use std::sync::Arc;
|
||||||
use structopt::{clap, StructOpt};
|
use structopt::{clap, StructOpt};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
use std::net::SocketAddr;
|
|
||||||
use std::sync::Arc;
|
|
||||||
use crate::fs::system_data_dir;
|
|
||||||
|
|
||||||
// See: https://moneroworld.com/
|
// See: https://moneroworld.com/
|
||||||
pub const DEFAULT_MONERO_DAEMON_ADDRESS: &str = "node.community.rino.io:18081";
|
pub const DEFAULT_MONERO_DAEMON_ADDRESS: &str = "node.community.rino.io:18081";
|
||||||
|
@ -79,8 +79,9 @@ where
|
||||||
is_testnet,
|
is_testnet,
|
||||||
debug,
|
debug,
|
||||||
json,
|
json,
|
||||||
None
|
None,
|
||||||
).await?;
|
)
|
||||||
|
.await?;
|
||||||
let request = Request {
|
let request = Request {
|
||||||
params: Params {
|
params: Params {
|
||||||
bitcoin_change_address: Some(bitcoin_change_address),
|
bitcoin_change_address: Some(bitcoin_change_address),
|
||||||
|
@ -93,44 +94,26 @@ where
|
||||||
(context, request)
|
(context, request)
|
||||||
}
|
}
|
||||||
RawCommand::History => {
|
RawCommand::History => {
|
||||||
let context = Context::build(
|
let context =
|
||||||
None,
|
Context::build(None, None, None, data, is_testnet, debug, json, None).await?;
|
||||||
None,
|
|
||||||
None,
|
|
||||||
data,
|
|
||||||
is_testnet,
|
|
||||||
debug,
|
|
||||||
json,
|
|
||||||
None
|
|
||||||
).await?;
|
|
||||||
|
|
||||||
let request = Request {
|
let request = Request {
|
||||||
params: Params::default(),
|
params: Params::default(),
|
||||||
cmd: Command::History,
|
cmd: Command::History,
|
||||||
};
|
};
|
||||||
(context, request)
|
(context, request)
|
||||||
},
|
}
|
||||||
RawCommand::Config => {
|
RawCommand::Config => {
|
||||||
let context = Context::build(
|
let context =
|
||||||
None,
|
Context::build(None, None, None, data, is_testnet, debug, json, None).await?;
|
||||||
None,
|
|
||||||
None,
|
|
||||||
data,
|
|
||||||
is_testnet,
|
|
||||||
debug,
|
|
||||||
json,
|
|
||||||
None
|
|
||||||
).await?;
|
|
||||||
|
|
||||||
let request = Request {
|
let request = Request {
|
||||||
params: Params::default(),
|
params: Params::default(),
|
||||||
cmd: Command::Config,
|
cmd: Command::Config,
|
||||||
};
|
};
|
||||||
(context, request)
|
(context, request)
|
||||||
},
|
}
|
||||||
RawCommand::Balance {
|
RawCommand::Balance { bitcoin } => {
|
||||||
bitcoin,
|
|
||||||
} => {
|
|
||||||
let context = Context::build(
|
let context = Context::build(
|
||||||
Some(bitcoin),
|
Some(bitcoin),
|
||||||
None,
|
None,
|
||||||
|
@ -139,8 +122,9 @@ where
|
||||||
is_testnet,
|
is_testnet,
|
||||||
debug,
|
debug,
|
||||||
json,
|
json,
|
||||||
None
|
None,
|
||||||
).await?;
|
)
|
||||||
|
.await?;
|
||||||
let request = Request {
|
let request = Request {
|
||||||
params: Params::default(),
|
params: Params::default(),
|
||||||
cmd: Command::Balance,
|
cmd: Command::Balance,
|
||||||
|
@ -162,7 +146,8 @@ where
|
||||||
debug,
|
debug,
|
||||||
json,
|
json,
|
||||||
server_address,
|
server_address,
|
||||||
).await?;
|
)
|
||||||
|
.await?;
|
||||||
let request = Request {
|
let request = Request {
|
||||||
params: Params::default(),
|
params: Params::default(),
|
||||||
cmd: Command::StartDaemon,
|
cmd: Command::StartDaemon,
|
||||||
|
@ -182,11 +167,12 @@ where
|
||||||
is_testnet,
|
is_testnet,
|
||||||
debug,
|
debug,
|
||||||
json,
|
json,
|
||||||
None
|
None,
|
||||||
).await?;
|
)
|
||||||
|
.await?;
|
||||||
let request = Request {
|
let request = Request {
|
||||||
params: Params {
|
params: Params {
|
||||||
amount: amount,
|
amount,
|
||||||
address: Some(address),
|
address: Some(address),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
|
@ -209,7 +195,8 @@ where
|
||||||
debug,
|
debug,
|
||||||
json,
|
json,
|
||||||
None,
|
None,
|
||||||
).await?;
|
)
|
||||||
|
.await?;
|
||||||
let request = Request {
|
let request = Request {
|
||||||
params: Params {
|
params: Params {
|
||||||
swap_id: Some(swap_id),
|
swap_id: Some(swap_id),
|
||||||
|
@ -231,8 +218,9 @@ where
|
||||||
is_testnet,
|
is_testnet,
|
||||||
debug,
|
debug,
|
||||||
json,
|
json,
|
||||||
None
|
None,
|
||||||
).await?;
|
)
|
||||||
|
.await?;
|
||||||
let request = Request {
|
let request = Request {
|
||||||
params: Params {
|
params: Params {
|
||||||
swap_id: Some(swap_id),
|
swap_id: Some(swap_id),
|
||||||
|
@ -254,8 +242,9 @@ where
|
||||||
is_testnet,
|
is_testnet,
|
||||||
debug,
|
debug,
|
||||||
json,
|
json,
|
||||||
None
|
None,
|
||||||
).await?;
|
)
|
||||||
|
.await?;
|
||||||
let request = Request {
|
let request = Request {
|
||||||
params: Params {
|
params: Params {
|
||||||
swap_id: Some(swap_id),
|
swap_id: Some(swap_id),
|
||||||
|
@ -269,16 +258,8 @@ where
|
||||||
rendezvous_point,
|
rendezvous_point,
|
||||||
tor,
|
tor,
|
||||||
} => {
|
} => {
|
||||||
let context = Context::build(
|
let context =
|
||||||
None,
|
Context::build(None, None, Some(tor), data, is_testnet, debug, json, None).await?;
|
||||||
None,
|
|
||||||
Some(tor),
|
|
||||||
data,
|
|
||||||
is_testnet,
|
|
||||||
debug,
|
|
||||||
json,
|
|
||||||
None
|
|
||||||
).await?;
|
|
||||||
|
|
||||||
let request = Request {
|
let request = Request {
|
||||||
params: Params {
|
params: Params {
|
||||||
|
@ -298,25 +279,18 @@ where
|
||||||
is_testnet,
|
is_testnet,
|
||||||
debug,
|
debug,
|
||||||
json,
|
json,
|
||||||
None
|
None,
|
||||||
).await?;
|
)
|
||||||
|
.await?;
|
||||||
let request = Request {
|
let request = Request {
|
||||||
params: Params::default(),
|
params: Params::default(),
|
||||||
cmd: Command::ExportBitcoinWallet,
|
cmd: Command::ExportBitcoinWallet,
|
||||||
};
|
};
|
||||||
(context, request)
|
(context, request)
|
||||||
},
|
}
|
||||||
RawCommand::MoneroRecovery { swap_id } => {
|
RawCommand::MoneroRecovery { swap_id } => {
|
||||||
let context = Context::build(
|
let context =
|
||||||
None,
|
Context::build(None, None, None, data, is_testnet, debug, json, None).await?;
|
||||||
None,
|
|
||||||
None,
|
|
||||||
data,
|
|
||||||
is_testnet,
|
|
||||||
debug,
|
|
||||||
json,
|
|
||||||
None
|
|
||||||
).await?;
|
|
||||||
|
|
||||||
let request = Request {
|
let request = Request {
|
||||||
params: Params {
|
params: Params {
|
||||||
|
@ -326,7 +300,7 @@ where
|
||||||
cmd: Command::MoneroRecovery,
|
cmd: Command::MoneroRecovery,
|
||||||
};
|
};
|
||||||
(context, request)
|
(context, request)
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(ParseResult::Context(Arc::new(context), Box::new(request)))
|
Ok(ParseResult::Context(Arc::new(context), Box::new(request)))
|
||||||
|
@ -347,7 +321,6 @@ pub enum Command {
|
||||||
StartDaemon,
|
StartDaemon,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(structopt::StructOpt, Debug)]
|
#[derive(structopt::StructOpt, Debug)]
|
||||||
#[structopt(
|
#[structopt(
|
||||||
name = "swap",
|
name = "swap",
|
||||||
|
@ -443,7 +416,10 @@ enum RawCommand {
|
||||||
#[structopt(flatten)]
|
#[structopt(flatten)]
|
||||||
monero: Monero,
|
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>,
|
server_address: Option<SocketAddr>,
|
||||||
#[structopt(flatten)]
|
#[structopt(flatten)]
|
||||||
tor: Tor,
|
tor: Tor,
|
||||||
|
@ -588,7 +564,6 @@ struct Seller {
|
||||||
seller: Multiaddr,
|
seller: Multiaddr,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn bitcoin_address(address: Address, is_testnet: bool) -> Result<Address> {
|
fn bitcoin_address(address: Address, is_testnet: bool) -> Result<Address> {
|
||||||
let network = if is_testnet {
|
let network = if is_testnet {
|
||||||
bitcoin::Network::Testnet
|
bitcoin::Network::Testnet
|
||||||
|
@ -699,12 +674,16 @@ mod tests {
|
||||||
let (is_testnet, debug, json) = (false, false, false);
|
let (is_testnet, debug, json) = (false, false, false);
|
||||||
let data_dir = data_dir_path_cli(is_testnet);
|
let data_dir = data_dir_path_cli(is_testnet);
|
||||||
|
|
||||||
let (expected_context, expected_request) =
|
let (expected_context, expected_request) = (
|
||||||
(Context::default(is_testnet, data_dir, debug, json).await.unwrap(), Request::buy_xmr(is_testnet));
|
Context::default(is_testnet, data_dir, debug, json)
|
||||||
|
.await
|
||||||
|
.unwrap(),
|
||||||
|
Request::buy_xmr(is_testnet),
|
||||||
|
);
|
||||||
|
|
||||||
let (actual_context, actual_request) = match args {
|
let (actual_context, actual_request) = match args {
|
||||||
ParseResult::Context(context, request) => (context, request),
|
ParseResult::Context(context, request) => (context, request),
|
||||||
_ => panic!("Couldn't parse result")
|
_ => panic!("Couldn't parse result"),
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(actual_context, Arc::new(expected_context));
|
assert_eq!(actual_context, Arc::new(expected_context));
|
||||||
|
@ -729,12 +708,16 @@ mod tests {
|
||||||
let (is_testnet, debug, json) = (true, false, false);
|
let (is_testnet, debug, json) = (true, false, false);
|
||||||
let data_dir = data_dir_path_cli(is_testnet);
|
let data_dir = data_dir_path_cli(is_testnet);
|
||||||
|
|
||||||
let (expected_context, expected_request) =
|
let (expected_context, expected_request) = (
|
||||||
(Context::default(is_testnet, data_dir, debug, json).await.unwrap(), Request::buy_xmr(is_testnet));
|
Context::default(is_testnet, data_dir, debug, json)
|
||||||
|
.await
|
||||||
|
.unwrap(),
|
||||||
|
Request::buy_xmr(is_testnet),
|
||||||
|
);
|
||||||
|
|
||||||
let (actual_context, actual_request) = match args {
|
let (actual_context, actual_request) = match args {
|
||||||
ParseResult::Context(context, request) => (context, request),
|
ParseResult::Context(context, request) => (context, request),
|
||||||
_ => panic!("Couldn't parse result")
|
_ => panic!("Couldn't parse result"),
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(actual_context, Arc::new(expected_context));
|
assert_eq!(actual_context, Arc::new(expected_context));
|
||||||
|
@ -798,12 +781,16 @@ mod tests {
|
||||||
let (is_testnet, debug, json) = (false, false, false);
|
let (is_testnet, debug, json) = (false, false, false);
|
||||||
let data_dir = data_dir_path_cli(is_testnet);
|
let data_dir = data_dir_path_cli(is_testnet);
|
||||||
|
|
||||||
let (expected_context, expected_request) =
|
let (expected_context, expected_request) = (
|
||||||
(Context::default(is_testnet, data_dir, debug, json).await.unwrap(), Request::resume());
|
Context::default(is_testnet, data_dir, debug, json)
|
||||||
|
.await
|
||||||
|
.unwrap(),
|
||||||
|
Request::resume(),
|
||||||
|
);
|
||||||
|
|
||||||
let (actual_context, actual_request) = match args {
|
let (actual_context, actual_request) = match args {
|
||||||
ParseResult::Context(context, request) => (context, request),
|
ParseResult::Context(context, request) => (context, request),
|
||||||
_ => panic!("Couldn't parse result")
|
_ => panic!("Couldn't parse result"),
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(actual_context, Arc::new(expected_context));
|
assert_eq!(actual_context, Arc::new(expected_context));
|
||||||
|
@ -818,12 +805,16 @@ mod tests {
|
||||||
let (is_testnet, debug, json) = (true, false, false);
|
let (is_testnet, debug, json) = (true, false, false);
|
||||||
let data_dir = data_dir_path_cli(is_testnet);
|
let data_dir = data_dir_path_cli(is_testnet);
|
||||||
|
|
||||||
let (expected_context, expected_request) =
|
let (expected_context, expected_request) = (
|
||||||
(Context::default(is_testnet, data_dir, debug, json).await.unwrap(), Request::resume());
|
Context::default(is_testnet, data_dir, debug, json)
|
||||||
|
.await
|
||||||
|
.unwrap(),
|
||||||
|
Request::resume(),
|
||||||
|
);
|
||||||
|
|
||||||
let (actual_context, actual_request) = match args {
|
let (actual_context, actual_request) = match args {
|
||||||
ParseResult::Context(context, request) => (context, request),
|
ParseResult::Context(context, request) => (context, request),
|
||||||
_ => panic!("Couldn't parse result")
|
_ => panic!("Couldn't parse result"),
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(actual_context, Arc::new(expected_context));
|
assert_eq!(actual_context, Arc::new(expected_context));
|
||||||
|
@ -839,12 +830,16 @@ mod tests {
|
||||||
let (is_testnet, debug, json) = (false, false, false);
|
let (is_testnet, debug, json) = (false, false, false);
|
||||||
let data_dir = data_dir_path_cli(is_testnet);
|
let data_dir = data_dir_path_cli(is_testnet);
|
||||||
|
|
||||||
let (expected_context, expected_request) =
|
let (expected_context, expected_request) = (
|
||||||
(Context::default(is_testnet, data_dir, debug, json).await.unwrap(), Request::cancel());
|
Context::default(is_testnet, data_dir, debug, json)
|
||||||
|
.await
|
||||||
|
.unwrap(),
|
||||||
|
Request::cancel(),
|
||||||
|
);
|
||||||
|
|
||||||
let (actual_context, actual_request) = match args {
|
let (actual_context, actual_request) = match args {
|
||||||
ParseResult::Context(context, request) => (context, request),
|
ParseResult::Context(context, request) => (context, request),
|
||||||
_ => panic!("Couldn't parse result")
|
_ => panic!("Couldn't parse result"),
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(actual_context, Arc::new(expected_context));
|
assert_eq!(actual_context, Arc::new(expected_context));
|
||||||
|
@ -859,12 +854,16 @@ mod tests {
|
||||||
let (is_testnet, debug, json) = (true, false, false);
|
let (is_testnet, debug, json) = (true, false, false);
|
||||||
let data_dir = data_dir_path_cli(is_testnet);
|
let data_dir = data_dir_path_cli(is_testnet);
|
||||||
|
|
||||||
let (expected_context, expected_request) =
|
let (expected_context, expected_request) = (
|
||||||
(Context::default(is_testnet, data_dir, debug, json).await.unwrap(), Request::cancel());
|
Context::default(is_testnet, data_dir, debug, json)
|
||||||
|
.await
|
||||||
|
.unwrap(),
|
||||||
|
Request::cancel(),
|
||||||
|
);
|
||||||
|
|
||||||
let (actual_context, actual_request) = match args {
|
let (actual_context, actual_request) = match args {
|
||||||
ParseResult::Context(context, request) => (context, request),
|
ParseResult::Context(context, request) => (context, request),
|
||||||
_ => panic!("Couldn't parse result")
|
_ => panic!("Couldn't parse result"),
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(actual_context, Arc::new(expected_context));
|
assert_eq!(actual_context, Arc::new(expected_context));
|
||||||
|
@ -879,12 +878,16 @@ mod tests {
|
||||||
let (is_testnet, debug, json) = (false, false, false);
|
let (is_testnet, debug, json) = (false, false, false);
|
||||||
let data_dir = data_dir_path_cli(is_testnet);
|
let data_dir = data_dir_path_cli(is_testnet);
|
||||||
|
|
||||||
let (expected_context, expected_request) =
|
let (expected_context, expected_request) = (
|
||||||
(Context::default(is_testnet, data_dir, debug, json).await.unwrap(), Request::refund());
|
Context::default(is_testnet, data_dir, debug, json)
|
||||||
|
.await
|
||||||
|
.unwrap(),
|
||||||
|
Request::refund(),
|
||||||
|
);
|
||||||
|
|
||||||
let (actual_context, actual_request) = match args {
|
let (actual_context, actual_request) = match args {
|
||||||
ParseResult::Context(context, request) => (context, request),
|
ParseResult::Context(context, request) => (context, request),
|
||||||
_ => panic!("Couldn't parse result")
|
_ => panic!("Couldn't parse result"),
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(actual_context, Arc::new(expected_context));
|
assert_eq!(actual_context, Arc::new(expected_context));
|
||||||
|
@ -899,12 +902,16 @@ mod tests {
|
||||||
let (is_testnet, debug, json) = (true, false, false);
|
let (is_testnet, debug, json) = (true, false, false);
|
||||||
let data_dir = data_dir_path_cli(is_testnet);
|
let data_dir = data_dir_path_cli(is_testnet);
|
||||||
|
|
||||||
let (expected_context, expected_request) =
|
let (expected_context, expected_request) = (
|
||||||
(Context::default(is_testnet, data_dir, debug, json).await.unwrap(), Request::refund());
|
Context::default(is_testnet, data_dir, debug, json)
|
||||||
|
.await
|
||||||
|
.unwrap(),
|
||||||
|
Request::refund(),
|
||||||
|
);
|
||||||
|
|
||||||
let (actual_context, actual_request) = match args {
|
let (actual_context, actual_request) = match args {
|
||||||
ParseResult::Context(context, request) => (context, request),
|
ParseResult::Context(context, request) => (context, request),
|
||||||
_ => panic!("Couldn't parse result")
|
_ => panic!("Couldn't parse result"),
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(actual_context, Arc::new(expected_context));
|
assert_eq!(actual_context, Arc::new(expected_context));
|
||||||
|
@ -932,12 +939,16 @@ mod tests {
|
||||||
let (is_testnet, debug, json) = (false, false, false);
|
let (is_testnet, debug, json) = (false, false, false);
|
||||||
let data_dir = PathBuf::from_str(args_data_dir).unwrap();
|
let data_dir = PathBuf::from_str(args_data_dir).unwrap();
|
||||||
|
|
||||||
let (expected_context, expected_request) =
|
let (expected_context, expected_request) = (
|
||||||
(Context::default(is_testnet, data_dir.clone(), debug, json).await.unwrap(), Request::buy_xmr(is_testnet));
|
Context::default(is_testnet, data_dir.clone(), debug, json)
|
||||||
|
.await
|
||||||
|
.unwrap(),
|
||||||
|
Request::buy_xmr(is_testnet),
|
||||||
|
);
|
||||||
|
|
||||||
let (actual_context, actual_request) = match args {
|
let (actual_context, actual_request) = match args {
|
||||||
ParseResult::Context(context, request) => (context, request),
|
ParseResult::Context(context, request) => (context, request),
|
||||||
_ => panic!("Couldn't parse result")
|
_ => panic!("Couldn't parse result"),
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(actual_context, Arc::new(expected_context));
|
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 args = parse_args_and_apply_defaults(raw_ars).await.unwrap();
|
||||||
let (is_testnet, debug, json) = (true, false, false);
|
let (is_testnet, debug, json) = (true, false, false);
|
||||||
|
|
||||||
let (expected_context, expected_request) =
|
let (expected_context, expected_request) = (
|
||||||
(Context::default(is_testnet, data_dir.clone(), debug, json).await.unwrap(), Request::buy_xmr(is_testnet));
|
Context::default(is_testnet, data_dir.clone(), debug, json)
|
||||||
|
.await
|
||||||
|
.unwrap(),
|
||||||
|
Request::buy_xmr(is_testnet),
|
||||||
|
);
|
||||||
|
|
||||||
let (actual_context, actual_request) = match args {
|
let (actual_context, actual_request) = match args {
|
||||||
ParseResult::Context(context, request) => (context, request),
|
ParseResult::Context(context, request) => (context, request),
|
||||||
_ => panic!("Couldn't parse result")
|
_ => panic!("Couldn't parse result"),
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(actual_context, Arc::new(expected_context));
|
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 args = parse_args_and_apply_defaults(raw_ars).await.unwrap();
|
||||||
let (is_testnet, debug, json) = (false, false, false);
|
let (is_testnet, debug, json) = (false, false, false);
|
||||||
|
|
||||||
let (expected_context, expected_request) =
|
let (expected_context, expected_request) = (
|
||||||
(Context::default(is_testnet, data_dir.clone(), debug, json).await.unwrap(), Request::resume());
|
Context::default(is_testnet, data_dir.clone(), debug, json)
|
||||||
|
.await
|
||||||
|
.unwrap(),
|
||||||
|
Request::resume(),
|
||||||
|
);
|
||||||
|
|
||||||
let (actual_context, actual_request) = match args {
|
let (actual_context, actual_request) = match args {
|
||||||
ParseResult::Context(context, request) => (context, request),
|
ParseResult::Context(context, request) => (context, request),
|
||||||
_ => panic!("Couldn't parse result")
|
_ => panic!("Couldn't parse result"),
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(actual_context, Arc::new(expected_context));
|
assert_eq!(actual_context, Arc::new(expected_context));
|
||||||
|
@ -1004,17 +1023,19 @@ mod tests {
|
||||||
SWAP_ID,
|
SWAP_ID,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
let args = parse_args_and_apply_defaults(raw_ars).await.unwrap();
|
let args = parse_args_and_apply_defaults(raw_ars).await.unwrap();
|
||||||
let (is_testnet, debug, json) = (true, false, false);
|
let (is_testnet, debug, json) = (true, false, false);
|
||||||
|
|
||||||
let (expected_context, expected_request) =
|
let (expected_context, expected_request) = (
|
||||||
(Context::default(is_testnet, data_dir.clone(), debug, json).await.unwrap(), Request::resume());
|
Context::default(is_testnet, data_dir.clone(), debug, json)
|
||||||
|
.await
|
||||||
|
.unwrap(),
|
||||||
|
Request::resume(),
|
||||||
|
);
|
||||||
|
|
||||||
let (actual_context, actual_request) = match args {
|
let (actual_context, actual_request) = match args {
|
||||||
ParseResult::Context(context, request) => (context, request),
|
ParseResult::Context(context, request) => (context, request),
|
||||||
_ => panic!("Couldn't parse result")
|
_ => panic!("Couldn't parse result"),
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(actual_context, Arc::new(expected_context));
|
assert_eq!(actual_context, Arc::new(expected_context));
|
||||||
|
@ -1039,12 +1060,16 @@ mod tests {
|
||||||
let (is_testnet, debug, json) = (false, true, false);
|
let (is_testnet, debug, json) = (false, true, false);
|
||||||
let data_dir = data_dir_path_cli(is_testnet);
|
let data_dir = data_dir_path_cli(is_testnet);
|
||||||
|
|
||||||
let (expected_context, expected_request) =
|
let (expected_context, expected_request) = (
|
||||||
(Context::default(is_testnet, data_dir, debug, json).await.unwrap(), Request::buy_xmr(is_testnet));
|
Context::default(is_testnet, data_dir, debug, json)
|
||||||
|
.await
|
||||||
|
.unwrap(),
|
||||||
|
Request::buy_xmr(is_testnet),
|
||||||
|
);
|
||||||
|
|
||||||
let (actual_context, actual_request) = match args {
|
let (actual_context, actual_request) = match args {
|
||||||
ParseResult::Context(context, request) => (context, request),
|
ParseResult::Context(context, request) => (context, request),
|
||||||
_ => panic!("Couldn't parse result")
|
_ => panic!("Couldn't parse result"),
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(actual_context, Arc::new(expected_context));
|
assert_eq!(actual_context, Arc::new(expected_context));
|
||||||
|
@ -1067,12 +1092,16 @@ mod tests {
|
||||||
let (is_testnet, debug, json) = (true, true, false);
|
let (is_testnet, debug, json) = (true, true, false);
|
||||||
let data_dir = data_dir_path_cli(is_testnet);
|
let data_dir = data_dir_path_cli(is_testnet);
|
||||||
|
|
||||||
let (expected_context, expected_request) =
|
let (expected_context, expected_request) = (
|
||||||
(Context::default(is_testnet, data_dir, debug, json).await.unwrap(), Request::buy_xmr(is_testnet));
|
Context::default(is_testnet, data_dir, debug, json)
|
||||||
|
.await
|
||||||
|
.unwrap(),
|
||||||
|
Request::buy_xmr(is_testnet),
|
||||||
|
);
|
||||||
|
|
||||||
let (actual_context, actual_request) = match args {
|
let (actual_context, actual_request) = match args {
|
||||||
ParseResult::Context(context, request) => (context, request),
|
ParseResult::Context(context, request) => (context, request),
|
||||||
_ => panic!("Couldn't parse result")
|
_ => panic!("Couldn't parse result"),
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(actual_context, Arc::new(expected_context));
|
assert_eq!(actual_context, Arc::new(expected_context));
|
||||||
|
@ -1084,12 +1113,16 @@ mod tests {
|
||||||
let (is_testnet, debug, json) = (false, true, false);
|
let (is_testnet, debug, json) = (false, true, false);
|
||||||
let data_dir = data_dir_path_cli(is_testnet);
|
let data_dir = data_dir_path_cli(is_testnet);
|
||||||
|
|
||||||
let (expected_context, expected_request) =
|
let (expected_context, expected_request) = (
|
||||||
(Context::default(is_testnet, data_dir, debug, json).await.unwrap(), Request::resume());
|
Context::default(is_testnet, data_dir, debug, json)
|
||||||
|
.await
|
||||||
|
.unwrap(),
|
||||||
|
Request::resume(),
|
||||||
|
);
|
||||||
|
|
||||||
let (actual_context, actual_request) = match args {
|
let (actual_context, actual_request) = match args {
|
||||||
ParseResult::Context(context, request) => (context, request),
|
ParseResult::Context(context, request) => (context, request),
|
||||||
_ => panic!("Couldn't parse result")
|
_ => panic!("Couldn't parse result"),
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(actual_context, Arc::new(expected_context));
|
assert_eq!(actual_context, Arc::new(expected_context));
|
||||||
|
@ -1108,12 +1141,16 @@ mod tests {
|
||||||
let (is_testnet, debug, json) = (true, true, false);
|
let (is_testnet, debug, json) = (true, true, false);
|
||||||
let data_dir = data_dir_path_cli(is_testnet);
|
let data_dir = data_dir_path_cli(is_testnet);
|
||||||
|
|
||||||
let (expected_context, expected_request) =
|
let (expected_context, expected_request) = (
|
||||||
(Context::default(is_testnet, data_dir, debug, json).await.unwrap(), Request::resume());
|
Context::default(is_testnet, data_dir, debug, json)
|
||||||
|
.await
|
||||||
|
.unwrap(),
|
||||||
|
Request::resume(),
|
||||||
|
);
|
||||||
|
|
||||||
let (actual_context, actual_request) = match args {
|
let (actual_context, actual_request) = match args {
|
||||||
ParseResult::Context(context, request) => (context, request),
|
ParseResult::Context(context, request) => (context, request),
|
||||||
_ => panic!("Couldn't parse result")
|
_ => panic!("Couldn't parse result"),
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(actual_context, Arc::new(expected_context));
|
assert_eq!(actual_context, Arc::new(expected_context));
|
||||||
|
@ -1138,12 +1175,16 @@ mod tests {
|
||||||
let (is_testnet, debug, json) = (false, false, true);
|
let (is_testnet, debug, json) = (false, false, true);
|
||||||
let data_dir = data_dir_path_cli(is_testnet);
|
let data_dir = data_dir_path_cli(is_testnet);
|
||||||
|
|
||||||
let (expected_context, expected_request) =
|
let (expected_context, expected_request) = (
|
||||||
(Context::default(is_testnet, data_dir, debug, json).await.unwrap(), Request::buy_xmr(is_testnet));
|
Context::default(is_testnet, data_dir, debug, json)
|
||||||
|
.await
|
||||||
|
.unwrap(),
|
||||||
|
Request::buy_xmr(is_testnet),
|
||||||
|
);
|
||||||
|
|
||||||
let (actual_context, actual_request) = match args {
|
let (actual_context, actual_request) = match args {
|
||||||
ParseResult::Context(context, request) => (context, request),
|
ParseResult::Context(context, request) => (context, request),
|
||||||
_ => panic!("Couldn't parse result")
|
_ => panic!("Couldn't parse result"),
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(actual_context, Arc::new(expected_context));
|
assert_eq!(actual_context, Arc::new(expected_context));
|
||||||
|
@ -1166,12 +1207,16 @@ mod tests {
|
||||||
let (is_testnet, debug, json) = (true, false, true);
|
let (is_testnet, debug, json) = (true, false, true);
|
||||||
let data_dir = data_dir_path_cli(is_testnet);
|
let data_dir = data_dir_path_cli(is_testnet);
|
||||||
|
|
||||||
let (expected_context, expected_request) =
|
let (expected_context, expected_request) = (
|
||||||
(Context::default(is_testnet, data_dir, debug, json).await.unwrap(), Request::buy_xmr(is_testnet));
|
Context::default(is_testnet, data_dir, debug, json)
|
||||||
|
.await
|
||||||
|
.unwrap(),
|
||||||
|
Request::buy_xmr(is_testnet),
|
||||||
|
);
|
||||||
|
|
||||||
let (actual_context, actual_request) = match args {
|
let (actual_context, actual_request) = match args {
|
||||||
ParseResult::Context(context, request) => (context, request),
|
ParseResult::Context(context, request) => (context, request),
|
||||||
_ => panic!("Couldn't parse result")
|
_ => panic!("Couldn't parse result"),
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(actual_context, Arc::new(expected_context));
|
assert_eq!(actual_context, Arc::new(expected_context));
|
||||||
|
@ -1182,12 +1227,16 @@ mod tests {
|
||||||
let (is_testnet, debug, json) = (false, false, true);
|
let (is_testnet, debug, json) = (false, false, true);
|
||||||
let data_dir = data_dir_path_cli(is_testnet);
|
let data_dir = data_dir_path_cli(is_testnet);
|
||||||
|
|
||||||
let (expected_context, expected_request) =
|
let (expected_context, expected_request) = (
|
||||||
(Context::default(is_testnet, data_dir, debug, json).await.unwrap(), Request::resume());
|
Context::default(is_testnet, data_dir, debug, json)
|
||||||
|
.await
|
||||||
|
.unwrap(),
|
||||||
|
Request::resume(),
|
||||||
|
);
|
||||||
|
|
||||||
let (actual_context, actual_request) = match args {
|
let (actual_context, actual_request) = match args {
|
||||||
ParseResult::Context(context, request) => (context, request),
|
ParseResult::Context(context, request) => (context, request),
|
||||||
_ => panic!("Couldn't parse result")
|
_ => panic!("Couldn't parse result"),
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(actual_context, Arc::new(expected_context));
|
assert_eq!(actual_context, Arc::new(expected_context));
|
||||||
|
@ -1206,12 +1255,16 @@ mod tests {
|
||||||
let (is_testnet, debug, json) = (true, false, true);
|
let (is_testnet, debug, json) = (true, false, true);
|
||||||
let data_dir = data_dir_path_cli(is_testnet);
|
let data_dir = data_dir_path_cli(is_testnet);
|
||||||
|
|
||||||
let (expected_context, expected_request) =
|
let (expected_context, expected_request) = (
|
||||||
(Context::default(is_testnet, data_dir, debug, json).await.unwrap(), Request::resume());
|
Context::default(is_testnet, data_dir, debug, json)
|
||||||
|
.await
|
||||||
|
.unwrap(),
|
||||||
|
Request::resume(),
|
||||||
|
);
|
||||||
|
|
||||||
let (actual_context, actual_request) = match args {
|
let (actual_context, actual_request) = match args {
|
||||||
ParseResult::Context(context, request) => (context, request),
|
ParseResult::Context(context, request) => (context, request),
|
||||||
_ => panic!("Couldn't parse result")
|
_ => panic!("Couldn't parse result"),
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(actual_context, Arc::new(expected_context));
|
assert_eq!(actual_context, Arc::new(expected_context));
|
||||||
|
|
|
@ -6,6 +6,7 @@ use async_trait::async_trait;
|
||||||
use libp2p::{Multiaddr, PeerId};
|
use libp2p::{Multiaddr, PeerId};
|
||||||
use sqlx::sqlite::Sqlite;
|
use sqlx::sqlite::Sqlite;
|
||||||
use sqlx::{Pool, SqlitePool};
|
use sqlx::{Pool, SqlitePool};
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use time::OffsetDateTime;
|
use time::OffsetDateTime;
|
||||||
|
@ -149,7 +150,7 @@ impl Database for SqliteDatabase {
|
||||||
|
|
||||||
let rows = sqlx::query!(
|
let rows = sqlx::query!(
|
||||||
r#"
|
r#"
|
||||||
SELECT address
|
SELECT DISTINCT address
|
||||||
FROM peer_addresses
|
FROM peer_addresses
|
||||||
WHERE peer_id = ?
|
WHERE peer_id = ?
|
||||||
"#,
|
"#,
|
||||||
|
@ -169,6 +170,24 @@ impl Database for SqliteDatabase {
|
||||||
addresses
|
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<()> {
|
async fn insert_latest_state(&self, swap_id: Uuid, state: State) -> Result<()> {
|
||||||
let mut conn = self.pool.acquire().await?;
|
let mut conn = self.pool.acquire().await?;
|
||||||
let entered_at = OffsetDateTime::now_utc();
|
let entered_at = OffsetDateTime::now_utc();
|
||||||
|
@ -249,6 +268,33 @@ impl Database for SqliteDatabase {
|
||||||
|
|
||||||
result
|
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)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
missing_copy_implementations
|
missing_copy_implementations
|
||||||
)]
|
)]
|
||||||
|
|
||||||
|
pub mod api;
|
||||||
pub mod asb;
|
pub mod asb;
|
||||||
pub mod bitcoin;
|
pub mod bitcoin;
|
||||||
pub mod cli;
|
pub mod cli;
|
||||||
|
@ -24,7 +25,6 @@ pub mod database;
|
||||||
pub mod env;
|
pub mod env;
|
||||||
pub mod fs;
|
pub mod fs;
|
||||||
pub mod kraken;
|
pub mod kraken;
|
||||||
pub mod api;
|
|
||||||
pub mod libp2p_ext;
|
pub mod libp2p_ext;
|
||||||
pub mod monero;
|
pub mod monero;
|
||||||
pub mod network;
|
pub mod network;
|
||||||
|
|
|
@ -11,6 +11,7 @@ use serde::{Deserialize, Serialize};
|
||||||
use sha2::Sha256;
|
use sha2::Sha256;
|
||||||
use sigma_fun::ext::dl_secp256k1_ed25519_eq::{CrossCurveDLEQ, CrossCurveDLEQProof};
|
use sigma_fun::ext::dl_secp256k1_ed25519_eq::{CrossCurveDLEQ, CrossCurveDLEQProof};
|
||||||
use sigma_fun::HashTranscript;
|
use sigma_fun::HashTranscript;
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
@ -139,7 +140,9 @@ pub trait Database {
|
||||||
async fn get_monero_address(&self, swap_id: Uuid) -> Result<monero::Address>;
|
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 insert_address(&self, peer_id: PeerId, address: Multiaddr) -> Result<()>;
|
||||||
async fn get_addresses(&self, peer_id: PeerId) -> Result<Vec<Multiaddr>>;
|
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 insert_latest_state(&self, swap_id: Uuid, state: State) -> Result<()>;
|
||||||
async fn get_state(&self, swap_id: Uuid) -> Result<State>;
|
async fn get_state(&self, swap_id: Uuid) -> Result<State>;
|
||||||
async fn all(&self) -> Result<Vec<(Uuid, State)>>;
|
async fn all(&self) -> Result<Vec<(Uuid, State)>>;
|
||||||
|
async fn raw_all(&self) -> Result<HashMap<Uuid, Vec<serde_json::Value>>>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
|
use crate::api::Context;
|
||||||
|
use jsonrpsee::http_server::{HttpServerBuilder, HttpServerHandle, RpcModule};
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
use jsonrpsee::http_server::{RpcModule, HttpServerBuilder, HttpServerHandle};
|
|
||||||
use thiserror::Error;
|
|
||||||
use crate::api::{Context};
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
pub mod methods;
|
pub mod methods;
|
||||||
|
|
||||||
|
@ -12,11 +12,15 @@ pub enum Error {
|
||||||
ExampleError,
|
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 server = HttpServerBuilder::default().build(server_address).await?;
|
||||||
let mut modules = RpcModule::new(());
|
let mut modules = RpcModule::new(());
|
||||||
{
|
{
|
||||||
modules.merge(methods::register_modules(Arc::clone(&context)))
|
modules
|
||||||
|
.merge(methods::register_modules(Arc::clone(&context)))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,4 +30,3 @@ pub async fn run_server(server_address: SocketAddr, context: Arc<Context>) -> an
|
||||||
|
|
||||||
Ok((addr, server_handle))
|
Ok((addr, server_handle))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,66 +1,164 @@
|
||||||
use jsonrpsee::http_server::{RpcModule};
|
use crate::api::{Context, Params, Request};
|
||||||
use crate::api::{Request, Context, Params};
|
use crate::cli::command::Command;
|
||||||
use crate::cli::command::{Command};
|
|
||||||
use std::str::FromStr;
|
|
||||||
use crate::rpc::Error;
|
use crate::rpc::Error;
|
||||||
use crate::{bitcoin, monero};
|
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 std::sync::Arc;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
use std::collections::HashMap;
|
|
||||||
use libp2p::core::Multiaddr;
|
|
||||||
|
|
||||||
pub fn register_modules(context: Arc<Context>) -> RpcModule<Arc<Context>> {
|
pub fn register_modules(context: Arc<Context>) -> RpcModule<Arc<Context>> {
|
||||||
let mut module = RpcModule::new(context);
|
let mut module = RpcModule::new(context);
|
||||||
module
|
module
|
||||||
.register_async_method("get_bitcoin_balance", |_, context| async move {
|
.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();
|
.unwrap();
|
||||||
module
|
module
|
||||||
.register_async_method("get_history", |_, context| async move {
|
.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();
|
.unwrap();
|
||||||
module
|
module
|
||||||
.register_async_method("resume_swap", |params, context| async move {
|
.register_async_method("resume_swap", |params, context| async move {
|
||||||
let swap_id: HashMap<String, String> = params.parse()?;
|
let params: 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();
|
let swap_id = Uuid::from_str(params.get("swap_id").ok_or_else(|| {
|
||||||
resume_swap(swap_id, &context).await.map_err(|err| jsonrpsee_core::Error::Custom(err.to_string()))
|
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();
|
.unwrap();
|
||||||
module
|
module
|
||||||
.register_async_method("withdraw_btc", |params, context| async move {
|
.register_async_method("withdraw_btc", |params, context| async move {
|
||||||
let map_params: HashMap<String, String> = params.parse()?;
|
let params: HashMap<String, String> = params.parse()?;
|
||||||
let amount = if let Some(amount_str) = map_params.get("amount") {
|
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()))?)
|
Some(
|
||||||
|
::bitcoin::Amount::from_str_in(amount_str, ::bitcoin::Denomination::Bitcoin)
|
||||||
|
.map_err(|_| {
|
||||||
|
jsonrpsee_core::Error::Custom("Unable to parse amount".to_string())
|
||||||
|
})?,
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
None
|
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();
|
let withdraw_address =
|
||||||
withdraw_btc(withdraw_address, amount, &context).await.map_err(|err| jsonrpsee_core::Error::Custom(err.to_string()))
|
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();
|
.unwrap();
|
||||||
module
|
module
|
||||||
.register_async_method("buy_xmr", |params, context| async move {
|
.register_async_method("buy_xmr", |params, context| async move {
|
||||||
let map_params: HashMap<String, String> = params.parse()?;
|
let 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 bitcoin_change_address = bitcoin::Address::from_str(
|
||||||
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();
|
params.get("bitcoin_change_address").ok_or_else(|| {
|
||||||
let seller = Multiaddr::from_str(map_params.get("seller").ok_or_else(|| jsonrpsee_core::Error::Custom("Does not contain seller".to_string()))?).unwrap();
|
jsonrpsee_core::Error::Custom(
|
||||||
buy_xmr(bitcoin_change_address, monero_receive_address, seller, &context).await.map_err(|err| jsonrpsee_core::Error::Custom(err.to_string()))
|
"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();
|
.unwrap();
|
||||||
module
|
module
|
||||||
.register_async_method("list_sellers", |params, context| async move {
|
.register_async_method("list_sellers", |params, context| async move {
|
||||||
let map_params: HashMap<String, String> = params.parse()?;
|
let 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();
|
let rendezvous_point =
|
||||||
list_sellers(rendezvous_point, &context).await.map_err(|err| jsonrpsee_core::Error::Custom(err.to_string()))
|
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();
|
.unwrap();
|
||||||
module
|
module
|
||||||
}
|
}
|
||||||
|
@ -83,7 +181,10 @@ async fn get_history(context: &Arc<Context>) -> anyhow::Result<serde_json::Value
|
||||||
Ok(history)
|
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 {
|
let request = Request {
|
||||||
params: Params {
|
params: Params {
|
||||||
swap_id: Some(swap_id),
|
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();
|
let result = request.call(Arc::clone(context)).await.unwrap();
|
||||||
Ok(result)
|
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 {
|
let request = Request {
|
||||||
params: Params {
|
params: Params {
|
||||||
amount: amount,
|
amount,
|
||||||
address: Some(withdraw_address),
|
address: Some(withdraw_address),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
|
@ -108,7 +213,12 @@ async fn withdraw_btc(withdraw_address: bitcoin::Address, amount: Option<bitcoin
|
||||||
Ok(result)
|
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 {
|
let request = Request {
|
||||||
params: Params {
|
params: Params {
|
||||||
bitcoin_change_address: Some(bitcoin_change_address),
|
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)
|
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 {
|
let request = Request {
|
||||||
params: Params {
|
params: Params {
|
||||||
rendezvous_point: Some(rendezvous_point),
|
rendezvous_point: Some(rendezvous_point),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue