mirror of
https://github.com/comit-network/xmr-btc-swap.git
synced 2025-07-30 18:18:49 -04:00
wip: refactor request.rs to allow type safety
This commit is contained in:
parent
757183e857
commit
472e3a57b3
16 changed files with 955 additions and 743 deletions
15
.zed/settings.json
Normal file
15
.zed/settings.json
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
// Folder-specific settings
|
||||||
|
//
|
||||||
|
// For a full list of overridable settings, and general information on folder-specific settings,
|
||||||
|
// see the documentation: https://zed.dev/docs/configuring-zed#folder-specific-settings
|
||||||
|
{
|
||||||
|
"lsp": {
|
||||||
|
"rust-analyzer": {
|
||||||
|
"initialization_options": {
|
||||||
|
"rust": {
|
||||||
|
"analyzerTargetDir": "./src-xmr-btc-swap"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
2
src-xmr-btc-swap/Cargo.lock
generated
2
src-xmr-btc-swap/Cargo.lock
generated
|
@ -6376,6 +6376,7 @@ dependencies = [
|
||||||
"directories-next",
|
"directories-next",
|
||||||
"ecdsa_fun",
|
"ecdsa_fun",
|
||||||
"ed25519-dalek",
|
"ed25519-dalek",
|
||||||
|
"erased-serde",
|
||||||
"futures",
|
"futures",
|
||||||
"get-port",
|
"get-port",
|
||||||
"hex",
|
"hex",
|
||||||
|
@ -7629,6 +7630,7 @@ dependencies = [
|
||||||
name = "unstoppableswap-gui-rs"
|
name = "unstoppableswap-gui-rs"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
|
|
@ -1,24 +1,24 @@
|
||||||
[package]
|
[package]
|
||||||
name = "unstoppableswap-gui-rs"
|
name = "unstoppableswap-gui-rs"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
description = "A Tauri App"
|
authors = [ "you" ]
|
||||||
authors = ["you"]
|
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
description = "A Tauri App"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
name = "unstoppableswap_gui_rs_lib"
|
name = "unstoppableswap_gui_rs_lib"
|
||||||
crate-type = ["lib", "cdylib", "staticlib"]
|
crate-type = [ "lib", "cdylib", "staticlib" ]
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
tauri-build = { version = "2.0.0-beta", features = [] }
|
tauri-build = { version = "2.0.0-beta", features = [ ] }
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
tauri = { version = "2.0.0-beta", features = [] }
|
anyhow = "1"
|
||||||
tauri-plugin-shell = "2.0.0-beta"
|
|
||||||
serde = { version = "1", features = ["derive"] }
|
|
||||||
serde_json = "1"
|
|
||||||
once_cell = "1"
|
once_cell = "1"
|
||||||
swap = { path= "../swap" }
|
serde = { version = "1", features = [ "derive" ] }
|
||||||
|
serde_json = "1"
|
||||||
|
swap = { path = "../swap" }
|
||||||
|
tauri = { version = "2.0.0-beta", features = [ ] }
|
||||||
|
tauri-plugin-shell = "2.0.0-beta"
|
||||||
|
|
|
@ -1,17 +1,29 @@
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use once_cell::sync::OnceCell;
|
use once_cell::sync::OnceCell;
|
||||||
use swap::{api::{request::{Method, Request}, Context}, cli::command::{Bitcoin, Monero}};
|
use swap::{
|
||||||
|
api::{
|
||||||
|
request::{get_balance, BalanceArgs, BalanceResponse},
|
||||||
|
Context,
|
||||||
|
},
|
||||||
|
cli::command::{Bitcoin, Monero},
|
||||||
|
};
|
||||||
|
|
||||||
// Lazy load the Context
|
// Lazy load the Context
|
||||||
static CONTEXT: OnceCell<Arc<Context>> = OnceCell::new();
|
static CONTEXT: OnceCell<Arc<Context>> = OnceCell::new();
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
async fn balance() -> String {
|
async fn balance() -> Result<BalanceResponse, String> {
|
||||||
let context = CONTEXT.get().unwrap();
|
let context = CONTEXT.get().unwrap();
|
||||||
let request = Request::new(Method::Balance { force_refresh: true });
|
|
||||||
let response = request.call(context.clone()).await.unwrap();
|
get_balance(
|
||||||
response.to_string()
|
BalanceArgs {
|
||||||
|
force_refresh: true,
|
||||||
|
},
|
||||||
|
context.clone(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map_err(|e| e.to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setup<'a>(app: &'a mut tauri::App) -> Result<(), Box<dyn std::error::Error>> {
|
fn setup<'a>(app: &'a mut tauri::App) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
@ -34,7 +46,9 @@ fn setup<'a>(app: &'a mut tauri::App) -> Result<(), Box<dyn std::error::Error>>
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
CONTEXT.set(Arc::new(context)).expect("Failed to initialize cli context");
|
CONTEXT
|
||||||
|
.set(Arc::new(context))
|
||||||
|
.expect("Failed to initialize cli context");
|
||||||
});
|
});
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,17 +27,31 @@ data-encoding = "2.6"
|
||||||
dialoguer = "0.11"
|
dialoguer = "0.11"
|
||||||
digest = "0.10.7"
|
digest = "0.10.7"
|
||||||
directories-next = "2"
|
directories-next = "2"
|
||||||
ecdsa_fun = { version = "0.10", default-features = false, features = [ "libsecp_compat", "serde", "adaptor" ] }
|
ecdsa_fun = { version = "0.10", default-features = false, features = [
|
||||||
|
"libsecp_compat",
|
||||||
|
"serde",
|
||||||
|
"adaptor",
|
||||||
|
] }
|
||||||
ed25519-dalek = "1"
|
ed25519-dalek = "1"
|
||||||
|
erased-serde = "0.4.5"
|
||||||
futures = { version = "0.3", default-features = false }
|
futures = { version = "0.3", default-features = false }
|
||||||
hex = "0.4"
|
hex = "0.4"
|
||||||
|
hyper = "0.14.20"
|
||||||
itertools = "0.13"
|
itertools = "0.13"
|
||||||
jsonrpsee = { version = "0.16.2", features = [ "server" ] }
|
jsonrpsee = { version = "0.16.2", features = [ "server" ] }
|
||||||
tower-http = { version = "0.3.4", features = ["full"] }
|
|
||||||
tower = { version = "0.4.13", features = ["full"] }
|
|
||||||
hyper = "0.14.20"
|
|
||||||
jsonrpsee-core = "0.16.2"
|
jsonrpsee-core = "0.16.2"
|
||||||
libp2p = { version = "0.42.2", default-features = false, features = [ "tcp-tokio", "yamux", "mplex", "dns-tokio", "noise", "request-response", "websocket", "ping", "rendezvous", "identify" ] }
|
libp2p = { version = "0.42.2", default-features = false, features = [
|
||||||
|
"tcp-tokio",
|
||||||
|
"yamux",
|
||||||
|
"mplex",
|
||||||
|
"dns-tokio",
|
||||||
|
"noise",
|
||||||
|
"request-response",
|
||||||
|
"websocket",
|
||||||
|
"ping",
|
||||||
|
"rendezvous",
|
||||||
|
"identify",
|
||||||
|
] }
|
||||||
monero = { version = "0.12", features = [ "serde_support" ] }
|
monero = { version = "0.12", features = [ "serde_support" ] }
|
||||||
monero-rpc = { path = "../monero-rpc" }
|
monero-rpc = { path = "../monero-rpc" }
|
||||||
pem = "3.0"
|
pem = "3.0"
|
||||||
|
@ -45,7 +59,12 @@ proptest = "1"
|
||||||
qrcode = "0.14"
|
qrcode = "0.14"
|
||||||
rand = "0.8"
|
rand = "0.8"
|
||||||
rand_chacha = "0.3"
|
rand_chacha = "0.3"
|
||||||
reqwest = { version = "0.12", features = [ "http2", "rustls-tls", "stream", "socks" ], default-features = false }
|
reqwest = { version = "0.12", features = [
|
||||||
|
"http2",
|
||||||
|
"rustls-tls",
|
||||||
|
"stream",
|
||||||
|
"socks",
|
||||||
|
], default-features = false }
|
||||||
rust_decimal = { version = "1", features = [ "serde-float" ] }
|
rust_decimal = { version = "1", features = [ "serde-float" ] }
|
||||||
rust_decimal_macros = "1"
|
rust_decimal_macros = "1"
|
||||||
serde = { version = "1", features = [ "derive" ] }
|
serde = { version = "1", features = [ "derive" ] }
|
||||||
|
@ -53,22 +72,52 @@ serde_cbor = "0.11"
|
||||||
serde_json = "1"
|
serde_json = "1"
|
||||||
serde_with = { version = "1", features = [ "macros" ] }
|
serde_with = { version = "1", features = [ "macros" ] }
|
||||||
sha2 = "0.10"
|
sha2 = "0.10"
|
||||||
sigma_fun = { version = "0.7", default-features = false, features = [ "ed25519", "serde", "secp256k1", "alloc" ] }
|
sigma_fun = { version = "0.7", default-features = false, features = [
|
||||||
sqlx = { version = "0.6.3", features = [ "sqlite", "runtime-tokio-rustls", "offline" ] }
|
"ed25519",
|
||||||
|
"serde",
|
||||||
|
"secp256k1",
|
||||||
|
"alloc",
|
||||||
|
] }
|
||||||
|
sqlx = { version = "0.6.3", features = [
|
||||||
|
"sqlite",
|
||||||
|
"runtime-tokio-rustls",
|
||||||
|
"offline",
|
||||||
|
] }
|
||||||
structopt = "0.3"
|
structopt = "0.3"
|
||||||
strum = { version = "0.26", features = [ "derive" ] }
|
strum = { version = "0.26", features = [ "derive" ] }
|
||||||
thiserror = "1"
|
thiserror = "1"
|
||||||
time = "0.3"
|
time = "0.3"
|
||||||
tokio = { version = "1", features = [ "rt-multi-thread", "time", "macros", "sync", "process", "fs", "net", "parking_lot" ] }
|
tokio = { version = "1", features = [
|
||||||
|
"rt-multi-thread",
|
||||||
|
"time",
|
||||||
|
"macros",
|
||||||
|
"sync",
|
||||||
|
"process",
|
||||||
|
"fs",
|
||||||
|
"net",
|
||||||
|
"parking_lot",
|
||||||
|
] }
|
||||||
tokio-socks = "0.5"
|
tokio-socks = "0.5"
|
||||||
tokio-tungstenite = { version = "0.15", features = [ "rustls-tls" ] }
|
tokio-tungstenite = { version = "0.15", features = [ "rustls-tls" ] }
|
||||||
tokio-util = { version = "0.7", features = [ "io", "codec" ] }
|
tokio-util = { version = "0.7", features = [ "io", "codec" ] }
|
||||||
toml = "0.8"
|
toml = "0.8"
|
||||||
torut = { version = "0.2", default-features = false, features = [ "v3", "control" ] }
|
torut = { version = "0.2", default-features = false, features = [
|
||||||
|
"v3",
|
||||||
|
"control",
|
||||||
|
] }
|
||||||
|
tower = { version = "0.4.13", features = [ "full" ] }
|
||||||
|
tower-http = { version = "0.3.4", features = [ "full" ] }
|
||||||
tracing = { version = "0.1", features = [ "attributes" ] }
|
tracing = { version = "0.1", features = [ "attributes" ] }
|
||||||
tracing-appender = "0.2"
|
tracing-appender = "0.2"
|
||||||
tracing-futures = { version = "0.2", features = [ "std-future", "futures-03" ] }
|
tracing-futures = { version = "0.2", features = [ "std-future", "futures-03" ] }
|
||||||
tracing-subscriber = { version = "0.3", default-features = false, features = [ "fmt", "ansi", "env-filter", "time", "tracing-log", "json" ] }
|
tracing-subscriber = { version = "0.3", default-features = false, features = [
|
||||||
|
"fmt",
|
||||||
|
"ansi",
|
||||||
|
"env-filter",
|
||||||
|
"time",
|
||||||
|
"tracing-log",
|
||||||
|
"json",
|
||||||
|
] }
|
||||||
url = { version = "2", features = [ "serde" ] }
|
url = { version = "2", features = [ "serde" ] }
|
||||||
uuid = { version = "1.9", features = [ "serde", "v4" ] }
|
uuid = { version = "1.9", features = [ "serde", "v4" ] }
|
||||||
void = "1"
|
void = "1"
|
||||||
|
@ -96,4 +145,8 @@ testcontainers = "0.15"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
anyhow = "1"
|
anyhow = "1"
|
||||||
vergen = { version = "8.3", default-features = false, features = [ "build", "git", "git2" ] }
|
vergen = { version = "8.3", default-features = false, features = [
|
||||||
|
"build",
|
||||||
|
"git",
|
||||||
|
"git2",
|
||||||
|
] }
|
||||||
|
|
|
@ -375,6 +375,7 @@ pub mod api_test {
|
||||||
use crate::api::request::{Method, Request};
|
use crate::api::request::{Method, Request};
|
||||||
|
|
||||||
use libp2p::Multiaddr;
|
use libp2p::Multiaddr;
|
||||||
|
use request::BuyXmrArgs;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
@ -431,12 +432,12 @@ pub mod api_test {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Request::new(Method::BuyXmr {
|
Request::new(Method::BuyXmr(BuyXmrArgs {
|
||||||
seller,
|
seller,
|
||||||
bitcoin_change_address,
|
bitcoin_change_address,
|
||||||
monero_receive_address,
|
monero_receive_address,
|
||||||
swap_id: Uuid::new_v4(),
|
swap_id: Uuid::new_v4(),
|
||||||
})
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resume() -> Request {
|
pub fn resume() -> Request {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::api::Context;
|
use crate::api::Context;
|
||||||
use crate::bitcoin::{Amount, ExpiredTimelocks, TxLock};
|
use crate::bitcoin::{Amount, ExpiredTimelocks, TxLock};
|
||||||
use crate::cli::{list_sellers, EventLoop, SellerStatus};
|
use crate::cli::{list_sellers as list_sellers_impl, EventLoop, SellerStatus};
|
||||||
use crate::libp2p_ext::MultiAddrExt;
|
use crate::libp2p_ext::MultiAddrExt;
|
||||||
use crate::network::quote::{BidQuote, ZeroQuoteReceived};
|
use crate::network::quote::{BidQuote, ZeroQuoteReceived};
|
||||||
use crate::network::swarm;
|
use crate::network::swarm;
|
||||||
|
@ -11,7 +11,9 @@ use anyhow::{bail, Context as AnyContext, Result};
|
||||||
use libp2p::core::Multiaddr;
|
use libp2p::core::Multiaddr;
|
||||||
use qrcode::render::unicode;
|
use qrcode::render::unicode;
|
||||||
use qrcode::QrCode;
|
use qrcode::QrCode;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
|
use serde_json::Value as JsonValue;
|
||||||
use std::cmp::min;
|
use std::cmp::min;
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
|
@ -27,44 +29,87 @@ pub struct Request {
|
||||||
pub log_reference: Option<String>,
|
pub log_reference: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Eq, PartialEq)]
|
||||||
|
pub struct BuyXmrArgs {
|
||||||
|
pub seller: Multiaddr,
|
||||||
|
pub bitcoin_change_address: bitcoin::Address,
|
||||||
|
pub monero_receive_address: monero::Address,
|
||||||
|
pub swap_id: Uuid,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Eq, PartialEq)]
|
||||||
|
pub struct ResumeArgs {
|
||||||
|
pub swap_id: Uuid,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Eq, PartialEq)]
|
||||||
|
pub struct CancelAndRefundArgs {
|
||||||
|
pub swap_id: Uuid,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Eq, PartialEq)]
|
||||||
|
pub struct MoneroRecoveryArgs {
|
||||||
|
pub swap_id: Uuid,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
pub struct ResumeSwapResponse {
|
||||||
|
pub result: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
pub struct BalanceResponse {
|
||||||
|
pub balance: u64, // in satoshis
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
pub struct BuyXmrResponse {
|
||||||
|
pub swap_id: String,
|
||||||
|
pub quote: BidQuote, // You'll need to import or define BidQuote
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Eq, PartialEq)]
|
||||||
|
pub struct WithdrawBtcArgs {
|
||||||
|
pub amount: Option<Amount>,
|
||||||
|
pub address: bitcoin::Address,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Eq, PartialEq)]
|
||||||
|
pub struct BalanceArgs {
|
||||||
|
pub force_refresh: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Eq, PartialEq)]
|
||||||
|
pub struct ListSellersArgs {
|
||||||
|
pub rendezvous_point: Multiaddr,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Eq, PartialEq)]
|
||||||
|
pub struct StartDaemonArgs {
|
||||||
|
pub server_address: Option<SocketAddr>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Eq, PartialEq)]
|
||||||
|
pub struct GetSwapInfoArgs {
|
||||||
|
pub swap_id: Uuid,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum Method {
|
pub enum Method {
|
||||||
BuyXmr {
|
BuyXmr(BuyXmrArgs),
|
||||||
seller: Multiaddr,
|
Resume(ResumeArgs),
|
||||||
bitcoin_change_address: bitcoin::Address,
|
CancelAndRefund(CancelAndRefundArgs),
|
||||||
monero_receive_address: monero::Address,
|
MoneroRecovery(MoneroRecoveryArgs),
|
||||||
swap_id: Uuid,
|
|
||||||
},
|
|
||||||
Resume {
|
|
||||||
swap_id: Uuid,
|
|
||||||
},
|
|
||||||
CancelAndRefund {
|
|
||||||
swap_id: Uuid,
|
|
||||||
},
|
|
||||||
MoneroRecovery {
|
|
||||||
swap_id: Uuid,
|
|
||||||
},
|
|
||||||
History,
|
History,
|
||||||
Config,
|
Config,
|
||||||
WithdrawBtc {
|
WithdrawBtc(WithdrawBtcArgs),
|
||||||
amount: Option<Amount>,
|
Balance(BalanceArgs),
|
||||||
address: bitcoin::Address,
|
ListSellers(ListSellersArgs),
|
||||||
},
|
|
||||||
Balance {
|
|
||||||
force_refresh: bool,
|
|
||||||
},
|
|
||||||
ListSellers {
|
|
||||||
rendezvous_point: Multiaddr,
|
|
||||||
},
|
|
||||||
ExportBitcoinWallet,
|
ExportBitcoinWallet,
|
||||||
SuspendCurrentSwap,
|
SuspendCurrentSwap,
|
||||||
StartDaemon {
|
StartDaemon(StartDaemonArgs),
|
||||||
server_address: Option<SocketAddr>,
|
|
||||||
},
|
|
||||||
GetCurrentSwap,
|
GetCurrentSwap,
|
||||||
GetSwapInfo {
|
GetSwapInfo(GetSwapInfoArgs),
|
||||||
swap_id: Uuid,
|
|
||||||
},
|
|
||||||
GetRawStates,
|
GetRawStates,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,13 +123,13 @@ impl Method {
|
||||||
log_reference_id = field::Empty
|
log_reference_id = field::Empty
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Method::BuyXmr { swap_id, .. } => {
|
Method::BuyXmr(BuyXmrArgs { swap_id, .. }) => {
|
||||||
debug_span!("method", method_name="BuyXmr", swap_id=%swap_id, log_reference_id=field::Empty)
|
debug_span!("method", method_name="BuyXmr", swap_id=%swap_id, log_reference_id=field::Empty)
|
||||||
}
|
}
|
||||||
Method::CancelAndRefund { swap_id } => {
|
Method::CancelAndRefund(CancelAndRefundArgs { swap_id }) => {
|
||||||
debug_span!("method", method_name="CancelAndRefund", swap_id=%swap_id, log_reference_id=field::Empty)
|
debug_span!("method", method_name="CancelAndRefund", swap_id=%swap_id, log_reference_id=field::Empty)
|
||||||
}
|
}
|
||||||
Method::Resume { swap_id } => {
|
Method::Resume(ResumeArgs { swap_id }) => {
|
||||||
debug_span!("method", method_name="Resume", swap_id=%swap_id, log_reference_id=field::Empty)
|
debug_span!("method", method_name="Resume", swap_id=%swap_id, log_reference_id=field::Empty)
|
||||||
}
|
}
|
||||||
Method::Config => {
|
Method::Config => {
|
||||||
|
@ -170,24 +215,7 @@ impl Method {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Request {
|
async fn suspend_current_swap(context: Arc<Context>) -> Result<serde_json::Value> {
|
||||||
pub fn new(cmd: Method) -> Request {
|
|
||||||
Request {
|
|
||||||
cmd,
|
|
||||||
log_reference: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with_id(cmd: Method, id: Option<String>) -> Request {
|
|
||||||
Request {
|
|
||||||
cmd,
|
|
||||||
log_reference: id,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn handle_cmd(self, context: Arc<Context>) -> Result<serde_json::Value> {
|
|
||||||
match self.cmd {
|
|
||||||
Method::SuspendCurrentSwap => {
|
|
||||||
let swap_id = context.swap_lock.get_current_swap_id().await;
|
let swap_id = context.swap_lock.get_current_swap_id().await;
|
||||||
|
|
||||||
if let Some(id_value) = swap_id {
|
if let Some(id_value) = swap_id {
|
||||||
|
@ -197,8 +225,13 @@ impl Request {
|
||||||
} else {
|
} else {
|
||||||
bail!("No swap is currently running")
|
bail!("No swap is currently running")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Method::GetSwapInfo { swap_id } => {
|
|
||||||
|
async fn get_swap_info(
|
||||||
|
get_swap_info: GetSwapInfoArgs,
|
||||||
|
context: Arc<Context>,
|
||||||
|
) -> Result<serde_json::Value> {
|
||||||
|
let GetSwapInfoArgs { swap_id } = get_swap_info;
|
||||||
let bitcoin_wallet = context
|
let bitcoin_wallet = context
|
||||||
.bitcoin_wallet
|
.bitcoin_wallet
|
||||||
.as_ref()
|
.as_ref()
|
||||||
|
@ -272,9 +305,9 @@ impl Request {
|
||||||
.with_context(|| "Did not find SwapSetupCompleted state for swap")?;
|
.with_context(|| "Did not find SwapSetupCompleted state for swap")?;
|
||||||
|
|
||||||
let timelock = match swap_state {
|
let timelock = match swap_state {
|
||||||
BobState::Started { .. }
|
BobState::Started { .. } | BobState::SafelyAborted | BobState::SwapSetupCompleted(_) => {
|
||||||
| BobState::SafelyAborted
|
None
|
||||||
| BobState::SwapSetupCompleted(_) => None,
|
}
|
||||||
BobState::BtcLocked { state3: state, .. }
|
BobState::BtcLocked { state3: state, .. }
|
||||||
| BobState::XmrLockProofReceived { state, .. } => {
|
| BobState::XmrLockProofReceived { state, .. } => {
|
||||||
Some(state.expired_timelock(bitcoin_wallet).await)
|
Some(state.expired_timelock(bitcoin_wallet).await)
|
||||||
|
@ -286,9 +319,7 @@ impl Request {
|
||||||
Some(state.expired_timelock(bitcoin_wallet).await)
|
Some(state.expired_timelock(bitcoin_wallet).await)
|
||||||
}
|
}
|
||||||
BobState::BtcPunished { .. } => Some(Ok(ExpiredTimelocks::Punish)),
|
BobState::BtcPunished { .. } => Some(Ok(ExpiredTimelocks::Punish)),
|
||||||
BobState::BtcRefunded(_)
|
BobState::BtcRefunded(_) | BobState::BtcRedeemed(_) | BobState::XmrRedeemed { .. } => None,
|
||||||
| BobState::BtcRedeemed(_)
|
|
||||||
| BobState::XmrRedeemed { .. } => None,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(json!({
|
Ok(json!({
|
||||||
|
@ -309,17 +340,17 @@ impl Request {
|
||||||
"btcRefundAddress": btc_refund_address.to_string(),
|
"btcRefundAddress": btc_refund_address.to_string(),
|
||||||
"cancelTimelock": cancel_timelock,
|
"cancelTimelock": cancel_timelock,
|
||||||
"punishTimelock": punish_timelock,
|
"punishTimelock": punish_timelock,
|
||||||
// If the timelock is None, it means that the swap is in a state where the timelock is not accessible to us.
|
|
||||||
// If that is the case, we return null. Otherwise, we return the timelock.
|
|
||||||
"timelock": timelock.map(|tl| tl.map(|tl| json!(tl)).unwrap_or(json!(null))).unwrap_or(json!(null)),
|
"timelock": timelock.map(|tl| tl.map(|tl| json!(tl)).unwrap_or(json!(null))).unwrap_or(json!(null)),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
Method::BuyXmr {
|
|
||||||
|
async fn buy_xmr(buy_xmr: BuyXmrArgs, context: Arc<Context>) -> Result<serde_json::Value> {
|
||||||
|
let BuyXmrArgs {
|
||||||
seller,
|
seller,
|
||||||
bitcoin_change_address,
|
bitcoin_change_address,
|
||||||
monero_receive_address,
|
monero_receive_address,
|
||||||
swap_id,
|
swap_id,
|
||||||
} => {
|
} = buy_xmr;
|
||||||
let bitcoin_wallet = Arc::clone(
|
let bitcoin_wallet = Arc::clone(
|
||||||
context
|
context
|
||||||
.bitcoin_wallet
|
.bitcoin_wallet
|
||||||
|
@ -484,8 +515,10 @@ impl Request {
|
||||||
"swapId": swap_id.to_string(),
|
"swapId": swap_id.to_string(),
|
||||||
"quote": bid_quote,
|
"quote": bid_quote,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
Method::Resume { swap_id } => {
|
|
||||||
|
async fn resume_swap(resume: ResumeArgs, context: Arc<Context>) -> Result<serde_json::Value> {
|
||||||
|
let ResumeArgs { swap_id } = resume;
|
||||||
context.swap_lock.acquire_swap_lock(swap_id).await?;
|
context.swap_lock.acquire_swap_lock(swap_id).await?;
|
||||||
|
|
||||||
let seller_peer_id = context.db.get_peer_id(swap_id).await?;
|
let seller_peer_id = context.db.get_peer_id(swap_id).await?;
|
||||||
|
@ -509,8 +542,7 @@ impl Request {
|
||||||
),
|
),
|
||||||
(seed.clone(), context.config.namespace),
|
(seed.clone(), context.config.namespace),
|
||||||
);
|
);
|
||||||
let mut swarm =
|
let mut swarm = swarm::cli(seed.clone(), context.config.tor_socks5_port, behaviour).await?;
|
||||||
swarm::cli(seed.clone(), context.config.tor_socks5_port, 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");
|
||||||
|
@ -590,8 +622,13 @@ impl Request {
|
||||||
Ok(json!({
|
Ok(json!({
|
||||||
"result": "ok",
|
"result": "ok",
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
Method::CancelAndRefund { swap_id } => {
|
|
||||||
|
async fn cancel_and_refund(
|
||||||
|
cancel_and_refund: CancelAndRefundArgs,
|
||||||
|
context: Arc<Context>,
|
||||||
|
) -> Result<serde_json::Value> {
|
||||||
|
let CancelAndRefundArgs { swap_id } = cancel_and_refund;
|
||||||
let bitcoin_wallet = context
|
let bitcoin_wallet = context
|
||||||
.bitcoin_wallet
|
.bitcoin_wallet
|
||||||
.as_ref()
|
.as_ref()
|
||||||
|
@ -599,12 +636,8 @@ impl Request {
|
||||||
|
|
||||||
context.swap_lock.acquire_swap_lock(swap_id).await?;
|
context.swap_lock.acquire_swap_lock(swap_id).await?;
|
||||||
|
|
||||||
let state = cli::cancel_and_refund(
|
let state =
|
||||||
swap_id,
|
cli::cancel_and_refund(swap_id, Arc::clone(bitcoin_wallet), Arc::clone(&context.db)).await;
|
||||||
Arc::clone(bitcoin_wallet),
|
|
||||||
Arc::clone(&context.db),
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
|
|
||||||
context
|
context
|
||||||
.swap_lock
|
.swap_lock
|
||||||
|
@ -617,8 +650,9 @@ impl Request {
|
||||||
"result": state,
|
"result": state,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
Method::History => {
|
|
||||||
|
async fn get_history(context: Arc<Context>) -> Result<serde_json::Value> {
|
||||||
let swaps = context.db.all().await?;
|
let swaps = context.db.all().await?;
|
||||||
let mut vec: Vec<(Uuid, String)> = Vec::new();
|
let mut vec: Vec<(Uuid, String)> = Vec::new();
|
||||||
for (swap_id, state) in swaps {
|
for (swap_id, state) in swaps {
|
||||||
|
@ -627,13 +661,15 @@ impl Request {
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(json!({ "swaps": vec }))
|
Ok(json!({ "swaps": vec }))
|
||||||
}
|
}
|
||||||
Method::GetRawStates => {
|
|
||||||
|
async fn get_raw_states(context: Arc<Context>) -> Result<serde_json::Value> {
|
||||||
let raw_history = context.db.raw_all().await?;
|
let raw_history = context.db.raw_all().await?;
|
||||||
|
|
||||||
Ok(json!({ "raw_states": raw_history }))
|
Ok(json!({ "raw_states": raw_history }))
|
||||||
}
|
}
|
||||||
Method::Config => {
|
|
||||||
|
async fn get_config(context: Arc<Context>) -> Result<serde_json::Value> {
|
||||||
let data_dir_display = context.config.data_dir.display();
|
let data_dir_display = context.config.data_dir.display();
|
||||||
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), "Log files directory");
|
||||||
|
@ -649,8 +685,13 @@ impl Request {
|
||||||
"monero-wallet-rpc": format!("{}/monero", data_dir_display),
|
"monero-wallet-rpc": format!("{}/monero", data_dir_display),
|
||||||
"bitcoin_wallet": format!("{}/wallet", data_dir_display),
|
"bitcoin_wallet": format!("{}/wallet", data_dir_display),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
Method::WithdrawBtc { address, amount } => {
|
|
||||||
|
async fn withdraw_btc(
|
||||||
|
withdraw_btc: WithdrawBtcArgs,
|
||||||
|
context: Arc<Context>,
|
||||||
|
) -> Result<serde_json::Value> {
|
||||||
|
let WithdrawBtcArgs { address, amount } = withdraw_btc;
|
||||||
let bitcoin_wallet = context
|
let bitcoin_wallet = context
|
||||||
.bitcoin_wallet
|
.bitcoin_wallet
|
||||||
.as_ref()
|
.as_ref()
|
||||||
|
@ -678,13 +719,17 @@ impl Request {
|
||||||
"amount": amount.to_sat(),
|
"amount": amount.to_sat(),
|
||||||
"txid": signed_tx.txid(),
|
"txid": signed_tx.txid(),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
Method::StartDaemon { server_address } => {
|
|
||||||
|
async fn start_daemon(
|
||||||
|
start_daemon: StartDaemonArgs,
|
||||||
|
context: Arc<Context>,
|
||||||
|
) -> Result<serde_json::Value> {
|
||||||
|
let StartDaemonArgs { server_address } = start_daemon;
|
||||||
// Default to 127.0.0.1:1234
|
// Default to 127.0.0.1:1234
|
||||||
let server_address = server_address.unwrap_or("127.0.0.1:1234".parse()?);
|
let server_address = server_address.unwrap_or("127.0.0.1:1234".parse()?);
|
||||||
|
|
||||||
let (addr, server_handle) =
|
let (addr, server_handle) = rpc::run_server(server_address, Arc::clone(&context)).await?;
|
||||||
rpc::run_server(server_address, Arc::clone(&context)).await?;
|
|
||||||
|
|
||||||
tracing::info!(%addr, "Started RPC server");
|
tracing::info!(%addr, "Started RPC server");
|
||||||
|
|
||||||
|
@ -693,8 +738,10 @@ impl Request {
|
||||||
tracing::info!("Stopped RPC server");
|
tracing::info!("Stopped RPC server");
|
||||||
|
|
||||||
Ok(json!({}))
|
Ok(json!({}))
|
||||||
}
|
}
|
||||||
Method::Balance { force_refresh } => {
|
|
||||||
|
pub async fn get_balance(balance: BalanceArgs, context: Arc<Context>) -> Result<BalanceResponse> {
|
||||||
|
let BalanceArgs { force_refresh } = balance;
|
||||||
let bitcoin_wallet = context
|
let bitcoin_wallet = context
|
||||||
.bitcoin_wallet
|
.bitcoin_wallet
|
||||||
.as_ref()
|
.as_ref()
|
||||||
|
@ -718,11 +765,16 @@ impl Request {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(json!({
|
Ok(BalanceResponse {
|
||||||
"balance": bitcoin_balance.to_sat()
|
balance: bitcoin_balance.to_sat(),
|
||||||
}))
|
})
|
||||||
}
|
}
|
||||||
Method::ListSellers { rendezvous_point } => {
|
|
||||||
|
async fn list_sellers(
|
||||||
|
list_sellers: ListSellersArgs,
|
||||||
|
context: Arc<Context>,
|
||||||
|
) -> Result<serde_json::Value> {
|
||||||
|
let ListSellersArgs { rendezvous_point } = list_sellers;
|
||||||
let rendezvous_node_peer_id = rendezvous_point
|
let rendezvous_node_peer_id = rendezvous_point
|
||||||
.extract_peer_id()
|
.extract_peer_id()
|
||||||
.context("Rendezvous node address must contain peer ID")?;
|
.context("Rendezvous node address must contain peer ID")?;
|
||||||
|
@ -734,7 +786,7 @@ impl Request {
|
||||||
.context("Cannot extract seed")?
|
.context("Cannot extract seed")?
|
||||||
.derive_libp2p_identity();
|
.derive_libp2p_identity();
|
||||||
|
|
||||||
let sellers = list_sellers(
|
let sellers = list_sellers_impl(
|
||||||
rendezvous_node_peer_id,
|
rendezvous_node_peer_id,
|
||||||
rendezvous_point,
|
rendezvous_point,
|
||||||
context.config.namespace,
|
context.config.namespace,
|
||||||
|
@ -766,8 +818,9 @@ impl Request {
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(json!({ "sellers": sellers }))
|
Ok(json!({ "sellers": sellers }))
|
||||||
}
|
}
|
||||||
Method::ExportBitcoinWallet => {
|
|
||||||
|
async fn export_bitcoin_wallet(context: Arc<Context>) -> Result<serde_json::Value> {
|
||||||
let bitcoin_wallet = context
|
let bitcoin_wallet = context
|
||||||
.bitcoin_wallet
|
.bitcoin_wallet
|
||||||
.as_ref()
|
.as_ref()
|
||||||
|
@ -778,8 +831,13 @@ impl Request {
|
||||||
Ok(json!({
|
Ok(json!({
|
||||||
"descriptor": wallet_export.to_string(),
|
"descriptor": wallet_export.to_string(),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
Method::MoneroRecovery { swap_id } => {
|
|
||||||
|
async fn monero_recovery(
|
||||||
|
monero_recovery: MoneroRecoveryArgs,
|
||||||
|
context: Arc<Context>,
|
||||||
|
) -> Result<serde_json::Value> {
|
||||||
|
let MoneroRecoveryArgs { swap_id } = monero_recovery;
|
||||||
let swap_state: BobState = context.db.get_state(swap_id).await?.try_into()?;
|
let swap_state: BobState = context.db.get_state(swap_id).await?.try_into()?;
|
||||||
|
|
||||||
if let BobState::BtcRedeemed(state5) = swap_state {
|
if let BobState::BtcRedeemed(state5) = swap_state {
|
||||||
|
@ -806,14 +864,40 @@ impl Request {
|
||||||
swap_state
|
swap_state
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Method::GetCurrentSwap => Ok(json!({
|
|
||||||
|
async fn get_current_swap(context: Arc<Context>) -> Result<serde_json::Value> {
|
||||||
|
Ok(json!({
|
||||||
"swap_id": context.swap_lock.get_current_swap_id().await
|
"swap_id": context.swap_lock.get_current_swap_id().await
|
||||||
})),
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Request {
|
||||||
|
pub fn new(cmd: Method) -> Request {
|
||||||
|
Request {
|
||||||
|
cmd,
|
||||||
|
log_reference: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn call(self, context: Arc<Context>) -> Result<serde_json::Value> {
|
pub fn with_id(cmd: Method, id: Option<String>) -> Request {
|
||||||
|
Request {
|
||||||
|
cmd,
|
||||||
|
log_reference: id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn handle_cmd(self, context: Arc<Context>) -> Result<Box<dyn erased_serde::Serialize>> {
|
||||||
|
match self.cmd {
|
||||||
|
Method::Balance(args) => {
|
||||||
|
let response = get_balance(args, context).await?;
|
||||||
|
Ok(Box::new(response) as Box<dyn erased_serde::Serialize>)
|
||||||
|
}
|
||||||
|
_ => todo!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn call(self, context: Arc<Context>) -> Result<JsonValue> {
|
||||||
let method_span = self.cmd.get_tracing_span(self.log_reference.clone());
|
let method_span = self.cmd.get_tracing_span(self.log_reference.clone());
|
||||||
|
|
||||||
self.handle_cmd(context)
|
self.handle_cmd(context)
|
||||||
|
@ -826,6 +910,7 @@ impl Request {
|
||||||
});
|
});
|
||||||
err
|
err
|
||||||
})
|
})
|
||||||
|
.map(|result| json!(result))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,9 +12,12 @@
|
||||||
#![forbid(unsafe_code)]
|
#![forbid(unsafe_code)]
|
||||||
#![allow(non_snake_case)]
|
#![allow(non_snake_case)]
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
cli::command::{parse_args_and_apply_defaults, ParseResult},
|
||||||
|
common::check_latest_version,
|
||||||
|
};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use std::env;
|
use std::env;
|
||||||
use crate::{cli::command::{parse_args_and_apply_defaults, ParseResult}, common::check_latest_version};
|
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
pub async fn main() -> Result<()> {
|
pub async fn main() -> Result<()> {
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
use crate::api::request::{Method, Request};
|
use crate::api::request::{
|
||||||
|
BalanceArgs, BuyXmrArgs, CancelAndRefundArgs, ListSellersArgs, Method, MoneroRecoveryArgs,
|
||||||
|
Request, ResumeArgs, StartDaemonArgs, WithdrawBtcArgs,
|
||||||
|
};
|
||||||
use crate::api::Context;
|
use crate::api::Context;
|
||||||
use crate::bitcoin::{bitcoin_address, Amount};
|
use crate::bitcoin::{bitcoin_address, Amount};
|
||||||
use crate::monero;
|
use crate::monero;
|
||||||
|
@ -74,12 +77,12 @@ where
|
||||||
let bitcoin_change_address =
|
let bitcoin_change_address =
|
||||||
bitcoin_address::validate_is_testnet(bitcoin_change_address, is_testnet)?;
|
bitcoin_address::validate_is_testnet(bitcoin_change_address, is_testnet)?;
|
||||||
|
|
||||||
let request = Request::new(Method::BuyXmr {
|
let request = Request::new(Method::BuyXmr(BuyXmrArgs {
|
||||||
seller,
|
seller,
|
||||||
bitcoin_change_address,
|
bitcoin_change_address,
|
||||||
monero_receive_address,
|
monero_receive_address,
|
||||||
swap_id: Uuid::new_v4(),
|
swap_id: Uuid::new_v4(),
|
||||||
});
|
}));
|
||||||
|
|
||||||
let context = Context::build(
|
let context = Context::build(
|
||||||
Some(bitcoin),
|
Some(bitcoin),
|
||||||
|
@ -109,9 +112,9 @@ where
|
||||||
(context, request)
|
(context, request)
|
||||||
}
|
}
|
||||||
CliCommand::Balance { bitcoin } => {
|
CliCommand::Balance { bitcoin } => {
|
||||||
let request = Request::new(Method::Balance {
|
let request = Request::new(Method::Balance(BalanceArgs {
|
||||||
force_refresh: true,
|
force_refresh: true,
|
||||||
});
|
}));
|
||||||
|
|
||||||
let context = Context::build(
|
let context = Context::build(
|
||||||
Some(bitcoin),
|
Some(bitcoin),
|
||||||
|
@ -132,7 +135,7 @@ where
|
||||||
monero,
|
monero,
|
||||||
tor,
|
tor,
|
||||||
} => {
|
} => {
|
||||||
let request = Request::new(Method::StartDaemon { server_address });
|
let request = Request::new(Method::StartDaemon(StartDaemonArgs { server_address }));
|
||||||
|
|
||||||
let context = Context::build(
|
let context = Context::build(
|
||||||
Some(bitcoin),
|
Some(bitcoin),
|
||||||
|
@ -153,7 +156,7 @@ where
|
||||||
address,
|
address,
|
||||||
} => {
|
} => {
|
||||||
let address = bitcoin_address::validate_is_testnet(address, is_testnet)?;
|
let address = bitcoin_address::validate_is_testnet(address, is_testnet)?;
|
||||||
let request = Request::new(Method::WithdrawBtc { amount, address });
|
let request = Request::new(Method::WithdrawBtc(WithdrawBtcArgs { amount, address }));
|
||||||
|
|
||||||
let context = Context::build(
|
let context = Context::build(
|
||||||
Some(bitcoin),
|
Some(bitcoin),
|
||||||
|
@ -174,7 +177,7 @@ where
|
||||||
monero,
|
monero,
|
||||||
tor,
|
tor,
|
||||||
} => {
|
} => {
|
||||||
let request = Request::new(Method::Resume { swap_id });
|
let request = Request::new(Method::Resume(ResumeArgs { swap_id }));
|
||||||
|
|
||||||
let context = Context::build(
|
let context = Context::build(
|
||||||
Some(bitcoin),
|
Some(bitcoin),
|
||||||
|
@ -194,7 +197,7 @@ where
|
||||||
bitcoin,
|
bitcoin,
|
||||||
tor,
|
tor,
|
||||||
} => {
|
} => {
|
||||||
let request = Request::new(Method::CancelAndRefund { swap_id });
|
let request = Request::new(Method::CancelAndRefund(CancelAndRefundArgs { swap_id }));
|
||||||
|
|
||||||
let context = Context::build(
|
let context = Context::build(
|
||||||
Some(bitcoin),
|
Some(bitcoin),
|
||||||
|
@ -213,7 +216,7 @@ where
|
||||||
rendezvous_point,
|
rendezvous_point,
|
||||||
tor,
|
tor,
|
||||||
} => {
|
} => {
|
||||||
let request = Request::new(Method::ListSellers { rendezvous_point });
|
let request = Request::new(Method::ListSellers(ListSellersArgs { rendezvous_point }));
|
||||||
|
|
||||||
let context =
|
let context =
|
||||||
Context::build(None, None, Some(tor), data, is_testnet, debug, json, None).await?;
|
Context::build(None, None, Some(tor), data, is_testnet, debug, json, None).await?;
|
||||||
|
@ -239,7 +242,7 @@ where
|
||||||
CliCommand::MoneroRecovery {
|
CliCommand::MoneroRecovery {
|
||||||
swap_id: SwapId { swap_id },
|
swap_id: SwapId { swap_id },
|
||||||
} => {
|
} => {
|
||||||
let request = Request::new(Method::MoneroRecovery { swap_id });
|
let request = Request::new(Method::MoneroRecovery(MoneroRecoveryArgs { swap_id }));
|
||||||
|
|
||||||
let context =
|
let context =
|
||||||
Context::build(None, None, None, data, is_testnet, debug, json, None).await?;
|
Context::build(None, None, None, data, is_testnet, debug, json, None).await?;
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
|
|
||||||
pub mod api;
|
pub mod api;
|
||||||
pub mod asb;
|
pub mod asb;
|
||||||
|
pub mod bin;
|
||||||
pub mod bitcoin;
|
pub mod bitcoin;
|
||||||
pub mod cli;
|
pub mod cli;
|
||||||
pub mod common;
|
pub mod common;
|
||||||
|
@ -27,14 +28,13 @@ pub mod fs;
|
||||||
pub mod kraken;
|
pub mod kraken;
|
||||||
pub mod libp2p_ext;
|
pub mod libp2p_ext;
|
||||||
pub mod monero;
|
pub mod monero;
|
||||||
|
mod monero_ext;
|
||||||
pub mod network;
|
pub mod network;
|
||||||
pub mod protocol;
|
pub mod protocol;
|
||||||
pub mod rpc;
|
pub mod rpc;
|
||||||
pub mod seed;
|
pub mod seed;
|
||||||
pub mod tor;
|
pub mod tor;
|
||||||
pub mod tracing_ext;
|
pub mod tracing_ext;
|
||||||
pub mod bin;
|
|
||||||
mod monero_ext;
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod proptest;
|
mod proptest;
|
||||||
|
|
|
@ -338,12 +338,18 @@ async fn next_state(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(Rejected { reason, .. }) => {
|
Ok(Rejected { reason, .. }) => {
|
||||||
tracing::error!(?reason, "Alice rejected our request for cooperative XMR redeem");
|
tracing::error!(
|
||||||
|
?reason,
|
||||||
|
"Alice rejected our request for cooperative XMR redeem"
|
||||||
|
);
|
||||||
return Err(reason)
|
return Err(reason)
|
||||||
.context("Alice rejected our request for cooperative XMR redeem");
|
.context("Alice rejected our request for cooperative XMR redeem");
|
||||||
}
|
}
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
tracing::error!(?error, "Failed to request cooperative XMR redeem from Alice");
|
tracing::error!(
|
||||||
|
?error,
|
||||||
|
"Failed to request cooperative XMR redeem from Alice"
|
||||||
|
);
|
||||||
return Err(error)
|
return Err(error)
|
||||||
.context("Failed to request cooperative XMR redeem from Alice");
|
.context("Failed to request cooperative XMR redeem from Alice");
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::api::Context;
|
use crate::api::Context;
|
||||||
use std::{net::SocketAddr, sync::Arc};
|
use std::{net::SocketAddr, sync::Arc};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use tower_http::cors::{Any, CorsLayer};
|
use tower_http::cors::CorsLayer;
|
||||||
|
|
||||||
use jsonrpsee::{
|
use jsonrpsee::{
|
||||||
core::server::host_filtering::AllowHosts,
|
core::server::host_filtering::AllowHosts,
|
||||||
|
@ -23,8 +23,11 @@ pub async fn run_server(
|
||||||
let cors = CorsLayer::permissive();
|
let cors = CorsLayer::permissive();
|
||||||
let middleware = tower::ServiceBuilder::new().layer(cors);
|
let middleware = tower::ServiceBuilder::new().layer(cors);
|
||||||
|
|
||||||
let server = ServerBuilder::default().set_host_filtering(AllowHosts::Any)
|
let server = ServerBuilder::default()
|
||||||
.set_middleware(middleware).build(server_address).await?;
|
.set_host_filtering(AllowHosts::Any)
|
||||||
|
.set_middleware(middleware)
|
||||||
|
.build(server_address)
|
||||||
|
.await?;
|
||||||
let mut modules = RpcModule::new(());
|
let mut modules = RpcModule::new(());
|
||||||
{
|
{
|
||||||
modules
|
modules
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
use crate::api::request::{Method, Request};
|
use crate::api::request::{
|
||||||
|
BalanceArgs, BuyXmrArgs, CancelAndRefundArgs, GetSwapInfoArgs, ListSellersArgs, Method,
|
||||||
|
MoneroRecoveryArgs, Request, ResumeArgs, WithdrawBtcArgs,
|
||||||
|
};
|
||||||
use crate::api::Context;
|
use crate::api::Context;
|
||||||
use crate::bitcoin::bitcoin_address;
|
use crate::bitcoin::bitcoin_address;
|
||||||
use crate::monero::monero_address;
|
use crate::monero::monero_address;
|
||||||
|
@ -29,7 +32,12 @@ pub fn register_modules(context: Arc<Context>) -> Result<RpcModule<Arc<Context>>
|
||||||
let swap_id = as_uuid(swap_id)
|
let swap_id = as_uuid(swap_id)
|
||||||
.ok_or_else(|| jsonrpsee_core::Error::Custom("Could not parse swap_id".to_string()))?;
|
.ok_or_else(|| jsonrpsee_core::Error::Custom("Could not parse swap_id".to_string()))?;
|
||||||
|
|
||||||
execute_request(params_raw, Method::GetSwapInfo { swap_id }, &context).await
|
execute_request(
|
||||||
|
params_raw,
|
||||||
|
Method::GetSwapInfo(GetSwapInfoArgs { swap_id }),
|
||||||
|
&context,
|
||||||
|
)
|
||||||
|
.await
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
module.register_async_method("get_bitcoin_balance", |params_raw, context| async move {
|
module.register_async_method("get_bitcoin_balance", |params_raw, context| async move {
|
||||||
|
@ -45,7 +53,12 @@ pub fn register_modules(context: Arc<Context>) -> Result<RpcModule<Arc<Context>>
|
||||||
jsonrpsee_core::Error::Custom("force_refesh is not a boolean".to_string())
|
jsonrpsee_core::Error::Custom("force_refesh is not a boolean".to_string())
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
execute_request(params_raw, Method::Balance { force_refresh }, &context).await
|
execute_request(
|
||||||
|
params_raw,
|
||||||
|
Method::Balance(BalanceArgs { force_refresh }),
|
||||||
|
&context,
|
||||||
|
)
|
||||||
|
.await
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
module.register_async_method("get_history", |params, context| async move {
|
module.register_async_method("get_history", |params, context| async move {
|
||||||
|
@ -66,7 +79,7 @@ pub fn register_modules(context: Arc<Context>) -> Result<RpcModule<Arc<Context>>
|
||||||
let swap_id = as_uuid(swap_id)
|
let swap_id = as_uuid(swap_id)
|
||||||
.ok_or_else(|| jsonrpsee_core::Error::Custom("Could not parse swap_id".to_string()))?;
|
.ok_or_else(|| jsonrpsee_core::Error::Custom("Could not parse swap_id".to_string()))?;
|
||||||
|
|
||||||
execute_request(params_raw, Method::Resume { swap_id }, &context).await
|
execute_request(params_raw, Method::Resume(ResumeArgs { swap_id }), &context).await
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
module.register_async_method("cancel_refund_swap", |params_raw, context| async move {
|
module.register_async_method("cancel_refund_swap", |params_raw, context| async move {
|
||||||
|
@ -79,7 +92,12 @@ pub fn register_modules(context: Arc<Context>) -> Result<RpcModule<Arc<Context>>
|
||||||
let swap_id = as_uuid(swap_id)
|
let swap_id = as_uuid(swap_id)
|
||||||
.ok_or_else(|| jsonrpsee_core::Error::Custom("Could not parse swap_id".to_string()))?;
|
.ok_or_else(|| jsonrpsee_core::Error::Custom("Could not parse swap_id".to_string()))?;
|
||||||
|
|
||||||
execute_request(params_raw, Method::CancelAndRefund { swap_id }, &context).await
|
execute_request(
|
||||||
|
params_raw,
|
||||||
|
Method::CancelAndRefund(CancelAndRefundArgs { swap_id }),
|
||||||
|
&context,
|
||||||
|
)
|
||||||
|
.await
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
module.register_async_method(
|
module.register_async_method(
|
||||||
|
@ -95,7 +113,12 @@ pub fn register_modules(context: Arc<Context>) -> Result<RpcModule<Arc<Context>>
|
||||||
jsonrpsee_core::Error::Custom("Could not parse swap_id".to_string())
|
jsonrpsee_core::Error::Custom("Could not parse swap_id".to_string())
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
execute_request(params_raw, Method::MoneroRecovery { swap_id }, &context).await
|
execute_request(
|
||||||
|
params_raw,
|
||||||
|
Method::MoneroRecovery(MoneroRecoveryArgs { swap_id }),
|
||||||
|
&context,
|
||||||
|
)
|
||||||
|
.await
|
||||||
},
|
},
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
@ -123,10 +146,10 @@ pub fn register_modules(context: Arc<Context>) -> Result<RpcModule<Arc<Context>>
|
||||||
|
|
||||||
execute_request(
|
execute_request(
|
||||||
params_raw,
|
params_raw,
|
||||||
Method::WithdrawBtc {
|
Method::WithdrawBtc(WithdrawBtcArgs {
|
||||||
amount,
|
amount,
|
||||||
address: withdraw_address,
|
address: withdraw_address,
|
||||||
},
|
}),
|
||||||
&context,
|
&context,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
|
@ -165,12 +188,12 @@ pub fn register_modules(context: Arc<Context>) -> Result<RpcModule<Arc<Context>>
|
||||||
|
|
||||||
execute_request(
|
execute_request(
|
||||||
params_raw,
|
params_raw,
|
||||||
Method::BuyXmr {
|
Method::BuyXmr(BuyXmrArgs {
|
||||||
bitcoin_change_address,
|
bitcoin_change_address,
|
||||||
monero_receive_address,
|
monero_receive_address,
|
||||||
seller,
|
seller,
|
||||||
swap_id: Uuid::new_v4(),
|
swap_id: Uuid::new_v4(),
|
||||||
},
|
}),
|
||||||
&context,
|
&context,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
|
@ -192,9 +215,9 @@ pub fn register_modules(context: Arc<Context>) -> Result<RpcModule<Arc<Context>>
|
||||||
|
|
||||||
execute_request(
|
execute_request(
|
||||||
params_raw,
|
params_raw,
|
||||||
Method::ListSellers {
|
Method::ListSellers(ListSellersArgs {
|
||||||
rendezvous_point: rendezvous_point.clone(),
|
rendezvous_point: rendezvous_point.clone(),
|
||||||
},
|
}),
|
||||||
&context,
|
&context,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
import { Box, DialogContentText } from '@material-ui/core';
|
import { Box, DialogContentText } from "@material-ui/core";
|
||||||
import { useActiveSwapInfo, useAppSelector } from 'store/hooks';
|
import { useActiveSwapInfo, useAppSelector } from "store/hooks";
|
||||||
import CliLogsBox from '../../../other/RenderedCliLog';
|
import CliLogsBox from "../../../other/RenderedCliLog";
|
||||||
import JsonTreeView from '../../../other/JSONViewTree';
|
import JsonTreeView from "../../../other/JSONViewTree";
|
||||||
|
|
||||||
export default function DebugPage() {
|
export default function DebugPage() {
|
||||||
const torStdOut = useAppSelector((s) => s.tor.stdOut);
|
const torStdOut = useAppSelector((s) => s.tor.stdOut);
|
||||||
const logs = useAppSelector((s) => s.swap.logs);
|
const logs = useAppSelector((s) => s.swap.logs);
|
||||||
const guiState = useAppSelector((s) => s.swap);
|
const guiState = useAppSelector((s) => s);
|
||||||
const cliState = useActiveSwapInfo();
|
const cliState = useActiveSwapInfo();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -14,9 +14,9 @@ export default function DebugPage() {
|
||||||
<DialogContentText>
|
<DialogContentText>
|
||||||
<Box
|
<Box
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
flexDirection: 'column',
|
flexDirection: "column",
|
||||||
gap: '8px',
|
gap: "8px",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<CliLogsBox logs={logs} label="Logs relevant to the swap" />
|
<CliLogsBox logs={logs} label="Logs relevant to the swap" />
|
||||||
|
@ -28,7 +28,7 @@ export default function DebugPage() {
|
||||||
data={cliState}
|
data={cliState}
|
||||||
label="Swap Daemon State (exposed via API)"
|
label="Swap Daemon State (exposed via API)"
|
||||||
/>
|
/>
|
||||||
<CliLogsBox label="Tor Daemon Logs" logs={torStdOut.split('\n')} />
|
<CliLogsBox label="Tor Daemon Logs" logs={torStdOut.split("\n")} />
|
||||||
</Box>
|
</Box>
|
||||||
</DialogContentText>
|
</DialogContentText>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { piconerosToXmr, satsToBtc } from 'utils/conversionUtils';
|
import { piconerosToXmr, satsToBtc } from "utils/conversionUtils";
|
||||||
import { Tooltip } from '@material-ui/core';
|
import { Tooltip } from "@material-ui/core";
|
||||||
import { useAppSelector } from 'store/hooks';
|
import { useAppSelector } from "store/hooks";
|
||||||
|
|
||||||
type Amount = number | null | undefined;
|
type Amount = number | null | undefined;
|
||||||
|
|
||||||
|
@ -21,13 +21,13 @@ export function AmountWithUnit({
|
||||||
title={
|
title={
|
||||||
dollarRate != null && amount != null
|
dollarRate != null && amount != null
|
||||||
? `≈ $${(dollarRate * amount).toFixed(2)}`
|
? `≈ $${(dollarRate * amount).toFixed(2)}`
|
||||||
: ''
|
: ""
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<span>
|
<span>
|
||||||
{amount != null
|
{amount != null
|
||||||
? Number.parseFloat(amount.toFixed(fixedPrecision))
|
? Number.parseFloat(amount.toFixed(fixedPrecision))
|
||||||
: '?'}{' '}
|
: "?"}{" "}
|
||||||
{unit}
|
{unit}
|
||||||
</span>
|
</span>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
|
|
@ -4,11 +4,15 @@ import { store } from "./store/storeRenderer";
|
||||||
import { rpcSetBalance } from "store/features/rpcSlice";
|
import { rpcSetBalance } from "store/features/rpcSlice";
|
||||||
|
|
||||||
export async function checkBitcoinBalance() {
|
export async function checkBitcoinBalance() {
|
||||||
const response = await invoke('balance') as BalanceBitcoinResponse;
|
// TODO: use tauri-bindgen here
|
||||||
|
const response = (await invoke("balance")) as {
|
||||||
|
balance: number;
|
||||||
|
};
|
||||||
|
|
||||||
store.dispatch(rpcSetBalance(response.balance));
|
store.dispatch(rpcSetBalance(response.balance));
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getRawSwapInfos() {
|
export async function getRawSwapInfos() {
|
||||||
const response = await invoke('swap_infos');
|
const response = await invoke("swap_infos");
|
||||||
console.log(response);
|
console.log(response);
|
||||||
}
|
}
|
Loading…
Add table
Add a link
Reference in a new issue