mirror of
https://github.com/creating2morrow/neveko.git
synced 2025-01-20 17:54:34 +00:00
1205 lines
38 KiB
Rust
1205 lines
38 KiB
Rust
use crate::{
|
|
args,
|
|
i2p,
|
|
proof,
|
|
reqres,
|
|
utils,
|
|
};
|
|
use clap::Parser;
|
|
use diqwest::WithDigestAuth;
|
|
use log::{
|
|
debug,
|
|
error,
|
|
info,
|
|
};
|
|
use std::process::Command;
|
|
|
|
use lazy_static::lazy_static;
|
|
use std::sync::Mutex;
|
|
|
|
pub const INVALID_VERSION: u32 = 0;
|
|
|
|
// global variable
|
|
lazy_static! {
|
|
/// used to avoid multisig wallet collision
|
|
static ref IS_WALLET_BUSY: Mutex<bool> = Mutex::new(false);
|
|
}
|
|
|
|
/// Current xmr ring size updated here.
|
|
const RING_SIZE: u32 = 0x10;
|
|
|
|
struct RpcLogin {
|
|
username: String,
|
|
credential: String,
|
|
}
|
|
|
|
pub enum TransactionType {
|
|
Failed,
|
|
In,
|
|
Out,
|
|
Pending,
|
|
Pool,
|
|
}
|
|
|
|
impl TransactionType {
|
|
pub fn value(&self) -> String {
|
|
match *self {
|
|
Self::Failed => String::from("failed"),
|
|
Self::In => String::from("in"),
|
|
Self::Out => String::from("out"),
|
|
Self::Pending => String::from("pending"),
|
|
Self::Pool => String::from("pool"),
|
|
}
|
|
}
|
|
pub fn propogated(tx_type: String) -> bool {
|
|
tx_type == Self::In.value() || tx_type == Self::Pool.value()
|
|
}
|
|
}
|
|
|
|
enum RpcFields {
|
|
Address,
|
|
Balance,
|
|
CheckTxProof,
|
|
Close,
|
|
CreateAddress,
|
|
CreateWallet,
|
|
DescribeTransfer,
|
|
ExchangeMultisigKeys,
|
|
Export,
|
|
GetTxProof,
|
|
GetTxById,
|
|
GetVersion,
|
|
Id,
|
|
Import,
|
|
JsonRpcVersion,
|
|
Make,
|
|
Open,
|
|
Prepare,
|
|
SignMultisig,
|
|
SubmitMultisig,
|
|
SweepAll,
|
|
Transfer,
|
|
ValidateAddress,
|
|
Verify,
|
|
}
|
|
|
|
impl RpcFields {
|
|
pub fn value(&self) -> String {
|
|
match *self {
|
|
RpcFields::Address => String::from("get_address"),
|
|
RpcFields::Balance => String::from("get_balance"),
|
|
RpcFields::CheckTxProof => String::from("check_tx_proof"),
|
|
RpcFields::Close => String::from("close_wallet"),
|
|
RpcFields::CreateAddress => String::from("create_address"),
|
|
RpcFields::CreateWallet => String::from("create_wallet"),
|
|
RpcFields::DescribeTransfer => String::from("describe_transfer"),
|
|
RpcFields::ExchangeMultisigKeys => String::from("exchange_multisig_keys"),
|
|
RpcFields::Export => String::from("export_multisig_info"),
|
|
RpcFields::GetTxProof => String::from("get_tx_proof"),
|
|
RpcFields::GetTxById => String::from("get_transfer_by_txid"),
|
|
RpcFields::GetVersion => String::from("get_version"),
|
|
RpcFields::Id => String::from("0"),
|
|
RpcFields::Import => String::from("import_multisig_info"),
|
|
RpcFields::JsonRpcVersion => String::from("2.0"),
|
|
RpcFields::Make => String::from("make_multisig"),
|
|
RpcFields::Open => String::from("open_wallet"),
|
|
RpcFields::Prepare => String::from("prepare_multisig"),
|
|
RpcFields::SignMultisig => String::from("sign_multisig"),
|
|
RpcFields::SubmitMultisig => String::from("submit_multisig"),
|
|
RpcFields::SweepAll => String::from("sweep_all"),
|
|
RpcFields::Transfer => String::from("transfer"),
|
|
RpcFields::ValidateAddress => String::from("validate_address"),
|
|
RpcFields::Verify => String::from("verify"),
|
|
}
|
|
}
|
|
}
|
|
|
|
enum DaemonFields {
|
|
GetBlock,
|
|
GetHeight,
|
|
GetInfo,
|
|
GetTransactions,
|
|
Id,
|
|
Version,
|
|
}
|
|
|
|
impl DaemonFields {
|
|
pub fn value(&self) -> String {
|
|
match *self {
|
|
DaemonFields::GetBlock => String::from("get_block"),
|
|
DaemonFields::GetHeight => String::from("get_height"),
|
|
DaemonFields::GetInfo => String::from("get_info"),
|
|
DaemonFields::GetTransactions => String::from("get_transactions"),
|
|
DaemonFields::Id => String::from("0"),
|
|
DaemonFields::Version => String::from("2.0"),
|
|
}
|
|
}
|
|
}
|
|
|
|
pub enum LockTimeLimit {
|
|
Blocks,
|
|
}
|
|
|
|
impl LockTimeLimit {
|
|
pub fn value(&self) -> u64 {
|
|
match *self {
|
|
LockTimeLimit::Blocks => 20,
|
|
}
|
|
}
|
|
}
|
|
|
|
// TODO(c2m): make inbound connections for i2p tx proxy configurable
|
|
|
|
/// Start monerod from the -`-monero-location` flag
|
|
///
|
|
/// default: /home/$USER/monero-xxx-xxx
|
|
pub fn start_daemon() {
|
|
info!("starting monerod");
|
|
let blockchain_dir = get_blockchain_dir();
|
|
let bin_dir = get_monero_location();
|
|
let release_env = utils::get_release_env();
|
|
let tx_proxy = format!("i2p,{}", utils::get_i2p_http_proxy());
|
|
let port = get_daemon_port();
|
|
let destination = i2p::get_destination(Some(port));
|
|
let anon_inbound = format!("{},127.0.0.1:{},8", destination, port);
|
|
if release_env == utils::ReleaseEnvironment::Development {
|
|
let args = ["--data-dir", &blockchain_dir, "--stagenet", "--detach"];
|
|
let output = Command::new(format!("{}/monerod", bin_dir))
|
|
.args(args)
|
|
.spawn()
|
|
.expect("monerod failed to start");
|
|
debug!("{:?}", output.stdout);
|
|
} else {
|
|
let args = [
|
|
"--data-dir",
|
|
&blockchain_dir,
|
|
"--tx-proxy",
|
|
&tx_proxy,
|
|
"--anonymous-inbound",
|
|
&anon_inbound,
|
|
"--detach",
|
|
];
|
|
let output = Command::new(format!("{}/monerod", bin_dir))
|
|
.args(args)
|
|
.spawn()
|
|
.expect("monerod failed to start");
|
|
debug!("{:?}", output.stdout);
|
|
}
|
|
}
|
|
|
|
/// Start monero-wallet-rpc
|
|
pub fn start_rpc() {
|
|
info!("starting monero-wallet-rpc");
|
|
let bin_dir = get_monero_location();
|
|
let port = get_rpc_port();
|
|
let login = get_rpc_creds();
|
|
let daemon_address = get_rpc_daemon();
|
|
let rpc_login = format!("{}:{}", &login.username, &login.credential);
|
|
let mut wallet_dir = format!(
|
|
"/home/{}/.neveko/stagenet/wallet/",
|
|
std::env::var("USER").unwrap_or(String::from("user")),
|
|
);
|
|
let release_env = utils::get_release_env();
|
|
if release_env == utils::ReleaseEnvironment::Development {
|
|
let args = [
|
|
"--rpc-bind-port",
|
|
&port,
|
|
"--wallet-dir",
|
|
&wallet_dir,
|
|
"--rpc-login",
|
|
&rpc_login,
|
|
"--daemon-address",
|
|
&daemon_address,
|
|
"--stagenet",
|
|
];
|
|
let output = Command::new(format!("{}/monero-wallet-rpc", bin_dir))
|
|
.args(args)
|
|
.spawn()
|
|
.expect("monero-wallet-rpc failed to start");
|
|
debug!("{:?}", output.stdout);
|
|
} else {
|
|
wallet_dir = format!(
|
|
"/home/{}/.neveko/wallet/",
|
|
std::env::var("USER").unwrap_or(String::from("user")),
|
|
);
|
|
let args = [
|
|
"--rpc-bind-port",
|
|
&port,
|
|
"--wallet-dir",
|
|
&wallet_dir,
|
|
"--rpc-login",
|
|
&rpc_login,
|
|
"--daemon-address",
|
|
&daemon_address,
|
|
];
|
|
let output = Command::new(format!("{}/monero-wallet-rpc", bin_dir))
|
|
.args(args)
|
|
.spawn()
|
|
.expect("monero-wallet-rpc failed to start");
|
|
debug!("{:?}", output.stdout);
|
|
}
|
|
}
|
|
|
|
fn get_rpc_port() -> String {
|
|
let args = args::Args::parse();
|
|
let rpc = String::from(args.monero_rpc_host);
|
|
let values = rpc.split(":");
|
|
let mut v: Vec<String> = values.map(|s| String::from(s)).collect();
|
|
let port = v.remove(2);
|
|
debug!("monero-wallet-rpc port: {}", port);
|
|
port
|
|
}
|
|
|
|
pub fn get_daemon_port() -> u16 {
|
|
let args = args::Args::parse();
|
|
let rpc = String::from(args.monero_rpc_daemon);
|
|
let values = rpc.split(":");
|
|
let mut v: Vec<String> = values.map(|s| String::from(s)).collect();
|
|
let port = v.remove(2);
|
|
debug!("monerod port: {}", port);
|
|
match port.parse::<u16>() {
|
|
Ok(p) => p,
|
|
Err(_) => 0,
|
|
}
|
|
}
|
|
|
|
/// Get monero rpc host from command line argument
|
|
fn get_blockchain_dir() -> String {
|
|
let args = args::Args::parse();
|
|
String::from(args.monero_blockchain_dir)
|
|
}
|
|
|
|
/// Get monero download location
|
|
fn get_monero_location() -> String {
|
|
let args = args::Args::parse();
|
|
String::from(args.monero_location)
|
|
}
|
|
|
|
/// Get monero rpc host from the `--monero-rpc-host` cli arg
|
|
fn get_rpc_host() -> String {
|
|
let args = args::Args::parse();
|
|
let rpc = String::from(args.monero_rpc_host);
|
|
format!("{}/json_rpc", rpc)
|
|
}
|
|
|
|
/// Get creds from the `--monero-rpc-daemon` cli arg
|
|
fn get_rpc_creds() -> RpcLogin {
|
|
let args = args::Args::parse();
|
|
let username = String::from(args.monero_rpc_username);
|
|
let credential = String::from(args.monero_rpc_cred);
|
|
RpcLogin {
|
|
username,
|
|
credential,
|
|
}
|
|
}
|
|
|
|
fn get_rpc_daemon() -> String {
|
|
let args = args::Args::parse();
|
|
let daemon = String::from(args.monero_rpc_daemon);
|
|
format!("{}/json_rpc", daemon)
|
|
}
|
|
|
|
/// Performs rpc 'get_version' method
|
|
pub async fn get_version() -> reqres::XmrRpcVersionResponse {
|
|
info!("executing {}", RpcFields::GetVersion.value());
|
|
let client = reqwest::Client::new();
|
|
let host = get_rpc_host();
|
|
let req = reqres::XmrRpcRequest {
|
|
jsonrpc: RpcFields::JsonRpcVersion.value(),
|
|
id: RpcFields::Id.value(),
|
|
method: RpcFields::GetVersion.value(),
|
|
};
|
|
let login: RpcLogin = get_rpc_creds();
|
|
match client
|
|
.post(host)
|
|
.json(&req)
|
|
.send_with_digest_auth(&login.username, &login.credential)
|
|
.await
|
|
{
|
|
Ok(response) => {
|
|
let res = response.json::<reqres::XmrRpcVersionResponse>().await;
|
|
debug!("{} response: {:?}", RpcFields::GetVersion.value(), res);
|
|
match res {
|
|
Ok(res) => res,
|
|
_ => Default::default(),
|
|
}
|
|
}
|
|
Err(_e) => Default::default(),
|
|
}
|
|
}
|
|
|
|
/// Helper function for checking xmr rpc online during app startup
|
|
pub async fn check_rpc_connection() -> () {
|
|
let res: reqres::XmrRpcVersionResponse = get_version().await;
|
|
if res.result.version == INVALID_VERSION {
|
|
error!("failed to connect to monero-wallet-rpc");
|
|
}
|
|
}
|
|
|
|
/// Performs the xmr rpc 'verify' method
|
|
pub async fn verify(address: String, data: String, signature: String) -> bool {
|
|
info!("executing {}", RpcFields::Verify.value());
|
|
let client = reqwest::Client::new();
|
|
let host = get_rpc_host();
|
|
let params = reqres::XmrRpcVerifyParams {
|
|
address,
|
|
data,
|
|
signature,
|
|
};
|
|
let req = reqres::XmrRpcVerifyRequest {
|
|
jsonrpc: RpcFields::JsonRpcVersion.value(),
|
|
id: RpcFields::Id.value(),
|
|
method: RpcFields::Verify.value(),
|
|
params,
|
|
};
|
|
let login: RpcLogin = get_rpc_creds();
|
|
match client
|
|
.post(host)
|
|
.json(&req)
|
|
.send_with_digest_auth(&login.username, &login.credential)
|
|
.await
|
|
{
|
|
Ok(response) => {
|
|
let res = response.json::<reqres::XmrRpcVerifyResponse>().await;
|
|
debug!("{} response: {:?}", RpcFields::Verify.value(), res);
|
|
match res {
|
|
Ok(res) => {
|
|
if res.result.good {
|
|
true
|
|
} else {
|
|
false
|
|
}
|
|
}
|
|
_ => false,
|
|
}
|
|
}
|
|
Err(_e) => false,
|
|
}
|
|
}
|
|
|
|
/// Performs the xmr rpc 'create_wallet' method
|
|
pub async fn create_wallet(filename: &String, password: &String) -> bool {
|
|
info!("executing {}", RpcFields::CreateWallet.value());
|
|
let client = reqwest::Client::new();
|
|
let host = get_rpc_host();
|
|
let params = reqres::XmrRpcCreateWalletParams {
|
|
filename: String::from(filename),
|
|
language: String::from("English"),
|
|
password: String::from(password),
|
|
};
|
|
let req = reqres::XmrRpcCreateRequest {
|
|
jsonrpc: RpcFields::JsonRpcVersion.value(),
|
|
id: RpcFields::Id.value(),
|
|
method: RpcFields::CreateWallet.value(),
|
|
params,
|
|
};
|
|
let login: RpcLogin = get_rpc_creds();
|
|
match client
|
|
.post(host)
|
|
.json(&req)
|
|
.send_with_digest_auth(&login.username, &login.credential)
|
|
.await
|
|
{
|
|
Ok(response) => {
|
|
// The result from wallet creation is empty
|
|
let res = response.text().await;
|
|
debug!("{} response: {:?}", RpcFields::CreateWallet.value(), res);
|
|
match res {
|
|
Ok(r) => {
|
|
if r.contains("-1") {
|
|
return false;
|
|
}
|
|
true
|
|
}
|
|
_ => false,
|
|
}
|
|
}
|
|
Err(_) => false,
|
|
}
|
|
}
|
|
|
|
/// Set the wallet lock to true during operations to avoid collisons
|
|
///
|
|
/// on different types of wallet (e.g. order versus NEVEKO instance).
|
|
///
|
|
/// The open functionality will break on `false` if busy.
|
|
fn update_wallet_lock(filename: &String, closing: bool) -> bool {
|
|
let is_busy: bool = match IS_WALLET_BUSY.lock() {
|
|
Ok(m) => *m,
|
|
Err(_) => true,
|
|
};
|
|
if is_busy && !closing {
|
|
debug!("wallet {} is busy", filename);
|
|
return false;
|
|
}
|
|
if !closing {
|
|
*IS_WALLET_BUSY.lock().unwrap() = true;
|
|
return true;
|
|
} else {
|
|
*IS_WALLET_BUSY.lock().unwrap() = false;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
/// Performs the xmr rpc 'open_wallet' method
|
|
pub async fn open_wallet(filename: &String, password: &String) -> bool {
|
|
let updated = update_wallet_lock(filename, false);
|
|
if !updated {
|
|
return updated;
|
|
}
|
|
info!("executing {}", RpcFields::Open.value());
|
|
let client = reqwest::Client::new();
|
|
let host = get_rpc_host();
|
|
let params = reqres::XmrRpcOpenWalletParams {
|
|
filename: String::from(filename),
|
|
password: String::from(password),
|
|
};
|
|
let req = reqres::XmrRpcOpenRequest {
|
|
jsonrpc: RpcFields::JsonRpcVersion.value(),
|
|
id: RpcFields::Id.value(),
|
|
method: RpcFields::Open.value(),
|
|
params,
|
|
};
|
|
let login: RpcLogin = get_rpc_creds();
|
|
match client
|
|
.post(host)
|
|
.json(&req)
|
|
.send_with_digest_auth(&login.username, &login.credential)
|
|
.await
|
|
{
|
|
Ok(response) => {
|
|
// The result from wallet operation is empty
|
|
let res = response.text().await;
|
|
debug!("{} response: {:?}", RpcFields::Open.value(), res);
|
|
match res {
|
|
Ok(r) => {
|
|
if r.contains("-1") {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
_ => false,
|
|
}
|
|
}
|
|
Err(_) => false,
|
|
}
|
|
}
|
|
|
|
/// Performs the xmr rpc 'close_wallet' method
|
|
pub async fn close_wallet(filename: &String, password: &String) -> bool {
|
|
let updated = update_wallet_lock(filename, true);
|
|
if !updated {
|
|
return updated;
|
|
}
|
|
info!("executing {}", RpcFields::Close.value());
|
|
let client = reqwest::Client::new();
|
|
let host = get_rpc_host();
|
|
let params = reqres::XmrRpcOpenWalletParams {
|
|
filename: String::from(filename),
|
|
password: String::from(password),
|
|
};
|
|
let req = reqres::XmrRpcOpenRequest {
|
|
jsonrpc: RpcFields::JsonRpcVersion.value(),
|
|
id: RpcFields::Id.value(),
|
|
method: RpcFields::Close.value(),
|
|
params,
|
|
};
|
|
let login: RpcLogin = get_rpc_creds();
|
|
match client
|
|
.post(host)
|
|
.json(&req)
|
|
.send_with_digest_auth(&login.username, &login.credential)
|
|
.await
|
|
{
|
|
Ok(response) => {
|
|
// The result from wallet operation is empty
|
|
let res = response.text().await;
|
|
debug!("{} response: {:?}", RpcFields::Close.value(), res);
|
|
match res {
|
|
Ok(_) => true,
|
|
_ => false,
|
|
}
|
|
}
|
|
Err(_) => false,
|
|
}
|
|
}
|
|
|
|
/// Performs the xmr rpc 'get_balance' method
|
|
pub async fn get_balance() -> reqres::XmrRpcBalanceResponse {
|
|
info!("executing {}", RpcFields::Balance.value());
|
|
let client = reqwest::Client::new();
|
|
let host = get_rpc_host();
|
|
let params: reqres::XmrRpcBalanceParams = reqres::XmrRpcBalanceParams {
|
|
account_index: 0,
|
|
address_indices: vec![0],
|
|
all_accounts: false,
|
|
strict: false,
|
|
};
|
|
let req = reqres::XmrRpcBalanceRequest {
|
|
jsonrpc: RpcFields::JsonRpcVersion.value(),
|
|
id: RpcFields::Id.value(),
|
|
method: RpcFields::Balance.value(),
|
|
params,
|
|
};
|
|
let login: RpcLogin = get_rpc_creds();
|
|
match client
|
|
.post(host)
|
|
.json(&req)
|
|
.send_with_digest_auth(&login.username, &login.credential)
|
|
.await
|
|
{
|
|
Ok(response) => {
|
|
let res = response.json::<reqres::XmrRpcBalanceResponse>().await;
|
|
debug!("{} response: {:?}", RpcFields::Balance.value(), res);
|
|
match res {
|
|
Ok(res) => res,
|
|
_ => Default::default(),
|
|
}
|
|
}
|
|
Err(_) => Default::default(),
|
|
}
|
|
}
|
|
|
|
/// Performs the xmr rpc 'get_address' method
|
|
pub async fn get_address() -> reqres::XmrRpcAddressResponse {
|
|
info!("executing {}", RpcFields::Address.value());
|
|
let client = reqwest::Client::new();
|
|
let host = get_rpc_host();
|
|
let params: reqres::XmrRpcAddressParams = reqres::XmrRpcAddressParams { account_index: 0 };
|
|
let req = reqres::XmrRpcAddressRequest {
|
|
jsonrpc: RpcFields::JsonRpcVersion.value(),
|
|
id: RpcFields::Id.value(),
|
|
method: RpcFields::Address.value(),
|
|
params,
|
|
};
|
|
let login: RpcLogin = get_rpc_creds();
|
|
match client
|
|
.post(host)
|
|
.json(&req)
|
|
.send_with_digest_auth(&login.username, &login.credential)
|
|
.await
|
|
{
|
|
Ok(response) => {
|
|
let res = response.json::<reqres::XmrRpcAddressResponse>().await;
|
|
debug!("{} response: {:?}", RpcFields::Address.value(), res);
|
|
match res {
|
|
Ok(res) => res,
|
|
_ => Default::default(),
|
|
}
|
|
}
|
|
Err(_) => Default::default(),
|
|
}
|
|
}
|
|
|
|
/// Performs the xmr rpc 'get_address' method
|
|
pub async fn validate_address(address: &String) -> reqres::XmrRpcValidateAddressResponse {
|
|
info!("executing {}", RpcFields::ValidateAddress.value());
|
|
let client = reqwest::Client::new();
|
|
let host = get_rpc_host();
|
|
let params: reqres::XmrRpcValidateAddressParams = reqres::XmrRpcValidateAddressParams {
|
|
address: String::from(address),
|
|
any_net_type: false,
|
|
allow_openalias: true,
|
|
};
|
|
let req = reqres::XmrRpcValidateAddressRequest {
|
|
jsonrpc: RpcFields::JsonRpcVersion.value(),
|
|
id: RpcFields::Id.value(),
|
|
method: RpcFields::ValidateAddress.value(),
|
|
params,
|
|
};
|
|
let login: RpcLogin = get_rpc_creds();
|
|
match client
|
|
.post(host)
|
|
.json(&req)
|
|
.send_with_digest_auth(&login.username, &login.credential)
|
|
.await
|
|
{
|
|
Ok(response) => {
|
|
let res = response
|
|
.json::<reqres::XmrRpcValidateAddressResponse>()
|
|
.await;
|
|
debug!("{} response: {:?}", RpcFields::ValidateAddress.value(), res);
|
|
match res {
|
|
Ok(res) => res,
|
|
_ => Default::default(),
|
|
}
|
|
}
|
|
Err(_) => Default::default(),
|
|
}
|
|
}
|
|
// START Multisig
|
|
|
|
/// Performs the xmr rpc 'prepare_multisig' method
|
|
pub async fn prepare_wallet() -> reqres::XmrRpcPrepareResponse {
|
|
info!("executing {}", RpcFields::Prepare.value());
|
|
let client = reqwest::Client::new();
|
|
let host = get_rpc_host();
|
|
let req = reqres::XmrRpcRequest {
|
|
jsonrpc: RpcFields::JsonRpcVersion.value(),
|
|
id: RpcFields::Id.value(),
|
|
method: RpcFields::Prepare.value(),
|
|
};
|
|
let login: RpcLogin = get_rpc_creds();
|
|
match client
|
|
.post(host)
|
|
.json(&req)
|
|
.send_with_digest_auth(&login.username, &login.credential)
|
|
.await
|
|
{
|
|
Ok(response) => {
|
|
let res = response.json::<reqres::XmrRpcPrepareResponse>().await;
|
|
debug!("{} response: {:?}", RpcFields::Prepare.value(), res);
|
|
match res {
|
|
Ok(res) => res,
|
|
_ => Default::default(),
|
|
}
|
|
}
|
|
Err(_) => Default::default(),
|
|
}
|
|
}
|
|
|
|
/// Performs the xmr rpc 'make_multisig' method
|
|
pub async fn make_wallet(info: Vec<String>) -> reqres::XmrRpcMakeResponse {
|
|
info!("executing {}", RpcFields::Make.value());
|
|
let client = reqwest::Client::new();
|
|
let host = get_rpc_host();
|
|
let params = reqres::XmrRpcMakeParams {
|
|
multisig_info: info,
|
|
threshold: 2,
|
|
};
|
|
let req = reqres::XmrRpcMakeRequest {
|
|
jsonrpc: RpcFields::JsonRpcVersion.value(),
|
|
id: RpcFields::Id.value(),
|
|
method: RpcFields::Make.value(),
|
|
params,
|
|
};
|
|
let login: RpcLogin = get_rpc_creds();
|
|
match client
|
|
.post(host)
|
|
.json(&req)
|
|
.send_with_digest_auth(&login.username, &login.credential)
|
|
.await
|
|
{
|
|
Ok(response) => {
|
|
let res = response.json::<reqres::XmrRpcMakeResponse>().await;
|
|
debug!("{} response: {:?}", RpcFields::Make.value(), res);
|
|
match res {
|
|
Ok(res) => res,
|
|
_ => Default::default(),
|
|
}
|
|
}
|
|
Err(_) => Default::default(),
|
|
}
|
|
}
|
|
|
|
/// Performs the xmr rpc 'export_multisig_info' method
|
|
pub async fn export_multisig_info() -> reqres::XmrRpcExportResponse {
|
|
info!("executing {}", RpcFields::Export.value());
|
|
let client = reqwest::Client::new();
|
|
let host = get_rpc_host();
|
|
let req = reqres::XmrRpcRequest {
|
|
jsonrpc: RpcFields::JsonRpcVersion.value(),
|
|
id: RpcFields::Id.value(),
|
|
method: RpcFields::Export.value(),
|
|
};
|
|
let login: RpcLogin = get_rpc_creds();
|
|
match client
|
|
.post(host)
|
|
.json(&req)
|
|
.send_with_digest_auth(&login.username, &login.credential)
|
|
.await
|
|
{
|
|
Ok(response) => {
|
|
let res = response.json::<reqres::XmrRpcExportResponse>().await;
|
|
debug!("{} response: {:?}", RpcFields::Export.value(), res);
|
|
match res {
|
|
Ok(res) => res,
|
|
_ => Default::default(),
|
|
}
|
|
}
|
|
Err(_) => Default::default(),
|
|
}
|
|
}
|
|
|
|
/// Performs the xmr rpc 'import_multisig_info' method
|
|
pub async fn import_multisig_info(info: Vec<String>) -> reqres::XmrRpcImportResponse {
|
|
info!("executing {}", RpcFields::Import.value());
|
|
let client = reqwest::Client::new();
|
|
let host = get_rpc_host();
|
|
let params = reqres::XmrRpcImportParams { info };
|
|
let req = reqres::XmrRpcImportRequest {
|
|
jsonrpc: RpcFields::JsonRpcVersion.value(),
|
|
id: RpcFields::Id.value(),
|
|
method: RpcFields::Import.value(),
|
|
params,
|
|
};
|
|
let login: RpcLogin = get_rpc_creds();
|
|
match client
|
|
.post(host)
|
|
.json(&req)
|
|
.send_with_digest_auth(&login.username, &login.credential)
|
|
.await
|
|
{
|
|
Ok(response) => {
|
|
let res = response.json::<reqres::XmrRpcImportResponse>().await;
|
|
debug!("{} response: {:?}", RpcFields::Import.value(), res);
|
|
match res {
|
|
Ok(res) => res,
|
|
_ => Default::default(),
|
|
}
|
|
}
|
|
Err(_) => Default::default(),
|
|
}
|
|
}
|
|
|
|
/// Performs the xmr rpc 'sign_multisig' method
|
|
pub async fn sign_multisig(tx_data_hex: String) -> reqres::XmrRpcSignMultisigResponse {
|
|
info!("executing {}", RpcFields::SignMultisig.value());
|
|
let client = reqwest::Client::new();
|
|
let host = get_rpc_host();
|
|
let params = reqres::XmrRpcSignMultisigParams { tx_data_hex };
|
|
let req = reqres::XmrRpcSignMultisigRequest {
|
|
jsonrpc: RpcFields::JsonRpcVersion.value(),
|
|
id: RpcFields::Id.value(),
|
|
method: RpcFields::SignMultisig.value(),
|
|
params,
|
|
};
|
|
let login: RpcLogin = get_rpc_creds();
|
|
match client
|
|
.post(host)
|
|
.json(&req)
|
|
.send_with_digest_auth(&login.username, &login.credential)
|
|
.await
|
|
{
|
|
Ok(response) => {
|
|
let res = response.json::<reqres::XmrRpcSignMultisigResponse>().await;
|
|
debug!("{} response: {:?}", RpcFields::SignMultisig.value(), res);
|
|
match res {
|
|
Ok(res) => res,
|
|
_ => Default::default(),
|
|
}
|
|
}
|
|
Err(_) => Default::default(),
|
|
}
|
|
}
|
|
|
|
/// Performs the xmr rpc 'submit_multisig' method
|
|
pub async fn submit_multisig(tx_data_hex: String) -> reqres::XmrRpcSubmitMultisigResponse {
|
|
info!("executing {}", RpcFields::SubmitMultisig.value());
|
|
let client = reqwest::Client::new();
|
|
let host = get_rpc_host();
|
|
let params = reqres::XmrRpcSignMultisigParams { tx_data_hex };
|
|
let req = reqres::XmrRpcSignMultisigRequest {
|
|
jsonrpc: RpcFields::JsonRpcVersion.value(),
|
|
id: RpcFields::Id.value(),
|
|
method: RpcFields::SubmitMultisig.value(),
|
|
params,
|
|
};
|
|
let login: RpcLogin = get_rpc_creds();
|
|
match client
|
|
.post(host)
|
|
.json(&req)
|
|
.send_with_digest_auth(&login.username, &login.credential)
|
|
.await
|
|
{
|
|
Ok(response) => {
|
|
let res = response
|
|
.json::<reqres::XmrRpcSubmitMultisigResponse>()
|
|
.await;
|
|
debug!("{} response: {:?}", RpcFields::SubmitMultisig.value(), res);
|
|
match res {
|
|
Ok(res) => res,
|
|
_ => Default::default(),
|
|
}
|
|
}
|
|
Err(_) => Default::default(),
|
|
}
|
|
}
|
|
|
|
/// Performs the xmr rpc 'exchange_multisig_keys' method
|
|
pub async fn exchange_multisig_keys(
|
|
force_update_use_with_caution: bool,
|
|
multisig_info: Vec<String>,
|
|
password: &String,
|
|
) -> reqres::XmrRpcExchangeMultisigKeysResponse {
|
|
info!("executing: {}", RpcFields::ExchangeMultisigKeys.value());
|
|
let client = reqwest::Client::new();
|
|
let host = get_rpc_host();
|
|
let params = reqres::XmrRpcExchangeMultisigKeysParams {
|
|
force_update_use_with_caution,
|
|
password: String::from(password),
|
|
multisig_info,
|
|
};
|
|
let req = reqres::XmrRpcExchangeMultisigKeysRequest {
|
|
jsonrpc: RpcFields::JsonRpcVersion.value(),
|
|
id: RpcFields::Id.value(),
|
|
method: RpcFields::ExchangeMultisigKeys.value(),
|
|
params,
|
|
};
|
|
let login: RpcLogin = get_rpc_creds();
|
|
match client
|
|
.post(host)
|
|
.json(&req)
|
|
.send_with_digest_auth(&login.username, &login.credential)
|
|
.await
|
|
{
|
|
Ok(response) => {
|
|
let res = response
|
|
.json::<reqres::XmrRpcExchangeMultisigKeysResponse>()
|
|
.await;
|
|
debug!(
|
|
"{} response: {:?}",
|
|
RpcFields::ExchangeMultisigKeys.value(),
|
|
res
|
|
);
|
|
match res {
|
|
Ok(res) => res,
|
|
_ => Default::default(),
|
|
}
|
|
}
|
|
Err(_) => Default::default(),
|
|
}
|
|
}
|
|
// END Multisig
|
|
|
|
/// Performs the xmr rpc 'check_tx_proof' method
|
|
pub async fn check_tx_proof(txp: &proof::TxProof) -> reqres::XmrRpcCheckTxProofResponse {
|
|
info!("executing {}", RpcFields::CheckTxProof.value());
|
|
let client = reqwest::Client::new();
|
|
let host = get_rpc_host();
|
|
let params: reqres::XmrRpcCheckTxProofParams = reqres::XmrRpcCheckTxProofParams {
|
|
address: String::from(&txp.subaddress),
|
|
message: String::from(&txp.message),
|
|
signature: String::from(&txp.signature),
|
|
txid: String::from(&txp.hash),
|
|
};
|
|
let req = reqres::XmrRpcCheckTxProofRequest {
|
|
jsonrpc: RpcFields::JsonRpcVersion.value(),
|
|
id: RpcFields::Id.value(),
|
|
method: RpcFields::CheckTxProof.value(),
|
|
params,
|
|
};
|
|
let login: RpcLogin = get_rpc_creds();
|
|
match client
|
|
.post(host)
|
|
.json(&req)
|
|
.send_with_digest_auth(&login.username, &login.credential)
|
|
.await
|
|
{
|
|
Ok(response) => {
|
|
let res = response.json::<reqres::XmrRpcCheckTxProofResponse>().await;
|
|
debug!("{} response: {:?}", RpcFields::CheckTxProof.value(), res);
|
|
match res {
|
|
Ok(res) => res,
|
|
_ => Default::default(),
|
|
}
|
|
}
|
|
Err(_) => Default::default(),
|
|
}
|
|
}
|
|
|
|
/// Performs the xmr rpc 'get_tx_proof' method
|
|
pub async fn get_tx_proof(ptxp: proof::TxProof) -> reqres::XmrRpcGetTxProofResponse {
|
|
info!("executing {}", RpcFields::GetTxProof.value());
|
|
let client = reqwest::Client::new();
|
|
let host = get_rpc_host();
|
|
let params: reqres::XmrRpcGetTxProofParams = reqres::XmrRpcGetTxProofParams {
|
|
address: String::from(&ptxp.subaddress),
|
|
message: String::from(&ptxp.message),
|
|
txid: String::from(&ptxp.hash),
|
|
};
|
|
let req = reqres::XmrRpcGetTxProofRequest {
|
|
jsonrpc: RpcFields::JsonRpcVersion.value(),
|
|
id: RpcFields::Id.value(),
|
|
method: RpcFields::GetTxProof.value(),
|
|
params,
|
|
};
|
|
let login: RpcLogin = get_rpc_creds();
|
|
match client
|
|
.post(host)
|
|
.json(&req)
|
|
.send_with_digest_auth(&login.username, &login.credential)
|
|
.await
|
|
{
|
|
Ok(response) => {
|
|
let res = response.json::<reqres::XmrRpcGetTxProofResponse>().await;
|
|
debug!("{} response: {:?}", RpcFields::GetTxProof.value(), res);
|
|
match res {
|
|
Ok(res) => res,
|
|
_ => Default::default(),
|
|
}
|
|
}
|
|
Err(_) => Default::default(),
|
|
}
|
|
}
|
|
|
|
/// Performs the xmr rpc 'get_transfer_by_txid' method
|
|
pub async fn get_transfer_by_txid(txid: &str) -> reqres::XmrRpcGetTxByIdResponse {
|
|
info!("executing: {}", RpcFields::GetTxById.value());
|
|
let client = reqwest::Client::new();
|
|
let host = get_rpc_host();
|
|
let params: reqres::XmrRpcGetTxByIdParams = reqres::XmrRpcGetTxByIdParams {
|
|
txid: String::from(txid),
|
|
};
|
|
let req = reqres::XmrRpcGetTxByIdRequest {
|
|
jsonrpc: RpcFields::JsonRpcVersion.value(),
|
|
id: RpcFields::Id.value(),
|
|
method: RpcFields::GetTxById.value(),
|
|
params,
|
|
};
|
|
let login: RpcLogin = get_rpc_creds();
|
|
match client
|
|
.post(host)
|
|
.json(&req)
|
|
.send_with_digest_auth(&login.username, &login.credential)
|
|
.await
|
|
{
|
|
Ok(response) => {
|
|
let res = response.json::<reqres::XmrRpcGetTxByIdResponse>().await;
|
|
debug!("{} response: {:?}", RpcFields::GetTxById.value(), res);
|
|
match res {
|
|
Ok(res) => res,
|
|
_ => Default::default(),
|
|
}
|
|
}
|
|
Err(_) => Default::default(),
|
|
}
|
|
}
|
|
|
|
/// Performs the xmr rpc 'transfer' method
|
|
pub async fn transfer(d: reqres::Destination) -> reqres::XmrRpcTransferResponse {
|
|
info!("executing {}", RpcFields::Transfer.value());
|
|
let client = reqwest::Client::new();
|
|
let host = get_rpc_host();
|
|
let mut destinations: Vec<reqres::Destination> = Vec::new();
|
|
destinations.push(d);
|
|
let params: reqres::XmrRpcTransferParams = reqres::XmrRpcTransferParams {
|
|
account_index: 0,
|
|
destinations,
|
|
get_tx_key: false,
|
|
priority: 0,
|
|
ring_size: RING_SIZE,
|
|
subaddr_indices: vec![0],
|
|
};
|
|
let req = reqres::XmrRpcTransfrerRequest {
|
|
jsonrpc: RpcFields::JsonRpcVersion.value(),
|
|
id: RpcFields::Id.value(),
|
|
method: RpcFields::Transfer.value(),
|
|
params,
|
|
};
|
|
let login: RpcLogin = get_rpc_creds();
|
|
match client
|
|
.post(host)
|
|
.json(&req)
|
|
.send_with_digest_auth(&login.username, &login.credential)
|
|
.await
|
|
{
|
|
Ok(response) => {
|
|
let res = response.json::<reqres::XmrRpcTransferResponse>().await;
|
|
debug!("{} response: {:?}", RpcFields::Transfer.value(), res);
|
|
match res {
|
|
Ok(res) => res,
|
|
_ => Default::default(),
|
|
}
|
|
}
|
|
Err(_) => Default::default(),
|
|
}
|
|
}
|
|
|
|
/// Performs the xmr rpc 'describe_transfer' method
|
|
pub async fn describe_transfer(multisig_txset: &String) -> reqres::XmrRpcDescribeTransferResponse {
|
|
info!("executing {}", RpcFields::DescribeTransfer.value());
|
|
let client = reqwest::Client::new();
|
|
let host = get_rpc_host();
|
|
let params: reqres::XmrRpcDescribeTransferParams = reqres::XmrRpcDescribeTransferParams {
|
|
multisig_txset: String::from(multisig_txset),
|
|
};
|
|
let req = reqres::XmrRpcDescribeTransfrerRequest {
|
|
jsonrpc: RpcFields::JsonRpcVersion.value(),
|
|
id: RpcFields::Id.value(),
|
|
method: RpcFields::DescribeTransfer.value(),
|
|
params,
|
|
};
|
|
let login: RpcLogin = get_rpc_creds();
|
|
match client
|
|
.post(host)
|
|
.json(&req)
|
|
.send_with_digest_auth(&login.username, &login.credential)
|
|
.await
|
|
{
|
|
Ok(response) => {
|
|
let res = response
|
|
.json::<reqres::XmrRpcDescribeTransferResponse>()
|
|
.await;
|
|
debug!(
|
|
"{} response: {:?}",
|
|
RpcFields::DescribeTransfer.value(),
|
|
res
|
|
);
|
|
match res {
|
|
Ok(res) => res,
|
|
_ => Default::default(),
|
|
}
|
|
}
|
|
Err(_) => Default::default(),
|
|
}
|
|
}
|
|
|
|
/// Performs the xmr rpc 'sweep_all' method
|
|
pub async fn sweep_all(address: String) -> reqres::XmrRpcSweepAllResponse {
|
|
info!("executing {}", RpcFields::SweepAll.value());
|
|
let client = reqwest::Client::new();
|
|
let host = get_rpc_host();
|
|
let params: reqres::XmrRpcSweepAllParams = reqres::XmrRpcSweepAllParams { address };
|
|
let req = reqres::XmrRpcSweepAllRequest {
|
|
jsonrpc: RpcFields::JsonRpcVersion.value(),
|
|
id: RpcFields::Id.value(),
|
|
method: RpcFields::SweepAll.value(),
|
|
params,
|
|
};
|
|
let login: RpcLogin = get_rpc_creds();
|
|
match client
|
|
.post(host)
|
|
.json(&req)
|
|
.send_with_digest_auth(&login.username, &login.credential)
|
|
.await
|
|
{
|
|
Ok(response) => {
|
|
let res = response.json::<reqres::XmrRpcSweepAllResponse>().await;
|
|
debug!("{} response: {:?}", RpcFields::SweepAll.value(), res);
|
|
match res {
|
|
Ok(res) => res,
|
|
_ => Default::default(),
|
|
}
|
|
}
|
|
Err(_) => Default::default(),
|
|
}
|
|
}
|
|
|
|
/// Performs the xmr rpc 'create_address' method
|
|
pub async fn create_address() -> reqres::XmrRpcCreateAddressResponse {
|
|
info!("executing {}", RpcFields::CreateAddress.value());
|
|
let client = reqwest::Client::new();
|
|
let host = get_rpc_host();
|
|
let params: reqres::XmrRpcCreateAddressParams =
|
|
reqres::XmrRpcCreateAddressParams { account_index: 0 };
|
|
let req = reqres::XmrRpcCreateAddressRequest {
|
|
jsonrpc: RpcFields::JsonRpcVersion.value(),
|
|
id: RpcFields::Id.value(),
|
|
method: RpcFields::CreateAddress.value(),
|
|
params,
|
|
};
|
|
let login: RpcLogin = get_rpc_creds();
|
|
match client
|
|
.post(host)
|
|
.json(&req)
|
|
.send_with_digest_auth(&login.username, &login.credential)
|
|
.await
|
|
{
|
|
Ok(response) => {
|
|
let res = response.json::<reqres::XmrRpcCreateAddressResponse>().await;
|
|
debug!("{} response: {:?}", RpcFields::CreateAddress.value(), res);
|
|
match res {
|
|
Ok(res) => res,
|
|
_ => Default::default(),
|
|
}
|
|
}
|
|
Err(_) => Default::default(),
|
|
}
|
|
}
|
|
|
|
// Daemon requests
|
|
//-------------------------------------------------------------------
|
|
/// Performs the xmr daemon 'get_info' method
|
|
pub async fn get_info() -> reqres::XmrDaemonGetInfoResponse {
|
|
info!("fetching daemon info");
|
|
let client = reqwest::Client::new();
|
|
let host = get_rpc_daemon();
|
|
let req = reqres::XmrRpcRequest {
|
|
jsonrpc: DaemonFields::Version.value(),
|
|
id: DaemonFields::Id.value(),
|
|
method: DaemonFields::GetInfo.value(),
|
|
};
|
|
match client.post(host).json(&req).send().await {
|
|
Ok(response) => {
|
|
let res = response.json::<reqres::XmrDaemonGetInfoResponse>().await;
|
|
// add debug log here if needed for adding more info to home screen in gui
|
|
match res {
|
|
Ok(res) => res,
|
|
_ => Default::default(),
|
|
}
|
|
}
|
|
Err(_) => Default::default(),
|
|
}
|
|
}
|
|
|
|
/// Performs the xmr daemon 'get_height' method
|
|
pub async fn get_height() -> reqres::XmrDaemonGetHeightResponse {
|
|
info!("fetching daemon height");
|
|
let client = reqwest::Client::new();
|
|
let args = args::Args::parse();
|
|
let daemon = String::from(args.monero_rpc_daemon);
|
|
let req = format!("{}/{}", daemon, DaemonFields::GetHeight.value());
|
|
match client.post(req).send().await {
|
|
Ok(response) => {
|
|
let res = response.json::<reqres::XmrDaemonGetHeightResponse>().await;
|
|
// don't log this one. The fee estimator blows up logs (T_T)
|
|
match res {
|
|
Ok(res) => res,
|
|
_ => Default::default(),
|
|
}
|
|
}
|
|
Err(_) => Default::default(),
|
|
}
|
|
}
|
|
|
|
/// Performs the xmr daemon 'get_block' method
|
|
pub async fn get_block(height: u64) -> reqres::XmrDaemonGetBlockResponse {
|
|
info!("fetching block at height: {}", height);
|
|
let client = reqwest::Client::new();
|
|
let host = get_rpc_daemon();
|
|
let params: reqres::XmrDaemonGetBlockParams = reqres::XmrDaemonGetBlockParams { height };
|
|
let req = reqres::XmrDaemonGetBlockRequest {
|
|
jsonrpc: DaemonFields::Version.value(),
|
|
id: DaemonFields::Id.value(),
|
|
method: DaemonFields::GetBlock.value(),
|
|
params,
|
|
};
|
|
match client.post(host).json(&req).send().await {
|
|
Ok(response) => {
|
|
let res = response.json::<reqres::XmrDaemonGetBlockResponse>().await;
|
|
// don't log this one. The fee estimator blows up logs (T_T)
|
|
match res {
|
|
Ok(res) => res,
|
|
_ => Default::default(),
|
|
}
|
|
}
|
|
Err(_) => Default::default(),
|
|
}
|
|
}
|
|
|
|
/// Performs the xmr daemon 'get_transactions' method
|
|
pub async fn get_transactions(txs_hashes: Vec<String>) -> reqres::XmrDaemonGetTransactionsResponse {
|
|
info!("fetching {} transactions", txs_hashes.len());
|
|
let client = reqwest::Client::new();
|
|
let args = args::Args::parse();
|
|
let daemon = String::from(args.monero_rpc_daemon);
|
|
let url = format!("{}/{}", daemon, DaemonFields::GetTransactions.value());
|
|
let req = reqres::XmrDaemonGetTransactionsRequest {
|
|
txs_hashes,
|
|
decode_as_json: true,
|
|
};
|
|
match client.post(url).json(&req).send().await {
|
|
Ok(response) => {
|
|
let res = response
|
|
.json::<reqres::XmrDaemonGetTransactionsResponse>()
|
|
.await;
|
|
// don't log this one. The fee estimator blows up logs (T_T)
|
|
match res {
|
|
Ok(res) => res,
|
|
_ => Default::default(),
|
|
}
|
|
}
|
|
Err(_) => Default::default(),
|
|
}
|
|
}
|