NEP-148: Fungible token metadata
NEP-148 fungible token metadata on NEAR: the ft_metadata view, the "ft-1.0.0" spec string, name, symbol, decimals and an inline data-URL icon.
Intermediate6 min read3-question check
NEP-141 moves raw integers around; it says nothing about what the token is called or where the decimal point goes. NEP-148 adds a single view method, ft_metadata(), that returns the token’s display information. Wallets and explorers call it once and cache the result.
The metadata object#
| Field | Type | Meaning |
|---|---|---|
spec | string | Must be "ft-1.0.0" for this version of the standard. |
name | string | Human-readable name, e.g. "Wrapped NEAR fungible token". |
symbol | string | Ticker, e.g. "wNEAR". |
icon | string or null | An image, ideally a small data URL (SVG preferred) so it renders without fetching anything. |
reference | string or null | Link to a JSON file with extra off-chain info (IPFS/Arweave/HTTPS). |
reference_hash | string or null | Base64-encoded sha256 of the reference JSON; required if reference is set. |
decimals | number (u8) | How many decimal places the integer amounts use. wNEAR uses 24 (like NEAR); USDC and USDT use 6. |
JSON
{
"spec": "ft-1.0.0",
"name": "Example Token",
"symbol": "EXT",
"icon": "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Ccircle cx='16' cy='16' r='16' fill='%2300EC97'/%3E%3C/svg%3E",
"reference": null,
"reference_hash": null,
"decimals": 18
}Solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract ExampleToken is ERC20 {
constructor() ERC20("Example Token", "EXT") {
_mint(msg.sender, 1_000_000 * 10 ** decimals());
}
// decimals() defaults to 18; no icon in the standard
}Rust
use near_contract_standards::fungible_token::metadata::{
FungibleTokenMetadata, FungibleTokenMetadataProvider, FT_METADATA_SPEC,
};
use near_contract_standards::fungible_token::FungibleToken;
use near_sdk::{near, PanicOnDefault};
#[near(contract_state)]
#[derive(PanicOnDefault)]
pub struct Contract {
token: FungibleToken,
metadata: FungibleTokenMetadata,
}
#[near]
impl Contract {
#[init]
pub fn new() -> Self {
let metadata = FungibleTokenMetadata {
spec: FT_METADATA_SPEC.to_string(), // "ft-1.0.0"
name: "Example Token".to_string(),
symbol: "EXT".to_string(),
icon: Some("data:image/svg+xml,...".to_string()),
reference: None,
reference_hash: None,
decimals: 18,
};
metadata.assert_valid();
// ...register the owner and mint the initial supply here
Self { token: FungibleToken::new(b"t"), metadata }
}
}
#[near]
impl FungibleTokenMetadataProvider for Contract {
fn ft_metadata(&self) -> FungibleTokenMetadata {
self.metadata.clone()
}
}Coming from EVM
ERC-20 splits metadata into three optional getters (name(), symbol(), decimals()). NEP-148 returns one object, adds an icon, and pins a spec version string.
assert_valid() checks the spec string and that reference and reference_hash are set together.
Check yourself
3 questions · progress saved in this browser