Browse Source

Maker publishes `OracleEventId` as part of offer

The latest announcement known to the maker's cfd actor is used for extracting the event id.
upload-correct-windows-binary
Daniel Karzel 3 years ago
parent
commit
da339bd139
No known key found for this signature in database GPG Key ID: 30C3FC2E438ADB6E
  1. 3
      daemon/migrations/20210903050345_create_cfd_and_order_tables.sql
  2. 146
      daemon/sqlx-data.json
  3. 46
      daemon/src/db.rs
  4. 31
      daemon/src/maker_cfd.rs
  5. 29
      daemon/src/model/cfd.rs
  6. 17
      daemon/src/routes_maker.rs

3
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

146
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
]
}

46
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<Sqlite>) -> 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<Sqlite>) -> 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<Sqlite>) -> 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<Sqlite>) -> 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<Sqlite>) -> 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<Sqlite>) -> 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()
}
}
}

31
daemon/src/maker_cfd.rs

@ -5,7 +5,7 @@ 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};
@ -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,
@ -121,7 +125,26 @@ 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 = if let Some(latest_announcement) = self.latest_announcement.clone() {
latest_announcement.id
} else {
bail!("Cannot create order because no announcement from oracle")
};
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?;
@ -565,7 +588,7 @@ impl Handler<Commit> for Actor {
#[async_trait]
impl Handler<NewOrder> for Actor {
async fn handle(&mut self, msg: NewOrder, _ctx: &mut Context<Self>) {
log_error!(self.handle_new_order(msg.0));
log_error!(self.handle_new_order(msg.price, msg.min_quantity, msg.max_quantity));
}
}

29
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<Self> {
pub fn new(
price: Usd,
min_quantity: Usd,
max_quantity: Usd,
origin: Origin,
oracle_event_id: OracleEventId,
) -> Result<Self> {
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(

17
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<CfdNewOrderRequest>,
cfd_actor_address: &State<Address<maker_cfd::Actor>>,
_auth: Authenticated,
) -> Result<status::Accepted<()>, status::BadRequest<String>> {
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::Accepted<()>, 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))
}

Loading…
Cancel
Save