【完全保存版】solidityでERC20,ERC721を作成しよう!(プログラミング未経験者向け)
この記事では、プログラミングを行ったことがない方を想定して、solidityでERC20、ERC721のコントラクトを作成することを目的としています。
事前にメタマスクのインストールをしていただければ、最後まで読み進めることができます。
0 はじめに
1 テストトークン(Mumbai)を取得する
まずは、始める前にテストトークンを取得します。
今回はPolygonのテストネットのMumbaiを使用します。
下のように、ウォレットアドレスを入れて、「Submit」
「Confirm」を押します。
このようになれば成功です。
なお、既にたくさんのMumbaiのトークンを持っている場合は、エラーになると思います。
2 メタマスクにMumbaiを入れる
では、次に、メタマスクにMumbaiを入れていきます。
「ChainList」から「Add to Metamask」で入れることができます。
1 Remixでコントラクトの作成を体験してみる
まずは、Remixを使って、コントラクトの作成を体験してみましょう。
今回は、フルオンチェーンのコントラクトの「Loot」をやってみます。
1 空のSolidityファイルを作る
では、Remixを使っていきましょう。
こちらの「+」ボタンを押します。
「Create Workspace」と出てくるので、そのまま「OK」を押します。
すると、このようなワークスペースができました。
「contracts」フォルダを選択した状態で、こちらを押して、ファイルを作成します。
名前を「Loot.sol」にします。
これでsolidityのファイルができました。
なお、solidityのファイルは末尾(拡張子)が「.sol」となっています。
2 公開されているコントラクトのコードをコピーする
では、公開されているコントラクトのコードを取得していきましょう。
今回は、こちらの「Loot」のコードを取得します。
https://opensea.io/ja/collection/lootproject
任意のNFTを選択します。
すると、下の「詳細」の部分に「コントラクトアドレス」が出るので、選択します。
すると、「Etherscan」のページに飛びました。
ここでコントラクトのコードを確認できます。
「Contract」の「Code」を選択します。
こちらがコードになります。
右のアイコンからコードをコピーしましょう。
3 solidityファイルにコードを貼り付ける
では、コピーしたコードを先ほどの空のファイルに貼り付けましょう。
すると、このような警告が出ます。
コピペはリスクがありますという警告です。
その通りですが、今回はテストなので、そのまま「OK」を押します。
これで、solidityのファイルができました。
4 コンパイルを行う。
solidityは(習得すれば)人間にとっては読みやすいですが、機械には読みにくいです。
下から「コンパイル」を行い、機会が読みやすい形にします。
緑のチェックがつけば、コンパイルが完了しています。
5 デプロイを行う
では、チェーン上にコントラクトを作っていきます。(デプロイ)
まずは、下のように、「Injected Provider」を選択します。
これにより、メタマスクでデプロイすることができます。
こちらから、どのコントラクトをデプロイするかを選択します。
このように、今回は「Loot」を選択します。
「Deploy」を選択します。
メタマスクが立ち上がるので、「確認」を押します。
「… pending」というのは完了していないことを示しています。
このように、緑のチェックがつけば完了です。
コントラクトが作成できました。
6 NFTを取得する(Claimを行う)
では、NFTを所得してみましょう。
下のボタンを押すと、使える関数が表示されます。
任意の番号を入れて、「claim」を押します。
この番号は欲しいNFTのトークンIDです。
このように、緑のチェックがつけば完了です。
7 Opensea(testnet)で確認してみる
では、できたNFTをOpenSeaのテストネットで確認してみましょう。
初めて入る場合は、承認を求められます。
「Accept and Sign」を選択します。
メタマスクが立ち上がるので、「署名」を行います。
「Profile」を確認するとこのように、LootのNFTができていました。
こちらを選択します。
このように、NFTができたことが確認できました。
8 コントラクトを少し触ってみる
では、コントラクトを少し触ってみましょう。
1291行目から「contract」として、コントラクトのコードが始まっています。
「weapon」を見ると、「Long Sword」などの武器があることが確認できます。
1527行目を見ると、元々「white」とあった部分があったので、「pink」に変えてみました。
これは文字色の部分です。
また、同じく1527行目の「black」を「blue」に変えてみました。
これは背景色の部分です。
先ほどまでと同様にNFTを作成してみると、このように色が変わったことが確認できました。
2 簡易コントラクトを作成する
ここでは、Remixがデフォルトで用意している、「storage.sol」を見ていきます。
1 Storage.solを確認する
「+」ボタンを押して、ワークスペースを作成します。
デフォルトのまま、「OK」を選択します。
「Contracts」フォルダの中に、「1_Storage.sol」があることが確認できました。
なおこのコントラクトは次の2つの機能を持った簡易コントラクトです。
数字を保管する
保管した数字を取り出す
2 SPDXライセンス識別子について
これは、このソフトウェアがどのライセンスに基づいているかを示してます。
このソースが、コピーや改変、再配布などが可能かどうかなどを表します。
最初はあまり気にしなくても良いと思います。
こちらは、「GPL-3.0」ですが、「MIT」などもよく使われます。
3 Solidityコンパイラのバージョンについて
こちらは、コンパイルを行う、コンパイラのバージョンを表しています。
ここでは「0.8.2」以上で「0.9.0」未満になっています。
4 コメントについて
この緑の部分はコメントと呼ばれるものです。
コードの説明などが書かれます。
5 contractについて
この「contract」からコントラクトが開始されます。
右の「Storage」はコントラクト名で、通常はファイル名と一致させます。
6 状態変数について
下のような(次に出てくる)関数以外の部分にあるのが状態変数です。
こちらが、台帳に保存されるものです。
「number」が変数です。
数学でやった、「x = 1」のようなアレです。
7 データ型について
でも数学と違い、この変数には、文字が入ったり、ウォレットアドレスが入ったりします。
uint256は0と正の整数が含まれます。(ざっくりですが)
このように、どう言ったものを入れるかをデータ型と呼びます。
8 関数について
「function」の部分が関数の印です。
その右の「store」や「retrieve」が関数の名前です。
関数は、操作を行う一つのまとまりのようなイメージです。
9 引数について
関数の()の中身は、この関数に何を渡すのかを表します。
これを引数と呼びます。
「store」関数の場合、「何を」保存するのかを示すためにも「num」を引数として渡しています。
「retrieve」関数のように、引数を何も渡さないケースもよくあります。
この辺りは後で実際に見てみましょう。
10 返り値について
関数の中には値が返ってくるものがあります。
下のように、「return」で返ってきます。
ちなみに、この場合、状態変数の「number」の値を返しています。
ここも後で見てみましょう。
また、何も返ってこない場合は、下のように「returns」がありません。
11 publicについて
Etherscanからコントラクトを読んだり書いたりするように、コントラクト外から操作できる関数があります。
それらには、下のように、「public」がついています。
12 「=」について
多くのプログラミング言語において、「=」は「等しい」ではなく、「代入」を表します。
下の場合も、引数の値を「number」という状態変数に入れています。
13 コンパイルを実行する
第1章で行ったのと同様に、コンパイルを行います。
このように、緑のチェックがつけばOKです。
14 デプロイする
では、デプロイしていきましょう。
先ほどと同様に、「Injected Provider」にして、「80001」番であることを確認します。
なお、うまくいかない場合は、「Remix VM」などでも大丈夫です。
この場合はローカルでの実施になりますが、操作自体は確認することができます。
デプロイするコントラクトが「Storage」となっていることを確認して、「Deploy」を選択します。
メタマスクが立ち上がります。
最初はこの「pending」の状態です。
少したち、このように緑のチェックがついたらOKです。
15 関数を確認する
できたら、関数を確認してみましょう。
下のように、「store」と「retrieve」の2つの関数があります。
これが先ほどコードで書いた関数に対応しています。
16 store関数の確認(引数を使ってみる)
では、store関数を使ってみます。
「引数」を設定していたので、このように関数に数字を渡すことができます。
では、「store」を押してみましょう。
メタマスクが立ち上がるので、「確認」を押します。
このように、緑のチェックがついて完了しました。
これで、状態変数の「number」が今入れた「30」になっているはずです。
17 retrieve関数の確認(返り値を見てみる)
では、次に、「retrieve」関数を見てみましょう。
「return」で返り値が設定されていました。
ボタンを押すと、このように、値を取得できました。
3 ERC20のコントラクトを作成する
1 ERC20のファイルを作成する
では、ERC20のコントラクトを作ってみましょう。
「+」ボタンを押します。
こちらの「Basic」の部分を選択して
「ERC20」を選択します。
今回は、ミントができるように、「Mintable」を選択して、「OK」
「MyToken.sol」を確認すると、solidityのファイルができていました。
2 importについて
下のように、「@openzeppelin/..」から、インポートしています。
これは、このファイルに「OpenZeppelin」のファイルを取り込んでいます。
3 継承について
importではファイルを取り込んだだけなので、「is」の「継承」でコントラクトに取り込みます。
例えば、「ERC20」を継承しています。
これにより、「ERC20」というコントラクトにある機能や状態を引き継ぐことができます。
4 constructorについて
コントラクトがデプロイされるときに一度だけ行われる処理が「constructor」です。
ここでは、コントラクト名、シンボル名を「MyToken」、「MTK」と設定しています。
ここは、後でまた出てきます。
5 mint関数について
mint関数を見てみましょう。
引数はこのように2つ以上渡すこともできます。
「誰に(to)」、「どのくらい(amoun)」ミントするのかの情報を渡しています。
6 onlyOwnwerについて
コントラクトの所有者だけしか実行できない処理に「onlyOwner」をつけています。
これは修飾子(modifier)と呼ばれるものです。
7 _mint関数について
関数の中を見てみると、「_mint(to, amount);」という別の関数が実行されています。
このように、関数の中で、別の関数を実行することが可能です。
なお先頭の「_」はコントラクト内部でしか実行できないことを慣習的に表しています。
8 インポートファイルの確認について
インポートしたファイルを確認してみましょう。
その前に、「コンパイル」を行う必要があります。
では、こちらのファイルを見てみましょう。
「cmd」キーを押した状態でこのファイルを選択します。(windowsの方は、おそらく「ctrl」キー)
すると、このように、「ERC20.sol」のファイルが立ち上がりました。
こちらも、下のようなコントラクトが構成されています。
9 constructorについて
こちらにconstructorがあります。
第4節で出てきた、constructorは実はこの部分を実行していました。
10 stringについて
stringは文字列を表すデータ型です。
つまり、例えば、「name_」という変数には文字が入るのですね。
11 memoryについて
ここの「memory」は文字列がどこに保存されるかを表しています。
メモリーという暫定的な場所に保存されています。
12 constructor内での処理について
ここでのconstructorは引数の値を状態変数に設定しています。
第2章の「store」関数と同じような動作ですね。
13 _mint関数について
mint関数の内部で行われていた「_mint」関数がここにありました。
今回は中身は細かく見ないですが、「require」だけ見てみましょう。
14 requireについて
requireは関数内で、前提条件として使われます。
例えば、この部分は、「ミント先は0アドレスでないこと」という条件がついています。
カンマの左側が条件、右側が条件に合わなかった時に出るエラーメッセージになります。
15 デプロイする
では、デプロイをしていきます。
内容は先ほどと同じです。また、事前にコンパイルも必要です。
16 mintする
では、ここから「mint」してみましょう。
うっすらと「address」「uint256」とあります。
それぞれ、ミント先とミント量を入れることになります。
例えば、このように入れて、「transact」を実行してみます。
17 totalSupplyを実行する
totalSupplyで総供給量を確認してみましょう。
先ほどのミント量が表示されればOKです。
18 メタマスクにインポートする
では、作ったERC20をメタマスクにインポートしてみましょう。
こちらがコントラクトアドレスなので、このアイコンでコピーします。
メタマスクを立ち上げて、「アセット」から下の方に向かいます。
「トークンをインポート」を選択します。
先ほどのコントラクトアドレスを貼り付けます。
数秒すると、「トークンシンボル」「トークンの小数桁数」が自動で入ります。
「カスタムトークンを追加」を選択します。
「トークンをインポート」を選択します。
すると、先ほど作成したトークンがメタマスクにインポートされました。
4 ERC721コントラクトを作成する
1 ERC721のファイルを作成する
では、最後にERC721のファイルを作成していきましょう。
「+」ボタンを選択します。
「Basic」を選択します。
「ERC721」を選択します。
「Mintable」にチェックを入れて、「OK」
すると、このように、ERC721のファイルができました。
2 tokenURIについて
NFTの名前や画像などの情報は「tokenURI」という関数で設定されています。
そちらを見てみましょう。
第3章8節と同じやり方で、「ERC721.sol」を見てみると、下のように、「tokenURI」関数がありました。
では、中身を見てみましょう。
_requireMinted関数で、そのトークンIDがミント済みかを確認しています。
(今回はその関数の中は見にいきません)
そして、「baseURI」に「_baseURI」という関数の結果を入れています。
ここが大事な部分です。
ちなみに、「_baseURI」という関数はここにありました。
中身を見てみると、「""」を返していることがわかりました。
これは空の文字列を表します。
下の部分はざっくりとですが、次のようになっています。
baseURIが
①空の文字列の場合 ⇨ 空の文字列を返す
②空の文字列でない場合 ⇨ baseURIとトークンIDを繋げたものを返す
現在、「_baseURI」が空の文字列を返しています。
そのため、NFTの情報である、名前や画像は何もないことになります。
3 _baseURI関数を上書きする
では、_baseURI関数が空の文字列ではなく、別の文字列を返すように上書きしてみましょう。
下のように、関数を返す値を変えて、「MyToken.sol」に貼り付けてみました。
しかし、エラーが出てしまいました。
4 overrideについて
上書きを行うときは、「override」を入れることが必要です。
そのため、「override」を入れると、エラーが消えました。
function _baseURI() internal pure override returns (string memory) {
return "https://metadata.nft-studio.com/test_sword/";
}
5 safeMintする
では、safeMintからミントをしていきましょう。
ミント先と、トークンIDを入れて、「transact」を実行します。
6 tokenURIで確認する
では、今ミントしたトークンIDのtokenURIを確認してみましょう。
すると、このようなURLが返ってきました。
これは「_baseURI」の返り値とトークンID(今回なら1)を繋いだものになっています。
見てみると、「name」や「description」、「image」の情報が入っています。
ちなみに、「image」に設定してあるURLを確認すると、このような画像を取得できます。
7 OpenSeaで確認する
では、これをもとに、OpenSeaのテストネットで見られる情報を確認してみましょう。
このように、先ほどtokenURIで取得した情報に紐づいていることが確認できました。
非常に長くなりましたが、以上です。
皆さんがsolidityからコントラクトを作成するきっかけになれば幸いです。
その他、必要な資料は、今後こちらに格納していきます。
サポートをしていただけたらすごく嬉しいです😄 いただけたサポートを励みに、これからもコツコツ頑張っていきます😊