Skip to content
Retr0 Academy
Tokens & NFTs on NEAR

Tokens & NFTs on NEAR · 3 min read

NEP-171 NFT Minting

Mint a soulbound or transferable NEP-171 NFT with metadata, enumeration, and a storage deposit — the same standard the diploma uses.

NEP-171 NFT Minting Contract

NEP-171 is the NEAR NFT standard. The Retr0 Academy diploma is a soulbound NEP-171 token: one per account, no nft_transfer. Your own collection can be transferable, or you can omit transfer to make it soulbound.

A NEP-171 mint, step by step.
A NEP-171 mint, step by step.

Core methods

MethodRole
nft_metadataCollection-level metadata (NEP-177)
nft_tokenOne token: owner, metadata, approved accounts
nft_transfer / nft_transfer_callChange owner (attach 1 yoctoNEAR)
nft_supply_for_owner / nft_tokens_for_ownerEnumeration (NEP-181)

Minting is not in the core standard. You add your own nft_mint (or a gated mint_diploma) and decide who may call it.

rust

use near_contract_standards::non_fungible_token::{NonFungibleToken, Token, TokenId};
use near_contract_standards::non_fungible_token::metadata::{
    NFTContractMetadata, TokenMetadata, NFT_METADATA_SPEC,
};
use near_sdk::{near, AccountId, NearToken, Promise};
 
#[near]
impl Contract {
    #[payable]
    pub fn nft_mint(
        &mut self,
        token_id: TokenId,
        receiver_id: AccountId,
        token_metadata: TokenMetadata,
    ) -> Token {
        // Charge the caller for the new storage rows, refund the rest.
        let token = self.tokens.internal_mint_with_refund(
            token_id,
            receiver_id,
            Some(token_metadata),
            Some(near_sdk::env::predecessor_account_id()),
        );
        token
    }
}

internal_mint_with_refund measures bytes, keeps storage_byte_cost() * bytes, and refunds leftover deposit to the predecessor. That is why the diploma mint asks for 0.02 NEAR but keeps less.

Soulbound vs transferable

To make a diploma-style token, do not expose nft_transfer. Callers will still be able to read nft_token and your custom verify_diploma view. If the NFT should trade, implement NonFungibleTokenCore so nft_transfer is public, and require 1 yoctoNEAR.

Metadata

Token metadata usually includes title, description, media (a URL or an on-chain data URI), and sometimes reference. Collection metadata includes name, symbol, and base_uri. The diploma art you see on X is a PNG generated by this site and pointed to from media.

Try a live token on testnet with a view call:

Read a diploma NFT from the live contract
<h1>nft_token view call</h1>
<input id="tid" value="near:demo-learner.retr0school.testnet" aria-label="Token id" />
<button type="button" id="go">Read nft_token</button>
<pre id="out">Press the button.</pre>

Edit this example in the Playground.

Open in Playground

Exercise

Decide whether your collection should be transferable. If it is a credential, list the methods you would not expose. Then run the Playground nft_token example with the demo token id.