nft-standards

安装量: 2.9K
排名: #762

安装

npx skills add https://github.com/wshobson/agents --skill nft-standards

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

}

Soulbound Tokens (Non-Transferable) contract SoulboundToken is ERC721 { constructor() ERC721("Soulbound", "SBT") {}

function _beforeTokenTransfer(
    address from,
    address to,
    uint256 tokenId,
    uint256 batchSize
) internal virtual override {
    require(from == address(0) || to == address(0), "Token is soulbound");
    super._beforeTokenTransfer(from, to, tokenId, batchSize);
}

function mint(address to) external {
    uint256 tokenId = totalSupply() + 1;
    _safeMint(to, tokenId);
}

// Burn is allowed (user can destroy their SBT)
function burn(uint256 tokenId) external {
    require(ownerOf(tokenId) == msg.sender, "Not token owner");
    _burn(tokenId);
}

}

Dynamic NFTs contract DynamicNFT is ERC721 { struct TokenState { uint256 level; uint256 experience; uint256 lastUpdated; }

mapping(uint256 => TokenState) public tokenStates;

function gainExperience(uint256 tokenId, uint256 exp) external {
    require(ownerOf(tokenId) == msg.sender, "Not token owner");

    TokenState storage state = tokenStates[tokenId];
    state.experience += exp;

    // Level up logic
    if (state.experience >= state.level * 100) {
        state.level++;
    }

    state.lastUpdated = block.timestamp;
}

function tokenURI(uint256 tokenId) public view override returns (string memory) {
    TokenState memory state = tokenStates[tokenId];

    // Generate metadata based on current state
    return generateMetadata(tokenId, state);
}

function generateMetadata(uint256 tokenId, TokenState memory state)
    internal
    pure
    returns (string memory)
{
    // Dynamic metadata generation
    return "";
}

}

Gas-Optimized Minting (ERC721A) import "erc721a/contracts/ERC721A.sol";

contract OptimizedNFT is ERC721A { uint256 public constant MAX_SUPPLY = 10000; uint256 public constant MINT_PRICE = 0.05 ether;

constructor() ERC721A("Optimized NFT", "ONFT") {}

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

    _mint(msg.sender, quantity);
}

function _baseURI() internal pure override returns (string memory) {
    return "ipfs://QmBaseHash/";
}

}

Resources references/erc721.md: ERC-721 specification details references/erc1155.md: ERC-1155 multi-token standard references/metadata-standards.md: Metadata best practices references/enumeration.md: Token enumeration patterns assets/erc721-contract.sol: Production ERC-721 template assets/erc1155-contract.sol: Production ERC-1155 template assets/metadata-schema.json: Standard metadata format assets/metadata-uploader.py: IPFS upload utility Best Practices Use OpenZeppelin: Battle-tested implementations Pin Metadata: Use IPFS with pinning service Implement Royalties: EIP-2981 for marketplace compatibility Gas Optimization: Use ERC721A for batch minting Reveal Mechanism: Placeholder → reveal pattern Enumeration: Support walletOfOwner for marketplaces Whitelist: Merkle trees for efficient whitelisting Marketplace Integration OpenSea: ERC-721/1155, metadata standards LooksRare: Royalty enforcement Rarible: Protocol fees, lazy minting Blur: Gas-optimized trading

返回排行榜