スマートコントラクト開発（作成、デプロイ）

# はじめに（Introduction）

EVM互換のブロックチェーンで動作するスマートコントラクトをHardhatを使って作成します。
ここではスマートコントラクトのソース作成とデプロイまでを行います。

前回の[準備](https://qiita.com/tis-nakagawa/private/ad5d668be821ed6cbd76)が終わっているものとします。

# ソース作成

[ERC-20](https://eips.ethereum.org/EIPS/eip-20)の標準トークンを作成します。
`contracts`フォルダ配下に以下のファイルを作成します。

```javascript:SampleToken.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

contract SampleToken is ERC20, Ownable {
    constructor(
        string memory name_,
        string memory symbol_
    ) ERC20(name_, symbol_) Ownable(msg.sender) {}

    function mint(address account, uint256 value) external onlyOwner {
        _mint(account, value);
    }
}
```

### ライセンス情報

１行目はソースコードのライセンス情報です。
コンパイラの`0.6.8`以降から推奨となっています。
（記載しない場合はコンパイル時に警告がでます。）
[ライセンスの一覧](https://spdx.org/licenses/)はリンク先にあります。

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

### コンパイルバージョン

２行目は、コンパイルバージョンです。
ここでは、コンパイルバージョンは`^0.8.24`を指定しています。
基本的には最新版を使うと良いです。

```javascript
pragma solidity ^0.8.24;
```

### インポート

４行目、５行目は外部ファイルのインポートです。
ここでは、Openzeppelinが提供してる、`ERC20.sol`と`Ownable.sol`をインポートしています。
`ERC20.sol`はERC20の抽象コントラクトです。
`Ownable.sol`はアクセス制御用の抽象コントラクトです。

```javascript
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
```

### コントラクト

７行目はコントラクトの宣言です。
`contract`の`SampleToken`はコントラクト名となります。
`is`の後は継承するコントラクトです。（複数あるので`,`カンマで連結しています。Openzeppelin）
ここでは、`ERC20`と`Ownable`となります。

```javascript
contract SampleToken is ERC20, Ownable {
```

### コンストラクタ

８～１１行目はコンストラクタです。
`string memory name_`と`string memory symbol_`はコンストラクタのパラメータとなります。`ERC20(name_, symbol_)`と`Ownable(msg.sender)`は継承しているコントラクトのコンストラクタです。
パラメータをそのまま`ERC20`のコンストラクトに設定しています。
`Ownable`にはトランザクション発行者である`msg.sender`を設定しています。
ここでは、コンストラクタでの処理はありません。

```javascript
    constructor(
        string memory name_,
        string memory symbol_
    ) ERC20(name_, symbol_) Ownable(msg.sender) {}
```

### 発行

１３～１５行目はERC20のコインを発行します。
`ERC20`の標準仕様には発行（`mint`）は存在しませんが、Openzeppelinが提供しているコードには`_mint`という内部実行可能（`internal`）な関数が用意されているのでそれを使用してERC20のコインを発行します。
だれでも発行可能にしてしまうとコインに価値が無くなってしまうので、`onlyOwner`を付与してこのコントラクトのオーナーだけが発行可能としています。

```javascript
    function mint(address account, uint256 value) external onlyOwner {
        _mint(account, value);
    }
```

# デプロイモジュール作成

`ignition/modules`フォルダ配下に以下のファイル（`SampleToken.js`）を作成します。

```javascript:SampleToken.js
const { buildModule } = require("@nomicfoundation/hardhat-ignition/modules");

module.exports = buildModule("SampleTokenModule", (m) => {
    const NAME = "Sample Token";
    const SYMBOL = "STC";
    const sampleToken = m.contract("SampleToken", [NAME, SYMBOL]);
    return { sampleToken };
});
```

１行目は`buildModule`のインポートです。

```javascript
const { buildModule } = require("@nomicfoundation/hardhat-ignition/modules");
```

３行目は`buildModule`でモジュールを作成してエクスポートしています。
このモジュールは`SampleTokenModule`をして識別されます。

```javascript
module.exports = buildModule("SampleTokenModule", (m) => {
```

４，５行目はコンストラクトのパラメータです。

```javascript
    const NAME = "Sample Token";
    const SYMBOL = "STC";
```

６行目でコントラクトを生成しています。

```javascript
    const sampleToken = m.contract("SampleToken", [NAME, SYMBOL]);
```

７行目で生成したコントラクトを返しています。

```javascript
    return { sampleToken };
```

# デプロイ

以下のコマンドでモジュールをデプロイします。

```powershell
npx hardhat ignition deploy .\ignition\modules\SampleToken.js
```

以下のような結果がでると思います。

```sh
You are running Hardhat Ignition against an in-process instance of Hardhat Network.
This will execute the deployment, but the results will be lost.
You can use --network <network-name> to deploy to a different network.

Hardhat Ignition 🚀

Deploying [ SampleTokenModule ]

Batch #1
  Executed SampleTokenModule#SampleToken

[ SampleTokenModule ] successfully deployed 🚀

Deployed Addresses

SampleTokenModule#SampleToken - 0x5FbDB2315678afecb367f032d93F642f64180aa3
```

コントラクトがコンパイルされていない場合、先頭に以下のような行が入ります。

```sh
Compiled 8 Solidity files successfully (evm target: paris).
```

## ローカルノードにデプロイ

２つのターミナルを使います。
一つのターミナルで以下のコマンドを使用してローカルノードを立てます。

```powershell
npx hardhat node
```

もう一つのターミナルで以下のコマンドを使用してデプロイします。
`--network localhost`でネットワークを指定しています。

```powershell
npx hardhat --network localhost ignition deploy .\ignition\modules\SampleToken.js
```

以下のような結果になります。

```sh
Hardhat Ignition 🚀

Deploying [ SampleTokenModule ]

Batch #1
  Executed SampleTokenModule#SampleToken

[ SampleTokenModule ] successfully deployed 🚀

Deployed Addresses

SampleTokenModule#SampleToken - 0x5FbDB2315678afecb367f032d93F642f64180aa3
```

デプロイされている状態でもう一度デプロイしてみます。

```powershell
npx hardhat --network localhost ignition deploy .\ignition\modules\SampleToken.js
```

以下のような結果になります。
一回デプロイされているので前回デプロイしたものを返します。

```sh
[ SampleTokenModule ] Nothing new to deploy based on previous execution stored in .\ignition\deployments\chain-31337

Deployed Addresses

SampleTokenModule#SampleToken - 0x5FbDB2315678afecb367f032d93F642f64180aa3
```


`ignition`フォルダ配下に`deployments`フォルダがありその下に`chain-31337`フォルダが出来ていると思います。
この`ignition/deployments/chain-31337`フォルダにデプロイ時の情報が入っています。

# まとめ（Conclusion）

Hardhatでコントラクトの作成とデプロイ用のモジュールを作成をしました。
理解しやすいように、かなりシンプルなつくりにしています。
次回はコントラクトのテストを作成したいと思います。