diff --git a/daemon/migrations/20210903050345_create_cfd_and_order_tables.sql b/daemon/migrations/20210903050345_create_cfd_and_order_tables.sql index b317b44..a4904a6 100644 --- a/daemon/migrations/20210903050345_create_cfd_and_order_tables.sql +++ b/daemon/migrations/20210903050345_create_cfd_and_order_tables.sql @@ -12,7 +12,8 @@ create table if not exists orders liquidation_price text not null, creation_timestamp text not null, term text not null, - origin text not null + origin text not null, + oracle_event_id text not null ); create unique index if not exists orders_uuid diff --git a/daemon/sqlx-data.json b/daemon/sqlx-data.json index 7e1a6d7..3cd8045 100644 --- a/daemon/sqlx-data.json +++ b/daemon/sqlx-data.json @@ -1,35 +1,7 @@ { "db": "SQLite", - "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": "state", - "ordinal": 0, - "type_info": "Text" - } - ], - "parameters": { - "Right": 1 - }, - "nullable": [ - false - ] - } - }, - "57c0eb6669321997352d87372431788aa039dd1898ca0b11ba4600f743ff4d93": { - "query": "\n select\n cfds.id as cfd_id,\n orders.uuid as order_id,\n orders.initial_price as price,\n orders.min_quantity as min_quantity,\n orders.max_quantity as max_quantity,\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 orders.creation_timestamp as creation_timestamp,\n orders.term as term,\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 ", + "41fb3bea22bde82a79aee6096d579a16494a20cfcfb2e8cfffe0a56073460bbf": { + "query": "\n select\n cfds.id as cfd_id,\n orders.uuid as order_id,\n orders.initial_price as price,\n orders.min_quantity as min_quantity,\n orders.max_quantity as max_quantity,\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 orders.creation_timestamp as creation_timestamp,\n orders.term as term,\n orders.oracle_event_id,\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": [ { @@ -93,14 +65,19 @@ "type_info": "Text" }, { - "name": "quantity_usd", + "name": "oracle_event_id", "ordinal": 12, "type_info": "Text" }, { - "name": "state", + "name": "quantity_usd", "ordinal": 13, "type_info": "Text" + }, + { + "name": "state", + "ordinal": 14, + "type_info": "Text" } ], "parameters": { @@ -120,12 +97,69 @@ false, false, false, + false, + false + ] + } + }, + "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": "state", + "ordinal": 0, + "type_info": "Text" + } + ], + "parameters": { + "Right": 1 + }, + "nullable": [ false ] } }, - "62c8df2dde7a305757a070149a7066faf15da1ef2d6c6fc4c0bd83e385e4750e": { - "query": "\n select\n cfds.id as cfd_id,\n orders.uuid as order_id,\n orders.initial_price as price,\n orders.min_quantity as min_quantity,\n orders.max_quantity as max_quantity,\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 orders.creation_timestamp as creation_timestamp,\n orders.term as term,\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 and orders.uuid = ?\n ", + "8e7571250da58b12f5884f17656e5966957c7798ea029c701a4fc43fd613f015": { + "query": "\n select\n id\n from cfds\n where order_uuid = ?;\n ", + "describe": { + "columns": [ + { + "name": "id", + "ordinal": 0, + "type_info": "Int64" + } + ], + "parameters": { + "Right": 1 + }, + "nullable": [ + true + ] + } + }, + "a464a1feb12abadff8bfd5b2b3b7362f3846869c0702944b21737eff8f420be5": { + "query": "\n insert into cfd_states (\n cfd_id,\n state\n ) values (?, ?);\n ", + "describe": { + "columns": [], + "parameters": { + "Right": 2 + }, + "nullable": [] + } + }, + "a59cf0824b5e4191c94c229086ce464d1b8084f65a6fafb165d27ce6df5b815b": { + "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 oracle_event_id\n ) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);\n ", + "describe": { + "columns": [], + "parameters": { + "Right": 12 + }, + "nullable": [] + } + }, + "c404a4eebb7118fd4e716fe4155e011a52e12a3594b698ca4f0662674cd067f8": { + "query": "\n select\n cfds.id as cfd_id,\n orders.uuid as order_id,\n orders.initial_price as price,\n orders.min_quantity as min_quantity,\n orders.max_quantity as max_quantity,\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 orders.creation_timestamp as creation_timestamp,\n orders.term as term,\n orders.oracle_event_id,\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 and orders.uuid = ?\n ", "describe": { "columns": [ { @@ -189,14 +223,19 @@ "type_info": "Text" }, { - "name": "quantity_usd", + "name": "oracle_event_id", "ordinal": 12, "type_info": "Text" }, { - "name": "state", + "name": "quantity_usd", "ordinal": 13, "type_info": "Text" + }, + { + "name": "state", + "ordinal": 14, + "type_info": "Text" } ], "parameters": { @@ -216,38 +255,11 @@ false, false, false, + false, false ] } }, - "8e7571250da58b12f5884f17656e5966957c7798ea029c701a4fc43fd613f015": { - "query": "\n select\n id\n from cfds\n where order_uuid = ?;\n ", - "describe": { - "columns": [ - { - "name": "id", - "ordinal": 0, - "type_info": "Int64" - } - ], - "parameters": { - "Right": 1 - }, - "nullable": [ - true - ] - } - }, - "a464a1feb12abadff8bfd5b2b3b7362f3846869c0702944b21737eff8f420be5": { - "query": "\n insert into cfd_states (\n cfd_id,\n state\n ) values (?, ?);\n ", - "describe": { - "columns": [], - "parameters": { - "Right": 2 - }, - "nullable": [] - } - }, "f3dce76f316212c91cb3402b0cef00f1c9adbef8519c54e9bdbd373aab946209": { "query": "\n select * from orders where uuid = ?;\n ", "describe": { @@ -311,6 +323,11 @@ "name": "origin", "ordinal": 11, "type_info": "Text" + }, + { + "name": "oracle_event_id", + "ordinal": 12, + "type_info": "Text" } ], "parameters": { @@ -328,6 +345,7 @@ false, false, false, + false, false ] } diff --git a/daemon/src/db.rs b/daemon/src/db.rs index f5823d3..0f933e7 100644 --- a/daemon/src/db.rs +++ b/daemon/src/db.rs @@ -1,5 +1,5 @@ use crate::model::cfd::{Cfd, CfdState, Order, OrderId, Origin}; -use crate::model::{Leverage, Position}; +use crate::model::{Leverage, OracleEventId, Position}; use anyhow::{Context, Result}; use rocket_db_pools::sqlx; use sqlx::pool::PoolConnection; @@ -24,6 +24,7 @@ pub async fn insert_order(order: &Order, conn: &mut PoolConnection) -> a 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(&order.origin).unwrap(); + let oracle_event_id = order.oracle_event_id.0.clone(); sqlx::query!( r#" @@ -38,8 +39,9 @@ pub async fn insert_order(order: &Order, conn: &mut PoolConnection) -> a liquidation_price, creation_timestamp, term, - origin - ) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); + origin, + oracle_event_id + ) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); "#, uuid, trading_pair, @@ -51,7 +53,8 @@ pub async fn insert_order(order: &Order, conn: &mut PoolConnection) -> a liquidation_price, creation_timestamp, term, - origin + origin, + oracle_event_id ) .execute(conn) .await?; @@ -85,6 +88,7 @@ pub async fn load_order_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(); let origin = serde_json::from_str(row.origin.as_str()).unwrap(); + let oracle_event_id = OracleEventId(row.oracle_event_id); Ok(Order { id: uuid, @@ -98,6 +102,7 @@ pub async fn load_order_by_id( creation_timestamp, term, origin, + oracle_event_id, }) } @@ -264,6 +269,7 @@ pub async fn load_cfd_by_order_id( orders.liquidation_price as liquidation_price, orders.creation_timestamp as creation_timestamp, orders.term as term, + orders.oracle_event_id, cfds.quantity_usd as quantity_usd, cfd_states.state as state from cfds as cfds @@ -295,6 +301,7 @@ pub async fn load_cfd_by_order_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(); let origin: Origin = serde_json::from_str(row.origin.as_str()).unwrap(); + let oracle_event_id = OracleEventId(row.oracle_event_id.clone()); let quantity = serde_json::from_str(row.quantity_usd.as_str()).unwrap(); let latest_state = serde_json::from_str(row.state.as_str()).unwrap(); @@ -311,6 +318,7 @@ pub async fn load_cfd_by_order_id( creation_timestamp, term, origin, + oracle_event_id, }; Ok(Cfd { @@ -339,6 +347,7 @@ pub async fn load_all_cfds(conn: &mut PoolConnection) -> anyhow::Result< orders.liquidation_price as liquidation_price, orders.creation_timestamp as creation_timestamp, orders.term as term, + orders.oracle_event_id, cfds.quantity_usd as quantity_usd, cfd_states.state as state from cfds as cfds @@ -371,6 +380,7 @@ pub async fn load_all_cfds(conn: &mut PoolConnection) -> anyhow::Result< let creation_timestamp = serde_json::from_str(row.creation_timestamp.as_str()).unwrap(); let term = serde_json::from_str(row.term.as_str()).unwrap(); let origin: Origin = serde_json::from_str(row.origin.as_str()).unwrap(); + let oracle_event_id = OracleEventId(row.oracle_event_id.clone()); let quantity = serde_json::from_str(row.quantity_usd.as_str()).unwrap(); let latest_state = serde_json::from_str(row.state.as_str()).unwrap(); @@ -387,6 +397,7 @@ pub async fn load_all_cfds(conn: &mut PoolConnection) -> anyhow::Result< creation_timestamp, term, origin, + oracle_event_id, }; Cfd { @@ -420,7 +431,7 @@ mod tests { let pool = setup_test_db().await; let mut conn = pool.acquire().await.unwrap(); - let order = Order::from_default_with_price(Usd(dec!(10000)), Origin::Theirs).unwrap(); + let order = Order::default(); insert_order(&order, &mut conn).await.unwrap(); let order_loaded = load_order_by_id(order.id, &mut conn).await.unwrap(); @@ -433,7 +444,7 @@ mod tests { let pool = setup_test_db().await; let mut conn = pool.acquire().await.unwrap(); - let order = Order::from_default_with_price(Usd(dec!(10000)), Origin::Theirs).unwrap(); + let order = Order::default(); let cfd = Cfd::new( order.clone(), Usd(dec!(1000)), @@ -457,7 +468,7 @@ mod tests { let pool = setup_test_db().await; let mut conn = pool.acquire().await.unwrap(); - let order = Order::from_default_with_price(Usd(dec!(10000)), Origin::Theirs).unwrap(); + let order = Order::default(); let cfd = Cfd::new( order.clone(), Usd(dec!(1000)), @@ -482,8 +493,7 @@ mod tests { let pool = setup_test_db().await; let mut conn = pool.acquire().await.unwrap(); - let order = Order::from_default_with_price(Usd(dec!(10000)), Origin::Theirs).unwrap(); - + let order = Order::default(); let cfd = Cfd::new( order.clone(), Usd(dec!(1000)), @@ -502,8 +512,7 @@ mod tests { let cfd_from_db = load_cfd_by_order_id(order_id, &mut conn).await.unwrap(); assert_eq!(cfd, cfd_from_db); - let order = Order::from_default_with_price(Usd(dec!(10000)), Origin::Theirs).unwrap(); - + let order = Order::default(); let cfd = Cfd::new( order.clone(), Usd(dec!(1000)), @@ -528,7 +537,7 @@ mod tests { let pool = setup_test_db().await; let mut conn = pool.acquire().await.unwrap(); - let order = Order::from_default_with_price(Usd(dec!(10000)), Origin::Theirs).unwrap(); + let order = Order::default(); let mut cfd = Cfd::new( order.clone(), Usd(dec!(1000)), @@ -572,4 +581,17 @@ mod tests { pool } + + impl Default for Order { + fn default() -> Self { + Order::new( + Usd(dec!(1000)), + Usd(dec!(100)), + Usd(dec!(1000)), + Origin::Theirs, + OracleEventId("Dummy".to_string()), + ) + .unwrap() + } + } } diff --git a/daemon/src/maker_cfd.rs b/daemon/src/maker_cfd.rs index 7c1f131..d23ad4b 100644 --- a/daemon/src/maker_cfd.rs +++ b/daemon/src/maker_cfd.rs @@ -5,10 +5,10 @@ use crate::db::{ }; use crate::maker_inc_connections::TakerCommand; use crate::model::cfd::{ - Cfd, CfdState, CfdStateChangeEvent, CfdStateCommon, Dlc, Order, OrderId, Role, + Cfd, CfdState, CfdStateChangeEvent, CfdStateCommon, Dlc, Order, OrderId, Origin, Role, SettlementProposal, SettlementProposals, }; -use crate::model::{TakerId, Usd}; +use crate::model::{OracleEventId, TakerId, Usd}; use crate::monitor::MonitorParams; use crate::wallet::Wallet; use crate::{maker_inc_connections, monitor, oracle, setup_contract, wire}; @@ -17,7 +17,7 @@ use async_trait::async_trait; use bdk::bitcoin::secp256k1::schnorrsig; use futures::channel::mpsc; use futures::{future, SinkExt}; -use std::collections::HashMap; +use std::collections::{BTreeMap, HashMap}; use std::time::SystemTime; use tokio::sync::watch; use xtra::prelude::*; @@ -43,7 +43,11 @@ pub struct RejectSettlement { pub order_id: OrderId, } -pub struct NewOrder(pub Order); +pub struct NewOrder { + pub price: Usd, + pub min_quantity: Usd, + pub max_quantity: Usd, +} pub struct NewTakerOnline { pub id: TakerId, @@ -70,8 +74,8 @@ pub struct Actor { current_order_id: Option, monitor_actor: Address>, setup_state: SetupState, - latest_announcement: Option, - _oracle_actor: Address>>, + latest_announcements: Option>, + oracle_actor: Address>>, current_settlement_proposals: HashMap, } @@ -107,8 +111,8 @@ impl Actor { current_order_id: None, monitor_actor, setup_state: SetupState::None, - latest_announcement: None, - _oracle_actor: oracle_actor, + latest_announcements: None, + oracle_actor, current_settlement_proposals: HashMap::new(), } } @@ -121,7 +125,30 @@ impl Actor { ))?) } - async fn handle_new_order(&mut self, order: Order) -> Result<()> { + async fn handle_new_order( + &mut self, + price: Usd, + min_quantity: Usd, + max_quantity: Usd, + ) -> Result<()> { + let oracle_event_id = self + .latest_announcements + .clone() + .context("Cannot create order because no announcement from oracle")? + .iter() + .next_back() + .context("Empty list of announcements")? + .0 + .clone(); + + let order = Order::new( + price, + min_quantity, + max_quantity, + Origin::Ours, + oracle_event_id, + )?; + // 1. Save to DB let mut conn = self.db.acquire().await?; insert_order(&order, &mut conn).await?; @@ -340,18 +367,21 @@ impl Actor { self.cfd_feed_actor_inbox .send(load_all_cfds(&mut conn).await?)?; - // let latest_announcement = self - // .latest_announcement - // .to_owned() - // .context("Unaware of oracle's latest announcement.")?; - - // self.oracle_actor - // .do_send_async(oracle::MonitorEvent { - // event_id: latest_announcement.id, - // }) - // .await?; + let offer_announcements = self + .latest_announcements + .clone() + .context("No oracle announcements available")?; + let offer_announcement = offer_announcements + .get(&cfd.order.oracle_event_id) + .context("Order's announcement not found in current oracle announcements")?; + + self.oracle_actor + .do_send_async(oracle::MonitorEvent { + event_id: offer_announcement.id.clone(), + }) + .await?; - let nonce_pks = Vec::new(); + let nonce_pks = offer_announcement.nonce_pks.clone(); let contract_future = setup_contract::new( self.takers.clone().into_sink().with(move |msg| { @@ -509,8 +539,13 @@ impl Actor { &mut self, announcements: oracle::Announcements, ) -> Result<()> { - tracing::debug!("Updating latest oracle announcements"); - self.latest_announcement = Some(announcements.0.last().unwrap().clone()); + self.latest_announcements.replace( + announcements + .0 + .iter() + .map(|announcement| (announcement.id.clone(), announcement.clone())) + .collect(), + ); Ok(()) } @@ -565,7 +600,7 @@ impl Handler for Actor { #[async_trait] impl Handler for Actor { async fn handle(&mut self, msg: NewOrder, _ctx: &mut Context) { - log_error!(self.handle_new_order(msg.0)); + log_error!(self.handle_new_order(msg.price, msg.min_quantity, msg.max_quantity)); } } diff --git a/daemon/src/model.rs b/daemon/src/model.rs index 8daeaad..0024a15 100644 --- a/daemon/src/model.rs +++ b/daemon/src/model.rs @@ -105,3 +105,6 @@ pub struct WalletInfo { pub address: Address, pub last_updated_at: SystemTime, } + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub struct OracleEventId(pub String); diff --git a/daemon/src/model/cfd.rs b/daemon/src/model/cfd.rs index 671f3a0..b2b22f3 100644 --- a/daemon/src/model/cfd.rs +++ b/daemon/src/model/cfd.rs @@ -1,4 +1,4 @@ -use crate::model::{Leverage, Percent, Position, TakerId, TradingPair, Usd}; +use crate::model::{Leverage, OracleEventId, Percent, Position, TakerId, TradingPair, Usd}; use crate::monitor; use anyhow::{bail, Context, Result}; use bdk::bitcoin::secp256k1::{SecretKey, Signature}; @@ -91,11 +91,22 @@ pub struct Order { pub term: Duration, pub origin: Origin, + + /// The id of the event to be used for price attestation + /// + /// The maker includes this into the Order based on the Oracle announcement to be used. + pub oracle_event_id: OracleEventId, } #[allow(dead_code)] // Only one binary and the tests use this. impl Order { - pub fn from_default_with_price(price: Usd, origin: Origin) -> Result { + pub fn new( + price: Usd, + min_quantity: Usd, + max_quantity: Usd, + origin: Origin, + oracle_event_id: OracleEventId, + ) -> Result { let leverage = Leverage(5); let maintenance_margin_rate = dec!(0.005); let liquidation_price = @@ -104,8 +115,8 @@ impl Order { Ok(Order { id: OrderId::default(), price, - min_quantity: Usd(dec!(1000)), - max_quantity: Usd(dec!(10000)), + min_quantity, + max_quantity, leverage, trading_pair: TradingPair::BtcUsd, liquidation_price, @@ -113,17 +124,9 @@ impl Order { creation_timestamp: SystemTime::now(), term: Duration::from_secs(60 * 60 * 8), // 8 hours origin, + oracle_event_id, }) } - 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) -> Order { - self.max_quantity = max_quantity; - self - } } fn calculate_liquidation_price( diff --git a/daemon/src/oracle.rs b/daemon/src/oracle.rs index 0b951ef..38fc04a 100644 --- a/daemon/src/oracle.rs +++ b/daemon/src/oracle.rs @@ -1,4 +1,5 @@ use crate::actors::log_error; +use crate::model::OracleEventId; use anyhow::{Context, Result}; use async_trait::async_trait; use cfd_protocol::secp256k1_zkp::{schnorrsig, SecretKey}; @@ -153,7 +154,7 @@ where } pub struct MonitorEvent { - pub event_id: String, + pub event_id: OracleEventId, } impl xtra::Message for MonitorEvent { @@ -167,7 +168,7 @@ where M: xtra::Handler, { async fn handle(&mut self, msg: MonitorEvent, _ctx: &mut xtra::Context) { - self.monitor_event(msg.event_id) + self.monitor_event(msg.event_id.0) } } @@ -202,11 +203,12 @@ pub struct Announcement { /// /// Doubles up as the path of the URL for this event i.e. /// https://h00.ooo/{id}. - pub id: String, + pub id: OracleEventId, pub expected_outcome_time: OffsetDateTime, pub nonce_pks: Vec, } +#[derive(Debug, Clone)] pub struct Announcements(pub [Announcement; 24]); // TODO: Implement real deserialization once price attestation is @@ -228,6 +230,7 @@ impl xtra::Message for Attestation { } mod olivia_api { + use crate::model::OracleEventId; use anyhow::Context; use cfd_protocol::secp256k1_zkp::{schnorrsig, SecretKey}; use std::convert::TryFrom; @@ -249,7 +252,7 @@ mod olivia_api { serde_json::from_str::(&response.announcement.oracle_event.data)?; Ok(Self { - id: data.id, + id: OracleEventId(data.id), expected_outcome_time: data.expected_outcome_time, nonce_pks: data.schemes.olivia_v1.nonces, }) @@ -338,6 +341,7 @@ mod olivia_api { mod tests { use std::vec; + use crate::model::OracleEventId; use crate::oracle; use time::macros::datetime; @@ -347,7 +351,7 @@ mod olivia_api { let deserialized = serde_json::from_str::(json).unwrap(); let expected = oracle::Announcement { - id: "/x/BitMEX/BXBT/2021-10-04T22:00:00.price[n:20]".to_string(), + id: OracleEventId("/x/BitMEX/BXBT/2021-10-04T22:00:00.price[n:20]".to_string()), expected_outcome_time: datetime!(2021-10-04 22:00:00).assume_utc(), nonce_pks: vec![ "8d72028eeaf4b85aec0f750f05a4a320cac193f5d8494bfe05cd4b29f3df4239" diff --git a/daemon/src/routes_maker.rs b/daemon/src/routes_maker.rs index c283231..409b989 100644 --- a/daemon/src/routes_maker.rs +++ b/daemon/src/routes_maker.rs @@ -1,5 +1,5 @@ use crate::auth::Authenticated; -use crate::model::cfd::{Cfd, Order, OrderId, Origin, Role, SettlementProposals}; +use crate::model::cfd::{Cfd, Order, OrderId, Role, SettlementProposals}; use crate::model::{Usd, WalletInfo}; use crate::routes::EmbeddedFileExt; use crate::to_sse_event::{CfdAction, CfdsWithAuxData, ToSseEvent}; @@ -87,16 +87,15 @@ pub async fn post_sell_order( order: Json, cfd_actor_address: &State>, _auth: Authenticated, -) -> Result, status::BadRequest> { - let order = Order::from_default_with_price(order.price, Origin::Ours) - .map_err(|e| status::BadRequest(Some(e.to_string())))? - .with_min_quantity(order.min_quantity) - .with_max_quantity(order.max_quantity); - +) -> Result, Status> { cfd_actor_address - .do_send_async(maker_cfd::NewOrder(order)) + .do_send_async(maker_cfd::NewOrder { + price: order.price, + min_quantity: order.min_quantity, + max_quantity: order.max_quantity, + }) .await - .expect("actor to always be available"); + .map_err(|_| Status::new(500))?; Ok(status::Accepted(None)) } diff --git a/daemon/src/taker_cfd.rs b/daemon/src/taker_cfd.rs index ad92ca7..265ff02 100644 --- a/daemon/src/taker_cfd.rs +++ b/daemon/src/taker_cfd.rs @@ -7,7 +7,7 @@ use crate::model::cfd::{ Cfd, CfdState, CfdStateChangeEvent, CfdStateCommon, Dlc, Order, OrderId, Origin, Role, SettlementProposal, SettlementProposals, }; -use crate::model::Usd; +use crate::model::{OracleEventId, Usd}; use crate::monitor::{self, MonitorParams}; use crate::wallet::Wallet; use crate::wire::SetupMsg; @@ -17,7 +17,7 @@ use async_trait::async_trait; use bdk::bitcoin::secp256k1::schnorrsig; use futures::channel::mpsc; use futures::{future, SinkExt}; -use std::collections::HashMap; +use std::collections::{BTreeMap, HashMap}; use std::time::SystemTime; use tokio::sync::watch; use xtra::prelude::*; @@ -63,8 +63,8 @@ pub struct Actor { send_to_maker: Address>, monitor_actor: Address>, setup_state: SetupState, - latest_announcement: Option, - _oracle_actor: Address>>, + latest_announcements: Option>, + oracle_actor: Address>>, current_settlement_proposals: HashMap, } @@ -91,8 +91,8 @@ impl Actor { send_to_maker, monitor_actor, setup_state: SetupState::None, - latest_announcement: None, - _oracle_actor: oracle_actor, + oracle_actor, + latest_announcements: None, current_settlement_proposals: HashMap::new(), } } @@ -213,18 +213,21 @@ impl Actor { .send(load_all_cfds(&mut conn).await?)?; let cfd = load_cfd_by_order_id(order_id, &mut conn).await?; - // let latest_announcement = self - // .latest_announcement - // .to_owned() - // .context("Unaware of oracle's latest announcement.")?; - - // self.oracle_actor - // .do_send_async(oracle::MonitorEvent { - // event_id: latest_announcement.id, - // }) - // .await?; + let offer_announcements = self + .latest_announcements + .clone() + .context("No oracle announcements available")?; + let offer_announcement = offer_announcements + .get(&cfd.order.oracle_event_id) + .context("Order's announcement not found in current oracle announcements")?; + + self.oracle_actor + .do_send_async(oracle::MonitorEvent { + event_id: offer_announcement.id.clone(), + }) + .await?; - let nonce_pks = Vec::new(); + let nonce_pks = offer_announcement.nonce_pks.clone(); let contract_future = setup_contract::new( self.send_to_maker @@ -392,8 +395,13 @@ impl Actor { &mut self, announcements: oracle::Announcements, ) -> Result<()> { - tracing::debug!("Updating latest oracle announcements"); - self.latest_announcement = Some(announcements.0.last().unwrap().clone()); + self.latest_announcements.replace( + announcements + .0 + .iter() + .map(|announcement| (announcement.id.clone(), announcement.clone())) + .collect(), + ); Ok(()) }