Skip to main content

NEAR NFT standards

An NFT contract is represented by a struct Contract:

Rust smart contract implementation
#[near_bindgen]
#[derive(BorshDeserialize, BorshSerialize, PanicOnDefault)]
pub struct Contract {
tokens: NonFungibleToken,
metadata: LazyOption<NFTContractMetadata>,
}

Standards used by the contract are enlisted in the StorageKey enum:

Rust smart contract implementation
#[derive(BorshSerialize, BorshStorageKey)]
enum StorageKey { // Regulating standard:
NonFungibleToken, // NEP171
Metadata, // NEP177
TokenMetadata, // NEP177
Enumeration, // NEP181
Approval, // NEP199
}

NEP-171 Core Functionality

Rust smart contract implementation
#[near_bindgen]
impl Contract {
/// Initializes the contract owned by `owner_id` with
/// default metadata (for example purposes only).
#[init]
pub fn new_default_meta(owner_id: AccountId) -> Self {
Self::new(
owner_id,
NFTContractMetadata {
spec: NFT_METADATA_SPEC.to_string(),
name: "Example NEAR non-fungible token".to_string(),
symbol: "EXAMPLE".to_string(),
icon: Some(DATA_IMAGE_SVG_NEAR_ICON.to_string()),
base_uri: None,
reference: None,
reference_hash: None,
},
)
}

#[init]
pub fn new(owner_id: AccountId, metadata: NFTContractMetadata) -> Self {
assert!(!env::state_exists(), "Already initialized");
metadata.assert_valid();
Self {
tokens: NonFungibleToken::new(
StorageKey::NonFungibleToken,
owner_id,
Some(StorageKey::TokenMetadata),
Some(StorageKey::Enumeration),
Some(StorageKey::Approval),
),
metadata: LazyOption::new(StorageKey::Metadata, Some(&metadata)),
}
}

#[payable]
pub fn nft_mint(
&mut self,
token_id: TokenId,
receiver_id: AccountId,
token_metadata: TokenMetadata,
) -> Token {
self.tokens.mint(token_id, receiver_id, Some(token_metadata))
}
}

/// Adding NEP171 implementation for the contract
near_contract_standards::impl_non_fungible_token_core!(Contract, tokens);

NEP-178 Approval

Rust smart contract implementation
/// Adding NEP171 implementation for the contract
near_contract_standards::impl_non_fungible_token_approval!(Contract, tokens);

NEP-177 Metadata

Rust smart contract implementation
/// Adding NEP177 implementation for the contract
impl NonFungibleTokenMetadataProvider for Contract {
fn nft_metadata(&self) -> NFTContractMetadata {
self.metadata.get().unwrap()
}
}

Metadata is applicable on two levels: contract & token.

1. TypeScript Contract Metadata
type NFTContractMetadata = {
spec: string, // required, MUST be formatted like: "nft-2.0.0"
name: string, // required, the human-readable name of the contract.
symbol: string, // required, the abbreviated symbol of the contract, like XPNFT
icon: string|null, // URL of a small image associated with this contract.
base_uri: string|null, // A gateway known to have reliable access to decentralized storage assets
reference: string|null, // a link to a valid JSON file containing various keys offering supplementary details on the token
reference_hash: string|null, //
}
2. TypeScript Token Metadata
type TokenMetadata = { 
title: string|null, // The name of this specific token.
description: string|null, // A longer description of the token.
media: string|null, // URL to associated media. Preferably to decentralized, content-addressed storage.
media_hash: string|null, // Base64-encoded sha256 hash of content referenced by the `media` field. Required if `media` is included.
copies: number|null, // number of copies of this set of metadata in existence when token was minted.
issued_at: number|null, // When token was issued or minted, Unix epoch in milliseconds
expires_at: number|null, // When token expires, Unix epoch in milliseconds
starts_at: number|null, // When token starts being valid, Unix epoch in milliseconds
updated_at: number|null, // When token was last updated, Unix epoch in milliseconds
extra: string|null, // anything extra the NFT wants to store on-chain. Can be stringified JSON.
reference: string|null, // URL to an off-chain JSON file with more info.
reference_hash: string|null // Base64-encoded sha256 hash of JSON from reference field. Required if `reference` is included.
}

NEP-181 Enumeration

Rust smart contract implementation
/// Adding NEP181 implementation for the contract
near_contract_standards::impl_non_fungible_token_enumeration!(Contract, tokens);

NEP-199 Royalties

Rust smart contract implementation
#[derive(Serialize, Deserialize)]
#[serde(crate = "near_sdk::serde")]
pub struct Payout {
pub payout: HashMap<AccountId, U128>,
}

pub trait Payouts {

fn nft_payout(&self, token_id: String, balance: U128, max_len_payout: Option<u32>) -> Payout;

#[payable]
fn nft_transfer_payout(
&mut self,
receiver_id: AccountId,
token_id: String,
approval_id: Option<u64>,
memo: Option<String>,
balance: U128,
max_len_payout: Option<u32>,
) -> Payout {
assert_one_yocto();
let payout = self.nft_payout(token_id, balance);
self.nft_transfer(receiver_id, token_id, approval_id, memo);
payout
}
}