mirror of
https://github.com/creating2morrow/neveko.git
synced 2025-01-03 17:39:55 +00:00
submit txset and finalize order - untested
This commit is contained in:
parent
bb492fce8c
commit
6340119435
5 changed files with 154 additions and 30 deletions
|
@ -9,8 +9,7 @@ use crate::{
|
||||||
monero,
|
monero,
|
||||||
order,
|
order,
|
||||||
product,
|
product,
|
||||||
reqres,
|
utils, reqres,
|
||||||
utils,
|
|
||||||
};
|
};
|
||||||
use log::{
|
use log::{
|
||||||
debug,
|
debug,
|
||||||
|
@ -421,12 +420,120 @@ pub async fn upload_delivery_info(
|
||||||
/// upon a `vendor_update_success: true` response
|
/// upon a `vendor_update_success: true` response
|
||||||
pub async fn finalize_order(orid: &String) -> reqres::FinalizeOrderResponse {
|
pub async fn finalize_order(orid: &String) -> reqres::FinalizeOrderResponse {
|
||||||
info!("finalizing order: {}", orid);
|
info!("finalizing order: {}", orid);
|
||||||
|
// verify recipient and unlock time
|
||||||
|
let mut m_order: Order = order::find(orid);
|
||||||
|
if m_order.vend_msig_txset == utils::empty_string() {
|
||||||
|
error!("txset missing");
|
||||||
|
return Default::default();
|
||||||
|
}
|
||||||
|
// get draft payment txset
|
||||||
|
let wallet_password = utils::empty_string();
|
||||||
|
monero::open_wallet(orid, &wallet_password).await;
|
||||||
|
monero::refresh().await;
|
||||||
|
let address: String = String::from(&m_order.subaddress);
|
||||||
|
let m_describe = monero::describe_transfer(&m_order.vend_msig_txset).await;
|
||||||
|
let check_destination: reqres::Destination = reqres::Destination {
|
||||||
|
address,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
let valid = m_describe.result.desc[0].recepients.contains(&check_destination)
|
||||||
|
&& m_describe.result.desc[0].unlock_time < monero::LockTimeLimit::Blocks.value();
|
||||||
|
if !valid {
|
||||||
|
monero::close_wallet(orid, &wallet_password).await;
|
||||||
|
error!("invalid txset");
|
||||||
|
return Default::default();
|
||||||
|
}
|
||||||
|
// verify order wallet has been swept clean
|
||||||
|
let balance = monero::get_balance().await;
|
||||||
|
if balance.result.unlocked_balance != 0 {
|
||||||
|
monero::close_wallet(orid, &wallet_password).await;
|
||||||
|
error!("order wallet not swept");
|
||||||
|
return Default::default();
|
||||||
|
}
|
||||||
|
m_order.status = order::StatusType::Delivered.value();
|
||||||
|
order::modify(Json(m_order));
|
||||||
reqres::FinalizeOrderResponse {
|
reqres::FinalizeOrderResponse {
|
||||||
|
vendor_update_success: true,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Executes POST /order/finalize/{orid}
|
||||||
|
///
|
||||||
|
/// finalizing the order on the vendor side.
|
||||||
|
///
|
||||||
|
/// Customer needs to verify the response and update their lmdb.
|
||||||
|
///
|
||||||
|
/// see `finalize_order`
|
||||||
|
pub async fn transmit_finalize_request(
|
||||||
|
contact: &String,
|
||||||
|
jwp: &String,
|
||||||
|
orid: &String,
|
||||||
|
) -> Result<reqres::FinalizeOrderResponse, Box<dyn Error>> {
|
||||||
|
info!("executing transmit_cancel_request");
|
||||||
|
let host = utils::get_i2p_http_proxy();
|
||||||
|
let proxy = reqwest::Proxy::http(&host)?;
|
||||||
|
let client = reqwest::Client::builder().proxy(proxy).build();
|
||||||
|
match client?
|
||||||
|
.post(format!(
|
||||||
|
"http://{}/market/order/finalize/{}", contact, orid
|
||||||
|
))
|
||||||
|
.header("proof", jwp)
|
||||||
|
.send()
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(response) => {
|
||||||
|
let res = response.json::<reqres::FinalizeOrderResponse>().await;
|
||||||
|
debug!("finalize order response: {:?}", res);
|
||||||
|
match res {
|
||||||
|
Ok(r) => Ok(r),
|
||||||
|
_ => Ok(Default::default()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
error!("failed to finalize order due to: {:?}", e);
|
||||||
|
Ok(Default::default())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A post-decomposition trigger for the finalize request so that the logic
|
||||||
|
///
|
||||||
|
/// can be executed from the gui.
|
||||||
|
pub async fn trigger_finalize_request(contact: &String, jwp: &String, orid: &String) -> reqres::FinalizeOrderResponse {
|
||||||
|
info!("executing trigger_finalize_request");
|
||||||
|
let finalize = transmit_finalize_request(contact, jwp, orid).await;
|
||||||
|
// cache finalize order request to db
|
||||||
|
if finalize.is_err() {
|
||||||
|
log::error!("failed to trigger cancel request");
|
||||||
|
return Default::default();
|
||||||
|
}
|
||||||
|
let unwrap: reqres::FinalizeOrderResponse = finalize.unwrap();
|
||||||
|
let mut m_order: Order = order::find(&orid);
|
||||||
|
m_order.status = order::StatusType::Delivered.value();
|
||||||
|
backup(&m_order);
|
||||||
|
unwrap
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Decomposition trigger for `finalize_order()`
|
||||||
|
pub async fn d_trigger_finalize_request(contact: &String, orid: &String) -> reqres::FinalizeOrderResponse {
|
||||||
|
// ugh, sorry seems we need to get jwp for vendor from fts cache
|
||||||
|
// get jwp from db
|
||||||
|
let s = db::Interface::async_open().await;
|
||||||
|
let k = format!("{}-{}", crate::FTS_JWP_DB_KEY, &contact);
|
||||||
|
let jwp = db::Interface::async_read(&s.env, &s.handle, &k).await;
|
||||||
|
info!("executing d_trigger_finalize_request");
|
||||||
|
// request finalize if the order status is shipped
|
||||||
|
let order: Order = order::find(&orid);
|
||||||
|
if order.status != order::StatusType::Shipped.value() {
|
||||||
|
let trigger = trigger_finalize_request(contact, &jwp, orid).await;
|
||||||
|
if trigger.vendor_update_success {
|
||||||
|
return trigger;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Default::default()
|
||||||
|
}
|
||||||
|
|
||||||
/// Send order request to vendor and start multisig flow
|
/// Send order request to vendor and start multisig flow
|
||||||
pub async fn transmit_order_request(
|
pub async fn transmit_order_request(
|
||||||
contact: String,
|
contact: String,
|
||||||
|
@ -638,7 +745,7 @@ pub async fn transmit_cancel_request(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Decomposition trigger for the shipping request
|
/// Decomposition trigger for the cancel request
|
||||||
pub async fn d_trigger_cancel_request(contact: &String, orid: &String) -> Order {
|
pub async fn d_trigger_cancel_request(contact: &String, orid: &String) -> Order {
|
||||||
// ugh, sorry seems we need to get jwp for vendor from fts cache
|
// ugh, sorry seems we need to get jwp for vendor from fts cache
|
||||||
// get jwp from db
|
// get jwp from db
|
||||||
|
|
|
@ -106,7 +106,7 @@ pub struct XmrRpcGetTxByIdParams {
|
||||||
pub txid: String,
|
pub txid: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize, Debug)]
|
#[derive(Deserialize, Serialize, Debug, PartialEq)]
|
||||||
pub struct Destination {
|
pub struct Destination {
|
||||||
pub address: String,
|
pub address: String,
|
||||||
pub amount: u128,
|
pub amount: u128,
|
||||||
|
|
|
@ -111,8 +111,8 @@ pub struct MarketApp {
|
||||||
_refresh_on_delete_product_rx: Receiver<bool>,
|
_refresh_on_delete_product_rx: Receiver<bool>,
|
||||||
submit_order_tx: Sender<models::Order>,
|
submit_order_tx: Sender<models::Order>,
|
||||||
submit_order_rx: Receiver<models::Order>,
|
submit_order_rx: Receiver<models::Order>,
|
||||||
_submit_txset_tx: Sender<bool>,
|
submit_txset_tx: Sender<bool>,
|
||||||
_submit_txset_rx: Receiver<bool>,
|
submit_txset_rx: Receiver<bool>,
|
||||||
cancel_request_tx: Sender<models::Order>,
|
cancel_request_tx: Sender<models::Order>,
|
||||||
cancel_request_rx: Receiver<models::Order>,
|
cancel_request_rx: Receiver<models::Order>,
|
||||||
// ship_request_tx: Sender<models::Order>,
|
// ship_request_tx: Sender<models::Order>,
|
||||||
|
@ -144,7 +144,7 @@ impl Default for MarketApp {
|
||||||
let (our_make_info_tx, our_make_info_rx) = std::sync::mpsc::channel();
|
let (our_make_info_tx, our_make_info_rx) = std::sync::mpsc::channel();
|
||||||
let (order_xmr_address_tx, order_xmr_address_rx) = std::sync::mpsc::channel();
|
let (order_xmr_address_tx, order_xmr_address_rx) = std::sync::mpsc::channel();
|
||||||
let (order_funded_tx, order_funded_rx) = std::sync::mpsc::channel();
|
let (order_funded_tx, order_funded_rx) = std::sync::mpsc::channel();
|
||||||
let (_submit_txset_tx, _submit_txset_rx) = std::sync::mpsc::channel();
|
let (submit_txset_tx, submit_txset_rx) = std::sync::mpsc::channel();
|
||||||
let contents = std::fs::read("./assets/qr.png").unwrap_or(Vec::new());
|
let contents = std::fs::read("./assets/qr.png").unwrap_or(Vec::new());
|
||||||
MarketApp {
|
MarketApp {
|
||||||
contact_info_rx,
|
contact_info_rx,
|
||||||
|
@ -217,8 +217,8 @@ impl Default for MarketApp {
|
||||||
// ship_request_tx,
|
// ship_request_tx,
|
||||||
submit_order_rx,
|
submit_order_rx,
|
||||||
submit_order_tx,
|
submit_order_tx,
|
||||||
_submit_txset_rx,
|
submit_txset_rx,
|
||||||
_submit_txset_tx,
|
submit_txset_tx,
|
||||||
vendor_status: Default::default(),
|
vendor_status: Default::default(),
|
||||||
vendors: Vec::new(),
|
vendors: Vec::new(),
|
||||||
}
|
}
|
||||||
|
@ -332,6 +332,13 @@ impl eframe::App for MarketApp {
|
||||||
self.is_loading = false;
|
self.is_loading = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Ok(finalized) = self.submit_txset_rx.try_recv() {
|
||||||
|
if !finalized {
|
||||||
|
log::error!("failure to finalize shipment please contact vendor")
|
||||||
|
}
|
||||||
|
self.is_loading = false;
|
||||||
|
}
|
||||||
|
|
||||||
// Vendor status window
|
// Vendor status window
|
||||||
//-----------------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------------
|
||||||
let mut is_showing_vendor_status = self.is_showing_vendor_status;
|
let mut is_showing_vendor_status = self.is_showing_vendor_status;
|
||||||
|
@ -649,8 +656,7 @@ impl eframe::App for MarketApp {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if self.msig.completed_export && !self.msig.completed_shipping_request {
|
if self.msig.completed_export && !self.msig.completed_shipping_request {
|
||||||
// idk if manual shipping request will be necessary with the new nasr logic,
|
// idk if manual shipping request will be necessary with the new nasr logic
|
||||||
// let's see
|
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
ui.label(
|
ui.label(
|
||||||
RichText::new("Delivery Pending")
|
RichText::new("Delivery Pending")
|
||||||
|
@ -698,19 +704,18 @@ impl eframe::App for MarketApp {
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
ui.label("Release Payment: \t");
|
ui.label("Release Payment: \t");
|
||||||
if ui.button("Submit Txset").clicked() {
|
if ui.button("Submit Txset").clicked() {
|
||||||
|
self.is_loading = true;
|
||||||
|
let vendor_prefix = String::from(crate::GUI_OVL_DB_KEY);
|
||||||
|
let vendor =
|
||||||
|
utils::search_gui_db(vendor_prefix, self.m_order.orid.clone());
|
||||||
// async trigger for signing and submitted the txset
|
// async trigger for signing and submitted the txset
|
||||||
// do something
|
|
||||||
release_txset(
|
release_txset(
|
||||||
utils::empty_string(),
|
vendor,
|
||||||
utils::empty_string(),
|
self.m_order.orid.clone(),
|
||||||
ctx.clone(),
|
ctx.clone(),
|
||||||
utils::empty_string(),
|
self.submit_txset_tx.clone(),
|
||||||
self._submit_txset_tx.clone(),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if ui.button("Check").clicked() {
|
|
||||||
// the multisig wallet should have a zero balance if the sweep succeeded
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// ui.horizontal(|ui| {
|
// ui.horizontal(|ui| {
|
||||||
|
@ -2296,10 +2301,9 @@ fn validate_msig_step(
|
||||||
}
|
}
|
||||||
|
|
||||||
fn release_txset(
|
fn release_txset(
|
||||||
_contact: String,
|
contact: String,
|
||||||
orid: String,
|
orid: String,
|
||||||
ctx: egui::Context,
|
ctx: egui::Context,
|
||||||
_jwp: String,
|
|
||||||
tx: Sender<bool>,
|
tx: Sender<bool>,
|
||||||
) {
|
) {
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
|
@ -2311,12 +2315,9 @@ fn release_txset(
|
||||||
let _ = tx.send(false);
|
let _ = tx.send(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// TODO(c2m): we need to build an API that tells the vendor
|
let finalize = order::d_trigger_finalize_request(&contact, &orid).await;
|
||||||
// to verify the txset was submitted successfully
|
|
||||||
// return boolean.
|
|
||||||
|
|
||||||
// update order to delivered if success
|
// update order to delivered if success
|
||||||
let _ = tx.send(true);
|
let _ = tx.send(finalize.vendor_update_success);
|
||||||
ctx.request_repaint();
|
ctx.request_repaint();
|
||||||
todo!()
|
todo!()
|
||||||
});
|
});
|
||||||
|
|
|
@ -12,6 +12,7 @@ use rocket::{
|
||||||
use neveko_core::*;
|
use neveko_core::*;
|
||||||
|
|
||||||
// JSON APIs exposed over i2p
|
// JSON APIs exposed over i2p
|
||||||
|
// Take care not to put any admin APIs inside of here
|
||||||
|
|
||||||
/// Get payment API version
|
/// Get payment API version
|
||||||
///
|
///
|
||||||
|
@ -236,14 +237,28 @@ pub async fn cancel_order(
|
||||||
if m_order.cid == utils::empty_string() {
|
if m_order.cid == utils::empty_string() {
|
||||||
return Custom(Status::BadRequest, Json(Default::default()));
|
return Custom(Status::BadRequest, Json(Default::default()));
|
||||||
}
|
}
|
||||||
Custom(Status::Created, Json(m_order))
|
Custom(Status::Ok, Json(m_order))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a dispute (customer)
|
/// Customer finalize order logic. Vendor updates order
|
||||||
|
///
|
||||||
|
/// to `Delivered` status.
|
||||||
|
///
|
||||||
|
/// Protected: true
|
||||||
|
#[post("/order/finalize/<orid>")]
|
||||||
|
pub async fn finalize_order(orid: String, _jwp: proof::PaymentProof) -> Custom<Json<reqres::FinalizeOrderResponse>> {
|
||||||
|
let finalize = order::finalize_order(&orid).await;
|
||||||
|
if !finalize.vendor_update_success {
|
||||||
|
return Custom(Status::BadRequest, Json(Default::default()));
|
||||||
|
}
|
||||||
|
Custom(Status::Ok, Json(finalize))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a dispute
|
||||||
#[post("/create", data = "<dispute>")]
|
#[post("/create", data = "<dispute>")]
|
||||||
pub async fn create_dispute(
|
pub async fn create_dispute(
|
||||||
dispute: Json<models::Dispute>,
|
dispute: Json<models::Dispute>,
|
||||||
_token: auth::BearerToken,
|
_jwp: proof::PaymentProof,
|
||||||
) -> Custom<Json<models::Dispute>> {
|
) -> Custom<Json<models::Dispute>> {
|
||||||
let m_dispute: models::Dispute = dispute::create(dispute);
|
let m_dispute: models::Dispute = dispute::create(dispute);
|
||||||
Custom(Status::Ok, Json(m_dispute))
|
Custom(Status::Ok, Json(m_dispute))
|
||||||
|
|
|
@ -50,6 +50,7 @@ async fn rocket() -> _ {
|
||||||
controller::request_shipment,
|
controller::request_shipment,
|
||||||
controller::retrieve_order,
|
controller::retrieve_order,
|
||||||
controller::trigger_nasr,
|
controller::trigger_nasr,
|
||||||
|
controller::finalize_order,
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue