add submit multisig api

This commit is contained in:
creating2morrow 2023-06-04 06:42:03 -04:00
parent 84a7656616
commit ffa625185a
13 changed files with 144 additions and 39 deletions

View file

@ -3,7 +3,7 @@
## Architecture
* gui
* three internal mircoservers (auth, contact and message)
* four internal mircoservers (auth, contact, market and message)
* core code module and lmdb
* one external i2p hidden service
* jwt for internal auth, jwp for external
@ -62,3 +62,7 @@
* If contacts don't come back online before JWP expiration the message must be drafted again
* It is primarily meant for handling connectivity issues or the edge case where a contact is
is online during the `check status` but goes offline while the message is being drafted
## Market
WIP

View file

@ -1,13 +1,13 @@
use log::{
debug,
error,
info,
};
use crate::{
db,
models::*,
utils,
};
use log::{
debug,
error,
info,
};
use rocket::serde::json::Json;
/// Create a new dispute

View file

@ -35,12 +35,6 @@ struct MultisigMessageData {
orid: String,
}
/*
TODOs(c2m):
- API to valid payment and import multisig info
- API to sign and submit the signed tx set
*/
/// Create a new message
pub async fn create(m: Json<Message>, jwp: String, m_type: MessageType) -> Message {
let rnd = utils::generate_rnd();

View file

@ -40,6 +40,7 @@ enum RpcFields {
Open,
Prepare,
SignMultisig,
SubmitMultisig,
SweepAll,
Transfer,
ValidateAddress,
@ -67,6 +68,7 @@ impl RpcFields {
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"),
@ -687,6 +689,37 @@ pub async fn sign_multisig(tx_data_hex: String) -> reqres::XmrRpcSignMultisigRes
}
}
/// 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,

View file

@ -1,8 +1,3 @@
use log::{
debug,
error,
info,
};
use crate::{
db,
models::*,
@ -10,8 +5,21 @@ use crate::{
reqres,
utils,
};
use log::{
debug,
error,
info,
};
use rocket::serde::json::Json;
/*
TODOs(c2m):
- API to valid payment and import multisig info
- update order status
*/
enum StatusType {
_Delivered,
MultisigMissing,
@ -35,8 +43,7 @@ pub async fn create(j_order: Json<reqres::OrderRequest>) -> Order {
info!("creating order");
let wallet_name = String::from(crate::APP_NAME);
let wallet_password =
std::env::var(crate::MONERO_WALLET_PASSWORD)
.unwrap_or(String::from("password"));
std::env::var(crate::MONERO_WALLET_PASSWORD).unwrap_or(String::from("password"));
monero::close_wallet(&wallet_name, &wallet_password).await;
let ts = chrono::offset::Utc::now().timestamp();
let orid: String = format!("O{}", utils::generate_rnd());
@ -144,3 +151,18 @@ pub fn modify(o: Json<Order>) -> Order {
db::Interface::write(&s.env, &s.handle, &u_order.pid, &Order::to_db(&u_order));
return u_order;
}
/// Sign and submit multisig
pub async fn sign_and_submit_multisig(
orid: &String,
tx_data_hex: &String) -> reqres::XmrRpcSubmitMultisigResponse {
info!("signin and submitting multisig");
let r_sign: reqres::XmrRpcSignMultisigResponse =
monero::sign_multisig(String::from(tx_data_hex)).await;
let r_submit: reqres::XmrRpcSubmitMultisigResponse =
monero::submit_multisig(r_sign.result.tx_data_hex).await;
if r_submit.result.tx_hash_list.len() == 0 {
error!("unable to submit payment for order: {}", orid);
}
r_submit
}

View file

@ -1,14 +1,14 @@
// Product repo/service layer
use log::{
debug,
error,
info,
};
use crate::{
db,
models::*,
utils,
};
use log::{
debug,
error,
info,
};
use rocket::serde::json::Json;
/// Create a new product
@ -16,7 +16,7 @@ pub fn create(d: Json<Product>) -> Product {
let pid: String = format!("product{}", utils::generate_rnd());
if !validate_product(&d) {
error!("invalid product");
return Default::default()
return Default::default();
}
let new_product = Product {
pid: String::from(&pid),

View file

@ -343,6 +343,12 @@ pub struct XmrRpcImportResult {
#[derive(Deserialize, Debug)]
pub struct XmrRpcSignMultisigResult {
pub tx_data_hex: String,
pub tx_hash_list: Vec<String>,
}
#[derive(Deserialize, Debug)]
pub struct XmrRpcSubmitMultisigResult {
pub tx_hash_list: Vec<String>,
}
@ -862,6 +868,22 @@ impl Default for XmrRpcSignMultisigResponse {
fn default() -> Self {
XmrRpcSignMultisigResponse {
result: XmrRpcSignMultisigResult {
tx_data_hex: utils::empty_string(),
tx_hash_list: Vec::new(),
},
}
}
}
#[derive(Deserialize, Debug)]
pub struct XmrRpcSubmitMultisigResponse {
pub result: XmrRpcSubmitMultisigResult,
}
impl Default for XmrRpcSubmitMultisigResponse {
fn default() -> Self {
XmrRpcSubmitMultisigResponse {
result: XmrRpcSubmitMultisigResult {
tx_hash_list: Vec::new(),
},
}
@ -1123,3 +1145,20 @@ impl Default for MultisigInfoRequest {
}
}
}
/// Request for signing and submitting the unsigned txset
#[derive(Serialize, Deserialize, Debug)]
#[serde(crate = "rocket::serde")]
pub struct SignAndSubmitRequest {
pub orid: String,
pub txset: String,
}
impl Default for SignAndSubmitRequest {
fn default() -> Self {
SignAndSubmitRequest {
orid: utils::empty_string(),
txset: utils::empty_string(),
}
}
}

View file

@ -237,9 +237,11 @@ pub fn empty_string() -> String {
pub const fn string_limit() -> usize {
512
}
pub const fn gpg_key_limit() -> usize {
4096
}
pub const fn message_limit() -> usize {
9999
}
@ -644,8 +646,7 @@ pub async fn estimate_fee() -> u128 {
pub async fn can_transfer(invoice: u128) -> bool {
let wallet_name = String::from(crate::APP_NAME);
let wallet_password =
std::env::var(crate::MONERO_WALLET_PASSWORD)
.unwrap_or(String::from("password"));
std::env::var(crate::MONERO_WALLET_PASSWORD).unwrap_or(String::from("password"));
monero::open_wallet(&wallet_name, &wallet_password).await;
let balance = monero::get_balance().await;
monero::close_wallet(&wallet_name, &wallet_password).await;

View file

@ -692,8 +692,7 @@ fn send_payment_req(
log::debug!("sending {} piconero(s) to: {}", &d.amount, &d.address);
let wallet_name = String::from(neveko_core::APP_NAME);
let wallet_password =
std::env::var(neveko_core::MONERO_WALLET_PASSWORD)
.unwrap_or(String::from("password"));
std::env::var(neveko_core::MONERO_WALLET_PASSWORD).unwrap_or(String::from("password"));
monero::open_wallet(&wallet_name, &wallet_password).await;
let transfer: reqres::XmrRpcTransferResponse = monero::transfer(d).await;
// in order to keep the jwp creation process transparent to the user

View file

@ -366,8 +366,7 @@ fn send_address_req(tx: Sender<reqres::XmrRpcAddressResponse>, ctx: egui::Contex
tokio::spawn(async move {
let wallet_name = String::from(neveko_core::APP_NAME);
let wallet_password =
std::env::var(neveko_core::MONERO_WALLET_PASSWORD)
.unwrap_or(String::from("password"));
std::env::var(neveko_core::MONERO_WALLET_PASSWORD).unwrap_or(String::from("password"));
monero::open_wallet(&wallet_name, &wallet_password).await;
let address: reqres::XmrRpcAddressResponse = monero::get_address().await;
monero::close_wallet(&wallet_name, &wallet_password).await;
@ -380,8 +379,7 @@ fn send_balance_req(tx: Sender<reqres::XmrRpcBalanceResponse>, ctx: egui::Contex
tokio::spawn(async move {
let wallet_name = String::from(neveko_core::APP_NAME);
let wallet_password =
std::env::var(neveko_core::MONERO_WALLET_PASSWORD)
.unwrap_or(String::from("password"));
std::env::var(neveko_core::MONERO_WALLET_PASSWORD).unwrap_or(String::from("password"));
monero::open_wallet(&wallet_name, &wallet_password).await;
let balance: reqres::XmrRpcBalanceResponse = monero::get_balance().await;
monero::close_wallet(&wallet_name, &wallet_password).await;

View file

@ -141,8 +141,7 @@ fn send_address_req(tx: Sender<reqres::XmrRpcAddressResponse>, ctx: egui::Contex
tokio::spawn(async move {
let wallet_name = String::from(neveko_core::APP_NAME);
let wallet_password =
std::env::var(neveko_core::MONERO_WALLET_PASSWORD)
.unwrap_or(String::from("password"));
std::env::var(neveko_core::MONERO_WALLET_PASSWORD).unwrap_or(String::from("password"));
monero::open_wallet(&wallet_name, &wallet_password).await;
let address: reqres::XmrRpcAddressResponse = monero::get_address().await;
monero::close_wallet(&wallet_name, &wallet_password).await;
@ -159,8 +158,7 @@ fn send_sweep_all_req(
tokio::spawn(async move {
let wallet_name = String::from(neveko_core::APP_NAME);
let wallet_password =
std::env::var(neveko_core::MONERO_WALLET_PASSWORD)
.unwrap_or(String::from("password"));
std::env::var(neveko_core::MONERO_WALLET_PASSWORD).unwrap_or(String::from("password"));
monero::open_wallet(&wallet_name, &wallet_password).await;
let result: reqres::XmrRpcSweepAllResponse = monero::sweep_all(address).await;
monero::close_wallet(&wallet_name, &wallet_password).await;

View file

@ -79,10 +79,24 @@ pub async fn create_dispute(
Custom(Status::Ok, Json(m_dispute))
}
/// Create a dispute
/// Fetch a dispute
#[get("/<did>")]
pub async fn get_dispute(_token: auth::BearerToken, did: String) -> Custom<Json<models::Dispute>> {
let m_dispute: models::Dispute = dispute::find(&did);
Custom(Status::Ok, Json(m_dispute))
}
/// Create a dispute
#[post("/sign/submit", data = "<r_data>")]
pub async fn sign_and_submit_multisig(
r_data: Json<reqres::SignAndSubmitRequest>,
_token: auth::BearerToken,
) -> Custom<Json<reqres::SignAndSubmitRequest>> {
let result: reqres::XmrRpcSubmitMultisigResponse =
order::sign_and_submit_multisig(&r_data.orid, &r_data.txset).await;
if result.result.tx_hash_list.is_empty() {
return Custom(Status::BadRequest, Json(Default::default()));
}
Custom(Status::Ok, Json(Default::default()))
}
// END JSON APIs

View file

@ -21,7 +21,10 @@ async fn rocket() -> _ {
)
.mount(
"/order",
routes![controller::get_order, controller::update_order],
routes![
controller::get_order,
controller::sign_and_submit_multisig,
controller::update_order],
)
.mount("/orders", routes![controller::get_orders])
.mount("/products", routes![controller::get_products])