Skip to content

Commit

Permalink
chore: update nep148 to use dynamic metadata
Browse files Browse the repository at this point in the history
  • Loading branch information
encody committed Sep 21, 2023
1 parent 26d4ee2 commit 9ddd0d1
Show file tree
Hide file tree
Showing 10 changed files with 248 additions and 166 deletions.
38 changes: 21 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,19 +99,28 @@ e.emit();
To create a contract that is compatible with the NEP-141 and NEP-148 standards, that emits standard-compliant (NEP-141, NEP-297) events.

```rust
use near_sdk_contract_tools::FungibleToken;
use near_sdk_contract_tools::ft::*;
use near_sdk::near_bindgen;

#[derive(FungibleToken)]
#[fungible_token(
name = "My Fungible Token",
symbol = "MYFT",
decimals = 18,
no_hooks
)]
#[fungible_token(no_hooks)]
#[near_bindgen]
struct FungibleToken {
// ...
struct FungibleToken {}

#[near_bindgen]
impl FungibleToken {
#[init]
pub fn new() -> Self {
let mut contract = Self {};

contract.set_metadata(&FungibleTokenMetadata::new(
"My Fungible Token".to_string(),
"MYFT".to_string(),
24,
));

contract
}
}
```

Expand Down Expand Up @@ -140,20 +149,15 @@ pub struct MyNft {}
One may wish to combine the features of multiple macros in one contract. All of the macros are written such that they will work in a standalone manner, so this should largely work without issue. However, sometimes it may be desirable for the macros to work in _combination_ with each other. For example, to make a fungible token pausable, use the fungible token hooks to require that a contract be unpaused before making a token transfer:

```rust
use near_sdk_contract_tools::{
pause::Pause,
standard::nep141::{Nep141Hook, Nep141Transfer},
FungibleToken, Pause,
};
use near_sdk_contract_tools::{ft::*, pause::Pause, Pause};
use near_sdk::near_bindgen;

#[derive(FungibleToken, Pause)]
#[fungible_token(name = "Pausable Fungible Token", symbol = "PFT", decimals = 18)]
#[near_bindgen]
struct Contract {}

impl Nep141Hook for Contract {
fn before_transfer(&mut self, _transfer: &Nep141Transfer) {
impl SimpleNep141Hook for Contract {
fn before_transfer(&self, _transfer: &Nep141Transfer) {
Contract::require_unpaused();
}
}
Expand Down
32 changes: 6 additions & 26 deletions macros/src/standard/fungible_token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,11 @@ use super::{nep141, nep148};
#[darling(attributes(fungible_token), supports(struct_named))]
pub struct FungibleTokenMeta {
// NEP-141 fields
pub storage_key: Option<Expr>,
pub core_storage_key: Option<Expr>,
pub no_hooks: Flag,

// NEP-148 fields
pub spec: Option<String>,
pub name: String,
pub symbol: String,
pub icon: Option<String>,
pub reference: Option<String>,
pub reference_hash: Option<String>,
pub decimals: u8,
pub metadata_storage_key: Option<Expr>,

// darling
pub generics: syn::Generics,
Expand All @@ -34,17 +28,10 @@ pub struct FungibleTokenMeta {

pub fn expand(meta: FungibleTokenMeta) -> Result<TokenStream, darling::Error> {
let FungibleTokenMeta {
storage_key,
core_storage_key,
metadata_storage_key,
no_hooks,

spec,
name,
symbol,
icon,
reference,
reference_hash,
decimals,

generics,
ident,

Expand All @@ -53,7 +40,7 @@ pub fn expand(meta: FungibleTokenMeta) -> Result<TokenStream, darling::Error> {
} = meta;

let expand_nep141 = nep141::expand(nep141::Nep141Meta {
storage_key,
storage_key: core_storage_key,
no_hooks,

generics: generics.clone(),
Expand All @@ -64,14 +51,7 @@ pub fn expand(meta: FungibleTokenMeta) -> Result<TokenStream, darling::Error> {
});

let expand_nep148 = nep148::expand(nep148::Nep148Meta {
spec,
name,
symbol,
icon,
reference,
reference_hash,
decimals,

storage_key: metadata_storage_key,
generics,
ident,

Expand Down
61 changes: 13 additions & 48 deletions macros/src/standard/nep148.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,12 @@
use darling::{FromDeriveInput, ToTokens};
use darling::FromDeriveInput;
use proc_macro2::TokenStream;
use quote::quote;
use syn::Expr;

#[derive(Debug, FromDeriveInput)]
#[darling(attributes(nep148), supports(struct_named))]
pub struct Nep148Meta {
pub spec: Option<String>,
pub name: String,
pub symbol: String,
pub icon: Option<String>,
pub reference: Option<String>,
pub reference_hash: Option<String>,
pub decimals: u8,

pub storage_key: Option<Expr>,
pub generics: syn::Generics,
pub ident: syn::Ident,

Expand All @@ -23,64 +17,35 @@ pub struct Nep148Meta {
pub near_sdk: syn::Path,
}

fn optionize<T>(t: Option<T>) -> TokenStream
where
T: ToTokens,
{
t.map_or_else(|| quote! { None }, |v| quote! { Some(#v) })
}

pub fn expand(meta: Nep148Meta) -> Result<TokenStream, darling::Error> {
let Nep148Meta {
storage_key,
generics,
ident,
// fields
spec,
name,
symbol,
icon,
reference,
reference_hash,
decimals,

me,
near_sdk,
} = meta;

let spec = spec.map(|s| s.to_token_stream()).unwrap_or_else(|| {
let root = storage_key.map(|storage_key| {
quote! {
#me::standard::nep148::FT_METADATA_SPEC
fn root() -> #me::slot::Slot<()> {
#me::slot::Slot::root(#storage_key)
}
}
});

let icon = optionize(icon);
let reference = optionize(reference);

// TODO: Download reference field at compile time and calculate reference_hash automatically
let reference_hash = optionize(reference_hash.map(|s| {
let v = format!("{:?}", base64::decode(s).unwrap())
.parse::<quote::__private::TokenStream>()
.unwrap();

quote! { #near_sdk::json_types::Base64VecU8::from(#v.to_vec()) }
}));

let (imp, ty, wher) = generics.split_for_impl();

Ok(quote! {
use #me::standard::nep148::Nep148;
impl #imp #me::standard::nep148::Nep148ControllerInternal for #ident #ty #wher {
#root
}

#[#near_sdk::near_bindgen]
impl #imp #me::standard::nep148::Nep148 for #ident #ty #wher {
fn ft_metadata(&self) -> #me::standard::nep148::FungibleTokenMetadata {
#me::standard::nep148::FungibleTokenMetadata {
spec: #spec.into(),
name: #name.into(),
symbol: #symbol.into(),
icon: #icon.map(|s: &str| s.into()),
reference: #reference.map(|s: &str| s.into()),
reference_hash: #reference_hash,
decimals: #decimals,
}
#me::standard::nep148::Nep148Controller::get_metadata(self)
}
}
})
Expand Down
11 changes: 11 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ pub enum DefaultStorageKey {
ApprovalManager,
/// Default storage key for [`standard::nep141::Nep141ControllerInternal::root`].
Nep141,
/// Default storage key for [`standard::nep148::Nep148ControllerInternal::root`].
Nep148,
/// Default storage key for [`standard::nep171::Nep171ControllerInternal::root`].
Nep171,
/// Default storage key for [`standard::nep177::Nep177ControllerInternal::root`].
Expand All @@ -34,6 +36,7 @@ impl IntoStorageKey for DefaultStorageKey {
match self {
DefaultStorageKey::ApprovalManager => b"~am".to_vec(),
DefaultStorageKey::Nep141 => b"~$141".to_vec(),
DefaultStorageKey::Nep148 => b"~$148".to_vec(),
DefaultStorageKey::Nep171 => b"~$171".to_vec(),
DefaultStorageKey::Nep177 => b"~$177".to_vec(),
DefaultStorageKey::Nep178 => b"~$178".to_vec(),
Expand Down Expand Up @@ -66,3 +69,11 @@ pub mod nft {
Nep171, Nep177, Nep178, Nep181, NonFungibleToken,
};
}

/// Re-exports of the FT standard traits.
pub mod ft {
pub use crate::{
standard::{nep141::*, nep148::*},
FungibleToken, Nep141, Nep148,
};
}
8 changes: 4 additions & 4 deletions src/standard/nep141/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ use serde::{Deserialize, Serialize};

use crate::{slot::Slot, standard::nep297::*, DefaultStorageKey};

pub mod error;
mod error;
pub use error::*;
pub mod event;
mod event;
pub use event::*;
pub mod ext;
mod ext;
pub use ext::*;
pub mod hook;
mod hook;
pub use hook::*;

/// Gas value required for ft_resolve_transfer calls
Expand Down
Loading

0 comments on commit 9ddd0d1

Please sign in to comment.