メインコンテンツへスキップ

NFTの作成&デプロイ方法(NFTチュートリアルシリーズの1/3)

ERC-721AlchemySolidityスマートコントラクト
初級
Sumi Mudgil
2021年4月22日
21 分の読書 minute read

NFTによってブロックチェーンが世間の目に触れるようになった今、イーサリアムブロックチェーン上に自分のNFTコントラクト(ERC-721トークン)を公開することで、自身のモチベーションを高める絶好の機会となります。

Alchemyは、Makersplace(直近では、Christie'sでレコードデジタルアートワークが$69Mで落札され、記録を更新)、 Dapper Labs(NBA Top Shot&Crypto Kittiesのクリエイター)、OpenSea(世界最大のNFTマーケットプレイス)、Zora、Super Rare、NFTFi、Foundation、Enjin、Origin Protocol、Immutableなど、NFTスペースで著名人の力になれることを非常に誇りに思っています。

このチュートリアルでは、MetaMask(opens in a new tab)Solidity(opens in a new tab)Hardhat(opens in a new tab)Pinata(opens in a new tab)Alchemy(opens in a new tab)を使用してSepoliaテストネットワーク上でERC-721スマートコントラクトの作成とデプロイのウォークスルーを行います(現時点でしっかりと理解できていなくても、心配はご無用です。後ほどご説明します) 。

チュートリアルのパート2では、スマートコントラクトを使用してNFTをミントする方法について、パート3では、MetaMaskでNFTを表示する方法について説明します。

ご質問があればAlchemy Discord(opens in a new tab)にお問い合わせいただくか、 AlchemyのNFT API docs(opens in a new tab)をご覧ください。

ステップ1: イーサリアムネットワークに接続する

イーサリアムのブロックチェーンにリクエストを行う方法はたくさんありますが、ここでは分かりやすくするため、Alchemy(opens in a new tab)の無料アカウントを使用します。このアカウントはブロックチェーンの開発者プラットフォームとAPIで、独自のノードを実行せずにイーサリアムチェーンと通信できるものです。

このチュートリアルでは、スマートコントラクトのデプロイメントの仕組みを理解するために、Alchemyの開発者用ツールも活用します。 Alchemyアカウントをお持ちでない場合は、 こちら(opens in a new tab)から無料で登録できます。

ステップ2: アプリ(およびAPIキー)を作成する

Alchemyのアカウントを作成すると、アプリを作成することでAPIキーを生成できます。 これにより、Sepoliaテストネットワークへのリクエストが可能になります。 テストネットワークの詳細については、こちらのガイド(opens in a new tab)をご覧ください。

  1. ナビゲーションバーの「Apps」にマウスを合わせて、「Create App)」をクリックし、Alchemyダッシュボードの「Create App」ページに移動してください。

アプリを作成する

  1. アプリに名前を付け(私たちは「My First NFT!」にしました)、簡単な説明を記述し、「Ethereum」チェーンを選択して、ネットワークに「Sepolia」を設定します。 マージ以降、他のテストネットは非推奨となっています。

アプリを設定して公開する

  1. 「Create app」をクリックして完了です。 下記のテーブルにアプリが表示されます。

ステップ 3: イーサリアムアカウント(アドレス)を作成する

トランザクションの送受信には、イーサリアムアカウントが必要です。 このチュートリアルでは、イーサリアムアカウントアドレスを管理するためにブラウザの仮想ウォレットであるMetamaskを使用します。 イーサリアムのトランザクションの仕組みの詳細については、イーサリアム・ファウンデーションのこちらのページをご覧ください。

Metamaskのアカウントはこちら(opens in a new tab)から無料でダウンロード、作成できます。 アカウントを作成後、またはすでにアカウントをお持ちの場合は(実際に支払いが発生しないように)右上の「Sepolia Test Network」に切り替えてください。

Sepoliaをネットワークとして設定する

ステップ4: フォーセットからイーサリアムを追加する

テストネットワークにスマートコントラクトをデプロイするには、偽のETHが複数必要になります。 ETHを取得するには、AlchemyがホストするSepoliaフォーセット(opens in a new tab)へ行き、ログインしてアカウントアドレスを入力し、「Send Me ETH」をクリックしてください。 MetamaskアカウントにETHが表示されるはずです。

ステップ5: 残高を確認する

残高を再度確認するには、 Alchemy CHAINS APIS(opens in a new tab)を使用して eth_getBalance(opens in a new tab)をリクエストしてみましょう。 リクエストすると、ウォレット内のETHの量が返却されます。 Metamaskアカウントアドレスを入力して「Send Request」をクリックすると、次のようなレスポンスが表示されます。

1`{"jsonrpc": "2.0", "id": 0, "result": "0xde0b6b3a7640000"}`

注: この結果の単位はweiであり、ETHではありません。 weiはETHの最小単位として使われています。 「wei」 から「ETH」への変換は次の通りです: 1 eth = 1018 wei 。 例えば、0xde0b6b3a7640000を10進数に変換すると1*1018 weiとなり、1ETHに相当します。

ご安心ください。 私たちの偽物のお金はすべてそこにあります。

ステップ6: プロジェクトを初期化する

まず、プロジェクトのフォルダを作成する必要があります。 コマンドラインに移動し、次のように入力します。

1mkdir my-nft
2cd my-nft

プロジェクトフォルダに入ったら、 npm initを使用してプロジェクトを初期化します。 npmがインストールされていない場合は、こちらの手順(opens in a new tab)に従ってください。(Node.js(opens in a new tab)も必要となりますので、こちらもダウンロードしてください。)

1npm init

インストール時の質問に対する回答方法は自由です。参考までに過去の回答方法は次のとおりです。

1package name: (my-nft)
2version: (1.0.0)
3description: My first NFT!
4entry point: (index.js)
5test command:
6git repository:
7keywords:
8author:
9license: (ISC)
10About to write to /Users/thesuperb1/Desktop/my-nft/package.json:
11
12{
13 "name": "my-nft",
14 "version": "1.0.0",
15 "description": "My first NFT!",
16 "main": "index.js",
17 "scripts": {
18 "test": "echo \"Error: no test specified\" && exit 1"
19 },
20 "author": "",
21 "license": "ISC"
22}
すべて表示

「package.json」を承認してください。これで準備が完了しました。

ステップ7: Hardhat(opens in a new tab)をインストールする

Hardhatは、イーサリアムのソフトウェアをコンパイル、デプロイ、テスト、デバッグするための開発環境です。 開発者がライブチェーンにデプロイする前に、スマートコントラクトやDappsをローカルに構築する際に役立ちます。

「my-nft」プロジェクトの中で実行してください。

1npm install --save-dev hardhat

インストール手順(opens in a new tab)の詳細については、こちらのページをご覧ください。

ステップ8: Hardhatプロジェクトを作成する

プロジェクトフォルダ内で実行してください。

1npx hardhat

次に、ウェルカムメッセージと選択肢が表示されます。 「create an empty hardhat.config.js」を選択してください。

1888 888 888 888 888
2888 888 888 888 888
3888 888 888 888 888
48888888888 8888b. 888d888 .d88888 88888b. 8888b. 888888
5888 888 "88b 888P" d88" 888 888 "88b "88b 888
6888 888 .d888888 888 888 888 888 888 .d888888 888
7888 888 888 888 888 Y88b 888 888 888 888 888 Y88b.
8888 888 "Y888888 888 "Y88888 888 888 "Y888888 "Y888
9👷 Welcome to Hardhat v2.0.11 👷‍
10? What do you want to do? …
11Create a sample project
12❯ Create an empty hardhat.config.js
13Quit
すべて表示

「hardhat.config.js」というファイルが生成され、ここでプロジェクトのセットアップの全てを指定します (ステップ13)。

ステップ9: プロジェクトフォルダを追加する

プロジェクトを整理するために、2つの新しいフォルダを作成します。 コマンドラインでプロジェクトのルートディレクトリに移動し、次のように入力します。

1mkdir contracts
2mkdir scripts
  • 「contracts/」は、NFT スマートコントラクトコードを保持する場所です。

  • 「scripts/」 は、スマートコントラクトをデプロイして対話するスクリプトを保持する場所です。

ステップ10: コントラクトを作成する

さて、環境が整ったところで、もっと面白いことをやりましょう。スマートコントラクトのコードの作成です。

お気に入りのエディタでmy-nftプロジェクトを開きます(通常はVScode(opens in a new tab)を使用しています)。 スマートコントラクトは、Solidityと呼ばれる言語で記述されています。MyNFT.solスマートコントラクトの作成にこの言語を使用します。

  1. contractsフォルダに移動し、MyNFT.solという名前の新規ファイルを作成します。

  2. 以下は、 NFTスマートコントラクトコードです。これはOpenZeppelin(opens in a new tab)ライブラリのERC-721実装に基づいています。 以下の内容をコピーして、MyNFT.solファイルに貼り付けます。

    1//Contract based on [https://docs.openzeppelin.com/contracts/3.x/erc721](https://docs.openzeppelin.com/contracts/3.x/erc721)
    2// SPDX-License-Identifier: MIT
    3pragma solidity ^0.8.0;
    4
    5import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
    6import "@openzeppelin/contracts/utils/Counters.sol";
    7import "@openzeppelin/contracts/access/Ownable.sol";
    8import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
    9
    10contract MyNFT is ERC721URIStorage, Ownable {
    11 using Counters for Counters.Counter;
    12 Counters.Counter private _tokenIds;
    13
    14 constructor() ERC721("MyNFT", "NFT") {}
    15
    16 function mintNFT(address recipient, string memory tokenURI)
    17 public onlyOwner
    18 returns (uint256)
    19 {
    20 _tokenIds.increment();
    21
    22 uint256 newItemId = _tokenIds.current();
    23 _mint(recipient, newItemId);
    24 _setTokenURI(newItemId, tokenURI);
    25
    26 return newItemId;
    27 }
    28}
    すべて表示
    コピー
  3. OpenZeppelinのコントラクトライブラリからクラスを継承しているので、コマンドラインでnpm install @openzeppelin/contractsを実行して、ライブラリをフォルダにインストールします。

では、このコードの役割は一体何でしょうか。 一行ずつ分解してみましょう。

スマートコントラクトの先頭で、3つのOpenZeppelin(opens in a new tab)スマートコントラクトのクラスをインポートしています。

  • @openzeppelin/contracts/token/ERC721/ERC721.solには、ERC-721標準の実装が含まれており、NFTスマートコントラクトはこれを継承しています。 (有効なNFTであるためには、スマートコントラクトはERC-721標準のすべてのメソッドを実装する必要があります。) 継承されたERC-721関数の詳細については、こちら(opens in a new tab)のインターフェイス定義をご覧ください。

  • @openzeppelin/contracts/utils/Counters.solは、1つずつ増減するカウンタを提供しており、 私たちのスマートコントラクトは、ミントされたNFTの合計数を追跡し、新しいNFTにユニークなIDを設定するためにカウンタを使用しています。 (スマートコントラクトを使用してミントされた各NFTには、ユニークなIDが割り当てられている必要があります。ここでは、ユニークIDは、存在するNFTの合計数によって決定されます。 例えば、スマートコントラクトでミントした最初のNFTには「1」のIDが付与され、2番目のNFTには「2」のIDが付与されます。)

  • @openzeppelin/contracts/access/Ownable.solはアクセスコントロール(opens in a new tab)をスマートコントラクトに設定するため、スマートコントラクトの所有者(あなた)だけがNFTをミントできます。 (注: アクセス制御の実装は完全に任意です。 スマートコントラクトを使って誰でもNFTをミントできるようにしたい場合は、10行目の「Ownable」、17行目の「onlyOwner」を削除します。)

インポートステートメントの後にカスタムNFTスマートコントラクトがありますが、非常に短いもので、カウンタ、コンストラクタ、単一の関数しか含まれていません。 これは、NFTの所有者を返すownerOfとNFTの所有権を他のアカウントに転送するtransferFromなど、NFTを作成するために必要な大部分のメソッドを実装しているOpenZeppelinコントラクトを継承したおかげです。

ERC-721コンストラクタでは、「MyNFT」と「NFT」の2つの文字列を渡すことに気づくでしょう。 最初の変数はスマートコントラクトの名前で、2番目の変数はそのシンボルです。 これらの変数にはそれぞれに自由に名前を付けることができます。

最後に、mintNFT(address recipient, string memory tokenURI)という関数で、NFTをミントすることできます。 この関数には2つの変数が必要です。

  • address recipientは、新しくミントされたNFTを受け取るアドレスを指定します。

  • string memory tokenURIは、NFTのメタデータを記述したJSONドキュメントに解決される必要がある文字列です。 NFTのメタデータは、名前、説明、画像、その他の属性など、設定可能なプロパティを持つことができます。 チュートリアルのパート2では、このメタデータの設定方法について説明します。

mintNFTは継承されたERC-721ライブラリから複数のメソッドを呼び出し、最終的にミントされたばかりのNFTのIDを示す数値を返します。

ステップ11: MetaMaskとAlchemyをプロジェクトに接続する

ここまででMetaMaskウォレットとAlchemyアカウントを作成し、スマートコントラクトを書きました。次はこの3つのアカウントを繋げていきましょう。

仮想ウォレットから送信されるすべてのトランザクションには、固有の秘密鍵を使用した署名が必要です。 この許可をプログラムに与えるために、秘密鍵(とAlchemyのAPIキー)を環境ファイルに安全に格納する作業を行います。

トランザクションの送信の詳細については、web3を使用したトランザクションの送信に関するこちらのチュートリアルをご覧ください。

まず、プロジェクトディレクトリにdotenvパッケージをインストールします。

1npm install dotenv --save

次に、 .envファイルをプロジェクトのルートディレクトリに作成し、そのファイルにMetamaskの秘密鍵とHTTP Alchemy APIのURLを追加します。

  • MetaMaskから秘密鍵をエクスポートするには、 こちらの手順(opens in a new tab)に従ってください。

  • HTTP Alchemy API URLを取得し、クリップボードにコピーするには、以下を参照してください。

Alchemy API URLをコピーする

.envファイルは次のようになります。

1API_URL="https://eth-sepolia.g.alchemy.com/v2/your-api-key"
2PRIVATE_KEY="your-metamask-private-key"

これらの変数を実際にコードに接続するために、ステップ13で hardhat.config.jsファイル内のこれらの変数を参照します。

page-tutorials-env-banner

ステップ12: Ethers.jsをインストールする

Ethers.jsは、よりユーザーフレンドリーなメソッドで標準のJSON-RPCメソッドをラップすることにより、イーサリアムとの対話やリクエストを簡単にするライブラリです。

Hardhatは、追加のツールと拡張機能のためのプラグイン(opens in a new tab)の統合を非常に簡単にしてくれます。 コントラクトのデプロイメントにEthersプラグイン(opens in a new tab)を利用します(Ethers.js(opens in a new tab)には、複数の非常にクリーンなコントラクトのデプロイメント方法があります)。

プロジェクトのホームディレクトリで以下を実行します。

1npm install --save-dev @nomiclabs/hardhat-ethers ethers@^5.0.0

次のステップでは、 hardhat.config.js でもイーサリアムが必要になります。

ステップ13: hardhat.config.jsをアップデートする

これまでにいくつかの依存関係とプラグインを追加しました。プロジェクトがそれらすべてを知るように、 hardhat.config.js を更新する必要があります。

「hardhat.config.js」を以下のように更新してください:

1/**
2* @type import('hardhat/config').HardhatUserConfig
3*/
4require('dotenv').config();
5require("@nomiclabs/hardhat-ethers");
6const { API_URL, PRIVATE_KEY } = process.env;
7module.exports = {
8 solidity: "0.8.1",
9 defaultNetwork: "sepolia",
10 networks: {
11 hardhat: {},
12 sepolia: {
13 url: API_URL,
14 accounts: [`0x${PRIVATE_KEY}`]
15 }
16 },
17}
すべて表示

ステップ14: コントラクトをコンパイルする

ここまででしっかりと動作していることを確認するため、コントラクトをコンパイルしてみましょう。 コンパイルは、Hardhat の組み込まれた機能の1つです。

コマンドラインで以下を実行します。

1npx hardhat compile

SPDX license identifier not provided in source file という警告が表示されるかもしれません。しかし、それについて心配する必要はありません — うまくいけば、他のすべてが良く見えるでしょう! 表示された場合は、いつでもAlchemy discord(opens in a new tab)でメッセージを送信できます。

ステップ15: デプロイスクリプトを書く

コントラクトの作成と設定ファイルの作成が完了したら、いよいよコントラクトのデプロイのためのスクリプトを作成します。

scripts/ フォルダに移動し、 deploy.js という名前の新しいファイルを作成し、以下の内容を追加します:

1async function main() {
2 const MyNFT = await ethers.getContractFactory("MyNFT")
3
4 // Start deployment, returning a promise that resolves to a contract object
5 const myNFT = await MyNFT.deploy()
6 await myNFT.deployed()
7 console.log("Contract deployed to address:", myNFT.address)
8}
9
10main()
11 .then(() => process.exit(0))
12 .catch((error) => {
13 console.error(error)
14 process.exit(1)
15 })
すべて表示
コピー

Hardhatがコードの各行で行っている驚くべき内容については、Hardhatのコントラクトチュートリアル(opens in a new tab)で説明されています。以下では、その説明を採用しています。

1const MyNFT = await ethers.getContractFactory("MyNFT");

ethers.js の中の ContractFactory は新しいスマートコントラクトを作成するための抽象化です。ここでの MyNFT は NFT コントラクトのインスタンスのためのファクトリです。 hardhat-ethers プラグインを使用する場合、 ContractFactory および Contract インスタンスはデフォルトで最初の署名者に接続されます。

1const myNFT = await MyNFT.deploy();

ContractFactory の deploy() を呼び出すとデプロイメントが開始し、 Contract を解決するための Promise が返されます。 これは、スマートコントラクトの各関数に対するメソッドを持つオブジェクトです。

ステップ16: コントラクトをデプロイする

ようやく、スマートコントラクトをデプロイする準備が整いました。 プロジェクトディレクトリのルートに戻り、コマンドラインで以下を実行します:

1npx hardhat --network sepolia run scripts/deploy.js

次のような画面が表示されるはずです。

1Contract deployed to address: 0x4C5266cCc4b3F426965d2f51b6D910325a0E7650

Sepolia etherscan(opens in a new tab)に移動し、コントラクトアドレスを検索すると、正常にデプロイされたことが確認できるはずです。 すぐに見られない場合は、しばらくお待ちください。 トランザクションは以下のようなものになります。

Etherscan でトランザクションアドレスを表示する

From アドレスは MetaMask アカウントアドレスと一致し、To アドレスは「Contract Creation」となります。 トランザクション内容をクリックすると、To フィールドにコントラクトアドレスが表示されます:

Etherscanでコントラクトアドレスを表示する

Yassss! イーサリアム(テストネット)チェーンにNFTスマートコントラクトをデプロイできました。

内部で何が起こっているのかを理解するために、Alchemyダッシュボード(opens in a new tab)のExplorerタブに移動してみましょう。 Alchemy のアプリが複数ある場合は、必ずアプリでフィルタリングし、「MyNFT」を選択してください。

Alchemy のエクスプローラーダッシュボードで「内部」で行われた通話を表示する

ここでは、 .deploy() 関数を呼び出した際に、Hardhat/Ethers が内部で作った JSON-RPC の呼び出しをいくつか見ることができます。 ここで呼び出している2つの重要なJSON-RPCは、実際にSepoliaチェーン上でコントラクトを書き込むリクエストのeth_sendRawTransactionと、(トランザクションを送信する際の典型的なパターンである) ハッシュを与えられたトランザクションに関する情報を読み取るリクエストeth_getTransactionByHashです。 トランザクションの送信の詳細については、このチュートリアルの Web3 を使用したトランザクションの送信 をご覧ください。

以上がこのチュートリアルのパート1です。 パート2 では、NFT を発行することで実際にスマートコントラクトとやりとりをします。そして、パート3 では、Etherreum ウォレット内の NFT を確認する方法を示します!

最終編集者: @mfujimori1018(opens in a new tab), 2024年4月1日

このチュートリアルは役に立ちましたか?