1use std::str::FromStr;
5
6use anyhow::ensure;
7use fastcrypto::hash::Blake2b256;
8use fastcrypto::hash::HashFunction;
9use move_core_types::account_address::AccountAddress;
10use move_core_types::annotated_value::MoveDatatypeLayout;
11use move_core_types::annotated_value::MoveValue;
12use move_core_types::ident_str;
13use move_core_types::identifier::IdentStr;
14use move_core_types::identifier::Identifier;
15use move_core_types::language_storage::StructTag;
16use schemars::JsonSchema;
17use serde::{Deserialize, Serialize};
18use serde_json::Value;
19use serde_with::Bytes;
20use serde_with::serde_as;
21
22use crate::SUI_SYSTEM_ADDRESS;
23use crate::base_types::{ObjectID, SuiAddress, TransactionDigest};
24use crate::digests::Digest;
25use crate::error::SuiErrorKind;
26use crate::error::SuiResult;
27use crate::object::bounded_visitor::BoundedVisitor;
28use crate::sui_serde::BigInt;
29use crate::sui_serde::Readable;
30
31#[derive(Debug, Clone, Serialize, Deserialize)]
33pub struct EventEnvelope {
34    pub timestamp: u64,
36    pub tx_digest: TransactionDigest,
38    pub event_num: u64,
40    pub event: Event,
42    pub parsed_json: Value,
44}
45#[serde_as]
47#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema, Hash)]
48#[serde(rename_all = "camelCase")]
49pub struct EventID {
50    pub tx_digest: TransactionDigest,
51    #[schemars(with = "BigInt<u64>")]
52    #[serde_as(as = "Readable<BigInt<u64>, _>")]
53    pub event_seq: u64,
54}
55
56impl From<(TransactionDigest, u64)> for EventID {
57    fn from((tx_digest_num, event_seq_number): (TransactionDigest, u64)) -> Self {
58        Self {
59            tx_digest: tx_digest_num as TransactionDigest,
60            event_seq: event_seq_number,
61        }
62    }
63}
64
65impl From<EventID> for String {
66    fn from(id: EventID) -> Self {
67        format!("{:?}:{}", id.tx_digest, id.event_seq)
68    }
69}
70
71impl TryFrom<String> for EventID {
72    type Error = anyhow::Error;
73
74    fn try_from(value: String) -> Result<Self, Self::Error> {
75        let values = value.split(':').collect::<Vec<_>>();
76        ensure!(values.len() == 2, "Malformed EventID : {value}");
77        Ok((
78            TransactionDigest::from_str(values[0])?,
79            u64::from_str(values[1])?,
80        )
81            .into())
82    }
83}
84
85impl EventEnvelope {
86    pub fn new(
87        timestamp: u64,
88        tx_digest: TransactionDigest,
89        event_num: u64,
90        event: Event,
91        move_struct_json_value: Value,
92    ) -> Self {
93        Self {
94            timestamp,
95            tx_digest,
96            event_num,
97            event,
98            parsed_json: move_struct_json_value,
99        }
100    }
101}
102
103#[serde_as]
105#[derive(PartialEq, Eq, Debug, Clone, Deserialize, Serialize)]
106pub struct Event {
107    pub package_id: ObjectID,
108    pub transaction_module: Identifier,
109    pub sender: SuiAddress,
110    pub type_: StructTag,
111    #[serde_as(as = "Bytes")]
112    pub contents: Vec<u8>,
113}
114
115impl Event {
116    pub fn new(
117        package_id: &AccountAddress,
118        module: &IdentStr,
119        sender: SuiAddress,
120        type_: StructTag,
121        contents: Vec<u8>,
122    ) -> Self {
123        Self {
124            package_id: ObjectID::from(*package_id),
125            transaction_module: Identifier::from(module),
126            sender,
127            type_,
128            contents,
129        }
130    }
131    pub fn move_event_to_move_value(
132        contents: &[u8],
133        layout: MoveDatatypeLayout,
134    ) -> SuiResult<MoveValue> {
135        BoundedVisitor::deserialize_value(contents, &layout.into_layout()).map_err(|e| {
136            SuiErrorKind::ObjectSerializationError {
137                error: e.to_string(),
138            }
139            .into()
140        })
141    }
142
143    pub fn is_system_epoch_info_event(&self) -> bool {
144        self.type_.address == SUI_SYSTEM_ADDRESS
145            && self.type_.module.as_ident_str() == ident_str!("sui_system_state_inner")
146            && self.type_.name.as_ident_str() == ident_str!("SystemEpochInfoEvent")
147    }
148
149    pub fn digest(&self) -> Digest {
151        let mut h = Blake2b256::new();
152        bcs::serialize_into(&mut h, &self).unwrap();
153        let digest = h.finalize();
154        Digest::new(digest.digest)
155    }
156}
157
158impl Event {
159    pub fn random_for_testing() -> Self {
160        Self {
161            package_id: ObjectID::random(),
162            transaction_module: Identifier::new("test").unwrap(),
163            sender: AccountAddress::random().into(),
164            type_: StructTag {
165                address: AccountAddress::random(),
166                module: Identifier::new("test").unwrap(),
167                name: Identifier::new("test").unwrap(),
168                type_params: vec![],
169            },
170            contents: vec![],
171        }
172    }
173}
174
175#[derive(Serialize, Deserialize, Default)]
177pub struct SystemEpochInfoEvent {
178    pub epoch: u64,
179    pub protocol_version: u64,
180    pub reference_gas_price: u64,
181    pub total_stake: u64,
182    pub storage_fund_reinvestment: u64,
183    pub storage_charge: u64,
184    pub storage_rebate: u64,
185    pub storage_fund_balance: u64,
186    pub stake_subsidy_amount: u64,
187    pub total_gas_fees: u64,
188    pub total_stake_rewards_distributed: u64,
189    pub leftover_storage_fund_inflow: u64,
190}