# RemixでWallet Connectを使用してコントラクト開発しよう！

> まずはRemixのページを開きましょう。

- URL: https://cardene.dev/articles/3903c469ffff87
- 公開日: 2024-05-21
- 更新日: 2024-05-21
- トピック: Blockchain
- タグ: solidity, ethereum, smartcontract, remix

# はじめに

初めまして。
**CryptoGames**というブロックチェーンゲーム企業でエンジニアをしている **cardene（かるでね）** です！
スマートコントラクトを書いたり、フロントエンド・バックエンド・インフラと幅広く触れています。

https://cryptogames.co.jp/

代表的なゲームは**クリプトスペルズ**というブロックチェーンゲームです。

https://cryptospells.jp/

以下でも情報発信しているので、興味ある記事があればぜひ読んでみてください！

https://twitter.com/cardene777

https://chaldene.net/

https://qiita.com/cardene

https://cardene.substack.com/

https://mirror.xyz/0xcE77b9fCd390847627c84359fC1Bc02fC78f0e58

https://cardene.notion.site/EIP-2a03fa3ea33d43baa9ed82288f98d4a9

今回は**Remix**という、ブラウザ上でスマートコントラクトの開発を行うことができるツールで、WalletConnectを使用して開発を行う手順を紹介します。
できる限り噛み砕いて非エンジニアでも実行できるよう解説していきます。

:::message alert
今回の記事は非エンジニアでも読めるようにしています。
そのため、言葉の定義が正確ではないところがあります。
これは正確性よりもわかりやすさを重視しているためです。
この前提を踏まえた上で読んでいただけると幸いです。
:::

# Remixにアクセス

まずはRemixのページを開きましょう。

https://remix.ethereum.org/#lang=en&optimize=false&runs=200&evmVersion=null&version=soljson-v0.8.25+commit.b61c2a91.js

[https://remix.ethereum.org/#lang=en&optimize=false&runs=200&evmVersion=null&version=soljson-v0.8.25+commit.b61c2a91.js
](https://remix.ethereum.org/#lang=en&optimize=false&runs=200&evmVersion=null&version=soljson-v0.8.25+commit.b61c2a91.js)

URLの末尾にコンパイラのバージョンなど含まれているので、上記のURLから開いてください。

![Remixにアクセスの図](https://storage.googleapis.com/zenn-user-upload/43ad0320f729-20240516.png)

開くと上記のようなページが表示されます。

![Remixにアクセスの図](https://storage.googleapis.com/zenn-user-upload/71df90bfa2ab-20240516.png)

ページの左側にあるサイドメニューに注目してください。
図の赤枠はそれぞれ以下のことができる場所です。

1. スマートコントラクトを開発をする場所。
2. コンピューターが読みやすい形式に変換する「**コンパイル**」を行うタブ。
3. コントラクトを公開する「**デプロイ**」を行うタブ。

# Solidityファイルの作成

では、次にSolidityのファイルを作成していきましょう。

![Solidityファイルの作成の図](https://storage.googleapis.com/zenn-user-upload/0f4494fe3a69-20240520.png)

上記の「contracts」という部分にカーソルを合わせるとファイルアイコンが出てくるのでクリックします。
そうするとファイルが作成されて、ファイル名を設定できるようになります。

ファイル名を設定でできたら、ファイルをクリックして開きましょう。
ファイルを開くと中身が空になっているので、以下のようにコードを書いていきましょう。

![Solidityファイルの作成の図](https://storage.googleapis.com/zenn-user-upload/1ceba88b53d2-20240520.png)

今回は1からかかず、以下に書かれているコードをコピペしてください。
1行目から最後の行までコピーして、先ほど作成したファイルにペーストしてください。

https://gist.github.com/cardene777/22cf12395c33a87fd96f585d9c41d621

これでSolidityでかかれた、スマートコントラクトの作成ができました。

# スマートコントラクトの解説

コントラクトの作成ができたところで、コントラクトの中身を見ていきましょう。

:::message
この章はコントラクトの細かい説明をしているため、手を動かしたい方は次の章に進んでください。
:::

## ライセンスとバージョン

```solidity
// SPDX-License-Identifier: MIT
```

この部分ではライセンスについて定義しています。

:::message
MITライセンスとは、使用、コピー、修正、マージ、公開、配布を自由に行うことができるライセンスです。
:::

```solidity
pragma solidity 0.8.25;
```

ここではSolidityのバージョンを定義しています。
今回は0.8.25というバージョンを使用しています。

## ライブラリのインポート

```solidity
import {ERC721} from "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import {ERC721Burnable} from "@openzeppelin/contracts/token/ERC721/extensions/ERC721Burnable.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {Base64} from "@openzeppelin/contracts/utils/Base64.sol";
import {Strings} from "@openzeppelin/contracts/utils/Strings.sol";
```

様々なライブラリを読み込んでいます。

- `ERC721`
    - Openzeppelinが開発をしている`ERC721`コントラクトを読み込んでいます。
    - `ERC721`形式のNFTを作成するときは、基本的にこのコントラクトを読み込みます。
- `ERC721Burnable`
    - `ERC721`形式のNFTを**burn**できる拡張機能です。
    - **burn**とは、NFTを削除して以降使えなくする機能です。
- `Ownable`
    - コントラクトの所有権を管理するコントラクトです。
- `Base64`
    - データを他の形式に変換するコントラクトです。

:::message
すべてのデータを「**a～z**」「**A～Z**」「**0～9**」「**+**」「**/**」の64文字と「**=**」の組み合わせに変換するやり方
:::

https://wa3.i-3-i.info/word11338.html

- `Strings`
    - 特定のデータを文字列に変換するコントラクトです。
 
## コントラクト定義

```solidity
contract JBANFT is ERC721, ERC721Burnable, Ownable {
```

上記でコントラクト名の定義と複数のコントラクトを継承しています。
継承とは、他のコントラクトの機能を引き継いで、継承先のコントラクトで使えるようにすることです。
今回でいえば、**JBANFT**というコントラクトを作成し、`ERC721`・`ERC721Burnable`・`Ownable`の3つのコントラクトを継承して、**JBANFT**からも3つのコントラクトの機能を使用できるようにしています。

## 変数

```solidity
uint256 private _nextTokenId;
```

`_nextTokenId`という変数を定義しています。
変数とは値が入る「**箱**」のようなものです。
今回は`_nextTokenId`という名前の「**箱**」を用意して、ここに任意の値を格納できるようにしています。
`uint256`というのはデータの種類を表していて**型**と呼ばれます。
`uint256`は$0$から$2^256 - 1$までの値を定義できる型です。
値が入っていないように見えるのは定義しているだけだからです。
ただ、Solidityの場合は`0`という値が入っています。

## constructor

```solidity
constructor(address initialOwner)
    ERC721("JBANFT", "JBAN")
    Ownable(initialOwner)
{}
```

`constructor`と呼ばれる、コントラクトをデプロイ（公開）した時に一度だけ実行される関数（一連の処理を一まとめにしたもの）を定義しています。
`initialOwner`というアドレスを引数（関数実行時に渡される値）で受け取り、`Ownable`コントラクトの機能を実行してコントラクトの所有者を`initialOwner`に設定しています。
`initialOwner`には、`0xabc123...`というようなアドレスが渡されます。
`ERC721("JBANFT", "JBAN")`という部分では、継承している`ERC721`コントラクトの機能を使用して、NFTの名前とシンボル名を設定しています。

## mint関数

```solidity
function safeMint(address to) public {
    uint256 tokenId = _nextTokenId++;
    _safeMint(to, tokenId);
}
```

この関数では、NFTを`mint`（新規発行）する処理を定義しています。
関数名は`safeMint`で、`to`というアドレスを引数で受け取っています。
`public`というのは関数のアクセス範囲を定義しています。

| アクセス範囲 | 説明 |
| :--------: | :--: |
| `external` | コントラクトの外部からのみ実行可能。 |
| `public` | コントラクトの外部・内部から実行可能。 |
| `internal` | コントラクトの内部からのみ実行可能。 |

上記3つのパターンがあり、データを更新する関数ではいずれかのパターンで定義する必要があります。
`external`の場合は、コントラクト内に定義されている他の関数から呼び出されることができないですが、フロントエンドアプリケーションなど外部から実行することはできます。
`public`の場合は、コントラクト内に定義されている他の関数から呼び出すことができ、フロントエンドアプリケーションなど外部からも実行できます。
`internal`の場合は、コントラクト内に定義されている他の関数からのみ呼び出すことができ、フロントエンドアプリケーションなど外部から実行することはできません。

では次に処理の内容を見ていきましょう。
`tokenId`という変数を定義して、`_nextTokenId++`という値を格納しています。
`_nextTokenId++`というのは、`_nextTokenId`に格納されている値に`1`を足す処理（インクリメント）をしています。
`_nextTokenId`が仮に`2`だった場合、`tokenId`には`3`が格納されます。
そしてこの`tokenId`こそ、NFTのユニーク性を示す要素の1つである値です。
NFTがmintされるたびに値が`1`ずつ増えるため、同じ`tokenId`を持つNFTは存在しません。

次に`_safeMint`という関数を実行して、引数で受け取っている`to`というアドレスと先ほど定義した`tokenId`という値を渡しています。
この`_safeMint`という関数は、継承している`ERC721`コントラクトに定義されています。

### _safeMint関数

ではせっかくなので、`_safeMint`の中身を見ていきましょう。

![_safeMint関数の図](https://storage.googleapis.com/zenn-user-upload/e63f655f4522-20240520.png)

上記の赤枠の部分を「**commandキー**」を押しながらクリックしてください。

![_safeMint関数の図](https://storage.googleapis.com/zenn-user-upload/9a5ea5ac1fb3-20240520.png)

そうすると、上記のように`ERC721`というコントラクトが開きます。
これが継承している`ERC721`のコントラクトです。

304行目あたりに先ほど呼び出した`_safeMint`という関数が定義されています。

```solidity
function _safeMint(address to, uint256 tokenId) internal {
    _safeMint(to, tokenId, "");
}
```

さらに別の関数を呼んでいますね。
Solidityでは、同じ関数名でも渡される引数が異なると別の関数扱いになります。
関数内で呼んでいる`_safeMint`は引数が3つで、先ほど実行した`_safeMint`は引数が2つなので別の関数扱いになります。

```solidity
function _safeMint(address to, uint256 tokenId, bytes memory data) internal virtual {
    _mint(to, tokenId);
    _checkOnERC721Received(address(0), to, tokenId, data);
}
```

上記が先ほど実行していた、引数が3つの方の`_safeMint`関数です。
`_mint`という関数を呼んでいるのが確認できます。

:::message
`_checkOnERC721Received(address(0), to, tokenId, data);`の説明は省きます。
:::

```solidity
function _mint(address to, uint256 tokenId) internal {
    if (to == address(0)) {
        revert ERC721InvalidReceiver(address(0));
    }
    address previousOwner = _update(to, tokenId, address(0));
    if (previousOwner != address(0)) {
        revert ERC721InvalidSender(address(0));
    }
}
```

上記の関数が先ほど実行されていた`_mint`関数です。
処理の中身を見ていきましょう。

```solidity
if (to == address(0)) {
    revert ERC721InvalidReceiver(address(0));
}
```

上記では条件分岐を行なっています。
条件分岐とは、条件によって別の処理をするということです。
今回は`to == address(0)`というのが条件です。
これは、mintしたNFTを渡すアドレスが`address(0)`かどうかを確認しています。
`==`は値が等しいかの記号です。
`address(0)`はゼロアドレスと呼ばれ、誰の所有でもないアドレスです。
よって、このゼロアドレスに送ってしまうと誰も取り出せなくなります。

:::message
**burn**するときはこの`address(0)`に送られます。
:::

もしこのゼロアドレスが`to`として引数で渡された場合は、`ERC721InvalidReceiver`というエラーを返して処理を中断します。

```solidity
address previousOwner = _update(to, tokenId, address(0));
```

次に`_update`という別の関数を実行しています。

```solidity
function _update(address to, uint256 tokenId, address auth) internal virtual returns (address) {
    address from = _ownerOf(tokenId);

    // Perform (optional) operator check
    if (auth != address(0)) {
        _checkAuthorized(from, auth, tokenId);
    }

    // Execute the update
    if (from != address(0)) {
        // Clear approval. No need to re-authorize or emit the Approval event
        _approve(address(0), tokenId, address(0), false);

        unchecked {
            _balances[from] -= 1;
        }
    }

    if (to != address(0)) {
        unchecked {
            _balances[to] += 1;
        }
    }

    _owners[tokenId] = to;

    emit Transfer(from, to, tokenId);

    return from;
}
```

ちょっと長いですね...。
まず引数で「`to`（NFTを受け取るアドレス）」、「`tokenId`（mintするNFTのトークンID）」、「`auth`（`tokenId`のNFTの操作権限を持つアドレス）」を渡しています。
`auth`には、現在のNFTの保有者からNFTの操作権限を付与されたアドレスが渡されますが、今回は新規発行のためゼロアドレスが格納されています。

```solidity
address from = _ownerOf(tokenId);
```

上記では、`_ownerOf`という関数を実行して、引数で渡された`tokenId`のNFTの保有者を取得しています。
今回は新規発行のためゼロアドレスが返ってきます。
このようにゼロアドレスは値がないときなどにも使用されます。

```solidity
if (auth != address(0)) {
    _checkAuthorized(from, auth, tokenId);
}
```

ここでは`auth`の値がゼロアドレス以外の場合に、本当に現在のNFTの保有者からNFTの操作権限を付与されているかをチェックしています。

```solidity
if (from != address(0)) {
    // Clear approval. No need to re-authorize or emit the Approval event
    _approve(address(0), tokenId, address(0), false);

    unchecked {
        _balances[from] -= 1;
    }
}
```

上記では、NFTの`trasnfer`（アドレスAからアドレスBへNFTを送るなど）の処理が行われます。

```solidity
if (to != address(0)) {
    unchecked {
        _balances[to] += 1;
    }
}
```

今回は新規発行（`mint`）なので、上記がメインの処理になります。
引数で渡された`to`には、NFTを受け取るアドレスが渡されているため、`address(0)`とは異なります。
`!=`は値が同じではないことを示す記号です。
その後、`_balances[to] += 1;`で`to`が保有しているNFTの数の合計数を`1`足しています。
`+=`は左側の値に右側の値を足す処理をします。

```solidity
mapping(address owner => uint256) private _balances;
```

`_balances`というのは、マッピング配列と言われ上記のように定義されていています。
簡単に説明すると、`owner`というアドレスごとに`uint256`の値が管理されています。

- `0x123abc...` -> `2`
- `0x456def...` -> `5`
- `0x789hij...` -> `1`

上記のようにアドレスごとに、現在保有しているNFTの数が管理されていて、`_balances[to]`（`to`には`0x456def...`などのアドレスが格納されています）というようにすることで`5`などのデータが取得できます。

今回はNFTを新規発行（`mint`）しているため、保有しているNFTの数を`1`増やしています。

```solidity
_owners[tokenId] = to;
```

上記では特定の`tokenId`に紐づくNFTの保有アドレスを取得しています。

```solidity
mapping(uint256 tokenId => address) private _owners;
```

先ほどの`_balances`同様、上記のようにマッピング配列でデータが管理されています。

- `1` -> `0x123abc...`
- `2` -> `0x456def...`
- `3` -> `0x789hij...`
- ...

上記のように`tokenId`に紐づくNFTの現在の保有者を管理しています。

今回はNFTを新規発行（`mint`）しているため、引数で渡されている`tokenId`の保有者を`to`のアドレスに設定しています。

```solidity
emit Transfer(from, to, tokenId);
```

最後に`Transfer`というイベントを発行して、フロントエンドアプリケーションなどに`mint`処理が成功したことを通知しています。

だいぶ長かったですが、これが`mint`処理の全貌です。

## tokenURI

`tokenURI`という関数は、NFTのメタデータを返す関数です。

:::message
メタデータとは、NFTのより詳細な情報が定義されたデータです。
各NFTの名前や説明、画像データ、動画データ、様々なパラメータ（属性など）が定義されています。
:::

![tokenURIの図](https://storage.googleapis.com/zenn-user-upload/c2a2a3dbffcb-20240520.png)

![tokenURIの図](https://storage.googleapis.com/zenn-user-upload/4c57a762de20-20240520.png)

Openseaでいう上記データを管理しているのがメタデータです。

https://opensea.io/ja/assets/ethereum/0x524cab2ec69124574082676e6f654a18df49a048/20599

```solidity
function tokenURI(uint256 tokenId)
        public
        view
        override
        returns (string memory)
    {
```

引数で`tokenId`という値を受け取り、他に色々な値が設定されているのが確認できます。
`public`は`mint`関数でも説明したように、コントラクトの内外からアクセスできるということです。
`view`は読み取り専用関数（データの更新をせずに、データを取得するだけの関数）を示しています。
`override`というのは、コントラクトを継承しているときに、継承元のコントラクト（今回の場合は`ERC721`）に定義されている同じ名前の関数（今回の場合は`tokenURI`）を上書きすることを示しています。
上書きをすることで関数の処理を自分の好きなように書き換えられます。

`returns (string memory)`の部分では、この関数が返すデータの型を定義しています。
今回は文字列を返すため、`string`という値が型として設定されています。
`memory`というのは、関数実行時に一時的にデータを保存することを指します。
通常であればブロックチェーン上にデータを書き込みますが、`memory`を使用すると一時的な保存場所にデータを保存するためガス代もかかりません。

```solidity
require(
    tokenId <= _nextTokenId,
    "ERC721Metadata: URI query for nonexistent token"
);
```

ここでは、引数で渡された`tokenId`が既に`mint`されているものかチェックをしています。
もしまだ`mint`されていないようであればエラーを返して処理を中断します。

```solidity
// string memory uri = "https://ipfs.io/ipfs/QmXbBSeMWZd3wSxAKMhMSs5m5ZzJJDUHdSimnUmEx8BuEp?filename=JBAN.png";
        string memory uri = "https://arweave.net/pP9Rw4hx-Ki8m1R1A5EotbpZW2MAJlenmXbAtTa93Gc"; // ここに好きな画像を入れることも可能
```

ここではNFTの画像のURLを設定しています。
通常であればNFTの画像は`tokenId`ごとに異なりますが、今回は全部同じにしています。

```solidity
return
            string(
                abi.encodePacked(
                    "data:application/json;base64,",
                    Base64.encode(
                        bytes(
                            abi.encodePacked(
                                '{"name": "JBANFT #',
                                Strings.toString(tokenId),
                                '", "description": "JBA NFT", "image": "',
                                uri,
                                '"}'
                            )
                        )
                    )
                )
            );
```

最後にメタデータを組み立てています。

```json
{
	"name": "JBANFT #0",
	"description": "JBANFT NFT",
	"image": "https://arweave.net/pP9Rw4hx-Ki8m1R1A5EotbpZW2MAJlenmXbAtTa93Gc"
}
```

詳細は省きますが、上記のようなデータになるように組み立てて、最終的な出力はbase64形式で変換した以下の値になります。

```bash
data:application/json;base64,eyJuYW1lIjogIkpCQU5GVCAjMCIsICJkZXNjcmlwdGlvbiI6ICJKQkEgTkZUIiwgImltYWdlIjogImh0dHBzOi8vYXJ3ZWF2ZS5uZXQvcFA5Unc0aHgtS2k4bTFSMUE1RW90YnBaVzJNQUpsZW5tWGJBdFRhOTNHYyJ9
```

メタデータがなぜbase64形式で変換されるのがデフォルトなのかの理由は定かではないですが、以下のメリットがあるようです。

- base64形式で変換した値をコントラクトに保存するときに効率よく保存される。
- ほとんどのデータをbase64形式で変換できる。
- 変換したデータだけをEtherum上でやり取りすれば良いため、無駄な処理をしなくて良い。

https://www.reddit.com/r/ethdev/comments/11ocw0s/why_is_base64_encoding_used_for_onchain_metadata/

これでコントラクト内に定義されている関数を一通り解説できました。
次にコントラクトをコンパイルしていきましょう。

# コントラクトのコンパイル

次にコントラクトをコンパイルしていきます。
Solidityで書かれたコントラクトは人間が読みやすいように作られていますが、コンピューターからは読みにくい状態です。
コンパイルをすることで、コンピューターが読みやすいデータに変換することができます。

では早速そのコンパイルをしてみましょう。

![コントラクトのコンパイルの図](https://storage.googleapis.com/zenn-user-upload/82dec0298958-20240520.png)

サイドメニューの真ん中のアイコンをクリックして、「**Compile Nft.sol**」というボタンをクリックします。
サイドメニューのアイコンの右下がくるくるして、サイドチェックマークになればコンパイル成功です。
これだけの単純な処理でコンパイルができます。

![コントラクトのコンパイルの図](https://storage.googleapis.com/zenn-user-upload/d103939df63d-20240520.gif)

# コントラクトのデプロイ

では次にコントラクトのデプロイをしていきましょう。
デプロイとは、コントラクトを公開して他の人が実行したりできるようにすることです。
また、この章ではEthereumのメインネットやテストネットではなく、Remixが提供している環境にデプロイします。
そのため、他の人が触ったりはできませんが動作の確認などはできるため、作成したコントラクトの挙動を確認していきましょう。

![コントラクトのデプロイの図](https://storage.googleapis.com/zenn-user-upload/e5a9b77add0f-20240520.png)

1. サイドメニューの下から2つ目のアイコンをクリック。
2. アドレス横にあるコピーボタンをクリック。
   - ここにあるアドレスは仮のアドレスになります。
3. 上記でコピーしたアドレスを貼り付けてください。
4. 「**Deploy**」ボタンをクリックするとコントラクトがデプロイされます。

上記の手順に沿ってデプロイしていきましょう。

![コントラクトのデプロイの図](https://storage.googleapis.com/zenn-user-upload/4b403d58e305-20240520.png)

デプロイが成功すると、上記のようにデプロイしたコントラクトの関数などが見れるようになります。

![コントラクトのデプロイの図](https://storage.googleapis.com/zenn-user-upload/73d80bd8bd9a-20240520.png)

一番上にコントラクトアドレスがあり、オレンジ色のボタンがデータを更新する関数、青色のボタンがデータを取得する関数です。

# 関数実行

ではデプロイしたコントラクトの関数を実行してみましょう！

# 前提

今回実行に使用するアドレスは、以下の部分でコピーしたものを使います。

![前提の図](https://storage.googleapis.com/zenn-user-upload/e8c9618e1bf0-20240520.png)

## NFT情報

まずはNFTの情報を取得してみましょう。

![NFT情報の図](https://storage.googleapis.com/zenn-user-upload/96c065986656-20240520.png)

上記の3つの関数を実行してそれぞれ正しい情報が表示されているか確認してください。

- `name`
    - NFTコントラクトの名前。
    - `JBANFT`
- `owner`
    - デプロイボタンを押すときに設定したアドレス。
- `symbol`
    - NFTのシンボル名。
    - `JBAN`

## safeMint

次にNFTをmintしていきましょう。

![safeMintの図](https://storage.googleapis.com/zenn-user-upload/a0a1929a4b41-20240520.png)

上記の右の赤枠にコピーしたアドレスを貼り付けて、左の「**safeMint**」というボタンをクリックしてください。

![safeMintの図](https://storage.googleapis.com/zenn-user-upload/5f46f794d862-20240520.png)

実行後、上記の画像のように右下のコンソールと呼ばれる部分に出力がされていれば実行成功です。

## balanceOf

では、次に`balanceOf`関数を実行して、特定のアドレスが保有しているNFTの数を確認しましょう。

![balanceOfの図](https://storage.googleapis.com/zenn-user-upload/83a37ef5a2bf-20240520.png)

上記の右側に先ほどNFTを取得したアドレスを入力し、「**balanceOf**」というボタンをクリックしてください。
「`1`」と出力されれば成功です。
再度`safeMint`関数を実行して、「**balanceOf**」というボタンをもう一度クリックしてみてください。
`balanceOf`はNFTの保有数を取得する関数であるため、「`2`」と出力されれば成功です。

## ownerOf

では、次に`ownerOf`を実行して、特定の`tokenId`に紐づくNFTの保有アドレスを確認しましょう。

![ownerOfの図](https://storage.googleapis.com/zenn-user-upload/39239d523a7c-20240520.png)

`tokenId`を入力する部分に入れます。
まずは`0`を入れて「**ownerOf**」をクリックしてください。
先ほど`safeMint`を実行してNFTを受け取ったアドレスが出力されていれば正しいです。
次に`1`を入れてみてください。
こちらも先ほど同様のアドレスが出力されるはずです。


`2`以降を入力して実行すると以下のようにエラーがコンソールに出力されます。

![ownerOfの図](https://storage.googleapis.com/zenn-user-upload/17a048e04039-20240520.png)

これは存在しない`tokenId`にアクセスしたためです。

## tokenURI

最後に、`tokenURI`関数を実行して、メタデータを取得しましょう。

![tokenURIの図](https://storage.googleapis.com/zenn-user-upload/bdd1422bafd8-20240520.png)

`0`と入力して、上記のようにやたら長いランダムな文字が出力されていれば成功です。
これはbase64という形式に変換されたデータなので、元の形式に戻す必要があります。

https://www.en-pc.jp/tech/base64.php

上記にアクセスして、「`data:application/json;base64,`」以降のデータをコピーしてください。

![tokenURIの図](https://storage.googleapis.com/zenn-user-upload/0538e90097a2-20240520.png)

上記のように入力して、「**変換**」をクリックしてください。
そうすると以下のように出力されます。

```json
{
	"name": "JBANFT #0",
	"description": "JBANFT NFT",
	"image": "https://arweave.net/pP9Rw4hx-Ki8m1R1A5EotbpZW2MAJlenmXbAtTa93Gc"
}
```

- `name`
    - **JBANFT #0**というNFTの名前が出力されます。
- `description`
    - **JBANFT NFT**というNFTの説明が出力されます。
- `image`
    - NFTの画像が出力されます。

`image`の以下のURLにアクセスしてみてください。

https://arweave.net/pP9Rw4hx-Ki8m1R1A5EotbpZW2MAJlenmXbAtTa93Gc

![tokenURIの図](https://storage.googleapis.com/zenn-user-upload/8c42e54bde0e-20240520.png)

上記のように画像が表示されるはずです。

これで一通りの実行は完了です。

# WalletConnectでテストネットにデプロイ

では次のWalletConnectを使用してテストネットにコントラクトをデプロイしてみましょう。

WalletConnectとは、PCやスマートフォンのウォレットアプリケーションに接続することができるサービスです。
WalletConnectを使用することで、スマホしか使用できないユーザーでも簡単にDappsと接続することができるため非常に便利です。

## 前提

### デプロイしたコントラクトの削除

まずは、先ほどデプロイしたコントラクトを削除しましょう。

![デプロイしたコントラクトの削除の図](https://storage.googleapis.com/zenn-user-upload/c54b44c865d2-20240520.png)

上記のようにゴミ箱アイコンをクリックすることで、デプロイしたコントラクトを削除できます。

### テストネットトークンの取得

:::message alert
0.5 Sepolia ETHくらいあると十分です。
:::

今回はSepoliaテストネットを使用するため、Sepoliaテストネットトークンの取得が必要になります。

https://app.optimism.io/faucet

Sepoliaテストネットトークンを保有していない方は以下のサイトから取得してください。

![テストネットトークンの取得の図](https://storage.googleapis.com/zenn-user-upload/72f7f3cbb575-20240520.png)

「**Connect Wallet**」からウォレットを接続し、Githubアカウントを保有している方はGithubアカウントを連携してください。

![テストネットトークンの取得の図](https://storage.googleapis.com/zenn-user-upload/25dc293fc79b-20240520.png)

上記の「**Ethereum Sepolia**」がSepoliaテストネットトークンなので、「**Claim your test ETH**」に取得したいアドレスを入力し、「**Ethereum Sepolia**」右にあるボタンをクリックしてください。
しばらくするとウォレットにSepoliaテストネットトークンが入ってきます。

もし、Githubアカウントを持っていない場合は以下のサイトから0.05 ETHを取得することができます。

https://cloud.google.com/application/web3/faucet/ethereum/sepolia

## WalletConnectでの接続

では、WalletConnectを使用してウォレットと接続していきましょう。

![WalletConnectでの接続の図](https://storage.googleapis.com/zenn-user-upload/cdb99a3e88ca-20240520.png)

上記のように「**ENVIRONMENT**」の部分をクリックして「**WalletConnect**」を選択してください。

![WalletConnectでの接続の図](https://storage.googleapis.com/zenn-user-upload/0d1668a1cae4-20240520.png)

そうすると上記のように「**Wallet Connect**」というタブが開くので、「**Connect Wallet**」というボタンをクリックしてください。

:::message
**Wallet Connect**と**Connect Wallet**がこんがらがってくると思いますが、頑張ってついてきてください。
:::

![WalletConnectでの接続の図](https://storage.googleapis.com/zenn-user-upload/8b8fea8d0459-20240520.png)

ここで2つのパターンがあります。

:::message alert
今回はスマホの方で進めます。
PCでもやっていることは変わらないので同じように進めてください。
:::

### PC

PCの場合は青枠の方の「**Metamask**」と「**Browser Wallet**」のどちらかを選択してください。

![PCの図](https://storage.googleapis.com/zenn-user-upload/6935850ef8ff-20240520.png)

そうすると上記のように接続したいウォレットを選択して、ページ下部までスクロールして「**Next**」をクリックしてください。

![PCの図](https://storage.googleapis.com/zenn-user-upload/bca7da37549c-20240520.png)

その後、「**Connect**」をクリックしてください。

![PCの図](https://storage.googleapis.com/zenn-user-upload/91de4e47aa4f-20240520.png)

remixのページに戻るので、上記の赤枠部分に接続したアドレスが表示されていれば成功です。

### スマホ

スマホの場合は赤枠の「**WalletConnect**」をクリックしてください。
今回はMetamaskアプリを使用していきます。

![スマホの図](https://storage.googleapis.com/zenn-user-upload/e1bc558cb73d-20240520.png)

スマホのカメラアプリで上記のように表示されたQRコードを読み込んでください。
Metamaskアプリに誘導されるので移動してください。

![スマホの図](https://storage.googleapis.com/zenn-user-upload/9eb072131a52-20240520.jpg)

上記のように表示されるので、右下の「**接続**」をクリックしてください。

![スマホの図](https://storage.googleapis.com/zenn-user-upload/ab62ab5092ff-20240520.png)

接続が完了すると、上記のように赤枠部分に接続したアドレスが表示されます。

![スマホの図](https://storage.googleapis.com/zenn-user-upload/9eb072131a52-20240520.jpg)

もし接続がうまくいかない場合は、上記のようにページ上部にあるネットワークの中から「**Sepolia Test Network**」を選択してください。
それでもうまくいかない場合はカメラアプリやMetamaskアプリの再起動やremixページのリロードなどをしてみてください。

## ウォレットの資産確認

今回はSepoliaテストネットを使用します。
そのため、先ほど接続したウォレットにSepliaテストネットトークンがない場合は、トークンを接続したウォレットに送付してください。

![ウォレットの資産確認の図](https://storage.googleapis.com/zenn-user-upload/6620ae6d4b94-20240520.png)

送付した後ページをリロードすると上記の赤枠に、ウォレット内のSepoliaテストネットトークンの保有量が表示されます。

![ウォレットの資産確認の図](https://storage.googleapis.com/zenn-user-upload/48607e357ba8-20240520.png)

## コントラクトのデプロイ

では、前章で試した手順で今後はSepoliaテストネットにコントラクトをデプロイしてみましょう。

![コントラクトのデプロイの図](https://storage.googleapis.com/zenn-user-upload/48607e357ba8-20240520.png)

上記のように接続したウォレットアドレスをコピーして、「**Deploy**」ボタンの右に貼り付けてください。
貼り付けるたら「**Deploy**」というボタンをクリックしてください。

![コントラクトのデプロイの図](https://storage.googleapis.com/zenn-user-upload/bdfc1a41ac08-20240520.jpg)

スマホのMetamaskアプリに上記のように表示されるので、右下の「**確定**」を押してください。

![コントラクトのデプロイの図](https://storage.googleapis.com/zenn-user-upload/3fd40875f89a-20240520.png)

上記のように赤枠部分が表示されていればデプロイ成功です。
「**view on etherscan**」をクリックすると、Sepoliaテストネットにコントラクトをデプロイした時のトランザクションを確認できます。

https://sepolia.etherscan.io/tx/0x1155875d424d9b7a79e321e9eb795f384a7aedb078be768e3577b23eda60d47e

## NFTのMint

では、次にNFTをMintしていきましょう。

![NFTのMintの図](https://storage.googleapis.com/zenn-user-upload/54a939d57bfc-20240520.png)

上記のように接続したウォレットアドレスを入力して「**safeMint**」というボタンを押してください。

![NFTのMintの図](https://storage.googleapis.com/zenn-user-upload/bfd32f753d1c-20240520.jpg)

スマホのMetamaskで上記のように表示されるので、「**確定**」を押します。

![NFTのMintの図](https://storage.googleapis.com/zenn-user-upload/dd9740e63518-20240520.jpg)

![NFTのMintの図](https://storage.googleapis.com/zenn-user-upload/706c7a48078a-20240520.jpg)

その後上記のようにページ下部にトランザクションの状態が表示され、「**トランザクション〇〇が完了しました**」と出力されれば成功です。

![NFTのMintの図](https://storage.googleapis.com/zenn-user-upload/4e5eed94ffec-20240520.png)

remixでも上記のようにコンソールに出力されていれば成功を確認できます。

コンソール内の「**view on etherscan**」をクリックすることで、Mintのトランザクションを確認できます。

https://sepolia.etherscan.io/tx/0xc1d1d9d85053f049dac30824392cd3a4c75ab929ec127f3d691f3282bd738aae

![NFTのMintの図](https://storage.googleapis.com/zenn-user-upload/cbcb1a9a52c5-20240527.png)

わかりづらいのですが、上記にコントラクトアドレスが記載されています。
右側のコピーアイコンをクリックして、コントラクトアドレスをコピーしてください。

https://testnets.opensea.io/ja

コピーできたら上記のリンクを開いてください。
これはOpenseaといって、NFTのマーケットプレイスです。
NFTの売買ができる場所と覚えてもらえれば問題ないです。
今回はTestnetにコントラクトをデプロイしているため、Testnet用のOpenseaサイトを開いています。

![NFTのMintの図](https://storage.googleapis.com/zenn-user-upload/cca11912331e-20240527.png)

上記の赤枠部分に、先ほどコピーしたコントラクトアドレスを貼り付けください。
そうすると「**コレクション**」という部分に、先ほどデプロイしたコントラクトが「**JBANFT**」と表示されているのでクリックします。

![NFTのMintの図](https://storage.googleapis.com/zenn-user-upload/5b54cd05dcc6-20240527.png)

上記のような画面が開き、「**JBANFT #0**」という名前のNFTが表示されているのでクリックします。

![NFTのMintの図](https://storage.googleapis.com/zenn-user-upload/49e2b576f263-20240527.png)

そうすると上記のように表示されます。
これが先ほどMintしたNFTです。

## NFTのチェック

では最後に`balanceOf`、`ownerOf`、`tokenURI`の関数を実行してデータをチェックしましょう。

![NFTのチェックの図](https://storage.googleapis.com/zenn-user-upload/ce081f981251-20240520.png)

上記のように、`balanceOf`にはウォレットのアドレス、`ownerOf`と`tokenURI`には`0`という値を入れて実行してください。

- `balanceOf`
    - `1`
- `ownerOf`
    - ウォレットのアドレス。
- `tokenURI`
    - ` data:application/json;base64,eyJuYW1lIjogIkpCQU5GVCAjMCIsICJkZXNjcmlwdGlvbiI6ICJKQkEgTkZUIiwgImltYWdlIjogImh0dHBzOi8vaXBmcy5pby9pcGZzL1FtWGJCU2VNV1pkM3dTeEFLTWhNU3M1bTVaekpKRFVIZFNpbW5VbUV4OEJ1RXA/ZmlsZW5hbWU9SkJBTi5wbmcifQ==`
 
上記のように出力されていれば成功です！

`tokenURI`の中身の確認方法は、以下の`tokenURI`の章を確認してください。

https://zenn.dev/cryptogames/articles/3903c469ffff87#tokenuri-1

# 最後に

今回はRemixでWallet Connectを使用してNFTコントラクトをデプロイする手順を紹介してきました。
できる限り噛み砕いて非エンジニアでもデプロイできるように解説してきましたがいかがだったでしょうか？

以下でも情報発信しているので、興味ある記事があればぜひ読んでみてください！

https://twitter.com/cardene777

https://chaldene.net/

https://qiita.com/cardene

https://cardene.substack.com/

https://mirror.xyz/0xcE77b9fCd390847627c84359fC1Bc02fC78f0e58

https://cardene.notion.site/EIP-2a03fa3ea33d43baa9ed82288f98d4a9
