NFTs (NEP-171)
NEP-171 is the ERC-721 of NEAR. Token ids are strings, transfers use the same transfer-and-call pattern, and NEP-177 metadata fields are stored on-chain (though the media field is usually a URL to off-chain content).
Beginner4 min read3-question check
NEP-171 is NEAR’s non-fungible-token standard — ERC-721’s counterpart. Same core idea, a few NEAR-isms: token ids are strings, transfers use the transfer-and-call pattern, and rich metadata (NEP-177) is part of the standard rather than an off-chain convention.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
interface IERC721 {
function ownerOf(uint256 tokenId) external view returns (address);
function balanceOf(address owner) external view returns (uint256);
function transferFrom(address from, address to, uint256 tokenId) external;
function approve(address to, uint256 tokenId) external;
function getApproved(uint256 tokenId) external view returns (address);
}use near_sdk::{AccountId, PromiseOrValue};
// NEP-171 core (near-contract-standards: NonFungibleTokenCore)
pub trait NonFungibleTokenCore {
fn nft_transfer(
&mut self,
receiver_id: AccountId,
token_id: String, // ids are strings, not uint256
approval_id: Option<u64>,
memo: Option<String>,
);
// transfer to a CONTRACT and call its nft_on_transfer
// (async: if the receiver rejects, nft_resolve_transfer returns the token)
fn nft_transfer_call(
&mut self,
receiver_id: AccountId,
token_id: String,
approval_id: Option<u64>,
memo: Option<String>,
msg: String,
) -> PromiseOrValue<bool>;
fn nft_token(&self, token_id: String) -> Option<Token>;
}tokenId is a `String`, not a uint256 — often a slug or a running counter rendered as text. ownerOf ↔ reading nft_token(id) (which bundles owner + metadata).
Like fungible tokens, nft_transfer_call moves the token to a contract and calls its nft_on_transfer in one step. Per-token approvals are an optional extension (NEP-178), not baked into the core the way ERC-721 approve is.
Metadata (NEP-177) and enumeration (NEP-181) are companion standards. NEP-177 fields (title, description, copies, …) are stored on-chain in contract state, but media / reference are usually URLs (IPFS, Arweave, HTTP) pointing at off-chain content, with optional media_hash / reference_hash to pin it; near-contract-standards bundles all of them behind a NonFungibleToken you embed.
Check yourself
3 questions · progress saved in this browser