Implement NFT standards with proper metadata handling

by wshobson · MIT license · ★ 39,857 on GitHub · updated Sep 21

Nft standards cover

Implement NFT standards (ERC-721, ERC-1155) with proper metadata handling, minting strategies, and marketplace integration. Use when creating NFT contracts, building NFT marketplaces, or implementing digital asset systems.

---
name: nft-standards
description: Implement NFT standards (ERC-721, ERC-1155) with proper metadata handling, minting strategies, and marketplace integration. Use when creating NFT contracts, building NFT marketplaces, or implementing digital asset systems.
---

# NFT Standards

Master ERC-721 and ERC-1155 NFT standards, metadata best practices, and advanced NFT features.

## When to Use This Skill

- Creating NFT collections (art, gaming, collectibles)
- Implementing marketplace functionality
- Building on-chain or off-chain metadata
- Creating soulbound tokens (non-transferable)
- Implementing royalties and revenue sharing
- Developing dynamic/evolving NFTs

Overview

Master ERC-721 and ERC-1155 NFT standards, metadata best practices, and advanced NFT features.

Manual install (npx, ZIP)
Claude Codenpx skills add wshobson/agents --skill nft-standards -g -a claude-code
Claude Code (manual)mkdir -p ~/.claude/skills && curl -sL https://codeload.github.com/wshobson/agents/tar.gz/4236bb91f839 \ | tar -xz -C ~/.claude/skills --strip-components=4 agents-4236bb91f839/plugins/blockchain-web3/skills/nft-standards
Windows (PowerShell)New-Item -ItemType Directory -Force "$HOME\.claude\skills" | Out-Null; Invoke-WebRequest "https://m.agentalley.io/zip/7d1bbfe223ba8e0ebd51/nft-standards.zip" -OutFile "$env:TEMP\nft-standards.zip"; Expand-Archive "$env:TEMP\nft-standards.zip" -DestinationPath "$HOME\.claude\skills" -Force
Claude.ai / desktopDownload the ZIP and upload it under Settings → Capabilities → Skills.
Codex, Cursor, other agentsPoint them at SKILL.md. The other files are plain text.

Connects with Agent Alley MCP · agentalley.io/mcp

Files included

  • SKILL.md7.5 KB
  • references/1 file · 2.5 KB
Read the files here
wshobson/4236bb92 files
SKILL.md
Show the full text264 lines

NFT Standards

Master ERC-721 and ERC-1155 NFT standards, metadata best practices, and advanced NFT features.

When to Use This Skill

  • Creating NFT collections (art, gaming, collectibles)
  • Implementing marketplace functionality
  • Building on-chain or off-chain metadata
  • Creating soulbound tokens (non-transferable)
  • Implementing royalties and revenue sharing
  • Developing dynamic/evolving NFTs

ERC-721 (Non-Fungible Token Standard)

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

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

contract MyNFT is ERC721URIStorage, ERC721Enumerable, Ownable {
    using Counters for Counters.Counter;
    Counters.Counter private _tokenIds;

    uint256 public constant MAX_SUPPLY = 10000;
    uint256 public constant MINT_PRICE = 0.08 ether;
    uint256 public constant MAX_PER_MINT = 20;

    constructor() ERC721("MyNFT", "MNFT") {}

    function mint(uint256 quantity) external payable {
        require(quantity > 0 && quantity <= MAX_PER_MINT, "Invalid quantity");
        require(_tokenIds.current() + quantity <= MAX_SUPPLY, "Exceeds max supply");
        require(msg.value >= MINT_PRICE * quantity, "Insufficient payment");

        for (uint256 i = 0; i < quantity; i++) {
            _tokenIds.increment();
            uint256 newTokenId = _tokenIds.current();
            _safeMint(msg.sender, newTokenId);
            _setTokenURI(newTokenId, generateTokenURI(newTokenId));
        }
    }

    function generateTokenURI(uint256 tokenId) internal pure returns (string memory) {
        // Return IPFS URI or on-chain metadata
        return string(abi.encodePacked("ipfs://QmHash/", Strings.toString(tokenId), ".json"));
    }

    // Required overrides
    function _beforeTokenTransfer(
        address from,
        address to,
        uint256 tokenId,
        uint256 batchSize
    ) internal override(ERC721, ERC721Enumerable) {
        super._beforeTokenTransfer(from, to, tokenId, batchSize);
    }

    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);
    }

    function supportsInterface(bytes4 interfaceId)
        public
        view
        override(ERC721, ERC721Enumerable)
        returns (bool)
    {
        return super.supportsInterface(interfaceId);
    }

    function withdraw() external onlyOwner {
        payable(owner()).transfer(address(this).balance);
    }
}

ERC-1155 (Multi-Token Standard)

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

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

contract GameItems is ERC1155, Ownable {
    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("ipfs://QmBaseHash/{id}.json") {
        maxSupply[SWORD] = 1000;
        maxSupply[SHIELD] = 500;
        maxSupply[POTION] = 10000;
    }

    function mint(
        address to,
        uint256 id,
        uint256 amount
    ) external 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
    ) external onlyOwner {
        for (uint256 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 burn(
        address from,
        uint256 id,
        uint256 amount
    ) external {
        require(from == msg.sender || isApprovedForAll(from, msg.sender), "Not authorized");
        _burn(from, id, amount);
        tokenSupply[id] -= amount;
    }
}

Metadata Standards

Off-Chain Metadata (IPFS)
{
  "name": "NFT #1",
  "description": "Description of the NFT",
  "image": "ipfs://QmImageHash",
  "attributes": [
    {
      "trait_type": "Background",
      "value": "Blue"
    },
    {
      "trait_type": "Rarity",
      "value": "Legendary"
    },
    {
      "trait_type": "Power",
      "value": 95,
      "display_type": "number",
      "max_value": 100
    }
  ]
}
On-Chain Metadata
contract OnChainNFT is ERC721 {
    struct Traits {
        uint8 background;
        uint8 body;
        uint8 head;
        uint8 rarity;
    }

    mapping(uint256 => Traits) public tokenTraits;

    function tokenURI(uint256 tokenId) public view override returns (string memory) {
        Traits memory traits = tokenTraits[tokenId];

        string memory json = Base64.encode(
            bytes(
                string(
                    abi.encodePacked(
                        '{"name": "NFT #', Strings.toString(tokenId), '",',
                        '"description": "On-chain NFT",',
                        '"image": "data:image/svg+xml;base64,', generateSVG(traits), '",',
                        '"attributes": [',
                        '{"trait_type": "Background", "value": "', Strings.toString(traits.background), '"},',
                        '{"trait_type": "Rarity", "value": "', getRarityName(traits.rarity), '"}',
                        ']}'
                    )
                )
            )
        );

        return string(abi.encodePacked("data:application/json;base64,", json));
    }

    function generateSVG(Traits memory traits) internal pure returns (string memory) {
        // Generate SVG based on traits
        return "...";
    }
}

Royalties (EIP-2981)

import "@openzeppelin/contracts/interfaces/IERC2981.sol";

contract NFTWithRoyalties is ERC721, IERC2981 {
    address public royaltyRecipient;
    uint96 public royaltyFee = 500; // 5%

    constructor() ERC721("Royalty NFT", "RNFT") {
        royaltyRecipient = msg.sender;
    }

    function royaltyInfo(uint256 tokenId, uint256 salePrice)
        external
        view
        override
        returns (address receiver, uint256 royaltyAmount)
    {
        return (royaltyRecipient, (salePrice * royaltyFee) / 10000);
    }

    function setRoyalty(address recipient, uint96 fee) external onlyOwner {
        require(fee <= 1000, "Royalty fee too high"); // Max 10%
        royaltyRecipient = recipient;
        royaltyFee = fee;
    }

    function supportsInterface(bytes4 interfaceId)
        public
        view
        override(ERC721, IERC165)
        returns (bool)
    {
        return interfaceId == type(IERC2981).interfaceId ||
               super.supportsInterface(interfaceId);
    }
}

Additional patterns and templates

More detailed templates and worked examples live in references/details.md. Read that file for the full pattern library.

1---
2name: nft-standards
3description: Implement NFT standards (ERC-721, ERC-1155) with proper metadata handling, minting strategies, and marketplace integration. Use when creating NFT contracts, building NFT marketplaces, or implementing digital asset systems.
4---
5 
6# NFT Standards
7 
8Master ERC-721 and ERC-1155 NFT standards, metadata best practices, and advanced NFT features.
9 
10## When to Use This Skill
11 
12- Creating NFT collections (art, gaming, collectibles)
13- Implementing marketplace functionality
14- Building on-chain or off-chain metadata
15- Creating soulbound tokens (non-transferable)
16- Implementing royalties and revenue sharing
17- Developing dynamic/evolving NFTs
18 
19## ERC-721 (Non-Fungible Token Standard)
20 
21```solidity
22// SPDX-License-Identifier: MIT
23pragma solidity ^0.8.0;
24 
25import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
26import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
27import "@openzeppelin/contracts/access/Ownable.sol";
28import "@openzeppelin/contracts/utils/Counters.sol";
29 
30contract MyNFT is ERC721URIStorage, ERC721Enumerable, Ownable {
31 using Counters for Counters.Counter;
32 Counters.Counter private _tokenIds;
33 
34 uint256 public constant MAX_SUPPLY = 10000;
35 uint256 public constant MINT_PRICE = 0.08 ether;
36 uint256 public constant MAX_PER_MINT = 20;
37 
38 constructor() ERC721("MyNFT", "MNFT") {}
39 
40 function mint(uint256 quantity) external payable {
41 require(quantity > 0 && quantity <= MAX_PER_MINT, "Invalid quantity");
42 require(_tokenIds.current() + quantity <= MAX_SUPPLY, "Exceeds max supply");
43 require(msg.value >= MINT_PRICE * quantity, "Insufficient payment");
44 
45 for (uint256 i = 0; i < quantity; i++) {
46 _tokenIds.increment();
47 uint256 newTokenId = _tokenIds.current();
48 _safeMint(msg.sender, newTokenId);
49 _setTokenURI(newTokenId, generateTokenURI(newTokenId));
50 }
51 }
52 
53 function generateTokenURI(uint256 tokenId) internal pure returns (string memory) {
54 // Return IPFS URI or on-chain metadata
55 return string(abi.encodePacked("ipfs://QmHash/", Strings.toString(tokenId), ".json"));
56 }
57 
58 // Required overrides
59 function _beforeTokenTransfer(
60 address from,
61 address to,
62 uint256 tokenId,
63 uint256 batchSize
64 ) internal override(ERC721, ERC721Enumerable) {
65 super._beforeTokenTransfer(from, to, tokenId, batchSize);
66 }
67 
68 function _burn(uint256 tokenId) internal override(ERC721, ERC721URIStorage) {
69 super._burn(tokenId);
70 }
71 
72 function tokenURI(uint256 tokenId) public view override(ERC721, ERC721URIStorage) returns (string memory) {
73 return super.tokenURI(tokenId);
74 }
75 
76 function supportsInterface(bytes4 interfaceId)
77 public
78 view
79 override(ERC721, ERC721Enumerable)
80 returns (bool)
81 {
82 return super.supportsInterface(interfaceId);
83 }
84 
85 function withdraw() external onlyOwner {
86 payable(owner()).transfer(address(this).balance);
87 }
88}
89```
90 
91## ERC-1155 (Multi-Token Standard)
92 
93```solidity
94// SPDX-License-Identifier: MIT
95pragma solidity ^0.8.0;
96 
97import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";
98import "@openzeppelin/contracts/access/Ownable.sol";
99 
100contract GameItems is ERC1155, Ownable {
101 uint256 public constant SWORD = 1;
102 uint256 public constant SHIELD = 2;
103 uint256 public constant POTION = 3;
104 
105 mapping(uint256 => uint256) public tokenSupply;
106 mapping(uint256 => uint256) public maxSupply;
107 
108 constructor() ERC1155("ipfs://QmBaseHash/{id}.json") {
109 maxSupply[SWORD] = 1000;
110 maxSupply[SHIELD] = 500;
111 maxSupply[POTION] = 10000;
112 }
113 
114 function mint(
115 address to,
116 uint256 id,
117 uint256 amount
118 ) external onlyOwner {
119 require(tokenSupply[id] + amount <= maxSupply[id], "Exceeds max supply");
120 
121 _mint(to, id, amount, "");
122 tokenSupply[id] += amount;
123 }
124 
125 function mintBatch(
126 address to,
127 uint256[] memory ids,
128 uint256[] memory amounts
129 ) external onlyOwner {
130 for (uint256 i = 0; i < ids.length; i++) {
131 require(tokenSupply[ids[i]] + amounts[i] <= maxSupply[ids[i]], "Exceeds max supply");
132 tokenSupply[ids[i]] += amounts[i];
133 }
134 
135 _mintBatch(to, ids, amounts, "");
136 }
137 
138 function burn(
139 address from,
140 uint256 id,
141 uint256 amount
142 ) external {
143 require(from == msg.sender || isApprovedForAll(from, msg.sender), "Not authorized");
144 _burn(from, id, amount);
145 tokenSupply[id] -= amount;
146 }
147}
148```
149 
150## Metadata Standards
151 
152### Off-Chain Metadata (IPFS)
153 
154```json
155{
156 "name": "NFT #1",
157 "description": "Description of the NFT",
158 "image": "ipfs://QmImageHash",
159 "attributes": [
160 {
161 "trait_type": "Background",
162 "value": "Blue"
163 },
164 {
165 "trait_type": "Rarity",
166 "value": "Legendary"
167 },
168 {
169 "trait_type": "Power",
170 "value": 95,
171 "display_type": "number",
172 "max_value": 100
173 }
174 ]
175}
176```
177 
178### On-Chain Metadata
179 
180```solidity
181contract OnChainNFT is ERC721 {
182 struct Traits {
183 uint8 background;
184 uint8 body;
185 uint8 head;
186 uint8 rarity;
187 }
188 
189 mapping(uint256 => Traits) public tokenTraits;
190 
191 function tokenURI(uint256 tokenId) public view override returns (string memory) {
192 Traits memory traits = tokenTraits[tokenId];
193 
194 string memory json = Base64.encode(
195 bytes(
196 string(
197 abi.encodePacked(
198 '{"name": "NFT #', Strings.toString(tokenId), '",',
199 '"description": "On-chain NFT",',
200 '"image": "data:image/svg+xml;base64,', generateSVG(traits), '",',
201 '"attributes": [',
202 '{"trait_type": "Background", "value": "', Strings.toString(traits.background), '"},',
203 '{"trait_type": "Rarity", "value": "', getRarityName(traits.rarity), '"}',
204 ']}'
205 )
206 )
207 )
208 );
209 
210 return string(abi.encodePacked("data:application/json;base64,", json));
211 }
212 
213 function generateSVG(Traits memory traits) internal pure returns (string memory) {
214 // Generate SVG based on traits
215 return "...";
216 }
217}
218```
219 
220## Royalties (EIP-2981)
221 
222```solidity
223import "@openzeppelin/contracts/interfaces/IERC2981.sol";
224 
225contract NFTWithRoyalties is ERC721, IERC2981 {
226 address public royaltyRecipient;
227 uint96 public royaltyFee = 500; // 5%
228 
229 constructor() ERC721("Royalty NFT", "RNFT") {
230 royaltyRecipient = msg.sender;
231 }
232 
233 function royaltyInfo(uint256 tokenId, uint256 salePrice)
234 external
235 view
236 override
237 returns (address receiver, uint256 royaltyAmount)
238 {
239 return (royaltyRecipient, (salePrice * royaltyFee) / 10000);
240 }
241 
242 function setRoyalty(address recipient, uint96 fee) external onlyOwner {
243 require(fee <= 1000, "Royalty fee too high"); // Max 10%
244 royaltyRecipient = recipient;
245 royaltyFee = fee;
246 }
247 
248 function supportsInterface(bytes4 interfaceId)
249 public
250 view
251 override(ERC721, IERC165)
252 returns (bool)
253 {
254 return interfaceId == type(IERC2981).interfaceId ||
255 super.supportsInterface(interfaceId);
256 }
257}
258```
259 
260## Additional patterns and templates
261 
262More detailed templates and worked examples live in `references/details.md`. Read that file for the full pattern library.
263 
264 
View all files on GitHub →

Details

Updated
Sep 21, 2026
License
MIT
Stars on the repo
★ 39,857
Checked
Source
wshobson/agents ↗
Creator
wshobson · 179 listings
View creator

Similar skills

See all →
MCPAgent-native x402 pay-per-call data & security APIs on BaseX402 data APIrezearcher/x402-data-api · by rezearcherAgent-native x402 pay-per-call data & security APIs on Base (crypto, DeFi, on-chain, Polymarket, MCP security scan)New listingSkillImplement DeFi protocols with production-ready templatesDefi protocol templateswshobson/agents · by wshobsonImplement DeFi protocols with production-ready templates for staking, AMMs, governance, and flash loans. Use when building decentralized finance applications or smart contract protocols.★ 39.9k GitHub starsSkillMaster smart contract security best practices to preventSolidity securitywshobson/agents · by wshobsonMaster smart contract security best practices to prevent common vulnerabilities and implement secure Solidity patterns. Use when writing smart contracts, auditing existing contracts, or implementing security measures for blockchain applications.★ 39.9k GitHub starsSkillTest smart contracts comprehensively using HardhatWeb3 Smart Contract Testingwshobson/agents · by wshobsonTest smart contracts comprehensively using Hardhat and Foundry with unit tests, integration tests, and mainnet forking. Use when testing Solidity contracts, setting up blockchain test suites, or validating DeFi protocols.★ 39.9k GitHub starsMCPBuilding smart contracts, DAppsBlockchain developerVoltAgent/awesome-claude-code-subagents · by VoltAgentUse this agent when building smart contracts, DApps, and blockchain protocols that require expertise in Solidity, gas optimization, security auditing, and Web3 integration.★ 25.2k GitHub starsSkillRequires technical rigor and verificationCode Review Receptionobra/superpowers · by obraUse when receiving code review feedback, before implementing suggestions, especially if feedback seems unclear or technically questionable - requires technical rigor and verification, not performative agreement or blind implementation★ 290k GitHub stars

More from wshobson

SkillMaster C/.NET backend development patterns for buildingwshobson/agents · by wshobsonMaster C#/.NET backend development patterns for building robust APIs, MCP servers, and enterprise applications. Covers async/await, dependency injection, Entity Framework Core, Dapper, configuration, caching, and testing with xUnit. Use when developing .NET backends, reviewing C# code, or designing API architectures.★ 39.9k GitHub starsSkillImplement WCAG 2.2 compliant interfaces with mobileAccessibility compliancewshobson/agents · by wshobsonImplement WCAG 2.2 compliant interfaces with mobile accessibility, inclusive design patterns, and assistive technology support. Use when auditing accessibility, implementing ARIA patterns, building for screen readers, or ensuring inclusive user experiences.★ 39.9k GitHub starsSkillMaster Material Design 3 and Jetpack Compose patternsAndroid Mobile Designwshobson/agents · by wshobsonMaster Material Design 3 and Jetpack Compose patterns for building native Android apps. Use when designing Android interfaces, implementing Compose UI, or following Google's Material Design guidelines.★ 39.9k GitHub starsSkillMigrate from AngularJS to Angular using hybrid modeAngular migrationwshobson/agents · by wshobsonMigrate from AngularJS to Angular using hybrid mode, incremental component rewriting, and dependency injection updates. Use when upgrading AngularJS applications, planning framework migrations, or modernizing legacy Angular code.★ 39.9k GitHub starsSkillUnderstand anti-reversing, obfuscationAnti reversing techniqueswshobson/agents · by wshobsonUnderstand anti-reversing, obfuscation, and protection techniques encountered during software analysis. Use this skill when analyzing malware evasion techniques, when implementing anti-debugging protections for CTF challenges, when reverse engineering packed binaries, or when building security research tools that need to detect virtualized environments.★ 39.9k GitHub starsSkillBuild production Apache Airflow DAGs with best practicesApache Airflow DAG Patternswshobson/agents · by wshobsonBuild production Apache Airflow DAGs with best practices for operators, sensors, testing, and deployment. Use when creating data pipelines, orchestrating workflows, or scheduling batch jobs.★ 39.9k GitHub stars