Skip to main content

streak_api/
settlement.rs

1//! Price-chain settlement helper for `AdminInstantSettlement`.
2//!
3//! Reads the open reference from `Treasury::last_close_*`, reads the Pyth close price,
4//! resolves UP/DOWN, emits `PeriodSettled`, and writes the close price back to Treasury.
5//! All market pool math and USDC distribution happen off-chain.
6
7use steel::*;
8
9use crate::consts::PYTH_BTC_USD_FEED_ID;
10use crate::error::StreakError;
11use crate::event::PeriodSettled;
12use crate::pyth::{load_fresh_price, outcome_from_open_close, Price};
13use crate::state::Treasury;
14
15pub struct SettlementResult {
16    pub outcome: u8,
17    pub close_px: Price,
18    pub open_px: Price,
19}
20
21/// Read open from Treasury, read close from Pyth, return outcome + both prices.
22/// Returns `Err(GenesisNotSet)` if the price chain has not been seeded.
23pub fn resolve_settlement(
24    treasury: &Treasury,
25    pyth_price_feed_info: &AccountInfo<'_>,
26    unix_timestamp: i64,
27) -> Result<SettlementResult, ProgramError> {
28    if treasury.last_close_price == 0 {
29        return Err(StreakError::GenesisNotSet.into());
30    }
31
32    let open_px = Price {
33        price: treasury.last_close_price,
34        conf: 0,
35        expo: treasury.last_close_expo,
36        publish_time: treasury.last_close_publish_time,
37    };
38
39    let close_px = load_fresh_price(pyth_price_feed_info, &PYTH_BTC_USD_FEED_ID, unix_timestamp)?;
40    let outcome = outcome_from_open_close(open_px, close_px)?;
41
42    Ok(SettlementResult { outcome, close_px, open_px })
43}
44
45/// Write close price back to Treasury and emit the `PeriodSettled` event.
46pub fn commit_settlement(
47    treasury: &mut Treasury,
48    result: SettlementResult,
49    series_id: u16,
50    period: u64,
51) {
52    PeriodSettled {
53        series_id,
54        outcome: result.outcome,
55        _pad: [0; 5],
56        period,
57        close_price: result.close_px.price,
58        close_expo: result.close_px.expo,
59        _pad2: [0; 4],
60        close_publish_time: result.close_px.publish_time,
61        open_price: result.open_px.price,
62        open_expo: result.open_px.expo,
63        _pad3: [0; 4],
64    }
65    .log();
66
67    treasury.last_close_price = result.close_px.price;
68    treasury.last_close_expo = result.close_px.expo;
69    treasury.last_close_publish_time = result.close_px.publish_time;
70}
71
72/// UP outcome constant (close > open).
73pub const SIDE_UP: u8 = 0;
74/// DOWN outcome constant (close <= open, including ties).
75pub const SIDE_DOWN: u8 = 1;