Skip to content

Commit

Permalink
feat: batch events, fix #62
Browse files Browse the repository at this point in the history
  • Loading branch information
encody committed Sep 21, 2022
1 parent ca84354 commit 1952ac1
Show file tree
Hide file tree
Showing 13 changed files with 353 additions and 242 deletions.
24 changes: 11 additions & 13 deletions README.md
Expand Up @@ -122,26 +122,24 @@ 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 = "nep171", version = "1.0.0")]
pub struct MintEvent {
pub owner_id: String,
pub token_ids: Vec<String>,
}

#[event(standard = "nep171", version = "1.0.0")]
pub enum Nep171 {
NftMint(Vec<Nep171NftMintData>),
}

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_ids: vec![
"t1".to_string(),
"t2".to_string(),
],
};

my_event.emit(); // Emits event to the blockchain
// Emits the event to the blockchain
e.emit();
```

### Fungible Token
Expand Down
15 changes: 12 additions & 3 deletions macros/src/lib.rs
Expand Up @@ -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;
Expand Down Expand Up @@ -47,7 +47,15 @@ where
///
/// Specify event standard parameters: `#[nep297(standard = "...", version = "...")]`
///
/// Rename strategy for all variants (default: unchanged): `#[event(..., rename_all = "<strategy>")]`
/// Optional: `#[nep297(name = "..."), batch]`
///
/// The `batch` flag means that events will always be emitted as a homogenous array:
///
/// ```ignore
/// [MyBatchableEvent("one"), MyBatchableEvent("two")].emit();
/// ```
///
/// Rename strategy for all variants (default: unchanged): `#[event(rename = "<strategy>")]`
/// Options for `<strategy>`:
/// - `UpperCamelCase`
/// - `lowerCamelCase`
Expand Down Expand Up @@ -167,9 +175,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())
}
25 changes: 15 additions & 10 deletions macros/src/standard/event.rs
@@ -1,18 +1,18 @@
use darling::FromMeta;
use darling::{util::Flag, FromMeta};
use proc_macro2::TokenStream;
use quote::quote;
use syn::Item;

use crate::rename::RenameStrategy;

#[derive(Debug, FromMeta)]
pub struct EventAttributeMeta {
pub standard: String,
pub version: String,
pub rename_all: Option<RenameStrategy>,
pub rename: Option<RenameStrategy>,
pub name: Option<String>,
pub batch: Flag,

// 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")]
Expand All @@ -23,26 +23,31 @@ pub struct EventAttributeMeta {

pub fn event_attribute(
attr: EventAttributeMeta,
item: TokenStream,
item: Item,
) -> Result<TokenStream, darling::Error> {
let EventAttributeMeta {
standard,
version,
rename_all,
rename,
name,
batch,
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();

let batch = batch.is_present().then_some(quote! {, batch});

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 #batch)]
#[serde(crate = #serde_str)]
#item
})
}
8 changes: 1 addition & 7 deletions macros/src/standard/nep141.rs
Expand Up @@ -51,16 +51,12 @@ pub fn expand(meta: Nep141Meta) -> Result<TokenStream, darling::Error> {
});

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]
Expand All @@ -72,7 +68,7 @@ pub fn expand(meta: Nep141Meta) -> Result<TokenStream, darling::Error> {
) {
use #me::{
standard::{
nep141::{Nep141Controller, Nep141Event},
nep141::{Nep141Controller, event},
nep297::Event,
},
};
Expand Down Expand Up @@ -142,8 +138,6 @@ pub fn expand(meta: Nep141Meta) -> Result<TokenStream, darling::Error> {
}
}

use #me::standard::nep141::Nep141Resolver;

#[#near_sdk::near_bindgen]
impl #imp #me::standard::nep141::Nep141Resolver for #ident #ty #wher {
#[private]
Expand Down
91 changes: 39 additions & 52 deletions macros/src/standard/nep297.rs
@@ -1,15 +1,17 @@
use darling::{ast::Style, FromDeriveInput, FromVariant};
use darling::{util::Flag, 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<RenameStrategy>,
pub name: Option<String>,
pub rename: Option<RenameStrategy>,
pub batch: Flag,

pub ident: syn::Ident,
pub generics: syn::Generics,
Expand All @@ -33,7 +35,9 @@ pub fn expand(meta: Nep297Meta) -> Result<TokenStream, darling::Error> {
let Nep297Meta {
standard,
version,
rename_all,
name,
rename,
batch,
ident: type_name,
generics,
data,
Expand All @@ -43,65 +47,48 @@ pub fn expand(meta: Nep297Meta) -> Result<TokenStream, darling::Error> {
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::<Vec<_>>();
quote! { #transformed_name }
}
_ => unreachable!(),
};

Ok(quote! {
impl #imp #me::standard::nep297::EventMetadata for #type_name #ty #wher {
fn standard(&self) -> &'static str {
#standard
}
Ok(if batch.is_present() {
quote! {
impl #imp #me::standard::nep297::BatchEvent for #type_name #ty #wher {
fn standard() -> &'static str {
#standard
}

fn version(&self) -> &'static str {
#version
}
fn version() -> &'static str {
#version
}

fn event(&self) -> &'static str {
match self {
#(#arms)*
fn event() -> &'static str {
#event
}
}
}

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),
)
} else {
quote! {
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,
}
}
}
}
})
Expand Down
49 changes: 29 additions & 20 deletions src/owner.rs
Expand Up @@ -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";
Expand All @@ -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<AccountId>,
pub old: Option<AccountId>,
/// The new owner of the contract. Will be `None` if ownership is renounced.
new: Option<AccountId>,
},
pub new: Option<AccountId>,
}
/// 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<AccountId>,
pub old: Option<AccountId>,
/// New proposed owner.
new: Option<AccountId>,
},
pub new: Option<AccountId>,
}
}

/// A contract with an owner
Expand Down Expand Up @@ -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(),
}
Expand All @@ -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(),
}
Expand Down Expand Up @@ -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()),
}
Expand Down Expand Up @@ -207,7 +216,7 @@ pub trait Owner {
ONLY_PROPOSED_OWNER_FAIL_MESSAGE,
);

OwnerEvent::Propose {
event::Propose {
old: Some(proposed_owner.clone()),
new: None,
}
Expand Down

0 comments on commit 1952ac1

Please sign in to comment.