ローカルのブロックチェーンにNFT発行する暗き老技術者あり

## はじめに

先日,自分のWindowsマシンにWSL2でUbuntu環境を作り,そこにHyperledgerBesuのブロックチェーンを構築。そこに極めて簡単なコントラクトをデプロイして遊んだのだった。これである。
https://qiita.com/oldEng/items/557ceb29a7849e92b5f2

これがなかなか面白く,老技術者に箱庭的愉楽を与えてくれたのだった。せっかく作った箱庭にもう少し植栽がほしくなり,まずはERC20トークンをデプロイしたのがこれ。
https://qiita.com/oldEng/items/537ce540c4ee48b5acc1

最近，NFTをやる人が増えてきて，この老技術者に2周りも若い人が教えを請いに来る。
ERC721.solはNFTじゃないんだぞ，なんて言っても当然だがわかってもらえない。
そこで実際にNFTを発行すれば，なるほどーとなるはず。と今宵こんなものを書き始めたのでした。

## コード

ERC721のシンプルなコードを書いてみる｡

```solidity:ERC721Token.sol
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
import {ReentrancyGuard} from "@openzeppelin/contracts/security/ReentrancyGuard.sol";

contract Nft is ERC721, ERC721URIStorage, ERC721Enumerable, ReentrancyGuard {
    uint256 private latestTokenId = 1;

    constructor(string memory name, string memory symbol)
        ERC721(name, symbol)
    {}

    function mint(string memory _tokenURI) public {
        uint256 tokenId = latestTokenId;
        _mint(msg.sender, tokenId);
        _setTokenURI(tokenId, _tokenURI);
        latestTokenId++;
    }

    function _burn(uint256 tokenId)
        internal
        override(ERC721, ERC721URIStorage)
    {
        super._burn(tokenId);
    }

    function tokenURI(uint256 tokenId)
        public
        view
        override(ERC721, ERC721URIStorage)
        returns (string memory)
    {
        return super.tokenURI(tokenId);
    }

    function _beforeTokenTransfer(
        address _from,
        address _to,
        uint256 _tokenId
    ) internal override(ERC721, ERC721Enumerable) {
        super._beforeTokenTransfer(_from, _to, _tokenId);
    }

    function supportsInterface(bytes4 _interfaceId)
        public
        view
        override(ERC721, ERC721Enumerable)
        returns (bool)
    {
        return super.supportsInterface(_interfaceId);
    }
}

```


こいつをRemixにNew File「ERC721Token.sol」として貼り付けて，Compile ERC721Token.solというボタンを押す。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202911/b95d66fe-7123-e4fe-1bdd-38f568ee6d88.png)

## アカウントを用意してトークンコントラクトをデプロイ

Metamaskを拡張機能から立ち上げ,NFTTestというアカウントを用意。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202911/9cec00ab-6c24-9e1c-5aa8-79d599d874fe.png)
こちらのアカウントIDを確認し，

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202911/d1f6262c-6d74-691c-d11c-e8f6b33b7467.png)

DEPLOY & RUN TRANSACTIONSで下図のラインの部分を確認し，
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202911/f55aba7c-ff80-644f-f42d-c9b165174418.png)

ENVIRONMENTやCONTRACTを確認し,ACCOUNTに先ほどのNFTTestのアカウントIDが入っているか確認。
DEPLOYの右のVマークをクリックし，
NAMEにトークン名（ここではNFTtakaとした｡takaとはわが幼名なり）,SYMBOLにはトークン記号（ここではNFTとした）｡
DEPLOYの下のこの2箇所の記入が終わったらtransact｡

こういうのが出たら「確認」。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202911/e8eb0395-65bf-254a-7424-bbb4ca99ae42.png)

こういう可愛いのが出たらデプロイ成功である。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202911/ddc90a4d-30e9-7ff2-c232-3bca5ab5ae5a.png)

ここまでで，ERC721トークンのコントラクトが私のローカルのブロックチェーンにデプロイされた。

## NFTの発行
次にこのトークンを発行する。
この記事の前に書いたこちらを参考にIPFS上に写真をアップロード。

https://qiita.com/oldEng/items/ce64bc0c8a52d5d6ca7b

こんな画像のNFTを作ることにする。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202911/2afb1e3d-775c-4a69-5944-87eae0337f05.png)

右上のMoreをつつくと出てくるShare linkを押す。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202911/a9001e19-ae2d-6e03-2a19-33fc4596c8f4.png)


こんなのが出たらCopy。いまコピーしたのがNFTのキモであるURIである。コンテンツの存在証明だ。別の場所に置いたり，画像を差し替えたり改変したらもはや同じURIにはならない。
URLじゃなくてURIですよ。URI=Uniform Resource Identifierです。場所とコンテンツをハッシュ関数にぶち込んで作るという。
ちなみにURL=uniform resource locator，こっちは場所を表すだけ。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202911/365f7d5b-83ce-be6c-a685-ead50f940b32.png)

RemixのDeployed Contractsの一番下のやつの左の「>」マークを押し，出てきたmintの右の「v」マークをつつき，出てきた欄に先ほどコピーしたURIを貼り付ける。貼り付けたらtransact。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202911/6daf6dae-ee51-e4e5-583e-7a5dd4bbd123.png)

MetaMaskがポップアップしてこういうのが出たら確認ボタンを押す。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202911/69f4a7b9-670e-3ea2-2c80-71995bc2ee3e.png)

可愛いキツネが出たら無事NFTが発行完了。
Remixに出ているNFTコントラクトのアカウントIDをコピー。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202911/0e729190-d312-c331-3f1e-ffc0f86c5101.png)

MetaMaskで「トークンをインポート」を押すと
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202911/728f2d75-6198-f632-6e7d-386b4b831d00.png)

こんなのが出るのでトークンコントラクトアドレスに先ほどコピーしたNFTコントラクトのアカウントIDを
貼り付けるとトークンシンボルは「NFT」と自動で入る。
トークンの小数桁数は0にして，「カスタムトークンを追加」を押す。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202911/afc40703-1f2f-ad40-3d9c-c2b6add2bd79.png)

こういうのが出るので，「トークンをインポート」。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202911/d6d2cabf-15d5-b3db-5c51-d311b78796f4.png)

無事NFTが発行された。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202911/952eab43-39a0-0f05-c153-108a69c2bb8d.png)

## NFTを移転
さっそくプレゼントしよう。KITTYtaka01という怪しい名前のアカウントのIDをコピー。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202911/602ff28d-fcbe-b12f-9949-5fc01c5e50a7.png)

RemixのtransferFromの右の「v」マークを押しtoにKITTYtaka01のアカウントIDを張り付け，
FromにはNFTTestのアカウントIDをコピペ。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202911/ca2de3d4-a427-9230-f18f-f5ece8a5aba6.png)

tokenIdに1を入れてtransact。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202911/bb8c509c-2406-06b5-311c-96dcdb5b4bca.png)

MetaMaskがPopupしてこんなのが出るので「確認」。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202911/d5a00484-1668-6934-42d8-d20e38d8fde7.png)

可愛いのが出る。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202911/23ecb020-c81b-082e-bdfa-f884d2f9225e.png)

上記と同様にKITTYtaka01にカスタムトークンを追加。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202911/9919e7e2-e035-cd55-f2cc-d59292e3d2d2.png)

トークンをインポート。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202911/260cbea0-d290-fc5a-966e-dc2d52b144d6.png)

NFTが届いた。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202911/076eae3f-35d1-7138-1d30-9701865c5355.png)

こちらのアカウントにはNFTがなくなっている。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202911/dde31204-d10c-7857-5466-b613b49cedba.png)