Now and Nawoo

NFTの制作記録、技術メモ → C#, Solidity, Blockchain, Bitcoin, Ethereum, NFT

おみくじNFTを作りました

NFT第2弾として、おみくじNFT を作ってみました。

f:id:nawoo5:20211005115620p:plain:w200

  • フルオンチェーンNFT
  • drawOmikujiでおみくじを引けます (ガス代のみ)
  • ランダムで大吉~大凶のNFTがもらえます
  • burn可能です (お焚き上げ?)
  • 発行数の制限はありません (何枚でもどうぞ)
  • Polygonのメインネットに公開しました

Polygonscanで見る

OpenSeaで見る

コード解説

前回はとてもシンプルなNFTだったので、今回はいくつか新しいことにチャレンジしました。

  • ERC721EnumerableとERC721Burnableを多重継承する
  • ReentrancyGuardを使ってみる
  • ランダム値を扱う
  • 日本語を扱う

コードはこちら

ERC721EnumerableとERC721Burnableを多重継承

totalSupplyを使いたかったのでERC721Enumerable、burnさせたかったのでERC721Burnableを継承しました。 しかし、前回の記事 で書いたようにtotalSupplyは使わないことになりました。

後で思ったのですが、まず2つを継承した ERC721EnumerableBurnable を作り、 それを継承して OmikujiNftを作ったほうが、コードの見通しがよくなったかもしれません。

ReentrancyGuardを使ってみる

リエントランシー攻撃対策としてdrawOmikuji関数にnonReentrantを付けています。 (Check-Effects-Interactionsパターンを守っていると思うので、無くてもいい気がしますが。)

ランダム値を扱う

uint256 rand = uint256(keccak256(abi.encodePacked(block.timestamp, tokenId)));
uint8 kujiResult = uint8(rand % 7); // 0:大吉, 1:中吉, 2:小吉, 3:吉, 4:末吉, 5:凶, 6:大凶

block.timestampとtokenIdを使って擬似的なランダム値を求めて、 そこからおみくじの結果(大吉~大凶)を決めています。

日本語を扱う

Solidityの文字列リテラルでは日本語をそのまま使えないので、\x形式でエンコードするか、unicodeリテラルを使います。

string memory s = "大吉"; // エラー
string memory s = unicode"大吉";
string memory s = "\xE5\xA4\xA7\xE5\x90\x89";

メインネットへのデプロイ

今回、初めてPolygonのメインネットへデプロイしました。 基本的には テストネットへのデプロイ と同じです。

truffle-config.jsのnetworksの設定に matic_mainnet を追加します。

  networks: {
    ...
    matic_mainnet: {
      provider: () => new HDWalletProvider(mnemonic, `https://matic-mainnet.chainstacklabs.com`),
      network_id: 137,
      confirmations: 2,
      timeoutBlocks: 200,
      skipDryRun: true
    },
  },

マイグレーションを実行して、しばらく待てばデプロイ完了です。

> truffle migrate --network matic_mainnet

デプロイは無事にできたのですが、その後にconsoleでコントラクトを触っていると、 なぜか応答しなくなる、という問題が繰り返し発生しました。

Polygonでトランザクションが詰まっていたのかもしれませんし、 truffle側に問題があったのかもしれません。 (原因はよくわかりませんが、無事にデプロイできてるので、良しとします。。。 )

おわりに

次回は、発行数に制限のあるタイプのNFTを考えています。