nft-development
Master NFT development with token standards, metadata, marketplaces, and on-chain art
What this skill does
# NFT Development Skill
> Master NFT development with token standards, metadata design, marketplace integration, and on-chain generative art.
## Quick Start
```python
# Invoke this skill for NFT development
Skill("nft-development", topic="standards", standard="ERC721A")
```
## Topics Covered
### 1. Token Standards
Choose the right standard:
- **ERC-721**: Standard NFTs, one token per ID
- **ERC-721A**: Gas-optimized batch minting
- **ERC-1155**: Multi-token, semi-fungible
- **DN404**: Divisible NFT hybrid
### 2. Metadata Design
Structure your NFT data:
- **On-chain**: Base64 JSON, SVG
- **IPFS**: Content-addressed storage
- **Arweave**: Permanent storage
- **Dynamic**: Evolving traits
### 3. Marketplace Integration
List and sell NFTs:
- **OpenSea**: Seaport protocol
- **Royalties**: EIP-2981
- **Operator Filter**: Royalty enforcement
- **Collection Verification**: Metadata standards
### 4. On-Chain Art
Generate art in Solidity:
- **SVG Generation**: Dynamic shapes
- **Seed-based**: Deterministic randomness
- **Traits**: Rarity distribution
- **Base64**: Data URI encoding
## Code Examples
### ERC-721A Mint
```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import "erc721a/contracts/ERC721A.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
contract MyNFT is ERC721A, Ownable {
uint256 public constant MAX_SUPPLY = 10000;
uint256 public constant PRICE = 0.08 ether;
error MaxSupplyReached();
error InsufficientPayment();
constructor() ERC721A("MyNFT", "MNFT") Ownable(msg.sender) {}
function mint(uint256 quantity) external payable {
if (_totalMinted() + quantity > MAX_SUPPLY) revert MaxSupplyReached();
if (msg.value < PRICE * quantity) revert InsufficientPayment();
_mint(msg.sender, quantity);
}
function _startTokenId() internal pure override returns (uint256) {
return 1;
}
}
```
### On-Chain SVG
```solidity
function tokenURI(uint256 tokenId) public view returns (string memory) {
uint256 seed = seeds[tokenId];
string memory svg = string(abi.encodePacked(
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 400">',
'<rect width="400" height="400" fill="#', _getColor(seed), '"/>',
'<circle cx="200" cy="200" r="80" fill="#', _getColor(seed >> 24), '"/>',
'</svg>'
));
string memory json = string(abi.encodePacked(
'{"name":"Art #', tokenId.toString(),
'","image":"data:image/svg+xml;base64,', Base64.encode(bytes(svg)), '"}'
));
return string(abi.encodePacked(
"data:application/json;base64,",
Base64.encode(bytes(json))
));
}
```
### EIP-2981 Royalties
```solidity
import "@openzeppelin/contracts/token/common/ERC2981.sol";
contract NFTWithRoyalty is ERC721A, ERC2981 {
constructor() {
_setDefaultRoyalty(msg.sender, 500); // 5%
}
function supportsInterface(bytes4 interfaceId)
public view override(ERC721A, ERC2981)
returns (bool)
{
return super.supportsInterface(interfaceId);
}
}
```
## Metadata Schema
### ERC-721 Standard
```json
{
"name": "Cool NFT #1",
"description": "A very cool NFT",
"image": "ipfs://QmXxx.../1.png",
"animation_url": "ipfs://QmXxx.../1.mp4",
"external_url": "https://example.com/1",
"attributes": [
{ "trait_type": "Background", "value": "Blue" },
{ "trait_type": "Rarity", "value": "Legendary" },
{ "display_type": "number", "trait_type": "Power", "value": 100 }
]
}
```
## Standard Comparison
| Standard | Best For | Gas (1 mint) | Gas (5 mints) |
|----------|----------|--------------|---------------|
| ERC-721 | Simple NFTs | ~100k | ~500k |
| ERC-721A | PFP collections | ~100k | ~120k |
| ERC-1155 | Game items | ~50k | ~80k |
## Common Pitfalls
| Pitfall | Issue | Solution |
|---------|-------|----------|
| Metadata not showing | Bad tokenURI | Validate JSON, check CORS |
| Gas too high | Standard ERC-721 | Use ERC-721A for batches |
| Royalties not paid | Marketplaces ignore | Use operator filter |
| Reveal broken | Wrong base URI | Test on testnet first |
## Troubleshooting
### "Metadata not showing on OpenSea"
1. Verify tokenURI returns valid JSON
2. Check IPFS gateway accessibility
3. Refresh metadata via API:
```bash
curl "https://api.opensea.io/api/v2/chain/ethereum/contract/{addr}/nfts/{id}/refresh"
```
### "Batch mint out of gas"
- Use ERC-721A instead of ERC-721
- Limit batch size to 10-20 per tx
### "Royalties not enforced"
Implement operator filter:
```solidity
import "operator-filter-registry/src/DefaultOperatorFilterer.sol";
function setApprovalForAll(address op, bool approved)
public override onlyAllowedOperatorApproval(op)
{
super.setApprovalForAll(op, approved);
}
```
## Gas Optimization
| Technique | Savings |
|-----------|---------|
| ERC721A batching | ~80% for batches |
| Merkle whitelist | ~50% vs mapping |
| Packed storage | ~20k per slot |
| Custom errors | ~200 per error |
## Cross-References
- **Bonded Agent**: `07-nft-development`
- **Related Skills**: `solidity-development`, `web3-frontend`
## Resources
- ERC-721: eips.ethereum.org/EIPS/eip-721
- ERC-721A: erc721a.org
- OpenSea Metadata: docs.opensea.io/docs/metadata-standards
## Version History
| Version | Date | Changes |
|---------|------|---------|
| 2.0.0 | 2025-01 | Production-grade with standards, on-chain |
| 1.0.0 | 2024-12 | Initial release |
Related in General
modeling-omnistudio-epc-catalog
IncludedSalesforce Industries CME EPC product-modeling skill for Product2-based catalog creation. Use when creating EPC products, configuring product attributes, building offer bundles with Product Child Items, or reviewing EPC DataPack JSON metadata for product catalog changes. TRIGGER when: user creates or updates Product2 EPC records, AttributeAssignment payloads, AttributeMetadata/AttributeDefaultValues, Offer bundles, or ProductChildItem relationships. DO NOT TRIGGER when: designing OmniScripts/FlexCards/Integration Procedures (use building-omnistudio-omniscript, building-omnistudio-flexcard, or building-omnistudio-integration-procedure), implementing Apex business logic (use generating-apex), or troubleshooting deployment pipelines (use deploying-metadata).
relationship-science-coach
IncludedUse this skill for direct, practical adult relationship coaching: couples conflict, repair, trust, marriage, dating, flirting, attachment patterns, emotional connection, sex, desire differences, eroticism, kink negotiation, affection, love languages, breakups, and long-term passion. Draw on Gottman, EFT and Hold Me Tight, attachment science, modern sex research, Perel, Nagoski, Kerner, Schnarch, Love and Stosny, and flexible love-language tools. Be concrete and low-hedge. Redirect only for imminent danger, abuse, coercive control, minors, non-consent, self-harm, stalking, or medical/legal/psychiatric decisions.
building-sf-integrations
IncludedSalesforce integration architecture and runtime plumbing with 120-point scoring. Use this skill to set up Named Credentials, External Credentials, External Services, REST/SOAP callout patterns, Platform Events, and Change Data Capture. TRIGGER when: user sets up Named Credentials, External Services, REST/SOAP callouts, Platform Events, CDC, or touches .namedCredential-meta.xml files. DO NOT TRIGGER when: Connected App/OAuth config (use configuring-connected-apps), Apex-only logic (use generating-apex), or data import/export (use handling-sf-data).
venue-templates
IncludedAccess comprehensive LaTeX templates, formatting requirements, and submission guidelines for major scientific publication venues (Nature, Science, PLOS, IEEE, ACM), academic conferences (NeurIPS, ICML, CVPR, CHI), research posters, and grant proposals (NSF, NIH, DOE, DARPA). This skill should be used when preparing manuscripts for journal submission, conference papers, research posters, or grant proposals and need venue-specific formatting requirements and templates.
let-fate-decide
IncludedDraws the 12 Houses of the Zodiac Tarot spread to inject entropy into planning when prompts are vague, ambiguous, or casually delegated. Interprets the spread to guide next steps. Use when the user says 'let fate decide', 'YOLO', 'whatever', 'idk', or other nonchalant phrases, makes Yu-Gi-Oh references, or when you are about to arbitrarily pick between multiple reasonable approaches. Prefer over ask-questions-if-underspecified when the user's tone is casual or playful rather than precision-seeking.
net-ops
IncludedCross-platform network troubleshooting (Windows, macOS, Linux) via local or remote shell. Use for: DNS broken, can't resolve hostnames, nslookup/dig works but apps fail, NRPT, WFP, scutil, /etc/resolver, systemd-resolved, /etc/resolv.conf, NetworkManager, VPN DNS leak residue (ProtonVPN/Mullvad/WireGuard/AnyConnect), AV/firewall blocking DNS or DoH, Tailscale DNS interaction, intermittent connectivity, remote diagnostics over SSH.