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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
//! On-chain events (`sol_log_data` via Steel `event!` / `.log()`).
//!
//! ## Indexer contract
//!
//! The off-chain indexer **must subscribe to these events** to reconstruct daily and weekly
//! leaderboard state. Accounts alone are insufficient for daily rank snapshots because the on-chain
//! Ledger only maintains rolling weekly aggregates, not per-day history.
//!
//! ### Daily leaderboard reconstruction
//!
//! For each UTC day the indexer:
//! 1. Groups `WinRecorded` events by `(player, UTC_day(period))` → daily wins + daily best streak.
//! 2. Groups `BetRecorded` events by `(player, UTC_day(period))` → daily bet count.
//! 3. Excludes periods matching any `MarketVoided` event from accuracy calculations.
//! 4. Uses `StreakBroken` events to confirm streak resets (optional — can also derive from missing
//! consecutive `WinRecorded` run).
//! 5. At UTC midnight, snapshots rank order for each player → feeds into weekly scoring.
//!
//! The `period` field maps to a UTC day via the `Market::open_ts` / `Market::close_ts` stored
//! on the Market PDA (288 periods per day for 5-minute rounds).
//!
//! ### Weekly score inputs (all on-chain, readable from events or Ledger state)
//!
//! | Component | Weight | Source |
//! |---|---|---|
//! | Best streak of the week | 50% | `WinRecorded.win_streak` peak per week |
//! | Daily leaderboard placement | 30% | Off-chain daily rank snapshots |
//! | Total correct calls | 10% | `WinRecorded.total_wins` at week end |
//! | Accuracy rate | 10% | `total_wins / total_bets` (min ~50 bets enforced off-chain) |
use *;
/// Emitted after successful [`Initialize`](crate::instruction::Initialize).
/// Emitted by `ExecutorTreasury` DISTRIBUTE when a win is confirmed for a player.
///
/// Contains full stat snapshot at the moment of win for accurate daily/weekly indexing.
/// Emitted by `PlaceBet` when a player's streak is broken (previous period settled as a loss).
///
/// The indexer uses this to confirm streak resets and close the daily streak window.
/// Emitted by `PlaceBet` when tickets are actually debited (both commit and live windows).
///
/// Enables accurate daily bet counting for accuracy-rate scoring.
/// Void-refunded bets are NOT un-counted here; the indexer excludes voided periods
/// from accuracy calculations using [`MarketVoided`] events instead.
/// Emitted by `AdminVoidMarket` when a market is voided.
///
/// The indexer must exclude this `(series_id, period)` from accuracy calculations
/// and not count any wins/losses for it in the leaderboard.
/// Emitted by `AdminRefundVoidPosition` for each refunded position.
///
/// Lets the indexer track that the player's ticket was returned and the bet should be excluded.
event!;
event!;
event!;
event!;
event!;
event!;