1
0

More than 1 year has passed since last update.

【Solidity】HardhatでDappを作ってみる ~ チュートリアル編(前半)~

Last updated at Posted at 2022-07-09

Hardhatとは

いい感じにSolidityでのDapp開発ができるやつ(語彙力皆無)

事前準備

  • Node.js使えるようにしておく
  • VSCode使ってる人はのExtensionをインストールしておくと便利っぽいです

環境

  • OS: MacOS Monterey 12.0.1
  • Node.js: 18.5.0
    (チュートりアルにインストールするversion書いてあるのでそれに従ってください)

チュートリアルをやってみる

これをやっていきます
https://hardhat.org/tutorial/creating-a-new-hardhat-project

プロジェクトの設定

作業用ディレクトリを作って移動

mkdir hardhat-tutorial
cd hardhat-tutorial

npm init すると色々聞かれるけどチュートリアルなので全部EnterでOK
最後に Is this OK? と聞かれるのでyes

npm init
...
Is this OK? (yes) 

そしたらHardhatをインストールします。ちょっと時間かかるかも。

npm install --save-dev hardhat

npx hardhat と打つといくつか選択肢が出てきます。
Create a TypeScript projectを選択したい気持ちを抑えて指示通りに Create an empty hardhat.config.jsを選択します。

npx hardhat

👷 Welcome to Hardhat v2.10.0 👷‍

? What do you want to do? … 
  Create a JavaScript project
  Create a TypeScript project
❯ Create an empty hardhat.config.js
  Quit

スマートコンラクトの開発に必要なもの全てが揃うと説明されているプラグインをインストールします。
WARNがいっぱい出てきますが無視します。

npm install --save-dev @nomicfoundation/hardhat-toolbox

hardhat.config.jsにrequire("@nomicfoundation/hardhat-toolbox");を追加します。

require("@nomicfoundation/hardhat-toolbox");

/** @type import('hardhat/config').HardhatUserConfig */
module.exports = {
  solidity: "0.8.9",
};

以上でプロジェクトの設定は完了です。

さっそくスマートコントラクトを書いてコンパイルする

contract用のディレクトリ作成し、Token.solを作成します

mkdir contracts
touch Token.sol

書いてみると言ってみたもののコピペです。
説明文のコメントアウト省いて記載しておきます。

//SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.9;

contract Token {
    string public name = "My Hardhat Token";
    string public symbol = "MHT";

    uint256 public totalSupply = 1000000;

    address public owner;

    mapping(address => uint256) balances;

    event Transfer(address indexed _from, address indexed _to, uint256 _value);

    constructor() {
        balances[msg.sender] = totalSupply;
        owner = msg.sender;
    }

    function transfer(address to, uint256 amount) external {   
        require(balances[msg.sender] >= amount, "Not enough tokens");

        balances[msg.sender] -= amount;
        balances[to] += amount;

        emit Transfer(msg.sender, to, amount);
    }

    function balanceOf(address account) external view returns (uint256) {
        return balances[account];
    }
}

コンパイルして成功するとartifactsというディレクトリが生成されます

npx hardhat compile
Compiled 1 Solidity file successfully

image.png

スマートコントラクトが正しく動作するか確認するためにテストコードを書いていきます。
まずはテスト用のディレクトリとファイルを作成します。
テストはOwnerがトークンの最大供給量を保有しているかを確認しています。

mkdir contracts
touch Token.sol

Token.js

const { expect } = require("chai");
const { loadFixture } = require("@nomicfoundation/hardhat-network-helpers");

describe("Token contract", function () {
    async function deployTokenFixture() {
        const Token = await ethers.getContractFactory("Token");
        const [owner, addr1, addr2] = await ethers.getSigners();
        const hardhatToken = await Token.deploy();

        await hardhatToken.deployed();

        return { Token, hardhatToken, owner, addr1, addr2 };
    }

    describe("Deployment", function () {
        it("Should set the right owner", async function () {
            const { hardhatToken, owner } = await loadFixture(deployTokenFixture);
            expect(await hardhatToken.owner()).to.equal(owner.address);
        });

        it("Should assign the total supply of tokens to the owner", async function () {
            const { hardhatToken, owner } = await loadFixture(deployTokenFixture);
            const ownerBalance = await hardhatToken.balanceOf(owner.address);
            expect(await hardhatToken.totalSupply()).to.equal(ownerBalance);
        });
    });

    describe("Transactions", function () {
        it("Should transfer tokens between accounts", async function () {
            const { hardhatToken, owner, addr1, addr2 } = await loadFixture(
                deployTokenFixture
            );

            await expect(
                hardhatToken.transfer(addr1.address, 50)
            ).to.changeTokenBalances(hardhatToken, [owner, addr1], [-50, 50]);

            await expect(
                hardhatToken.connect(addr1).transfer(addr2.address, 50)
            ).to.changeTokenBalances(hardhatToken, [addr1, addr2], [-50, 50]);
        });

        it("should emit Transfer events", async function () {
            const { hardhatToken, owner, addr1, addr2 } = await loadFixture(
                deployTokenFixture
            );

            await expect(hardhatToken.transfer(addr1.address, 50))
                .to.emit(hardhatToken, "Transfer")
                .withArgs(owner.address, addr1.address, 50);

            await expect(hardhatToken.connect(addr1).transfer(addr2.address, 50))
                .to.emit(hardhatToken, "Transfer")
                .withArgs(addr1.address, addr2.address, 50);
        });

        it("Should fail if sender doesn't have enough tokens", async function () {
            const { hardhatToken, owner, addr1 } = await loadFixture(
                deployTokenFixture
            );
            const initialOwnerBalance = await hardhatToken.balanceOf(owner.address);

            await expect(
                hardhatToken.connect(addr1).transfer(owner.address, 1)
            ).to.be.revertedWith("Not enough tokens");

            expect(await hardhatToken.balanceOf(owner.address)).to.equal(
                initialOwnerBalance
            );
        });
    });
});

これでテストを実行すると成功します。

npx hardhat test
Compiled 1 Solidity file successfully


  Token contract
    Deployment
      ✔ Should set the right owner (638ms)
      ✔ Should assign the total supply of tokens to the owner
    Transactions
      ✔ Should transfer tokens between accounts (67ms)
      ✔ should emit Transfer events
      ✔ Should fail if sender doesn't have enough tokens


  5 passing (775ms)

テストまでできるようになりました。
これで前半は終わりです。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0