NFT 開発スキル。ERC721/ERC1155 トークン標準、マーケットプレイス設計、 メタデータ管理(オンチェーン・IPFS・動的 NFT)のパターンを提供する。 ユーザーが "NFT", "ERC721", "ERC1155", "マーケットプレイス", "メタデータ", "solidity-nft" 等と言った時に使用。
NFT 開発における トークン標準選択、マーケットプレイス設計、メタデータ戦略を提供するドメイン特化スキル。
ユーザーの要件から NFT の対象ドメインを判定する:
| ユースケース | リファレンス | 読み込み時の注目ポイント |
|---|---|---|
| トークン発行・ミント | references/token-standards.md | ERC721 vs ERC1155 の選択基準、ERC721A のガス最適化、ERC6551 の TBA パターン |
| マーケットプレイス構築 | references/marketplace-patterns.md | オーダーブック vs オークション、エスクロー、ロイヤリティ徴収 |
| メタデータ設計 | references/metadata-patterns.md | オンチェーン vs IPFS vs 動的 NFT、OpenSea 互換メタデータスキーマ |
複数ドメインが関連する場合(例: ミント + メタデータ)は全ての該当リファレンスを読み込む。
検証ゲート: 少なくとも 1 つのドメインが特定できること。要件が不明確な場合は AskUserQuestion で確認する。
要件に基づきトークン標準を選択する:
| 要件 | 推奨標準 | 理由 |
|---|---|---|
| 1:1 のユニークアイテム | ERC721 | 最も広くサポートされる。OpenSea / マーケットプレイス互換性が高い |
| 大量ミント(1000+) | ERC721A | ERC721 互換。バッチミントでガス 60-70% 削減 |
| 同一アイテムの複数発行 | ERC1155 | FT と NFT を同一コントラクトで管理。ゲームアイテムに最適 |
| ゲームアイテム(複数種類) | ERC1155 | balanceOf(account, tokenId) で種類別の保有数を効率的に管理 |
| NFT にウォレット機能を持たせたい | ERC6551 | NFT 自体がスマートアカウントを持ち、資産の保有・トランザクション実行が可能 |
判断が難しい場合: AskUserQuestion で「アイテムの種類数」「同一アイテムの発行数」「ガスコスト重視か機能重視か」を確認する。
検証ゲート: トークン標準が決定し、対応する OpenZeppelin / Solady / ERC721A ライブラリが利用可能であること。
solidity-core の language-patterns.md に従い NatSpec・コーディング規約を適用する。onlyOwner / Merkle proof / 署名検証)MAX_SUPPLY 上限の設定baseURI + tokenId、または個別 URI)royaltyInfo 実装検証ゲート: forge build がエラーなく完了すること。forge test で全テストがパスすること。
name, description, image フィールドが存在するかattributes が trait 表示に対応しているかtokenURI が有効な JSON を返すかroyaltyInfo が正しいアドレスと金額を返すかERC721Enumerable が必要な場合はガスコストのトレードオフを理解した上で導入しているか検証ゲート: tokenURI が有効な JSON を返し、OpenSea メタデータ標準に準拠していること。
ユーザー入力: 「10,000 体の NFT コレクションを作りたい。ホワイトリスト付きでミントしたい」
アクション:
token-standards.md + metadata-patterns.md を読み込みsrc/GenesisNFT.sol — ERC721A 継承。Merkle proof によるホワイトリスト検証、MAX_SUPPLY = 10_000、reveal 機能(初期は placeholder URI → 後で baseURI を更新)src/libraries/MerkleVerifier.sol — Merkle proof 検証ヘルパーtest/GenesisNFT.t.sol — ホワイトリスト検証、ミント上限、reveal 前後の URI テストscript/GenerateMerkleRoot.s.sol — ホワイトリストからの Merkle root 生成スクリプト結果: Merkle proof ホワイトリスト付きの ERC721A コレクションがテスト・スクリプト付きで生成される。
ユーザー入力: 「NFT のレベルが上がるとメタデータが変わるようにしたい」
アクション:
metadata-patterns.md を読み込み → 動的 NFT パターンを選択src/DynamicNFT.sol — ERC721URIStorage 継承。level mapping、levelUp 関数、tokenURI をオンチェーンで動的生成(Base64 エンコード JSON + SVG)test/DynamicNFT.t.sol — レベルアップ前後の tokenURI 変化テスト、権限チェックtokenURI がレベルに応じて正しい JSON を返すか確認結果: レベルに応じてメタデータが自動更新されるオンチェーン NFT が生成される。
ユーザー入力: 「ゲームのアイテム(剣・盾・ポーション)を NFT として発行したい。ポーションは消費可能にして」
アクション:
token-standards.md の ERC1155 セクションを読み込みsrc/GameItems.sol — ERC1155 継承。アイテム ID 定数(SWORD = 0, SHIELD = 1, POTION = 2)。mint / mintBatch、usePotion 関数(burn で消費)test/GameItems.t.sol — ミント、バッチ転送、ポーション消費、残高確認テストuri 関数が各アイテム ID に対して正しいメタデータを返すか確認結果: FT(ポーション:消費可能)と NFT(剣・盾:ユニーク)を同一コントラクトで管理するゲームアイテムが生成される。
症状: NFT が OpenSea に表示されるが、画像・属性が出ない
原因と対策:
tokenURI が無効な JSON を返す: cast call <address> "tokenURI(uint256)" <tokenId> で返り値を確認する。JSON が正しい形式か検証する。ipfs:// プレフィックスを使用しているか確認。HTTPS ゲートウェイ URL(https://ipfs.io/ipfs/...)でもアクセス可能にする。refresh_metadata を呼び出す。image フィールドの MIME タイプ: SVG の場合は data:image/svg+xml;base64,... 形式を使用する。症状: 1件ミントごとに 100k+ gas かかる
原因と対策:
_safeMint を使用: ERC721A に切り替えることで、バッチミント時のガスを 60-70% 削減できる。forge install chiru-labs/ERC721A でインストール。ERC721Enumerable の使用: Enumerable は追加のストレージ書き込みでガスが高い。不要な場合は削除する。totalSupply は counter 変数で代替可能。uint256 の tokenId カウンターを uint96 等に縮小し、struct 内でパッキングする。MaxSupplyReached でリバートする症状: まだ MAX_SUPPLY に達していないのにリバートする
原因と対策:
_tokenIdCounter が 0 始まりか 1 始まりかを確認する。MAX_SUPPLY = 10_000 で 0 始まりの場合、最後の tokenId は 9999。_tokenIdCounter + quantity > MAX_SUPPLY ではなく _tokenIdCounter + quantity <= MAX_SUPPLY で判定しているか確認する。症状: EIP-2981 を実装したが、一部のマーケットプレイスでロイヤリティが徴収されない
原因と対策:
royaltyInfo(tokenId, salePrice) が正しい金額を返すか cast call で確認する。推奨率は 2.5-7.5%。症状: NFT に紐づくアカウントの作成が失敗する
原因と対策:
createAccount に渡す implementation コントラクトが正しくデプロイされているか確認する。account() で既存アドレスを取得する。MAX_PER_TX / MAX_PER_WALLET の制限を推奨)。solidity-core を参照する。web3-frontend を参照する。