From 69ec6fb9dfdfdaa97a7800948d0dd9fd51823724 Mon Sep 17 00:00:00 2001 From: Jacob Lindahl Date: Wed, 8 May 2024 15:04:06 +0900 Subject: [PATCH] feat: deserializable events, fixes #147 --- macros/src/standard/nep297.rs | 8 +-- src/owner.rs | 2 +- src/pause.rs | 2 +- src/standard/nep141/event.rs | 2 +- src/standard/nep171/event.rs | 2 +- src/standard/nep297.rs | 105 ++++++++++++++++++++++++++++------ 6 files changed, 95 insertions(+), 26 deletions(-) diff --git a/macros/src/standard/nep297.rs b/macros/src/standard/nep297.rs index 2b260bc..dd1997a 100644 --- a/macros/src/standard/nep297.rs +++ b/macros/src/standard/nep297.rs @@ -153,11 +153,11 @@ pub fn expand(meta: Nep297Meta) -> Result { impl #imp #me::standard::nep297::ToEventLog for #ident #ty #wher { type Data = #ident #ty; - fn to_event_log<'__el>(&'__el self) -> #me::standard::nep297::EventLog<&'__el Self> { + fn to_event_log<'__el>(&'__el self) -> #me::standard::nep297::EventLog<&'__el Self::Data> { #me::standard::nep297::EventLog { - standard: #standard, - version: #version, - event: #event, + standard: #standard.into(), + version: #version.into(), + event: #event.into(), data: self, } } diff --git a/src/owner.rs b/src/owner.rs index 2bee8c5..8a1735e 100644 --- a/src/owner.rs +++ b/src/owner.rs @@ -49,7 +49,7 @@ const NO_PROPOSED_OWNER_FAIL_MESSAGE: &str = "No proposed owner"; crate = "crate", macros = "near_sdk_contract_tools_macros" )] -#[derive(Debug, Clone)] +#[derive(Debug)] pub enum OwnerEvent { /// Emitted when the current owner of the contract changes Transfer { diff --git a/src/pause.rs b/src/pause.rs index 7090f68..bdb878a 100644 --- a/src/pause.rs +++ b/src/pause.rs @@ -36,7 +36,7 @@ const PAUSED_FAIL_MESSAGE: &str = "Disallowed while contract is paused"; crate = "crate", macros = "near_sdk_contract_tools_macros" )] -#[derive(Debug, Clone)] +#[derive(Debug)] pub enum PauseEvent { /// Emitted when the contract is paused Pause, diff --git a/src/standard/nep141/event.rs b/src/standard/nep141/event.rs index e4c85de..16d7f5b 100644 --- a/src/standard/nep141/event.rs +++ b/src/standard/nep141/event.rs @@ -17,7 +17,7 @@ use near_sdk_contract_tools_macros::event; standard = "nep141", version = "1.0.0" )] -#[derive(Debug, Clone)] +#[derive(Debug)] pub enum Nep141Event<'a> { /// Token mint event. Emitted when tokens are created and total_supply is /// increased. diff --git a/src/standard/nep171/event.rs b/src/standard/nep171/event.rs index 5e1b753..200eada 100644 --- a/src/standard/nep171/event.rs +++ b/src/standard/nep171/event.rs @@ -15,7 +15,7 @@ use near_sdk_contract_tools_macros::event; standard = "nep171", version = "1.2.0" )] -#[derive(Debug, Clone)] +#[derive(Debug)] pub enum Nep171Event<'a> { /// Emitted when a token is newly minted. NftMint(Vec>), diff --git a/src/standard/nep297.rs b/src/standard/nep297.rs index 572aa4c..79def6f 100644 --- a/src/standard/nep297.rs +++ b/src/standard/nep297.rs @@ -1,13 +1,16 @@ //! Helpers for `#[derive(near_sdk_contract_tools::Nep297)]` -use near_sdk::{serde::Serialize, serde_json}; +use std::borrow::Cow; + +use near_sdk::{ + serde::{self, Deserialize, Serialize}, + serde_json, +}; /// Emit events according to the [NEP-297 event standard](https://nomicon.io/Standards/EventsFormat). /// /// # Examples /// -/// ## Normal events -/// /// ``` /// use near_sdk_contract_tools::event; /// @@ -27,10 +30,10 @@ use near_sdk::{serde::Serialize, serde_json}; /// e.emit(); /// ``` pub trait Event { - /// Converts the event into an NEP-297 event-formatted string + /// Converts the event into an NEP-297 event-formatted string. fn to_event_string(&self) -> String; - /// Emits the event string to the blockchain + /// Emits the event string to the blockchain. fn emit(&self); } @@ -60,26 +63,92 @@ where } } -/// This type can be converted into an [`EventLog`] struct +/// This type can be converted into an [`EventLog`] struct. pub trait ToEventLog { - /// Metadata associated with the event - type Data: ?Sized; + /// Metadata associated with the event. + type Data; - /// Retrieves the event log before serialization + /// Retrieves the event log before serialization. fn to_event_log(&self) -> EventLog<&Self::Data>; } /// NEP-297 Event Log Data /// -#[derive(Serialize, Clone, Debug)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] #[serde(crate = "near_sdk::serde")] -pub struct EventLog { - /// Name of the event standard, e.g. "nep171" - pub standard: &'static str, - /// Version of the standard, e.g. "1.0.0" - pub version: &'static str, - /// Name of the particular event, e.g. "nft_mint", "ft_transfer" - pub event: &'static str, - /// Data type of the event metadata +pub struct EventLog<'a, T> { + /// Name of the event standard, e.g. `"nep171"`. + pub standard: Cow<'a, str>, + /// Version of the standard, e.g. `"1.0.0"`. + pub version: Cow<'a, str>, + /// Name of the particular event, e.g. `"nft_mint"`, `"ft_transfer"`. + pub event: Cow<'a, str>, + /// Data type of the event metadata. pub data: T, } + +impl<'de, T: Deserialize<'de>> EventLog<'de, T> { + /// Deserializes an event log from a string. + /// + /// # Errors + /// + /// Will return `Err` if the string is not a valid event log. A valid event + /// log begins with the string `"EVENT_JSON:"`, and is followed by a JSON + /// string. + pub fn from_event_log_string(s: &'de str) -> Result { + let data_str = s + .strip_prefix("EVENT_JSON:") + .ok_or(serde::de::Error::custom(serde::de::Unexpected::Str( + "EVENT_JSON:", + )))?; + let data = + serde_json::from_str::>(data_str).map_err(serde::de::Error::custom)?; + let x = Some(1); + x.as_ref(); + Ok(data) + } + + /// Converts the event log into a borrowed reference. + pub fn as_ref(&self) -> EventLog<&T> { + EventLog { + standard: Cow::Borrowed(&self.standard), + version: Cow::Borrowed(&self.version), + event: Cow::Borrowed(&self.event), + data: &self.data, + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn to_and_from_event_log() { + #[derive(Debug, PartialEq, Eq)] + struct MyEvent; + + impl ToEventLog for MyEvent { + type Data = u32; + + fn to_event_log(&self) -> EventLog<&u32> { + EventLog { + standard: "nep171".into(), + version: "1.0.0".into(), + event: "nft_mint".into(), + data: &1, + } + } + } + + let event = MyEvent; + + let string = event.to_event_string(); + + assert_eq!(string, "EVENT_JSON:{\"standard\":\"nep171\",\"version\":\"1.0.0\",\"event\":\"nft_mint\",\"data\":1}"); + + let from_event_log_str = EventLog::::from_event_log_string(&string).unwrap(); + + assert_eq!(from_event_log_str.as_ref(), event.to_event_log()); + } +}