Skip to main content

aptos_sdk/types/
events.rs

1//! Event types.
2//!
3//! Events are emitted by Move modules and can be used to track
4//! on-chain activity without reading full transaction data.
5
6use crate::types::{AccountAddress, HashValue};
7use serde::{Deserialize, Serialize};
8use std::fmt;
9
10/// A unique identifier for an event stream.
11///
12/// Event keys are composed of a creation number and an address.
13#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
14pub struct EventKey {
15    /// The creation number (unique within the account).
16    pub creation_number: u64,
17    /// The account address that owns this event stream.
18    pub account_address: AccountAddress,
19}
20
21impl EventKey {
22    /// Creates a new event key.
23    pub fn new(creation_number: u64, account_address: AccountAddress) -> Self {
24        Self {
25            creation_number,
26            account_address,
27        }
28    }
29}
30
31impl fmt::Display for EventKey {
32    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
33        write!(f, "{}:{}", self.account_address, self.creation_number)
34    }
35}
36
37/// A handle to an event stream stored on chain.
38#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
39pub struct EventHandle {
40    /// The number of events that have been emitted to this handle.
41    pub counter: u64,
42    /// The globally unique ID for this event stream.
43    pub guid: EventGuid,
44}
45
46/// A globally unique identifier for an event stream.
47#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
48pub struct EventGuid {
49    /// The creation number.
50    pub creation_number: u64,
51    /// The account address.
52    pub account_address: AccountAddress,
53}
54
55/// An event emitted during transaction execution.
56#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
57pub struct Event {
58    /// The globally unique identifier for this event.
59    #[serde(default, skip_serializing_if = "Option::is_none")]
60    pub guid: Option<EventGuid>,
61    /// The sequence number of this event within its stream.
62    pub sequence_number: u64,
63    /// The type of the event data.
64    #[serde(rename = "type")]
65    pub typ: String,
66    /// The event data as JSON.
67    pub data: serde_json::Value,
68}
69
70impl Event {
71    /// Returns the event type as a string.
72    pub fn event_type(&self) -> &str {
73        &self.typ
74    }
75
76    /// Tries to deserialize the event data into a specific type.
77    ///
78    /// # Errors
79    ///
80    /// Returns an error if the event data cannot be deserialized into the requested type.
81    pub fn data_as<T: for<'de> Deserialize<'de>>(&self) -> Result<T, serde_json::Error> {
82        serde_json::from_value(self.data.clone())
83    }
84}
85
86/// A versioned event from the indexer (includes transaction context).
87#[allow(dead_code)] // Public API for users
88#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
89pub struct VersionedEvent {
90    /// The transaction version that emitted this event.
91    pub version: u64,
92    /// The event itself.
93    #[serde(flatten)]
94    pub event: Event,
95    /// The transaction hash (optional, from indexer).
96    #[serde(default, skip_serializing_if = "Option::is_none")]
97    pub transaction_hash: Option<HashValue>,
98}
99
100/// Common event types in the Aptos framework.
101#[allow(dead_code)] // Public API constants for users
102pub mod framework {
103    /// Event type for coin deposits.
104    pub const DEPOSIT_EVENT: &str = "0x1::coin::DepositEvent";
105    /// Event type for coin withdrawals.
106    pub const WITHDRAW_EVENT: &str = "0x1::coin::WithdrawEvent";
107    /// Event type for account creation.
108    pub const ACCOUNT_CREATE_EVENT: &str = "0x1::account::CreateAccountEvent";
109    /// Event type for key rotation.
110    pub const KEY_ROTATION_EVENT: &str = "0x1::account::KeyRotationEvent";
111}
112
113#[cfg(test)]
114mod tests {
115    use super::*;
116
117    #[test]
118    fn test_event_key() {
119        let key = EventKey::new(42, AccountAddress::ONE);
120        assert_eq!(key.creation_number, 42);
121        assert_eq!(key.account_address, AccountAddress::ONE);
122    }
123
124    #[test]
125    fn test_event_key_display() {
126        let key = EventKey::new(42, AccountAddress::ONE);
127        let display = format!("{key}");
128        assert!(display.contains("42"));
129        assert!(display.contains(':'));
130    }
131
132    #[test]
133    fn test_event_deserialization() {
134        let json = r#"{
135            "sequence_number": 1,
136            "type": "0x1::coin::DepositEvent",
137            "data": {"amount": "1000"}
138        }"#;
139
140        let event: Event = serde_json::from_str(json).unwrap();
141        assert_eq!(event.sequence_number, 1);
142        assert_eq!(event.typ, "0x1::coin::DepositEvent");
143    }
144
145    #[test]
146    fn test_event_type() {
147        let json = r#"{
148            "sequence_number": 1,
149            "type": "0x1::coin::DepositEvent",
150            "data": {"amount": "1000"}
151        }"#;
152
153        let event: Event = serde_json::from_str(json).unwrap();
154        assert_eq!(event.event_type(), "0x1::coin::DepositEvent");
155    }
156
157    #[test]
158    fn test_event_data_as() {
159        #[derive(serde::Deserialize, Debug, PartialEq)]
160        struct DepositEvent {
161            amount: String,
162        }
163
164        let json = r#"{
165            "sequence_number": 1,
166            "type": "0x1::coin::DepositEvent",
167            "data": {"amount": "1000"}
168        }"#;
169
170        let event: Event = serde_json::from_str(json).unwrap();
171        let data: DepositEvent = event.data_as().unwrap();
172        assert_eq!(data.amount, "1000");
173    }
174
175    #[test]
176    fn test_event_handle_deserialization() {
177        let json = r#"{
178            "counter": 100,
179            "guid": {
180                "creation_number": 5,
181                "account_address": "0x1"
182            }
183        }"#;
184
185        let handle: EventHandle = serde_json::from_str(json).unwrap();
186        assert_eq!(handle.counter, 100);
187        assert_eq!(handle.guid.creation_number, 5);
188    }
189
190    #[test]
191    fn test_event_guid() {
192        let guid = EventGuid {
193            creation_number: 10,
194            account_address: AccountAddress::ONE,
195        };
196        assert_eq!(guid.creation_number, 10);
197        assert_eq!(guid.account_address, AccountAddress::ONE);
198    }
199
200    #[test]
201    fn test_versioned_event_deserialization() {
202        let json = r#"{
203            "version": 12345,
204            "sequence_number": 1,
205            "type": "0x1::coin::DepositEvent",
206            "data": {"amount": "1000"}
207        }"#;
208
209        let event: VersionedEvent = serde_json::from_str(json).unwrap();
210        assert_eq!(event.version, 12345);
211        assert_eq!(event.event.sequence_number, 1);
212    }
213
214    #[test]
215    fn test_framework_event_constants() {
216        assert_eq!(framework::DEPOSIT_EVENT, "0x1::coin::DepositEvent");
217        assert_eq!(framework::WITHDRAW_EVENT, "0x1::coin::WithdrawEvent");
218        assert_eq!(
219            framework::ACCOUNT_CREATE_EVENT,
220            "0x1::account::CreateAccountEvent"
221        );
222        assert_eq!(
223            framework::KEY_ROTATION_EVENT,
224            "0x1::account::KeyRotationEvent"
225        );
226    }
227}