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",
"221a6283db798bacaba99e7e85130f9a8bbea1299d8cb99d272b1d478dc19775": {
"query": "\n select\n state\n from cfd_states\n where cfd_id = $1\n order by id desc\n limit 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 ",
"07b8db7d3a709a7f06a20251d5b7251c2a3428ec73c6710a83048d6c8e974958": {
"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": [
{
@ -73,12 +55,12 @@
"type_info": "Int64"
},
{
"name": "term_secs: i64",
"name": "settlement_time_interval_secs: i64",
"ordinal": 10,
"type_info": "Int64"
},
{
"name": "term_nanos: i32",
"name": "settlement_time_interval_nanos: i32",
"ordinal": 11,
"type_info": "Int64"
},
@ -91,20 +73,10 @@
"name": "oracle_event_id",
"ordinal": 13,
"type_info": "Text"
},
{
"name": "quantity_usd",
"ordinal": 14,
"type_info": "Text"
},
{
"name": "state",
"ordinal": 15,
"type_info": "Text"
}
],
"parameters": {
"Right": 0
"Right": 1
},
"nullable": [
false,
@ -120,14 +92,12 @@
false,
false,
false,
false,
false,
false
]
}
},
"7610f0d5a9d216dba503cb5f9980fa5d9cabd13dc0131166bb6439ded37ee5dd": {
"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 ",
"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 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": {
"columns": [
{
@ -181,12 +151,12 @@
"type_info": "Int64"
},
{
"name": "term_secs: i64",
"name": "settlement_time_interval_secs: i64",
"ordinal": 10,
"type_info": "Int64"
},
{
"name": "term_nanos: i32",
"name": "settlement_time_interval_nanos: i32",
"ordinal": 11,
"type_info": "Int64"
},
@ -234,26 +204,26 @@
]
}
},
"8cbe349911b35d8e79763d64b4f5813b4bd98f12e0bba5ada84d2cae8b08ef4f": {
"query": "\n select\n id\n from cfds\n where order_uuid = $1;\n ",
"221a6283db798bacaba99e7e85130f9a8bbea1299d8cb99d272b1d478dc19775": {
"query": "\n select\n state\n from cfd_states\n where cfd_id = $1\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
]
}
},
"b593977ea0af1bfe0a111ec908bab2149cf6d0cdee74e3321b5f2fa8154480e5": {
"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 ",
"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 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": {
"columns": [
{
@ -307,12 +277,12 @@
"type_info": "Int64"
},
{
"name": "term_secs: i64",
"name": "settlement_time_interval_secs: i64",
"ordinal": 10,
"type_info": "Int64"
},
{
"name": "term_nanos: i32",
"name": "settlement_time_interval_nanos: i32",
"ordinal": 11,
"type_info": "Int64"
},
@ -360,8 +330,26 @@
]
}
},
"b708b7116aa14093e0e21ab8f87e52928a70649a62250902054ef6526f1d6f66": {
"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 ",
"8cbe349911b35d8e79763d64b4f5813b4bd98f12e0bba5ada84d2cae8b08ef4f": {
"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": {
"columns": [
{
@ -415,12 +403,12 @@
"type_info": "Int64"
},
{
"name": "term_secs: i64",
"name": "settlement_time_interval_secs: i64",
"ordinal": 10,
"type_info": "Int64"
},
{
"name": "term_nanos: i32",
"name": "settlement_time_interval_nanos: i32",
"ordinal": 11,
"type_info": "Int64"
},
@ -433,10 +421,20 @@
"name": "oracle_event_id",
"ordinal": 13,
"type_info": "Text"
},
{
"name": "quantity_usd",
"ordinal": 14,
"type_info": "Text"
},
{
"name": "state",
"ordinal": 15,
"type_info": "Text"
}
],
"parameters": {
"Right": 1
"Right": 0
},
"nullable": [
false,
@ -452,6 +450,8 @@
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,
creation_timestamp_seconds,
creation_timestamp_nanoseconds,
term_seconds,
term_nanoseconds,
settlement_time_interval_seconds,
settlement_time_interval_nanoseconds,
origin,
oracle_event_id
) 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)?
.subsec_nanos() as i32,
)
.bind(&order.term.whole_seconds())
.bind(&order.term.subsec_nanoseconds())
.bind(&order.settlement_time_interval_hours.whole_seconds())
.bind(&order.settlement_time_interval_hours.subsec_nanoseconds())
.bind(&order.origin)
.bind(&order.oracle_event_id.to_string())
.execute(conn)
@ -84,8 +84,8 @@ pub async fn load_order_by_id(
liquidation_price,
creation_timestamp_seconds as "ts_secs: i64",
creation_timestamp_nanoseconds as "ts_nanos: i32",
term_seconds as "term_secs: i64",
term_nanoseconds as "term_nanos: i32",
settlement_time_interval_seconds as "settlement_time_interval_secs: i64",
settlement_time_interval_nanoseconds as "settlement_time_interval_nanos: i32",
origin as "origin: crate::model::cfd::Origin",
oracle_event_id
@ -107,7 +107,10 @@ pub async fn load_order_by_id(
leverage: row.leverage,
liquidation_price: Usd::new(Decimal::from_str(&row.liquidation_price)?),
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,
oracle_event_id: row.oracle_event_id.parse::<BitMexPriceEventId>()?,
})
@ -251,8 +254,8 @@ pub async fn load_cfd_by_order_id(
liquidation_price,
creation_timestamp_seconds as ts_secs,
creation_timestamp_nanoseconds as ts_nanos,
term_seconds as term_secs,
term_nanoseconds as term_nanos,
settlement_time_interval_seconds as settlement_time_interval_secs,
settlement_time_interval_nanoseconds as settlement_time_interval_nanos,
origin,
oracle_event_id
from orders
@ -294,8 +297,8 @@ pub async fn load_cfd_by_order_id(
ord.liquidation_price,
ord.ts_secs as "ts_secs: i64",
ord.ts_nanos as "ts_nanos: i32",
ord.term_secs as "term_secs: i64",
ord.term_nanos as "term_nanos: i32",
ord.settlement_time_interval_secs as "settlement_time_interval_secs: i64",
ord.settlement_time_interval_nanos as "settlement_time_interval_nanos: i32",
ord.origin as "origin: crate::model::cfd::Origin",
ord.oracle_event_id,
state.quantity_usd,
@ -321,7 +324,10 @@ pub async fn load_cfd_by_order_id(
leverage: row.leverage,
liquidation_price: Usd::new(Decimal::from_str(&row.liquidation_price)?),
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,
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,
creation_timestamp_seconds as ts_secs,
creation_timestamp_nanoseconds as ts_nanos,
term_seconds as term_secs,
term_nanoseconds as term_nanos,
settlement_time_interval_seconds as settlement_time_interval_secs,
settlement_time_interval_nanoseconds as settlement_time_interval_nanos,
origin,
oracle_event_id
from orders
@ -396,8 +402,8 @@ pub async fn load_all_cfds(conn: &mut PoolConnection<Sqlite>) -> anyhow::Result<
ord.liquidation_price,
ord.ts_secs as "ts_secs: i64",
ord.ts_nanos as "ts_nanos: i32",
ord.term_secs as "term_secs: i64",
ord.term_nanos as "term_nanos: i32",
ord.settlement_time_interval_secs as "settlement_time_interval_secs: i64",
ord.settlement_time_interval_nanos as "settlement_time_interval_nanos: i32",
ord.origin as "origin: crate::model::cfd::Origin",
ord.oracle_event_id,
state.quantity_usd,
@ -423,7 +429,10 @@ pub async fn load_all_cfds(conn: &mut PoolConnection<Sqlite>) -> anyhow::Result<
leverage: row.leverage,
liquidation_price: Usd::new(Decimal::from_str(&row.liquidation_price)?),
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,
oracle_event_id: row.oracle_event_id.parse::<BitMexPriceEventId>()?,
};
@ -460,8 +469,8 @@ pub async fn load_cfds_by_oracle_event_id(
liquidation_price,
creation_timestamp_seconds as ts_secs,
creation_timestamp_nanoseconds as ts_nanos,
term_seconds as term_secs,
term_nanoseconds as term_nanos,
settlement_time_interval_seconds as settlement_time_interval_secs,
settlement_time_interval_nanoseconds as settlement_time_interval_nanos,
origin,
oracle_event_id
from orders
@ -503,8 +512,8 @@ pub async fn load_cfds_by_oracle_event_id(
ord.liquidation_price,
ord.ts_secs as "ts_secs: i64",
ord.ts_nanos as "ts_nanos: i32",
ord.term_secs as "term_secs: i64",
ord.term_nanos as "term_nanos: i32",
ord.settlement_time_interval_secs as "settlement_time_interval_secs: i64",
ord.settlement_time_interval_nanos as "settlement_time_interval_nanos: i32",
ord.origin as "origin: crate::model::cfd::Origin",
ord.oracle_event_id,
state.quantity_usd,
@ -533,7 +542,10 @@ pub async fn load_cfds_by_oracle_event_id(
leverage: row.leverage,
liquidation_price: Usd::new(Decimal::from_str(&row.liquidation_price)?),
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,
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<FromTaker>>,
) -> T,
term: time::Duration,
settlement_time_interval_hours: time::Duration,
) -> Result<Self>
where
F: Future<Output = Result<M>>,
@ -100,7 +100,7 @@ where
let cfd_actor_addr = maker_cfd::Actor::new(
db,
wallet_addr,
term,
settlement_time_interval_hours,
oracle_pk,
cfd_feed_sender,
order_feed_sender,

11
daemon/src/maker.rs

@ -51,9 +51,9 @@ struct Opts {
#[clap(short, long)]
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")]
term: u8,
settlement_time_interval_hours: u8,
#[clap(subcommand)]
network: Network,
@ -190,7 +190,8 @@ async fn main() -> Result<()> {
housekeeping::transition_non_continue_cfds_to_setup_failed(&mut conn).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 {
cfd_actor_addr,
cfd_feed_receiver,
@ -201,7 +202,7 @@ async fn main() -> Result<()> {
db.clone(),
wallet.clone(),
oracle,
|cfds, channel| oracle::Actor::new(cfds, channel, term),
|cfds, channel| oracle::Actor::new(cfds, channel, settlement_time_interval_hours),
{
|channel, cfds| {
let electrum = opts.network.electrum().to_string();
@ -209,7 +210,7 @@ async fn main() -> Result<()> {
}
},
|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?;

18
daemon/src/maker_cfd.rs

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

24
daemon/src/model/cfd.rs

@ -114,7 +114,7 @@ pub struct Order {
pub creation_timestamp: SystemTime,
/// The duration that will be used for calculating the settlement timestamp
pub term: Duration,
pub settlement_time_interval_hours: Duration,
pub origin: Origin,
@ -131,7 +131,7 @@ impl Order {
max_quantity: Usd,
origin: Origin,
oracle_event_id: BitMexPriceEventId,
term: Duration,
settlement_time_interval_hours: Duration,
) -> Result<Self> {
let leverage = Leverage(2);
let maintenance_margin_rate = dec!(0.005);
@ -148,7 +148,7 @@ impl Order {
liquidation_price,
position: Position::Sell,
creation_timestamp: SystemTime::now(),
term,
settlement_time_interval_hours,
origin,
oracle_event_id,
})
@ -682,25 +682,29 @@ impl Cfd {
}
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 {
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
/// 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 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
/// `1.5` times the settlement_time_interval_hours 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.settlement_time_interval_hours` 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
/// term to get his funds back.
/// of the cfd settlement_time_interval_hours. In this case the users has to wait for another
/// `1.5` times of the settlement_time_interval_hours to get his funds back.
const REFUND_THRESHOLD: f32 = 1.5;
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>)>,
pending_attestations: HashSet<BitMexPriceEventId>,
attestation_channel: Box<dyn StrongMessageChannel<Attestation>>,
term: Duration,
announcement_lookahead: Duration,
}
pub struct Sync;
@ -62,7 +62,7 @@ impl Actor {
pub fn new(
cfds: Vec<Cfd>,
attestation_channel: Box<dyn StrongMessageChannel<Attestation>>,
term: Duration,
announcement_lookahead: Duration,
) -> Self {
let mut pending_attestations = HashSet::new();
@ -96,13 +96,17 @@ impl Actor {
announcements: HashMap::new(),
pending_attestations,
attestation_channel,
term,
announcement_lookahead,
}
}
fn ensure_having_announcements(&mut self, term: Duration, ctx: &mut xtra::Context<Self>) {
// we want inclusive the term length hence +1
for hour in 1..term.whole_hours() + 1 {
fn ensure_having_announcements(
&mut self,
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(
time::OffsetDateTime::now_utc() + Duration::hours(hour)
));
@ -235,7 +239,7 @@ impl Actor {
}
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);
}
}

4
daemon/src/taker.rs

@ -27,7 +27,7 @@ use xtra::Actor;
mod routes_taker;
pub const TERM: time::Duration = time::Duration::hours(24);
pub const ANNOUNCEMENT_LOOKAHEAD: time::Duration = time::Duration::hours(24);
#[derive(Clap)]
struct Opts {
@ -181,7 +181,7 @@ async fn main() -> Result<()> {
oracle,
send_to_maker,
read_from_maker,
|cfds, channel| oracle::Actor::new(cfds, channel, TERM),
|cfds, channel| oracle::Actor::new(cfds, channel, ANNOUNCEMENT_LOOKAHEAD),
{
|channel, cfds| {
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 creation_timestamp: u64,
pub term_in_secs: u64,
pub settlement_time_interval_in_secs: u64,
}
pub trait ToSseEvent {
@ -290,11 +290,11 @@ impl ToSseEvent for Option<model::cfd::Order> {
.duration_since(UNIX_EPOCH)
.expect("timestamp to be convertible to duration since epoch")
.as_secs(),
term_in_secs: order
.term
settlement_time_interval_in_secs: order
.settlement_time_interval_hours
.whole_seconds()
.try_into()
.expect("term is always positive number"),
.expect("settlement_time_interval_hours is always positive number"),
});
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 term = time::Duration::hours(24);
let settlement_time_interval_hours = time::Duration::hours(24);
let maker = daemon::MakerActorSystem::new(
db,
@ -174,7 +174,7 @@ impl Maker {
|_, _| Oracle,
|_, _| async { Ok(Monitor) },
|channel0, channel1| maker_inc_connections::Actor::new(channel0, channel1),
term,
settlement_time_interval_hours,
)
.await
.unwrap();

2
frontend/src/components/Types.tsx

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

Loading…
Cancel
Save