Browse Source

Rename `term` to `settlement_time_interval` and `announcement_lookahead`

Depending on the context, this makes it more explicit what we mean by `term` in the context of the `Cfd` and the `Oracle`.
contact-taker-before-changing-cfd-state
Daniel Karzel 3 years ago
parent
commit
9adf30b93d
No known key found for this signature in database GPG Key ID: 30C3FC2E438ADB6E
  1. 5
      daemon/migrations/20211025050345_rename_term_to_settlement_time_interval.sql
  2. 106
      daemon/sqlx-data.json
  3. 56
      daemon/src/db.rs
  4. 4
      daemon/src/lib.rs
  5. 11
      daemon/src/maker.rs
  6. 18
      daemon/src/maker_cfd.rs
  7. 24
      daemon/src/model/cfd.rs
  8. 18
      daemon/src/oracle.rs
  9. 4
      daemon/src/taker.rs
  10. 8
      daemon/src/to_sse_event.rs
  11. 4
      daemon/tests/happy_path.rs
  12. 2
      frontend/src/components/Types.tsx

5
daemon/migrations/20211025050345_rename_term_to_settlement_time_interval.sql

@ -0,0 +1,5 @@
alter table orders
rename column term_seconds to settlement_time_interval_seconds;
alter table orders
rename column term_nanoseconds to settlement_time_interval_nanoseconds;

106
daemon/sqlx-data.json

@ -1,25 +1,7 @@
{ {
"db": "SQLite", "db": "SQLite",
"221a6283db798bacaba99e7e85130f9a8bbea1299d8cb99d272b1d478dc19775": { "07b8db7d3a709a7f06a20251d5b7251c2a3428ec73c6710a83048d6c8e974958": {
"query": "\n select\n state\n from cfd_states\n where cfd_id = $1\n order by id desc\n limit 1;\n ", "query": "\n select\n uuid as \"uuid: crate::model::cfd::OrderId\",\n trading_pair as \"trading_pair: crate::model::TradingPair\",\n position as \"position: crate::model::Position\",\n initial_price,\n min_quantity,\n max_quantity,\n leverage as \"leverage: crate::model::Leverage\",\n liquidation_price,\n creation_timestamp_seconds as \"ts_secs: i64\",\n creation_timestamp_nanoseconds as \"ts_nanos: i32\",\n settlement_time_interval_seconds as \"settlement_time_interval_secs: i64\",\n settlement_time_interval_nanoseconds as \"settlement_time_interval_nanos: i32\",\n origin as \"origin: crate::model::cfd::Origin\",\n oracle_event_id\n\n from orders\n where uuid = $1\n ",
"describe": {
"columns": [
{
"name": "state",
"ordinal": 0,
"type_info": "Text"
}
],
"parameters": {
"Right": 1
},
"nullable": [
false
]
}
},
"3e122ab8f81d5fb1ab7f137316c9aa15ea419114de5720b2667267a33daad6bd": {
"query": "\n with ord as (\n select\n id as order_id,\n uuid,\n trading_pair,\n position,\n initial_price,\n min_quantity,\n max_quantity,\n leverage,\n liquidation_price,\n creation_timestamp_seconds as ts_secs,\n creation_timestamp_nanoseconds as ts_nanos,\n term_seconds as term_secs,\n term_nanoseconds as term_nanos,\n origin,\n oracle_event_id\n from orders\n ),\n\n cfd as (\n select\n ord.order_id,\n id as cfd_id,\n quantity_usd\n from cfds\n inner join ord on ord.order_id = cfds.order_id\n ),\n\n state as (\n select\n id as state_id,\n cfd.order_id,\n cfd.quantity_usd,\n state\n from cfd_states\n inner join cfd on cfd.cfd_id = cfd_states.cfd_id\n where id in (\n select\n max(id) as id\n from cfd_states\n group by (cfd_id)\n )\n )\n\n select\n ord.uuid as \"uuid: crate::model::cfd::OrderId\",\n ord.trading_pair as \"trading_pair: crate::model::TradingPair\",\n ord.position as \"position: crate::model::Position\",\n ord.initial_price,\n ord.min_quantity,\n ord.max_quantity,\n ord.leverage as \"leverage: crate::model::Leverage\",\n ord.liquidation_price,\n ord.ts_secs as \"ts_secs: i64\",\n ord.ts_nanos as \"ts_nanos: i32\",\n ord.term_secs as \"term_secs: i64\",\n ord.term_nanos as \"term_nanos: i32\",\n ord.origin as \"origin: crate::model::cfd::Origin\",\n ord.oracle_event_id,\n state.quantity_usd,\n state.state\n\n from ord\n inner join state on state.order_id = ord.order_id\n ",
"describe": { "describe": {
"columns": [ "columns": [
{ {
@ -73,12 +55,12 @@
"type_info": "Int64" "type_info": "Int64"
}, },
{ {
"name": "term_secs: i64", "name": "settlement_time_interval_secs: i64",
"ordinal": 10, "ordinal": 10,
"type_info": "Int64" "type_info": "Int64"
}, },
{ {
"name": "term_nanos: i32", "name": "settlement_time_interval_nanos: i32",
"ordinal": 11, "ordinal": 11,
"type_info": "Int64" "type_info": "Int64"
}, },
@ -91,20 +73,10 @@
"name": "oracle_event_id", "name": "oracle_event_id",
"ordinal": 13, "ordinal": 13,
"type_info": "Text" "type_info": "Text"
},
{
"name": "quantity_usd",
"ordinal": 14,
"type_info": "Text"
},
{
"name": "state",
"ordinal": 15,
"type_info": "Text"
} }
], ],
"parameters": { "parameters": {
"Right": 0 "Right": 1
}, },
"nullable": [ "nullable": [
false, false,
@ -120,14 +92,12 @@
false, false,
false, false,
false, false,
false,
false,
false false
] ]
} }
}, },
"7610f0d5a9d216dba503cb5f9980fa5d9cabd13dc0131166bb6439ded37ee5dd": { "1ea6916f2e25bdd8f4761f0810178ed3b5e52817e6440b54d2bf4e13fb786405": {
"query": "\n with ord as (\n select\n id as order_id,\n uuid,\n trading_pair,\n position,\n initial_price,\n min_quantity,\n max_quantity,\n leverage,\n liquidation_price,\n creation_timestamp_seconds as ts_secs,\n creation_timestamp_nanoseconds as ts_nanos,\n term_seconds as term_secs,\n term_nanoseconds as term_nanos,\n origin,\n oracle_event_id\n from orders\n ),\n\n cfd as (\n select\n ord.order_id,\n id as cfd_id,\n quantity_usd\n from cfds\n inner join ord on ord.order_id = cfds.order_id\n ),\n\n state as (\n select\n id as state_id,\n cfd.order_id,\n cfd.quantity_usd,\n state\n from cfd_states\n inner join cfd on cfd.cfd_id = cfd_states.cfd_id\n where id in (\n select\n max(id) as id\n from cfd_states\n group by (cfd_id)\n )\n )\n\n select\n ord.uuid as \"uuid: crate::model::cfd::OrderId\",\n ord.trading_pair as \"trading_pair: crate::model::TradingPair\",\n ord.position as \"position: crate::model::Position\",\n ord.initial_price,\n ord.min_quantity,\n ord.max_quantity,\n ord.leverage as \"leverage: crate::model::Leverage\",\n ord.liquidation_price,\n ord.ts_secs as \"ts_secs: i64\",\n ord.ts_nanos as \"ts_nanos: i32\",\n ord.term_secs as \"term_secs: i64\",\n ord.term_nanos as \"term_nanos: i32\",\n ord.origin as \"origin: crate::model::cfd::Origin\",\n ord.oracle_event_id,\n state.quantity_usd,\n state.state\n\n from ord\n inner join state on state.order_id = ord.order_id\n\n where ord.uuid = $1\n ", "query": "\n with ord as (\n select\n id as order_id,\n uuid,\n trading_pair,\n position,\n initial_price,\n min_quantity,\n max_quantity,\n leverage,\n liquidation_price,\n creation_timestamp_seconds as ts_secs,\n creation_timestamp_nanoseconds as ts_nanos,\n settlement_time_interval_seconds as settlement_time_interval_secs,\n settlement_time_interval_nanoseconds as settlement_time_interval_nanos,\n origin,\n oracle_event_id\n from orders\n ),\n\n cfd as (\n select\n ord.order_id,\n id as cfd_id,\n quantity_usd\n from cfds\n inner join ord on ord.order_id = cfds.order_id\n ),\n\n state as (\n select\n id as state_id,\n cfd.order_id,\n cfd.quantity_usd,\n state\n from cfd_states\n inner join cfd on cfd.cfd_id = cfd_states.cfd_id\n where id in (\n select\n max(id) as id\n from cfd_states\n group by (cfd_id)\n )\n )\n\n select\n ord.uuid as \"uuid: crate::model::cfd::OrderId\",\n ord.trading_pair as \"trading_pair: crate::model::TradingPair\",\n ord.position as \"position: crate::model::Position\",\n ord.initial_price,\n ord.min_quantity,\n ord.max_quantity,\n ord.leverage as \"leverage: crate::model::Leverage\",\n ord.liquidation_price,\n ord.ts_secs as \"ts_secs: i64\",\n ord.ts_nanos as \"ts_nanos: i32\",\n ord.settlement_time_interval_secs as \"settlement_time_interval_secs: i64\",\n ord.settlement_time_interval_nanos as \"settlement_time_interval_nanos: i32\",\n ord.origin as \"origin: crate::model::cfd::Origin\",\n ord.oracle_event_id,\n state.quantity_usd,\n state.state\n\n from ord\n inner join state on state.order_id = ord.order_id\n\n where ord.uuid = $1\n ",
"describe": { "describe": {
"columns": [ "columns": [
{ {
@ -181,12 +151,12 @@
"type_info": "Int64" "type_info": "Int64"
}, },
{ {
"name": "term_secs: i64", "name": "settlement_time_interval_secs: i64",
"ordinal": 10, "ordinal": 10,
"type_info": "Int64" "type_info": "Int64"
}, },
{ {
"name": "term_nanos: i32", "name": "settlement_time_interval_nanos: i32",
"ordinal": 11, "ordinal": 11,
"type_info": "Int64" "type_info": "Int64"
}, },
@ -234,26 +204,26 @@
] ]
} }
}, },
"8cbe349911b35d8e79763d64b4f5813b4bd98f12e0bba5ada84d2cae8b08ef4f": { "221a6283db798bacaba99e7e85130f9a8bbea1299d8cb99d272b1d478dc19775": {
"query": "\n select\n id\n from cfds\n where order_uuid = $1;\n ", "query": "\n select\n state\n from cfd_states\n where cfd_id = $1\n order by id desc\n limit 1;\n ",
"describe": { "describe": {
"columns": [ "columns": [
{ {
"name": "id", "name": "state",
"ordinal": 0, "ordinal": 0,
"type_info": "Int64" "type_info": "Text"
} }
], ],
"parameters": { "parameters": {
"Right": 1 "Right": 1
}, },
"nullable": [ "nullable": [
true false
] ]
} }
}, },
"b593977ea0af1bfe0a111ec908bab2149cf6d0cdee74e3321b5f2fa8154480e5": { "571575003ef3ad8ad627213f11c9080c25a29bb665077ada9047630acfe4465c": {
"query": "\n with ord as (\n select\n id as order_id,\n uuid,\n trading_pair,\n position,\n initial_price,\n min_quantity,\n max_quantity,\n leverage,\n liquidation_price,\n creation_timestamp_seconds as ts_secs,\n creation_timestamp_nanoseconds as ts_nanos,\n term_seconds as term_secs,\n term_nanoseconds as term_nanos,\n origin,\n oracle_event_id\n from orders\n ),\n\n cfd as (\n select\n ord.order_id,\n id as cfd_id,\n quantity_usd\n from cfds\n inner join ord on ord.order_id = cfds.order_id\n ),\n\n state as (\n select\n id as state_id,\n cfd.order_id,\n cfd.quantity_usd,\n state\n from cfd_states\n inner join cfd on cfd.cfd_id = cfd_states.cfd_id\n where id in (\n select\n max(id) as id\n from cfd_states\n group by (cfd_id)\n )\n )\n\n select\n ord.uuid as \"uuid: crate::model::cfd::OrderId\",\n ord.trading_pair as \"trading_pair: crate::model::TradingPair\",\n ord.position as \"position: crate::model::Position\",\n ord.initial_price,\n ord.min_quantity,\n ord.max_quantity,\n ord.leverage as \"leverage: crate::model::Leverage\",\n ord.liquidation_price,\n ord.ts_secs as \"ts_secs: i64\",\n ord.ts_nanos as \"ts_nanos: i32\",\n ord.term_secs as \"term_secs: i64\",\n ord.term_nanos as \"term_nanos: i32\",\n ord.origin as \"origin: crate::model::cfd::Origin\",\n ord.oracle_event_id,\n state.quantity_usd,\n state.state\n\n from ord\n inner join state on state.order_id = ord.order_id\n\n where ord.oracle_event_id = $1\n ", "query": "\n with ord as (\n select\n id as order_id,\n uuid,\n trading_pair,\n position,\n initial_price,\n min_quantity,\n max_quantity,\n leverage,\n liquidation_price,\n creation_timestamp_seconds as ts_secs,\n creation_timestamp_nanoseconds as ts_nanos,\n settlement_time_interval_seconds as settlement_time_interval_secs,\n settlement_time_interval_nanoseconds as settlement_time_interval_nanos,\n origin,\n oracle_event_id\n from orders\n ),\n\n cfd as (\n select\n ord.order_id,\n id as cfd_id,\n quantity_usd\n from cfds\n inner join ord on ord.order_id = cfds.order_id\n ),\n\n state as (\n select\n id as state_id,\n cfd.order_id,\n cfd.quantity_usd,\n state\n from cfd_states\n inner join cfd on cfd.cfd_id = cfd_states.cfd_id\n where id in (\n select\n max(id) as id\n from cfd_states\n group by (cfd_id)\n )\n )\n\n select\n ord.uuid as \"uuid: crate::model::cfd::OrderId\",\n ord.trading_pair as \"trading_pair: crate::model::TradingPair\",\n ord.position as \"position: crate::model::Position\",\n ord.initial_price,\n ord.min_quantity,\n ord.max_quantity,\n ord.leverage as \"leverage: crate::model::Leverage\",\n ord.liquidation_price,\n ord.ts_secs as \"ts_secs: i64\",\n ord.ts_nanos as \"ts_nanos: i32\",\n ord.settlement_time_interval_secs as \"settlement_time_interval_secs: i64\",\n ord.settlement_time_interval_nanos as \"settlement_time_interval_nanos: i32\",\n ord.origin as \"origin: crate::model::cfd::Origin\",\n ord.oracle_event_id,\n state.quantity_usd,\n state.state\n\n from ord\n inner join state on state.order_id = ord.order_id\n\n where ord.oracle_event_id = $1\n ",
"describe": { "describe": {
"columns": [ "columns": [
{ {
@ -307,12 +277,12 @@
"type_info": "Int64" "type_info": "Int64"
}, },
{ {
"name": "term_secs: i64", "name": "settlement_time_interval_secs: i64",
"ordinal": 10, "ordinal": 10,
"type_info": "Int64" "type_info": "Int64"
}, },
{ {
"name": "term_nanos: i32", "name": "settlement_time_interval_nanos: i32",
"ordinal": 11, "ordinal": 11,
"type_info": "Int64" "type_info": "Int64"
}, },
@ -360,8 +330,26 @@
] ]
} }
}, },
"b708b7116aa14093e0e21ab8f87e52928a70649a62250902054ef6526f1d6f66": { "8cbe349911b35d8e79763d64b4f5813b4bd98f12e0bba5ada84d2cae8b08ef4f": {
"query": "\n select\n uuid as \"uuid: crate::model::cfd::OrderId\",\n trading_pair as \"trading_pair: crate::model::TradingPair\",\n position as \"position: crate::model::Position\",\n initial_price,\n min_quantity,\n max_quantity,\n leverage as \"leverage: crate::model::Leverage\",\n liquidation_price,\n creation_timestamp_seconds as \"ts_secs: i64\",\n creation_timestamp_nanoseconds as \"ts_nanos: i32\",\n term_seconds as \"term_secs: i64\",\n term_nanoseconds as \"term_nanos: i32\",\n origin as \"origin: crate::model::cfd::Origin\",\n oracle_event_id\n\n from orders\n where uuid = $1\n ", "query": "\n select\n id\n from cfds\n where order_uuid = $1;\n ",
"describe": {
"columns": [
{
"name": "id",
"ordinal": 0,
"type_info": "Int64"
}
],
"parameters": {
"Right": 1
},
"nullable": [
true
]
}
},
"b5a6bcafbfa745d147c30410e0acf8ee6c7733cc3e550a2db0c7860737c756dd": {
"query": "\n with ord as (\n select\n id as order_id,\n uuid,\n trading_pair,\n position,\n initial_price,\n min_quantity,\n max_quantity,\n leverage,\n liquidation_price,\n creation_timestamp_seconds as ts_secs,\n creation_timestamp_nanoseconds as ts_nanos,\n settlement_time_interval_seconds as settlement_time_interval_secs,\n settlement_time_interval_nanoseconds as settlement_time_interval_nanos,\n origin,\n oracle_event_id\n from orders\n ),\n\n cfd as (\n select\n ord.order_id,\n id as cfd_id,\n quantity_usd\n from cfds\n inner join ord on ord.order_id = cfds.order_id\n ),\n\n state as (\n select\n id as state_id,\n cfd.order_id,\n cfd.quantity_usd,\n state\n from cfd_states\n inner join cfd on cfd.cfd_id = cfd_states.cfd_id\n where id in (\n select\n max(id) as id\n from cfd_states\n group by (cfd_id)\n )\n )\n\n select\n ord.uuid as \"uuid: crate::model::cfd::OrderId\",\n ord.trading_pair as \"trading_pair: crate::model::TradingPair\",\n ord.position as \"position: crate::model::Position\",\n ord.initial_price,\n ord.min_quantity,\n ord.max_quantity,\n ord.leverage as \"leverage: crate::model::Leverage\",\n ord.liquidation_price,\n ord.ts_secs as \"ts_secs: i64\",\n ord.ts_nanos as \"ts_nanos: i32\",\n ord.settlement_time_interval_secs as \"settlement_time_interval_secs: i64\",\n ord.settlement_time_interval_nanos as \"settlement_time_interval_nanos: i32\",\n ord.origin as \"origin: crate::model::cfd::Origin\",\n ord.oracle_event_id,\n state.quantity_usd,\n state.state\n\n from ord\n inner join state on state.order_id = ord.order_id\n ",
"describe": { "describe": {
"columns": [ "columns": [
{ {
@ -415,12 +403,12 @@
"type_info": "Int64" "type_info": "Int64"
}, },
{ {
"name": "term_secs: i64", "name": "settlement_time_interval_secs: i64",
"ordinal": 10, "ordinal": 10,
"type_info": "Int64" "type_info": "Int64"
}, },
{ {
"name": "term_nanos: i32", "name": "settlement_time_interval_nanos: i32",
"ordinal": 11, "ordinal": 11,
"type_info": "Int64" "type_info": "Int64"
}, },
@ -433,10 +421,20 @@
"name": "oracle_event_id", "name": "oracle_event_id",
"ordinal": 13, "ordinal": 13,
"type_info": "Text" "type_info": "Text"
},
{
"name": "quantity_usd",
"ordinal": 14,
"type_info": "Text"
},
{
"name": "state",
"ordinal": 15,
"type_info": "Text"
} }
], ],
"parameters": { "parameters": {
"Right": 1 "Right": 0
}, },
"nullable": [ "nullable": [
false, false,
@ -452,6 +450,8 @@
false, false,
false, false,
false, false,
false,
false,
false false
] ]
} }

56
daemon/src/db.rs

@ -27,8 +27,8 @@ pub async fn insert_order(order: &Order, conn: &mut PoolConnection<Sqlite>) -> a
liquidation_price, liquidation_price,
creation_timestamp_seconds, creation_timestamp_seconds,
creation_timestamp_nanoseconds, creation_timestamp_nanoseconds,
term_seconds, settlement_time_interval_seconds,
term_nanoseconds, settlement_time_interval_nanoseconds,
origin, origin,
oracle_event_id oracle_event_id
) values ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14)"#, ) values ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14)"#,
@ -53,8 +53,8 @@ pub async fn insert_order(order: &Order, conn: &mut PoolConnection<Sqlite>) -> a
.duration_since(SystemTime::UNIX_EPOCH)? .duration_since(SystemTime::UNIX_EPOCH)?
.subsec_nanos() as i32, .subsec_nanos() as i32,
) )
.bind(&order.term.whole_seconds()) .bind(&order.settlement_time_interval_hours.whole_seconds())
.bind(&order.term.subsec_nanoseconds()) .bind(&order.settlement_time_interval_hours.subsec_nanoseconds())
.bind(&order.origin) .bind(&order.origin)
.bind(&order.oracle_event_id.to_string()) .bind(&order.oracle_event_id.to_string())
.execute(conn) .execute(conn)
@ -84,8 +84,8 @@ pub async fn load_order_by_id(
liquidation_price, liquidation_price,
creation_timestamp_seconds as "ts_secs: i64", creation_timestamp_seconds as "ts_secs: i64",
creation_timestamp_nanoseconds as "ts_nanos: i32", creation_timestamp_nanoseconds as "ts_nanos: i32",
term_seconds as "term_secs: i64", settlement_time_interval_seconds as "settlement_time_interval_secs: i64",
term_nanoseconds as "term_nanos: i32", settlement_time_interval_nanoseconds as "settlement_time_interval_nanos: i32",
origin as "origin: crate::model::cfd::Origin", origin as "origin: crate::model::cfd::Origin",
oracle_event_id oracle_event_id
@ -107,7 +107,10 @@ pub async fn load_order_by_id(
leverage: row.leverage, leverage: row.leverage,
liquidation_price: Usd::new(Decimal::from_str(&row.liquidation_price)?), liquidation_price: Usd::new(Decimal::from_str(&row.liquidation_price)?),
creation_timestamp: convert_to_system_time(row.ts_secs, row.ts_nanos)?, creation_timestamp: convert_to_system_time(row.ts_secs, row.ts_nanos)?,
term: Duration::new(row.term_secs, row.term_nanos), settlement_time_interval_hours: Duration::new(
row.settlement_time_interval_secs,
row.settlement_time_interval_nanos,
),
origin: row.origin, origin: row.origin,
oracle_event_id: row.oracle_event_id.parse::<BitMexPriceEventId>()?, oracle_event_id: row.oracle_event_id.parse::<BitMexPriceEventId>()?,
}) })
@ -251,8 +254,8 @@ pub async fn load_cfd_by_order_id(
liquidation_price, liquidation_price,
creation_timestamp_seconds as ts_secs, creation_timestamp_seconds as ts_secs,
creation_timestamp_nanoseconds as ts_nanos, creation_timestamp_nanoseconds as ts_nanos,
term_seconds as term_secs, settlement_time_interval_seconds as settlement_time_interval_secs,
term_nanoseconds as term_nanos, settlement_time_interval_nanoseconds as settlement_time_interval_nanos,
origin, origin,
oracle_event_id oracle_event_id
from orders from orders
@ -294,8 +297,8 @@ pub async fn load_cfd_by_order_id(
ord.liquidation_price, ord.liquidation_price,
ord.ts_secs as "ts_secs: i64", ord.ts_secs as "ts_secs: i64",
ord.ts_nanos as "ts_nanos: i32", ord.ts_nanos as "ts_nanos: i32",
ord.term_secs as "term_secs: i64", ord.settlement_time_interval_secs as "settlement_time_interval_secs: i64",
ord.term_nanos as "term_nanos: i32", ord.settlement_time_interval_nanos as "settlement_time_interval_nanos: i32",
ord.origin as "origin: crate::model::cfd::Origin", ord.origin as "origin: crate::model::cfd::Origin",
ord.oracle_event_id, ord.oracle_event_id,
state.quantity_usd, state.quantity_usd,
@ -321,7 +324,10 @@ pub async fn load_cfd_by_order_id(
leverage: row.leverage, leverage: row.leverage,
liquidation_price: Usd::new(Decimal::from_str(&row.liquidation_price)?), liquidation_price: Usd::new(Decimal::from_str(&row.liquidation_price)?),
creation_timestamp: convert_to_system_time(row.ts_secs, row.ts_nanos)?, creation_timestamp: convert_to_system_time(row.ts_secs, row.ts_nanos)?,
term: Duration::new(row.term_secs, row.term_nanos), settlement_time_interval_hours: Duration::new(
row.settlement_time_interval_secs,
row.settlement_time_interval_nanos,
),
origin: row.origin, origin: row.origin,
oracle_event_id: row.oracle_event_id.parse::<BitMexPriceEventId>()?, oracle_event_id: row.oracle_event_id.parse::<BitMexPriceEventId>()?,
}; };
@ -353,8 +359,8 @@ pub async fn load_all_cfds(conn: &mut PoolConnection<Sqlite>) -> anyhow::Result<
liquidation_price, liquidation_price,
creation_timestamp_seconds as ts_secs, creation_timestamp_seconds as ts_secs,
creation_timestamp_nanoseconds as ts_nanos, creation_timestamp_nanoseconds as ts_nanos,
term_seconds as term_secs, settlement_time_interval_seconds as settlement_time_interval_secs,
term_nanoseconds as term_nanos, settlement_time_interval_nanoseconds as settlement_time_interval_nanos,
origin, origin,
oracle_event_id oracle_event_id
from orders from orders
@ -396,8 +402,8 @@ pub async fn load_all_cfds(conn: &mut PoolConnection<Sqlite>) -> anyhow::Result<
ord.liquidation_price, ord.liquidation_price,
ord.ts_secs as "ts_secs: i64", ord.ts_secs as "ts_secs: i64",
ord.ts_nanos as "ts_nanos: i32", ord.ts_nanos as "ts_nanos: i32",
ord.term_secs as "term_secs: i64", ord.settlement_time_interval_secs as "settlement_time_interval_secs: i64",
ord.term_nanos as "term_nanos: i32", ord.settlement_time_interval_nanos as "settlement_time_interval_nanos: i32",
ord.origin as "origin: crate::model::cfd::Origin", ord.origin as "origin: crate::model::cfd::Origin",
ord.oracle_event_id, ord.oracle_event_id,
state.quantity_usd, state.quantity_usd,
@ -423,7 +429,10 @@ pub async fn load_all_cfds(conn: &mut PoolConnection<Sqlite>) -> anyhow::Result<
leverage: row.leverage, leverage: row.leverage,
liquidation_price: Usd::new(Decimal::from_str(&row.liquidation_price)?), liquidation_price: Usd::new(Decimal::from_str(&row.liquidation_price)?),
creation_timestamp: convert_to_system_time(row.ts_secs, row.ts_nanos)?, creation_timestamp: convert_to_system_time(row.ts_secs, row.ts_nanos)?,
term: Duration::new(row.term_secs, row.term_nanos), settlement_time_interval_hours: Duration::new(
row.settlement_time_interval_secs,
row.settlement_time_interval_nanos,
),
origin: row.origin, origin: row.origin,
oracle_event_id: row.oracle_event_id.parse::<BitMexPriceEventId>()?, oracle_event_id: row.oracle_event_id.parse::<BitMexPriceEventId>()?,
}; };
@ -460,8 +469,8 @@ pub async fn load_cfds_by_oracle_event_id(
liquidation_price, liquidation_price,
creation_timestamp_seconds as ts_secs, creation_timestamp_seconds as ts_secs,
creation_timestamp_nanoseconds as ts_nanos, creation_timestamp_nanoseconds as ts_nanos,
term_seconds as term_secs, settlement_time_interval_seconds as settlement_time_interval_secs,
term_nanoseconds as term_nanos, settlement_time_interval_nanoseconds as settlement_time_interval_nanos,
origin, origin,
oracle_event_id oracle_event_id
from orders from orders
@ -503,8 +512,8 @@ pub async fn load_cfds_by_oracle_event_id(
ord.liquidation_price, ord.liquidation_price,
ord.ts_secs as "ts_secs: i64", ord.ts_secs as "ts_secs: i64",
ord.ts_nanos as "ts_nanos: i32", ord.ts_nanos as "ts_nanos: i32",
ord.term_secs as "term_secs: i64", ord.settlement_time_interval_secs as "settlement_time_interval_secs: i64",
ord.term_nanos as "term_nanos: i32", ord.settlement_time_interval_nanos as "settlement_time_interval_nanos: i32",
ord.origin as "origin: crate::model::cfd::Origin", ord.origin as "origin: crate::model::cfd::Origin",
ord.oracle_event_id, ord.oracle_event_id,
state.quantity_usd, state.quantity_usd,
@ -533,7 +542,10 @@ pub async fn load_cfds_by_oracle_event_id(
leverage: row.leverage, leverage: row.leverage,
liquidation_price: Usd::new(Decimal::from_str(&row.liquidation_price)?), liquidation_price: Usd::new(Decimal::from_str(&row.liquidation_price)?),
creation_timestamp: convert_to_system_time(row.ts_secs, row.ts_nanos)?, creation_timestamp: convert_to_system_time(row.ts_secs, row.ts_nanos)?,
term: Duration::new(row.term_secs, row.term_nanos), settlement_time_interval_hours: Duration::new(
row.settlement_time_interval_secs,
row.settlement_time_interval_nanos,
),
origin: row.origin, origin: row.origin,
oracle_event_id: row.oracle_event_id.parse::<BitMexPriceEventId>()?, oracle_event_id: row.oracle_event_id.parse::<BitMexPriceEventId>()?,
}; };

4
daemon/src/lib.rs

@ -79,7 +79,7 @@ where
Box<dyn MessageChannel<NewTakerOnline>>, Box<dyn MessageChannel<NewTakerOnline>>,
Box<dyn MessageChannel<FromTaker>>, Box<dyn MessageChannel<FromTaker>>,
) -> T, ) -> T,
term: time::Duration, settlement_time_interval_hours: time::Duration,
) -> Result<Self> ) -> Result<Self>
where where
F: Future<Output = Result<M>>, F: Future<Output = Result<M>>,
@ -100,7 +100,7 @@ where
let cfd_actor_addr = maker_cfd::Actor::new( let cfd_actor_addr = maker_cfd::Actor::new(
db, db,
wallet_addr, wallet_addr,
term, settlement_time_interval_hours,
oracle_pk, oracle_pk,
cfd_feed_sender, cfd_feed_sender,
order_feed_sender, order_feed_sender,

11
daemon/src/maker.rs

@ -51,9 +51,9 @@ struct Opts {
#[clap(short, long)] #[clap(short, long)]
json: bool, json: bool,
/// The term length of each CFD in hours. /// The time interval until potential settlement of each CFD in hours
#[clap(long, default_value = "24")] #[clap(long, default_value = "24")]
term: u8, settlement_time_interval_hours: u8,
#[clap(subcommand)] #[clap(subcommand)]
network: Network, network: Network,
@ -190,7 +190,8 @@ async fn main() -> Result<()> {
housekeeping::transition_non_continue_cfds_to_setup_failed(&mut conn).await?; housekeeping::transition_non_continue_cfds_to_setup_failed(&mut conn).await?;
housekeeping::rebroadcast_transactions(&mut conn, &wallet).await?; housekeeping::rebroadcast_transactions(&mut conn, &wallet).await?;
let term = time::Duration::hours(opts.term as i64); let settlement_time_interval_hours =
time::Duration::hours(opts.settlement_time_interval_hours as i64);
let MakerActorSystem { let MakerActorSystem {
cfd_actor_addr, cfd_actor_addr,
cfd_feed_receiver, cfd_feed_receiver,
@ -201,7 +202,7 @@ async fn main() -> Result<()> {
db.clone(), db.clone(),
wallet.clone(), wallet.clone(),
oracle, oracle,
|cfds, channel| oracle::Actor::new(cfds, channel, term), |cfds, channel| oracle::Actor::new(cfds, channel, settlement_time_interval_hours),
{ {
|channel, cfds| { |channel, cfds| {
let electrum = opts.network.electrum().to_string(); let electrum = opts.network.electrum().to_string();
@ -209,7 +210,7 @@ async fn main() -> Result<()> {
} }
}, },
|channel0, channel1| maker_inc_connections::Actor::new(channel0, channel1), |channel0, channel1| maker_inc_connections::Actor::new(channel0, channel1),
time::Duration::hours(opts.term as i64), time::Duration::hours(opts.settlement_time_interval_hours as i64),
) )
.await?; .await?;

18
daemon/src/maker_cfd.rs

@ -61,7 +61,7 @@ pub struct FromTaker {
pub struct Actor<O, M, T, W> { pub struct Actor<O, M, T, W> {
db: sqlx::SqlitePool, db: sqlx::SqlitePool,
wallet: Address<W>, wallet: Address<W>,
term: Duration, settlement_time_interval_hours: Duration,
oracle_pk: schnorrsig::PublicKey, oracle_pk: schnorrsig::PublicKey,
cfd_feed_actor_inbox: watch::Sender<Vec<Cfd>>, cfd_feed_actor_inbox: watch::Sender<Vec<Cfd>>,
order_feed_sender: watch::Sender<Option<Order>>, order_feed_sender: watch::Sender<Option<Order>>,
@ -98,7 +98,7 @@ impl<O, M, T, W> Actor<O, M, T, W> {
pub fn new( pub fn new(
db: sqlx::SqlitePool, db: sqlx::SqlitePool,
wallet: Address<W>, wallet: Address<W>,
term: Duration, settlement_time_interval_hours: Duration,
oracle_pk: schnorrsig::PublicKey, oracle_pk: schnorrsig::PublicKey,
cfd_feed_actor_inbox: watch::Sender<Vec<Cfd>>, cfd_feed_actor_inbox: watch::Sender<Vec<Cfd>>,
order_feed_sender: watch::Sender<Option<Order>>, order_feed_sender: watch::Sender<Option<Order>>,
@ -110,7 +110,7 @@ impl<O, M, T, W> Actor<O, M, T, W> {
Self { Self {
db, db,
wallet, wallet,
term, settlement_time_interval_hours,
oracle_pk, oracle_pk,
cfd_feed_actor_inbox, cfd_feed_actor_inbox,
order_feed_sender, order_feed_sender,
@ -637,8 +637,9 @@ where
min_quantity: Usd, min_quantity: Usd,
max_quantity: Usd, max_quantity: Usd,
) -> Result<()> { ) -> Result<()> {
let oracle_event_id = let oracle_event_id = oracle::next_announcement_after(
oracle::next_announcement_after(time::OffsetDateTime::now_utc() + self.term)?; time::OffsetDateTime::now_utc() + self.settlement_time_interval_hours,
)?;
let order = Order::new( let order = Order::new(
price, price,
@ -646,7 +647,7 @@ where
max_quantity, max_quantity,
Origin::Ours, Origin::Ours,
oracle_event_id, oracle_event_id,
self.term, self.settlement_time_interval_hours,
)?; )?;
// 1. Save to DB // 1. Save to DB
@ -751,8 +752,9 @@ where
let dlc = cfd.open_dlc().context("CFD was in wrong state")?; let dlc = cfd.open_dlc().context("CFD was in wrong state")?;
let oracle_event_id = let oracle_event_id = oracle::next_announcement_after(
oracle::next_announcement_after(time::OffsetDateTime::now_utc() + cfd.order.term)?; time::OffsetDateTime::now_utc() + cfd.order.settlement_time_interval_hours,
)?;
let announcement = self let announcement = self
.oracle_actor .oracle_actor
.send(oracle::GetAnnouncement(oracle_event_id)) .send(oracle::GetAnnouncement(oracle_event_id))

24
daemon/src/model/cfd.rs

@ -114,7 +114,7 @@ pub struct Order {
pub creation_timestamp: SystemTime, pub creation_timestamp: SystemTime,
/// The duration that will be used for calculating the settlement timestamp /// The duration that will be used for calculating the settlement timestamp
pub term: Duration, pub settlement_time_interval_hours: Duration,
pub origin: Origin, pub origin: Origin,
@ -131,7 +131,7 @@ impl Order {
max_quantity: Usd, max_quantity: Usd,
origin: Origin, origin: Origin,
oracle_event_id: BitMexPriceEventId, oracle_event_id: BitMexPriceEventId,
term: Duration, settlement_time_interval_hours: Duration,
) -> Result<Self> { ) -> Result<Self> {
let leverage = Leverage(2); let leverage = Leverage(2);
let maintenance_margin_rate = dec!(0.005); let maintenance_margin_rate = dec!(0.005);
@ -148,7 +148,7 @@ impl Order {
liquidation_price, liquidation_price,
position: Position::Sell, position: Position::Sell,
creation_timestamp: SystemTime::now(), creation_timestamp: SystemTime::now(),
term, settlement_time_interval_hours,
origin, origin,
oracle_event_id, oracle_event_id,
}) })
@ -682,25 +682,29 @@ impl Cfd {
} }
pub fn refund_timelock_in_blocks(&self) -> u32 { pub fn refund_timelock_in_blocks(&self) -> u32 {
(self.order.term * Cfd::REFUND_THRESHOLD).as_blocks().ceil() as u32 (self.order.settlement_time_interval_hours * Cfd::REFUND_THRESHOLD)
.as_blocks()
.ceil() as u32
} }
pub fn expiry_timestamp(&self) -> OffsetDateTime { pub fn expiry_timestamp(&self) -> OffsetDateTime {
self.order.oracle_event_id.timestamp() self.order.oracle_event_id.timestamp()
} }
/// A factor to be added to the CFD order term for calculating the refund timelock. /// A factor to be added to the CFD order settlement_time_interval_hours for calculating the
/// refund timelock.
/// ///
/// The refund timelock is important in case the oracle disappears or never publishes a /// 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 /// signature. Ideally, both users collaboratively settle in the refund scenario. This
/// factor is important if the users do not settle collaboratively. /// factor is important if the users do not settle collaboratively.
/// `1.5` times the term as defined in CFD order should be safe in the extreme case where a user /// `1.5` times the settlement_time_interval_hours as defined in CFD order should be safe in the
/// publishes the commit transaction right after the contract was initialized. In this case, the /// extreme case where a user publishes the commit transaction right after the contract was
/// oracle still has `1.0 * cfdorder.term` time to attest and no one can publish the refund /// initialized. In this case, the oracle still has `1.0 *
/// cfdorder.settlement_time_interval_hours` time to attest and no one can publish the refund
/// transaction. /// transaction.
/// The downside is that if the oracle disappears: the users would only notice at the end /// 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 /// of the cfd settlement_time_interval_hours. In this case the users has to wait for another
/// term to get his funds back. /// `1.5` times of the settlement_time_interval_hours to get his funds back.
const REFUND_THRESHOLD: f32 = 1.5; const REFUND_THRESHOLD: f32 = 1.5;
pub const CET_TIMELOCK: u32 = 12; pub const CET_TIMELOCK: u32 = 12;

18
daemon/src/oracle.rs

@ -17,7 +17,7 @@ pub struct Actor {
announcements: HashMap<BitMexPriceEventId, (OffsetDateTime, Vec<schnorrsig::PublicKey>)>, announcements: HashMap<BitMexPriceEventId, (OffsetDateTime, Vec<schnorrsig::PublicKey>)>,
pending_attestations: HashSet<BitMexPriceEventId>, pending_attestations: HashSet<BitMexPriceEventId>,
attestation_channel: Box<dyn StrongMessageChannel<Attestation>>, attestation_channel: Box<dyn StrongMessageChannel<Attestation>>,
term: Duration, announcement_lookahead: Duration,
} }
pub struct Sync; pub struct Sync;
@ -62,7 +62,7 @@ impl Actor {
pub fn new( pub fn new(
cfds: Vec<Cfd>, cfds: Vec<Cfd>,
attestation_channel: Box<dyn StrongMessageChannel<Attestation>>, attestation_channel: Box<dyn StrongMessageChannel<Attestation>>,
term: Duration, announcement_lookahead: Duration,
) -> Self { ) -> Self {
let mut pending_attestations = HashSet::new(); let mut pending_attestations = HashSet::new();
@ -96,13 +96,17 @@ impl Actor {
announcements: HashMap::new(), announcements: HashMap::new(),
pending_attestations, pending_attestations,
attestation_channel, attestation_channel,
term, announcement_lookahead,
} }
} }
fn ensure_having_announcements(&mut self, term: Duration, ctx: &mut xtra::Context<Self>) { fn ensure_having_announcements(
// we want inclusive the term length hence +1 &mut self,
for hour in 1..term.whole_hours() + 1 { announcement_lookahead: Duration,
ctx: &mut xtra::Context<Self>,
) {
// we want inclusive the settlement_time_interval_hours length hence +1
for hour in 1..announcement_lookahead.whole_hours() + 1 {
let event_id = try_continue!(next_announcement_after( let event_id = try_continue!(next_announcement_after(
time::OffsetDateTime::now_utc() + Duration::hours(hour) time::OffsetDateTime::now_utc() + Duration::hours(hour)
)); ));
@ -235,7 +239,7 @@ impl Actor {
} }
fn handle_sync(&mut self, _: Sync, ctx: &mut xtra::Context<Self>) { fn handle_sync(&mut self, _: Sync, ctx: &mut xtra::Context<Self>) {
self.ensure_having_announcements(self.term, ctx); self.ensure_having_announcements(self.announcement_lookahead, ctx);
self.update_pending_attestations(ctx); self.update_pending_attestations(ctx);
} }
} }

4
daemon/src/taker.rs

@ -27,7 +27,7 @@ use xtra::Actor;
mod routes_taker; mod routes_taker;
pub const TERM: time::Duration = time::Duration::hours(24); pub const ANNOUNCEMENT_LOOKAHEAD: time::Duration = time::Duration::hours(24);
#[derive(Clap)] #[derive(Clap)]
struct Opts { struct Opts {
@ -181,7 +181,7 @@ async fn main() -> Result<()> {
oracle, oracle,
send_to_maker, send_to_maker,
read_from_maker, read_from_maker,
|cfds, channel| oracle::Actor::new(cfds, channel, TERM), |cfds, channel| oracle::Actor::new(cfds, channel, ANNOUNCEMENT_LOOKAHEAD),
{ {
|channel, cfds| { |channel, cfds| {
let electrum = opts.network.electrum().to_string(); let electrum = opts.network.electrum().to_string();

8
daemon/src/to_sse_event.rs

@ -172,7 +172,7 @@ pub struct CfdOrder {
pub liquidation_price: Usd, pub liquidation_price: Usd,
pub creation_timestamp: u64, pub creation_timestamp: u64,
pub term_in_secs: u64, pub settlement_time_interval_in_secs: u64,
} }
pub trait ToSseEvent { pub trait ToSseEvent {
@ -290,11 +290,11 @@ impl ToSseEvent for Option<model::cfd::Order> {
.duration_since(UNIX_EPOCH) .duration_since(UNIX_EPOCH)
.expect("timestamp to be convertible to duration since epoch") .expect("timestamp to be convertible to duration since epoch")
.as_secs(), .as_secs(),
term_in_secs: order settlement_time_interval_in_secs: order
.term .settlement_time_interval_hours
.whole_seconds() .whole_seconds()
.try_into() .try_into()
.expect("term is always positive number"), .expect("settlement_time_interval_hours is always positive number"),
}); });
Event::json(&order).event("order") Event::json(&order).event("order")

4
daemon/tests/happy_path.rs

@ -165,7 +165,7 @@ impl Maker {
let wallet_addr = Wallet {}.create(None).spawn_global(); let wallet_addr = Wallet {}.create(None).spawn_global();
let term = time::Duration::hours(24); let settlement_time_interval_hours = time::Duration::hours(24);
let maker = daemon::MakerActorSystem::new( let maker = daemon::MakerActorSystem::new(
db, db,
@ -174,7 +174,7 @@ impl Maker {
|_, _| Oracle, |_, _| Oracle,
|_, _| async { Ok(Monitor) }, |_, _| async { Ok(Monitor) },
|channel0, channel1| maker_inc_connections::Actor::new(channel0, channel1), |channel0, channel1| maker_inc_connections::Actor::new(channel0, channel1),
term, settlement_time_interval_hours,
) )
.await .await
.unwrap(); .unwrap();

2
frontend/src/components/Types.tsx

@ -8,7 +8,7 @@ export interface Order {
leverage: number; leverage: number;
liquidation_price: number; liquidation_price: number;
creation_timestamp: number; creation_timestamp: number;
term_in_secs: number; settlement_time_interval_in_secs: number;
} }
export class Position { export class Position {

Loading…
Cancel
Save