From a0447d60c3674a16dfe4facabbbf1d097a8a3189 Mon Sep 17 00:00:00 2001 From: Daniel Karzel Date: Wed, 15 Sep 2021 13:20:42 +1000 Subject: [PATCH 1/3] Fix typos --- daemon/src/to_sse_event.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/daemon/src/to_sse_event.rs b/daemon/src/to_sse_event.rs index 76843ac..7b3cfc7 100644 --- a/daemon/src/to_sse_event.rs +++ b/daemon/src/to_sse_event.rs @@ -105,7 +105,7 @@ impl ToSseEvent for Option { creation_unix_timestamp: offer .creation_timestamp .duration_since(UNIX_EPOCH) - .expect("timestamp to be convertiblae to dureation since epoch") + .expect("timestamp to be convertible to duration since epoch") .as_secs(), term_in_secs: offer.term.as_secs(), }); From 76f49bce225203bda9c66adaa0d8f907237887de Mon Sep 17 00:00:00 2001 From: Daniel Karzel Date: Wed, 15 Sep 2021 13:22:29 +1000 Subject: [PATCH 2/3] `Origin` renames --- daemon/src/db.rs | 20 ++++++++++---------- daemon/src/maker_cfd_actor.rs | 4 ++-- daemon/src/taker_cfd_actor.rs | 4 ++-- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/daemon/src/db.rs b/daemon/src/db.rs index da6ab21..67cd322 100644 --- a/daemon/src/db.rs +++ b/daemon/src/db.rs @@ -9,9 +9,9 @@ use std::convert::TryInto; use std::mem; #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] -pub enum OfferOrigin { - Mine, - Others, +pub enum Origin { + Ours, + Theirs, } pub async fn run_migrations(pool: &SqlitePool) -> anyhow::Result<()> { @@ -22,7 +22,7 @@ pub async fn run_migrations(pool: &SqlitePool) -> anyhow::Result<()> { pub async fn insert_cfd_offer( cfd_offer: &CfdOffer, conn: &mut PoolConnection, - origin: OfferOrigin, + origin: Origin, ) -> anyhow::Result<()> { let uuid = serde_json::to_string(&cfd_offer.id).unwrap(); let trading_pair = serde_json::to_string(&cfd_offer.trading_pair).unwrap(); @@ -293,12 +293,12 @@ pub async fn load_all_cfds(conn: &mut PoolConnection) -> anyhow::Result< let quantity = serde_json::from_str(row.quantity_usd.as_str()).unwrap(); let latest_state = serde_json::from_str(row.state.as_str()).unwrap(); - let origin: OfferOrigin = serde_json::from_str(row.origin.as_str()).unwrap(); + let origin: Origin = serde_json::from_str(row.origin.as_str()).unwrap(); let position: Position = serde_json::from_str(row.position.as_str()).unwrap(); let position = match origin { - OfferOrigin::Mine => position, - OfferOrigin::Others => position.counter_position(), + Origin::Ours => position, + Origin::Theirs => position.counter_position(), }; Cfd { @@ -338,7 +338,7 @@ mod tests { let mut conn = pool.acquire().await.unwrap(); let cfd_offer = CfdOffer::from_default_with_price(Usd(dec!(10000))).unwrap(); - insert_cfd_offer(&cfd_offer, &mut conn, OfferOrigin::Others) + insert_cfd_offer(&cfd_offer, &mut conn, Origin::Theirs) .await .unwrap(); @@ -365,7 +365,7 @@ mod tests { ); // the order ahs to exist in the db in order to be able to insert the cfd - insert_cfd_offer(&cfd_offer, &mut conn, OfferOrigin::Others) + insert_cfd_offer(&cfd_offer, &mut conn, Origin::Theirs) .await .unwrap(); insert_cfd(cfd.clone(), &mut conn).await.unwrap(); @@ -393,7 +393,7 @@ mod tests { ); // the order ahs to exist in the db in order to be able to insert the cfd - insert_cfd_offer(&cfd_offer, &mut conn, OfferOrigin::Others) + insert_cfd_offer(&cfd_offer, &mut conn, Origin::Theirs) .await .unwrap(); insert_cfd(cfd.clone(), &mut conn).await.unwrap(); diff --git a/daemon/src/maker_cfd_actor.rs b/daemon/src/maker_cfd_actor.rs index 6af064d..99acedb 100644 --- a/daemon/src/maker_cfd_actor.rs +++ b/daemon/src/maker_cfd_actor.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; use std::time::SystemTime; -use crate::db::{insert_cfd, insert_cfd_offer, load_all_cfds, load_offer_by_id, OfferOrigin}; +use crate::db::{insert_cfd, insert_cfd_offer, load_all_cfds, load_offer_by_id, Origin}; use crate::model::cfd::{Cfd, CfdOffer, CfdOfferId, CfdState, CfdStateCommon, FinalizedCfd}; use crate::model::{TakerId, Usd}; use crate::wire::{Msg0, Msg1, SetupMsg}; @@ -131,7 +131,7 @@ where maker_cfd_actor::Command::NewOffer(offer) => { // 1. Save to DB let mut conn = db.acquire().await.unwrap(); - insert_cfd_offer(&offer, &mut conn, OfferOrigin::Mine) + insert_cfd_offer(&offer, &mut conn, Origin::Ours) .await .unwrap(); diff --git a/daemon/src/taker_cfd_actor.rs b/daemon/src/taker_cfd_actor.rs index 6e4a744..f1f34c0 100644 --- a/daemon/src/taker_cfd_actor.rs +++ b/daemon/src/taker_cfd_actor.rs @@ -1,6 +1,6 @@ use crate::db::{ insert_cfd, insert_cfd_offer, insert_new_cfd_state_by_offer_id, load_all_cfds, - load_offer_by_id, OfferOrigin, + load_offer_by_id, Origin, }; use crate::model::cfd::{ AsBlocks, Cfd, CfdOffer, CfdOfferId, CfdState, CfdStateCommon, FinalizedCfd, @@ -102,7 +102,7 @@ where } Command::NewOffer(Some(offer)) => { let mut conn = db.acquire().await.unwrap(); - insert_cfd_offer(&offer, &mut conn, OfferOrigin::Others) + insert_cfd_offer(&offer, &mut conn, Origin::Theirs) .await .unwrap(); offer_feed_actor_inbox.send(Some(offer)).unwrap(); From a8a807688772fef60571cc2506e7d67cfa646558 Mon Sep 17 00:00:00 2001 From: Daniel Karzel Date: Wed, 15 Sep 2021 13:56:33 +1000 Subject: [PATCH 3/3] Rename offer to order. Everywhere!!! --- README.md | 2 +- cfd_protocol/src/lib.rs | 2 +- ...903050345_create_cfd_and_order_tables.sql} | 16 +-- daemon/sqlx-data.json | 70 +++++----- daemon/src/db.rs | 122 +++++++++--------- daemon/src/maker.rs | 12 +- daemon/src/maker_cfd_actor.rs | 86 ++++++------ daemon/src/maker_inc_connections_actor.rs | 42 +++--- daemon/src/model/cfd.rs | 36 +++--- daemon/src/routes_maker.rs | 50 +++---- daemon/src/routes_taker.rs | 22 ++-- daemon/src/taker.rs | 8 +- daemon/src/taker_cfd_actor.rs | 58 ++++----- daemon/src/taker_inc_message_actor.rs | 10 +- daemon/src/to_sse_event.rs | 36 +++--- daemon/src/wire.rs | 16 +-- docs/asset/mvp_maker_taker_db.puml | 6 +- docs/asset/mvp_maker_taker_messaging.puml | 34 ++--- frontend/src/Maker.tsx | 42 +++--- frontend/src/Taker.tsx | 24 ++-- .../{CfdOffer.tsx => OrderTile.tsx} | 30 ++--- frontend/src/components/Types.tsx | 4 +- 22 files changed, 361 insertions(+), 367 deletions(-) rename daemon/migrations/{20210903050345_create_cfd_and_offer_tables.sql => 20210903050345_create_cfd_and_order_tables.sql} (75%) rename frontend/src/components/{CfdOffer.tsx => OrderTile.tsx} (71%) diff --git a/README.md b/README.md index d2f8af1..5f1ceeb 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ Once the maker is started you can start the taker: cargo run --bin taker ``` -Upon startup the taker daemon will connect to the (hardcoded) maker and retrieve the current offer. +Upon startup the taker daemon will connect to the (hardcoded) maker and retrieve the current order. Note: The sqlite databases for maker and taker are currently created in the project root. diff --git a/cfd_protocol/src/lib.rs b/cfd_protocol/src/lib.rs index 6b814ab..3b0e154 100644 --- a/cfd_protocol/src/lib.rs +++ b/cfd_protocol/src/lib.rs @@ -409,7 +409,7 @@ pub fn punish_transaction( Ok(punish_tx) } -// NOTE: We have decided to not offer any verification utility because +// NOTE: We have decided to not order any verification utility because // the APIs would be incredibly thin #[derive(Clone)] diff --git a/daemon/migrations/20210903050345_create_cfd_and_offer_tables.sql b/daemon/migrations/20210903050345_create_cfd_and_order_tables.sql similarity index 75% rename from daemon/migrations/20210903050345_create_cfd_and_offer_tables.sql rename to daemon/migrations/20210903050345_create_cfd_and_order_tables.sql index 3d0cdbd..b317b44 100644 --- a/daemon/migrations/20210903050345_create_cfd_and_offer_tables.sql +++ b/daemon/migrations/20210903050345_create_cfd_and_order_tables.sql @@ -1,5 +1,5 @@ -- todo: Decimal is had to deserialize as number so we use text -create table if not exists offers +create table if not exists orders ( id integer primary key autoincrement, uuid text unique not null, @@ -15,21 +15,21 @@ create table if not exists offers origin text not null ); -create unique index if not exists offers_uuid - on offers (uuid); +create unique index if not exists orders_uuid + on orders (uuid); create table if not exists cfds ( id integer primary key autoincrement, - offer_id integer unique not null, - offer_uuid text unique not null, + order_id integer unique not null, + order_uuid text unique not null, quantity_usd text not null, - foreign key (offer_id) references offers (id) + foreign key (order_id) references orders (id) ); -create unique index if not exists cfd_offer_uuid - on cfds (offer_uuid); +create unique index if not exists cfd_order_uuid + on cfds (order_uuid); create table if not exists cfd_states ( diff --git a/daemon/sqlx-data.json b/daemon/sqlx-data.json index 0ae0200..bd4298a 100644 --- a/daemon/sqlx-data.json +++ b/daemon/sqlx-data.json @@ -1,25 +1,35 @@ { "db": "SQLite", - "1bd5f2355d2e9351a443ec10b2533ca9326bb2a27b9f049d60759ac5a9eba758": { - "query": "\n select\n id\n from cfds\n where offer_uuid = ?;\n ", + "3ec696a1077ae52f21230ac33b9083ae3420698ff4d6bb1bba2d71ad518daf85": { + "query": "\n insert into orders (\n uuid,\n trading_pair,\n position,\n initial_price,\n min_quantity,\n max_quantity,\n leverage,\n liquidation_price,\n creation_timestamp,\n term,\n origin\n ) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);\n ", + "describe": { + "columns": [], + "parameters": { + "Right": 11 + }, + "nullable": [] + } + }, + "50abbb297394739ec9d85917f8c32aa8bcfa0bfe140b24e9eeda4ce8d30d4f8d": { + "query": "\n select\n state\n from cfd_states\n where cfd_id = ?\n order by id desc\n limit 1;\n ", "describe": { "columns": [ { - "name": "id", + "name": "state", "ordinal": 0, - "type_info": "Int64" + "type_info": "Text" } ], "parameters": { "Right": 1 }, "nullable": [ - true + false ] } }, - "2bfe23378b852e9c98f1db3e7c7694e1a7037183eb6fa8d81916cdb46c760547": { - "query": "\n select\n cfds.id as cfd_id,\n offers.uuid as offer_id,\n offers.initial_price as initial_price,\n offers.leverage as leverage,\n offers.trading_pair as trading_pair,\n offers.position as position,\n offers.origin as origin,\n offers.liquidation_price as liquidation_price,\n cfds.quantity_usd as quantity_usd,\n cfd_states.state as state\n from cfds as cfds\n inner join offers as offers on cfds.offer_id = offers.id\n inner join cfd_states as cfd_states on cfd_states.cfd_id = cfds.id\n where cfd_states.state in (\n select\n state\n from cfd_states\n where cfd_id = cfds.id\n order by id desc\n limit 1\n )\n ", + "7941da81b43abcaa82d51bbfecaed51f13fc637dc611cebb87eea638ba055a42": { + "query": "\n select\n cfds.id as cfd_id,\n orders.uuid as order_id,\n orders.initial_price as initial_price,\n orders.leverage as leverage,\n orders.trading_pair as trading_pair,\n orders.position as position,\n orders.origin as origin,\n orders.liquidation_price as liquidation_price,\n cfds.quantity_usd as quantity_usd,\n cfd_states.state as state\n from cfds as cfds\n inner join orders as orders on cfds.order_id = orders.id\n inner join cfd_states as cfd_states on cfd_states.cfd_id = cfds.id\n where cfd_states.state in (\n select\n state\n from cfd_states\n where cfd_id = cfds.id\n order by id desc\n limit 1\n )\n ", "describe": { "columns": [ { @@ -28,7 +38,7 @@ "type_info": "Int64" }, { - "name": "offer_id", + "name": "order_id", "ordinal": 1, "type_info": "Text" }, @@ -90,44 +100,24 @@ ] } }, - "4a8db91aaef56a804d0151460297175355c9adee100b87fa9052245cdd18d7e9": { - "query": "\n insert into offers (\n uuid,\n trading_pair,\n position,\n initial_price,\n min_quantity,\n max_quantity,\n leverage,\n liquidation_price,\n creation_timestamp,\n term,\n origin\n ) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);\n ", - "describe": { - "columns": [], - "parameters": { - "Right": 11 - }, - "nullable": [] - } - }, - "50abbb297394739ec9d85917f8c32aa8bcfa0bfe140b24e9eeda4ce8d30d4f8d": { - "query": "\n select\n state\n from cfd_states\n where cfd_id = ?\n order by id desc\n limit 1;\n ", + "8e7571250da58b12f5884f17656e5966957c7798ea029c701a4fc43fd613f015": { + "query": "\n select\n id\n from cfds\n where order_uuid = ?;\n ", "describe": { "columns": [ { - "name": "state", + "name": "id", "ordinal": 0, - "type_info": "Text" + "type_info": "Int64" } ], "parameters": { "Right": 1 }, "nullable": [ - false + true ] } }, - "79162c94809f9fac4850236d06a76206d0914285d462c04e30ad7af222092675": { - "query": "\n insert into cfds (\n offer_id,\n offer_uuid,\n quantity_usd\n ) values (?, ?, ?);\n ", - "describe": { - "columns": [], - "parameters": { - "Right": 3 - }, - "nullable": [] - } - }, "a464a1feb12abadff8bfd5b2b3b7362f3846869c0702944b21737eff8f420be5": { "query": "\n insert into cfd_states (\n cfd_id,\n state\n ) values (?, ?);\n ", "describe": { @@ -138,8 +128,8 @@ "nullable": [] } }, - "d380cac37744c2169d4e0a8f13d223cbd37ca5034e461a583b18cf7566a9c5c6": { - "query": "\n select * from offers where uuid = ?;\n ", + "f3dce76f316212c91cb3402b0cef00f1c9adbef8519c54e9bdbd373aab946209": { + "query": "\n select * from orders where uuid = ?;\n ", "describe": { "columns": [ { @@ -231,5 +221,15 @@ }, "nullable": [] } + }, + "fad32c267100e26f4fba80e4feb5ff45ee29c3a67bd378f6627b1f13ee45c573": { + "query": "\n insert into cfds (\n order_id,\n order_uuid,\n quantity_usd\n ) values (?, ?, ?);\n ", + "describe": { + "columns": [], + "parameters": { + "Right": 3 + }, + "nullable": [] + } } } \ No newline at end of file diff --git a/daemon/src/db.rs b/daemon/src/db.rs index 67cd322..8cc1509 100644 --- a/daemon/src/db.rs +++ b/daemon/src/db.rs @@ -1,4 +1,4 @@ -use crate::model::cfd::{Cfd, CfdOffer, CfdOfferId, CfdState}; +use crate::model::cfd::{Cfd, CfdState, Order, OrderId}; use crate::model::{Leverage, Position}; use anyhow::Context; use rocket_db_pools::sqlx; @@ -19,26 +19,26 @@ pub async fn run_migrations(pool: &SqlitePool) -> anyhow::Result<()> { Ok(()) } -pub async fn insert_cfd_offer( - cfd_offer: &CfdOffer, +pub async fn insert_order( + order: &Order, conn: &mut PoolConnection, origin: Origin, ) -> anyhow::Result<()> { - let uuid = serde_json::to_string(&cfd_offer.id).unwrap(); - let trading_pair = serde_json::to_string(&cfd_offer.trading_pair).unwrap(); - let position = serde_json::to_string(&cfd_offer.position).unwrap(); - let initial_price = serde_json::to_string(&cfd_offer.price).unwrap(); - let min_quantity = serde_json::to_string(&cfd_offer.min_quantity).unwrap(); - let max_quantity = serde_json::to_string(&cfd_offer.max_quantity).unwrap(); - let leverage = cfd_offer.leverage.0; - let liquidation_price = serde_json::to_string(&cfd_offer.liquidation_price).unwrap(); - let creation_timestamp = serde_json::to_string(&cfd_offer.creation_timestamp).unwrap(); - let term = serde_json::to_string(&cfd_offer.term).unwrap(); + let uuid = serde_json::to_string(&order.id).unwrap(); + let trading_pair = serde_json::to_string(&order.trading_pair).unwrap(); + let position = serde_json::to_string(&order.position).unwrap(); + let initial_price = serde_json::to_string(&order.price).unwrap(); + let min_quantity = serde_json::to_string(&order.min_quantity).unwrap(); + let max_quantity = serde_json::to_string(&order.max_quantity).unwrap(); + let leverage = order.leverage.0; + let liquidation_price = serde_json::to_string(&order.liquidation_price).unwrap(); + let creation_timestamp = serde_json::to_string(&order.creation_timestamp).unwrap(); + let term = serde_json::to_string(&order.term).unwrap(); let origin = serde_json::to_string(&origin).unwrap(); sqlx::query!( r#" - insert into offers ( + insert into orders ( uuid, trading_pair, position, @@ -70,15 +70,15 @@ pub async fn insert_cfd_offer( Ok(()) } -pub async fn load_offer_by_id( - id: CfdOfferId, +pub async fn load_order_by_id( + id: OrderId, conn: &mut PoolConnection, -) -> anyhow::Result { +) -> anyhow::Result { let uuid = serde_json::to_string(&id).unwrap(); let row = sqlx::query!( r#" - select * from offers where uuid = ?; + select * from orders where uuid = ?; "#, uuid ) @@ -96,7 +96,7 @@ pub async fn load_offer_by_id( let creation_timestamp = serde_json::from_str(row.creation_timestamp.as_str()).unwrap(); let term = serde_json::from_str(row.term.as_str()).unwrap(); - Ok(CfdOffer { + Ok(Order { id: uuid, trading_pair, position, @@ -113,17 +113,17 @@ pub async fn load_offer_by_id( pub async fn insert_cfd(cfd: Cfd, conn: &mut PoolConnection) -> anyhow::Result<()> { let mut tx = conn.begin().await?; - let offer_uuid = serde_json::to_string(&cfd.offer_id)?; - let offer_row = sqlx::query!( + let order_uuid = serde_json::to_string(&cfd.order_id)?; + let order_row = sqlx::query!( r#" - select * from offers where uuid = ?; + select * from orders where uuid = ?; "#, - offer_uuid + order_uuid ) .fetch_one(&mut tx) .await?; - let offer_id = offer_row.id; + let order_id = order_row.id; let quantity_usd = serde_json::to_string(&cfd.quantity_usd)?; let cfd_state = serde_json::to_string(&cfd.state)?; @@ -134,13 +134,13 @@ pub async fn insert_cfd(cfd: Cfd, conn: &mut PoolConnection) -> anyhow:: let cfd_id = sqlx::query!( r#" insert into cfds ( - offer_id, - offer_uuid, + order_id, + order_uuid, quantity_usd ) values (?, ?, ?); "#, - offer_id, - offer_uuid, + order_id, + order_uuid, quantity_usd, ) .execute(&mut tx) @@ -166,12 +166,12 @@ pub async fn insert_cfd(cfd: Cfd, conn: &mut PoolConnection) -> anyhow:: } #[allow(dead_code)] -pub async fn insert_new_cfd_state_by_offer_id( - offer_id: CfdOfferId, +pub async fn insert_new_cfd_state_by_order_id( + order_id: OrderId, new_state: CfdState, conn: &mut PoolConnection, ) -> anyhow::Result<()> { - let cfd_id = load_cfd_id_by_offer_uuid(offer_id, conn).await?; + let cfd_id = load_cfd_id_by_order_uuid(order_id, conn).await?; let latest_cfd_state_in_db = load_latest_cfd_state(cfd_id, conn) .await .context("loading latest state failed")?; @@ -179,7 +179,7 @@ pub async fn insert_new_cfd_state_by_offer_id( // make sure that the new state is different than the current one to avoid that we save the same // state twice if mem::discriminant(&latest_cfd_state_in_db) == mem::discriminant(&new_state) { - anyhow::bail!("Cannot insert new state {} for cfd with order_id {} because it currently already is in state {}", new_state, offer_id, latest_cfd_state_in_db); + anyhow::bail!("Cannot insert new state {} for cfd with order_id {} because it currently already is in state {}", new_state, order_id, latest_cfd_state_in_db); } let cfd_state = serde_json::to_string(&new_state)?; @@ -201,20 +201,20 @@ pub async fn insert_new_cfd_state_by_offer_id( } #[allow(dead_code)] -async fn load_cfd_id_by_offer_uuid( - offer_uuid: CfdOfferId, +async fn load_cfd_id_by_order_uuid( + order_uuid: OrderId, conn: &mut PoolConnection, ) -> anyhow::Result { - let offer_uuid = serde_json::to_string(&offer_uuid)?; + let order_uuid = serde_json::to_string(&order_uuid)?; let cfd_id = sqlx::query!( r#" select id from cfds - where offer_uuid = ?; + where order_uuid = ?; "#, - offer_uuid + order_uuid ) .fetch_one(conn) .await?; @@ -257,17 +257,17 @@ pub async fn load_all_cfds(conn: &mut PoolConnection) -> anyhow::Result< r#" select cfds.id as cfd_id, - offers.uuid as offer_id, - offers.initial_price as initial_price, - offers.leverage as leverage, - offers.trading_pair as trading_pair, - offers.position as position, - offers.origin as origin, - offers.liquidation_price as liquidation_price, + orders.uuid as order_id, + orders.initial_price as initial_price, + orders.leverage as leverage, + orders.trading_pair as trading_pair, + orders.position as position, + orders.origin as origin, + orders.liquidation_price as liquidation_price, cfds.quantity_usd as quantity_usd, cfd_states.state as state from cfds as cfds - inner join offers as offers on cfds.offer_id = offers.id + inner join orders as orders on cfds.order_id = orders.id inner join cfd_states as cfd_states on cfd_states.cfd_id = cfds.id where cfd_states.state in ( select @@ -285,7 +285,7 @@ pub async fn load_all_cfds(conn: &mut PoolConnection) -> anyhow::Result< let cfds = rows .iter() .map(|row| { - let offer_id = serde_json::from_str(row.offer_id.as_str()).unwrap(); + let order_id = serde_json::from_str(row.order_id.as_str()).unwrap(); let initial_price = serde_json::from_str(row.initial_price.as_str()).unwrap(); let leverage = Leverage(row.leverage.try_into().unwrap()); let trading_pair = serde_json::from_str(row.trading_pair.as_str()).unwrap(); @@ -302,7 +302,7 @@ pub async fn load_all_cfds(conn: &mut PoolConnection) -> anyhow::Result< }; Cfd { - offer_id, + order_id, initial_price, leverage, trading_pair, @@ -326,25 +326,25 @@ mod tests { use sqlx::SqlitePool; use tempfile::tempdir; - use crate::db::insert_cfd_offer; - use crate::model::cfd::{Cfd, CfdOffer, CfdState, CfdStateCommon}; + use crate::db::insert_order; + use crate::model::cfd::{Cfd, CfdState, CfdStateCommon, Order}; use crate::model::Usd; use super::*; #[tokio::test] - async fn test_insert_and_load_offer() { + async fn test_insert_and_load_order() { let pool = setup_test_db().await; let mut conn = pool.acquire().await.unwrap(); - let cfd_offer = CfdOffer::from_default_with_price(Usd(dec!(10000))).unwrap(); - insert_cfd_offer(&cfd_offer, &mut conn, Origin::Theirs) + let order = Order::from_default_with_price(Usd(dec!(10000))).unwrap(); + insert_order(&order, &mut conn, Origin::Theirs) .await .unwrap(); - let cfd_offer_loaded = load_offer_by_id(cfd_offer.id, &mut conn).await.unwrap(); + let order_loaded = load_order_by_id(order.id, &mut conn).await.unwrap(); - assert_eq!(cfd_offer, cfd_offer_loaded); + assert_eq!(order, order_loaded); } #[tokio::test] @@ -352,9 +352,9 @@ mod tests { let pool = setup_test_db().await; let mut conn = pool.acquire().await.unwrap(); - let cfd_offer = CfdOffer::from_default_with_price(Usd(dec!(10000))).unwrap(); + let order = Order::from_default_with_price(Usd(dec!(10000))).unwrap(); let cfd = Cfd::new( - cfd_offer.clone(), + order.clone(), Usd(dec!(1000)), CfdState::PendingTakeRequest { common: CfdStateCommon { @@ -365,7 +365,7 @@ mod tests { ); // the order ahs to exist in the db in order to be able to insert the cfd - insert_cfd_offer(&cfd_offer, &mut conn, Origin::Theirs) + insert_order(&order, &mut conn, Origin::Theirs) .await .unwrap(); insert_cfd(cfd.clone(), &mut conn).await.unwrap(); @@ -380,9 +380,9 @@ mod tests { let pool = setup_test_db().await; let mut conn = pool.acquire().await.unwrap(); - let cfd_offer = CfdOffer::from_default_with_price(Usd(dec!(10000))).unwrap(); + let order = Order::from_default_with_price(Usd(dec!(10000))).unwrap(); let mut cfd = Cfd::new( - cfd_offer.clone(), + order.clone(), Usd(dec!(1000)), CfdState::PendingTakeRequest { common: CfdStateCommon { @@ -393,7 +393,7 @@ mod tests { ); // the order ahs to exist in the db in order to be able to insert the cfd - insert_cfd_offer(&cfd_offer, &mut conn, Origin::Theirs) + insert_order(&order, &mut conn, Origin::Theirs) .await .unwrap(); insert_cfd(cfd.clone(), &mut conn).await.unwrap(); @@ -403,7 +403,7 @@ mod tests { transition_timestamp: SystemTime::now(), }, }; - insert_new_cfd_state_by_offer_id(cfd.offer_id, cfd.state, &mut conn) + insert_new_cfd_state_by_order_id(cfd.order_id, cfd.state, &mut conn) .await .unwrap(); diff --git a/daemon/src/maker.rs b/daemon/src/maker.rs index 143f639..b277b0e 100644 --- a/daemon/src/maker.rs +++ b/daemon/src/maker.rs @@ -2,7 +2,7 @@ use anyhow::Result; use bdk::bitcoin::secp256k1::{schnorrsig, SECP256K1}; use bdk::bitcoin::{self, Amount}; use bdk::blockchain::{ElectrumBlockchain, NoopProgress}; -use model::cfd::{Cfd, CfdOffer}; +use model::cfd::{Cfd, Order}; use rocket::fairing::AdHoc; use rocket::figment::util::map; use rocket::figment::value::{Map, Value}; @@ -45,7 +45,7 @@ async fn main() -> Result<()> { let oracle = schnorrsig::KeyPair::new(SECP256K1, &mut rand::thread_rng()); // TODO: Fetch oracle public key from oracle. let (cfd_feed_sender, cfd_feed_receiver) = watch::channel::>(vec![]); - let (offer_feed_sender, offer_feed_receiver) = watch::channel::>(None); + let (order_feed_sender, order_feed_receiver) = watch::channel::>(None); let (_balance_feed_sender, balance_feed_receiver) = watch::channel::(Amount::ZERO); let db: Map<_, Value> = map! { @@ -63,7 +63,7 @@ async fn main() -> Result<()> { rocket::custom(figment) .manage(cfd_feed_receiver) - .manage(offer_feed_receiver) + .manage(order_feed_receiver) .manage(balance_feed_receiver) .attach(Db::init()) .attach(AdHoc::try_on_ignite( @@ -95,7 +95,7 @@ async fn main() -> Result<()> { schnorrsig::PublicKey::from_keypair(SECP256K1, &oracle), connections_actor_inbox_sender, cfd_feed_sender, - offer_feed_sender, + order_feed_sender, ); let connections_actor = maker_inc_connections_actor::new( listener, @@ -113,8 +113,8 @@ async fn main() -> Result<()> { "/", rocket::routes![ routes_maker::maker_feed, - routes_maker::post_sell_offer, - // routes_maker::post_confirm_offer, + routes_maker::post_sell_order, + // routes_maker::post_confirm_order, routes_maker::get_health_check ], ) diff --git a/daemon/src/maker_cfd_actor.rs b/daemon/src/maker_cfd_actor.rs index 99acedb..24cb1ba 100644 --- a/daemon/src/maker_cfd_actor.rs +++ b/daemon/src/maker_cfd_actor.rs @@ -1,8 +1,8 @@ use std::collections::HashMap; use std::time::SystemTime; -use crate::db::{insert_cfd, insert_cfd_offer, load_all_cfds, load_offer_by_id, Origin}; -use crate::model::cfd::{Cfd, CfdOffer, CfdOfferId, CfdState, CfdStateCommon, FinalizedCfd}; +use crate::db::{insert_cfd, insert_order, load_all_cfds, load_order_by_id, Origin}; +use crate::model::cfd::{Cfd, CfdState, CfdStateCommon, FinalizedCfd, Order, OrderId}; use crate::model::{TakerId, Usd}; use crate::wire::{Msg0, Msg1, SetupMsg}; use crate::{maker_cfd_actor, maker_inc_connections_actor}; @@ -19,15 +19,15 @@ use tokio::sync::{mpsc, watch}; #[allow(clippy::large_enum_variant)] #[derive(Debug)] pub enum Command { - TakeOffer { + TakeOrder { taker_id: TakerId, - offer_id: CfdOfferId, + order_id: OrderId, quantity: Usd, }, - NewOffer(CfdOffer), + NewOrder(Order), StartContractSetup { taker_id: TakerId, - offer_id: CfdOfferId, + order_id: OrderId, }, NewTakerOnline { id: TakerId, @@ -42,7 +42,7 @@ pub fn new( oracle_pk: schnorrsig::PublicKey, takers: mpsc::UnboundedSender, cfd_feed_actor_inbox: watch::Sender>, - offer_feed_sender: watch::Sender>, + order_feed_sender: watch::Sender>, ) -> ( impl Future, mpsc::UnboundedSender, @@ -53,7 +53,7 @@ where let (sender, mut receiver) = mpsc::unbounded_channel(); let mut current_contract_setup = None; - let mut current_offer_id = None; + let mut current_order_id = None; let actor = { let sender = sender.clone(); @@ -67,27 +67,27 @@ where while let Some(message) = receiver.recv().await { match message { - maker_cfd_actor::Command::TakeOffer { + maker_cfd_actor::Command::TakeOrder { taker_id, - offer_id, + order_id, quantity, } => { println!( - "Taker {} wants to take {} of offer {}", - taker_id, quantity, offer_id + "Taker {} wants to take {} of order {}", + taker_id, quantity, order_id ); let mut conn = db.acquire().await.unwrap(); - // 1. Validate if offer is still valid - let current_offer = match current_offer_id { - Some(current_offer_id) if current_offer_id == offer_id => { - load_offer_by_id(current_offer_id, &mut conn).await.unwrap() + // 1. Validate if order is still valid + let current_order = match current_order_id { + Some(current_order_id) if current_order_id == order_id => { + load_order_by_id(current_order_id, &mut conn).await.unwrap() } _ => { takers - .send(maker_inc_connections_actor::Command::NotifyInvalidOfferId { - id: offer_id, + .send(maker_inc_connections_actor::Command::NotifyInvalidOrderId { + id: order_id, taker_id, }) .unwrap(); @@ -98,20 +98,20 @@ where // 2. Insert CFD in DB // TODO: Don't auto-accept, present to user in UI instead let cfd = Cfd::new( - current_offer.clone(), + current_order.clone(), quantity, CfdState::Accepted { common: CfdStateCommon { transition_timestamp: SystemTime::now(), }, }, - current_offer.position, + current_order.position, ); insert_cfd(cfd, &mut conn).await.unwrap(); takers - .send(maker_inc_connections_actor::Command::NotifyOfferAccepted { - id: offer_id, + .send(maker_inc_connections_actor::Command::NotifyOrderAccepted { + id: order_id, taker_id, }) .unwrap(); @@ -119,60 +119,56 @@ where .send(load_all_cfds(&mut conn).await.unwrap()) .unwrap(); - // 3. Remove current offer - current_offer_id = None; + // 3. Remove current order + current_order_id = None; takers - .send(maker_inc_connections_actor::Command::BroadcastCurrentOffer( - None, - )) + .send(maker_inc_connections_actor::Command::BroadcastOrder(None)) .unwrap(); - offer_feed_sender.send(None).unwrap(); + order_feed_sender.send(None).unwrap(); } - maker_cfd_actor::Command::NewOffer(offer) => { + maker_cfd_actor::Command::NewOrder(order) => { // 1. Save to DB let mut conn = db.acquire().await.unwrap(); - insert_cfd_offer(&offer, &mut conn, Origin::Ours) - .await - .unwrap(); + insert_order(&order, &mut conn, Origin::Ours).await.unwrap(); - // 2. Update actor state to current offer - current_offer_id.replace(offer.id); + // 2. Update actor state to current order + current_order_id.replace(order.id); // 3. Notify UI via feed - offer_feed_sender.send(Some(offer.clone())).unwrap(); + order_feed_sender.send(Some(order.clone())).unwrap(); // 4. Inform connected takers takers - .send(maker_inc_connections_actor::Command::BroadcastCurrentOffer( - Some(offer), - )) + .send(maker_inc_connections_actor::Command::BroadcastOrder(Some( + order, + ))) .unwrap(); } maker_cfd_actor::Command::NewTakerOnline { id: taker_id } => { let mut conn = db.acquire().await.unwrap(); - let current_offer = match current_offer_id { - Some(current_offer_id) => { - Some(load_offer_by_id(current_offer_id, &mut conn).await.unwrap()) + let current_order = match current_order_id { + Some(current_order_id) => { + Some(load_order_by_id(current_order_id, &mut conn).await.unwrap()) } None => None, }; takers - .send(maker_inc_connections_actor::Command::SendCurrentOffer { - offer: current_offer, + .send(maker_inc_connections_actor::Command::SendOrder { + order: current_order, taker_id, }) .unwrap(); } maker_cfd_actor::Command::StartContractSetup { taker_id, - offer_id: _offer_id, + order_id: _order_id, } => { // Kick-off the CFD protocol let (sk, pk) = crate::keypair::new(&mut rand::thread_rng()); - // TODO: Load correct quantity from DB with offer_id + // TODO: Load correct quantity from DB with order_id let maker_params = wallet .build_party_params(bitcoin::Amount::ZERO, pk) .unwrap(); diff --git a/daemon/src/maker_inc_connections_actor.rs b/daemon/src/maker_inc_connections_actor.rs index 2e64359..8f5afec 100644 --- a/daemon/src/maker_inc_connections_actor.rs +++ b/daemon/src/maker_inc_connections_actor.rs @@ -1,4 +1,4 @@ -use crate::model::cfd::{CfdOffer, CfdOfferId}; +use crate::model::cfd::{Order, OrderId}; use crate::model::TakerId; use crate::wire::SetupMsg; use crate::{maker_cfd_actor, maker_inc_connections_actor, send_wire_message_actor, wire}; @@ -12,17 +12,17 @@ use tokio_util::codec::{FramedRead, LengthDelimitedCodec}; #[allow(clippy::large_enum_variant)] #[derive(Debug)] pub enum Command { - BroadcastCurrentOffer(Option), - SendCurrentOffer { - offer: Option, + BroadcastOrder(Option), + SendOrder { + order: Option, taker_id: TakerId, }, - NotifyInvalidOfferId { - id: CfdOfferId, + NotifyInvalidOrderId { + id: OrderId, taker_id: TakerId, }, - NotifyOfferAccepted { - id: CfdOfferId, + NotifyOrderAccepted { + id: OrderId, taker_id: TakerId, }, OutProtocolMsg { @@ -59,22 +59,22 @@ pub fn new( }, Some(message) = our_inbox.recv() => { match message { - maker_inc_connections_actor::Command::NotifyInvalidOfferId { id, taker_id } => { + maker_inc_connections_actor::Command::NotifyInvalidOrderId { id, taker_id } => { let conn = write_connections.get(&taker_id).expect("no connection to taker_id"); - conn.send(wire::MakerToTaker::InvalidOfferId(id)).unwrap(); + conn.send(wire::MakerToTaker::InvalidOrderId(id)).unwrap(); }, - maker_inc_connections_actor::Command::BroadcastCurrentOffer(offer) => { + maker_inc_connections_actor::Command::BroadcastOrder(order) => { for conn in write_connections.values() { - conn.send(wire::MakerToTaker::CurrentOffer(offer.clone())).unwrap(); + conn.send(wire::MakerToTaker::CurrentOrder(order.clone())).unwrap(); } }, - maker_inc_connections_actor::Command::SendCurrentOffer {offer, taker_id} => { + maker_inc_connections_actor::Command::SendOrder {order, taker_id} => { let conn = write_connections.get(&taker_id).expect("no connection to taker_id"); - conn.send(wire::MakerToTaker::CurrentOffer(offer)).unwrap(); + conn.send(wire::MakerToTaker::CurrentOrder(order)).unwrap(); }, - maker_inc_connections_actor::Command::NotifyOfferAccepted { id, taker_id } => { + maker_inc_connections_actor::Command::NotifyOrderAccepted { id, taker_id } => { let conn = write_connections.get(&taker_id).expect("no connection to taker_id"); - conn.send(wire::MakerToTaker::ConfirmTakeOffer(id)).unwrap(); + conn.send(wire::MakerToTaker::ConfirmTakeOrder(id)).unwrap(); }, maker_inc_connections_actor::Command::OutProtocolMsg { taker_id, msg } => { let conn = write_connections.get(&taker_id).expect("no connection to taker_id"); @@ -100,15 +100,15 @@ fn in_taker_messages( async move { while let Some(message) = messages.next().await { match message { - Ok(wire::TakerToMaker::TakeOffer { offer_id, quantity }) => cfd_actor_inbox - .send(maker_cfd_actor::Command::TakeOffer { + Ok(wire::TakerToMaker::TakeOrder { order_id, quantity }) => cfd_actor_inbox + .send(maker_cfd_actor::Command::TakeOrder { taker_id, - offer_id, + order_id, quantity, }) .unwrap(), - Ok(wire::TakerToMaker::StartContractSetup(offer_id)) => cfd_actor_inbox - .send(maker_cfd_actor::Command::StartContractSetup { taker_id, offer_id }) + Ok(wire::TakerToMaker::StartContractSetup(order_id)) => cfd_actor_inbox + .send(maker_cfd_actor::Command::StartContractSetup { taker_id, order_id }) .unwrap(), Ok(wire::TakerToMaker::Protocol(msg)) => cfd_actor_inbox .send(maker_cfd_actor::Command::IncProtocolMsg(msg)) diff --git a/daemon/src/model/cfd.rs b/daemon/src/model/cfd.rs index 7522bc0..45cedab 100644 --- a/daemon/src/model/cfd.rs +++ b/daemon/src/model/cfd.rs @@ -12,24 +12,24 @@ use std::time::{Duration, SystemTime}; use uuid::Uuid; #[derive(Debug, Copy, Clone, Serialize, Deserialize, PartialEq)] -pub struct CfdOfferId(Uuid); +pub struct OrderId(Uuid); -impl Default for CfdOfferId { +impl Default for OrderId { fn default() -> Self { Self(Uuid::new_v4()) } } -impl Display for CfdOfferId { +impl Display for OrderId { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { self.0.fmt(f) } } -/// A concrete offer created by a maker for a taker +/// A concrete order created by a maker for a taker #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] -pub struct CfdOffer { - pub id: CfdOfferId, +pub struct Order { + pub id: OrderId, pub trading_pair: TradingPair, pub position: Position, @@ -52,15 +52,15 @@ pub struct CfdOffer { } #[allow(dead_code)] // Only one binary and the tests use this. -impl CfdOffer { +impl Order { pub fn from_default_with_price(price: Usd) -> Result { let leverage = Leverage(5); let maintenance_margin_rate = dec!(0.005); let liquidation_price = calculate_liquidation_price(&leverage, &price, &maintenance_margin_rate)?; - Ok(CfdOffer { - id: CfdOfferId::default(), + Ok(Order { + id: OrderId::default(), price, min_quantity: Usd(dec!(1000)), max_quantity: Usd(dec!(10000)), @@ -72,12 +72,12 @@ impl CfdOffer { term: Duration::from_secs(60 * 60 * 8), // 8 hours }) } - pub fn with_min_quantity(mut self, min_quantity: Usd) -> CfdOffer { + pub fn with_min_quantity(mut self, min_quantity: Usd) -> Order { self.min_quantity = min_quantity; self } - pub fn with_max_quantity(mut self, max_quantity: Usd) -> CfdOffer { + pub fn with_max_quantity(mut self, max_quantity: Usd) -> Order { self.max_quantity = max_quantity; self } @@ -240,7 +240,7 @@ impl Display for CfdState { /// Represents a cfd (including state) #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] pub struct Cfd { - pub offer_id: CfdOfferId, + pub order_id: OrderId, pub initial_price: Usd, pub leverage: Leverage, @@ -254,14 +254,14 @@ pub struct Cfd { } impl Cfd { - pub fn new(cfd_offer: CfdOffer, quantity: Usd, state: CfdState, position: Position) -> Self { + pub fn new(cfd_order: Order, quantity: Usd, state: CfdState, position: Position) -> Self { Cfd { - offer_id: cfd_offer.id, - initial_price: cfd_offer.price, - leverage: cfd_offer.leverage, - trading_pair: cfd_offer.trading_pair, + order_id: cfd_order.id, + initial_price: cfd_order.price, + leverage: cfd_order.leverage, + trading_pair: cfd_order.trading_pair, position, - liquidation_price: cfd_offer.liquidation_price, + liquidation_price: cfd_order.liquidation_price, quantity_usd: quantity, state, } diff --git a/daemon/src/routes_maker.rs b/daemon/src/routes_maker.rs index cc38314..ca438db 100644 --- a/daemon/src/routes_maker.rs +++ b/daemon/src/routes_maker.rs @@ -1,5 +1,5 @@ use crate::maker_cfd_actor; -use crate::model::cfd::{Cfd, CfdOffer}; +use crate::model::cfd::{Cfd, Order}; use crate::model::Usd; use crate::to_sse_event::ToSseEvent; use anyhow::Result; @@ -15,19 +15,19 @@ use tokio::sync::{mpsc, watch}; #[rocket::get("/maker-feed")] pub async fn maker_feed( rx_cfds: &State>>, - rx_offer: &State>>, + rx_order: &State>>, rx_balance: &State>, ) -> EventStream![] { let mut rx_cfds = rx_cfds.inner().clone(); - let mut rx_offer = rx_offer.inner().clone(); + let mut rx_order = rx_order.inner().clone(); let mut rx_balance = rx_balance.inner().clone(); EventStream! { let balance = rx_balance.borrow().clone(); yield balance.to_sse_event(); - let offer = rx_offer.borrow().clone(); - yield offer.to_sse_event(); + let order = rx_order.borrow().clone(); + yield order.to_sse_event(); let cfds = rx_cfds.borrow().clone(); yield cfds.to_sse_event(); @@ -38,9 +38,9 @@ pub async fn maker_feed( let balance = rx_balance.borrow().clone(); yield balance.to_sse_event(); }, - Ok(()) = rx_offer.changed() => { - let offer = rx_offer.borrow().clone(); - yield offer.to_sse_event(); + Ok(()) = rx_order.changed() => { + let order = rx_order.borrow().clone(); + yield order.to_sse_event(); } Ok(()) = rx_cfds.changed() => { let cfds = rx_cfds.borrow().clone(); @@ -51,10 +51,10 @@ pub async fn maker_feed( } } -/// The maker POSTs this to create a new CfdOffer +/// The maker POSTs this to create a new CfdOrder // TODO: Use Rocket form? #[derive(Debug, Clone, Deserialize)] -pub struct CfdNewOfferRequest { +pub struct CfdNewOrderRequest { pub price: Usd, // TODO: [post-MVP] Representation of the contract size; at the moment the contract size is // always 1 USD @@ -62,18 +62,18 @@ pub struct CfdNewOfferRequest { pub max_quantity: Usd, } -#[rocket::post("/offer/sell", data = "")] -pub async fn post_sell_offer( - offer: Json, +#[rocket::post("/order/sell", data = "")] +pub async fn post_sell_order( + order: Json, cfd_actor_inbox: &State>, ) -> Result, status::BadRequest> { - let offer = CfdOffer::from_default_with_price(offer.price) + let order = Order::from_default_with_price(order.price) .map_err(|e| status::BadRequest(Some(e.to_string())))? - .with_min_quantity(offer.min_quantity) - .with_max_quantity(offer.max_quantity); + .with_min_quantity(order.min_quantity) + .with_max_quantity(order.max_quantity); cfd_actor_inbox - .send(maker_cfd_actor::Command::NewOffer(offer)) + .send(maker_cfd_actor::Command::NewOrder(order)) .expect("actor to always be available"); Ok(status::Accepted(None)) @@ -81,20 +81,20 @@ pub async fn post_sell_offer( // // TODO: Shall we use a simpler struct for verification? AFAICT quantity is not // // needed, no need to send the whole CFD either as the other fields can be generated from the -// offer #[rocket::post("/offer/confirm", data = "")] -// pub async fn post_confirm_offer( -// cfd_confirm_offer_request: Json, -// queue: &State>, +// order #[rocket::post("/order/confirm", data = "")] +// pub async fn post_confirm_order( +// cfd_confirm_order_request: Json, +// queue: &State>, // mut conn: Connection, // ) -> Result, status::BadRequest> { -// dbg!(&cfd_confirm_offer_request); +// dbg!(&cfd_confirm_order_request); -// let offer = db::load_offer_by_id_from_conn(cfd_confirm_offer_request.offer_id, &mut conn) +// let order = db::load_order_by_id_from_conn(cfd_confirm_order_request.order_id, &mut conn) // .await // .map_err(|e| status::BadRequest(Some(e.to_string())))?; // let _res = queue -// .send(offer) +// .send(order) // .await // .map_err(|_| status::BadRequest(Some("internal server error".to_string())))?; @@ -105,4 +105,4 @@ pub async fn post_sell_offer( pub fn get_health_check() {} #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] -struct RetrieveCurrentOffer; +struct RetrieveCurrentOrder; diff --git a/daemon/src/routes_taker.rs b/daemon/src/routes_taker.rs index 1bffee7..30d69ff 100644 --- a/daemon/src/routes_taker.rs +++ b/daemon/src/routes_taker.rs @@ -1,4 +1,4 @@ -use crate::model::cfd::{calculate_buy_margin, Cfd, CfdOffer, CfdOfferId}; +use crate::model::cfd::{calculate_buy_margin, Cfd, Order, OrderId}; use crate::model::{Leverage, Usd}; use crate::taker_cfd_actor; use crate::to_sse_event::ToSseEvent; @@ -14,19 +14,19 @@ use tokio::sync::{mpsc, watch}; #[rocket::get("/feed")] pub async fn feed( rx_cfds: &State>>, - rx_offer: &State>>, + rx_order: &State>>, rx_balance: &State>, ) -> EventStream![] { let mut rx_cfds = rx_cfds.inner().clone(); - let mut rx_offer = rx_offer.inner().clone(); + let mut rx_order = rx_order.inner().clone(); let mut rx_balance = rx_balance.inner().clone(); EventStream! { let balance = rx_balance.borrow().clone(); yield balance.to_sse_event(); - let offer = rx_offer.borrow().clone(); - yield offer.to_sse_event(); + let order = rx_order.borrow().clone(); + yield order.to_sse_event(); let cfds = rx_cfds.borrow().clone(); yield cfds.to_sse_event(); @@ -37,9 +37,9 @@ pub async fn feed( let balance = rx_balance.borrow().clone(); yield balance.to_sse_event(); }, - Ok(()) = rx_offer.changed() => { - let offer = rx_offer.borrow().clone(); - yield offer.to_sse_event(); + Ok(()) = rx_order.changed() => { + let order = rx_order.borrow().clone(); + yield order.to_sse_event(); } Ok(()) = rx_cfds.changed() => { let cfds = rx_cfds.borrow().clone(); @@ -52,7 +52,7 @@ pub async fn feed( #[derive(Debug, Clone, Serialize, Deserialize)] pub struct CfdTakeRequest { - pub offer_id: CfdOfferId, + pub order_id: OrderId, pub quantity: Usd, } @@ -62,8 +62,8 @@ pub async fn post_cfd( cfd_actor_inbox: &State>, ) { cfd_actor_inbox - .send(taker_cfd_actor::Command::TakeOffer { - offer_id: cfd_take_request.offer_id, + .send(taker_cfd_actor::Command::TakeOrder { + order_id: cfd_take_request.order_id, quantity: cfd_take_request.quantity, }) .expect("actor to never disappear"); diff --git a/daemon/src/taker.rs b/daemon/src/taker.rs index cc61230..76869e2 100644 --- a/daemon/src/taker.rs +++ b/daemon/src/taker.rs @@ -2,7 +2,7 @@ use anyhow::Result; use bdk::bitcoin::secp256k1::{schnorrsig, SECP256K1}; use bdk::bitcoin::{self, Amount}; use bdk::blockchain::{ElectrumBlockchain, NoopProgress}; -use model::cfd::{Cfd, CfdOffer}; +use model::cfd::{Cfd, Order}; use rocket::fairing::AdHoc; use rocket::figment::util::map; use rocket::figment::value::{Map, Value}; @@ -45,7 +45,7 @@ async fn main() -> Result<()> { let oracle = schnorrsig::KeyPair::new(SECP256K1, &mut rand::thread_rng()); // TODO: Fetch oracle public key from oracle. let (cfd_feed_sender, cfd_feed_receiver) = watch::channel::>(vec![]); - let (offer_feed_sender, offer_feed_receiver) = watch::channel::>(None); + let (order_feed_sender, order_feed_receiver) = watch::channel::>(None); let (_balance_feed_sender, balance_feed_receiver) = watch::channel::(Amount::ZERO); let socket = tokio::net::TcpSocket::new_v4().unwrap(); @@ -64,7 +64,7 @@ async fn main() -> Result<()> { rocket::custom(figment) .manage(cfd_feed_receiver) - .manage(offer_feed_receiver) + .manage(order_feed_receiver) .manage(balance_feed_receiver) .attach(Db::init()) .attach(AdHoc::try_on_ignite( @@ -94,7 +94,7 @@ async fn main() -> Result<()> { wallet, schnorrsig::PublicKey::from_keypair(SECP256K1, &oracle), cfd_feed_sender, - offer_feed_sender, + order_feed_sender, out_maker_actor_inbox, ); let inc_maker_messages_actor = diff --git a/daemon/src/taker_cfd_actor.rs b/daemon/src/taker_cfd_actor.rs index f1f34c0..0714bb9 100644 --- a/daemon/src/taker_cfd_actor.rs +++ b/daemon/src/taker_cfd_actor.rs @@ -1,10 +1,8 @@ use crate::db::{ - insert_cfd, insert_cfd_offer, insert_new_cfd_state_by_offer_id, load_all_cfds, - load_offer_by_id, Origin, -}; -use crate::model::cfd::{ - AsBlocks, Cfd, CfdOffer, CfdOfferId, CfdState, CfdStateCommon, FinalizedCfd, + insert_cfd, insert_new_cfd_state_by_order_id, insert_order, load_all_cfds, load_order_by_id, + Origin, }; +use crate::model::cfd::{AsBlocks, Cfd, CfdState, CfdStateCommon, FinalizedCfd, Order, OrderId}; use crate::model::Usd; use crate::wire; use crate::wire::{AdaptorSignature, Msg0, Msg1, SetupMsg}; @@ -23,14 +21,14 @@ use std::collections::HashMap; use std::time::SystemTime; use tokio::sync::{mpsc, watch}; -/// A factor to be added to the CFD offer term for calculating the refund timelock. +/// A factor to be added to the CFD order term for calculating the refund timelock. /// /// The refund timelock is important in case the oracle disappears or never publishes a signature. /// Ideally, both users collaboratively settle in the refund scenario. This factor is important if /// the users do not settle collaboratively. -/// `1.5` times the term as defined in CFD offer should be safe in the extreme case where a user -/// publishes the commit transaction right after the contract was initialized. In this case, the -/// oracle still has `1.0 * cfdoffer.term` time to attest and no one can publish the refund +/// `1.5` times the term as defined in CFD order should be safe in the extreme case where a user +/// publishes the commit transaction right after the contract was initialized. In this case, the +/// oracle still has `1.0 * cfdorder.term` time to attest and no one can publish the refund /// transaction. /// The downside is that if the oracle disappears: the users would only notice at the end /// of the cfd term. In this case the users has to wait for another `1.5` times of the @@ -40,9 +38,9 @@ pub const REFUND_THRESHOLD: f32 = 1.5; #[derive(Debug)] #[allow(clippy::large_enum_variant)] pub enum Command { - TakeOffer { offer_id: CfdOfferId, quantity: Usd }, - NewOffer(Option), - OfferAccepted(CfdOfferId), + TakeOrder { order_id: OrderId, quantity: Usd }, + NewOrder(Option), + OrderAccepted(OrderId), IncProtocolMsg(SetupMsg), CfdSetupCompleted(FinalizedCfd), } @@ -52,7 +50,7 @@ pub fn new( wallet: bdk::Wallet, oracle_pk: schnorrsig::PublicKey, cfd_feed_actor_inbox: watch::Sender>, - offer_feed_actor_inbox: watch::Sender>, + order_feed_actor_inbox: watch::Sender>, out_msg_maker_inbox: mpsc::UnboundedSender, ) -> (impl Future, mpsc::UnboundedSender) where @@ -73,22 +71,22 @@ where while let Some(message) = receiver.recv().await { match message { - Command::TakeOffer { offer_id, quantity } => { + Command::TakeOrder { order_id, quantity } => { let mut conn = db.acquire().await.unwrap(); - let current_offer = load_offer_by_id(offer_id, &mut conn).await.unwrap(); + let current_order = load_order_by_id(order_id, &mut conn).await.unwrap(); - println!("Accepting current offer: {:?}", ¤t_offer); + println!("Accepting current order: {:?}", ¤t_order); let cfd = Cfd::new( - current_offer.clone(), + current_order.clone(), quantity, CfdState::PendingTakeRequest { common: CfdStateCommon { transition_timestamp: SystemTime::now(), }, }, - current_offer.position.counter_position(), + current_order.position.counter_position(), ); insert_cfd(cfd, &mut conn).await.unwrap(); @@ -97,24 +95,24 @@ where .send(load_all_cfds(&mut conn).await.unwrap()) .unwrap(); out_msg_maker_inbox - .send(wire::TakerToMaker::TakeOffer { offer_id, quantity }) + .send(wire::TakerToMaker::TakeOrder { order_id, quantity }) .unwrap(); } - Command::NewOffer(Some(offer)) => { + Command::NewOrder(Some(order)) => { let mut conn = db.acquire().await.unwrap(); - insert_cfd_offer(&offer, &mut conn, Origin::Theirs) + insert_order(&order, &mut conn, Origin::Theirs) .await .unwrap(); - offer_feed_actor_inbox.send(Some(offer)).unwrap(); + order_feed_actor_inbox.send(Some(order)).unwrap(); } - Command::NewOffer(None) => { - offer_feed_actor_inbox.send(None).unwrap(); + Command::NewOrder(None) => { + order_feed_actor_inbox.send(None).unwrap(); } - Command::OfferAccepted(offer_id) => { + Command::OrderAccepted(order_id) => { let mut conn = db.acquire().await.unwrap(); - insert_new_cfd_state_by_offer_id( - offer_id, + insert_new_cfd_state_by_order_id( + order_id, CfdState::ContractSetup { common: CfdStateCommon { transition_timestamp: SystemTime::now(), @@ -135,7 +133,7 @@ where .build_party_params(bitcoin::Amount::ZERO, pk) // TODO: Load correct quantity from DB .unwrap(); - let cfd = load_offer_by_id(offer_id, &mut conn).await.unwrap(); + let cfd = load_order_by_id(order_id, &mut conn).await.unwrap(); let (actor, inbox) = setup_contract( { @@ -188,7 +186,7 @@ fn setup_contract( taker: PartyParams, sk: SecretKey, oracle_pk: schnorrsig::PublicKey, - offer: CfdOffer, + order: Order, ) -> ( impl Future, mpsc::UnboundedSender, @@ -212,7 +210,7 @@ fn setup_contract( (maker.clone(), maker_punish), (taker.clone(), taker_punish), oracle_pk, - offer.term.mul_f32(REFUND_THRESHOLD).as_blocks().ceil() as u32, + order.term.mul_f32(REFUND_THRESHOLD).as_blocks().ceil() as u32, vec![], sk, ) diff --git a/daemon/src/taker_inc_message_actor.rs b/daemon/src/taker_inc_message_actor.rs index f2f51d5..a5c3ec5 100644 --- a/daemon/src/taker_inc_message_actor.rs +++ b/daemon/src/taker_inc_message_actor.rs @@ -18,18 +18,18 @@ pub fn new( async move { while let Some(message) = messages.next().await { match message { - Ok(wire::MakerToTaker::CurrentOffer(offer)) => { + Ok(wire::MakerToTaker::CurrentOrder(order)) => { cfd_actor - .send(taker_cfd_actor::Command::NewOffer(offer)) + .send(taker_cfd_actor::Command::NewOrder(order)) .unwrap(); } - Ok(wire::MakerToTaker::ConfirmTakeOffer(offer_id)) => { + Ok(wire::MakerToTaker::ConfirmTakeOrder(order_id)) => { // TODO: This naming is not well aligned. cfd_actor - .send(taker_cfd_actor::Command::OfferAccepted(offer_id)) + .send(taker_cfd_actor::Command::OrderAccepted(order_id)) .unwrap(); } - Ok(wire::MakerToTaker::InvalidOfferId(_)) => { + Ok(wire::MakerToTaker::InvalidOrderId(_)) => { todo!() } Ok(wire::MakerToTaker::Protocol(msg)) => { diff --git a/daemon/src/to_sse_event.rs b/daemon/src/to_sse_event.rs index 7b3cfc7..fbecd47 100644 --- a/daemon/src/to_sse_event.rs +++ b/daemon/src/to_sse_event.rs @@ -1,5 +1,5 @@ use crate::model; -use crate::model::cfd::CfdOfferId; +use crate::model::cfd::OrderId; use crate::model::{Leverage, Position, TradingPair, Usd}; use bdk::bitcoin::Amount; use rocket::response::stream::Event; @@ -8,7 +8,7 @@ use std::time::UNIX_EPOCH; #[derive(Debug, Clone, Serialize)] pub struct Cfd { - pub offer_id: CfdOfferId, + pub order_id: OrderId, pub initial_price: Usd, pub leverage: Leverage, @@ -30,8 +30,8 @@ pub struct Cfd { } #[derive(Debug, Clone, Serialize)] -pub struct CfdOffer { - pub id: CfdOfferId, +pub struct CfdOrder { + pub id: OrderId, pub trading_pair: TradingPair, pub position: Position, @@ -63,7 +63,7 @@ impl ToSseEvent for Vec { let (profit_btc, profit_usd) = cfd.calc_profit(current_price).unwrap(); Cfd { - offer_id: cfd.offer_id, + order_id: cfd.order_id, initial_price: cfd.initial_price, leverage: cfd.leverage, trading_pair: cfd.trading_pair.clone(), @@ -91,26 +91,26 @@ impl ToSseEvent for Vec { } } -impl ToSseEvent for Option { +impl ToSseEvent for Option { fn to_sse_event(&self) -> Event { - let offer = self.clone().map(|offer| CfdOffer { - id: offer.id, - trading_pair: offer.trading_pair, - position: offer.position, - price: offer.price, - min_quantity: offer.min_quantity, - max_quantity: offer.max_quantity, - leverage: offer.leverage, - liquidation_price: offer.liquidation_price, - creation_unix_timestamp: offer + let order = self.clone().map(|order| CfdOrder { + id: order.id, + trading_pair: order.trading_pair, + position: order.position, + price: order.price, + min_quantity: order.min_quantity, + max_quantity: order.max_quantity, + leverage: order.leverage, + liquidation_price: order.liquidation_price, + creation_unix_timestamp: order .creation_timestamp .duration_since(UNIX_EPOCH) .expect("timestamp to be convertible to duration since epoch") .as_secs(), - term_in_secs: offer.term.as_secs(), + term_in_secs: order.term.as_secs(), }); - Event::json(&offer).event("offer") + Event::json(&order).event("order") } } diff --git a/daemon/src/wire.rs b/daemon/src/wire.rs index a7d6f35..3a23e27 100644 --- a/daemon/src/wire.rs +++ b/daemon/src/wire.rs @@ -1,6 +1,6 @@ -use crate::model::cfd::CfdOfferId; +use crate::model::cfd::OrderId; use crate::model::Usd; -use crate::CfdOffer; +use crate::Order; use bdk::bitcoin::secp256k1::Signature; use bdk::bitcoin::util::psbt::PartiallySignedTransaction; use bdk::bitcoin::{Address, Amount, PublicKey, Txid}; @@ -24,10 +24,10 @@ impl std::ops::Deref for AdaptorSignature { #[serde(tag = "type", content = "payload")] #[allow(clippy::large_enum_variant)] pub enum TakerToMaker { - TakeOffer { offer_id: CfdOfferId, quantity: Usd }, + TakeOrder { order_id: OrderId, quantity: Usd }, // TODO: Currently the taker starts, can already send some stuff for signing over in the first // message. - StartContractSetup(CfdOfferId), + StartContractSetup(OrderId), Protocol(SetupMsg), } @@ -35,10 +35,10 @@ pub enum TakerToMaker { #[serde(tag = "type", content = "payload")] #[allow(clippy::large_enum_variant)] pub enum MakerToTaker { - CurrentOffer(Option), - // TODO: Needs RejectOffer as well - ConfirmTakeOffer(CfdOfferId), // TODO: Include payout curve in "accept" message from maker - InvalidOfferId(CfdOfferId), + CurrentOrder(Option), + // TODO: Needs RejectOrder as well + ConfirmTakeOrder(OrderId), // TODO: Include payout curve in "accept" message from maker + InvalidOrderId(OrderId), Protocol(SetupMsg), } diff --git a/docs/asset/mvp_maker_taker_db.puml b/docs/asset/mvp_maker_taker_db.puml index 793e247..a0e2af4 100644 --- a/docs/asset/mvp_maker_taker_db.puml +++ b/docs/asset/mvp_maker_taker_db.puml @@ -6,7 +6,7 @@ hide circle ' avoid problems with angled crows feet skinparam linetype ortho -entity "offers" as offer { +entity "orders" as order { *id : number <> <> -- ... @@ -15,7 +15,7 @@ entity "offers" as offer { entity "cfds" as cfd { *id : number <> <> -- - *offer_id : text <> + *order_id : text <> -- quantity_usd: long creation_timestamp: Date @@ -29,7 +29,7 @@ entity "cfd_states" as cfd_states { note left: state de-/serialized \nfrom rust state enum \nthis is not backwards\ncompatible, but that's \nOK for the MVP -offer ||--|| cfd +order ||--|| cfd cfd ||--|{ cfd_states diff --git a/docs/asset/mvp_maker_taker_messaging.puml b/docs/asset/mvp_maker_taker_messaging.puml index def7adb..f888917 100644 --- a/docs/asset/mvp_maker_taker_messaging.puml +++ b/docs/asset/mvp_maker_taker_messaging.puml @@ -2,48 +2,48 @@ actor "Buyer=Taker \n[frontend]" as Buyer participant "Buyer \n[daemon]" as BuyerApp -participant "Buyer Offer Feed \n[in daemon]" as BuyerOfferFeed +participant "Buyer OrderTile Feed \n[in daemon]" as BuyerOrderFeed participant "Buyer CFD Feed \n[in daemon]" as BuyerCfdFeed participant "Seller CFD Feed \n[in daemon]" as SellerCfdFeed -participant "Seller Offer Feed \n[in daemon]" as SellerOfferFeed +participant "Seller OrderTile Feed \n[in daemon]" as SellerOrderFeed participant "Seller \n[daemon]" as SellerApp actor "Seller=Maker \n[frontend]" as Seller participant Oracle as Oracle -note over Seller : currently static offer in the frontend -Seller -> SellerOfferFeed: Subscribe -note over Seller: The seller should see the current active offer \nInitially there is none (until one POSTed) -Seller -> SellerApp: POST sell offer +note over Seller : currently static order in the frontend +Seller -> SellerOrderFeed: Subscribe +note over Seller: The seller should see the current active order \nInitially there is none (until one POSTed) +Seller -> SellerApp: POST sell order group Oracle stuff? -SellerApp -> Oracle: Attestation for sell offer +SellerApp -> Oracle: Attestation for sell order Oracle --> SellerApp: Attestation pubkey end group -SellerApp -> SellerApp: Store current offer -SellerApp -> SellerOfferFeed: Push offer -SellerOfferFeed --> Seller: offer [Untaken] +SellerApp -> SellerApp: Store current order +SellerApp -> SellerOrderFeed: Push order +SellerOrderFeed --> Seller: order [Untaken] Buyer -> BuyerApp: Start daemon & UI -BuyerApp -> BuyerOfferFeed: Subscribe +BuyerApp -> BuyerOrderFeed: Subscribe BuyerApp -> BuyerCfdFeed: Subscribe BuyerApp -> SellerApp: Open TCP (socket) connection SellerApp -> SellerApp: New connection -SellerApp -> BuyerApp: {TCP} Current offer +SellerApp -> BuyerApp: {TCP} Current order -note over SellerOfferFeed : Assumption: Current offer \nalways available for new subscriptions -BuyerApp -> BuyerOfferFeed: push offer -BuyerOfferFeed --> Buyer: offer +note over SellerOrderFeed : Assumption: Current order \nalways available for new subscriptions +BuyerApp -> BuyerOrderFeed: push order +BuyerOrderFeed --> Buyer: order Buyer -> Buyer: Click BUY Buyer -> BuyerApp: POST cfd_take_request BuyerApp -> BuyerApp: Create cfd [TakeRequested] -note over BuyerApp: Must include offer_id +note over BuyerApp: Must include order_id BuyerApp -> BuyerCfdFeed: Push cfd BuyerCfdFeed --> Buyer: cfd [TakeRequested] -BuyerApp -> SellerApp: {TCP} cfd_take_request (offer_id, quantity) +BuyerApp -> SellerApp: {TCP} cfd_take_request (order_id, quantity) SellerApp -> SellerApp: Create cfd [TakeRequested] SellerApp -> SellerCfdFeed: cfd [TakeRequested] SellerCfdFeed --> Seller: cfd [TakeRequested] diff --git a/frontend/src/Maker.tsx b/frontend/src/Maker.tsx index 0b7c047..a5f966e 100644 --- a/frontend/src/Maker.tsx +++ b/frontend/src/Maker.tsx @@ -17,28 +17,28 @@ import { useAsync } from "react-async"; import { Route, Routes } from "react-router-dom"; import { useEventSource } from "react-sse-hooks"; import "./App.css"; -import CfdOffer from "./components/CfdOffer"; +import OrderTile from "./components/OrderTile"; import CfdTile from "./components/CfdTile"; import CurrencyInputField from "./components/CurrencyInputField"; import useLatestEvent from "./components/Hooks"; import NavLink from "./components/NavLink"; -import { Cfd, Offer } from "./components/Types"; +import { Cfd, Order } from "./components/Types"; /* TODO: Change from localhost:8001 */ const BASE_URL = "http://localhost:8001"; -interface CfdSellOfferPayload { +interface CfdSellOrderPayload { price: number; min_quantity: number; max_quantity: number; } -async function postCfdSellOfferRequest(payload: CfdSellOfferPayload) { - let res = await axios.post(BASE_URL + `/offer/sell`, JSON.stringify(payload)); +async function postCfdSellOrderRequest(payload: CfdSellOrderPayload) { + let res = await axios.post(BASE_URL + `/order/sell`, JSON.stringify(payload)); if (!res.status.toString().startsWith("2")) { console.log("Status: " + res.status + ", " + res.statusText); - throw new Error("failed to publish new offer"); + throw new Error("failed to publish new order"); } } @@ -46,7 +46,7 @@ export default function App() { let source = useEventSource({ source: BASE_URL + "/maker-feed" }); const cfds = useLatestEvent(source, "cfds"); - const offer = useLatestEvent(source, "offer"); + const order = useLatestEvent(source, "order"); console.log(cfds); @@ -55,15 +55,15 @@ export default function App() { const toast = useToast(); let [minQuantity, setMinQuantity] = useState("100"); let [maxQuantity, setMaxQuantity] = useState("1000"); - let [offerPrice, setOfferPrice] = useState("10000"); + let [orderPrice, setOrderPrice] = useState("10000"); const format = (val: any) => `$` + val; const parse = (val: any) => val.replace(/^\$/, ""); - let { run: makeNewCfdSellOffer, isLoading: isCreatingNewCfdOffer } = useAsync({ + let { run: makeNewCfdSellOrder, isLoading: isCreatingNewCfdOrder } = useAsync({ deferFn: async ([payload]: any[]) => { try { - await postCfdSellOfferRequest(payload as CfdSellOfferPayload); + await postCfdSellOrderRequest(payload as CfdSellOrderPayload); } catch (e) { const description = typeof e === "string" ? e : JSON.stringify(e); @@ -139,11 +139,11 @@ export default function App() { /> - Offer Price: + Order Price: setOfferPrice(parse(valueString))} - value={format(offerPrice)} + onChange={(valueString: string) => setOrderPrice(parse(valueString))} + value={format(orderPrice)} /> Leverage: @@ -154,26 +154,26 @@ export default function App() {
Maker UI
- {offer - && } diff --git a/frontend/src/Taker.tsx b/frontend/src/Taker.tsx index a218eff..089d31e 100644 --- a/frontend/src/Taker.tsx +++ b/frontend/src/Taker.tsx @@ -9,13 +9,13 @@ import CfdTile from "./components/CfdTile"; import CurrencyInputField from "./components/CurrencyInputField"; import useLatestEvent from "./components/Hooks"; import NavLink from "./components/NavLink"; -import { Cfd, Offer } from "./components/Types"; +import { Cfd, Order } from "./components/Types"; /* TODO: Change from localhost:8000 */ const BASE_URL = "http://localhost:8000"; interface CfdTakeRequestPayload { - offer_id: string; + order_id: string; quantity: number; } @@ -51,7 +51,7 @@ export default function App() { let source = useEventSource({ source: BASE_URL + "/feed" }); const cfds = useLatestEvent(source, "cfds"); - const offer = useLatestEvent(source, "offer"); + const order = useLatestEvent(source, "order"); const balance = useLatestEvent(source, "balance"); const toast = useToast(); @@ -140,13 +140,13 @@ export default function App() { {balance} - {/*TODO: Do we need this? does it make sense to only display the price from the offer?*/} + {/*TODO: Do we need this? does it make sense to only display the price from the order?*/} Current Price (Kraken): tbd - Offer Price: - {offer?.price} + Order Price: + {order?.price} Quantity: @@ -154,14 +154,14 @@ export default function App() { onChange={(valueString: string) => { setQuantity(parse(valueString)) - if (!offer) { + if (!order) { return; } let quantity = valueString ? Number.parseFloat(valueString) : 0; let payload: MarginRequestPayload = { - leverage: offer.leverage, - price: offer.price, + leverage: order.leverage, + price: order.price, quantity } calculateMargin(payload); @@ -178,15 +178,15 @@ export default function App() { - + {