diff --git a/README.md b/README.md index 7eae596..b406cb8 100644 --- a/README.md +++ b/README.md @@ -122,26 +122,21 @@ fn own_accept_owner(&mut self); ### Events ```rust -use serde::Serialize; use near_contract_tools::{event, standard::nep297::Event}; -#[derive(Serialize)] -pub struct Nep171NftMintData { +#[event(standard = "nft", version = "1.0.0")] +pub struct MintEvent { pub owner_id: String, - pub token_ids: Vec, + pub token_id: String, } -#[event(standard = "nep171", version = "1.0.0")] -pub enum Nep171 { - NftMint(Vec), -} - -let my_event = Nep171::NftMint(vec![Nep171NftMintData { - owner_id: "owner".to_string(), - token_ids: vec!["token_1".to_string(), "token_2".to_string()], -}]); +let e = MintEvent { + owner_id: "account".to_string(), + token_id: "token_1".to_string(), +}; -my_event.emit(); // Emits event to the blockchain +// Emits the event to the blockchain +e.emit(); ``` ### Fungible Token diff --git a/macros/src/lib.rs b/macros/src/lib.rs index 0740022..7922d3f 100644 --- a/macros/src/lib.rs +++ b/macros/src/lib.rs @@ -2,7 +2,7 @@ use darling::{FromDeriveInput, FromMeta}; use proc_macro::TokenStream; -use syn::{parse_macro_input, AttributeArgs, DeriveInput}; +use syn::{parse_macro_input, AttributeArgs, DeriveInput, Item}; mod approval; mod migrate; @@ -47,7 +47,9 @@ where /// /// Specify event standard parameters: `#[nep297(standard = "...", version = "...")]` /// -/// Rename strategy for all variants (default: unchanged): `#[event(..., rename_all = "")]` +/// Optional: `#[nep297(name = "...")]` +/// +/// Rename strategy for all variants (default: unchanged): `#[event(rename = "")]` /// Options for ``: /// - `UpperCamelCase` /// - `lowerCamelCase` @@ -167,9 +169,10 @@ pub fn derive_simple_multisig(input: TokenStream) -> TokenStream { #[proc_macro_attribute] pub fn event(attr: TokenStream, item: TokenStream) -> TokenStream { let attr = parse_macro_input!(attr as AttributeArgs); + let item = parse_macro_input!(item as Item); standard::event::EventAttributeMeta::from_list(&attr) - .and_then(|meta| standard::event::event_attribute(meta, item.into())) + .and_then(|meta| standard::event::event_attribute(meta, item)) .map(Into::into) .unwrap_or_else(|e| e.write_errors().into()) } diff --git a/macros/src/standard/event.rs b/macros/src/standard/event.rs index 63b3627..bbdaa2d 100644 --- a/macros/src/standard/event.rs +++ b/macros/src/standard/event.rs @@ -1,6 +1,7 @@ use darling::FromMeta; use proc_macro2::TokenStream; use quote::quote; +use syn::Item; use crate::rename::RenameStrategy; @@ -8,11 +9,9 @@ use crate::rename::RenameStrategy; pub struct EventAttributeMeta { pub standard: String, pub version: String, - pub rename_all: Option, + pub rename: Option, + pub name: Option, - // pub me: String, - // pub macros: String, - // pub serde: String, #[darling(rename = "crate", default = "crate::default_crate_name")] pub me: syn::Path, #[darling(default = "crate::default_macros")] @@ -23,26 +22,28 @@ pub struct EventAttributeMeta { pub fn event_attribute( attr: EventAttributeMeta, - item: TokenStream, + item: Item, ) -> Result { let EventAttributeMeta { standard, version, - rename_all, + rename, + name, serde, me, macros, } = attr; - let rename_all = rename_all.unwrap_or(RenameStrategy::SnakeCase).to_string(); + let rename = rename.unwrap_or(RenameStrategy::SnakeCase).to_string(); + let name = name.map(|n| quote! { , name = #n }); let serde_str = quote! { #serde }.to_string(); let me_str = quote! { #me }.to_string(); Ok(quote::quote! { #[derive(#macros::Nep297, #serde::Serialize)] - #[nep297(standard = #standard, version = #version, rename_all = #rename_all, crate = #me_str)] - #[serde(crate = #serde_str, untagged)] + #[nep297(standard = #standard, version = #version, rename = #rename, crate = #me_str #name)] + #[serde(crate = #serde_str)] #item }) } diff --git a/macros/src/standard/nep141.rs b/macros/src/standard/nep141.rs index 8789de1..0bad864 100644 --- a/macros/src/standard/nep141.rs +++ b/macros/src/standard/nep141.rs @@ -51,16 +51,12 @@ pub fn expand(meta: Nep141Meta) -> Result { }); Ok(quote! { - use #me::standard::nep141::Nep141Controller; - impl #imp #me::standard::nep141::Nep141Controller for #ident #ty #wher { fn root() -> #me::slot::Slot<()> { #me::slot::Slot::root(#storage_key) } } - use #me::standard::nep141::Nep141; - #[#near_sdk::near_bindgen] impl #imp #me::standard::nep141::Nep141 for #ident #ty #wher { #[payable] @@ -72,7 +68,7 @@ pub fn expand(meta: Nep141Meta) -> Result { ) { use #me::{ standard::{ - nep141::{Nep141Controller, Nep141Event}, + nep141::{Nep141Controller, event}, nep297::Event, }, }; @@ -142,8 +138,6 @@ pub fn expand(meta: Nep141Meta) -> Result { } } - use #me::standard::nep141::Nep141Resolver; - #[#near_sdk::near_bindgen] impl #imp #me::standard::nep141::Nep141Resolver for #ident #ty #wher { #[private] diff --git a/macros/src/standard/nep297.rs b/macros/src/standard/nep297.rs index ba72702..a29ba70 100644 --- a/macros/src/standard/nep297.rs +++ b/macros/src/standard/nep297.rs @@ -1,16 +1,16 @@ -use darling::{ast::Style, FromDeriveInput, FromVariant}; +use darling::{FromDeriveInput, FromVariant}; use proc_macro2::TokenStream; use quote::quote; use crate::rename::RenameStrategy; #[derive(Debug, FromDeriveInput)] -#[darling(attributes(nep297), supports(enum_any))] +#[darling(attributes(nep297), supports(struct_any))] pub struct Nep297Meta { pub standard: String, pub version: String, - pub rename_all: Option, - + pub name: Option, + pub rename: Option, pub ident: syn::Ident, pub generics: syn::Generics, pub data: darling::ast::Data, @@ -33,7 +33,8 @@ pub fn expand(meta: Nep297Meta) -> Result { let Nep297Meta { standard, version, - rename_all, + name, + rename, ident: type_name, generics, data, @@ -43,66 +44,31 @@ pub fn expand(meta: Nep297Meta) -> Result { let (imp, ty, wher) = generics.split_for_impl(); // Variant attributes - let arms = match &data { - darling::ast::Data::Enum(variants) => variants, - _ => unreachable!(), // Because of darling supports(enum_any) above - } - .iter() - .map( - |EventVariantReceiver { - ident, - fields, - rename, - name, - }| { + let event = match &data { + darling::ast::Data::Struct(_) => { let transformed_name = if let Some(name) = name { - name.to_string() + name } else if let Some(rename) = rename { - rename.transform(&ident.to_string()) - } else if let Some(rename_all) = &rename_all { - rename_all.transform(&ident.to_string()) + rename.transform(&type_name.to_string()) } else { - ident.to_string() + type_name.to_string() }; - match fields.style { - Style::Unit => quote! { #type_name :: #ident => #transformed_name , }, - Style::Tuple => { - quote! { #type_name :: #ident (..) => #transformed_name , } - } - Style::Struct => { - quote! { #type_name :: #ident {..} => #transformed_name , } - } - } - }, - ) - .collect::>(); + quote! { #transformed_name } + } + _ => unreachable!(), + }; Ok(quote! { - impl #imp #me::standard::nep297::EventMetadata for #type_name #ty #wher { - fn standard(&self) -> &'static str { - #standard - } - - fn version(&self) -> &'static str { - #version - } - - fn event(&self) -> &'static str { - match self { - #(#arms)* + impl #imp #me::standard::nep297::Event<#type_name #ty> for #type_name #ty #wher { + fn event_log<'geld>(&'geld self) -> #me::standard::nep297::EventLog<&'geld Self> { + #me::standard::nep297::EventLog { + standard: #standard, + version: #version, + event: #event, + data: self, } } } - - impl #imp ::std::fmt::Display for #type_name #ty #wher { - fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { - write!( - f, - "{}", - #me::standard::nep297::Event::to_event_string(self), - ) - } - } }) } diff --git a/src/owner.rs b/src/owner.rs index 6e6bf6c..c068604 100644 --- a/src/owner.rs +++ b/src/owner.rs @@ -3,7 +3,7 @@ use near_sdk::{env, ext_contract, require, AccountId}; -use crate::{event, slot::Slot, standard::nep297::Event}; +use crate::{slot::Slot, standard::nep297::Event}; const ONLY_OWNER_FAIL_MESSAGE: &str = "Owner only"; const OWNER_INIT_FAIL_MESSAGE: &str = "Owner already initialized"; @@ -12,27 +12,36 @@ const ONLY_PROPOSED_OWNER_FAIL_MESSAGE: &str = "Proposed owner only"; const NO_PROPOSED_OWNER_FAIL_MESSAGE: &str = "No proposed owner"; /// Events emitted by function calls on an ownable contract -#[event( - standard = "x-own", - version = "1.0.0", - crate = "crate", - macros = "near_contract_tools_macros" -)] -pub enum OwnerEvent { +pub mod event { + use near_sdk::AccountId; + + use crate::event; /// Emitted when the current owner of the contract changes - Transfer { + #[event( + standard = "x-own", + version = "1.0.0", + crate = "crate", + macros = "near_contract_tools_macros" + )] + pub struct Transfer { /// Former owner of the contract. Will be `None` if the contract is being initialized. - old: Option, + pub old: Option, /// The new owner of the contract. Will be `None` if ownership is renounced. - new: Option, - }, + pub new: Option, + } /// Emitted when the proposed owner of the contract changes - Propose { + #[event( + standard = "x-own", + version = "1.0.0", + crate = "crate", + macros = "near_contract_tools_macros" + )] + pub struct Propose { /// Old proposed owner. - old: Option, + pub old: Option, /// New proposed owner. - new: Option, - }, + pub new: Option, + } } /// A contract with an owner @@ -60,7 +69,7 @@ pub trait Owner { let owner = Self::slot_owner(); let old = owner.read(); if old != new { - OwnerEvent::Transfer { + event::Transfer { old, new: new.clone(), } @@ -74,7 +83,7 @@ pub trait Owner { let proposed_owner = Self::slot_proposed_owner(); let old = proposed_owner.read(); if old != new { - OwnerEvent::Propose { + event::Propose { old, new: new.clone(), } @@ -129,7 +138,7 @@ pub trait Owner { Self::slot_is_initialized().write(&true); Self::slot_owner().write(owner_id); - OwnerEvent::Transfer { + event::Transfer { old: None, new: Some(owner_id.clone()), } @@ -207,7 +216,7 @@ pub trait Owner { ONLY_PROPOSED_OWNER_FAIL_MESSAGE, ); - OwnerEvent::Propose { + event::Propose { old: Some(proposed_owner.clone()), new: None, } diff --git a/src/pause.rs b/src/pause.rs index 2e0484d..dd73264 100644 --- a/src/pause.rs +++ b/src/pause.rs @@ -1,24 +1,33 @@ //! Contract method pausing/unpausing #![allow(missing_docs)] // #[ext_contract(...)] does not play nicely with clippy -use crate::{event, slot::Slot, standard::nep297::Event}; +use crate::{slot::Slot, standard::nep297::Event}; use near_sdk::{ext_contract, require}; const UNPAUSED_FAIL_MESSAGE: &str = "Disallowed while contract is unpaused"; const PAUSED_FAIL_MESSAGE: &str = "Disallowed while contract is paused"; /// Events emitted when contract pause state is changed -#[event( - standard = "x-paus", - version = "1.0.0", - crate = "crate", - macros = "near_contract_tools_macros" -)] -pub enum PauseEvent { +pub mod event { + use crate::event; + /// Emitted when the contract is paused - Pause, + #[event( + standard = "x-paus", + version = "1.0.0", + crate = "crate", + macros = "near_contract_tools_macros" + )] + pub struct Pause; + /// Emitted when the contract is unpaused - Unpause, + #[event( + standard = "x-paus", + version = "1.0.0", + crate = "crate", + macros = "near_contract_tools_macros" + )] + pub struct Unpause; } /// Internal-only interactions for a pausable contract @@ -79,7 +88,7 @@ pub trait Pause { fn pause(&mut self) { Self::require_unpaused(); self.set_is_paused(true); - PauseEvent::Pause.emit(); + event::Pause.emit(); } /// Unpauses the contract if it is currently paused, panics otherwise. @@ -87,7 +96,7 @@ pub trait Pause { fn unpause(&mut self) { Self::require_paused(); self.set_is_paused(false); - PauseEvent::Unpause.emit(); + event::Unpause.emit(); } /// Rejects if the contract is unpaused diff --git a/src/standard/nep141.rs b/src/standard/nep141.rs index fbbd9bd..a6e0284 100644 --- a/src/standard/nep141.rs +++ b/src/standard/nep141.rs @@ -10,7 +10,7 @@ use near_sdk::{ }; use serde::{Deserialize, Serialize}; -use crate::{event, slot::Slot, standard::nep297::Event}; +use crate::{slot::Slot, standard::nep297::*}; /// Gas value required for ft_resolve_transfer calls pub const GAS_FOR_RESOLVE_TRANSFER: Gas = Gas(5_000_000_000_000); @@ -20,49 +20,132 @@ pub const GAS_FOR_FT_TRANSFER_CALL: Gas = Gas(25_000_000_000_000 + GAS_FOR_RESOL const MORE_GAS_FAIL_MESSAGE: &str = "More gas is required"; /// NEP-141 standard events for minting, burning, and transferring tokens -#[event( - crate = "crate", - macros = "crate", - serde = "serde", - standard = "nep141", - version = "1.0.0" -)] -pub enum Nep141Event<'a> { +pub mod event { + use near_sdk::{json_types::U128, AccountId}; + use serde::Serialize; + + use crate::event; + /// Token mint event. Emitted when tokens are created and total_supply is /// increased. - FtMint { + #[event( + crate = "crate", + macros = "crate", + serde = "serde", + standard = "nep141", + version = "1.0.0" + )] + pub struct FtMint<'a>(pub &'a [FtMintData<'a>]); + + #[derive(Serialize, Debug, Clone)] + pub struct FtMintData<'a> { /// Address to which new tokens were minted - owner_id: &'a AccountId, + pub owner_id: &'a AccountId, /// Amount of minted tokens - amount: &'a U128, + pub amount: U128, /// Optional note #[serde(skip_serializing_if = "Option::is_none")] - memo: Option<&'a str>, - }, + pub memo: Option<&'a str>, + } + /// Token transfer event. Emitted when tokens are transferred between two /// accounts. No change to total_supply. - FtTransfer { + #[event( + crate = "crate", + macros = "crate", + serde = "serde", + standard = "nep141", + version = "1.0.0" + )] + pub struct FtTransfer<'a>(pub &'a [FtTransferData<'a>]); + + #[derive(Serialize, Debug, Clone)] + pub struct FtTransferData<'a> { /// Account ID of the sender - old_owner_id: &'a AccountId, + pub old_owner_id: &'a AccountId, /// Account ID of the receiver - new_owner_id: &'a AccountId, + pub new_owner_id: &'a AccountId, /// Amount of transferred tokens - amount: &'a U128, + pub amount: U128, /// Optional note #[serde(skip_serializing_if = "Option::is_none")] - memo: Option<&'a str>, - }, + pub memo: Option<&'a str>, + } + /// Token burn event. Emitted when tokens are burned (removed from supply). /// Decrease in total_supply. - FtBurn { + #[event( + crate = "crate", + macros = "crate", + serde = "serde", + standard = "nep141", + version = "1.0.0" + )] + pub struct FtBurn<'a>(pub &'a [FtBurnData<'a>]); + + #[derive(Serialize, Debug, Clone)] + pub struct FtBurnData<'a> { /// Account ID from which tokens were burned - owner_id: &'a AccountId, + pub owner_id: &'a AccountId, /// Amount of burned tokens - amount: &'a U128, + pub amount: U128, /// Optional note #[serde(skip_serializing_if = "Option::is_none")] - memo: Option<&'a str>, - }, + pub memo: Option<&'a str>, + } + + #[cfg(test)] + mod tests { + use super::{super::Event, *}; + + #[test] + fn mint() { + assert_eq!( + FtMint(&[FtMintData { + owner_id: &"foundation.near".parse().unwrap(), + amount: 500u128.into(), + memo: None, + }]) + .to_event_string(), + r#"EVENT_JSON:{"standard":"nep141","version":"1.0.0","event":"ft_mint","data":[{"owner_id":"foundation.near","amount":"500"}]}"#, + ); + } + + #[test] + fn transfer() { + assert_eq!( + FtTransfer(&[ + FtTransferData { + old_owner_id: &"from.near".parse().unwrap(), + new_owner_id: &"to.near".parse().unwrap(), + amount: 42u128.into(), + memo: Some("hi hello bonjour"), + }, + FtTransferData { + old_owner_id: &"user1.near".parse().unwrap(), + new_owner_id: &"user2.near".parse().unwrap(), + amount: 7500u128.into(), + memo: None + }, + ]) + .to_event_string(), + r#"EVENT_JSON:{"standard":"nep141","version":"1.0.0","event":"ft_transfer","data":[{"old_owner_id":"from.near","new_owner_id":"to.near","amount":"42","memo":"hi hello bonjour"},{"old_owner_id":"user1.near","new_owner_id":"user2.near","amount":"7500"}]}"#, + ); + } + + #[test] + fn burn() { + assert_eq!( + FtBurn(&[FtBurnData { + owner_id: &"foundation.near".parse().unwrap(), + amount: 100u128.into(), + memo: None, + }]) + .to_event_string(), + r#"EVENT_JSON:{"standard":"nep141","version":"1.0.0","event":"ft_burn","data":[{"owner_id":"foundation.near","amount":"100"}]}"#, + ); + } + } } #[derive(BorshSerialize, BorshStorageKey)] @@ -233,12 +316,12 @@ pub trait Nep141Controller { ) { self.transfer_unchecked(sender_account_id, receiver_account_id, amount); - Nep141Event::FtTransfer { + event::FtTransfer(&[event::FtTransferData { old_owner_id: sender_account_id, new_owner_id: receiver_account_id, - amount: &amount.into(), + amount: amount.into(), memo, - } + }]) .emit(); } @@ -250,11 +333,11 @@ pub trait Nep141Controller { fn mint(&mut self, account_id: &AccountId, amount: u128, memo: Option<&str>) { self.deposit_unchecked(account_id, amount); - Nep141Event::FtMint { + event::FtMint(&[event::FtMintData { owner_id: account_id, - amount: &amount.into(), + amount: amount.into(), memo, - } + }]) .emit(); } @@ -266,11 +349,11 @@ pub trait Nep141Controller { fn burn(&mut self, account_id: &AccountId, amount: u128, memo: Option<&str>) { self.withdraw_unchecked(account_id, amount); - Nep141Event::FtBurn { + event::FtBurn(&[event::FtBurnData { owner_id: account_id, - amount: &amount.into(), + amount: amount.into(), memo, - } + }]) .emit(); } diff --git a/src/standard/nep297.rs b/src/standard/nep297.rs index b16e91c..202c575 100644 --- a/src/standard/nep297.rs +++ b/src/standard/nep297.rs @@ -5,73 +5,61 @@ use near_sdk::serde::Serialize; /// Emit events according to the [NEP-297 event standard](https://nomicon.io/Standards/EventsFormat). /// /// # Examples +/// +/// ## Normal events +/// /// ``` -/// use near_contract_tools::standard::nep297::*; -/// use near_contract_tools::Nep297; -/// use serde::Serialize; +/// use near_contract_tools::event; /// -/// #[derive(Serialize)] -/// pub struct Nep171NftMintData { +/// #[event(standard = "nft", version = "1.0.0")] +/// pub struct MintEvent { /// pub owner_id: String, -/// pub token_ids: Vec, +/// pub token_id: String, /// } /// -/// #[derive(Nep297, Serialize)] -/// #[nep297(standard = "nep171", version = "1.0.0")] -/// #[serde(untagged)] -/// pub enum Nep171 { -/// #[nep297(name = "nft_mint")] -/// NftMint(Vec), -/// } +/// let e = MintEvent { +/// owner_id: "account".to_string(), +/// token_id: "token_1".to_string(), +/// }; +/// +/// use near_contract_tools::standard::nep297::Event; +/// +/// e.emit(); /// ``` -pub trait Event { - /// Returns an `EVENT_JSON:{}`-formatted log string - fn to_event_string(&self) -> String; - /// Consumes the event and emits it to the NEAR blockchain - fn emit(&self); -} +pub trait Event { + /// Retrieves the event log before serialization + fn event_log(&self) -> EventLog<&T>; -/// Metadata for NEP-297-compliant events & variants -pub trait EventMetadata { - /// The name of the event standard, e.g. "nep171" - fn standard(&self) -> &'static str; - /// Version of the standard, e.g. "1.0.0" - fn version(&self) -> &'static str; - /// What type of event within the event standard, e.g. "nft_mint" - fn event(&self) -> &'static str; -} - -/// NEP-297 Event Log Data -/// -#[derive(Serialize, Debug)] -struct EventLogData<'a, T> { - pub standard: &'a str, - pub version: &'a str, - pub event: &'a str, - pub data: &'a T, -} - -impl<'a, T: EventMetadata> From<&'a T> for EventLogData<'a, T> { - fn from(m: &'a T) -> Self { - Self { - standard: m.standard(), - version: m.version(), - event: m.event(), - data: m, - } - } -} - -impl Event for T { - fn to_event_string(&self) -> String { + /// Converts the event into an NEP-297 event-formatted string + fn to_event_string(&self) -> String + where + T: Serialize, + { format!( "EVENT_JSON:{}", - serde_json::to_string(&Into::>::into(self)) - .unwrap_or_else(|_| near_sdk::env::abort()), + serde_json::to_string(&self.event_log()).unwrap_or_else(|_| near_sdk::env::abort()), ) } - fn emit(&self) { + /// Emits the event string to the blockchain + fn emit(&self) + where + T: Serialize, + { near_sdk::env::log_str(&self.to_event_string()); } } + +/// NEP-297 Event Log Data +/// +#[derive(Serialize, Clone, Debug)] +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 data: T, +} diff --git a/tests/macros/event.rs b/tests/macros/event.rs index 8d8da82..9f14667 100644 --- a/tests/macros/event.rs +++ b/tests/macros/event.rs @@ -1,32 +1,36 @@ -use near_contract_tools::{standard::nep297::*, Nep297}; -use serde::Serialize; +use near_contract_tools::standard::nep297::Event; -#[derive(Serialize)] -pub struct Nep171NftMintData { - pub owner_id: String, - pub token_ids: Vec, -} +use crate::macros::event::test_events::Nep171NftMintData; + +mod test_events { + use near_contract_tools::Nep297; + use serde::Serialize; -#[derive(Nep297, Serialize)] -// Required fields -#[nep297(standard = "nep171", version = "1.0.0")] -// Optional. Default event name is the untransformed variant name, e.g. NftMint, AnotherEvent, CustomEvent -#[nep297(rename_all = "snake_case")] -// Variant name will not appear in the serialized output -#[serde(untagged)] -pub enum Nep171 { - NftMint(Vec), // Name will be "nft_mint" because rename_all = snake_case + #[derive(Serialize)] + pub struct Nep171NftMintData { + pub owner_id: String, + pub token_ids: Vec, + } - #[nep297(name = "sneaky_event")] - AnotherEvent, // Name will be "sneaky_event" + #[derive(Nep297, Serialize)] + // Required fields + #[nep297(standard = "nep171", version = "1.0.0")] + // Optional. Default event name is the untransformed variant name, e.g. NftMint, AnotherEvent, CustomEvent + #[nep297(rename = "snake_case")] + pub struct NftMint(pub Vec); // Name will be "nft_mint" because rename = snake_case - #[nep297(rename = "SHOUTY-KEBAB-CASE")] - CustomEvent, // Name will be "CUSTOM-EVENT" + #[derive(Nep297, Serialize)] + #[nep297(standard = "nep171", version = "1.0.0", name = "sneaky_event")] + pub struct AnotherEvent; // Name will be "sneaky_event" + + #[derive(Nep297, Serialize)] + #[nep297(standard = "nep171", version = "1.0.0", rename = "SHOUTY-KEBAB-CASE")] + pub struct CustomEvent; // Name will be "CUSTOM-EVENT" } #[test] fn derive_event() { - let e = Nep171::NftMint(vec![Nep171NftMintData { + let e = test_events::NftMint(vec![Nep171NftMintData { owner_id: "owner".to_string(), token_ids: vec!["token_1".to_string(), "token_2".to_string()], }]); @@ -36,28 +40,33 @@ fn derive_event() { r#"EVENT_JSON:{"standard":"nep171","version":"1.0.0","event":"nft_mint","data":[{"owner_id":"owner","token_ids":["token_1","token_2"]}]}"# ); - assert_eq!(Nep171::AnotherEvent.event(), "sneaky_event"); + assert_eq!(test_events::AnotherEvent.event_log().event, "sneaky_event"); - assert_eq!(Nep171::CustomEvent.event(), "CUSTOM-EVENT"); + assert_eq!(test_events::CustomEvent.event_log().event, "CUSTOM-EVENT"); } mod event_attribute_macro { - use near_contract_tools::{event, standard::nep297::Event}; + use near_contract_tools::standard::nep297::Event; + + mod my_event { + use near_contract_tools::event; - #[event(standard = "my_event_standard", version = "1")] - #[allow(unused)] - enum MyEvent { - One, - ThreePointFive { foo: &'static str }, - Six, + #[event(standard = "my_event_standard", version = "1")] + pub struct One; + #[event(standard = "my_event_standard", version = "1")] + pub struct ThreePointFive { + pub foo: &'static str, + } + #[event(standard = "my_event_standard", version = "1")] + pub struct Six; } #[test] fn test() { - let e = MyEvent::ThreePointFive { foo: "hello" }; + let e = my_event::ThreePointFive { foo: "hello" }; e.emit(); assert_eq!( - e.to_string(), + e.to_event_string(), r#"EVENT_JSON:{"standard":"my_event_standard","version":"1","event":"three_point_five","data":{"foo":"hello"}}"#, ); } diff --git a/tests/macros/mod.rs b/tests/macros/mod.rs index 99991a4..c3254e3 100644 --- a/tests/macros/mod.rs +++ b/tests/macros/mod.rs @@ -4,7 +4,7 @@ use near_contract_tools::{ pause::Pause, rbac::Rbac, standard::nep297::Event, - Migrate, Nep297, Owner, Pause, Rbac, + Migrate, Owner, Pause, Rbac, }; use near_sdk::{ borsh::{self, BorshDeserialize, BorshSerialize}, @@ -12,7 +12,6 @@ use near_sdk::{ test_utils::VMContextBuilder, testing_env, AccountId, BorshStorageKey, }; -use serde::Serialize; mod event; mod migrate; @@ -20,12 +19,23 @@ mod owner; mod pause; mod standard; -#[derive(Serialize, Nep297)] -#[nep297(standard = "x-myevent", version = "1.0.0", rename_all = "snake_case")] -#[serde(untagged)] -enum MyEvent { - ValueChanged { from: u32, to: u32 }, - PermissionGranted { to: AccountId }, +mod my_event { + use near_contract_tools::Nep297; + use near_sdk::AccountId; + use serde::Serialize; + + #[derive(Serialize, Nep297)] + #[nep297(standard = "x-myevent", version = "1.0.0", rename = "snake_case")] + pub struct ValueChanged { + pub from: u32, + pub to: u32, + } + + #[derive(Serialize, Nep297)] + #[nep297(standard = "x-myevent", version = "1.0.0", rename = "snake_case")] + pub struct PermissionGranted { + pub to: AccountId, + } } #[derive(BorshSerialize, BorshStorageKey)] @@ -68,7 +78,7 @@ impl Integration { self.add_role(&account_id, &Role::CanSetValue); - MyEvent::PermissionGranted { to: account_id }.emit(); + my_event::PermissionGranted { to: account_id }.emit(); } pub fn set_value(&mut self, value: u32) { @@ -79,7 +89,7 @@ impl Integration { self.value = value; - MyEvent::ValueChanged { + my_event::ValueChanged { from: old, to: value, } @@ -131,7 +141,7 @@ impl MigrateIntegration { self.add_role(&account_id, &Role::CanSetValue); - MyEvent::PermissionGranted { to: account_id }.emit(); + my_event::PermissionGranted { to: account_id }.emit(); } pub fn set_value(&mut self, value: u32) { @@ -142,7 +152,7 @@ impl MigrateIntegration { self.moved_value = value; - MyEvent::ValueChanged { + my_event::ValueChanged { from: old, to: value, } @@ -345,7 +355,7 @@ fn integration_fail_migrate_paused() { mod pausable_fungible_token { use near_contract_tools::{ pause::Pause, - standard::nep141::{Nep141Hook, Nep141Transfer}, + standard::nep141::{Nep141, Nep141Controller, Nep141Hook, Nep141Transfer}, FungibleToken, Pause, }; use near_sdk::{ diff --git a/tests/macros/standard/fungible_token.rs b/tests/macros/standard/fungible_token.rs index 4e6005e..7180213 100644 --- a/tests/macros/standard/fungible_token.rs +++ b/tests/macros/standard/fungible_token.rs @@ -1,4 +1,7 @@ -use near_contract_tools::FungibleToken; +use near_contract_tools::{ + standard::nep141::{Nep141, Nep141Controller}, + FungibleToken, +}; use near_sdk::{ json_types::Base64VecU8, near_bindgen, test_utils::VMContextBuilder, testing_env, AccountId, }; diff --git a/workspaces-tests/src/bin/fungible_token.rs b/workspaces-tests/src/bin/fungible_token.rs index afbe808..60053fc 100644 --- a/workspaces-tests/src/bin/fungible_token.rs +++ b/workspaces-tests/src/bin/fungible_token.rs @@ -3,7 +3,7 @@ // Ignore pub fn main() {} -use near_contract_tools::FungibleToken; +use near_contract_tools::{standard::nep141::*, FungibleToken}; use near_sdk::{ borsh::{self, BorshDeserialize, BorshSerialize}, env,