Skip to main content

iota_types/
event.rs

1// Copyright (c) Mysten Labs, Inc.
2// Modifications Copyright (c) 2024 IOTA Stiftung
3// SPDX-License-Identifier: Apache-2.0
4
5use std::str::FromStr;
6
7use anyhow::ensure;
8use iota_sdk_move_types::iota_system::iota_system_state_inner::{
9    SystemEpochInfoEventV1, SystemEpochInfoEventV2,
10};
11use iota_sdk_types::{Event, TransactionDigest};
12use serde::{Deserialize, Serialize};
13use serde_json::Value;
14use serde_with::serde_as;
15
16use crate::iota_serde::{BigInt, Readable};
17
18/// A universal IOTA event type encapsulating different types of events
19#[derive(Debug, Clone, Serialize, Deserialize)]
20pub struct EventEnvelope {
21    /// UTC timestamp in milliseconds since epoch (1/1/1970)
22    pub timestamp: u64,
23    /// Transaction digest of associated transaction
24    pub tx_digest: TransactionDigest,
25    /// Consecutive per-tx counter assigned to this event.
26    pub event_num: u64,
27    /// Specific event type
28    pub event: Event,
29    /// Move event's json value
30    pub parsed_json: Value,
31}
32/// Unique ID of an IOTA Event, the ID is a combination of transaction digest
33/// and event seq number.
34#[serde_as]
35#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Hash)]
36#[serde(rename_all = "camelCase")]
37pub struct EventID {
38    pub tx_digest: TransactionDigest,
39    #[serde_as(as = "Readable<BigInt<u64>, _>")]
40    pub event_seq: u64,
41}
42
43impl From<(TransactionDigest, u64)> for EventID {
44    fn from((tx_digest_num, event_seq_number): (TransactionDigest, u64)) -> Self {
45        Self {
46            tx_digest: tx_digest_num as TransactionDigest,
47            event_seq: event_seq_number,
48        }
49    }
50}
51
52impl From<EventID> for String {
53    fn from(id: EventID) -> Self {
54        format!("{:?}:{}", id.tx_digest, id.event_seq)
55    }
56}
57
58impl TryFrom<String> for EventID {
59    type Error = anyhow::Error;
60
61    fn try_from(value: String) -> Result<Self, Self::Error> {
62        let values = value.split(':').collect::<Vec<_>>();
63        ensure!(values.len() == 2, "Malformed EventID : {value}");
64        Ok((
65            TransactionDigest::from_str(values[0])?,
66            u64::from_str(values[1])?,
67        )
68            .into())
69    }
70}
71
72impl EventEnvelope {
73    pub fn new(
74        timestamp: u64,
75        tx_digest: TransactionDigest,
76        event_num: u64,
77        event: Event,
78        move_struct_json_value: Value,
79    ) -> Self {
80        Self {
81            timestamp,
82            tx_digest,
83            event_num,
84            event,
85            parsed_json: move_struct_json_value,
86        }
87    }
88}
89
90#[derive(Deserialize)]
91pub enum SystemEpochInfoEvent {
92    V1(SystemEpochInfoEventV1),
93    V2(SystemEpochInfoEventV2),
94}
95
96impl SystemEpochInfoEvent {
97    pub fn supply_change(&self) -> i64 {
98        match self {
99            SystemEpochInfoEvent::V1(event) => {
100                event.minted_tokens_amount as i64 - event.burnt_tokens_amount as i64
101            }
102            SystemEpochInfoEvent::V2(event) => {
103                event.minted_tokens_amount as i64 - event.burnt_tokens_amount as i64
104            }
105        }
106    }
107}
108
109impl From<Event> for SystemEpochInfoEvent {
110    fn from(event: Event) -> Self {
111        if event.is_system_epoch_info_event_v2() {
112            SystemEpochInfoEvent::V2(
113                bcs::from_bytes::<SystemEpochInfoEventV2>(&event.contents)
114                    .expect("event deserialization should succeed as type was pre-validated"),
115            )
116        } else {
117            SystemEpochInfoEvent::V1(
118                bcs::from_bytes::<SystemEpochInfoEventV1>(&event.contents)
119                    .expect("event deserialization should succeed as type was pre-validated"),
120            )
121        }
122    }
123}