Skip to content

Commit

Permalink
chore: docs
Browse files Browse the repository at this point in the history
  • Loading branch information
encody committed Aug 26, 2023
1 parent 4ca7b90 commit 6824eb4
Show file tree
Hide file tree
Showing 6 changed files with 61 additions and 20 deletions.
4 changes: 4 additions & 0 deletions macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,10 @@ pub fn derive_nep177(input: TokenStream) -> TokenStream {
make_derive(input, standard::nep177::expand)
}

/// Adds NEP-178 non-fungible token approvals functionality to a contract.
///
/// The storage key prefix for the fields can be optionally specified (default:
/// `"~$178"`) using `#[nep178(storage_key = "<expression>")]`.
#[proc_macro_derive(Nep178, attributes(nep178))]
pub fn derive_nep178(input: TokenStream) -> TokenStream {
make_derive(input, standard::nep178::expand)
Expand Down
4 changes: 2 additions & 2 deletions macros/src/standard/nep171.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ pub fn expand(meta: Nep171Meta) -> Result<TokenStream, darling::Error> {

Ok(quote! {
impl #imp #me::standard::nep171::Nep171ControllerInternal for #ident #ty #wher {
type CheckTransfer = #check_external_transfer;
type CheckExternalTransfer = #check_external_transfer;

#root
}
Expand Down Expand Up @@ -141,7 +141,7 @@ pub fn expand(meta: Nep171Meta) -> Result<TokenStream, darling::Error> {
msg: None,
};

let check_result = <Self as Nep171Controller>::CheckTransfer::check_external_transfer(self, &transfer);
let check_result = <Self as Nep171Controller>::CheckExternalTransfer::check_external_transfer(self, &transfer);

match check_result {
Ok(_) => {
Expand Down
15 changes: 11 additions & 4 deletions src/standard/nep171/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,8 @@ pub enum Nep171TransferError {

/// Internal (storage location) methods for implementors of [`Nep171Controller`].
pub trait Nep171ControllerInternal {
type CheckTransfer: CheckExternalTransfer<Self>
/// Invoked during an external transfer.
type CheckExternalTransfer: CheckExternalTransfer<Self>
where
Self: Sized;

Expand All @@ -116,7 +117,8 @@ pub trait Nep171ControllerInternal {

/// Non-public controller interface for NEP-171 implementations.
pub trait Nep171Controller {
type CheckTransfer: CheckExternalTransfer<Self>
/// Invoked during an external transfer.
type CheckExternalTransfer: CheckExternalTransfer<Self>
where
Self: Sized;

Expand Down Expand Up @@ -197,9 +199,12 @@ pub struct Nep171Transfer<'a> {
pub msg: Option<&'a str>,
}

/// Authorization for a transfer.
#[derive(Serialize, BorshSerialize, PartialEq, Eq, Clone, Debug, Hash)]
pub enum Nep171TransferAuthorization {
/// The sender is the owner of the token.
Owner,
/// The sender holds a valid approval ID for the token.
ApprovalId(u32),
}

Expand All @@ -212,6 +217,8 @@ pub trait CheckExternalTransfer<C> {
) -> Result<AccountId, Nep171TransferError>;
}

/// Default external transfer checker. Only allows transfers by the owner of a
/// token. Does not support approval IDs.
pub struct DefaultCheckExternalTransfer;

impl<T: Nep171Controller> CheckExternalTransfer<T> for DefaultCheckExternalTransfer {
Expand Down Expand Up @@ -305,10 +312,10 @@ where
}

impl<T: Nep171ControllerInternal> Nep171Controller for T {
type CheckTransfer = <Self as Nep171ControllerInternal>::CheckTransfer;
type CheckExternalTransfer = <Self as Nep171ControllerInternal>::CheckExternalTransfer;

fn external_transfer(&mut self, transfer: &Nep171Transfer) -> Result<(), Nep171TransferError> {
match Self::CheckTransfer::check_external_transfer(self, transfer) {
match Self::CheckExternalTransfer::check_external_transfer(self, transfer) {
Ok(current_owner_id) => {
self.transfer_unchecked(
&[transfer.token_id.to_string()],
Expand Down
42 changes: 41 additions & 1 deletion src/standard/nep178.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,15 @@ use crate::{slot::Slot, standard::nep171::*, DefaultStorageKey};

pub use ext::*;

/// Type for approval IDs.
pub type ApprovalId = u32;
/// Maximum number of approvals per token.
pub const MAX_APPROVALS: ApprovalId = 32;

/// Non-fungible token metadata.
#[derive(BorshSerialize, BorshDeserialize, Debug)]
pub struct TokenApprovals {
/// The next approval ID to use. Only incremented.
pub next_approval_id: ApprovalId,

/// The list of approved accounts.
Expand Down Expand Up @@ -102,44 +105,66 @@ pub trait Nep178ControllerInternal {
}
}

/// Errors that can occur when managing non-fungible token approvals.
#[derive(Error, Debug)]
pub enum Nep178ApproveError {
/// The account is not authorized to approve the token.
#[error("Account `{account_id}` is cannot create approvals for token `{token_id}`.")]
Unauthorized {
/// The token ID.
token_id: TokenId,
/// The unauthorized account ID.
account_id: AccountId,
},
/// The account is already approved for the token.
#[error("Account {account_id} is already approved for token {token_id}.")]
AccountAlreadyApproved {
/// The token ID.
token_id: TokenId,
/// The account ID that has already been approved.
account_id: AccountId,
},
/// The token has too many approvals.
#[error(
"Too many approvals for token {token_id}, maximum is {}.",
MAX_APPROVALS
)]
TooManyApprovals { token_id: TokenId },
TooManyApprovals {
/// The token ID.
token_id: TokenId,
},
}

/// Errors that can occur when revoking non-fungible token approvals.
#[derive(Error, Debug)]
pub enum Nep178RevokeError {
/// The account is not authorized to revoke approvals for the token.
#[error("Account `{account_id}` is cannot revoke approvals for token `{token_id}`.")]
Unauthorized {
/// The token ID.
token_id: TokenId,
/// The unauthorized account ID.
account_id: AccountId,
},
/// The account is not approved for the token.
#[error("Account {account_id} is not approved for token {token_id}")]
AccountNotApproved {
/// The token ID.
token_id: TokenId,
/// The account ID that is not approved.
account_id: AccountId,
},
}

/// Errors that can occur when revoking all approvals for a non-fungible token.
#[derive(Error, Debug)]
pub enum Nep178RevokeAllError {
/// The account is not authorized to revoke approvals for the token.
#[error("Account `{account_id}` is cannot revoke approvals for token `{token_id}`.")]
Unauthorized {
/// The token ID.
token_id: TokenId,
/// The unauthorized account ID.
account_id: AccountId,
},
}
Expand Down Expand Up @@ -352,9 +377,12 @@ impl<T: Nep178ControllerInternal + Nep171Controller> Nep178Controller for T {
}
}

/// Hooks for NEP-178.
pub trait Nep178Hook<AState = (), RState = (), RAState = ()> {
/// Called before a token is approved for transfer.
fn before_nft_approve(&self, token_id: &TokenId, account_id: &AccountId) -> AState;

/// Called after a token is approved for transfer.
fn after_nft_approve(
&mut self,
token_id: &TokenId,
Expand All @@ -363,12 +391,16 @@ pub trait Nep178Hook<AState = (), RState = (), RAState = ()> {
state: AState,
);

/// Called before a token approval is revoked.
fn before_nft_revoke(&self, token_id: &TokenId, account_id: &AccountId) -> RState;

/// Called after a token approval is revoked.
fn after_nft_revoke(&mut self, token_id: &TokenId, account_id: &AccountId, state: RState);

/// Called before all approvals for a token are revoked.
fn before_nft_revoke_all(&self, token_id: &TokenId) -> RAState;

/// Called after all approvals for a token are revoked.
fn after_nft_revoke_all(&mut self, token_id: &TokenId, state: RAState);
}

Expand All @@ -380,6 +412,9 @@ mod ext {

use super::*;

/// NEP-178 external interface.
///
/// See <https://github.com/near/NEPs/blob/master/neps/nep-0178.md#interface> for more details.
#[near_sdk::ext_contract(ext_nep178)]
pub trait Nep178 {
fn nft_approve(
Expand All @@ -401,6 +436,11 @@ mod ext {
) -> bool;
}

/// NEP-178 receiver interface.
///
/// Respond to notification that contract has been granted approval for a token.
///
/// See <https://github.com/near/NEPs/blob/master/neps/nep-0178.md#approved-account-contract-interface> for more details.
#[near_sdk::ext_contract(ext_nep178_receiver)]
pub trait Nep178Receiver {
fn nft_on_approve(
Expand Down
1 change: 0 additions & 1 deletion tests/macros/standard/nep171.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ impl From<Token> for TokenRecord {
}

#[derive(NonFungibleToken, BorshDeserialize, BorshSerialize)]
// #[nep171(no_hooks, token_type = "()")]
#[non_fungible_token(no_core_hooks, no_approval_hooks)]
#[near_bindgen]
struct NonFungibleTokenNoHooks {
Expand Down
15 changes: 3 additions & 12 deletions workspaces-tests/tests/non_fungible_token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,10 +143,7 @@ async fn create_and_mint_with_metadata() {
owner_id: alice.id().parse().unwrap(),
extensions_metadata: [
("metadata".to_string(), token_meta("token_0".to_string())),
(
"approved_account_ids".to_string(),
near_sdk::serde_json::json!({}),
)
("approved_account_ids".to_string(), json!({}),)
]
.into(),
}),
Expand All @@ -158,10 +155,7 @@ async fn create_and_mint_with_metadata() {
owner_id: bob.id().parse().unwrap(),
extensions_metadata: [
("metadata".to_string(), token_meta("token_1".to_string())),
(
"approved_account_ids".to_string(),
near_sdk::serde_json::json!({}),
)
("approved_account_ids".to_string(), json!({}),)
]
.into(),
}),
Expand All @@ -173,10 +167,7 @@ async fn create_and_mint_with_metadata() {
owner_id: charlie.id().parse().unwrap(),
extensions_metadata: [
("metadata".to_string(), token_meta("token_2".to_string())),
(
"approved_account_ids".to_string(),
near_sdk::serde_json::json!({}),
)
("approved_account_ids".to_string(), json!({}),)
]
.into(),
}),
Expand Down

0 comments on commit 6824eb4

Please sign in to comment.