From 9cde2c96497f8ed6294be1e9d4e9a30889c64364 Mon Sep 17 00:00:00 2001 From: arkanoider Date: Wed, 4 Dec 2024 22:22:43 +0100 Subject: [PATCH 01/31] mostro key management logic start --- Cargo.lock | 47 +++++++++++++++++++++++++---- Cargo.toml | 4 +++ migrations/20231005195154_users.sql | 3 +- src/app.rs | 25 +++++++++++++++ src/app/order.rs | 2 ++ src/db.rs | 15 +++++++++ 6 files changed, 89 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 75c92071..83fc253c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -376,14 +376,14 @@ dependencies = [ [[package]] name = "bitcoin" -version = "0.32.4" +version = "0.32.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "788902099d47c8682efe6a7afb01c8d58b9794ba66c06affd81c3d6b560743eb" +checksum = "ce6bc65742dea50536e35ad42492b234c27904a27f0abdcbce605015cb4ea026" dependencies = [ "base58ck", "bech32 0.11.0", "bitcoin-internals 0.3.0", - "bitcoin-io", + "bitcoin-io 0.1.3", "bitcoin-units", "bitcoin_hashes 0.14.0", "hex-conservative 0.2.1", @@ -407,12 +407,27 @@ dependencies = [ "serde", ] +[[package]] +name = "bitcoin-internals" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b854212e29b96c8f0fe04cab11d57586c8f3257de0d146c76cb3b42b3eb9118" + [[package]] name = "bitcoin-io" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b47c4ab7a93edb0c7198c5535ed9b52b63095f4e9b45279c6736cec4b856baf" +[[package]] +name = "bitcoin-io" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26792cd2bf245069a1c5acb06aa7ad7abe1de69b507c90b490bca81e0665d0ee" +dependencies = [ + "bitcoin-internals 0.4.0", +] + [[package]] name = "bitcoin-units" version = "0.1.2" @@ -439,11 +454,21 @@ version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb18c03d0db0247e147a21a6faafd5a7eb851c743db062de72018b6b7e8e4d16" dependencies = [ - "bitcoin-io", + "bitcoin-io 0.1.3", "hex-conservative 0.2.1", "serde", ] +[[package]] +name = "bitcoin_hashes" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0982261c82a50d89d1a411602afee0498b3e0debe3d36693f0c661352809639" +dependencies = [ + "bitcoin-io 0.2.0", + "hex-conservative 0.3.0", +] + [[package]] name = "bitflags" version = "1.3.2" @@ -1283,6 +1308,15 @@ dependencies = [ "arrayvec", ] +[[package]] +name = "hex-conservative" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4afe881d0527571892c4034822e59bb10c6c991cce6abe8199b6f5cf10766f55" +dependencies = [ + "arrayvec", +] + [[package]] name = "hex_lit" version = "0.1.1" @@ -1951,6 +1985,7 @@ name = "mostro" version = "0.12.8" dependencies = [ "anyhow", + "bitcoin", "chrono", "clap", "config", @@ -1976,10 +2011,10 @@ dependencies = [ [[package]] name = "mostro-core" version = "0.6.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3416a4220576cecb437ff5f22df995d296e022ab85ed541c385ba7bfc97d14bc" dependencies = [ "anyhow", + "bitcoin", + "bitcoin_hashes 0.15.0", "chrono", "nostr-sdk", "serde", diff --git a/Cargo.toml b/Cargo.toml index 596ff7a4..5e9fd137 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,3 +46,7 @@ clap = { version = "4.5.19", features = ["derive"] } lnurl-rs = "0.8.0" openssl = { version = "0.10.66", features = ["vendored"] } once_cell = "1.20.2" +bitcoin = "0.32.5" + +[patch.crates-io] +mostro-core = { path = "../mostro-core" } \ No newline at end of file diff --git a/migrations/20231005195154_users.sql b/migrations/20231005195154_users.sql index 47838581..7910bb47 100644 --- a/migrations/20231005195154_users.sql +++ b/migrations/20231005195154_users.sql @@ -5,5 +5,6 @@ CREATE TABLE IF NOT EXISTS users ( is_solver integer not null default 0, is_banned integer not null default 0, category integer not null default 0, - created_at integer not null + created_at integer not null, + trade_index integer not null default 0 ); \ No newline at end of file diff --git a/src/app.rs b/src/app.rs index b763d0eb..5834e3c6 100644 --- a/src/app.rs +++ b/src/app.rs @@ -43,6 +43,8 @@ use nostr_sdk::prelude::*; use sqlx::{Pool, Sqlite}; use std::sync::Arc; use tokio::sync::Mutex; +use mostro_core::user::User; +use sqlx_crud::Crud; /// Helper function to log warning messages for action errors fn warning_msg(action: &Action, e: anyhow::Error) { @@ -146,11 +148,34 @@ pub async fn run( continue; } + // Parse and process the message let message = Message::from_json(&event.rumor.content); match message { Ok(msg) => { if msg.get_inner_message_kind().verify() { + let is_trade_index = msg.get_inner_message_kind().trade_index.is_some; + // Function to search if user is yet present in db + match db::is_new_user(event.sender){ + Ok(user) => { + let next_trade_index = user.trade_index + 1; + if is_trade_index == next_trade_index { + user.trade_index = next_trade_index; + if msg.get_inner_message_kind().verify_content_signature(event.sender){ + if let Ok(user) = user.update(pool).await{ + tracing::info!("Update user trade index"); + } + } + } + }, + Err(_) => { + let new_user = User::new{ pubkey: event.sender, trade_index: next_trade_index, ..Default::default()}; + if let Ok(user) = new_user.update(pool).await{ + tracing::info!("Added new user for rate"); + } + }, + } + if let Some(action) = msg.inner_action() { if let Err(e) = handle_message_action( &action, diff --git a/src/app/order.rs b/src/app/order.rs index b256ca9c..5cc96071 100644 --- a/src/app/order.rs +++ b/src/app/order.rs @@ -18,6 +18,8 @@ pub async fn order_action( // Get request id let request_id = msg.get_inner_message_kind().request_id; + let pubkey_0 = event.sender + if let Some(order) = msg.get_inner_message_kind().get_order() { let mostro_settings = Settings::get_mostro(); diff --git a/src/db.rs b/src/db.rs index 7cf498c8..6a20d1e9 100644 --- a/src/db.rs +++ b/src/db.rs @@ -310,6 +310,21 @@ pub async fn find_solver_pubkey(pool: &SqlitePool, solver_npub: String) -> anyho Ok(user) } +pub async fn is_new_user(pool: &SqlitePool, npub: String) -> anyhow::Result { + let user = sqlx::query_as::<_, User>( + r#" + SELECT * + FROM users + WHERE pubkey == ?1 + "#, + ) + .bind(npub) + .fetch_one(pool) + .await?; + + Ok(user) +} + pub async fn is_assigned_solver( pool: &SqlitePool, solver_pubkey: &str, From 29776c4d10bee1a1a9c743c3a86e3b71464a2bd1 Mon Sep 17 00:00:00 2001 From: arkanoider Date: Thu, 5 Dec 2024 22:25:25 +0100 Subject: [PATCH 02/31] working on incoming messages with trade-index --- src/app.rs | 18 ++++++++---------- src/app/order.rs | 2 +- src/db.rs | 2 +- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/src/app.rs b/src/app.rs index 5834e3c6..753d1a66 100644 --- a/src/app.rs +++ b/src/app.rs @@ -45,7 +45,7 @@ use std::sync::Arc; use tokio::sync::Mutex; use mostro_core::user::User; use sqlx_crud::Crud; - +use crate::db::is_user_present; /// Helper function to log warning messages for action errors fn warning_msg(action: &Action, e: anyhow::Error) { tracing::warn!("Error in {} with context {}", action, e); @@ -147,29 +147,27 @@ pub async fn run( if event.rumor.created_at.as_u64() < since_time { continue; } - - + // Parse and process the message let message = Message::from_json(&event.rumor.content); match message { Ok(msg) => { if msg.get_inner_message_kind().verify() { - let is_trade_index = msg.get_inner_message_kind().trade_index.is_some; + let message_kind = msg.get_inner_message_kind(); // Function to search if user is yet present in db - match db::is_new_user(event.sender){ + match is_user_present(&pool, event.sender.to_string()).await{ Ok(user) => { - let next_trade_index = user.trade_index + 1; - if is_trade_index == next_trade_index { - user.trade_index = next_trade_index; + if user.trade_index < message_kind.get_trade_index() { + user.trade_index = message_kind.get_trade_index(); if msg.get_inner_message_kind().verify_content_signature(event.sender){ - if let Ok(user) = user.update(pool).await{ + if let Ok(user) = user.update(&pool).await{ tracing::info!("Update user trade index"); } } } }, Err(_) => { - let new_user = User::new{ pubkey: event.sender, trade_index: next_trade_index, ..Default::default()}; + let new_user = User::new{ pubkey: event.sender, trade_index: message_kind.get_trade_index(), ..Default::default()}; if let Ok(user) = new_user.update(pool).await{ tracing::info!("Added new user for rate"); } diff --git a/src/app/order.rs b/src/app/order.rs index 5cc96071..ecf3b51c 100644 --- a/src/app/order.rs +++ b/src/app/order.rs @@ -18,7 +18,7 @@ pub async fn order_action( // Get request id let request_id = msg.get_inner_message_kind().request_id; - let pubkey_0 = event.sender + let pubkey_0 = event.sender; if let Some(order) = msg.get_inner_message_kind().get_order() { let mostro_settings = Settings::get_mostro(); diff --git a/src/db.rs b/src/db.rs index 6a20d1e9..9613b00f 100644 --- a/src/db.rs +++ b/src/db.rs @@ -310,7 +310,7 @@ pub async fn find_solver_pubkey(pool: &SqlitePool, solver_npub: String) -> anyho Ok(user) } -pub async fn is_new_user(pool: &SqlitePool, npub: String) -> anyhow::Result { +pub async fn is_user_present(pool: &SqlitePool, npub: String) -> anyhow::Result { let user = sqlx::query_as::<_, User>( r#" SELECT * From e1dec18f77e6256e659c5f9d062cd3117b758a91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Francisco=20Calder=C3=B3n?= Date: Fri, 6 Dec 2024 16:49:06 -0300 Subject: [PATCH 03/31] bumps to mostro-core 0.6.12 use users.i0_pubkey as primary key fix is_user_present() --- Cargo.lock | 4 +++- Cargo.toml | 5 +---- migrations/20231005195154_users.sql | 3 +-- src/db.rs | 7 ++++--- 4 files changed, 9 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 83fc253c..2990ca6b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2010,7 +2010,9 @@ dependencies = [ [[package]] name = "mostro-core" -version = "0.6.11" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a7b93370ea527dbbb30fc754becccc21ce0ecd9a4332269d40f076f8de34946" dependencies = [ "anyhow", "bitcoin", diff --git a/Cargo.toml b/Cargo.toml index 5e9fd137..35644347 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,7 +38,7 @@ uuid = { version = "1.8.0", features = [ "serde", ] } reqwest = { version = "0.12.1", features = ["json"] } -mostro-core = { version = "0.6.11", features = ["sqlx"] } +mostro-core = { version = "0.6.12", features = ["sqlx"] } tracing = "0.1.40" tracing-subscriber = { version = "0.3.18", features = ["env-filter"] } config = "0.14.0" @@ -47,6 +47,3 @@ lnurl-rs = "0.8.0" openssl = { version = "0.10.66", features = ["vendored"] } once_cell = "1.20.2" bitcoin = "0.32.5" - -[patch.crates-io] -mostro-core = { path = "../mostro-core" } \ No newline at end of file diff --git a/migrations/20231005195154_users.sql b/migrations/20231005195154_users.sql index 7910bb47..02935a39 100644 --- a/migrations/20231005195154_users.sql +++ b/migrations/20231005195154_users.sql @@ -1,6 +1,5 @@ CREATE TABLE IF NOT EXISTS users ( - id char(36) primary key not null, - pubkey char(64) not null, + i0_pubkey char(64) primary key not null, is_admin integer not null default 0, is_solver integer not null default 0, is_banned integer not null default 0, diff --git a/src/db.rs b/src/db.rs index 9613b00f..9e8b5dab 100644 --- a/src/db.rs +++ b/src/db.rs @@ -310,15 +310,16 @@ pub async fn find_solver_pubkey(pool: &SqlitePool, solver_npub: String) -> anyho Ok(user) } -pub async fn is_user_present(pool: &SqlitePool, npub: String) -> anyhow::Result { +pub async fn is_user_present(pool: &SqlitePool, public_key: String) -> anyhow::Result { let user = sqlx::query_as::<_, User>( r#" SELECT * FROM users - WHERE pubkey == ?1 + WHERE i0_pubkey == ?1 + LIMIT 1 "#, ) - .bind(npub) + .bind(public_key) .fetch_one(pool) .await?; From 4d199c8b0ca07ea842ae69e91665f7bb0891dd03 Mon Sep 17 00:00:00 2001 From: arkanoider Date: Fri, 6 Dec 2024 22:44:37 +0100 Subject: [PATCH 04/31] Added parsing function in app.rs - not compiling --- Cargo.lock | 2 - Cargo.toml | 3 ++ migrations/20231005195154_users.sql | 2 +- src/app.rs | 67 ++++++++++++++++++----------- 4 files changed, 45 insertions(+), 29 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2990ca6b..99a24c66 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2011,8 +2011,6 @@ dependencies = [ [[package]] name = "mostro-core" version = "0.6.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a7b93370ea527dbbb30fc754becccc21ce0ecd9a4332269d40f076f8de34946" dependencies = [ "anyhow", "bitcoin", diff --git a/Cargo.toml b/Cargo.toml index 35644347..9094606b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,3 +47,6 @@ lnurl-rs = "0.8.0" openssl = { version = "0.10.66", features = ["vendored"] } once_cell = "1.20.2" bitcoin = "0.32.5" + +[patch.crates-io] +mostro-core = { path = "../mostro-core" } diff --git a/migrations/20231005195154_users.sql b/migrations/20231005195154_users.sql index 02935a39..281adcdb 100644 --- a/migrations/20231005195154_users.sql +++ b/migrations/20231005195154_users.sql @@ -1,5 +1,5 @@ CREATE TABLE IF NOT EXISTS users ( - i0_pubkey char(64) primary key not null, + pubkey char(64) primary key not null, is_admin integer not null default 0, is_solver integer not null default 0, is_banned integer not null default 0, diff --git a/src/app.rs b/src/app.rs index 753d1a66..57ab175f 100644 --- a/src/app.rs +++ b/src/app.rs @@ -37,20 +37,55 @@ use crate::nip59::unwrap_gift_wrap; use crate::Settings; // External dependencies +use crate::db::is_user_present; use anyhow::Result; use mostro_core::message::{Action, Message}; +use mostro_core::user::User; use nostr_sdk::prelude::*; use sqlx::{Pool, Sqlite}; +use sqlx_crud::Crud; use std::sync::Arc; use tokio::sync::Mutex; -use mostro_core::user::User; -use sqlx_crud::Crud; -use crate::db::is_user_present; /// Helper function to log warning messages for action errors fn warning_msg(action: &Action, e: anyhow::Error) { tracing::warn!("Error in {} with context {}", action, e); } +/// Function to search if user is yet present in db +async fn process_message(pool: &Pool, event: &UnwrappedGift, msg: Message) { + let message_kind = msg.get_inner_message_kind(); + if let Action::NewOrder | Action::TakeBuy | Action::TakeSell = message_kind.action { + match is_user_present(&pool, event.sender.to_string()).await { + Ok(mut user) => { + if let (true, index) = message_kind.has_trade_index() { + if index > user.trade_index + && msg + .get_inner_message_kind() + .verify_content_signature(event.sender) + { + user.trade_index = index; + if let Ok(_) = user.update(&pool).await { + tracing::info!("Update user trade index"); + } + } + } + } + Err(_) => { + if let (true, trade_index) = message_kind.has_trade_index() { + let new_user = User { + pubkey: event.sender.to_string(), + trade_index, + ..Default::default() + }; + if let Ok(_) = new_user.update(&pool).await { + tracing::info!("Added new user for rate"); + } + } + } + } + } +} + /// Handles the processing of a single message action by routing it to the appropriate handler /// based on the action type. This is the core message routing logic of the application. /// @@ -147,33 +182,13 @@ pub async fn run( if event.rumor.created_at.as_u64() < since_time { continue; } - + // Parse and process the message let message = Message::from_json(&event.rumor.content); match message { Ok(msg) => { - if msg.get_inner_message_kind().verify() { - let message_kind = msg.get_inner_message_kind(); - // Function to search if user is yet present in db - match is_user_present(&pool, event.sender.to_string()).await{ - Ok(user) => { - if user.trade_index < message_kind.get_trade_index() { - user.trade_index = message_kind.get_trade_index(); - if msg.get_inner_message_kind().verify_content_signature(event.sender){ - if let Ok(user) = user.update(&pool).await{ - tracing::info!("Update user trade index"); - } - } - } - }, - Err(_) => { - let new_user = User::new{ pubkey: event.sender, trade_index: message_kind.get_trade_index(), ..Default::default()}; - if let Ok(user) = new_user.update(pool).await{ - tracing::info!("Added new user for rate"); - } - }, - } - + let message_kind = msg.get_inner_message_kind(); + if message_kind.verify() { if let Some(action) = msg.inner_action() { if let Err(e) = handle_message_action( &action, From 99248980988cf527ff42c08de0ea85615ffee376 Mon Sep 17 00:00:00 2001 From: arkanoider Date: Sun, 8 Dec 2024 21:21:40 +0100 Subject: [PATCH 05/31] working on key management - added initial check on messages and started to update all commands - TBD --- migrations/20221222153301_orders.sql | 5 +- src/app/add_invoice.rs | 5 ++ src/app/fiat_sent.rs | 3 + src/app/order.rs | 6 +- src/app/take_buy.rs | 2 + src/app/take_sell.rs | 2 + src/util.rs | 96 +++++++++++++++++----------- 7 files changed, 77 insertions(+), 42 deletions(-) diff --git a/migrations/20221222153301_orders.sql b/migrations/20221222153301_orders.sql index 12bb8939..eb513503 100644 --- a/migrations/20221222153301_orders.sql +++ b/migrations/20221222153301_orders.sql @@ -35,5 +35,6 @@ CREATE TABLE IF NOT EXISTS orders ( seller_sent_rate integer default 0, payment_attempts integer default 0, failed_payment integer default 0, - expires_at integer not null -); \ No newline at end of file + expires_at integer not null, + trade_index integer default 0 +); diff --git a/src/app/add_invoice.rs b/src/app/add_invoice.rs index f928bd27..ae0a74ac 100644 --- a/src/app/add_invoice.rs +++ b/src/app/add_invoice.rs @@ -83,6 +83,7 @@ pub async fn add_invoice_action( Action::IncorrectInvoiceAmount, None, &event.sender, + None, ) .await; return Ok(()); @@ -107,6 +108,7 @@ pub async fn add_invoice_action( Action::InvoiceUpdated, None, &buyer_pubkey, + None, ) .await; return Ok(()); @@ -118,6 +120,7 @@ pub async fn add_invoice_action( Action::NotAllowedByStatus, None, &event.sender, + None, ) .await; return Ok(()); @@ -163,6 +166,7 @@ pub async fn add_invoice_action( Action::BuyerTookOrder, Some(Content::Order(order_data.clone())), &seller_pubkey, + None, ) .await; // We send a message to buyer saying seller paid @@ -172,6 +176,7 @@ pub async fn add_invoice_action( Action::HoldInvoicePaymentAccepted, Some(Content::Order(order_data)), &buyer_pubkey, + None, ) .await; } else { diff --git a/src/app/fiat_sent.rs b/src/app/fiat_sent.rs index 49e418b1..42df0f6f 100644 --- a/src/app/fiat_sent.rs +++ b/src/app/fiat_sent.rs @@ -39,6 +39,7 @@ pub async fn fiat_sent_action( Action::NotAllowedByStatus, None, &event.sender, + None, ) .await; return Ok(()); @@ -71,6 +72,7 @@ pub async fn fiat_sent_action( Action::FiatSentOk, Some(Content::Peer(peer)), &seller_pubkey, + None, ) .await; // We send a message to buyer to wait @@ -82,6 +84,7 @@ pub async fn fiat_sent_action( Action::FiatSentOk, Some(Content::Peer(peer)), &event.sender, + None, ) .await; diff --git a/src/app/order.rs b/src/app/order.rs index ecf3b51c..2fdd58d5 100644 --- a/src/app/order.rs +++ b/src/app/order.rs @@ -18,8 +18,6 @@ pub async fn order_action( // Get request id let request_id = msg.get_inner_message_kind().request_id; - let pubkey_0 = event.sender; - if let Some(order) = msg.get_inner_message_kind().get_order() { let mostro_settings = Settings::get_mostro(); @@ -36,6 +34,7 @@ pub async fn order_action( Action::IncorrectInvoiceAmount, None, &event.sender, + None, ) .await; return Ok(()); @@ -92,6 +91,7 @@ pub async fn order_action( Action::InvalidSatsAmount, None, &event.sender, + None, ) .await; return Ok(()); @@ -106,6 +106,7 @@ pub async fn order_action( Action::OutOfRangeSatsAmount, None, &event.sender, + None, ) .await; return Ok(()); @@ -119,6 +120,7 @@ pub async fn order_action( &event.sender.to_string(), event.sender, request_id, + msg.get_inner_message_kind().trade_index, ) .await?; } diff --git a/src/app/take_buy.rs b/src/app/take_buy.rs index 88ae886c..4e98c3fb 100644 --- a/src/app/take_buy.rs +++ b/src/app/take_buy.rs @@ -69,6 +69,7 @@ pub async fn take_buy_action( Action::NotAllowedByStatus, None, &seller_pubkey, + None, ) .await; return Ok(()); @@ -85,6 +86,7 @@ pub async fn take_buy_action( Action::OutOfRangeFiatAmount, None, &event.sender, + None, ) .await; return Ok(()); diff --git a/src/app/take_sell.rs b/src/app/take_sell.rs index d9afd3b3..6e3793f0 100644 --- a/src/app/take_sell.rs +++ b/src/app/take_sell.rs @@ -101,6 +101,7 @@ pub async fn take_sell_action( Action::NotAllowedByStatus, None, &buyer_pubkey, + None, ) .await; return Ok(()); @@ -117,6 +118,7 @@ pub async fn take_sell_action( Action::OutOfRangeFiatAmount, None, &event.sender, + None, ) .await; return Ok(()); diff --git a/src/util.rs b/src/util.rs index 16d938d7..95f361ff 100644 --- a/src/util.rs +++ b/src/util.rs @@ -21,6 +21,7 @@ use nostr_sdk::prelude::*; use sqlx::SqlitePool; use sqlx_crud::Crud; use std::fmt::Write; +use std::path::is_separator; use std::str::FromStr; use std::sync::Arc; use std::thread; @@ -163,44 +164,10 @@ pub async fn publish_order( initiator_pubkey: &str, ack_pubkey: PublicKey, request_id: Option, + trade_index: Option, ) -> Result<()> { - let mut fee = 0; - if new_order.amount > 0 { - fee = get_fee(new_order.amount); - } - - // Get expiration time of the order - let expiry_date = get_expiration_date(new_order.expires_at); - // Prepare a new default order - let mut new_order_db = Order { - id: Uuid::new_v4(), - kind: OrderKind::Sell.to_string(), - status: Status::Pending.to_string(), - creator_pubkey: initiator_pubkey.to_string(), - payment_method: new_order.payment_method.clone(), - amount: new_order.amount, - fee, - fiat_code: new_order.fiat_code.clone(), - min_amount: new_order.min_amount, - max_amount: new_order.max_amount, - fiat_amount: new_order.fiat_amount, - premium: new_order.premium, - buyer_invoice: new_order.buyer_invoice.clone(), - created_at: Timestamp::now().as_u64() as i64, - expires_at: expiry_date, - ..Default::default() - }; - - if new_order.kind == Some(OrderKind::Buy) { - new_order_db.kind = OrderKind::Buy.to_string(); - new_order_db.buyer_pubkey = Some(initiator_pubkey.to_string()); - } else { - new_order_db.seller_pubkey = Some(initiator_pubkey.to_string()); - } - - // Request price from API in case amount is 0 - new_order_db.price_from_api = new_order.amount == 0; + let new_order_db = prepare_new_order(new_order, initiator_pubkey, trade_index).await?; // CRUD order creation let mut order = new_order_db.clone().create(pool).await?; @@ -228,6 +195,7 @@ pub async fn publish_order( Action::NewOrder, Some(Content::Order(order)), &ack_pubkey, + trade_index, ) .await; @@ -240,6 +208,54 @@ pub async fn publish_order( .map_err(|err| err.into()) } +async fn prepare_new_order( + new_order: &SmallOrder, + initiator_pubkey: &str, + trade_index: Option, +) -> Result { + let mut fee = 0; + if new_order.amount > 0 { + fee = get_fee(new_order.amount); + } + + // Get expiration time of the order + let expiry_date = get_expiration_date(new_order.expires_at); + + // Prepare a new default order + let mut new_order_db = Order { + id: Uuid::new_v4(), + kind: OrderKind::Sell.to_string(), + status: Status::Pending.to_string(), + creator_pubkey: initiator_pubkey.to_string(), + payment_method: new_order.payment_method.clone(), + amount: new_order.amount, + fee, + fiat_code: new_order.fiat_code.clone(), + min_amount: new_order.min_amount, + max_amount: new_order.max_amount, + fiat_amount: new_order.fiat_amount, + premium: new_order.premium, + buyer_invoice: new_order.buyer_invoice.clone(), + created_at: Timestamp::now().as_u64() as i64, + expires_at: expiry_date, + ..Default::default() + }; + + if new_order.kind == Some(OrderKind::Buy) { + new_order_db.kind = OrderKind::Buy.to_string(); + new_order_db.buyer_pubkey = Some(initiator_pubkey.to_string()); + new_order_db.trade_index_buyer = trade_index; + } else { + new_order_db.seller_pubkey = Some(initiator_pubkey.to_string()); + new_order_db.trade_index_seller = trade_index; + } + + // Request price from API in case amount is 0 + new_order_db.price_from_api = new_order.amount == 0; + + Ok(new_order_db) +} + pub async fn send_dm( receiver_pubkey: &PublicKey, sender_keys: Keys, @@ -409,6 +425,7 @@ pub async fn show_hold_invoice( None, )), seller_pubkey, + None, ) .await; // We send a message to buyer to know that seller was requested to pay the invoice @@ -418,6 +435,7 @@ pub async fn show_hold_invoice( Action::WaitingSellerToPay, None, buyer_pubkey, + None, ) .await; @@ -521,6 +539,7 @@ pub async fn set_waiting_invoice_status( Action::AddInvoice, Some(Content::Order(order_data)), &buyer_pubkey, + None, ) .await; @@ -594,7 +613,7 @@ pub async fn send_cant_do_msg( let content = message.map(Content::TextMessage); // Send message to event creator - let message = Message::cant_do(request_id, order_id, content); + let message = Message::cant_do(request_id, order_id, content, None); if let Ok(message) = message.as_json() { let sender_keys = crate::util::get_keys().unwrap(); let _ = send_dm(destination_key, sender_keys, message).await; @@ -607,9 +626,10 @@ pub async fn send_new_order_msg( action: Action, content: Option, destination_key: &PublicKey, + trade_index: Option, ) { // Send message to event creator - let message = Message::new_order(request_id, order_id, action, content); + let message = Message::new_order(request_id, order_id, None, action, content, None); if let Ok(message) = message.as_json() { let sender_keys = crate::util::get_keys().unwrap(); let _ = send_dm(destination_key, sender_keys, message).await; From 7596afabae78f3850a90d54d454af4feafd96d41 Mon Sep 17 00:00:00 2001 From: arkanoider Date: Sun, 8 Dec 2024 21:38:58 +0100 Subject: [PATCH 06/31] small fixes on CRUD and messages - need message fixing and improvement --- src/app.rs | 2 +- src/util.rs | 19 ++++++++++++++----- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/app.rs b/src/app.rs index 57ab175f..e7d6f51c 100644 --- a/src/app.rs +++ b/src/app.rs @@ -77,7 +77,7 @@ async fn process_message(pool: &Pool, event: &UnwrappedGift, msg: Messag trade_index, ..Default::default() }; - if let Ok(_) = new_user.update(&pool).await { + if let Ok(_) = new_user.create(&pool).await { tracing::info!("Added new user for rate"); } } diff --git a/src/util.rs b/src/util.rs index 95f361ff..5a711301 100644 --- a/src/util.rs +++ b/src/util.rs @@ -555,7 +555,15 @@ pub async fn rate_counterpart( ) -> Result<()> { // Send dm to counterparts // to buyer - send_new_order_msg(request_id, Some(order.id), Action::Rate, None, buyer_pubkey).await; + send_new_order_msg( + request_id, + Some(order.id), + Action::Rate, + None, + buyer_pubkey, + None, + ) + .await; // to seller send_new_order_msg( request_id, @@ -563,6 +571,7 @@ pub async fn rate_counterpart( Action::Rate, None, seller_pubkey, + None, ) .await; @@ -581,7 +590,7 @@ pub async fn settle_seller_hold_invoice( ) -> Result<()> { // Check if the pubkey is right if !is_admin && event.sender.to_string() != *order.seller_pubkey.as_ref().unwrap().to_string() { - send_cant_do_msg(request_id, Some(order.id), None, &event.sender).await; + send_cant_do_msg(request_id, Some(order.id), None, &event.sender, None).await; return Err(Error::msg("Not allowed")); } @@ -590,7 +599,7 @@ pub async fn settle_seller_hold_invoice( ln_client.settle_hold_invoice(preimage).await?; info!("{action}: Order Id {}: hold invoice settled", order.id); } else { - send_cant_do_msg(request_id, Some(order.id), None, &event.sender).await; + send_cant_do_msg(request_id, Some(order.id), None, &event.sender, None).await; return Err(Error::msg("No preimage")); } Ok(()) @@ -613,7 +622,7 @@ pub async fn send_cant_do_msg( let content = message.map(Content::TextMessage); // Send message to event creator - let message = Message::cant_do(request_id, order_id, content, None); + let message = Message::cant_do(order_id, request_id, content, None); if let Ok(message) = message.as_json() { let sender_keys = crate::util::get_keys().unwrap(); let _ = send_dm(destination_key, sender_keys, message).await; @@ -629,7 +638,7 @@ pub async fn send_new_order_msg( trade_index: Option, ) { // Send message to event creator - let message = Message::new_order(request_id, order_id, None, action, content, None); + let message = Message::new_order(order_id, request_id, trade_index, action, content, None); if let Ok(message) = message.as_json() { let sender_keys = crate::util::get_keys().unwrap(); let _ = send_dm(destination_key, sender_keys, message).await; From 76b34745ef87535dfc3a7ca3420c7f7c07f71822 Mon Sep 17 00:00:00 2001 From: arkanoider Date: Sun, 8 Dec 2024 22:02:23 +0100 Subject: [PATCH 07/31] typos cant-do --- src/util.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/util.rs b/src/util.rs index 5a711301..da95d14e 100644 --- a/src/util.rs +++ b/src/util.rs @@ -590,7 +590,7 @@ pub async fn settle_seller_hold_invoice( ) -> Result<()> { // Check if the pubkey is right if !is_admin && event.sender.to_string() != *order.seller_pubkey.as_ref().unwrap().to_string() { - send_cant_do_msg(request_id, Some(order.id), None, &event.sender, None).await; + send_cant_do_msg(request_id, Some(order.id), None, &event.sender).await; return Err(Error::msg("Not allowed")); } @@ -599,7 +599,7 @@ pub async fn settle_seller_hold_invoice( ln_client.settle_hold_invoice(preimage).await?; info!("{action}: Order Id {}: hold invoice settled", order.id); } else { - send_cant_do_msg(request_id, Some(order.id), None, &event.sender, None).await; + send_cant_do_msg(request_id, Some(order.id), None, &event.sender).await; return Err(Error::msg("No preimage")); } Ok(()) From db7e1be78ea3db6625631c02687e9f0275683a40 Mon Sep 17 00:00:00 2001 From: arkanoider Date: Mon, 9 Dec 2024 19:00:25 +0100 Subject: [PATCH 08/31] fixing trade index in take sell and take buy --- src/app/take_buy.rs | 2 ++ src/app/take_sell.rs | 1 + 2 files changed, 3 insertions(+) diff --git a/src/app/take_buy.rs b/src/app/take_buy.rs index 4e98c3fb..37b00f80 100644 --- a/src/app/take_buy.rs +++ b/src/app/take_buy.rs @@ -101,6 +101,8 @@ pub async fn take_buy_action( order.fee = fee; } + // Update trade index for seller + order.trade_index_seller = msg.get_inner_message_kind().trade_index; // Timestamp order take time order.taken_at = Timestamp::now().as_u64() as i64; diff --git a/src/app/take_sell.rs b/src/app/take_sell.rs index 6e3793f0..a9296519 100644 --- a/src/app/take_sell.rs +++ b/src/app/take_sell.rs @@ -126,6 +126,7 @@ pub async fn take_sell_action( // Add buyer pubkey to order order.buyer_pubkey = Some(buyer_pubkey.to_string()); + order.trade_index_buyer = msg.get_inner_message_kind().trade_index; // Timestamp take order time order.taken_at = Timestamp::now().as_u64() as i64; From e3e4ebf591af9f6f3919d0b09ac012b6f2d704e5 Mon Sep 17 00:00:00 2001 From: arkanoider Date: Mon, 9 Dec 2024 19:01:38 +0100 Subject: [PATCH 09/31] adding trade index in msg in show hold invoice --- src/util.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/util.rs b/src/util.rs index da95d14e..cfcf23ae 100644 --- a/src/util.rs +++ b/src/util.rs @@ -425,7 +425,7 @@ pub async fn show_hold_invoice( None, )), seller_pubkey, - None, + order.trade_index_seller, ) .await; // We send a message to buyer to know that seller was requested to pay the invoice @@ -435,7 +435,7 @@ pub async fn show_hold_invoice( Action::WaitingSellerToPay, None, buyer_pubkey, - None, + order.trade_index_buyer, ) .await; @@ -539,7 +539,7 @@ pub async fn set_waiting_invoice_status( Action::AddInvoice, Some(Content::Order(order_data)), &buyer_pubkey, - None, + order.trade_index_buyer, ) .await; From 693cb9c5f0ec7bb4d204ce06e86c5e08aa260a96 Mon Sep 17 00:00:00 2001 From: arkanoider Date: Mon, 9 Dec 2024 22:20:19 +0100 Subject: [PATCH 10/31] rough refactoring of MessageKind with new Payload field - TBD --- Cargo.lock | 4 +++- Cargo.toml | 6 +++--- src/app.rs | 2 +- src/app/add_invoice.rs | 6 +++--- src/app/admin_add_solver.rs | 8 ++++---- src/app/admin_take_dispute.rs | 21 ++++++++++++++------- src/app/cancel.rs | 11 +++++++++-- src/app/dispute.rs | 8 +++++--- src/app/fiat_sent.rs | 6 +++--- src/app/rate_user.rs | 6 +++--- src/app/release.rs | 5 ++++- src/flow.rs | 8 ++++---- src/util.rs | 14 +++++++------- 13 files changed, 63 insertions(+), 42 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 99a24c66..29738fea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2010,7 +2010,9 @@ dependencies = [ [[package]] name = "mostro-core" -version = "0.6.12" +version = "0.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "789e88b48f35ab22d655d2ebf0674b4c3b4f31e4ee5f3c965398becb3bf9ead7" dependencies = [ "anyhow", "bitcoin", diff --git a/Cargo.toml b/Cargo.toml index 9094606b..1a0e42bb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,7 +38,7 @@ uuid = { version = "1.8.0", features = [ "serde", ] } reqwest = { version = "0.12.1", features = ["json"] } -mostro-core = { version = "0.6.12", features = ["sqlx"] } +mostro-core = { version = "0.6.13", features = ["sqlx"] } tracing = "0.1.40" tracing-subscriber = { version = "0.3.18", features = ["env-filter"] } config = "0.14.0" @@ -48,5 +48,5 @@ openssl = { version = "0.10.66", features = ["vendored"] } once_cell = "1.20.2" bitcoin = "0.32.5" -[patch.crates-io] -mostro-core = { path = "../mostro-core" } +# [patch.crates-io] +# mostro-core = { path = "../mostro-core" } diff --git a/src/app.rs b/src/app.rs index e7d6f51c..720889f4 100644 --- a/src/app.rs +++ b/src/app.rs @@ -61,7 +61,7 @@ async fn process_message(pool: &Pool, event: &UnwrappedGift, msg: Messag if index > user.trade_index && msg .get_inner_message_kind() - .verify_content_signature(event.sender) + .verify_signature(event.sender, event.rumor.content.) { user.trade_index = index; if let Ok(_) = user.update(&pool).await { diff --git a/src/app/add_invoice.rs b/src/app/add_invoice.rs index ae0a74ac..edb47edb 100644 --- a/src/app/add_invoice.rs +++ b/src/app/add_invoice.rs @@ -3,7 +3,7 @@ use crate::util::{send_cant_do_msg, send_new_order_msg, show_hold_invoice, updat use anyhow::{Error, Result}; -use mostro_core::message::{Action, Content, Message}; +use mostro_core::message::{Action, Payload, Message}; use mostro_core::order::SmallOrder; use mostro_core::order::{Kind, Order, Status}; use nostr::nips::nip59::UnwrappedGift; @@ -164,7 +164,7 @@ pub async fn add_invoice_action( None, Some(order.id), Action::BuyerTookOrder, - Some(Content::Order(order_data.clone())), + Some(Payload::Order(order_data.clone())), &seller_pubkey, None, ) @@ -174,7 +174,7 @@ pub async fn add_invoice_action( request_id, Some(order.id), Action::HoldInvoicePaymentAccepted, - Some(Content::Order(order_data)), + Some(Payload::Order(order_data)), &buyer_pubkey, None, ) diff --git a/src/app/admin_add_solver.rs b/src/app/admin_add_solver.rs index 983e1302..204ef66f 100644 --- a/src/app/admin_add_solver.rs +++ b/src/app/admin_add_solver.rs @@ -1,7 +1,7 @@ use crate::util::{send_cant_do_msg, send_dm}; use anyhow::Result; -use mostro_core::message::{Action, Content, Message}; +use mostro_core::message::{Action, Payload, Message}; use mostro_core::user::User; use nostr::nips::nip59::UnwrappedGift; use nostr_sdk::prelude::*; @@ -25,7 +25,7 @@ pub async fn admin_add_solver_action( error!("No pubkey found!"); return Ok(()); }; - let npubkey = if let Content::TextMessage(p) = content { + let npubkey = if let Payload::TextMessage(p) = content { p } else { error!("No pubkey found!"); @@ -39,14 +39,14 @@ pub async fn admin_add_solver_action( return Ok(()); } let public_key = PublicKey::from_bech32(npubkey)?.to_hex(); - let user = User::new(public_key, 0, 1, 0, 0); + let user = User::new(public_key, 0, 1, 0, 0, None); // Use CRUD to create user match user.create(pool).await { Ok(r) => info!("Solver added: {:#?}", r), Err(ee) => error!("Error creating solver: {:#?}", ee), } // We create a Message for admin - let message = Message::new_dispute(request_id, None, Action::AdminAddSolver, None); + let message = Message::new_dispute(request_id, None, None, Action::AdminAddSolver, None, None); let message = message.as_json()?; // Send the message let sender_keys = crate::util::get_keys().unwrap(); diff --git a/src/app/admin_take_dispute.rs b/src/app/admin_take_dispute.rs index 072b91f8..520e6cb9 100644 --- a/src/app/admin_take_dispute.rs +++ b/src/app/admin_take_dispute.rs @@ -4,7 +4,7 @@ use crate::util::{get_nostr_client, send_cant_do_msg, send_dm, send_new_order_ms use anyhow::{Error, Result}; use mostro_core::dispute::{Dispute, Status}; -use mostro_core::message::{Action, Content, Message, Peer}; +use mostro_core::message::{Action, Payload, Message, Peer}; use mostro_core::order::Order; use nostr::nips::nip59::UnwrappedGift; use nostr_sdk::prelude::*; @@ -63,6 +63,7 @@ pub async fn admin_take_dispute_action( Action::NotFound, None, &event.sender, + None ) .await; return Ok(()); @@ -107,10 +108,12 @@ pub async fn admin_take_dispute_action( // We create a Message for admin let message = Message::new_dispute( - request_id, Some(dispute_id), + request_id, + None, Action::AdminTookDispute, - Some(Content::Order(new_order)), + Some(Payload::Order(new_order)), + None, ); let message = message.as_json()?; let sender_keys = crate::util::get_keys().unwrap(); @@ -119,17 +122,21 @@ pub async fn admin_take_dispute_action( // to them know who will assist them on the dispute let solver_pubkey = Peer::new(event.sender.to_hex()); let msg_to_buyer = Message::new_order( - None, Some(order.id), + request_id, + None, Action::AdminTookDispute, - Some(Content::Peer(solver_pubkey.clone())), + Some(Payload::Peer(solver_pubkey.clone())), + None, ); let msg_to_seller = Message::new_order( - None, Some(order.id), + request_id, + None, Action::AdminTookDispute, - Some(Content::Peer(solver_pubkey)), + Some(Payload::Peer(solver_pubkey)), + None, ); let (seller_pubkey, buyer_pubkey) = match (&order.seller_pubkey, &order.buyer_pubkey) { diff --git a/src/app/cancel.rs b/src/app/cancel.rs index ab5dbc21..fc7a26b6 100644 --- a/src/app/cancel.rs +++ b/src/app/cancel.rs @@ -65,6 +65,7 @@ pub async fn cancel_action( Action::Canceled, None, &event.sender, + None ) .await; } @@ -132,6 +133,7 @@ pub async fn cancel_action( Action::CooperativeCancelAccepted, None, &event.sender, + None ) .await; let counterparty_pubkey = PublicKey::from_str(&counterparty_pubkey)?; @@ -141,6 +143,7 @@ pub async fn cancel_action( Action::CooperativeCancelAccepted, None, &counterparty_pubkey, + None ) .await; info!("Cancel: Order Id {order_id} canceled cooperatively!"); @@ -157,6 +160,7 @@ pub async fn cancel_action( Action::CooperativeCancelInitiatedByYou, None, &event.sender, + None ) .await; let counterparty_pubkey = PublicKey::from_str(&counterparty_pubkey)?; @@ -166,6 +170,7 @@ pub async fn cancel_action( Action::CooperativeCancelInitiatedByPeer, None, &counterparty_pubkey, + None ) .await; } @@ -212,9 +217,10 @@ pub async fn cancel_add_invoice( Action::Canceled, None, &event.sender, + None ) .await; - send_new_order_msg(None, Some(order.id), Action::Canceled, None, &seller_pubkey).await; + send_new_order_msg(None, Some(order.id), Action::Canceled, None, &seller_pubkey, None).await; Ok(()) } else { // We re-publish the event with Pending status @@ -274,9 +280,10 @@ pub async fn cancel_pay_hold_invoice( Action::Canceled, None, &event.sender, + None ) .await; - send_new_order_msg(None, Some(order.id), Action::Canceled, None, &seller_pubkey).await; + send_new_order_msg(None, Some(order.id), Action::Canceled, None, &seller_pubkey, None).await; Ok(()) } else { // We re-publish the event with Pending status diff --git a/src/app/dispute.rs b/src/app/dispute.rs index 503a9917..a3828946 100644 --- a/src/app/dispute.rs +++ b/src/app/dispute.rs @@ -11,7 +11,7 @@ use crate::util::{get_nostr_client, send_cant_do_msg, send_new_order_msg}; use anyhow::{Error, Result}; use mostro_core::dispute::Dispute; -use mostro_core::message::{Action, Content, Message}; +use mostro_core::message::{Action, Payload, Message}; use mostro_core::order::{Order, Status}; use nostr::nips::nip59::UnwrappedGift; use nostr_sdk::prelude::*; @@ -239,8 +239,9 @@ pub async fn dispute_action( msg.get_inner_message_kind().request_id, Some(order_id), Action::DisputeInitiatedByYou, - Some(Content::Dispute(dispute.clone().id, initiator_token)), + Some(Payload::Dispute(dispute.clone().id, initiator_token)), &initiator_pubkey, + None ) .await; @@ -256,8 +257,9 @@ pub async fn dispute_action( msg.get_inner_message_kind().request_id, Some(order_id), Action::DisputeInitiatedByPeer, - Some(Content::Dispute(dispute.clone().id, counterpart_token)), + Some(Payload::Dispute(dispute.clone().id, counterpart_token)), &counterpart_pubkey, + None ) .await; diff --git a/src/app/fiat_sent.rs b/src/app/fiat_sent.rs index 42df0f6f..ec1eeb2d 100644 --- a/src/app/fiat_sent.rs +++ b/src/app/fiat_sent.rs @@ -1,7 +1,7 @@ use crate::util::{send_cant_do_msg, send_new_order_msg, update_order_event}; use anyhow::{Error, Result}; -use mostro_core::message::{Action, Content, Message, Peer}; +use mostro_core::message::{Action, Payload, Message, Peer}; use mostro_core::order::{Order, Status}; use nostr::nips::nip59::UnwrappedGift; use nostr_sdk::prelude::*; @@ -70,7 +70,7 @@ pub async fn fiat_sent_action( None, Some(order.id), Action::FiatSentOk, - Some(Content::Peer(peer)), + Some(Payload::Peer(peer)), &seller_pubkey, None, ) @@ -82,7 +82,7 @@ pub async fn fiat_sent_action( msg.get_inner_message_kind().request_id, Some(order.id), Action::FiatSentOk, - Some(Content::Peer(peer)), + Some(Payload::Peer(peer)), &event.sender, None, ) diff --git a/src/app/rate_user.rs b/src/app/rate_user.rs index f25ad707..f57d95b9 100644 --- a/src/app/rate_user.rs +++ b/src/app/rate_user.rs @@ -2,7 +2,7 @@ use crate::util::{send_cant_do_msg, send_new_order_msg, update_user_rating_event use crate::NOSTR_CLIENT; use anyhow::{Error, Result}; -use mostro_core::message::{Action, Content, Message}; +use mostro_core::message::{Action, Payload, Message}; use mostro_core::order::{Order, Status}; use mostro_core::rating::Rating; use mostro_core::NOSTR_REPLACEABLE_EVENT_KIND; @@ -120,7 +120,7 @@ pub async fn update_user_reputation_action( // Check if content of Peer is the same of counterpart let rating; - if let Some(Content::RatingUser(v)) = msg.get_inner_message_kind().content.to_owned() { + if let Some(Payload::RatingUser(v)) = msg.get_inner_message_kind().content.to_owned() { rating = v; } else { return Err(Error::msg("No rating present")); @@ -171,7 +171,7 @@ pub async fn update_user_reputation_action( msg.get_inner_message_kind().request_id, Some(order.id), Action::RateReceived, - Some(Content::RatingUser(rating)), + Some(Payload::RatingUser(rating)), &event.sender, ) .await; diff --git a/src/app/release.rs b/src/app/release.rs index 52cab525..1ac09b3c 100644 --- a/src/app/release.rs +++ b/src/app/release.rs @@ -50,6 +50,7 @@ pub async fn check_failure_retries(order: &Order, request_id: Option) -> Re Action::PaymentFailed, None, &buyer_pubkey, + None ) .await; @@ -137,6 +138,7 @@ pub async fn release_action( Action::HoldInvoicePaymentSettled, None, &seller_pubkey, + None ) .await; @@ -145,7 +147,7 @@ pub async fn release_action( Some(buyer) => PublicKey::from_str(buyer.as_str())?, _ => return Err(Error::msg("Missing buyer pubkeys")), }; - send_new_order_msg(None, Some(order_id), Action::Released, None, &buyer_pubkey).await; + send_new_order_msg(None, Some(order_id), Action::Released, None, &buyer_pubkey, None).await; let _ = do_payment(order_updated, request_id).await; @@ -252,6 +254,7 @@ async fn payment_success( Action::PurchaseCompleted, None, buyer_pubkey, + None ) .await; diff --git a/src/flow.rs b/src/flow.rs index 3b540ee0..5f11bc53 100644 --- a/src/flow.rs +++ b/src/flow.rs @@ -1,6 +1,6 @@ use crate::util::send_new_order_msg; use anyhow::{Error, Result}; -use mostro_core::message::{Action, Content}; +use mostro_core::message::{Action, Payload}; use mostro_core::order::{Kind, SmallOrder, Status}; use nostr_sdk::prelude::*; use sqlx_crud::Crud; @@ -64,7 +64,7 @@ pub async fn hold_invoice_paid(hash: &str, request_id: Option) -> Result<() request_id, Some(order.id), Action::BuyerTookOrder, - Some(Content::Order(order_data.clone())), + Some(Payload::Order(order_data.clone())), &seller_pubkey, ) .await; @@ -73,7 +73,7 @@ pub async fn hold_invoice_paid(hash: &str, request_id: Option) -> Result<() request_id, Some(order.id), Action::HoldInvoicePaymentAccepted, - Some(Content::Order(order_data)), + Some(Payload::Order(order_data)), &buyer_pubkey, ) .await; @@ -89,7 +89,7 @@ pub async fn hold_invoice_paid(hash: &str, request_id: Option) -> Result<() request_id, Some(order.id), Action::AddInvoice, - Some(Content::Order(order_data)), + Some(Payload::Order(order_data)), &buyer_pubkey, ) .await; diff --git a/src/util.rs b/src/util.rs index cfcf23ae..a8f9a222 100644 --- a/src/util.rs +++ b/src/util.rs @@ -14,7 +14,7 @@ use crate::NOSTR_CLIENT; use anyhow::{Context, Error, Result}; use chrono::Duration; -use mostro_core::message::{Action, Content, Message}; +use mostro_core::message::{Action, Payload, Message}; use mostro_core::order::{Kind as OrderKind, Order, SmallOrder, Status}; use nostr::nips::nip59::UnwrappedGift; use nostr_sdk::prelude::*; @@ -193,7 +193,7 @@ pub async fn publish_order( request_id, Some(order_id), Action::NewOrder, - Some(Content::Order(order)), + Some(Payload::Order(order)), &ack_pubkey, trade_index, ) @@ -419,7 +419,7 @@ pub async fn show_hold_invoice( request_id, Some(order.id), Action::PayInvoice, - Some(Content::PaymentRequest( + Some(Payload::PaymentRequest( Some(new_order), invoice_response.payment_request, None, @@ -537,7 +537,7 @@ pub async fn set_waiting_invoice_status( request_id, Some(order.id), Action::AddInvoice, - Some(Content::Order(order_data)), + Some(Payload::Order(order_data)), &buyer_pubkey, order.trade_index_buyer, ) @@ -619,7 +619,7 @@ pub async fn send_cant_do_msg( destination_key: &PublicKey, ) { // Prepare content in case - let content = message.map(Content::TextMessage); + let content = message.map(Payload::TextMessage); // Send message to event creator let message = Message::cant_do(order_id, request_id, content, None); @@ -633,7 +633,7 @@ pub async fn send_new_order_msg( request_id: Option, order_id: Option, action: Action, - content: Option, + content: Option, destination_key: &PublicKey, trade_index: Option, ) { @@ -773,7 +773,7 @@ mod tests { Some(1), Some(uuid), Action::TakeSell, - Some(Content::Amount(order.amount)), + Some(Payload::Amount(order.amount)), )); let amount = get_fiat_amount_requested(&order, &message); assert_eq!(amount, Some(1000)); From cf4140aae9c2e3fe5df9615d58e551df6af6f4f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Francisco=20Calder=C3=B3n?= Date: Tue, 10 Dec 2024 13:15:46 -0300 Subject: [PATCH 11/31] Bumps to nostr-sdk 0.37 Fixes related to nostr sdk upgrade and payload --- Cargo.lock | 134 ++++------------------------------------------- Cargo.toml | 4 +- src/app.rs | 4 +- src/nip59.rs | 23 ++++++-- src/scheduler.rs | 4 +- src/util.rs | 30 +++++------ 6 files changed, 50 insertions(+), 149 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 29738fea..1cde3128 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -577,12 +577,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" -[[package]] -name = "cfg_aliases" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" - [[package]] name = "chacha20" version = "0.9.1" @@ -1473,7 +1467,6 @@ dependencies = [ "tokio", "tokio-rustls 0.26.0", "tower-service", - "webpki-roots 0.26.6", ] [[package]] @@ -1840,18 +1833,6 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "643cb0b8d4fcc284004d5fd0d67ccf61dfffadb7f75e1e71bc420f4688a3a704" -[[package]] -name = "lnurl-pay" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "536e7c782167a2d48346ca0b2677fad19eaef20f19a4ab868e4d5b96ca879def" -dependencies = [ - "bech32 0.11.0", - "reqwest", - "serde", - "serde_json", -] - [[package]] name = "lnurl-rs" version = "0.8.0" @@ -2010,9 +1991,9 @@ dependencies = [ [[package]] name = "mostro-core" -version = "0.6.13" +version = "0.6.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "789e88b48f35ab22d655d2ebf0674b4c3b4f31e4ee5f3c965398becb3bf9ead7" +checksum = "0c5609bc9985505f2190e8c6e657872f71a83942133aa75a067420d96cf86854" dependencies = [ "anyhow", "bitcoin", @@ -2074,11 +2055,10 @@ dependencies = [ [[package]] name = "nostr" -version = "0.36.0" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14ad56c1d9a59f4edc46b17bc64a217b38b99baefddc0080f85ad98a0855336d" +checksum = "8aad4b767bbed24ac5eb4465bfb83bc1210522eb99d67cf4e547ec2ec7e47786" dependencies = [ - "aes", "async-trait", "base64 0.22.1", "bech32 0.11.0", @@ -2089,26 +2069,21 @@ dependencies = [ "chacha20poly1305", "getrandom", "instant", - "js-sys", "negentropy 0.3.1", "negentropy 0.4.3", "once_cell", - "reqwest", "scrypt", "serde", "serde_json", "unicode-normalization", "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", ] [[package]] name = "nostr-database" -version = "0.36.0" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1859abebf78d7d9e945b20c8faaf710c9db905adeb148035b803ae45792dbebe" +checksum = "23696338d51e45cd44e061823847f4b0d1d362eca80d5033facf9c184149f72f" dependencies = [ "async-trait", "lru", @@ -2120,9 +2095,9 @@ dependencies = [ [[package]] name = "nostr-relay-pool" -version = "0.36.0" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e39cfcb30cab86b30ca9acba89f5ccb25a4142a5dc5fcfbf3edf34b204ddd7c7" +checksum = "15fcc6e3f0ca54d0fc779009bc5f2684cea9147be3b6aa68a7d301ea590f95f5" dependencies = [ "async-utility", "async-wsocket", @@ -2139,34 +2114,20 @@ dependencies = [ [[package]] name = "nostr-sdk" -version = "0.36.0" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4739ed15ff81a0e474d79b38c3eb481ff5f968c1865f38ba46852daf6f6495e" +checksum = "491221fc89b1aa189a0de640127127d68b4e7c5c1d44371b04d9a6d10694b5af" dependencies = [ "async-utility", "atomic-destructor", - "lnurl-pay", "nostr", "nostr-database", "nostr-relay-pool", - "nostr-zapper", - "nwc", "thiserror", "tokio", "tracing", ] -[[package]] -name = "nostr-zapper" -version = "0.36.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d9709ecf8050bbe4ecf0e5efda2f25b690bb1761fc504e05654621ba9e568a8" -dependencies = [ - "async-trait", - "nostr", - "thiserror", -] - [[package]] name = "nu-ansi-term" version = "0.46.0" @@ -2186,21 +2147,6 @@ dependencies = [ "autocfg", ] -[[package]] -name = "nwc" -version = "0.36.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b5f98bcaf232b3ec48e018792ca7bc2b90e7520d001a07b8218a9e76a03fda2" -dependencies = [ - "async-trait", - "async-utility", - "nostr", - "nostr-relay-pool", - "nostr-zapper", - "thiserror", - "tracing", -] - [[package]] name = "object" version = "0.36.5" @@ -2570,55 +2516,6 @@ dependencies = [ "prost", ] -[[package]] -name = "quinn" -version = "0.11.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c7c5fdde3cdae7203427dc4f0a68fe0ed09833edc525a03456b153b79828684" -dependencies = [ - "bytes", - "pin-project-lite", - "quinn-proto", - "quinn-udp", - "rustc-hash", - "rustls 0.23.16", - "socket2", - "thiserror", - "tokio", - "tracing", -] - -[[package]] -name = "quinn-proto" -version = "0.11.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fadfaed2cd7f389d0161bb73eeb07b7b78f8691047a6f3e73caaeae55310a4a6" -dependencies = [ - "bytes", - "rand", - "ring 0.17.8", - "rustc-hash", - "rustls 0.23.16", - "slab", - "thiserror", - "tinyvec", - "tracing", -] - -[[package]] -name = "quinn-udp" -version = "0.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d5a626c6807713b15cac82a6acaccd6043c9a5408c24baae07611fec3f243da" -dependencies = [ - "cfg_aliases", - "libc", - "once_cell", - "socket2", - "tracing", - "windows-sys 0.59.0", -] - [[package]] name = "quote" version = "1.0.37" @@ -2747,10 +2644,7 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", - "quinn", - "rustls 0.23.16", "rustls-pemfile 2.2.0", - "rustls-pki-types", "serde", "serde_json", "serde_urlencoded", @@ -2758,14 +2652,12 @@ dependencies = [ "system-configuration", "tokio", "tokio-native-tls", - "tokio-rustls 0.26.0", "tokio-socks", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "webpki-roots 0.26.6", "windows-registry", ] @@ -2827,12 +2719,6 @@ version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" -[[package]] -name = "rustc-hash" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" - [[package]] name = "rustix" version = "0.38.39" diff --git a/Cargo.toml b/Cargo.toml index 1a0e42bb..7515cb19 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,7 +17,7 @@ anyhow = "1.0.89" chrono = "0.4.35" easy-hasher = "2.2.1" lightning-invoice = { version = "0.32.0", features = ["std"] } -nostr-sdk = "0.36.0" +nostr-sdk = { version = "0.37.0", features = ["nip59"] } serde = { version = "1.0.210" } serde_json = "1.0.128" sqlx = { version = "0.6.2", features = [ @@ -38,7 +38,7 @@ uuid = { version = "1.8.0", features = [ "serde", ] } reqwest = { version = "0.12.1", features = ["json"] } -mostro-core = { version = "0.6.13", features = ["sqlx"] } +mostro-core = { version = "0.6.14", features = ["sqlx"] } tracing = "0.1.40" tracing-subscriber = { version = "0.3.18", features = ["env-filter"] } config = "0.14.0" diff --git a/src/app.rs b/src/app.rs index 720889f4..fde37218 100644 --- a/src/app.rs +++ b/src/app.rs @@ -58,10 +58,12 @@ async fn process_message(pool: &Pool, event: &UnwrappedGift, msg: Messag match is_user_present(&pool, event.sender.to_string()).await { Ok(mut user) => { if let (true, index) = message_kind.has_trade_index() { + let (_, sig): (String, nostr_sdk::secp256k1::schnorr::Signature) = + serde_json::from_str(&event.rumor.content).unwrap(); if index > user.trade_index && msg .get_inner_message_kind() - .verify_signature(event.sender, event.rumor.content.) + .verify_signature(event.sender, sig) { user.trade_index = index; if let Ok(_) = user.update(&pool).await { diff --git a/src/nip59.rs b/src/nip59.rs index d6b25e39..9440db26 100644 --- a/src/nip59.rs +++ b/src/nip59.rs @@ -1,4 +1,5 @@ use base64::engine::{general_purpose, Engine}; +use mostro_core::message::Message; use nostr_sdk::event::builder::Error as BuilderError; use nostr_sdk::nostr::nips::nip44::v2::{decrypt_to_bytes, encrypt_to_bytes, ConversationKey}; use nostr_sdk::prelude::*; @@ -18,10 +19,17 @@ use nostr_sdk::prelude::*; pub fn gift_wrap( sender_keys: &Keys, receiver: PublicKey, - content: String, + payload: String, expiration: Option, ) -> Result { - let rumor: UnsignedEvent = EventBuilder::text_note(content, []).build(sender_keys.public_key()); + // We convert back the string to a message + let message = Message::from_json(&payload).unwrap(); + // We sign the message + let sig = message.get_inner_message_kind().sign(sender_keys); + // We compose the content + let content = (message, sig); + let content = serde_json::to_string(&content).unwrap(); + let rumor: UnsignedEvent = EventBuilder::text_note(content).build(sender_keys.public_key()); let seal: Event = seal(sender_keys, &receiver, rumor)?.sign_with_keys(sender_keys)?; gift_wrap_from_seal(&receiver, &seal, expiration) @@ -39,7 +47,7 @@ pub fn seal( // Encode with base64 let b64decoded_content = general_purpose::STANDARD.encode(encrypted_content); // Compose builder - Ok(EventBuilder::new(Kind::Seal, b64decoded_content, []) + Ok(EventBuilder::new(Kind::Seal, b64decoded_content) .custom_created_at(Timestamp::tweaked(nip59::RANGE_RANDOM_TIMESTAMP_TWEAK))) } @@ -60,11 +68,16 @@ pub fn gift_wrap_from_seal( if let Some(timestamp) = expiration { tags.push(Tag::expiration(timestamp)); } + let tags = Tags::new(tags); // Encode with base64 let b64decoded_content = general_purpose::STANDARD.encode(encrypted_content); - EventBuilder::new(Kind::GiftWrap, b64decoded_content, tags) + let event = EventBuilder::new(Kind::GiftWrap, b64decoded_content) + .tags(tags) .custom_created_at(Timestamp::tweaked(nip59::RANGE_RANDOM_TIMESTAMP_TWEAK)) - .sign_with_keys(&ephemeral_keys) + .build(ephemeral_keys.public_key()) + .sign_with_keys(&ephemeral_keys)?; + + Ok(event) } pub fn unwrap_gift_wrap(keys: &Keys, gift_wrap: &Event) -> Result { diff --git a/src/scheduler.rs b/src/scheduler.rs index 9ba7a885..1e66e8e4 100644 --- a/src/scheduler.rs +++ b/src/scheduler.rs @@ -50,8 +50,8 @@ async fn job_relay_list() { } } - if let Ok(relay_ev) = EventBuilder::new(NostrKind::RelayList, "", relay_tags) - .sign_with_keys(&mostro_keys) + if let Ok(relay_ev) = + EventBuilder::new(NostrKind::RelayList, "").sign_with_keys(&mostro_keys) { if let Ok(client) = get_nostr_client() { let _ = client.send_event(relay_ev).await; diff --git a/src/util.rs b/src/util.rs index a8f9a222..11cf4d6a 100644 --- a/src/util.rs +++ b/src/util.rs @@ -14,14 +14,13 @@ use crate::NOSTR_CLIENT; use anyhow::{Context, Error, Result}; use chrono::Duration; -use mostro_core::message::{Action, Payload, Message}; +use mostro_core::message::{Action, Message, Payload}; use mostro_core::order::{Kind as OrderKind, Order, SmallOrder, Status}; use nostr::nips::nip59::UnwrappedGift; use nostr_sdk::prelude::*; use sqlx::SqlitePool; use sqlx_crud::Crud; use std::fmt::Write; -use std::path::is_separator; use std::str::FromStr; use std::sync::Arc; use std::thread; @@ -259,12 +258,12 @@ async fn prepare_new_order( pub async fn send_dm( receiver_pubkey: &PublicKey, sender_keys: Keys, - content: String, + payload: String, ) -> Result<()> { - let event = gift_wrap(&sender_keys, *receiver_pubkey, content.clone(), None)?; + let event = gift_wrap(&sender_keys, *receiver_pubkey, payload.clone(), None)?; info!( - "Sending DM, Event ID: {} with content: {:#?}", - event.id, content + "Sending DM, Event ID: {} with payload: {:#?}", + event.id, payload ); if let Ok(client) = get_nostr_client() { @@ -618,11 +617,11 @@ pub async fn send_cant_do_msg( message: Option, destination_key: &PublicKey, ) { - // Prepare content in case - let content = message.map(Payload::TextMessage); + // Prepare payload in case + let payload = message.map(Payload::TextMessage); // Send message to event creator - let message = Message::cant_do(order_id, request_id, content, None); + let message = Message::cant_do(order_id, request_id, payload); if let Ok(message) = message.as_json() { let sender_keys = crate::util::get_keys().unwrap(); let _ = send_dm(destination_key, sender_keys, message).await; @@ -633,12 +632,12 @@ pub async fn send_new_order_msg( request_id: Option, order_id: Option, action: Action, - content: Option, + payload: Option, destination_key: &PublicKey, trade_index: Option, ) { // Send message to event creator - let message = Message::new_order(order_id, request_id, trade_index, action, content, None); + let message = Message::new_order(order_id, request_id, trade_index, action, payload); if let Ok(message) = message.as_json() { let sender_keys = crate::util::get_keys().unwrap(); let _ = send_dm(destination_key, sender_keys, message).await; @@ -674,7 +673,7 @@ pub fn get_nostr_client() -> Result<&'static Client> { } /// Getter function with error management for nostr relays -pub async fn get_nostr_relays() -> Option> { +pub async fn get_nostr_relays() -> Option> { if let Some(client) = NOSTR_CLIENT.get() { Some(client.relays().await) } else { @@ -753,9 +752,9 @@ mod tests { initialize(); // Mock the send_dm function let receiver_pubkey = Keys::generate().public_key(); - let content = "Test message".to_string(); + let payload = "Test message".to_string(); let sender_keys = Keys::generate(); - let result = send_dm(&receiver_pubkey, sender_keys, content).await; + let result = send_dm(&receiver_pubkey, sender_keys, payload).await; assert!(result.is_ok()); } @@ -770,8 +769,9 @@ mod tests { ..Default::default() }; let message = Message::Order(MessageKind::new( - Some(1), Some(uuid), + Some(1), + Some(1), Action::TakeSell, Some(Payload::Amount(order.amount)), )); From 477f2448e97e65a56af6cb9d17c72e6f9cd0a3a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Francisco=20Calder=C3=B3n?= Date: Tue, 10 Dec 2024 15:18:12 -0300 Subject: [PATCH 12/31] More cosmetics and payload related fixes --- src/app/admin_add_solver.rs | 13 +++++++------ src/app/admin_cancel.rs | 18 ++++++++++++++---- src/app/admin_settle.rs | 11 ++++++++--- src/app/admin_take_dispute.rs | 7 ++----- src/app/cancel.rs | 35 ++++++++++++++++++++++++++--------- src/app/dispute.rs | 7 ++++--- src/app/order.rs | 1 + src/app/rate_user.rs | 5 +++-- src/app/release.rs | 17 +++++++++++++---- src/flow.rs | 4 ++++ src/nip33.rs | 4 +++- 11 files changed, 85 insertions(+), 37 deletions(-) diff --git a/src/app/admin_add_solver.rs b/src/app/admin_add_solver.rs index 204ef66f..6cf56159 100644 --- a/src/app/admin_add_solver.rs +++ b/src/app/admin_add_solver.rs @@ -1,7 +1,7 @@ use crate::util::{send_cant_do_msg, send_dm}; use anyhow::Result; -use mostro_core::message::{Action, Payload, Message}; +use mostro_core::message::{Action, Message, Payload}; use mostro_core::user::User; use nostr::nips::nip59::UnwrappedGift; use nostr_sdk::prelude::*; @@ -19,13 +19,13 @@ pub async fn admin_add_solver_action( let request_id = msg.get_inner_message_kind().request_id; let inner_message = msg.get_inner_message_kind(); - let content = if let Some(content) = &inner_message.content { - content + let payload = if let Some(payload) = &inner_message.payload { + payload } else { error!("No pubkey found!"); return Ok(()); }; - let npubkey = if let Payload::TextMessage(p) = content { + let npubkey = if let Payload::TextMessage(p) = payload { p } else { error!("No pubkey found!"); @@ -38,15 +38,16 @@ pub async fn admin_add_solver_action( send_cant_do_msg(request_id, None, None, &event.sender).await; return Ok(()); } + let trade_index = inner_message.trade_index.unwrap_or(0); let public_key = PublicKey::from_bech32(npubkey)?.to_hex(); - let user = User::new(public_key, 0, 1, 0, 0, None); + let user = User::new(public_key, 0, 1, 0, 0, trade_index); // Use CRUD to create user match user.create(pool).await { Ok(r) => info!("Solver added: {:#?}", r), Err(ee) => error!("Error creating solver: {:#?}", ee), } // We create a Message for admin - let message = Message::new_dispute(request_id, None, None, Action::AdminAddSolver, None, None); + let message = Message::new_dispute(None, request_id, None, Action::AdminAddSolver, None); let message = message.as_json()?; // Send the message let sender_keys = crate::util::get_keys().unwrap(); diff --git a/src/app/admin_cancel.rs b/src/app/admin_cancel.rs index 1c4d75ca..c7acd845 100644 --- a/src/app/admin_cancel.rs +++ b/src/app/admin_cancel.rs @@ -31,15 +31,17 @@ pub async fn admin_cancel_action( } else { return Err(Error::msg("No order id")); }; + let inner_message = msg.get_inner_message_kind(); match is_assigned_solver(pool, &event.sender.to_string(), order_id).await { Ok(false) => { send_new_order_msg( - msg.get_inner_message_kind().request_id, + inner_message.request_id, Some(order_id), Action::IsNotYourDispute, None, &event.sender, + inner_message.trade_index, ) .await; return Ok(()); @@ -62,8 +64,9 @@ pub async fn admin_cancel_action( // Was order cooperatively cancelled? if order.status == Status::CooperativelyCanceled.to_string() { let message = MessageKind::new( - request_id, Some(order_id), + request_id, + inner_message.trade_index, Action::CooperativeCancelAccepted, None, ); @@ -76,11 +79,12 @@ pub async fn admin_cancel_action( if order.status != Status::Dispute.to_string() { send_new_order_msg( - msg.get_inner_message_kind().request_id, + inner_message.request_id, Some(order.id), Action::NotAllowedByStatus, None, &event.sender, + inner_message.trade_index, ) .await; return Ok(()); @@ -135,7 +139,13 @@ pub async fn admin_cancel_action( let order_updated = update_order_event(my_keys, Status::CanceledByAdmin, &order).await?; order_updated.update(pool).await?; // We create a Message for cancel - let message = Message::new_order(request_id, Some(order.id), Action::AdminCanceled, None); + let message = Message::new_order( + Some(order.id), + request_id, + inner_message.trade_index, + Action::AdminCanceled, + None, + ); let message = message.as_json()?; // Message to admin let sender_keys = crate::util::get_keys().unwrap(); diff --git a/src/app/admin_settle.rs b/src/app/admin_settle.rs index c5358a89..7003dd64 100644 --- a/src/app/admin_settle.rs +++ b/src/app/admin_settle.rs @@ -33,6 +33,7 @@ pub async fn admin_settle_action( } else { return Err(Error::msg("No order id")); }; + let inner_message = msg.get_inner_message_kind(); match is_assigned_solver(pool, &event.sender.to_string(), order_id).await { Ok(false) => { @@ -42,6 +43,7 @@ pub async fn admin_settle_action( Action::IsNotYourDispute, None, &event.sender, + inner_message.trade_index, ) .await; return Ok(()); @@ -64,8 +66,9 @@ pub async fn admin_settle_action( // Was orde cooperatively cancelled? if order.status == Status::CooperativelyCanceled.to_string() { let message = MessageKind::new( - msg.get_inner_message_kind().request_id, Some(order_id), + msg.get_inner_message_kind().request_id, + inner_message.trade_index, Action::CooperativeCancelAccepted, None, ); @@ -78,11 +81,12 @@ pub async fn admin_settle_action( if order.status != Status::Dispute.to_string() { send_new_order_msg( - msg.get_inner_message_kind().request_id, + inner_message.request_id, Some(order.id), Action::NotAllowedByStatus, None, &event.sender, + inner_message.trade_index, ) .await; return Ok(()); @@ -140,8 +144,9 @@ pub async fn admin_settle_action( } // We create a Message for settle let message = Message::new_order( - request_id, Some(order_updated.id), + request_id, + inner_message.trade_index, Action::AdminSettled, None, ); diff --git a/src/app/admin_take_dispute.rs b/src/app/admin_take_dispute.rs index 520e6cb9..c41e24d4 100644 --- a/src/app/admin_take_dispute.rs +++ b/src/app/admin_take_dispute.rs @@ -4,7 +4,7 @@ use crate::util::{get_nostr_client, send_cant_do_msg, send_dm, send_new_order_ms use anyhow::{Error, Result}; use mostro_core::dispute::{Dispute, Status}; -use mostro_core::message::{Action, Payload, Message, Peer}; +use mostro_core::message::{Action, Message, Payload, Peer}; use mostro_core::order::Order; use nostr::nips::nip59::UnwrappedGift; use nostr_sdk::prelude::*; @@ -63,7 +63,7 @@ pub async fn admin_take_dispute_action( Action::NotFound, None, &event.sender, - None + None, ) .await; return Ok(()); @@ -113,7 +113,6 @@ pub async fn admin_take_dispute_action( None, Action::AdminTookDispute, Some(Payload::Order(new_order)), - None, ); let message = message.as_json()?; let sender_keys = crate::util::get_keys().unwrap(); @@ -127,7 +126,6 @@ pub async fn admin_take_dispute_action( None, Action::AdminTookDispute, Some(Payload::Peer(solver_pubkey.clone())), - None, ); let msg_to_seller = Message::new_order( @@ -136,7 +134,6 @@ pub async fn admin_take_dispute_action( None, Action::AdminTookDispute, Some(Payload::Peer(solver_pubkey)), - None, ); let (seller_pubkey, buyer_pubkey) = match (&order.seller_pubkey, &order.buyer_pubkey) { diff --git a/src/app/cancel.rs b/src/app/cancel.rs index fc7a26b6..9dc7fcfc 100644 --- a/src/app/cancel.rs +++ b/src/app/cancel.rs @@ -50,6 +50,7 @@ pub async fn cancel_action( Action::IsNotYourOrder, None, &event.sender, + None, ) .await; } else { @@ -65,7 +66,7 @@ pub async fn cancel_action( Action::Canceled, None, &event.sender, - None + None, ) .await; } @@ -133,7 +134,7 @@ pub async fn cancel_action( Action::CooperativeCancelAccepted, None, &event.sender, - None + None, ) .await; let counterparty_pubkey = PublicKey::from_str(&counterparty_pubkey)?; @@ -143,7 +144,7 @@ pub async fn cancel_action( Action::CooperativeCancelAccepted, None, &counterparty_pubkey, - None + None, ) .await; info!("Cancel: Order Id {order_id} canceled cooperatively!"); @@ -160,7 +161,7 @@ pub async fn cancel_action( Action::CooperativeCancelInitiatedByYou, None, &event.sender, - None + None, ) .await; let counterparty_pubkey = PublicKey::from_str(&counterparty_pubkey)?; @@ -170,7 +171,7 @@ pub async fn cancel_action( Action::CooperativeCancelInitiatedByPeer, None, &counterparty_pubkey, - None + None, ) .await; } @@ -217,10 +218,18 @@ pub async fn cancel_add_invoice( Action::Canceled, None, &event.sender, - None + None, + ) + .await; + send_new_order_msg( + None, + Some(order.id), + Action::Canceled, + None, + &seller_pubkey, + None, ) .await; - send_new_order_msg(None, Some(order.id), Action::Canceled, None, &seller_pubkey, None).await; Ok(()) } else { // We re-publish the event with Pending status @@ -280,10 +289,18 @@ pub async fn cancel_pay_hold_invoice( Action::Canceled, None, &event.sender, - None + None, + ) + .await; + send_new_order_msg( + None, + Some(order.id), + Action::Canceled, + None, + &seller_pubkey, + None, ) .await; - send_new_order_msg(None, Some(order.id), Action::Canceled, None, &seller_pubkey, None).await; Ok(()) } else { // We re-publish the event with Pending status diff --git a/src/app/dispute.rs b/src/app/dispute.rs index a3828946..6f335020 100644 --- a/src/app/dispute.rs +++ b/src/app/dispute.rs @@ -11,7 +11,7 @@ use crate::util::{get_nostr_client, send_cant_do_msg, send_new_order_msg}; use anyhow::{Error, Result}; use mostro_core::dispute::Dispute; -use mostro_core::message::{Action, Payload, Message}; +use mostro_core::message::{Action, Message, Payload}; use mostro_core::order::{Order, Status}; use nostr::nips::nip59::UnwrappedGift; use nostr_sdk::prelude::*; @@ -121,6 +121,7 @@ async fn get_valid_order( Action::NotAllowedByStatus, None, &event.sender, + None, ) .await; return Err(Error::msg(format!( @@ -241,7 +242,7 @@ pub async fn dispute_action( Action::DisputeInitiatedByYou, Some(Payload::Dispute(dispute.clone().id, initiator_token)), &initiator_pubkey, - None + None, ) .await; @@ -259,7 +260,7 @@ pub async fn dispute_action( Action::DisputeInitiatedByPeer, Some(Payload::Dispute(dispute.clone().id, counterpart_token)), &counterpart_pubkey, - None + None, ) .await; diff --git a/src/app/order.rs b/src/app/order.rs index 2fdd58d5..30a6f967 100644 --- a/src/app/order.rs +++ b/src/app/order.rs @@ -59,6 +59,7 @@ pub async fn order_action( Action::InvalidSatsAmount, None, &event.sender, + None, ) .await; return Ok(()); diff --git a/src/app/rate_user.rs b/src/app/rate_user.rs index f57d95b9..2bdf7555 100644 --- a/src/app/rate_user.rs +++ b/src/app/rate_user.rs @@ -2,7 +2,7 @@ use crate::util::{send_cant_do_msg, send_new_order_msg, update_user_rating_event use crate::NOSTR_CLIENT; use anyhow::{Error, Result}; -use mostro_core::message::{Action, Payload, Message}; +use mostro_core::message::{Action, Message, Payload}; use mostro_core::order::{Order, Status}; use mostro_core::rating::Rating; use mostro_core::NOSTR_REPLACEABLE_EVENT_KIND; @@ -120,7 +120,7 @@ pub async fn update_user_reputation_action( // Check if content of Peer is the same of counterpart let rating; - if let Some(Payload::RatingUser(v)) = msg.get_inner_message_kind().content.to_owned() { + if let Some(Payload::RatingUser(v)) = msg.get_inner_message_kind().payload.to_owned() { rating = v; } else { return Err(Error::msg("No rating present")); @@ -173,6 +173,7 @@ pub async fn update_user_reputation_action( Action::RateReceived, Some(Payload::RatingUser(rating)), &event.sender, + None, ) .await; } diff --git a/src/app/release.rs b/src/app/release.rs index 1ac09b3c..51f98bb7 100644 --- a/src/app/release.rs +++ b/src/app/release.rs @@ -50,7 +50,7 @@ pub async fn check_failure_retries(order: &Order, request_id: Option) -> Re Action::PaymentFailed, None, &buyer_pubkey, - None + None, ) .await; @@ -108,6 +108,7 @@ pub async fn release_action( Action::NotAllowedByStatus, None, &event.sender, + None, ) .await; return Ok(()); @@ -138,7 +139,7 @@ pub async fn release_action( Action::HoldInvoicePaymentSettled, None, &seller_pubkey, - None + None, ) .await; @@ -147,7 +148,15 @@ pub async fn release_action( Some(buyer) => PublicKey::from_str(buyer.as_str())?, _ => return Err(Error::msg("Missing buyer pubkeys")), }; - send_new_order_msg(None, Some(order_id), Action::Released, None, &buyer_pubkey, None).await; + send_new_order_msg( + None, + Some(order_id), + Action::Released, + None, + &buyer_pubkey, + None, + ) + .await; let _ = do_payment(order_updated, request_id).await; @@ -254,7 +263,7 @@ async fn payment_success( Action::PurchaseCompleted, None, buyer_pubkey, - None + None, ) .await; diff --git a/src/flow.rs b/src/flow.rs index 5f11bc53..02d63cb2 100644 --- a/src/flow.rs +++ b/src/flow.rs @@ -66,6 +66,7 @@ pub async fn hold_invoice_paid(hash: &str, request_id: Option) -> Result<() Action::BuyerTookOrder, Some(Payload::Order(order_data.clone())), &seller_pubkey, + None, ) .await; // We send a message to buyer saying seller paid @@ -75,6 +76,7 @@ pub async fn hold_invoice_paid(hash: &str, request_id: Option) -> Result<() Action::HoldInvoicePaymentAccepted, Some(Payload::Order(order_data)), &buyer_pubkey, + None, ) .await; } else { @@ -91,6 +93,7 @@ pub async fn hold_invoice_paid(hash: &str, request_id: Option) -> Result<() Action::AddInvoice, Some(Payload::Order(order_data)), &buyer_pubkey, + None, ) .await; @@ -101,6 +104,7 @@ pub async fn hold_invoice_paid(hash: &str, request_id: Option) -> Result<() Action::WaitingBuyerInvoice, None, &seller_pubkey, + None, ) .await; } diff --git a/src/nip33.rs b/src/nip33.rs index e3bef7e9..1a668493 100644 --- a/src/nip33.rs +++ b/src/nip33.rs @@ -29,8 +29,10 @@ pub fn new_event( let mut tags: Vec = Vec::with_capacity(1 + extra_tags.len()); tags.push(Tag::identifier(identifier)); tags.extend(extra_tags); + let tags = Tags::new(tags); - EventBuilder::new(Kind::Custom(NOSTR_REPLACEABLE_EVENT_KIND), content, tags) + EventBuilder::new(Kind::Custom(NOSTR_REPLACEABLE_EVENT_KIND), content) + .tags(tags) .sign_with_keys(keys) } From a5385f67ee4bccc3e2b952d93f257578c4793019 Mon Sep 17 00:00:00 2001 From: arkanoider Date: Tue, 10 Dec 2024 22:31:08 +0100 Subject: [PATCH 13/31] mostrod compiles and checks incoming messages to check trade index - first CantDo described messages - needs bumping mostro core --- Cargo.toml | 3 --- src/app.rs | 39 ++++++++++++++++++++++++++++++++------- src/app/add_invoice.rs | 2 +- src/app/fiat_sent.rs | 2 +- src/app/take_sell.rs | 4 ++-- src/util.rs | 8 +++----- 6 files changed, 39 insertions(+), 19 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 7515cb19..1ec5531e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,6 +47,3 @@ lnurl-rs = "0.8.0" openssl = { version = "0.10.66", features = ["vendored"] } once_cell = "1.20.2" bitcoin = "0.32.5" - -# [patch.crates-io] -# mostro-core = { path = "../mostro-core" } diff --git a/src/app.rs b/src/app.rs index fde37218..4fab8005 100644 --- a/src/app.rs +++ b/src/app.rs @@ -34,12 +34,13 @@ use crate::app::take_sell::take_sell_action; // Core functionality imports use crate::lightning::LndConnector; use crate::nip59::unwrap_gift_wrap; +use crate::util::send_cant_do_msg; use crate::Settings; // External dependencies use crate::db::is_user_present; use anyhow::Result; -use mostro_core::message::{Action, Message}; +use mostro_core::message::{Action, CantDoReason, Message}; use mostro_core::user::User; use nostr_sdk::prelude::*; use sqlx::{Pool, Sqlite}; @@ -51,11 +52,23 @@ fn warning_msg(action: &Action, e: anyhow::Error) { tracing::warn!("Error in {} with context {}", action, e); } -/// Function to search if user is yet present in db -async fn process_message(pool: &Pool, event: &UnwrappedGift, msg: Message) { +/// Function to check if a user is present in the database and update or create their trade index. +/// +/// This function performs the following tasks: +/// 1. It checks if the action associated with the incoming message is related to trading (NewOrder, TakeBuy, or TakeSell). +/// 2. If the user is found in the database, it verifies the trade index and the signature of the message. +/// - If valid, it updates the user's trade index. +/// - If invalid, it logs a warning and sends a message indicating the issue. +/// 3. If the user is not found, it creates a new user entry with the provided trade index if applicable. +/// +/// # Arguments +/// * `pool` - The database connection pool used to query and update user data. +/// * `event` - The unwrapped gift event containing the sender's information. +/// * `msg` - The message containing action details and trade index information. +async fn check_trade_index(pool: &Pool, event: &UnwrappedGift, msg: &Message) { let message_kind = msg.get_inner_message_kind(); if let Action::NewOrder | Action::TakeBuy | Action::TakeSell = message_kind.action { - match is_user_present(&pool, event.sender.to_string()).await { + match is_user_present(pool, event.sender.to_string()).await { Ok(mut user) => { if let (true, index) = message_kind.has_trade_index() { let (_, sig): (String, nostr_sdk::secp256k1::schnorr::Signature) = @@ -66,9 +79,18 @@ async fn process_message(pool: &Pool, event: &UnwrappedGift, msg: Messag .verify_signature(event.sender, sig) { user.trade_index = index; - if let Ok(_) = user.update(&pool).await { + if user.update(pool).await.is_ok() { tracing::info!("Update user trade index"); } + } else { + tracing::info!("Invalid signature or trade index"); + send_cant_do_msg( + None, + msg.get_inner_message_kind().id, + Some(CantDoReason::InvalidTradeIndex), + &event.sender, + ) + .await; } } } @@ -79,7 +101,7 @@ async fn process_message(pool: &Pool, event: &UnwrappedGift, msg: Messag trade_index, ..Default::default() }; - if let Ok(_) = new_user.create(&pool).await { + if new_user.create(pool).await.is_ok() { tracing::info!("Added new user for rate"); } } @@ -184,12 +206,15 @@ pub async fn run( if event.rumor.created_at.as_u64() < since_time { continue; } - // Parse and process the message let message = Message::from_json(&event.rumor.content); + match message { Ok(msg) => { let message_kind = msg.get_inner_message_kind(); + // Check if message is message with trade index + check_trade_index(&pool, &event, &msg).await; + if message_kind.verify() { if let Some(action) = msg.inner_action() { if let Err(e) = handle_message_action( diff --git a/src/app/add_invoice.rs b/src/app/add_invoice.rs index edb47edb..17e2683a 100644 --- a/src/app/add_invoice.rs +++ b/src/app/add_invoice.rs @@ -3,7 +3,7 @@ use crate::util::{send_cant_do_msg, send_new_order_msg, show_hold_invoice, updat use anyhow::{Error, Result}; -use mostro_core::message::{Action, Payload, Message}; +use mostro_core::message::{Action, Message, Payload}; use mostro_core::order::SmallOrder; use mostro_core::order::{Kind, Order, Status}; use nostr::nips::nip59::UnwrappedGift; diff --git a/src/app/fiat_sent.rs b/src/app/fiat_sent.rs index ec1eeb2d..9b510efd 100644 --- a/src/app/fiat_sent.rs +++ b/src/app/fiat_sent.rs @@ -1,7 +1,7 @@ use crate::util::{send_cant_do_msg, send_new_order_msg, update_order_event}; use anyhow::{Error, Result}; -use mostro_core::message::{Action, Payload, Message, Peer}; +use mostro_core::message::{Action, Message, Payload, Peer}; use mostro_core::order::{Order, Status}; use nostr::nips::nip59::UnwrappedGift; use nostr_sdk::prelude::*; diff --git a/src/app/take_sell.rs b/src/app/take_sell.rs index a9296519..9c34cfb0 100644 --- a/src/app/take_sell.rs +++ b/src/app/take_sell.rs @@ -5,7 +5,7 @@ use crate::util::{ }; use anyhow::{Error, Result}; -use mostro_core::message::{Action, Message}; +use mostro_core::message::{Action, CantDoReason, Message}; use mostro_core::order::{Kind, Order, Status}; use nostr::nips::nip59::UnwrappedGift; use nostr_sdk::prelude::*; @@ -72,7 +72,7 @@ pub async fn take_sell_action( send_cant_do_msg( request_id, Some(order.id), - Some(e.to_string()), + Some(CantDoReason::InvalidInvoice), &event.sender, ) .await; diff --git a/src/util.rs b/src/util.rs index 11cf4d6a..a6ef387e 100644 --- a/src/util.rs +++ b/src/util.rs @@ -14,6 +14,7 @@ use crate::NOSTR_CLIENT; use anyhow::{Context, Error, Result}; use chrono::Duration; +use mostro_core::message::CantDoReason; use mostro_core::message::{Action, Message, Payload}; use mostro_core::order::{Kind as OrderKind, Order, SmallOrder, Status}; use nostr::nips::nip59::UnwrappedGift; @@ -614,14 +615,11 @@ pub fn bytes_to_string(bytes: &[u8]) -> String { pub async fn send_cant_do_msg( request_id: Option, order_id: Option, - message: Option, + reason: Option, destination_key: &PublicKey, ) { - // Prepare payload in case - let payload = message.map(Payload::TextMessage); - // Send message to event creator - let message = Message::cant_do(order_id, request_id, payload); + let message = Message::cant_do(order_id, request_id, Some(Payload::CantDo(reason))); if let Ok(message) = message.as_json() { let sender_keys = crate::util::get_keys().unwrap(); let _ = send_dm(destination_key, sender_keys, message).await; From 31f8ee3c57326ab2fc06200936313a730d79b2b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Francisco=20Calder=C3=B3n?= Date: Wed, 11 Dec 2024 10:19:39 -0300 Subject: [PATCH 14/31] Bumps mostro-core to 0.6.15 --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1cde3128..f976524d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1991,9 +1991,9 @@ dependencies = [ [[package]] name = "mostro-core" -version = "0.6.14" +version = "0.6.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c5609bc9985505f2190e8c6e657872f71a83942133aa75a067420d96cf86854" +checksum = "0bc7ecd3f791c2d427a620709f57e9c3998412479289a9f7d0fce85cc79c11ba" dependencies = [ "anyhow", "bitcoin", diff --git a/Cargo.toml b/Cargo.toml index 1ec5531e..7287926d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,7 +38,7 @@ uuid = { version = "1.8.0", features = [ "serde", ] } reqwest = { version = "0.12.1", features = ["json"] } -mostro-core = { version = "0.6.14", features = ["sqlx"] } +mostro-core = { version = "0.6.15", features = ["sqlx"] } tracing = "0.1.40" tracing-subscriber = { version = "0.3.18", features = ["env-filter"] } config = "0.14.0" From ec17876c1e221e2a29f945f5dc6732d5a6c62812 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Francisco=20Calder=C3=B3n?= Date: Wed, 11 Dec 2024 10:46:11 -0300 Subject: [PATCH 15/31] bumps lnurl version --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f976524d..39fbee8b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1835,9 +1835,9 @@ checksum = "643cb0b8d4fcc284004d5fd0d67ccf61dfffadb7f75e1e71bc420f4688a3a704" [[package]] name = "lnurl-rs" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2951a7783efa798febff75dfd9df4716c3ddc5bea969f132b282972a36bc7d8f" +checksum = "41eacdd87b675792f7752f3dd0937a00241a504c3956c47f72986490662e1db4" dependencies = [ "aes", "anyhow", diff --git a/Cargo.toml b/Cargo.toml index 7287926d..fdbebabc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,7 +43,7 @@ tracing = "0.1.40" tracing-subscriber = { version = "0.3.18", features = ["env-filter"] } config = "0.14.0" clap = { version = "4.5.19", features = ["derive"] } -lnurl-rs = "0.8.0" +lnurl-rs = "0.9.0" openssl = { version = "0.10.66", features = ["vendored"] } once_cell = "1.20.2" bitcoin = "0.32.5" From 617548eaa96ee944eb1f44e939560e90aa6a98b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Francisco=20Calder=C3=B3n?= Date: Wed, 11 Dec 2024 10:46:34 -0300 Subject: [PATCH 16/31] Fix tests --- src/main.rs | 4 ++-- src/util.rs | 10 +++++++++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/main.rs b/src/main.rs index 944c9733..49ddd707 100644 --- a/src/main.rs +++ b/src/main.rs @@ -110,7 +110,7 @@ mod tests { #[test] fn test_message_deserialize_serialize() { - let sample_message = r#"{"order":{"version":1,"request_id":1,"id":"7dd204d2-d06c-4406-a3d9-4415f4a8b9c9","action":"fiat-sent","content":null}}"#; + let sample_message = r#"{"order":{"version":1,"request_id":1,"trade_index":null,"id":"7dd204d2-d06c-4406-a3d9-4415f4a8b9c9","action":"fiat-sent","payload":null}}"#; let message = Message::from_json(sample_message).unwrap(); assert!(message.verify()); let json_message = message.as_json().unwrap(); @@ -119,7 +119,7 @@ mod tests { #[test] fn test_wrong_message_should_fail() { - let sample_message = r#"{"order":{"version":1,"request_id":1,"action":"take-sell","content":{"order":{"kind":"sell","status":"pending","amount":100,"fiat_code":"XXX","fiat_amount":10,"payment_method":"SEPA","premium":1,"payment_request":null,"created_at":1640839235}}}}"#; + let sample_message = r#"{"order":{"version":1,"request_id":1,"action":"take-sell","payload":{"order":{"kind":"sell","status":"pending","amount":100,"fiat_code":"XXX","fiat_amount":10,"payment_method":"SEPA","premium":1,"payment_request":null,"created_at":1640839235}}}}"#; let message = Message::from_json(sample_message).unwrap(); assert!(!message.verify()); } diff --git a/src/util.rs b/src/util.rs index a6ef387e..8874a6b0 100644 --- a/src/util.rs +++ b/src/util.rs @@ -750,7 +750,15 @@ mod tests { initialize(); // Mock the send_dm function let receiver_pubkey = Keys::generate().public_key(); - let payload = "Test message".to_string(); + let uuid = uuid!("308e1272-d5f4-47e6-bd97-3504baea9c23"); + let message = Message::Order(MessageKind::new( + Some(uuid), + None, + None, + Action::FiatSent, + None, + )); + let payload = message.as_json().unwrap(); let sender_keys = Keys::generate(); let result = send_dm(&receiver_pubkey, sender_keys, payload).await; assert!(result.is_ok()); From df2c53b07ece5083fa63d205d92ed002b3dcacb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Francisco=20Calder=C3=B3n?= Date: Wed, 11 Dec 2024 17:22:48 -0300 Subject: [PATCH 17/31] Fix signature verification in rumor --- src/app.rs | 49 +++++++++++++++++++++++-------------------------- 1 file changed, 23 insertions(+), 26 deletions(-) diff --git a/src/app.rs b/src/app.rs index 4fab8005..c014907b 100644 --- a/src/app.rs +++ b/src/app.rs @@ -206,36 +206,33 @@ pub async fn run( if event.rumor.created_at.as_u64() < since_time { continue; } - // Parse and process the message - let message = Message::from_json(&event.rumor.content); + let (message, sig): (Message, Signature) = + serde_json::from_str(&event.rumor.content).unwrap(); + let inner_message = message.get_inner_message_kind(); + if !inner_message.verify_signature(event.rumor.pubkey, sig) { + tracing::warn!("Error in event verification"); + continue; + } - match message { - Ok(msg) => { - let message_kind = msg.get_inner_message_kind(); - // Check if message is message with trade index - check_trade_index(&pool, &event, &msg).await; + // Check if message is message with trade index + check_trade_index(&pool, &event, &message).await; - if message_kind.verify() { - if let Some(action) = msg.inner_action() { - if let Err(e) = handle_message_action( - &action, - msg, - &event, - &my_keys, - &pool, - ln_client, - rate_list.clone(), - ) - .await - { - warning_msg(&action, e) - } - } + if inner_message.verify() { + if let Some(action) = message.inner_action() { + if let Err(e) = handle_message_action( + &action, + message, + &event, + &my_keys, + &pool, + ln_client, + rate_list.clone(), + ) + .await + { + warning_msg(&action, e) } } - Err(e) => { - tracing::warn!("Failed to parse event message from JSON: {:?}", e) - } } } } From 8eafef686e5770fea2abe04e852090b9517494b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Francisco=20Calder=C3=B3n?= Date: Wed, 11 Dec 2024 17:35:07 -0300 Subject: [PATCH 18/31] Add LIMIT 1 on fetch_one() db --- src/db.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/db.rs b/src/db.rs index 9e8b5dab..1485b396 100644 --- a/src/db.rs +++ b/src/db.rs @@ -301,6 +301,7 @@ pub async fn find_solver_pubkey(pool: &SqlitePool, solver_npub: String) -> anyho SELECT * FROM users WHERE pubkey == ?1 AND is_solver == true + LIMIT 1 "#, ) .bind(solver_npub) @@ -315,7 +316,7 @@ pub async fn is_user_present(pool: &SqlitePool, public_key: String) -> anyhow::R r#" SELECT * FROM users - WHERE i0_pubkey == ?1 + WHERE pubkey == ?1 LIMIT 1 "#, ) From 9fec4cf18e95c251da303ce539966ea92ebaf006 Mon Sep 17 00:00:00 2001 From: arkanoider Date: Wed, 11 Dec 2024 22:51:54 +0100 Subject: [PATCH 19/31] added indexes for buyer and seller in db table --- migrations/20221222153301_orders.sql | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/migrations/20221222153301_orders.sql b/migrations/20221222153301_orders.sql index eb513503..885bb396 100644 --- a/migrations/20221222153301_orders.sql +++ b/migrations/20221222153301_orders.sql @@ -36,5 +36,6 @@ CREATE TABLE IF NOT EXISTS orders ( payment_attempts integer default 0, failed_payment integer default 0, expires_at integer not null, - trade_index integer default 0 + trade_index_seller integer default 0, + trade_index_buyer integer default 0 ); From 819670b30364600b0c9b112629837b27f4f23f82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Francisco=20Calder=C3=B3n?= Date: Thu, 12 Dec 2024 17:17:51 -0300 Subject: [PATCH 20/31] Code refactoring and fixes * bumps to mostro core v0.6.16 * add new fields on users table, fields related to user rating * fix bug parsing message and content on app.rs * change all dm destination, now is sending to the trade key --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- migrations/20231005195154_users.sql | 12 +++++++++--- src/app.rs | 12 ++++++------ src/app/add_invoice.rs | 2 +- src/app/admin_add_solver.rs | 2 +- src/app/admin_take_dispute.rs | 2 +- src/app/cancel.rs | 6 +++--- src/app/dispute.rs | 2 +- src/app/fiat_sent.rs | 2 +- src/app/order.rs | 12 ++++++------ src/app/rate_user.rs | 4 ++-- src/app/release.rs | 2 +- src/app/take_buy.rs | 2 +- src/app/take_sell.rs | 4 ++-- src/util.rs | 4 ++-- 16 files changed, 40 insertions(+), 34 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 39fbee8b..7aa80c3b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1991,9 +1991,9 @@ dependencies = [ [[package]] name = "mostro-core" -version = "0.6.15" +version = "0.6.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bc7ecd3f791c2d427a620709f57e9c3998412479289a9f7d0fce85cc79c11ba" +checksum = "cfa673ea01ea2e91bcfc8fa4c6557afb1f8c9795ee909ff1776ff686f6fb26b8" dependencies = [ "anyhow", "bitcoin", diff --git a/Cargo.toml b/Cargo.toml index fdbebabc..4eefd0e0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,7 +38,7 @@ uuid = { version = "1.8.0", features = [ "serde", ] } reqwest = { version = "0.12.1", features = ["json"] } -mostro-core = { version = "0.6.15", features = ["sqlx"] } +mostro-core = { version = "0.6.16", features = ["sqlx"] } tracing = "0.1.40" tracing-subscriber = { version = "0.3.18", features = ["env-filter"] } config = "0.14.0" diff --git a/migrations/20231005195154_users.sql b/migrations/20231005195154_users.sql index 281adcdb..f3941c40 100644 --- a/migrations/20231005195154_users.sql +++ b/migrations/20231005195154_users.sql @@ -1,9 +1,15 @@ CREATE TABLE IF NOT EXISTS users ( - pubkey char(64) primary key not null, + id char(36) primary key not null, + pubkey char(64) unique not null, is_admin integer not null default 0, is_solver integer not null default 0, is_banned integer not null default 0, category integer not null default 0, - created_at integer not null, - trade_index integer not null default 0 + last_trade_index integer not null default 0, + total_reviews integer not null default 0, + total_rating integer not null default 0, + last_rating integer not null default 0, + max_rating integer not null default 0, + min_rating integer not null default 0, + created_at integer not null ); \ No newline at end of file diff --git a/src/app.rs b/src/app.rs index c014907b..2f8e1b86 100644 --- a/src/app.rs +++ b/src/app.rs @@ -71,14 +71,14 @@ async fn check_trade_index(pool: &Pool, event: &UnwrappedGift, msg: &Mes match is_user_present(pool, event.sender.to_string()).await { Ok(mut user) => { if let (true, index) = message_kind.has_trade_index() { - let (_, sig): (String, nostr_sdk::secp256k1::schnorr::Signature) = + let (_, sig): (Message, nostr_sdk::secp256k1::schnorr::Signature) = serde_json::from_str(&event.rumor.content).unwrap(); - if index > user.trade_index + if index > user.last_trade_index && msg .get_inner_message_kind() .verify_signature(event.sender, sig) { - user.trade_index = index; + user.last_trade_index = index; if user.update(pool).await.is_ok() { tracing::info!("Update user trade index"); } @@ -88,17 +88,17 @@ async fn check_trade_index(pool: &Pool, event: &UnwrappedGift, msg: &Mes None, msg.get_inner_message_kind().id, Some(CantDoReason::InvalidTradeIndex), - &event.sender, + &event.rumor.pubkey, ) .await; } } } Err(_) => { - if let (true, trade_index) = message_kind.has_trade_index() { + if let (true, last_trade_index) = message_kind.has_trade_index() { let new_user = User { pubkey: event.sender.to_string(), - trade_index, + last_trade_index, ..Default::default() }; if new_user.create(pool).await.is_ok() { diff --git a/src/app/add_invoice.rs b/src/app/add_invoice.rs index 17e2683a..5199510b 100644 --- a/src/app/add_invoice.rs +++ b/src/app/add_invoice.rs @@ -58,7 +58,7 @@ pub async fn add_invoice_action( }; // Only the buyer can add an invoice if buyer_pubkey != event.sender { - send_cant_do_msg(request_id, Some(order.id), None, &event.sender).await; + send_cant_do_msg(request_id, Some(order.id), None, &event.rumor.pubkey).await; return Ok(()); } diff --git a/src/app/admin_add_solver.rs b/src/app/admin_add_solver.rs index 6cf56159..2209588a 100644 --- a/src/app/admin_add_solver.rs +++ b/src/app/admin_add_solver.rs @@ -35,7 +35,7 @@ pub async fn admin_add_solver_action( // Check if the pubkey is Mostro if event.sender.to_string() != my_keys.public_key().to_string() { // We create a Message - send_cant_do_msg(request_id, None, None, &event.sender).await; + send_cant_do_msg(request_id, None, None, &event.rumor.pubkey).await; return Ok(()); } let trade_index = inner_message.trade_index.unwrap_or(0); diff --git a/src/app/admin_take_dispute.rs b/src/app/admin_take_dispute.rs index c41e24d4..276e99e4 100644 --- a/src/app/admin_take_dispute.rs +++ b/src/app/admin_take_dispute.rs @@ -74,7 +74,7 @@ pub async fn admin_take_dispute_action( if let Ok(dispute_status) = Status::from_str(&dispute.status) { if !pubkey_event_can_solve(pool, &event.sender, dispute_status).await { // We create a Message - send_cant_do_msg(request_id, Some(dispute_id), None, &event.sender).await; + send_cant_do_msg(request_id, Some(dispute_id), None, &event.rumor.pubkey).await; return Ok(()); } } else { diff --git a/src/app/cancel.rs b/src/app/cancel.rs index 9dc7fcfc..2c59e9e8 100644 --- a/src/app/cancel.rs +++ b/src/app/cancel.rs @@ -110,7 +110,7 @@ pub async fn cancel_action( Some(ref initiator_pubkey) => { if initiator_pubkey == &user_pubkey { // We create a Message - send_cant_do_msg(request_id, Some(order_id), None, &event.sender).await; + send_cant_do_msg(request_id, Some(order_id), None, &event.rumor.pubkey).await; return Ok(()); } else { if let Some(hash) = &order.hash { @@ -203,7 +203,7 @@ pub async fn cancel_add_invoice( if buyer_pubkey != &user_pubkey { // We create a Message - send_cant_do_msg(request_id, Some(order.id), None, &event.sender).await; + send_cant_do_msg(request_id, Some(order.id), None, &event.rumor.pubkey).await; return Ok(()); } @@ -274,7 +274,7 @@ pub async fn cancel_pay_hold_invoice( if seller_pubkey.to_string() != user_pubkey { // We create a Message - send_cant_do_msg(request_id, Some(order.id), None, &event.sender).await; + send_cant_do_msg(request_id, Some(order.id), None, &event.rumor.pubkey).await; return Ok(()); } diff --git a/src/app/dispute.rs b/src/app/dispute.rs index 6f335020..5749734e 100644 --- a/src/app/dispute.rs +++ b/src/app/dispute.rs @@ -184,7 +184,7 @@ pub async fn dispute_action( match get_counterpart_info(&message_sender, &buyer, &seller) { Ok((counterpart, is_buyer_dispute)) => (counterpart, is_buyer_dispute), Err(_) => { - send_cant_do_msg(request_id, Some(order.id), None, &event.sender).await; + send_cant_do_msg(request_id, Some(order.id), None, &event.rumor.pubkey).await; return Ok(()); } }; diff --git a/src/app/fiat_sent.rs b/src/app/fiat_sent.rs index 9b510efd..b6128d1d 100644 --- a/src/app/fiat_sent.rs +++ b/src/app/fiat_sent.rs @@ -46,7 +46,7 @@ pub async fn fiat_sent_action( } // Check if the pubkey is the buyer if Some(event.sender.to_string()) != order.buyer_pubkey { - send_cant_do_msg(request_id, Some(order.id), None, &event.sender).await; + send_cant_do_msg(request_id, Some(order.id), None, &event.rumor.pubkey).await; return Ok(()); } diff --git a/src/app/order.rs b/src/app/order.rs index 30a6f967..585e6b27 100644 --- a/src/app/order.rs +++ b/src/app/order.rs @@ -33,7 +33,7 @@ pub async fn order_action( order.id, Action::IncorrectInvoiceAmount, None, - &event.sender, + &event.rumor.pubkey, None, ) .await; @@ -49,7 +49,7 @@ pub async fn order_action( // in case of single order do like usual if let (Some(min), Some(max)) = (order.min_amount, order.max_amount) { if min >= max { - send_cant_do_msg(request_id, order.id, None, &event.sender).await; + send_cant_do_msg(request_id, order.id, None, &event.rumor.pubkey).await; return Ok(()); } if order.amount != 0 { @@ -58,7 +58,7 @@ pub async fn order_action( None, Action::InvalidSatsAmount, None, - &event.sender, + &event.rumor.pubkey, None, ) .await; @@ -91,7 +91,7 @@ pub async fn order_action( None, Action::InvalidSatsAmount, None, - &event.sender, + &event.rumor.pubkey, None, ) .await; @@ -106,7 +106,7 @@ pub async fn order_action( None, Action::OutOfRangeSatsAmount, None, - &event.sender, + &event.rumor.pubkey, None, ) .await; @@ -119,7 +119,7 @@ pub async fn order_action( my_keys, order, &event.sender.to_string(), - event.sender, + event.rumor.pubkey, request_id, msg.get_inner_message_kind().trade_index, ) diff --git a/src/app/rate_user.rs b/src/app/rate_user.rs index 2bdf7555..b0697e75 100644 --- a/src/app/rate_user.rs +++ b/src/app/rate_user.rs @@ -79,7 +79,7 @@ pub async fn update_user_reputation_action( let message_sender = event.sender.to_string(); if order.status != Status::Success.to_string() { - send_cant_do_msg(request_id, Some(order.id), None, &event.sender).await; + send_cant_do_msg(request_id, Some(order.id), None, &event.rumor.pubkey).await; error!("Order Id {order_id} wrong status"); return Ok(()); } @@ -100,7 +100,7 @@ pub async fn update_user_reputation_action( // Add a check in case of no counterpart found if counterpart.is_empty() { // We create a Message - send_cant_do_msg(request_id, Some(order.id), None, &event.sender).await; + send_cant_do_msg(request_id, Some(order.id), None, &event.rumor.pubkey).await; return Ok(()); }; diff --git a/src/app/release.rs b/src/app/release.rs index 51f98bb7..723a7bc5 100644 --- a/src/app/release.rs +++ b/src/app/release.rs @@ -115,7 +115,7 @@ pub async fn release_action( } if &seller_pubkey.to_string() != seller_pubkey_hex { - send_cant_do_msg(request_id, Some(order.id), None, &event.sender).await; + send_cant_do_msg(request_id, Some(order.id), None, &event.rumor.pubkey).await; return Ok(()); } diff --git a/src/app/take_buy.rs b/src/app/take_buy.rs index 37b00f80..8d46509e 100644 --- a/src/app/take_buy.rs +++ b/src/app/take_buy.rs @@ -38,7 +38,7 @@ pub async fn take_buy_action( // Maker can't take own order if order.kind != Kind::Buy.to_string() || order.creator_pubkey == event.sender.to_hex() { - send_cant_do_msg(request_id, Some(order.id), None, &event.sender).await; + send_cant_do_msg(request_id, Some(order.id), None, &event.rumor.pubkey).await; return Ok(()); } diff --git a/src/app/take_sell.rs b/src/app/take_sell.rs index 9c34cfb0..9bba5e11 100644 --- a/src/app/take_sell.rs +++ b/src/app/take_sell.rs @@ -39,7 +39,7 @@ pub async fn take_sell_action( // Maker can't take own order if order.creator_pubkey == event.sender.to_hex() { - send_cant_do_msg(request_id, Some(order.id), None, &event.sender).await; + send_cant_do_msg(request_id, Some(order.id), None, &event.rumor.pubkey).await; return Ok(()); } @@ -73,7 +73,7 @@ pub async fn take_sell_action( request_id, Some(order.id), Some(CantDoReason::InvalidInvoice), - &event.sender, + &event.rumor.pubkey, ) .await; error!("{e}"); diff --git a/src/util.rs b/src/util.rs index 8874a6b0..a64d0048 100644 --- a/src/util.rs +++ b/src/util.rs @@ -590,7 +590,7 @@ pub async fn settle_seller_hold_invoice( ) -> Result<()> { // Check if the pubkey is right if !is_admin && event.sender.to_string() != *order.seller_pubkey.as_ref().unwrap().to_string() { - send_cant_do_msg(request_id, Some(order.id), None, &event.sender).await; + send_cant_do_msg(request_id, Some(order.id), None, &event.rumor.pubkey).await; return Err(Error::msg("Not allowed")); } @@ -599,7 +599,7 @@ pub async fn settle_seller_hold_invoice( ln_client.settle_hold_invoice(preimage).await?; info!("{action}: Order Id {}: hold invoice settled", order.id); } else { - send_cant_do_msg(request_id, Some(order.id), None, &event.sender).await; + send_cant_do_msg(request_id, Some(order.id), None, &event.rumor.pubkey).await; return Err(Error::msg("No preimage")); } Ok(()) From ca38530ec0343cd3c0fadc9f46a8fbe46c1ba780 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Francisco=20Calder=C3=B3n?= Date: Fri, 13 Dec 2024 10:34:04 -0300 Subject: [PATCH 21/31] Improve error management --- src/app/rate_user.rs | 6 ++++++ src/util.rs | 4 +++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/app/rate_user.rs b/src/app/rate_user.rs index b0697e75..bf207306 100644 --- a/src/app/rate_user.rs +++ b/src/app/rate_user.rs @@ -121,6 +121,12 @@ pub async fn update_user_reputation_action( let rating; if let Some(Payload::RatingUser(v)) = msg.get_inner_message_kind().payload.to_owned() { + if !(MIN_RATING..=MAX_RATING).contains(&v) { + return Err(Error::msg(format!( + "Rating must be between {} and {}", + MIN_RATING, MAX_RATING + ))); + } rating = v; } else { return Err(Error::msg("No rating present")); diff --git a/src/util.rs b/src/util.rs index a64d0048..6645c077 100644 --- a/src/util.rs +++ b/src/util.rs @@ -268,7 +268,9 @@ pub async fn send_dm( ); if let Ok(client) = get_nostr_client() { - let _ = client.send_event(event).await; + if let Err(e) = client.send_event(event).await { + error!("Failed to send event: {}", e); + } } Ok(()) From 3a637508ba04da8b90ede44ba4b14ceb4ce0acc8 Mon Sep 17 00:00:00 2001 From: arkanoider Date: Sun, 15 Dec 2024 11:12:41 +0100 Subject: [PATCH 22/31] Fix: changed to trade keys the receiver of the messages of take-sell --- src/app/take_sell.rs | 11 ++++++----- src/util.rs | 14 +++++++++----- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/app/take_sell.rs b/src/app/take_sell.rs index 9bba5e11..3610d670 100644 --- a/src/app/take_sell.rs +++ b/src/app/take_sell.rs @@ -47,7 +47,8 @@ pub async fn take_sell_action( return Ok(()); } - let buyer_pubkey = event.sender; + // Get trade pubkey of the buyer + let buyer_trade_pubkey = event.rumor.pubkey; let seller_pubkey = match &order.seller_pubkey { Some(seller) => PublicKey::from_str(seller.as_str())?, @@ -100,7 +101,7 @@ pub async fn take_sell_action( Some(order.id), Action::NotAllowedByStatus, None, - &buyer_pubkey, + &buyer_trade_pubkey, None, ) .await; @@ -125,7 +126,7 @@ pub async fn take_sell_action( } // Add buyer pubkey to order - order.buyer_pubkey = Some(buyer_pubkey.to_string()); + order.buyer_pubkey = Some(buyer_trade_pubkey.to_string()); order.trade_index_buyer = msg.get_inner_message_kind().trade_index; // Timestamp take order time order.taken_at = Timestamp::now().as_u64() as i64; @@ -140,7 +141,7 @@ pub async fn take_sell_action( } if pr.is_none() { - match set_waiting_invoice_status(&mut order, buyer_pubkey, request_id).await { + match set_waiting_invoice_status(&mut order, buyer_trade_pubkey, request_id).await { Ok(_) => { // Update order status if let Ok(order_updated) = @@ -159,7 +160,7 @@ pub async fn take_sell_action( show_hold_invoice( my_keys, pr, - &buyer_pubkey, + &buyer_trade_pubkey, &seller_pubkey, order, request_id, diff --git a/src/util.rs b/src/util.rs index 6645c077..42632636 100644 --- a/src/util.rs +++ b/src/util.rs @@ -162,12 +162,12 @@ pub async fn publish_order( keys: &Keys, new_order: &SmallOrder, initiator_pubkey: &str, - ack_pubkey: PublicKey, + trade_pubkey: PublicKey, request_id: Option, trade_index: Option, ) -> Result<()> { // Prepare a new default order - let new_order_db = prepare_new_order(new_order, initiator_pubkey, trade_index).await?; + let new_order_db = prepare_new_order(new_order, initiator_pubkey, trade_index, trade_pubkey).await?; // CRUD order creation let mut order = new_order_db.clone().create(pool).await?; @@ -194,7 +194,7 @@ pub async fn publish_order( Some(order_id), Action::NewOrder, Some(Payload::Order(order)), - &ack_pubkey, + &trade_pubkey, trade_index, ) .await; @@ -212,6 +212,7 @@ async fn prepare_new_order( new_order: &SmallOrder, initiator_pubkey: &str, trade_index: Option, + trade_pubkey: PublicKey, ) -> Result { let mut fee = 0; if new_order.amount > 0 { @@ -243,10 +244,10 @@ async fn prepare_new_order( if new_order.kind == Some(OrderKind::Buy) { new_order_db.kind = OrderKind::Buy.to_string(); - new_order_db.buyer_pubkey = Some(initiator_pubkey.to_string()); + new_order_db.buyer_pubkey = Some(trade_pubkey.to_string()); new_order_db.trade_index_buyer = trade_index; } else { - new_order_db.seller_pubkey = Some(initiator_pubkey.to_string()); + new_order_db.seller_pubkey = Some(trade_pubkey.to_string()); new_order_db.trade_index_seller = trade_index; } @@ -261,6 +262,9 @@ pub async fn send_dm( sender_keys: Keys, payload: String, ) -> Result<()> { + + info!("sender key {} - receiver key {}", sender_keys.public_key().to_hex(), receiver_pubkey.to_hex()); + let event = gift_wrap(&sender_keys, *receiver_pubkey, payload.clone(), None)?; info!( "Sending DM, Event ID: {} with payload: {:#?}", From 6f9af773af31f54eaada3e58a0a5599f381cc296 Mon Sep 17 00:00:00 2001 From: arkanoider Date: Sun, 15 Dec 2024 11:39:15 +0100 Subject: [PATCH 23/31] small improvement on new-order creation suggested by the rabbit --- src/error.rs | 2 ++ src/util.rs | 48 +++++++++++++++++++++++++++++++++++------------- 2 files changed, 37 insertions(+), 13 deletions(-) diff --git a/src/error.rs b/src/error.rs index 0d3190e8..fcce1f40 100644 --- a/src/error.rs +++ b/src/error.rs @@ -16,6 +16,7 @@ pub enum MostroError { LnAddressWrongAmount, LnPaymentError(String), LnNodeError(String), + InvalidOrderKind, } impl std::error::Error for MostroError {} @@ -37,6 +38,7 @@ impl fmt::Display for MostroError { MostroError::LnAddressParseError => write!(f, "Ln address parsing error - please check your address"), MostroError::LnPaymentError(e) => write!(f, "Lightning payment failure cause: {}",e), MostroError::LnNodeError(e) => write!(f, "Lightning node connection failure caused by: {}",e), + MostroError::InvalidOrderKind => write!(f, "Invalid order kind"), } } } diff --git a/src/util.rs b/src/util.rs index 42632636..226e4a11 100644 --- a/src/util.rs +++ b/src/util.rs @@ -167,7 +167,13 @@ pub async fn publish_order( trade_index: Option, ) -> Result<()> { // Prepare a new default order - let new_order_db = prepare_new_order(new_order, initiator_pubkey, trade_index, trade_pubkey).await?; + let new_order_db = + match prepare_new_order(new_order, initiator_pubkey, trade_index, trade_pubkey).await { + Some(order) => order, + None => { + return Ok(()); + } + }; // CRUD order creation let mut order = new_order_db.clone().create(pool).await?; @@ -213,7 +219,7 @@ async fn prepare_new_order( initiator_pubkey: &str, trade_index: Option, trade_pubkey: PublicKey, -) -> Result { +) -> Option { let mut fee = 0; if new_order.amount > 0 { fee = get_fee(new_order.amount); @@ -242,19 +248,32 @@ async fn prepare_new_order( ..Default::default() }; - if new_order.kind == Some(OrderKind::Buy) { - new_order_db.kind = OrderKind::Buy.to_string(); - new_order_db.buyer_pubkey = Some(trade_pubkey.to_string()); - new_order_db.trade_index_buyer = trade_index; - } else { - new_order_db.seller_pubkey = Some(trade_pubkey.to_string()); - new_order_db.trade_index_seller = trade_index; + match new_order.kind { + Some(OrderKind::Buy) => { + new_order_db.kind = OrderKind::Buy.to_string(); + new_order_db.buyer_pubkey = Some(trade_pubkey.to_string()); + new_order_db.trade_index_buyer = trade_index; + } + Some(OrderKind::Sell) => { + new_order_db.kind = OrderKind::Sell.to_string(); + new_order_db.seller_pubkey = Some(trade_pubkey.to_string()); + new_order_db.trade_index_seller = trade_index; + } + None => { + send_cant_do_msg( + None, + None, + Some(CantDoReason::InvalidOrderKind), + &trade_pubkey, + ) + .await; + return None; + } } // Request price from API in case amount is 0 new_order_db.price_from_api = new_order.amount == 0; - - Ok(new_order_db) + Some(new_order_db) } pub async fn send_dm( @@ -262,8 +281,11 @@ pub async fn send_dm( sender_keys: Keys, payload: String, ) -> Result<()> { - - info!("sender key {} - receiver key {}", sender_keys.public_key().to_hex(), receiver_pubkey.to_hex()); + info!( + "sender key {} - receiver key {}", + sender_keys.public_key().to_hex(), + receiver_pubkey.to_hex() + ); let event = gift_wrap(&sender_keys, *receiver_pubkey, payload.clone(), None)?; info!( From 4d7df93df1e438da9dbd442c90aa91fba9b8c245 Mon Sep 17 00:00:00 2001 From: arkanoider Date: Sun, 15 Dec 2024 11:52:10 +0100 Subject: [PATCH 24/31] bumped mostro-core for building --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 4eefd0e0..1279c2e0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,7 +38,7 @@ uuid = { version = "1.8.0", features = [ "serde", ] } reqwest = { version = "0.12.1", features = ["json"] } -mostro-core = { version = "0.6.16", features = ["sqlx"] } +mostro-core = { version = "0.6.18", features = ["sqlx"] } tracing = "0.1.40" tracing-subscriber = { version = "0.3.18", features = ["env-filter"] } config = "0.14.0" From 6045d4e3f4de1f159015db8de977d47d222b2a76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Francisco=20Calder=C3=B3n?= Date: Tue, 17 Dec 2024 15:41:54 -0300 Subject: [PATCH 25/31] Use right seller pubkey on take_buy command --- Cargo.lock | 4 ++-- src/app/take_buy.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7aa80c3b..2471597a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1991,9 +1991,9 @@ dependencies = [ [[package]] name = "mostro-core" -version = "0.6.16" +version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfa673ea01ea2e91bcfc8fa4c6557afb1f8c9795ee909ff1776ff686f6fb26b8" +checksum = "365f4109979a283c0f198befaa9a518edb346873ead95fca742fb7cc5eb65c81" dependencies = [ "anyhow", "bitcoin", diff --git a/src/app/take_buy.rs b/src/app/take_buy.rs index 8d46509e..f829c6e3 100644 --- a/src/app/take_buy.rs +++ b/src/app/take_buy.rs @@ -58,7 +58,7 @@ pub async fn take_buy_action( }; // We update the pubkey - let seller_pubkey = event.sender; + let seller_pubkey = event.rumor.pubkey; // Seller can take pending orders only match order_status { Status::Pending => {} From 65a1d4965b94dfbe612fe1adef051fed393f190a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Francisco=20Calder=C3=B3n?= Date: Thu, 19 Dec 2024 18:07:31 -0300 Subject: [PATCH 26/31] Fix sender pubkey Before keys management we send back DM to event.sender now the event.sender pubkey in our gift wrap is the user identity and we need to send the message to the trade key and keep the user privacy --- src/app/add_invoice.rs | 16 +++++++++++----- src/app/admin_add_solver.rs | 4 ++-- src/app/admin_cancel.rs | 10 +++++----- src/app/admin_settle.rs | 10 +++++----- src/app/admin_take_dispute.rs | 12 ++++++------ src/app/cancel.rs | 18 +++++++++--------- src/app/dispute.rs | 4 ++-- src/app/fiat_sent.rs | 8 ++++---- src/app/order.rs | 2 +- src/app/rate_user.rs | 4 ++-- src/app/release.rs | 4 ++-- src/app/take_buy.rs | 4 ++-- src/app/take_sell.rs | 4 ++-- src/util.rs | 4 ++-- 14 files changed, 55 insertions(+), 49 deletions(-) diff --git a/src/app/add_invoice.rs b/src/app/add_invoice.rs index 5199510b..b2ba221b 100644 --- a/src/app/add_invoice.rs +++ b/src/app/add_invoice.rs @@ -3,7 +3,7 @@ use crate::util::{send_cant_do_msg, send_new_order_msg, show_hold_invoice, updat use anyhow::{Error, Result}; -use mostro_core::message::{Action, Message, Payload}; +use mostro_core::message::{Action, CantDoReason, Message, Payload}; use mostro_core::order::SmallOrder; use mostro_core::order::{Kind, Order, Status}; use nostr::nips::nip59::UnwrappedGift; @@ -57,8 +57,14 @@ pub async fn add_invoice_action( } }; // Only the buyer can add an invoice - if buyer_pubkey != event.sender { - send_cant_do_msg(request_id, Some(order.id), None, &event.rumor.pubkey).await; + if buyer_pubkey != event.rumor.pubkey { + send_cant_do_msg( + request_id, + Some(order.id), + Some(CantDoReason::InvalidPeer), + &event.rumor.pubkey, + ) + .await; return Ok(()); } @@ -82,7 +88,7 @@ pub async fn add_invoice_action( Some(order.id), Action::IncorrectInvoiceAmount, None, - &event.sender, + &event.rumor.pubkey, None, ) .await; @@ -119,7 +125,7 @@ pub async fn add_invoice_action( Some(order.id), Action::NotAllowedByStatus, None, - &event.sender, + &event.rumor.pubkey, None, ) .await; diff --git a/src/app/admin_add_solver.rs b/src/app/admin_add_solver.rs index 2209588a..22e7d1e6 100644 --- a/src/app/admin_add_solver.rs +++ b/src/app/admin_add_solver.rs @@ -33,7 +33,7 @@ pub async fn admin_add_solver_action( }; // Check if the pubkey is Mostro - if event.sender.to_string() != my_keys.public_key().to_string() { + if event.rumor.pubkey.to_string() != my_keys.public_key().to_string() { // We create a Message send_cant_do_msg(request_id, None, None, &event.rumor.pubkey).await; return Ok(()); @@ -51,7 +51,7 @@ pub async fn admin_add_solver_action( let message = message.as_json()?; // Send the message let sender_keys = crate::util::get_keys().unwrap(); - send_dm(&event.sender, sender_keys, message).await?; + send_dm(&event.rumor.pubkey, sender_keys, message).await?; Ok(()) } diff --git a/src/app/admin_cancel.rs b/src/app/admin_cancel.rs index c7acd845..3bf9bc7d 100644 --- a/src/app/admin_cancel.rs +++ b/src/app/admin_cancel.rs @@ -33,14 +33,14 @@ pub async fn admin_cancel_action( }; let inner_message = msg.get_inner_message_kind(); - match is_assigned_solver(pool, &event.sender.to_string(), order_id).await { + match is_assigned_solver(pool, &event.rumor.pubkey.to_string(), order_id).await { Ok(false) => { send_new_order_msg( inner_message.request_id, Some(order_id), Action::IsNotYourDispute, None, - &event.sender, + &event.rumor.pubkey, inner_message.trade_index, ) .await; @@ -72,7 +72,7 @@ pub async fn admin_cancel_action( ); if let Ok(message) = message.as_json() { let sender_keys = crate::util::get_keys().unwrap(); - let _ = send_dm(&event.sender, sender_keys, message).await; + let _ = send_dm(&event.rumor.pubkey, sender_keys, message).await; } return Ok(()); } @@ -83,7 +83,7 @@ pub async fn admin_cancel_action( Some(order.id), Action::NotAllowedByStatus, None, - &event.sender, + &event.rumor.pubkey, inner_message.trade_index, ) .await; @@ -149,7 +149,7 @@ pub async fn admin_cancel_action( let message = message.as_json()?; // Message to admin let sender_keys = crate::util::get_keys().unwrap(); - send_dm(&event.sender, sender_keys, message.clone()).await?; + send_dm(&event.rumor.pubkey, sender_keys, message.clone()).await?; let (seller_pubkey, buyer_pubkey) = match (&order.seller_pubkey, &order.buyer_pubkey) { (Some(seller), Some(buyer)) => ( diff --git a/src/app/admin_settle.rs b/src/app/admin_settle.rs index 7003dd64..c25a8626 100644 --- a/src/app/admin_settle.rs +++ b/src/app/admin_settle.rs @@ -35,14 +35,14 @@ pub async fn admin_settle_action( }; let inner_message = msg.get_inner_message_kind(); - match is_assigned_solver(pool, &event.sender.to_string(), order_id).await { + match is_assigned_solver(pool, &event.rumor.pubkey.to_string(), order_id).await { Ok(false) => { send_new_order_msg( msg.get_inner_message_kind().request_id, Some(order_id), Action::IsNotYourDispute, None, - &event.sender, + &event.rumor.pubkey, inner_message.trade_index, ) .await; @@ -74,7 +74,7 @@ pub async fn admin_settle_action( ); if let Ok(message) = message.as_json() { let sender_keys = crate::util::get_keys().unwrap(); - let _ = send_dm(&event.sender, sender_keys, message).await; + let _ = send_dm(&event.rumor.pubkey, sender_keys, message).await; } return Ok(()); } @@ -85,7 +85,7 @@ pub async fn admin_settle_action( Some(order.id), Action::NotAllowedByStatus, None, - &event.sender, + &event.rumor.pubkey, inner_message.trade_index, ) .await; @@ -153,7 +153,7 @@ pub async fn admin_settle_action( let message = message.as_json()?; // Message to admin let sender_keys = crate::util::get_keys().unwrap(); - send_dm(&event.sender, sender_keys.clone(), message.clone()).await?; + send_dm(&event.rumor.pubkey, sender_keys.clone(), message.clone()).await?; if let Some(ref seller_pubkey) = order_updated.seller_pubkey { send_dm( &PublicKey::from_str(seller_pubkey)?, diff --git a/src/app/admin_take_dispute.rs b/src/app/admin_take_dispute.rs index 276e99e4..4c94093e 100644 --- a/src/app/admin_take_dispute.rs +++ b/src/app/admin_take_dispute.rs @@ -62,7 +62,7 @@ pub async fn admin_take_dispute_action( Some(dispute_id), Action::NotFound, None, - &event.sender, + &event.rumor.pubkey, None, ) .await; @@ -72,7 +72,7 @@ pub async fn admin_take_dispute_action( // Check if the pubkey is a solver or admin if let Ok(dispute_status) = Status::from_str(&dispute.status) { - if !pubkey_event_can_solve(pool, &event.sender, dispute_status).await { + if !pubkey_event_can_solve(pool, &event.rumor.pubkey, dispute_status).await { // We create a Message send_cant_do_msg(request_id, Some(dispute_id), None, &event.rumor.pubkey).await; return Ok(()); @@ -96,10 +96,10 @@ pub async fn admin_take_dispute_action( // Update dispute fields dispute.status = Status::InProgress.to_string(); - dispute.solver_pubkey = Some(event.sender.to_string()); + dispute.solver_pubkey = Some(event.rumor.pubkey.to_string()); dispute.taken_at = Timestamp::now().as_u64() as i64; - info!("Dispute {} taken by {}", dispute_id, event.sender); + info!("Dispute {} taken by {}", dispute_id, event.rumor.pubkey); // Assign token for admin message new_order.seller_token = dispute.seller_token; new_order.buyer_token = dispute.buyer_token; @@ -116,10 +116,10 @@ pub async fn admin_take_dispute_action( ); let message = message.as_json()?; let sender_keys = crate::util::get_keys().unwrap(); - send_dm(&event.sender, sender_keys, message).await?; + send_dm(&event.rumor.pubkey, sender_keys, message).await?; // Now we create a message to both parties of the order // to them know who will assist them on the dispute - let solver_pubkey = Peer::new(event.sender.to_hex()); + let solver_pubkey = Peer::new(event.rumor.pubkey.to_hex()); let msg_to_buyer = Message::new_order( Some(order.id), request_id, diff --git a/src/app/cancel.rs b/src/app/cancel.rs index 2c59e9e8..d66da4b6 100644 --- a/src/app/cancel.rs +++ b/src/app/cancel.rs @@ -30,7 +30,7 @@ pub async fn cancel_action( } else { return Err(Error::msg("No order id")); }; - let user_pubkey = event.sender.to_string(); + let user_pubkey = event.rumor.pubkey.to_string(); let mut order = match find_order_by_id(pool, order_id, &user_pubkey).await { Ok(order) => order, @@ -49,7 +49,7 @@ pub async fn cancel_action( Some(order.id), Action::IsNotYourOrder, None, - &event.sender, + &event.rumor.pubkey, None, ) .await; @@ -65,7 +65,7 @@ pub async fn cancel_action( Some(order.id), Action::Canceled, None, - &event.sender, + &event.rumor.pubkey, None, ) .await; @@ -133,7 +133,7 @@ pub async fn cancel_action( Some(order.id), Action::CooperativeCancelAccepted, None, - &event.sender, + &event.rumor.pubkey, None, ) .await; @@ -160,7 +160,7 @@ pub async fn cancel_action( Some(order.id), Action::CooperativeCancelInitiatedByYou, None, - &event.sender, + &event.rumor.pubkey, None, ) .await; @@ -193,7 +193,7 @@ pub async fn cancel_add_invoice( info!("Order Id {}: Funds returned to seller", &order.id); } - let user_pubkey = event.sender.to_string(); + let user_pubkey = event.rumor.pubkey.to_string(); let (seller_pubkey, buyer_pubkey) = match (&order.seller_pubkey, &order.buyer_pubkey) { (Some(seller), Some(buyer)) => (PublicKey::from_str(seller.as_str())?, buyer), @@ -217,7 +217,7 @@ pub async fn cancel_add_invoice( Some(order.id), Action::Canceled, None, - &event.sender, + &event.rumor.pubkey, None, ) .await; @@ -264,7 +264,7 @@ pub async fn cancel_pay_hold_invoice( info!("Order Id {}: Funds returned to seller", &order.id); } } - let user_pubkey = event.sender.to_string(); + let user_pubkey = event.rumor.pubkey.to_string(); let (seller_pubkey, buyer_pubkey) = match (&order.seller_pubkey, &order.buyer_pubkey) { (Some(seller), Some(buyer)) => (PublicKey::from_str(seller.as_str())?, buyer), @@ -288,7 +288,7 @@ pub async fn cancel_pay_hold_invoice( Some(order.id), Action::Canceled, None, - &event.sender, + &event.rumor.pubkey, None, ) .await; diff --git a/src/app/dispute.rs b/src/app/dispute.rs index 5749734e..855c11eb 100644 --- a/src/app/dispute.rs +++ b/src/app/dispute.rs @@ -120,7 +120,7 @@ async fn get_valid_order( Some(order.id), Action::NotAllowedByStatus, None, - &event.sender, + &event.rumor.pubkey, None, ) .await; @@ -179,7 +179,7 @@ pub async fn dispute_action( (_, None) => return Err(Error::msg("Missing buyer pubkey")), }; - let message_sender = event.sender.to_string(); + let message_sender = event.rumor.pubkey.to_string(); let (counterpart, is_buyer_dispute) = match get_counterpart_info(&message_sender, &buyer, &seller) { Ok((counterpart, is_buyer_dispute)) => (counterpart, is_buyer_dispute), diff --git a/src/app/fiat_sent.rs b/src/app/fiat_sent.rs index b6128d1d..aeaae559 100644 --- a/src/app/fiat_sent.rs +++ b/src/app/fiat_sent.rs @@ -38,14 +38,14 @@ pub async fn fiat_sent_action( Some(order.id), Action::NotAllowedByStatus, None, - &event.sender, + &event.rumor.pubkey, None, ) .await; return Ok(()); } // Check if the pubkey is the buyer - if Some(event.sender.to_string()) != order.buyer_pubkey { + if Some(event.rumor.pubkey.to_string()) != order.buyer_pubkey { send_cant_do_msg(request_id, Some(order.id), None, &event.rumor.pubkey).await; return Ok(()); } @@ -63,7 +63,7 @@ pub async fn fiat_sent_action( return Ok(()); } }; - let peer = Peer::new(event.sender.to_string()); + let peer = Peer::new(event.rumor.pubkey.to_string()); // We a message to the seller send_new_order_msg( @@ -83,7 +83,7 @@ pub async fn fiat_sent_action( Some(order.id), Action::FiatSentOk, Some(Payload::Peer(peer)), - &event.sender, + &event.rumor.pubkey, None, ) .await; diff --git a/src/app/order.rs b/src/app/order.rs index 585e6b27..9e2dbe36 100644 --- a/src/app/order.rs +++ b/src/app/order.rs @@ -118,7 +118,7 @@ pub async fn order_action( pool, my_keys, order, - &event.sender.to_string(), + &event.rumor.pubkey.to_string(), event.rumor.pubkey, request_id, msg.get_inner_message_kind().trade_index, diff --git a/src/app/rate_user.rs b/src/app/rate_user.rs index bf207306..52e63bfe 100644 --- a/src/app/rate_user.rs +++ b/src/app/rate_user.rs @@ -76,7 +76,7 @@ pub async fn update_user_reputation_action( (_, None) => return Err(Error::msg("Missing buyer pubkey")), }; - let message_sender = event.sender.to_string(); + let message_sender = event.rumor.pubkey.to_string(); if order.status != Status::Success.to_string() { send_cant_do_msg(request_id, Some(order.id), None, &event.rumor.pubkey).await; @@ -178,7 +178,7 @@ pub async fn update_user_reputation_action( Some(order.id), Action::RateReceived, Some(Payload::RatingUser(rating)), - &event.sender, + &event.rumor.pubkey, None, ) .await; diff --git a/src/app/release.rs b/src/app/release.rs index 723a7bc5..a7ec8ccb 100644 --- a/src/app/release.rs +++ b/src/app/release.rs @@ -90,7 +90,7 @@ pub async fn release_action( return Ok(()); } }; - let seller_pubkey = event.sender; + let seller_pubkey = event.rumor.pubkey; let current_status = if let Ok(current_status) = Status::from_str(&order.status) { current_status @@ -107,7 +107,7 @@ pub async fn release_action( Some(order.id), Action::NotAllowedByStatus, None, - &event.sender, + &event.rumor.pubkey, None, ) .await; diff --git a/src/app/take_buy.rs b/src/app/take_buy.rs index f829c6e3..05938210 100644 --- a/src/app/take_buy.rs +++ b/src/app/take_buy.rs @@ -37,7 +37,7 @@ pub async fn take_buy_action( }; // Maker can't take own order - if order.kind != Kind::Buy.to_string() || order.creator_pubkey == event.sender.to_hex() { + if order.kind != Kind::Buy.to_string() || order.creator_pubkey == event.rumor.pubkey.to_hex() { send_cant_do_msg(request_id, Some(order.id), None, &event.rumor.pubkey).await; return Ok(()); } @@ -85,7 +85,7 @@ pub async fn take_buy_action( Some(order.id), Action::OutOfRangeFiatAmount, None, - &event.sender, + &event.rumor.pubkey, None, ) .await; diff --git a/src/app/take_sell.rs b/src/app/take_sell.rs index 3610d670..9dc5fbc9 100644 --- a/src/app/take_sell.rs +++ b/src/app/take_sell.rs @@ -38,7 +38,7 @@ pub async fn take_sell_action( }; // Maker can't take own order - if order.creator_pubkey == event.sender.to_hex() { + if order.creator_pubkey == event.rumor.pubkey.to_hex() { send_cant_do_msg(request_id, Some(order.id), None, &event.rumor.pubkey).await; return Ok(()); } @@ -118,7 +118,7 @@ pub async fn take_sell_action( Some(order.id), Action::OutOfRangeFiatAmount, None, - &event.sender, + &event.rumor.pubkey, None, ) .await; diff --git a/src/util.rs b/src/util.rs index 226e4a11..87d65c28 100644 --- a/src/util.rs +++ b/src/util.rs @@ -383,8 +383,8 @@ pub async fn connect_nostr() -> Result { let nostr_settings = Settings::get_nostr(); let mut limits = RelayLimits::default(); - limits.messages.max_size = Some(3_000); - limits.events.max_size = Some(3_500); + limits.messages.max_size = Some(6_000); + limits.events.max_size = Some(6_500); let opts = Options::new().relay_limits(limits); // Create new client From d4d4540e01525939bd3ba18ce1bef1e3d5e2282d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Francisco=20Calder=C3=B3n?= Date: Thu, 19 Dec 2024 18:35:36 -0300 Subject: [PATCH 27/31] Key management related bug fix on release --- src/app/release.rs | 26 ++++++++++++++++++++++---- src/util.rs | 20 +++++++++++++++++--- 2 files changed, 39 insertions(+), 7 deletions(-) diff --git a/src/app/release.rs b/src/app/release.rs index a7ec8ccb..247ed32e 100644 --- a/src/app/release.rs +++ b/src/app/release.rs @@ -11,7 +11,7 @@ use crate::NOSTR_CLIENT; use anyhow::{Error, Result}; use fedimint_tonic_lnd::lnrpc::payment::PaymentStatus; use lnurl::lightning_address::LightningAddress; -use mostro_core::message::{Action, Message}; +use mostro_core::message::{Action, CantDoReason, Message}; use mostro_core::order::{Order, Status}; use nostr::nips::nip59::UnwrappedGift; use nostr_sdk::prelude::*; @@ -115,7 +115,13 @@ pub async fn release_action( } if &seller_pubkey.to_string() != seller_pubkey_hex { - send_cant_do_msg(request_id, Some(order.id), None, &event.rumor.pubkey).await; + send_cant_do_msg( + request_id, + Some(order.id), + Some(CantDoReason::InvalidPeer), + &event.rumor.pubkey, + ) + .await; return Ok(()); } @@ -358,8 +364,20 @@ async fn payment_success( Ordering::Less => {} } } else { - send_cant_do_msg(None, Some(order.id), None, buyer_pubkey).await; - send_cant_do_msg(request_id, Some(order.id), None, seller_pubkey).await; + send_cant_do_msg( + None, + Some(order.id), + Some(CantDoReason::InvalidAmount), + buyer_pubkey, + ) + .await; + send_cant_do_msg( + request_id, + Some(order.id), + Some(CantDoReason::InvalidAmount), + seller_pubkey, + ) + .await; } } } diff --git a/src/util.rs b/src/util.rs index 87d65c28..60cd205b 100644 --- a/src/util.rs +++ b/src/util.rs @@ -617,8 +617,16 @@ pub async fn settle_seller_hold_invoice( request_id: Option, ) -> Result<()> { // Check if the pubkey is right - if !is_admin && event.sender.to_string() != *order.seller_pubkey.as_ref().unwrap().to_string() { - send_cant_do_msg(request_id, Some(order.id), None, &event.rumor.pubkey).await; + if !is_admin + && event.rumor.pubkey.to_string() != *order.seller_pubkey.as_ref().unwrap().to_string() + { + send_cant_do_msg( + request_id, + Some(order.id), + Some(CantDoReason::InvalidPeer), + &event.rumor.pubkey, + ) + .await; return Err(Error::msg("Not allowed")); } @@ -627,7 +635,13 @@ pub async fn settle_seller_hold_invoice( ln_client.settle_hold_invoice(preimage).await?; info!("{action}: Order Id {}: hold invoice settled", order.id); } else { - send_cant_do_msg(request_id, Some(order.id), None, &event.rumor.pubkey).await; + send_cant_do_msg( + request_id, + Some(order.id), + Some(CantDoReason::InvalidInvoice), + &event.rumor.pubkey, + ) + .await; return Err(Error::msg("No preimage")); } Ok(()) From 9c0f69f25ecc1c280db1e210cc443c37c6864b44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Francisco=20Calder=C3=B3n?= Date: Fri, 20 Dec 2024 09:21:08 -0300 Subject: [PATCH 28/31] Message and event size limits comments --- src/util.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/util.rs b/src/util.rs index 60cd205b..f7321ce9 100644 --- a/src/util.rs +++ b/src/util.rs @@ -383,6 +383,8 @@ pub async fn connect_nostr() -> Result { let nostr_settings = Settings::get_nostr(); let mut limits = RelayLimits::default(); + // Some specific events can have a bigger size than regular events + // So we increase the limits for those events limits.messages.max_size = Some(6_000); limits.events.max_size = Some(6_500); let opts = Options::new().relay_limits(limits); From c7f91a8038e6c7fdd58b776d19da7f39afb94e20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Francisco=20Calder=C3=B3n?= Date: Fri, 20 Dec 2024 09:56:34 -0300 Subject: [PATCH 29/31] Ensure message signature verification --- src/nip59.rs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/nip59.rs b/src/nip59.rs index 9440db26..e92ee9f7 100644 --- a/src/nip59.rs +++ b/src/nip59.rs @@ -23,12 +23,22 @@ pub fn gift_wrap( expiration: Option, ) -> Result { // We convert back the string to a message - let message = Message::from_json(&payload).unwrap(); + let message = Message::from_json(&payload).map_err(|e| { + BuilderError::NIP59(nip59::Error::Event(nostr::event::Error::Json(format!( + "Failed to parse message: {}", + e + )))) + })?; // We sign the message let sig = message.get_inner_message_kind().sign(sender_keys); // We compose the content let content = (message, sig); - let content = serde_json::to_string(&content).unwrap(); + let content = serde_json::to_string(&content).map_err(|e| { + BuilderError::NIP59(nip59::Error::Event(nostr::event::Error::Json(format!( + "Failed to serialize content: {}", + e + )))) + })?; let rumor: UnsignedEvent = EventBuilder::text_note(content).build(sender_keys.public_key()); let seal: Event = seal(sender_keys, &receiver, rumor)?.sign_with_keys(sender_keys)?; From f4488959634c2252c1ebee27fe6822feef179962 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Francisco=20Calder=C3=B3n?= Date: Fri, 20 Dec 2024 11:14:17 -0300 Subject: [PATCH 30/31] Save identity key on new order --- src/app/order.rs | 3 ++- src/util.rs | 32 ++++++++++++++++++++++---------- 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/src/app/order.rs b/src/app/order.rs index 9e2dbe36..901fe362 100644 --- a/src/app/order.rs +++ b/src/app/order.rs @@ -118,7 +118,8 @@ pub async fn order_action( pool, my_keys, order, - &event.rumor.pubkey.to_string(), + event.rumor.pubkey, + event.sender, event.rumor.pubkey, request_id, msg.get_inner_message_kind().trade_index, diff --git a/src/util.rs b/src/util.rs index f7321ce9..081af31a 100644 --- a/src/util.rs +++ b/src/util.rs @@ -157,30 +157,39 @@ pub fn get_expiration_date(expire: Option) -> i64 { expire_date } +#[allow(clippy::too_many_arguments)] pub async fn publish_order( pool: &SqlitePool, keys: &Keys, new_order: &SmallOrder, - initiator_pubkey: &str, + initiator_pubkey: PublicKey, + identity_pubkey: PublicKey, trade_pubkey: PublicKey, request_id: Option, trade_index: Option, ) -> Result<()> { // Prepare a new default order - let new_order_db = - match prepare_new_order(new_order, initiator_pubkey, trade_index, trade_pubkey).await { - Some(order) => order, - None => { - return Ok(()); - } - }; + let new_order_db = match prepare_new_order( + new_order, + initiator_pubkey, + trade_index, + identity_pubkey, + trade_pubkey, + ) + .await + { + Some(order) => order, + None => { + return Ok(()); + } + }; // CRUD order creation let mut order = new_order_db.clone().create(pool).await?; let order_id = order.id; info!("New order saved Id: {}", order_id); // Get user reputation - let reputation = get_user_reputation(initiator_pubkey, keys).await?; + let reputation = get_user_reputation(&initiator_pubkey.to_string(), keys).await?; // We transform the order fields to tags to use in the event let tags = order_to_tags(&new_order_db, reputation); // nip33 kind with order fields as tags and order id as identifier @@ -216,8 +225,9 @@ pub async fn publish_order( async fn prepare_new_order( new_order: &SmallOrder, - initiator_pubkey: &str, + initiator_pubkey: PublicKey, trade_index: Option, + identity_pubkey: PublicKey, trade_pubkey: PublicKey, ) -> Option { let mut fee = 0; @@ -252,11 +262,13 @@ async fn prepare_new_order( Some(OrderKind::Buy) => { new_order_db.kind = OrderKind::Buy.to_string(); new_order_db.buyer_pubkey = Some(trade_pubkey.to_string()); + new_order_db.master_buyer_pubkey = Some(identity_pubkey.to_string()); new_order_db.trade_index_buyer = trade_index; } Some(OrderKind::Sell) => { new_order_db.kind = OrderKind::Sell.to_string(); new_order_db.seller_pubkey = Some(trade_pubkey.to_string()); + new_order_db.master_seller_pubkey = Some(identity_pubkey.to_string()); new_order_db.trade_index_seller = trade_index; } None => { From 9ed2f2467b37b45c14bedfe7c8fd997d152a092e Mon Sep 17 00:00:00 2001 From: arkanoider Date: Fri, 20 Dec 2024 16:01:26 +0100 Subject: [PATCH 31/31] fix: range order counterpart trade index reset after success --- src/app/release.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/app/release.rs b/src/app/release.rs index 247ed32e..4acdc7ab 100644 --- a/src/app/release.rs +++ b/src/app/release.rs @@ -289,9 +289,11 @@ async fn payment_success( if new_order.kind == "sell" { new_order.buyer_pubkey = None; new_order.master_buyer_pubkey = None; + new_order.trade_index_buyer = None; } else { new_order.seller_pubkey = None; new_order.master_seller_pubkey = None; + new_order.trade_index_seller = None; } if let Some(min_amount) = &order.min_amount { match new_max.cmp(min_amount) {