Skip to content

Commit

Permalink
BREAKING: Token standards ergonomics improvements (#148)
Browse files Browse the repository at this point in the history
* feat: FungibleTokenMetadata -> ContractMetadata rename for consistency with nft; improved reference ergos

* chore: use AccountIdRef

* feat: convenience constructor functions

* feat: deserializable events, fixes #147

* fix: revert removing clone derive
  • Loading branch information
encody authored May 8, 2024
1 parent d540ed7 commit 0d1ae85
Show file tree
Hide file tree
Showing 40 changed files with 780 additions and 592 deletions.
44 changes: 21 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,11 @@

## NFT

```diff
use near_sdk::{near, PanicOnDefault};
+ use near_sdk_contract_tools::nft::*;
```rust
use near_sdk::near;
use near_sdk_contract_tools::nft::*;

#[derive(PanicOnDefault)]
+ #[derive(NonFungibleToken)]
#[derive(Default, NonFungibleToken)]
#[near(contract_state)]
pub struct MyNftContract {}

Expand All @@ -17,11 +16,11 @@ impl MyNftContract {
pub fn new() -> Self {
let mut contract = Self {};

+ contract.set_contract_metadata(ContractMetadata::new(
+ "My NFT".to_string(),
+ "MNFT".to_string(),
+ None,
+ ));
contract.set_contract_metadata(&ContractMetadata::new(
"My NFT".to_string(),
"MNFT".to_string(),
None,
));

contract
}
Expand All @@ -30,12 +29,11 @@ impl MyNftContract {

## FT

```diff
use near_sdk::{near, PanicOnDefault};
+ use near_sdk_contract_tools::ft::*;
```rust
use near_sdk::near;
use near_sdk_contract_tools::ft::*;

#[derive(PanicOnDefault)]
+ #[derive(FungibleToken)]
#[derive(Default, FungibleToken)]
#[near(contract_state)]
pub struct MyFtContract {}

Expand All @@ -45,11 +43,11 @@ impl MyFtContract {
pub fn new() -> Self {
let mut contract = Self {};

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

contract
}
Expand Down Expand Up @@ -157,10 +155,10 @@ e.emit();
To create a contract that is compatible with the [NEP-141][nep141], [NEP-145][nep145], and [NEP-148][nep148] standards, that emits standard-compliant ([NEP-297][nep297]) events.

```rust
use near_sdk::near;
use near_sdk_contract_tools::ft::*;
use near_sdk::{near, PanicOnDefault};

#[derive(FungibleToken, PanicOnDefault)]
#[derive(Default, FungibleToken)]
#[near(contract_state)]
struct MyFt {}

Expand All @@ -170,7 +168,7 @@ impl MyFt {
pub fn new() -> Self {
let mut contract = Self {};

contract.set_metadata(&FungibleTokenMetadata::new(
contract.set_metadata(&ContractMetadata::new(
"My Fungible Token".to_string(),
"MYFT".to_string(),
24,
Expand Down
2 changes: 1 addition & 1 deletion macros/src/standard/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ pub fn event_attribute(
let me_str = quote! { #me }.to_string();

Ok(quote::quote! {
#[derive(#macros::Nep297, #serde::Serialize)]
#[derive(#macros::Nep297, #serde::Serialize, #serde::Deserialize)]
#[nep297(
crate = #me_str,
standard = #standard,
Expand Down
9 changes: 4 additions & 5 deletions macros/src/standard/fungible_token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ use proc_macro2::TokenStream;
use quote::quote;
use syn::{Expr, Type};

use crate::unitify;

use super::{nep141, nep145, nep148};

#[derive(Debug, FromDeriveInput)]
Expand Down Expand Up @@ -53,11 +55,8 @@ pub fn expand(meta: FungibleTokenMeta) -> Result<TokenStream, darling::Error> {
near_sdk,
} = meta;

let all_hooks_or_unit = all_hooks
.clone()
.unwrap_or_else(|| syn::parse_quote! { () });
let force_unregister_hook_or_unit =
force_unregister_hook.unwrap_or_else(|| syn::parse_quote! { () });
let all_hooks_or_unit = unitify(all_hooks.clone());
let force_unregister_hook_or_unit = unitify(force_unregister_hook);

let expand_nep141 = nep141::expand(nep141::Nep141Meta {
storage_key: core_storage_key,
Expand Down
26 changes: 13 additions & 13 deletions macros/src/standard/nep141.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,10 @@ pub fn expand(meta: Nep141Meta) -> Result<TokenStream, darling::Error> {
let amount: u128 = amount.into();

let transfer = Nep141Transfer {
sender_id: &sender_id,
receiver_id: &receiver_id,
sender_id: sender_id.into(),
receiver_id: receiver_id.into(),
amount,
memo: memo.as_deref(),
memo: memo.map(Into::into),
msg: None,
revert: false,
};
Expand Down Expand Up @@ -118,11 +118,11 @@ pub fn expand(meta: Nep141Meta) -> Result<TokenStream, darling::Error> {
let amount: u128 = amount.into();

let transfer = Nep141Transfer {
sender_id: &sender_id,
receiver_id: &receiver_id,
sender_id: sender_id.into(),
receiver_id: receiver_id.into(),
amount,
memo: memo.as_deref(),
msg: Some(&msg),
memo: memo.map(Into::into),
msg: Some(msg.clone().into()),
revert: false,
};

Expand All @@ -134,15 +134,15 @@ pub fn expand(meta: Nep141Meta) -> Result<TokenStream, darling::Error> {
.unwrap_or_else(|| #near_sdk::env::panic_str("Prepaid gas underflow."));

// Initiating receiver's call and the callback
ext_nep141_receiver::ext(transfer.receiver_id.clone())
ext_nep141_receiver::ext(transfer.receiver_id.clone().into())
.with_static_gas(receiver_gas)
.ft_on_transfer(transfer.sender_id.clone(), transfer.amount.into(), msg.clone())
.ft_on_transfer(transfer.sender_id.clone().into(), transfer.amount.into(), msg)
.then(
ext_nep141_resolver::ext(#near_sdk::env::current_account_id())
.with_static_gas(GAS_FOR_RESOLVE_TRANSFER)
.ft_resolve_transfer(
transfer.sender_id.clone(),
transfer.receiver_id.clone(),
transfer.sender_id.clone().into(),
transfer.receiver_id.clone().into(),
transfer.amount.into(),
),
)
Expand Down Expand Up @@ -190,8 +190,8 @@ pub fn expand(meta: Nep141Meta) -> Result<TokenStream, darling::Error> {
if receiver_balance > 0 {
let refund_amount = std::cmp::min(receiver_balance, unused_amount);
let transfer = Nep141Transfer {
sender_id: &receiver_id,
receiver_id: &sender_id,
sender_id: receiver_id.into(),
receiver_id: sender_id.into(),
amount: refund_amount,
memo: None,
msg: None,
Expand Down
2 changes: 1 addition & 1 deletion macros/src/standard/nep148.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ pub fn expand(meta: Nep148Meta) -> Result<TokenStream, darling::Error> {

#[#near_sdk::near]
impl #imp #me::standard::nep148::Nep148 for #ident #ty #wher {
fn ft_metadata(&self) -> #me::standard::nep148::FungibleTokenMetadata {
fn ft_metadata(&self) -> #me::standard::nep148::ContractMetadata {
#me::standard::nep148::Nep148Controller::get_metadata(self)
}
}
Expand Down
45 changes: 21 additions & 24 deletions macros/src/standard/nep171.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,13 +104,11 @@ pub fn expand(meta: Nep171Meta) -> Result<TokenStream, darling::Error> {
};

if should_revert {
let token_ids = [token_id];

let transfer = action::Nep171Transfer {
token_id: &token_ids[0],
token_id,
authorization: Nep171TransferAuthorization::Owner,
sender_id: &receiver_id,
receiver_id: &previous_owner_id,
sender_id: receiver_id.into(),
receiver_id: previous_owner_id.into(),
memo: None,
msg: None,
revert: true,
Expand Down Expand Up @@ -140,14 +138,12 @@ pub fn expand(meta: Nep171Meta) -> Result<TokenStream, darling::Error> {

let sender_id = #near_sdk::env::predecessor_account_id();

let token_ids = [token_id];

let transfer = action::Nep171Transfer {
token_id: &token_ids[0],
token_id,
authorization: approval_id.map(Nep171TransferAuthorization::ApprovalId).unwrap_or(Nep171TransferAuthorization::Owner),
sender_id: &sender_id,
receiver_id: &receiver_id,
memo: memo.as_deref(),
sender_id: sender_id.into(),
receiver_id: receiver_id.into(),
memo: memo.map(Into::into),
msg: None,
revert: false,
};
Expand Down Expand Up @@ -176,35 +172,36 @@ pub fn expand(meta: Nep171Meta) -> Result<TokenStream, darling::Error> {

let sender_id = #near_sdk::env::predecessor_account_id();

let token_ids = [token_id];

let transfer = action::Nep171Transfer {
token_id: &token_ids[0],
token_id: token_id.clone(),
authorization: approval_id.map(Nep171TransferAuthorization::ApprovalId).unwrap_or(Nep171TransferAuthorization::Owner),
sender_id: &sender_id,
receiver_id: &receiver_id,
memo: memo.as_deref(),
msg: Some(&msg),
sender_id: sender_id.clone().into(),
receiver_id: receiver_id.clone().into(),
memo: memo.map(Into::into),
msg: Some(msg.clone().into()),
revert: false,
};

<Self as Nep171Controller>::external_transfer(self, &transfer)
.unwrap_or_else(|e| #near_sdk::env::panic_str(&e.to_string()));

let [token_id] = token_ids;

ext_nep171_receiver::ext(receiver_id.clone())
ext_nep171_receiver::ext(receiver_id.clone().into())
.with_static_gas(#near_sdk::env::prepaid_gas().saturating_sub(GAS_FOR_NFT_TRANSFER_CALL))
.nft_on_transfer(
sender_id.clone(),
sender_id.clone(),
sender_id.clone().into(),
sender_id.clone().into(),
token_id.clone(),
msg.clone(),
)
.then(
ext_nep171_resolver::ext(#near_sdk::env::current_account_id())
.with_static_gas(GAS_FOR_RESOLVE_TRANSFER)
.nft_resolve_transfer(sender_id.clone(), receiver_id.clone(), token_id.clone(), None),
.nft_resolve_transfer(
sender_id.clone().into(),
receiver_id.clone().into(),
token_id.clone(),
None,
),
)
.into()
}
Expand Down
16 changes: 8 additions & 8 deletions macros/src/standard/nep178.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,9 @@ pub fn expand(meta: Nep178Meta) -> Result<TokenStream, darling::Error> {
let predecessor = #near_sdk::env::predecessor_account_id();

let action = action::Nep178Approve {
token_id: &token_id,
current_owner_id: &predecessor,
account_id: &account_id,
token_id: token_id.clone(),
current_owner_id: predecessor.clone().into(),
account_id: account_id.clone().into(),
};

let approval_id = Nep178Controller::approve(self, &action)
Expand All @@ -107,9 +107,9 @@ pub fn expand(meta: Nep178Meta) -> Result<TokenStream, darling::Error> {
let predecessor = #near_sdk::env::predecessor_account_id();

let action = action::Nep178Revoke {
token_id: &token_id,
current_owner_id: &predecessor,
account_id: &account_id,
token_id,
current_owner_id: predecessor.into(),
account_id: account_id.into(),
};

Nep178Controller::revoke(self, &action)
Expand All @@ -125,8 +125,8 @@ pub fn expand(meta: Nep178Meta) -> Result<TokenStream, darling::Error> {
let predecessor = #near_sdk::env::predecessor_account_id();

let action = action::Nep178RevokeAll {
token_id: &token_id,
current_owner_id: &predecessor,
token_id,
current_owner_id: predecessor.into(),
};

Nep178Controller::revoke_all(self, &action)
Expand Down
8 changes: 4 additions & 4 deletions macros/src/standard/nep297.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,11 +153,11 @@ pub fn expand(meta: Nep297Meta) -> Result<TokenStream, darling::Error> {
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,
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ pub mod ft {
StorageBalance, StorageBalanceBounds,
},
nep148::{
self, ext_nep148, FungibleTokenMetadata, Nep148, Nep148Controller,
self, ext_nep148, ContractMetadata, Nep148, Nep148Controller,
Nep148ControllerInternal,
},
},
Expand Down
15 changes: 12 additions & 3 deletions src/slot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//!
//! Makes it easy to create and manage storage keys and avoid unnecessary
//! writes to contract storage. This reduces transaction IO and saves on gas.
use std::marker::PhantomData;
use std::{marker::PhantomData, ops::Deref};

use near_sdk::{
borsh::{self, BorshDeserialize, BorshSerialize},
Expand Down Expand Up @@ -95,9 +95,18 @@ impl<T> Slot<T> {
}

impl<T: BorshSerialize> Slot<T> {
/// Writes a value to the managed storage slot
/// Writes a value to the managed storage slot.
pub fn write(&mut self, value: &T) -> bool {
self.write_raw(&{ borsh::to_vec(&value) }.unwrap())
self.write_raw(&borsh::to_vec(value).unwrap())
}

/// Writes a value to the managed storage slot which is dereferenced from
/// the target type.
pub fn write_deref<U: BorshSerialize + ?Sized>(&mut self, value: &U) -> bool
where
T: Deref<Target = U>,
{
self.write_raw(&borsh::to_vec(value).unwrap())
}

/// If the given value is `Some(T)`, writes `T` to storage. Otherwise,
Expand Down
Loading

0 comments on commit 0d1ae85

Please sign in to comment.