HardhatでPolygonテストネットにNFTをデプロイ・Mintする
はじめに
今回はテストネットはMumbaiを使います。
ただ、Mumbaiは非推奨となるようです。
Amoyになる模様。
Hardhatのバージョンは
2.20.1
を使います。
コントラクト実装
OpenZepplinのERC721コントラクトを使います。バージョンは5.0.1
yarn add @openzeppelin/contracts
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.24;
// Uncomment this line to use console.log
// import "hardhat/console.sol";
import {ERC721} from "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
contract HideExampleNft is ERC721, Ownable {
constructor() ERC721("HideExampleNft", "HENFT") Ownable(_msgSender()) {}
function _baseURI() internal pure override returns (string memory) {
return "https://hid3h.github.io/assets/hide-example-nft/metadata/";
}
function safeMint(address to, uint256 tokenId) public onlyOwner {
_safeMint(to, tokenId);
}
}
今回は個人だけで使うので、metadataのJSONファイルは自身のGitHubのリポジトリにおいて公開しているものを使います。
また、念の為mintできるのも自身(コントラクトオーナー)のみとしています。
1年ぶりに触ったんですが、Owanable
のconstructorが引数を取るように変わっていたのを知らなかった。
テスト実装
import { loadFixture } from "@nomicfoundation/hardhat-network-helpers";
import { expect } from "chai";
import { ethers } from "hardhat";
describe("HideExampleNft", function () {
// We define a fixture to reuse the same setup in every test.
// We use loadFixture to run this setup once, snapshot that state,
// and reset Hardhat Network to that snapshot in every test.
async function deployFixture() {
// Contracts are deployed using the first signer/account by default
const [owner, otherAccount] = await ethers.getSigners();
const HideExampleNft = await ethers.getContractFactory("HideExampleNft");
const hideExampleNft = await HideExampleNft.deploy();
return { hideExampleNft, owner, otherAccount };
}
it("token nameとsymbolとオーナーが正しく設定されている", async () => {
const { hideExampleNft, owner } = await loadFixture(deployFixture);
expect(await hideExampleNft.name()).to.equal("HideExampleNft");
expect(await hideExampleNft.symbol()).to.equal("HENFT");
expect(await hideExampleNft.owner()).to.equal(owner.address);
});
it("ミントできる", async () => {
const { hideExampleNft, owner, otherAccount } = await loadFixture(
deployFixture
);
const tokenId = 0;
await hideExampleNft.connect(owner).safeMint(otherAccount.address, tokenId);
expect(await hideExampleNft.ownerOf(tokenId)).to.equal(
otherAccount.address
);
});
it("オーナー以外はミントできない", async () => {
const { hideExampleNft, otherAccount } = await loadFixture(deployFixture);
const tokenId = 0;
await expect(
hideExampleNft
.connect(otherAccount)
.safeMint(otherAccount.address, tokenId)
).to.be.revertedWithCustomError(
hideExampleNft,
"OwnableUnauthorizedAccount"
);
});
it("token URIが正しい", async () => {
const { hideExampleNft, owner, otherAccount } = await loadFixture(
deployFixture
);
const tokenId = 0;
await hideExampleNft.connect(owner).safeMint(otherAccount.address, tokenId);
const tokenURI = await hideExampleNft.tokenURI(tokenId);
expect(tokenURI).to.equal(
"https://hid3h.github.io/assets/hide-example-nft/metadata/0"
);
});
});
コントラクトデプロイの設定
hardhat.config.ts
の設定を行っていきます。
import { HardhatUserConfig } from "hardhat/config";
import "@nomicfoundation/hardhat-toolbox";
require("dotenv").config();
const config: HardhatUserConfig = {
solidity: "0.8.24",
networks: {
mumbai: {
url: `https://polygon-mumbai.g.alchemy.com/v2/${process.env.MUMBAI_ALCHEMY_API_KEY}`,
accounts: [process.env.PRIVATE_KEY || ""],
},
},
};
export default config;
上記のurl
に関して。
デプロイにはAlchemyを使います。
Alchemyは、ブロックチェーンとやり取りするためのインフラストラクチャプロバイダーで、ノードへのアクセスを提供しています。
Alchemyを使うことで、自分でノードを立ち上げなくて済みます。
MUMBAI_ALCHEMY_API_KEY=xxxxxxxxxxxxxx
API_KEYはAlchemyで適当にAppを作成して「API Key」から表示されるのでそれを使います。
accounts
に関して。
PRIVATE_KEY
にはコントラクトをデプロイするアカウントの秘密鍵をセットします。
秘密鍵の確認方法は、MetaMaskの場合は「アカウントの詳細」->「秘密鍵を表示」となります。
MUMBAI_ALCHEMY_API_KEY=xxxxxxxxxxxxxx
PRIVATE_KEY=xxxxxxxxxxx
また、環境変数を.env
ファイルで扱いたいのでdotenv
をインストールしておきます。
yarn add dotenv
コントラクトデプロイ
デプロイするスクリプトを用意してそれを実行します。
import { ethers } from "hardhat";
async function main() {
const hideExampleNft = await ethers.deployContract("HideExampleNft");
await hideExampleNft.waitForDeployment();
console.log(`deployed to ${hideExampleNft.target}`);
}
// We recommend this pattern to be able to use async/await everywhere
// and properly handle errors.
main().catch((error) => {
console.error(error);
process.exitCode = 1;
});
デプロイはネットワークを指定して実行します。
このときデプロイするアカウント(PRIVATE_KEYに秘密鍵をセットしたアカウント)にMATIC
が必要です。デプロイにガス代がかかるためです。
npx hardhat run --network mumbai scripts/deploy.ts
hide@hidenoMacBook-Pro deploy-and-mint % npx hardhat run --network mumbai scripts/deploy.ts
deployed to 0x038F81478a8A15300772e4D769f21a1Be3289533
hide@hidenoMacBook-Pro deploy-and-mint %
1分くらい時間がかかりました。
デプロイされたコントラクトを確認してみます。
コントラクトアドレスを出力するようにしていたので、そのコントラクトアドレスをpolygonscanで検索してみます。
デプロイされていました。
ガス代は0.0029MATICかかっていました。
ミント
以下のアドレスのアカウント(今回はコントラクトをデプロイしたアカウントと同じ)にトークンID0
でミントしてみます。
0xB55327dC3dA686b6c312De1E6c8F6361a107718a
import { ethers } from "hardhat";
require("dotenv").config();
const contract = require("../artifacts/contracts/HideExampleNft.sol/HideExampleNft.json");
const contractAddress = "0x038F81478a8A15300772e4D769f21a1Be3289533";
// ミント対象のアドレス
const to = "0xB55327dC3dA686b6c312De1E6c8F6361a107718a";
// トークンID
const tokenId = 0;
async function main() {
const provider = ethers.provider;
// 署名(mint)するアカウントを取得
// getSigner()の引数無しの場合、デフォルトで0番目のアカウントを取得
// ここで言うアカウントはhardhat.config.tsのaccountsにセットしているもの
const signer = await provider.getSigner();
const abi = contract.abi;
// コントラクトのインスタンスを作成
const myNftContract = new ethers.Contract(contractAddress, abi, signer);
// コントラクトで実装したsafeMint()を呼び出してミントします
const nftTxn = await myNftContract.safeMint(to, tokenId);
await nftTxn.wait();
console.log(
`NFT Minted! Check it out at: https://etherscan.io/tx/${nftTxn.hash}`
);
}
// We recommend this pattern to be able to use async/await everywhere
// and properly handle errors.
main().catch((error) => {
console.error(error);
process.exitCode = 1;
});
また、NFTのメタデータのJSONもデプロイしておきます。
今回は、https://github.com/hid3h/hid3h.github.io/tree/main/assets/hide-example-nft
でGitHub Pagesで公開したものを使います。
ミント用のスクリプトを実装して実行します。
npx hardhat run --network mumbai scripts/mint.ts
hide@hidenoMacBook-Pro deploy-and-mint % npx hardhat run --network mumbai scripts/mint.ts
NFT Minted! Check it out at: https://etherscan.io/tx/0x8db7ef2ceba3bf7b8a35f23144c62dd8052ee864913eebad87094a2dae20e856
hide@hidenoMacBook-Pro deploy-and-mint %
今回は5秒くらいで完了しました。
ミントに成功していました。
0.0001MATICかかっていました。
OpenSea(テストネットワーク)で確認
ミントすると特に設定すること無くOpenSea上でNFTを確認することができます。
コントラクトアドレスで検索するとページを見つけることができます。
ミントした0番目のNFTも確認することができました。https://github.com/hid3h/hid3h.github.io/blob/main/assets/hide-example-nft/metadata/0 で設定したものになっていました。
画像やDescriptionなども、サンプルプロジェクト
Discussion