Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix FT events & NEP-297 API improvements #63

Merged
merged 4 commits into from
Sep 22, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
23 changes: 9 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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<String>,
pub token_id: 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_id: "token_1".to_string(),
};

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

### Fungible Token
Expand Down
9 changes: 6 additions & 3 deletions macros/src/lib.rs
Original file line number Diff line number Diff line change
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,9 @@ where
///
/// Specify event standard parameters: `#[nep297(standard = "...", version = "...")]`
///
/// Rename strategy for all variants (default: unchanged): `#[event(..., rename_all = "<strategy>")]`
/// Optional: `#[nep297(name = "...")]`
///
/// Rename strategy for all variants (default: unchanged): `#[event(rename = "<strategy>")]`
/// Options for `<strategy>`:
/// - `UpperCamelCase`
/// - `lowerCamelCase`
Expand Down Expand Up @@ -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())
}
19 changes: 10 additions & 9 deletions macros/src/standard/event.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
use darling::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 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 +22,28 @@ 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,
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
})
}
8 changes: 1 addition & 7 deletions macros/src/standard/nep141.rs
Original file line number Diff line number Diff line change
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
78 changes: 22 additions & 56 deletions macros/src/standard/nep297.rs
Original file line number Diff line number Diff line change
@@ -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<RenameStrategy>,

pub name: Option<String>,
pub rename: Option<RenameStrategy>,
pub ident: syn::Ident,
pub generics: syn::Generics,
pub data: darling::ast::Data<EventVariantReceiver, ()>,
Expand All @@ -33,7 +33,8 @@ pub fn expand(meta: Nep297Meta) -> Result<TokenStream, darling::Error> {
let Nep297Meta {
standard,
version,
rename_all,
name,
rename,
ident: type_name,
generics,
data,
Expand All @@ -43,66 +44,31 @@ 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
}

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),
)
}
}
})
}
49 changes: 29 additions & 20 deletions src/owner.rs
Original file line number Diff line number Diff line change
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