use crate::types::{AccountAddress, HashValue};
use serde::{Deserialize, Serialize};
use std::fmt;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct EventKey {
pub creation_number: u64,
pub account_address: AccountAddress,
}
impl EventKey {
pub fn new(creation_number: u64, account_address: AccountAddress) -> Self {
Self {
creation_number,
account_address,
}
}
}
impl fmt::Display for EventKey {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}:{}", self.account_address, self.creation_number)
}
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct EventHandle {
pub counter: u64,
pub guid: EventGuid,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct EventGuid {
pub creation_number: u64,
pub account_address: AccountAddress,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct Event {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub guid: Option<EventGuid>,
pub sequence_number: u64,
#[serde(rename = "type")]
pub typ: String,
pub data: serde_json::Value,
}
impl Event {
pub fn event_type(&self) -> &str {
&self.typ
}
pub fn data_as<T: for<'de> Deserialize<'de>>(&self) -> Result<T, serde_json::Error> {
serde_json::from_value(self.data.clone())
}
}
#[allow(dead_code)] #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct VersionedEvent {
pub version: u64,
#[serde(flatten)]
pub event: Event,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub transaction_hash: Option<HashValue>,
}
#[allow(dead_code)] pub mod framework {
pub const DEPOSIT_EVENT: &str = "0x1::coin::DepositEvent";
pub const WITHDRAW_EVENT: &str = "0x1::coin::WithdrawEvent";
pub const ACCOUNT_CREATE_EVENT: &str = "0x1::account::CreateAccountEvent";
pub const KEY_ROTATION_EVENT: &str = "0x1::account::KeyRotationEvent";
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_event_key() {
let key = EventKey::new(42, AccountAddress::ONE);
assert_eq!(key.creation_number, 42);
assert_eq!(key.account_address, AccountAddress::ONE);
}
#[test]
fn test_event_key_display() {
let key = EventKey::new(42, AccountAddress::ONE);
let display = format!("{key}");
assert!(display.contains("42"));
assert!(display.contains(':'));
}
#[test]
fn test_event_deserialization() {
let json = r#"{
"sequence_number": 1,
"type": "0x1::coin::DepositEvent",
"data": {"amount": "1000"}
}"#;
let event: Event = serde_json::from_str(json).unwrap();
assert_eq!(event.sequence_number, 1);
assert_eq!(event.typ, "0x1::coin::DepositEvent");
}
#[test]
fn test_event_type() {
let json = r#"{
"sequence_number": 1,
"type": "0x1::coin::DepositEvent",
"data": {"amount": "1000"}
}"#;
let event: Event = serde_json::from_str(json).unwrap();
assert_eq!(event.event_type(), "0x1::coin::DepositEvent");
}
#[test]
fn test_event_data_as() {
#[derive(serde::Deserialize, Debug, PartialEq)]
struct DepositEvent {
amount: String,
}
let json = r#"{
"sequence_number": 1,
"type": "0x1::coin::DepositEvent",
"data": {"amount": "1000"}
}"#;
let event: Event = serde_json::from_str(json).unwrap();
let data: DepositEvent = event.data_as().unwrap();
assert_eq!(data.amount, "1000");
}
#[test]
fn test_event_handle_deserialization() {
let json = r#"{
"counter": 100,
"guid": {
"creation_number": 5,
"account_address": "0x1"
}
}"#;
let handle: EventHandle = serde_json::from_str(json).unwrap();
assert_eq!(handle.counter, 100);
assert_eq!(handle.guid.creation_number, 5);
}
#[test]
fn test_event_guid() {
let guid = EventGuid {
creation_number: 10,
account_address: AccountAddress::ONE,
};
assert_eq!(guid.creation_number, 10);
assert_eq!(guid.account_address, AccountAddress::ONE);
}
#[test]
fn test_versioned_event_deserialization() {
let json = r#"{
"version": 12345,
"sequence_number": 1,
"type": "0x1::coin::DepositEvent",
"data": {"amount": "1000"}
}"#;
let event: VersionedEvent = serde_json::from_str(json).unwrap();
assert_eq!(event.version, 12345);
assert_eq!(event.event.sequence_number, 1);
}
#[test]
fn test_framework_event_constants() {
assert_eq!(framework::DEPOSIT_EVENT, "0x1::coin::DepositEvent");
assert_eq!(framework::WITHDRAW_EVENT, "0x1::coin::WithdrawEvent");
assert_eq!(
framework::ACCOUNT_CREATE_EVENT,
"0x1::account::CreateAccountEvent"
);
assert_eq!(
framework::KEY_ROTATION_EVENT,
"0x1::account::KeyRotationEvent"
);
}
}