Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Range order fixes #286

Merged
merged 6 commits into from
May 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,10 @@ uuid = { version = "1.8.0", features = [
"serde",
] }
reqwest = { version = "0.12.1", features = ["json"] }
mostro-core = { version = "0.5.8", features = ["sqlx"] }
mostro-core = { version = "0.5.13", features = ["sqlx"] }
tracing = "0.1.40"
tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
config = "0.14.0"
clap = { version = "4.5.3", features = ["derive"] }
lnurl-rs = "0.5.0"
openssl = { version = "0.10", features = ["vendored"] }
openssl = { version = "0.10", features = ["vendored"] }
5 changes: 3 additions & 2 deletions src/app/add_invoice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,7 @@ pub async fn add_invoice_action(
Some(order.id),
Some(format!(
"You are not allowed to add an invoice because order Id {} status is {}",
order_status.to_string(),
order.id
order_status, order.id
)),
&buyer_pubkey,
)
Expand All @@ -134,6 +133,8 @@ pub async fn add_invoice_action(
Some(Status::Active),
order.amount,
order.fiat_code.clone(),
order.min_amount,
order.max_amount,
order.fiat_amount,
order.payment_method.clone(),
order.premium,
Expand Down
2 changes: 1 addition & 1 deletion src/app/admin_cancel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ pub async fn admin_cancel_action(
if order.status != Status::Dispute.to_string() {
let error = format!(
"Can't settle an order with status different than {}!",
Status::Dispute.to_string()
Status::Dispute
);
send_cant_do_msg(Some(order.id), Some(error), &event.pubkey).await;

Expand Down
2 changes: 1 addition & 1 deletion src/app/admin_settle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ pub async fn admin_settle_action(
if order.status != Status::Dispute.to_string() {
let error = format!(
"Can't settle an order with status different than {}!",
Status::Dispute.to_string()
Status::Dispute
);
send_cant_do_msg(Some(order.id), Some(error), &event.pubkey).await;

Expand Down
8 changes: 6 additions & 2 deletions src/app/admin_take_dispute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,12 @@ pub async fn admin_take_dispute_action(
};

let mut new_order = order.as_new_order();
new_order.master_buyer_pubkey = order.master_buyer_pubkey.clone();
new_order.master_seller_pubkey = order.master_seller_pubkey.clone();
new_order
.master_buyer_pubkey
.clone_from(&order.master_buyer_pubkey);
new_order
.master_seller_pubkey
.clone_from(&order.master_seller_pubkey);

// Update dispute fields
dispute.status = Status::InProgress.to_string();
Expand Down
51 changes: 32 additions & 19 deletions src/app/order.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,28 @@ pub async fn order_action(
}
}

let quote = match order.amount {
0 => match get_market_quote(&order.fiat_amount, &order.fiat_code, 0).await {
Ok(amount) => amount,
Err(e) => {
error!("{:?}", e.to_string());
return Ok(());
}
},
_ => order.amount,
};
// Default case single amount
let mut amount_vec = vec![order.fiat_amount];

// Get max and and min amount in case of range order
// in case of single order do like usual
if let (Some(min), Some(max)) = (order.min_amount, order.max_amount) {
amount_vec.clear();
amount_vec.push(min);
amount_vec.push(max);
}

for fiat_amount in amount_vec {
let quote = match order.amount {
0 => match get_market_quote(&fiat_amount, &order.fiat_code, 0).await {
Ok(amount) => amount,
Err(e) => {
error!("{:?}", e.to_string());
return Ok(());
}
},
_ => order.amount,
};

// Check amount is positive - extra safety check
if quote < 0 {
Expand All @@ -50,15 +62,16 @@ pub async fn order_action(
return Ok(());
}

if quote > mostro_settings.max_order_amount as i64
|| quote < mostro_settings.min_payment_amount as i64
{
let msg = format!(
"Quote is out of sats boundaries min is {} max is {}",
mostro_settings.min_payment_amount, mostro_settings.max_order_amount
);
send_cant_do_msg(order.id, Some(msg), &event.pubkey).await;
return Ok(());
if quote > mostro_settings.max_order_amount as i64
|| quote < mostro_settings.min_payment_amount as i64
{
let msg = format!(
"Quote is out of sats boundaries min is {} max is {}",
mostro_settings.min_payment_amount, mostro_settings.max_order_amount
);
send_cant_do_msg(order.id, Some(msg), &event.pubkey).await;
return Ok(());
}
}

let initiator_ephemeral_pubkey = event.pubkey.to_string();
Expand Down
85 changes: 80 additions & 5 deletions src/app/release.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use crate::util::{
get_keys, rate_counterpart, send_cant_do_msg, send_new_order_msg, settle_seller_hold_invoice,
update_order_event,
};
use crate::NOSTR_CLIENT;

use anyhow::{Error, Result};
use lnurl::lightning_address::LightningAddress;
Expand All @@ -14,6 +15,7 @@ use mostro_core::order::{Order, Status};
use nostr_sdk::prelude::*;
use sqlx::{Pool, Sqlite};
use sqlx_crud::Crud;
use std::cmp::Ordering;
use std::str::FromStr;
use tokio::sync::mpsc::channel;
use tonic_openssl_lnd::lnrpc::payment::PaymentStatus;
Expand Down Expand Up @@ -131,7 +133,7 @@ pub async fn release_action(
Ok(())
}

pub async fn do_payment(order: Order) -> Result<()> {
pub async fn do_payment(mut order: Order) -> Result<()> {
// Finally we try to pay buyer's invoice
let payment_request = match order.buyer_invoice.as_ref() {
Some(req) => req.to_string(),
Expand Down Expand Up @@ -182,9 +184,13 @@ pub async fn do_payment(order: Order) -> Result<()> {
"Order Id {}: Invoice with hash: {} paid!",
order.id, msg.payment.payment_hash
);
let _ =
payment_success(&order, &buyer_pubkey, &seller_pubkey, &my_keys)
.await;
let _ = payment_success(
&mut order,
&buyer_pubkey,
&seller_pubkey,
&my_keys,
)
.await;
}
PaymentStatus::Failed => {
info!(
Expand All @@ -211,7 +217,7 @@ pub async fn do_payment(order: Order) -> Result<()> {
}

async fn payment_success(
order: &Order,
order: &mut Order,
buyer_pubkey: &PublicKey,
seller_pubkey: &PublicKey,
my_keys: &Keys,
Expand All @@ -225,6 +231,75 @@ async fn payment_success(
)
.await;

// Check if order is range type
// Add parent range id and update max amount
if order.max_amount.is_some() && order.min_amount.is_some() {
if let Some(max) = order.max_amount {
if let Some(new_max) = max.checked_sub(order.fiat_amount) {
match new_max.cmp(&order.min_amount.unwrap()) {
Ordering::Equal => {
// Update order in case max == min
let pool = db::connect().await?;
let mut new_order = order.clone();
new_order.max_amount = None;
new_order.min_amount = None;
new_order.amount = 0;
new_order.fiat_amount = new_max;
new_order.status = Status::Pending.to_string();
new_order.id = uuid::Uuid::new_v4();
new_order.status = Status::Pending.to_string();
// CRUD order creation
new_order.clone().create(&pool).await?;
// We transform the order fields to tags to use in the event
let tags = crate::nip33::order_to_tags(&new_order);

info!("range order tags to be republished: {:#?}", tags);
// nip33 kind with order fields as tags and order id as identifier
let event =
crate::nip33::new_event(my_keys, "", new_order.id.to_string(), tags)?;

let _ = NOSTR_CLIENT
.get()
.unwrap()
.send_event(event)
.await
.map(|_s| ())
.map_err(|err| err.to_string());
}
Ordering::Greater => {
// Update order in case new max is still greater the min amount
let pool = db::connect().await?;
let mut new_order = order.clone();
new_order.max_amount = Some(new_max);
new_order.range_parent_id = Some(order.id);
new_order.amount = 0;
new_order.id = uuid::Uuid::new_v4();
new_order.status = Status::Pending.to_string();
// CRUD order creation
new_order.clone().create(&pool).await?;
// We transform the order fields to tags to use in the event
let tags = crate::nip33::order_to_tags(&new_order);

info!("range order tags to be republished: {:#?}", tags);
// nip33 kind with order fields as tags and order id as identifier
let event =
crate::nip33::new_event(my_keys, "", new_order.id.to_string(), tags)?;

let _ = NOSTR_CLIENT
.get()
.unwrap()
.send_event(event)
.await
.map(|_s| ())
.map_err(|err| err.to_string());
}
// Update order status in case new max is smaller the min amount
Ordering::Less => {}
}
}
}
}

// Let's wait 5 secs before publish this new event
tokio::time::sleep(tokio::time::Duration::from_secs(5)).await;
// We publish a new replaceable kind nostr event with the status updated
Expand Down
19 changes: 17 additions & 2 deletions src/app/take_buy.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::util::{
get_market_amount_and_fee, send_cant_do_msg, send_new_order_msg, show_hold_invoice,
get_fiat_amount_requested, get_market_amount_and_fee, send_cant_do_msg, send_new_order_msg,
show_hold_invoice,
};

use anyhow::{Error, Result};
Expand Down Expand Up @@ -48,6 +49,18 @@ pub async fn take_buy_action(
return Ok(());
}

// Get amount request if user requested one for range order - fiat amount will be used below
if let Some(am) = get_fiat_amount_requested(&order, &msg) {
order.fiat_amount = am;
} else {
let error = format!(
"Amount requested is not correct, probably out of range min {:#?} - max {:#?}",
order.min_amount, order.max_amount
);
send_cant_do_msg(Some(order.id), Some(error), &event.pubkey).await;
return Ok(());
}

let order_status = match Status::from_str(&order.status) {
Ok(s) => s,
Err(e) => {
Expand All @@ -67,7 +80,9 @@ pub async fn take_buy_action(
return Ok(());
}
// We update the master pubkey
order.master_seller_pubkey = msg.get_inner_message_kind().pubkey.clone();
order
.master_seller_pubkey
.clone_from(&msg.get_inner_message_kind().pubkey);

let seller_pubkey = event.pubkey;
// Seller can take pending orders only
Expand Down
20 changes: 17 additions & 3 deletions src/app/take_sell.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::lightning::invoice::is_valid_invoice;
use crate::util::{
get_market_amount_and_fee, send_cant_do_msg, send_dm, set_waiting_invoice_status,
show_hold_invoice, update_order_event,
get_fiat_amount_requested, get_market_amount_and_fee, send_cant_do_msg, send_dm,
set_waiting_invoice_status, show_hold_invoice, update_order_event,
};

use anyhow::{Error, Result};
Expand Down Expand Up @@ -32,6 +32,18 @@ pub async fn take_sell_action(
return Ok(());
}
};

// Get amount request if user requested one for range order - fiat amount will be used below
if let Some(am) = get_fiat_amount_requested(&order, &msg) {
order.fiat_amount = am;
} else {
let error = format!(
"Amount requested is not correct, probably out of range min {:#?} - max {:#?}",
order.min_amount, order.max_amount
);
send_cant_do_msg(Some(order.id), Some(error), &event.pubkey).await;
}

// Maker can't take own order
if order.creator_pubkey == event.pubkey.to_hex() {
send_cant_do_msg(Some(order.id), None, &event.pubkey).await;
Expand Down Expand Up @@ -99,7 +111,9 @@ pub async fn take_sell_action(
}

// We update the master pubkey
order.master_buyer_pubkey = msg.get_inner_message_kind().pubkey.clone();
order
.master_buyer_pubkey
.clone_from(&msg.get_inner_message_kind().pubkey);
// Add buyer pubkey to order
order.buyer_pubkey = Some(buyer_pubkey.to_string());
// Timestamp take order time
Expand Down
2 changes: 2 additions & 0 deletions src/flow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ pub async fn hold_invoice_paid(hash: &str) -> Result<()> {
None,
order.amount,
order.fiat_code.clone(),
order.min_amount,
order.max_amount,
order.fiat_amount,
order.payment_method.clone(),
order.premium,
Expand Down
Loading
Loading