mirror of
https://github.com/creating2morrow/neveko.git
synced 2025-01-03 09:29:39 +00:00
add submit multisig api
This commit is contained in:
parent
84a7656616
commit
ffa625185a
13 changed files with 144 additions and 39 deletions
|
@ -3,7 +3,7 @@
|
||||||
## Architecture
|
## Architecture
|
||||||
|
|
||||||
* gui
|
* gui
|
||||||
* three internal mircoservers (auth, contact and message)
|
* four internal mircoservers (auth, contact, market and message)
|
||||||
* core code module and lmdb
|
* core code module and lmdb
|
||||||
* one external i2p hidden service
|
* one external i2p hidden service
|
||||||
* jwt for internal auth, jwp for external
|
* 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
|
* 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
|
* 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
|
is online during the `check status` but goes offline while the message is being drafted
|
||||||
|
|
||||||
|
## Market
|
||||||
|
|
||||||
|
WIP
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
use log::{
|
|
||||||
debug,
|
|
||||||
error,
|
|
||||||
info,
|
|
||||||
};
|
|
||||||
use crate::{
|
use crate::{
|
||||||
db,
|
db,
|
||||||
models::*,
|
models::*,
|
||||||
utils,
|
utils,
|
||||||
};
|
};
|
||||||
|
use log::{
|
||||||
|
debug,
|
||||||
|
error,
|
||||||
|
info,
|
||||||
|
};
|
||||||
use rocket::serde::json::Json;
|
use rocket::serde::json::Json;
|
||||||
|
|
||||||
/// Create a new dispute
|
/// Create a new dispute
|
||||||
|
|
|
@ -35,12 +35,6 @@ struct MultisigMessageData {
|
||||||
orid: String,
|
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
|
/// Create a new message
|
||||||
pub async fn create(m: Json<Message>, jwp: String, m_type: MessageType) -> Message {
|
pub async fn create(m: Json<Message>, jwp: String, m_type: MessageType) -> Message {
|
||||||
let rnd = utils::generate_rnd();
|
let rnd = utils::generate_rnd();
|
||||||
|
|
|
@ -40,6 +40,7 @@ enum RpcFields {
|
||||||
Open,
|
Open,
|
||||||
Prepare,
|
Prepare,
|
||||||
SignMultisig,
|
SignMultisig,
|
||||||
|
SubmitMultisig,
|
||||||
SweepAll,
|
SweepAll,
|
||||||
Transfer,
|
Transfer,
|
||||||
ValidateAddress,
|
ValidateAddress,
|
||||||
|
@ -67,6 +68,7 @@ impl RpcFields {
|
||||||
RpcFields::Open => String::from("open_wallet"),
|
RpcFields::Open => String::from("open_wallet"),
|
||||||
RpcFields::Prepare => String::from("prepare_multisig"),
|
RpcFields::Prepare => String::from("prepare_multisig"),
|
||||||
RpcFields::SignMultisig => String::from("sign_multisig"),
|
RpcFields::SignMultisig => String::from("sign_multisig"),
|
||||||
|
RpcFields::SubmitMultisig => String::from("submit_multisig"),
|
||||||
RpcFields::SweepAll => String::from("sweep_all"),
|
RpcFields::SweepAll => String::from("sweep_all"),
|
||||||
RpcFields::Transfer => String::from("transfer"),
|
RpcFields::Transfer => String::from("transfer"),
|
||||||
RpcFields::ValidateAddress => String::from("validate_address"),
|
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
|
/// Performs the xmr rpc 'exchange_multisig_keys' method
|
||||||
pub async fn exchange_multisig_keys(
|
pub async fn exchange_multisig_keys(
|
||||||
force_update_use_with_caution: bool,
|
force_update_use_with_caution: bool,
|
||||||
|
|
|
@ -1,8 +1,3 @@
|
||||||
use log::{
|
|
||||||
debug,
|
|
||||||
error,
|
|
||||||
info,
|
|
||||||
};
|
|
||||||
use crate::{
|
use crate::{
|
||||||
db,
|
db,
|
||||||
models::*,
|
models::*,
|
||||||
|
@ -10,8 +5,21 @@ use crate::{
|
||||||
reqres,
|
reqres,
|
||||||
utils,
|
utils,
|
||||||
};
|
};
|
||||||
|
use log::{
|
||||||
|
debug,
|
||||||
|
error,
|
||||||
|
info,
|
||||||
|
};
|
||||||
use rocket::serde::json::Json;
|
use rocket::serde::json::Json;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
TODOs(c2m):
|
||||||
|
- API to valid payment and import multisig info
|
||||||
|
- update order status
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
enum StatusType {
|
enum StatusType {
|
||||||
_Delivered,
|
_Delivered,
|
||||||
MultisigMissing,
|
MultisigMissing,
|
||||||
|
@ -35,8 +43,7 @@ pub async fn create(j_order: Json<reqres::OrderRequest>) -> Order {
|
||||||
info!("creating order");
|
info!("creating order");
|
||||||
let wallet_name = String::from(crate::APP_NAME);
|
let wallet_name = String::from(crate::APP_NAME);
|
||||||
let wallet_password =
|
let wallet_password =
|
||||||
std::env::var(crate::MONERO_WALLET_PASSWORD)
|
std::env::var(crate::MONERO_WALLET_PASSWORD).unwrap_or(String::from("password"));
|
||||||
.unwrap_or(String::from("password"));
|
|
||||||
monero::close_wallet(&wallet_name, &wallet_password).await;
|
monero::close_wallet(&wallet_name, &wallet_password).await;
|
||||||
let ts = chrono::offset::Utc::now().timestamp();
|
let ts = chrono::offset::Utc::now().timestamp();
|
||||||
let orid: String = format!("O{}", utils::generate_rnd());
|
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));
|
db::Interface::write(&s.env, &s.handle, &u_order.pid, &Order::to_db(&u_order));
|
||||||
return 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
|
||||||
|
}
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
// Product repo/service layer
|
// Product repo/service layer
|
||||||
use log::{
|
|
||||||
debug,
|
|
||||||
error,
|
|
||||||
info,
|
|
||||||
};
|
|
||||||
use crate::{
|
use crate::{
|
||||||
db,
|
db,
|
||||||
models::*,
|
models::*,
|
||||||
utils,
|
utils,
|
||||||
};
|
};
|
||||||
|
use log::{
|
||||||
|
debug,
|
||||||
|
error,
|
||||||
|
info,
|
||||||
|
};
|
||||||
use rocket::serde::json::Json;
|
use rocket::serde::json::Json;
|
||||||
|
|
||||||
/// Create a new product
|
/// Create a new product
|
||||||
|
@ -16,7 +16,7 @@ pub fn create(d: Json<Product>) -> Product {
|
||||||
let pid: String = format!("product{}", utils::generate_rnd());
|
let pid: String = format!("product{}", utils::generate_rnd());
|
||||||
if !validate_product(&d) {
|
if !validate_product(&d) {
|
||||||
error!("invalid product");
|
error!("invalid product");
|
||||||
return Default::default()
|
return Default::default();
|
||||||
}
|
}
|
||||||
let new_product = Product {
|
let new_product = Product {
|
||||||
pid: String::from(&pid),
|
pid: String::from(&pid),
|
||||||
|
|
|
@ -343,6 +343,12 @@ pub struct XmrRpcImportResult {
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
pub struct XmrRpcSignMultisigResult {
|
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>,
|
pub tx_hash_list: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -862,6 +868,22 @@ impl Default for XmrRpcSignMultisigResponse {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
XmrRpcSignMultisigResponse {
|
XmrRpcSignMultisigResponse {
|
||||||
result: XmrRpcSignMultisigResult {
|
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(),
|
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(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -237,9 +237,11 @@ pub fn empty_string() -> String {
|
||||||
pub const fn string_limit() -> usize {
|
pub const fn string_limit() -> usize {
|
||||||
512
|
512
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const fn gpg_key_limit() -> usize {
|
pub const fn gpg_key_limit() -> usize {
|
||||||
4096
|
4096
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const fn message_limit() -> usize {
|
pub const fn message_limit() -> usize {
|
||||||
9999
|
9999
|
||||||
}
|
}
|
||||||
|
@ -644,8 +646,7 @@ pub async fn estimate_fee() -> u128 {
|
||||||
pub async fn can_transfer(invoice: u128) -> bool {
|
pub async fn can_transfer(invoice: u128) -> bool {
|
||||||
let wallet_name = String::from(crate::APP_NAME);
|
let wallet_name = String::from(crate::APP_NAME);
|
||||||
let wallet_password =
|
let wallet_password =
|
||||||
std::env::var(crate::MONERO_WALLET_PASSWORD)
|
std::env::var(crate::MONERO_WALLET_PASSWORD).unwrap_or(String::from("password"));
|
||||||
.unwrap_or(String::from("password"));
|
|
||||||
monero::open_wallet(&wallet_name, &wallet_password).await;
|
monero::open_wallet(&wallet_name, &wallet_password).await;
|
||||||
let balance = monero::get_balance().await;
|
let balance = monero::get_balance().await;
|
||||||
monero::close_wallet(&wallet_name, &wallet_password).await;
|
monero::close_wallet(&wallet_name, &wallet_password).await;
|
||||||
|
|
|
@ -692,8 +692,7 @@ fn send_payment_req(
|
||||||
log::debug!("sending {} piconero(s) to: {}", &d.amount, &d.address);
|
log::debug!("sending {} piconero(s) to: {}", &d.amount, &d.address);
|
||||||
let wallet_name = String::from(neveko_core::APP_NAME);
|
let wallet_name = String::from(neveko_core::APP_NAME);
|
||||||
let wallet_password =
|
let wallet_password =
|
||||||
std::env::var(neveko_core::MONERO_WALLET_PASSWORD)
|
std::env::var(neveko_core::MONERO_WALLET_PASSWORD).unwrap_or(String::from("password"));
|
||||||
.unwrap_or(String::from("password"));
|
|
||||||
monero::open_wallet(&wallet_name, &wallet_password).await;
|
monero::open_wallet(&wallet_name, &wallet_password).await;
|
||||||
let transfer: reqres::XmrRpcTransferResponse = monero::transfer(d).await;
|
let transfer: reqres::XmrRpcTransferResponse = monero::transfer(d).await;
|
||||||
// in order to keep the jwp creation process transparent to the user
|
// in order to keep the jwp creation process transparent to the user
|
||||||
|
|
|
@ -366,8 +366,7 @@ fn send_address_req(tx: Sender<reqres::XmrRpcAddressResponse>, ctx: egui::Contex
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
let wallet_name = String::from(neveko_core::APP_NAME);
|
let wallet_name = String::from(neveko_core::APP_NAME);
|
||||||
let wallet_password =
|
let wallet_password =
|
||||||
std::env::var(neveko_core::MONERO_WALLET_PASSWORD)
|
std::env::var(neveko_core::MONERO_WALLET_PASSWORD).unwrap_or(String::from("password"));
|
||||||
.unwrap_or(String::from("password"));
|
|
||||||
monero::open_wallet(&wallet_name, &wallet_password).await;
|
monero::open_wallet(&wallet_name, &wallet_password).await;
|
||||||
let address: reqres::XmrRpcAddressResponse = monero::get_address().await;
|
let address: reqres::XmrRpcAddressResponse = monero::get_address().await;
|
||||||
monero::close_wallet(&wallet_name, &wallet_password).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 {
|
tokio::spawn(async move {
|
||||||
let wallet_name = String::from(neveko_core::APP_NAME);
|
let wallet_name = String::from(neveko_core::APP_NAME);
|
||||||
let wallet_password =
|
let wallet_password =
|
||||||
std::env::var(neveko_core::MONERO_WALLET_PASSWORD)
|
std::env::var(neveko_core::MONERO_WALLET_PASSWORD).unwrap_or(String::from("password"));
|
||||||
.unwrap_or(String::from("password"));
|
|
||||||
monero::open_wallet(&wallet_name, &wallet_password).await;
|
monero::open_wallet(&wallet_name, &wallet_password).await;
|
||||||
let balance: reqres::XmrRpcBalanceResponse = monero::get_balance().await;
|
let balance: reqres::XmrRpcBalanceResponse = monero::get_balance().await;
|
||||||
monero::close_wallet(&wallet_name, &wallet_password).await;
|
monero::close_wallet(&wallet_name, &wallet_password).await;
|
||||||
|
|
|
@ -141,8 +141,7 @@ fn send_address_req(tx: Sender<reqres::XmrRpcAddressResponse>, ctx: egui::Contex
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
let wallet_name = String::from(neveko_core::APP_NAME);
|
let wallet_name = String::from(neveko_core::APP_NAME);
|
||||||
let wallet_password =
|
let wallet_password =
|
||||||
std::env::var(neveko_core::MONERO_WALLET_PASSWORD)
|
std::env::var(neveko_core::MONERO_WALLET_PASSWORD).unwrap_or(String::from("password"));
|
||||||
.unwrap_or(String::from("password"));
|
|
||||||
monero::open_wallet(&wallet_name, &wallet_password).await;
|
monero::open_wallet(&wallet_name, &wallet_password).await;
|
||||||
let address: reqres::XmrRpcAddressResponse = monero::get_address().await;
|
let address: reqres::XmrRpcAddressResponse = monero::get_address().await;
|
||||||
monero::close_wallet(&wallet_name, &wallet_password).await;
|
monero::close_wallet(&wallet_name, &wallet_password).await;
|
||||||
|
@ -159,8 +158,7 @@ fn send_sweep_all_req(
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
let wallet_name = String::from(neveko_core::APP_NAME);
|
let wallet_name = String::from(neveko_core::APP_NAME);
|
||||||
let wallet_password =
|
let wallet_password =
|
||||||
std::env::var(neveko_core::MONERO_WALLET_PASSWORD)
|
std::env::var(neveko_core::MONERO_WALLET_PASSWORD).unwrap_or(String::from("password"));
|
||||||
.unwrap_or(String::from("password"));
|
|
||||||
monero::open_wallet(&wallet_name, &wallet_password).await;
|
monero::open_wallet(&wallet_name, &wallet_password).await;
|
||||||
let result: reqres::XmrRpcSweepAllResponse = monero::sweep_all(address).await;
|
let result: reqres::XmrRpcSweepAllResponse = monero::sweep_all(address).await;
|
||||||
monero::close_wallet(&wallet_name, &wallet_password).await;
|
monero::close_wallet(&wallet_name, &wallet_password).await;
|
||||||
|
|
|
@ -79,10 +79,24 @@ pub async fn create_dispute(
|
||||||
Custom(Status::Ok, Json(m_dispute))
|
Custom(Status::Ok, Json(m_dispute))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a dispute
|
/// Fetch a dispute
|
||||||
#[get("/<did>")]
|
#[get("/<did>")]
|
||||||
pub async fn get_dispute(_token: auth::BearerToken, did: String) -> Custom<Json<models::Dispute>> {
|
pub async fn get_dispute(_token: auth::BearerToken, did: String) -> Custom<Json<models::Dispute>> {
|
||||||
let m_dispute: models::Dispute = dispute::find(&did);
|
let m_dispute: models::Dispute = dispute::find(&did);
|
||||||
Custom(Status::Ok, Json(m_dispute))
|
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
|
// END JSON APIs
|
||||||
|
|
|
@ -21,7 +21,10 @@ async fn rocket() -> _ {
|
||||||
)
|
)
|
||||||
.mount(
|
.mount(
|
||||||
"/order",
|
"/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("/orders", routes![controller::get_orders])
|
||||||
.mount("/products", routes![controller::get_products])
|
.mount("/products", routes![controller::get_products])
|
||||||
|
|
Loading…
Reference in a new issue