初心者向けスマコン開発環境構築メモ (VS Code + Solidity + Truffle)

# この記事について
スマートコントラクトの開発に興味が出たので試してみようと思ったが、検索してヒットする日本語の情報がだいたい古い。折角なので自分の作業メモをQiitaに残しておく。厳密さはないし恐らく正確でもないので、英語に抵抗が無い人は[OpenZeppelinの学習用ドキュメント](https://docs.openzeppelin.com/learn)でも参照した方がいい。

この記事は自分のようなズブの素人にしか役立たないかもしれない。すでにバリバリスマコン開発している人は読む必要がなさそう。また、ブロックチェーンや Ethereum 、スマートコントラクトとは何であるか等の基礎的な説明は本稿では行わないので注意されたし。

# 本記事で使う環境について
以下の環境で開発を行う(本稿では各環境名の大文字、小文字表記を特に区別しない)。

- Windows 10 Home
- Visual Studio Code v1.68.1
- Solidityコンパイラ 0.8.15
- Truffle v5.5.20
- Ganache CLI v6.12.2 (ganache-core: v2.13.2)
- Visual Studio Code Extension: solidity v0.0.139
- OpenZeppelin v4.4.1

Remix もよさそうだが、使い慣れている VisualStudio Code (以下、VS Code)を採用したい。
以下、まずは環境構築から順を追って述べる。
なお本稿では Visual Studio Code と Solidity コンパイラの導入手順については割愛する。

# 環境構築手順
## truffle をインストールする
truffle は EVM を採用するブロックチェーン向けの開発環境・フレームワークにあたる。
[公式サイト](https://trufflesuite.com/)を見るにtruffleは英語でお菓子のトリュフを意味するらしい。
前提としてnode.jsとnpmをインストールしておく必要がある。npmを使ってtruffleをインストールする。
```
npm install -g truffle
```

## プロジェクトを初期化する
コマンドプロンプトを開き、適当なフォルダに移動して下記コマンドを実行する。

```
> truffle init
```

成功するとプロジェクトフォルダが構築される。トップに truffle-config.js ファイルや contracts, migrations フォルダが見つかるはず。
このプロジェクトフォルダを VS Code で開いて、これ以降の作業を進める。

## VS Code にsolidity拡張を導入する 
折角 VS Code を使うので便利な拡張をインストールしておく。[solidity拡張](https://marketplace.visualstudio.com/items?itemName=JuanBlanco.solidity)を導入する。
多機能だが、今回は主にシンタックスハイライトが欲しかったので導入する。F5押下で.solをコンパイルできるが、この機能は本稿では使わない。
他にも機能はいろいろあるので、詳細については公式のIntroductionを確認するとよい。

## VS Code のターミナル上でtruffleを実行する
solidity拡張を導入しても、開発に必要な全ての操作をカバーしてくれるわけではない。
truffleを用いたスマートコントラクトのデプロイ等を行うのに、可能ならVS Code上のターミナルを使いたい。
しかしターミナル上でいきなりtruffleを実行しようとしても下記エラーが出るかもしれない。
```
ExtendableError: Could not find suitable configuration file.
```
[参考にしたQiita記事](https://qiita.com/Targityen/items/3d2e0b5b0b7b04963750)によれば、Powershellのスクリプト実行時のポリシー設定がまずいらしい。
これを解決するにはVS Codeのsetting.jsonに下記を追記する。
```
{
    "terminal.integrated.env.windows": {
        "PSExecutionPolicyPreference": "RemoteSigned"
    }
}
```
設定を適用後、問題なくターミナルからtruffleコマンドを実行できるようになった。

## OpenZeppelin をインストールする
スマートコントラクトを自前で実装すると脆弱性を作ってしまうかもしれない。
スマートコントラクトの脆弱性の恐ろしさについては[The DAO事件](https://gentosha-go.com/articles/-/17332)を参照するとよくわかる。
脆弱性に関する技術的な解説を読みたい人は[Mastering Ethereum 第9章](https://github.com/ethereumbook/ethereumbook/blob/develop/09smart-contracts-security.asciidoc)を参照するとよい。日本語翻訳されたものも出版されている。
セキュアなスマートコントラクトを開発するにはライブラリを使用するのが一般的。[OpenZeppelin](https://www.openzeppelin.com/) が有名なので本稿ではこれを使う。
OpenZeppelinをインストールするには下記のようにする。

```
>  npm install @openzeppelin/contracts

added 1 package, and audited 3 packages in 5s

found 0 vulnerabilities
```

OpenZeppelin 詳細については公式ドキュメントを参照されたし。上で紹介した書籍 Mastering Ethereum 内でも言及されている。

## ganacheをインストールする
実際にイーサリアムブロックチェーン上へデプロイする場合、メインネットは実際にETHを購入してガス代などを支払う必要があるので開発用途ではまず使わない。
ropstenなどのテストネットをデプロイ先として選ぶこともできるが、今回は完全ローカルで完結する＆自由度が高いローカルのプライベートチェーンを選択する。
プライベートチェーンを作るには[ganache](https://trufflesuite.com/ganache/)を使う。GUIもあるが今回はCUIベースで使用したい。下記のようにインストールする。
```
> npm install -g ganache-cli
```

# 実験手順
簡単なコントラクトを作ってプライベートチェーン上にデプロイするまでの手順をまとめる。

## ERC20の派生コントラクトをコンパイルする
下記のコードを contracts/MyToken.sol ファイルとして作成する。
```
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;

import '@openzeppelin/contracts/token/ERC20/ERC20.sol';

// OpenZeppelinのERC20実装を継承しただけ
contract Myken is ERC20 {
    constructor() ERC20("MyFT", "MFT") {}
}
```
VS Codeのターミナルから、下記のようにコンパイルする。
```
> npx truffle compile

Compiling your contracts...
===========================
> Compiling .\contracts\MyToken.sol
> Compiling .\contracts\MyToken.sol
> Artifacts written to D:\Blockchain\Eth\MyToken\build\contracts
> Compiled successfully using:
   - solc: 0.8.15+commit.e14f2714.Emscripten.clang
```

コンパイルに成功すると build フォルダが作成され、以下に各種 .json ファイルが配置されているのを確認できるはず。

## プライベートチェーンを立ち上げる
ganache-cliを起動するだけでプライベートチェーンが接続可能な形で立ち上がる。
しかしデフォルトの起動方法だと利用可能アカウントのアドレスはランダムになってしまう。
固定のアドレス値を参照して実験したいので determinitstic モードで実行する。
```
> npx ganache-cli --deterministic
```
成功すると接続先のIPアドレスが表示される。デフォルトでは 127.0.0.1:8545 になる。
ganache プロセスを停止するとこのプライベートチェーンの状態はリセットされるので要注意。
状態を次回起動時にも引き継ぎたい場合は --db オプションを伴っておく必要があるとのこと。今回は使わない。

## プライベートチェーンをデプロイ先として指定する
truffle-config.jsに下記を追加する。
```
  networks: {
  ...
     development: {
      host: "127.0.0.1",     // Localhost (default: none)
      port: 8545,            // Standard Ethereum port (default: none)
      network_id: "*",       // Any network (default: none)
     },
  ...
```
これで既に立てたプライベートチェーンを開発用ネットワークとして指定できるようになった。
実際のデプロイ操作は truffle を介したマイグレーション操作によって行う。

## MyToken のマイグレーションスクリプトを追加する
今回作成したコントラクトである MyToken をデプロイするには、対応するマイグレーションスクリプトを用意する必要がある。
migration フォルダ以下に 2_deploy.js ファイルを作成し、下記のコードを記述する。
```
const MyToken = artifacts.require('MyToken');

module.exports = async function (deployer) {
  await deployer.deploy(MyToken);
};
```

## MyToken をデプロイする
下記コマンドをターミナルから実行することでデプロイが行われる。
```
> npx truffle migrate --network development
```
各種デプロイに成功すると詳細情報が出力される。以下、MyToken の情報を抜粋する。

```
2_deploy.js
===========

   Deploying 'MyToken'
   -------------------
   > transaction hash:    0x642a46edc2c75662af0e8595b06611b910a37c16ffe5fd3f47765d5204a1b6cc
   > Blocks: 0            Seconds: 0
   > contract address:    0xCfEB869F69431e42cdB54A4F4f105C19C080A601
   > block number:        3
   > block timestamp:     1656921031
   > account:             0x90F8bf6A479f320ead074411a4B0e7944Ea8c9C1
   > balance:             99.9717472
   > gas used:            1121273 (0x111bf9)
   > gas price:           20 gwei
   > value sent:          0 ETH
   > total cost:          0.02242546 ETH

   > Saving migration to chain.
   > Saving artifacts
   -------------------------------------
   > Total cost:          0.02242546 ETH
```

以上。