簡単NFT発行　老技術者が一夜でRopsten上にERC721トークンをデプロイしてNFTを発行してしまったお話

# はじめに
年明けから2つのブロックチェーンプロジェクトをお世話して若い人たちに頼りにされる老技術者は幸せなものよとは言いつつ,わけあって衆人環視の下でcurlをたたくというスリルを味わい若干また頭髪の国境線が後退したと娘に指摘された春の日。
年度が明けたら嘘のように暇になり,テストネットで遊んでその顛末をQiitaに書いて社会にご奉仕しようとは露ほども思わず単なる自己満足に浸るのであった。

# ERC721トークンの作成からデプロイまで
## (1) Metamaskでアカウント作成

まずはEdge(Chrome)の拡張機能に追加したMetamaskでアカウントを作成する。
アカウント名は何でもいいがここでは「NFTtest01」とする。

<img width="300pix" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202911/4766f300-5366-3927-2d4c-37a50f122d5a.png">

## (2) アカウントにガス代用ETHを入れる
アカウントができたら,アカウントIDをコピー。

<img width="300pix" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202911/691fd978-1d47-fa11-86dd-772b8566abcf.png">

ガス代のためにETHをもらっておく。

こちら
https://faucet.egorfine.com/
のサイトに先ほどコピーしたアカウントIDを入れて「Give me Ropsten ETH!」を押すと,

<img width="300pix" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202911/ba83a4c6-aced-d629-d22f-da2fa5ee4a2a.png">

数分後には入金される。打ち出の小槌だ。

<img width="300pix" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202911/de9fb638-cf88-9575-4beb-036f0fce515b.png">

## (3) コントラクトを書いてコンパイル後にデプロイする
remixを開き,testsを右クリックし，New Fileを選択し「NFT001.sol」というファイルを作る。
次のコードをコピペする。

```solidity:NFT001.sol
//Contract based on [https://docs.openzeppelin.com/contracts/3.x/erc721](https://docs.openzeppelin.com/contracts/3.x/erc721)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
contract MyNFT is ERC721URIStorage, Ownable {
    using Counters for Counters.Counter;
    Counters.Counter private _tokenIds;

    constructor() ERC721("MyNFT", "NFT") {}

    function mintNFT(address recipient, string memory tokenURI)
        public onlyOwner
        returns (uint256)
    {
        _tokenIds.increment();
 
        uint256 newItemId = _tokenIds.current();
        _mint(recipient, newItemId);
        _setTokenURI(newItemId, tokenURI);
 
        return newItemId;
    }
}
```

左端のアイコンからSolidity Compilerを選び「Compile NFT001.sol」をクリック。

<img width="800pix" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202911/ab5e104c-7eef-1cdf-84b7-55802b6d1861.png">

左端のアイコンからDeploy & run transactionを選び，
ENVIRONMENTが Injected Web3
ACCOUNTが NFTtest01のアカウントID
CONTRACTが MyNFT-tests/NFT001.sol
になっているかを確認して「Deploy」をクリック。

<img width="300pix" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202911/5b3f58a8-cb04-3482-5ae5-de0acca65082.png">

MetaMaskがポップアップし，ガス代見積もりが示されるが，大金持ちゆえ気にせず「確認」をクリック。

<img width="300pix" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202911/311f5e07-b29d-9738-d5f2-951a9f5abca1.png">

この可愛いやつが出ればデプロイ成功。

<img width="300pix" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202911/636cc532-f694-9765-61e1-b0787579a58c.png">

MetaMaskを開き，アクティビティタブへ。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202911/b66e9140-ff85-6309-530c-312f6c3f3286.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202911/283be888-d6d1-4b83-a352-bc134d5c7c41.png)

「コントラクトの展開」をクリックするとこんな画面が現れる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202911/6ff7847e-0808-078b-298c-0e65c2611982.png)

「ブロックエクスプローラーで表示」をクリックすると，Etherscanの画面が現れる。
外部所有アカウントNFTtest01（ID:0x6581f7b537a1~）から送出されたトランザクション（Hash:0x2781c9ee57448759c8ce4ba4372d~）によってNFT001.solのコントラクトアカウント（ID:0xa61e5cc98f477~）ができたことがわかる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202911/7ff964bb-4f36-ad5f-8bdc-488c3789a3ea.png)

# IPFSにお宝画像を格納
## (1) IPFS DESKTOPのインストール
IPFS（InterPlanetary File System）はコンテンツ指向ネットワークと言われ，コンテンツのハッシュ値を指定することでコンテンツにアクセスする。データを取得した人はアクセスしたデータのIDであるハッシュ値と、そのコンテンツから得られるハッシュ値を比較することで容易にコンテンツの正当性を検証することができる。
まず，こちらからIPFS Desktopをインストール。
https://github.com/ipfs/ipfs-desktop

<img width="600pix" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202911/0e8e9920-1d83-9ffa-8d21-bef8c6ec917d.png">

Windowsの人はダウンロードしたインストーラー（IPFS-Desktop-Setup-0.20.5.exe）を実行すればOK。
すべてのユーザーに使わせる。

<img width="600pix" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202911/d5edba89-e7e4-31e0-96df-83b2fb88032a.png">

変えなくてOK。

<img width="600pix" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202911/625a1d51-3671-cf87-6c6a-7278bc3c255d.png">

あっという間だ。


<img width="600pix" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202911/215a0268-bf14-3a56-09c7-02b8045f785c.png">

## (2) IPFSにバラの画像を格納

起動したIPFS DESKTOPのFILESからImportボタン。

<img width="600pix" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202911/9985b991-9116-7398-4ea7-ccc88a826fc6.png">

バラの花の写真を

<img width="600pix" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202911/e0711ce9-723b-e4df-6363-6ffbd99893e2.jpeg">

ドラッグエンドドロップするとあっという間にIPFSに格納される。

<img width="600pix" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202911/9a07ddf9-9e7d-7282-d7ea-a2f98d496f72.png">

三点リーダーからShare linkを突き，
<img width="600pix" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202911/c1af7268-0cc0-35e7-449d-7f2d0e7e0f6a.png">

ここでCopyボタンを押すとこの画像のURIがクリップボードにコピーされる。
URIには画像のメタデータのハッシュ値が入っているわけだから，もうバラの写真は改ざんできない。

<img width="600pix" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202911/d2ff8b7b-2f83-7342-ae92-f433299f0f67.png">

# いよいよNFTの発行だ
Remixに戻り，先ほどデプロイしたコントラクトの左の>を突くとこんなのが現れる。

<img width="300pix" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202911/4b798abb-612d-12eb-ba01-658ca18617a0.png">

mintNFTの右のvを突くとこんなのが現れる。

<img width="300pix" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202911/9034c0ad-05d7-f761-7eaa-07c4514cc81c.png">

recipientには，NFTを送る先のアカウントNFTtest01のアカウントIDをMetamaskからコピーしてきて入れる。
tokenURIには先ほどコピーしたバラ画像のURIを入れる。
これでtransactボタンをクリック。

ガス代見積もりを見て確認ボタンを押す。

<img width="300pix" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202911/63689a47-7909-6bc6-9393-2feaf88d1761.png">

こんな可愛いのが出たらNFT発行が成功。

![スクリーンショット 2022-04-05 014522.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202911/d2595366-3577-406c-5483-6eb0e8530076.png)

まず，コントラクトのアカウントID（トークンコントラクトアドレス）をコピー。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202911/abcfe46b-fa98-905f-094b-1b4e360664e1.png)


MetaMaskを開き，アセットタブから「トークンをインポート」をクリック。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202911/1db69e7f-b1e1-7288-208a-35c95cf038a3.png)

トークンコントラクトアドレスに先ほどコピーしたトークンコントラクトアドレスをペーストするとトークンシンボルにはNFTが自動で入り，トークンの小数桁数は0を入れ，「カスタムトークンを追加」というボタンを押す。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202911/c06ac34a-8d97-7cd5-c30e-b3cb18f1eac5.png)

こういう画面が出るので「トークンをインポート」

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202911/cb3a8f89-b8f6-a906-fcca-8356efc5d317.png)

ちゃんと1 NFTがmintされていました。

次に，MetaMaskを開き，アクティビティタブへ。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202911/b66e9140-ff85-6309-530c-312f6c3f3286.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202911/5c1ae53c-bb99-d616-2567-8a7b75daebff.png)

「Mint N F T」をクリックするとこんな画面が現れる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202911/7f4ad431-eb58-fcdd-23e9-0ffb8647b75c.png)

「ブロックエクスプローラーで表示」をクリックすると，Etherscanの画面が現れる。
外部所有アカウントNFTtest01（ID:0x6581f7b537a1~）からコントラクトアカウント（ID:0xa61e5cc98f477~）に送出されたトランザクション（Hash:0xedacbc4a72e7ce03b6585bff060~）によってコントラクトNFT001.solのmintが実行され，コントラクト外部所有アカウントNFTtest01（ID:0x6581f7b537a1~）にNFTが発行(mint）されたことがわかる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202911/5b640c47-3859-4711-21a0-636bb848d72d.png)