外国人がまとめた最良の契約書に見られる最も一般的な開発パターンは次のとおりです。
- ERC721Enumerable をカウンターに置き換えてガスを節約します。
- ERC721A を使用して、効率的なバッチ キャストを実現します。
- セーフミントの代わりにミントを使用してください
- マークル ツリーを使用してホワイトリスト メカニズムを実装する
- アップグレード可能/交換可能なメタデータ契約
- ロボットから守る
- NFTスナイパーの防止(レアなNFTのターゲットを絞ったキャスティング)
- 他のモード
ERC721Enumerable をカウンターに置き換えてガスを節約します。
まず、簡単な背景について説明します。ERC-721 標準は 2 つの拡張機能で構成されています。
- ERC721メタデータ
- ERC721数えられる
Core 721 標準は非常にシンプルで、Core 721 標準に準拠するには次の関数を実装するだけで済みます。
2 つの拡張機能により、上記の関数が追加されます。
では、ERC721Enumerable のどこに問題があるのでしょうか?
OpenZeppelin は、これらすべてのインターフェイスに対して既製の実装を提供します。どれも完璧ではありませんが、2 つの実装 (ERC721 と ERC721Metadata) はかなり良い仕事をします。ただし、ERC721Enumerable の実装はガスを非常に無駄にします。ガスを大量に消費し、保管スペースを無駄にします。ERC721Enumerable インターフェイスがどのように実装されているかをご覧ください。
非常に多くのマップと配列を追跡することがいかに無駄であるかは想像できるでしょう。(ちなみに、転送の前後に更新されます)。上記のコードは読み取り関数に対して (誤って) 最適化されていますが、書き込み関数に対しては最適化する必要があります (読み取り関数はほとんど無料であるため)。ほとんどの契約開発者は怠け者で、OpenZeppelin から 3 つのインターフェイスすべてを継承するだけです。しかし、もっとうまくやることもできます。
解決策: ERC721Enumerable インターフェイスに必要な関数が 1 つだけの場合は、totalSupply
整数を使用し、それをカウンターとして使用して、NFT がどれだけ鋳造されたかを追跡することができます。コントラクトでは Enumerable インターフェイス全体が実装されなくなりますが、大量のガスを節約できます。幸いなことに、ERC721 の要件を満たすには、コア ERC721 インターフェイスを実装するだけで済みます。(つまり、Enumerable インターフェイスを実装していなくても、NFT マーケットプレイスは問題なくコントラクトを解析できます)。
注意点は、tokenID から所有者へのマッピング、またはその逆のマッピングができなくなることです。ただし、この情報はイーサリアム イベントを使用してオフチェーンで追跡できます。OpenSea API はすでにこれを提供していると思います。さらに、The Graph を使用すると、Ethereum イベントに関連付けられた Web2 インフラストラクチャが簡素化されます。
コントラクトでは、次のように OZ の ERC721Enumerable を継承する代わりにカウンターを使用します。
- クリプト・コーヴン
- あずき
探索に関してはShiny Objectの功績です。
ERC721Aを使用した効率的なバッチ鋳造
ほとんどの NFT 契約は OpenZeppelin の実装を拡張します。ただし、バッチ ミント用には最適化されていません。1 回限りの鋳造と比較して、バッチ鋳造ではコストを大幅に節約できます。
たとえば、ミントごとに転送イベントを起動する代わりに、イベントを 1 つだけ起動し、イベント内でミントのバッチ全体を指定することができます。別の例では、所有者残高を毎回の鋳造後ではなく、バッチごとに 1 回だけ更新します。
バッチ ミントにはいくつかの最適化の可能性があることに気づき、Azuki チームはバッチ ミント用に最適化された ERC721 の実装である ERC721A を作成しました。OZ の実装との比較は次のとおりです。
ERC721A はどのようにしてこの節約を実現しているのでしょうか? 主に次の最適化を使用します。
- OZ の ERC721Enumerable を取り除く
- コイン鋳造のたびにデータを更新するのではなく、バッチごとに 1 回のみデータを更新します。
- より効率的なストレージ レイアウトを使用します。連続する NFT の所有者が同じ場合、所有者に関する冗長な情報を保存しないでください (最初に所有された NFT に対して 1 回のみ)。このデータは、所有者情報が見つかるまで読み続けることで、実行時に推測できます。
- バッチごとにトリガーされる転送イベントは 1 つだけです。(これは、オリジナルの ERC721A の一部ではなく、より関連性の高い最近の変更です)
ERC721A の詳細については、AZUKI の Web サイトをご覧ください。
Enumerable インターフェイスのすべての機能が必要な場合は、ERC721Enumerable の最適化されたバージョンであるAZUKI のERC721AQueryableインターフェイスを使用できます。
ERC721Aを使用した契約:
- あずき
- ゴブリンタウン
- 待つ
- ムーンバード
セーフミントの代わりにミントを使用してください
safeMint
もともとは、NFTが契約から失われるのを防ぐことを目的としていました。NFT の受信者が契約であり、転送 NFT メソッドがない場合、NFT は契約内に永久に残ります。
したがって、受信側コントラクトは ERC721Receiver インターフェイスを実装して、NFT コントラクトが NFT が受信側で正しく受信されたかどうかを確認できるようにする必要があります。コントラクトが受信側インターフェイスを実装している場合、NFT を受信した後にそれをどう処理するかを知っていることを示します。
受信者が契約ではなく、通常のアカウントである場合は、それを使用する必要はありませんsafeMint
。受信者のコントラクトが NFT を処理できると 100% 確信している場合は、NFT を使用する必要もありませんsafeMint
。
セーフミントの代わりにミントを使用すると、ガスをいくらか節約できます。transfer
の代わりに使用する場合も同様ですsafeTransfer
。
これを行う契約は次のとおりです。
- クリプト・コーヴン
マークル ツリーを使用してホワイトリスト メカニズムを実装する
マークル ツリーを使用してホワイトリストを実装すると、大量のストレージ (およびガス) を節約できます。マークル ツリーは、単一のアドレスを犠牲にして多数のアドレスを保存できる効率的なデータ構造です。トレードオフは、検索時間がO(1)ではないことです。しかし、*O(n)* もかなり良いです。
契約に追加する必要があるのは、次の機能だけです。
検証ステップにはOpenZeppelin の MerkleProofライブラリを使用できます。
次に、キャスト関数を次のように変更します。
基本的には、 mint 関数に追加のパラメーターを追加するだけですmerkleProof
。これは、ミント可能アドレスからルート アドレスまでのパスを形成するアドレスのハッシュの配列です。ウェブサイト上で、許可された鋳造アドレスごとにこのパスを計算できます。詳細については、こちらをご覧ください。
マークル ツリーを使用したコントラクト:
- クリプト・コーヴン
- OKPC
アップグレード可能/置換可能なメタデータ コントラクト
後で NFT のプレゼンテーションをアップグレードする場合、またはオンチェーンとオフチェーンのレンダリングを切り替えたい場合は、メタデータ コントラクトを置き換え可能にする必要があります。このような:
この方法を使用する契約は次のとおりです。
- OKPC
- ウォッチフェイス
ボットのミントを防ぐ
ボットがすべてのトークンをマイニングするのを防ぐために、2 つの安全策を講じることができます。
- 各ウォレットの鋳造可能額を制限する
- チェックしてください
msg.sender == tx.origin
。コントラクトがミント関数を呼び出すとき、msg.sender
それはコントラクトのアドレスになりますが、tx.origin
コントラクトを呼び出した人のアドレスになります。詳細については、こちらをご覧ください。
NFTスナイパーからの保護
NFTスナイピングとは、誰かがどのトークンが希少であるかを知っており、トークンが鋳造された順序を知っている場合です。したがって、彼らは希少なNFTを入手することを目的として、適切な時期を選択して大量のNFTを鋳造します。
すべての人にトークンが公平に配布されるようにするために、NFT が狙撃されるのを避けたいと考えています。NFTスナイピングを(少なくともある程度は)防ぐ方法について話しましょう。NFTスナイピングは2つの質問で構成されます。
- トークンのメタデータの公開 (スナイパーがトークンの希少性を推測できるようにする)
- 明確な順序でトークンを鋳造します(レアなトークンを鋳造する正確な時間をスナイパーに推測させます)。
最初の問題は、トークンが鋳造されるまでメタデータを公開しないことで解決できます (詳細はこちら)。または、バッチ処理された段階的な開示を使用することもできます。さらに、チェーン上のすべてのデータが読み取られて利用されます。したがって、ミントが開始されるまでは契約を確認しないでください。
2 番目の問題は、鋳造順序をランダム化することで解決できます。オンチェーンのランダム化は困難です。イーサリアムには乱数生成機能が組み込まれていないため、人々は現在のブロック番号をシードとして使用したり、ランダム性を高めるためにそれをマイナーアドレスと組み合わせたりするなど、さまざまなトリックを使用してきました。これは完全にランダムではないため、この種のトリックは上級スナイパーによって簡単に見破られます。
ランダム化されたオラクル(チェーンリンク)を使用することもできますが、その場合でも、高度なスナイパーは 偷看
NFTを使用してそれをバイパスでき、これは達成できます:鋳造されたNFTがまれではないことが証明された場合は、トランザクションをロールバックします(例はこちら)。したがって、残念ながら、2 番目の問題を 100% 解決する方法はありません。できることの 1 つは、ホワイトリスト登録メカニズムを追加することですが、それは NFT のコレクション全体をホワイトリスト登録されたコミュニティに制限できる場合にのみ機能します。
イーサリアムは本当に暗い森で、注意しないと狙撃される可能性があります。NFT狙撃攻撃の詳細については、こちらをご覧ください。
他のモード
- コントラクトを抽出可能にする ERC-721 および ERC-20: ほとんどのコントラクトは ETH 抽出機能を実装するだけで、ERC-721 および ERC-20 の問題を忘れています。しかし、場合によっては、誤って、またはその他の理由でトークンをコントラクトに送信してしまうことがあります。コントラクトに引っかからないように抽出関数を追加します (実装例については Crypto Coven コントラクトを参照してください)。
- データを不変にします。オンチェーン NFT を作成するか、オフチェーンでレンダリングされる場合は、proof-of-hashを使用します。
- 手数料ゼロのリストについて OpenSea を事前承認します: (Seaport 以降廃止されました)。以前は、 NFT 保有者が OpenSea 契約を呼び出す必要がないように、OpenSea 契約を事前承認することが可能でした
setApproval
。しかし、Seaport の導入により、これは必要なくなりました (実装例については Crypto Coven コントラクトを参照してください)。