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}