🤖

【Solidity】インタラクティブなNFTの作り方【Remix】

2022/01/18に公開

前置き

この記事は特定のNFTや仮想通貨の購買を促進する記事ではありません。

インタラクティブなNFTとは?

一般定義として固まっているわけではありませんが、ここではクリックやマウスのカーソルに合わせて動くNFTと定義します。

例えば、↓のようなNFTを作れます。今回は(2)を題材に取り上げます。

(1) (2)

また、今回作るNFTはOpenSeaでは動作確認できたものの、他のマーケットでは正常に動作するか確認していません。

作り方

環境

コントラクトの作成とデプロイ

コントラクトは特に変なことはせず、ERC721の規格にあわせて実装します

// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.0;

import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.4.2/contracts/token/ERC721/ERC721.sol";
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.4.2/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.4.2/contracts/utils/Counters.sol";


contract SushiNeko is ERC721URIStorage {
    using Counters for Counters.Counter;
    Counters.Counter private _tokenIds;

    constructor () ERC721 ("SushiNeko", "SNEKO") {}

    function mint(string memory tokenURI) public returns (uint256) {
        _tokenIds.increment();
        uint256 newItemId = _tokenIds.current();

        _safeMint(msg.sender, newItemId);
        _setTokenURI(newItemId, tokenURI);

        return newItemId;
    }
}

メタマスクから接続先ネットワークを Rinkeby テストネットワーク に切り替えてからデプロイします。
デプロイ用のETHをもらう方法はこちら

mintする際はtokenのメタデータが記されているjsonファイルの保存先を指定します。

次のステップでインタラクティブなNFTの実体と、メタデータ用のjsonファイルを作成します。

NFTの実体とメタデータの作成

このNFTの実体、実は複雑なことを行っているわけではなく、ただのHTMLです。
OpenSeaでは公式でHTMLのページのサポートを表記していて、JavaScriptCanvasやWebGLも表示できます。

Animation_url also supports HTML pages, allowing you to build rich experiences and interactive NFTs using JavaScript canvas, WebGL, and more. Scripts and relative paths within the HTML page are now supported. However, access to browser extensions is not supported.

https://docs.opensea.io/docs/metadata-standards#metadata-structure

今回は p5.js を利用したHTMLファイルを作成して表示します。

https://p5js.org/

<html>
  <head>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.min.js"></script>
  </head>
  <body>
    <script>
      let circleX;
      let circleY;
      let circleSize;

      function setup() {
        createCanvas(420, 420);
        noFill();
        strokeWeight(5);
        circleX = width / 2;
        circleY = height / 2;
        circleSize = 0;
      }

      function draw() {
        background(0, 128, 255);

        circleSize += 10;

        stroke(0, 64, 128);
        circle(circleX, circleY, circleSize);
        circle(circleX, circleY, circleSize * 0.75);
        circle(circleX, circleY, circleSize * 0.5);
      }

      function mousePressed() {
        circleX = mouseX;
        circleY = mouseY;
        circleSize = 0;
      }
    </script>
    <style>
      #defaultCanvas0 {
        position: fixed; /*canvasを固定*/
        top: 0; /*canvasを上に固定*/
        left: 0;
        z-index: -1;
      }
    </style>
  </body>
</html>

作成したHTMLファイルとサムネイル表示用の画像をpinata経由でipfsにアップロードします。

https://www.pinata.cloud/

アップロードしたHTMLや画像のURLを元にtokenURI用のメタデータjsonを作成します。

{
  "name": "InteractiveNFT",
  "description": "hello world",
  "image": "https://gateway.pinata.cloud/ipfs/QmVfiTuZqaykw4Fgn8PNTnrW2WcmUbFHFv47KCiy7NAKZL",
  "animation_url": "https://gateway.pinata.cloud/ipfs/QmY83TyX1hTWNc4CSKEVPKAwDDYuMSgVQAynTr1X5mKxn7"
}

こちらもpinata経由でipfsにアップロードします。

アップロードできたら、Remixに戻りmintしましょう

サンプルでは https://gateway.pinata.cloud/ipfs/QmVyACZL3XvwJKmV2L6VAJJv6AR5MCm8uupYZmJRb6f1jU をtokenURIにセットしています。

確認する

mintが成功したら、 OpenSeaのテストネットに見に行きます
https://testnets.opensea.io/assets/コントラクトのアドレス/トークンID

サンプルは以下

https://testnets.opensea.io/assets/0x5db01e866557d21737088af4a6b51f38fea40c03/1

正常に動作しているのが確認できました。

まとめ

  • Remixを使ってインタラクティブなNFTを作成した
  • OpenSeaではHTMLページの表示がサポートされていて、今回のようなJavaScriptCanvasやWebGLの描画もサポートしている

関連リンク

http://remix.ethereum.org/
https://www.pinata.cloud/
https://github.com/kmaebashi/jstetris

最後に

Solidityについてワイワイ学ぶコミュニティ「solidity-jp」を作りました!
いまから学んでみたい/学習中だけどの日本語の情報が少ない/古くて時間がかかっているという方、一緒に学びましょう〜!!

https://solidity-jp.dev/

また、TwitterにてSolidityについて技術的な部分を発信しています。良ければフォローお願いします!

https://twitter.com/k0uhashi

Discussion