-
Notifications
You must be signed in to change notification settings - Fork 82
/
total_surplus.rs
75 lines (71 loc) · 2.91 KB
/
total_surplus.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
use {
anyhow::Result,
database::{byte_array::ByteArray, Address},
primitive_types::{H160, U256},
sqlx::PgConnection,
};
/// Computes a user's total surplus received (price improvement over limit price
/// and **NOT** quoted price) since march 2023.
async fn fetch_total_surplus(ex: &mut PgConnection, user: &Address) -> Result<f64, sqlx::Error> {
const TOTAL_SURPLUS_QUERY: &str = r#"
WITH regular_orders AS (
SELECT ARRAY_AGG(uid) AS ids FROM orders WHERE owner = $1
),
onchain_orders AS (
SELECT ARRAY_AGG(uid) AS ids FROM onchain_placed_orders WHERE sender = $1
),
trade_components AS (
SELECT
CASE kind
-- so much was actually bought
WHEN 'sell' THEN t.buy_amount
-- so much was actually converted to buy tokens
WHEN 'buy' THEN t.sell_amount - t.fee_amount
END AS trade_amount,
CASE kind
-- so much had to be bought at least (given exeucted amount and limit price)
WHEN 'sell' THEN (t.sell_amount - t.fee_amount) * o.buy_amount / o.sell_amount
-- so much could be converted to buy_token at most (given executed amount and limit price)
WHEN 'buy' THEN t.buy_amount * o.sell_amount / o.buy_amount
END AS limit_amount,
o.kind,
CASE kind
WHEN 'sell' THEN (SELECT price FROM auction_prices ap WHERE ap.token = o.buy_token AND ap.auction_id = oe.auction_id)
WHEN 'buy' THEN (SELECT price FROM auction_prices ap WHERE ap.token = o.sell_token AND ap.auction_id = oe.auction_id)
END AS surplus_token_native_price
FROM orders o
JOIN trades t ON o.uid = t.order_uid
JOIN order_execution oe ON o.uid = oe.order_uid
-- use this weird construction instead of `where owner=address or sender=address` to help postgres make efficient use of indices
WHERE uid = ANY(ARRAY_CAT((SELECT ids FROM regular_orders), (SELECT ids FROM onchain_orders)))
),
trade_surplus AS (
SELECT
CASE kind
-- amounts refer to tokens bought; more is better
WHEN 'sell' THEN (trade_amount - limit_amount) * surplus_token_native_price
-- amounts refer to tokens sold; less is better
WHEN 'buy' THEN (limit_amount - trade_amount) * surplus_token_native_price
END / POWER(10, 18) AS surplus_in_wei
FROM trade_components
)
SELECT
COALESCE(SUM(surplus_in_wei), 0) AS total_surplus_in_wei
FROM trade_surplus
"#;
sqlx::query_scalar(TOTAL_SURPLUS_QUERY)
.bind(user)
.fetch_one(ex)
.await
}
impl super::Postgres {
pub async fn total_surplus(&self, user: &H160) -> Result<U256> {
let _timer = super::Metrics::get()
.database_queries
.with_label_values(&["get_total_surplus"])
.start_timer();
let mut ex = self.pool.acquire().await?;
let surplus = fetch_total_surplus(&mut ex, &ByteArray(user.0)).await?;
Ok(U256::from_f64_lossy(surplus))
}
}