Documentation/Smart Contracts/NFT Standards
Smart Contracts • NFT Standards

NFT Standards (ERC-721 & ERC-1155)

Create and deploy non-fungible tokens (NFTs) on Tetreum Testnet using industry-standard protocols.

What are NFTs?

Non-Fungible Tokens (NFTs) are unique digital assets that represent ownership of specific items or content on the blockchain. Unlike ERC-20 tokens, each NFT has distinct properties and value.

ERC-721 (Single NFTs)

  • • Each token is completely unique
  • • One token per transaction
  • • Perfect for art, collectibles
  • • Simple ownership model
  • • Most widely adopted standard

ERC-1155 (Multi-Token)

  • • Multiple token types in one contract
  • • Batch transfers for efficiency
  • • Gaming items, utility tokens
  • • Fungible and non-fungible support
  • • Gas-efficient operations
ERC-721 Implementation

Basic ERC-721 NFT contract using OpenZeppelin:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Counters.sol";

contract MyNFT is ERC721, ERC721URIStorage, Ownable {
    using Counters for Counters.Counter;
    Counters.Counter private _tokenIds;
    
    uint256 public constant MAX_SUPPLY = 10000;
    uint256 public constant MINT_PRICE = 0.01 ether;
    
    constructor() ERC721("MyNFT Collection", "MYNFT") {}
    
    function mintNFT(address recipient, string memory tokenURI) 
        public onlyOwner returns (uint256) {
        require(_tokenIds.current() < MAX_SUPPLY, "Max supply reached");
        
        _tokenIds.increment();
        uint256 newItemId = _tokenIds.current();
        
        _mint(recipient, newItemId);
        _setTokenURI(newItemId, tokenURI);
        
        return newItemId;
    }
    
    function publicMint(string memory tokenURI) public payable returns (uint256) {
        require(msg.value >= MINT_PRICE, "Insufficient payment");
        require(_tokenIds.current() < MAX_SUPPLY, "Max supply reached");
        
        return mintNFT(msg.sender, tokenURI);
    }
    
    function withdraw() public onlyOwner {
        payable(owner()).transfer(address(this).balance);
    }
    
    // Override required by Solidity
    function _burn(uint256 tokenId) internal override(ERC721, ERC721URIStorage) {
        super._burn(tokenId);
    }
    
    function tokenURI(uint256 tokenId) 
        public view override(ERC721, ERC721URIStorage) returns (string memory) {
        return super.tokenURI(tokenId);
    }
}
ERC-1155 Implementation

Multi-token standard contract for gaming and utility NFTs:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Strings.sol";

contract GameItems is ERC1155, Ownable {
    using Strings for uint256;
    
    // Token IDs
    uint256 public constant SWORD = 1;
    uint256 public constant SHIELD = 2;
    uint256 public constant POTION = 3;
    
    mapping(uint256 => uint256) public tokenSupply;
    mapping(uint256 => uint256) public maxSupply;
    
    constructor() ERC1155("https://api.gameserver.com/metadata/{id}.json") {
        // Set max supplies
        maxSupply[SWORD] = 1000;
        maxSupply[SHIELD] = 2000;
        maxSupply[POTION] = 10000;
        
        // Mint initial supply to owner
        _mint(msg.sender, SWORD, 100, "");
        _mint(msg.sender, SHIELD, 200, "");
        _mint(msg.sender, POTION, 1000, "");
        
        tokenSupply[SWORD] = 100;
        tokenSupply[SHIELD] = 200;
        tokenSupply[POTION] = 1000;
    }
    
    function mint(address to, uint256 id, uint256 amount) public onlyOwner {
        require(tokenSupply[id] + amount <= maxSupply[id], "Exceeds max supply");
        
        _mint(to, id, amount, "");
        tokenSupply[id] += amount;
    }
    
    function mintBatch(address to, uint256[] memory ids, uint256[] memory amounts) 
        public onlyOwner {
        for (uint i = 0; i < ids.length; i++) {
            require(tokenSupply[ids[i]] + amounts[i] <= maxSupply[ids[i]], 
                "Exceeds max supply");
            tokenSupply[ids[i]] += amounts[i];
        }
        
        _mintBatch(to, ids, amounts, "");
    }
    
    function uri(uint256 tokenId) public view override returns (string memory) {
        return string(abi.encodePacked(
            "https://api.gameserver.com/metadata/",
            tokenId.toString(),
            ".json"
        ));
    }
}
Metadata Standards

NFT metadata follows a standard JSON format for interoperability:

Standard Metadata Format

{
  "name": "Amazing NFT #1",
  "description": "This is an amazing NFT with unique properties",
  "image": "https://ipfs.io/ipfs/QmYourImageHash",
  "external_url": "https://yourwebsite.com/nft/1",
  "attributes": [
    {
      "trait_type": "Rarity",
      "value": "Legendary"
    },
    {
      "trait_type": "Power",
      "value": 95,
      "max_value": 100
    },
    {
      "trait_type": "Element",
      "value": "Fire"
    }
  ]
}

Storage Options

IPFS (Recommended)

Decentralized, immutable storage for true NFT permanence

Arweave

Permanent storage with one-time payment model

Cloud Storage

Traditional hosting (less decentralized)

On-chain SVG

Fully on-chain generative art and metadata

Advanced NFT Features

Royalties (EIP-2981)

Automatic creator royalties on secondary sales

function royaltyInfo(uint256, uint256 salePrice)

Enumerable Extension

Query tokens by owner and iterate collections

ERC721Enumerable

Burnable Tokens

Allow token holders to destroy their NFTs

ERC721Burnable

Pausable Transfers

Emergency pause functionality for security

ERC721Pausable

Launch Your NFT Collection

Create unique digital assets and build thriving NFT communities on Tetreum Testnet.