TypeScriptでTruffleの環境を作成する

TypeScript, Ethereum, Truffle
2021-02-16

ちょっと久しぶりにEthereum(Dapp)の勉強をしているので、いろいろナレッジを書き残していきたい。

こちらのTypeChainを参考にしています 👀

https://github.com/ethereum-ts/TypeChain

前提条件

Truffle v5.1.66 (core: 5.1.66)
Solidity - 0.6.2 (solc-js)
Node v14.15.3
Web3.js v1.2.9

Node.jsはv14だと、truffle unbox react が動かなかったりするので v12 でもいいと思う。

ディレクトリを作成し、各種ファイルをインストール

$ mkdir truffle-ts-demo
$ cd truffle-ts-demo

# package.jsonを作成
$ npm init --y

# 必要なパッケージをインストール
$ npm install truffle typechain @typechain/truffle-v5 typescript -D
$ npm install @types/bn.js @types/mocha @types/chai @types/web3 -D

npm scriptの作成

package.jsonのscripts部分を以下のように変更する

"scripts": {
  "generate-types": "typechain --target=truffle-v5 'build/contracts/*.json'",
  "postinstall": "truffle compile && npm run generate-types",
  "build-migration-files": "tsc -p ./tsconfig.migrate.json --outDir ./migrations",
  "migrate": "npm run build-migration-files && truffle migrate",
  "test": "npm run postinstall && truffle test"
},

generate-types

build/contract/*.jsonからtypes(typescriptの型ファイル)を生成。testファイル等の型依存をこのファイルで管理する。

postinstall

solidityのコンパイルを行い、型ファイルを生成する。solファイルの型を変更した場合は都度実行する必要がある。

migrate

マイグレーションを実行。migrationファイルもTypeScriptで記述されているため、一度jsファイルを作成し、そのファイルを元にマイグレーションを行う。

test

ビルドを実行し、テストを実行します。

tsconfig.jsonを作成

tsconfig.jsonとマイグレーション用のtsconfig.migrate.jsonを作成する。

$ touch tsconfig.json tsconfig.migrate.json

tsconfig.jsonは以下のようにする。お好みで変えてもよい。

{
  "compilerOptions": {
    "target": "es2018",
    "module": "commonjs",
    "lib": ["ES2018", "DOM"],
    "sourceMap": true,
    "strict": true,
    "moduleResolution": "node",
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
  },
  "include": ["**/*.ts", "**/*.tsx"],
  "exclude": ["node_modules"]
}

tsconfig.migrate.jsonはマイグレーションファイルのトランスパイルに利用します。基本的には同じで対象のファイルの対象が異なることになります。

{
  "extends": "./tsconfig.json",
  "include": ["./migrations-ts/*.ts", "./types/**/*.ts"]
}

`truffle init`のような雛形を作成する。

# まずディレクトリを作成します
$ mkdir contracts migrations-ts test
# truffleの設定ファイルを作成します。
$ touch truffle-config.js

truffle-config.jsはとりあえず最低限の設定をしておきます

module.exports = {
  networks: {
    development: {
      host: "127.0.0.1",
      port: 8545,
      network_id: "*"
    }
  },

  compilers: {
    solc: {
      version: "0.6.2"
    }
  }
};

ソースファイルを作成し、マイグレーションを行う

Migrations.solとそのマイグレーションファイルを作成します。

$ touch contracts/Migrations.sol
$ touch migrations-ts/1_initail_migration.ts

Migrations.solはtruffle initと同じ内容を記述します。1_initial_migration.tsはTypeScriptで以下の内容を記述します。

const Migrations = artifacts.require("Migrations");

module.exports = function (deployer) {
  deployer.deploy(Migrations);
} as Truffle.Migration;

export {};

基本的にはjsと同じですが、`as Truffle.Migration` で型の担保を行っています。また、最後の行に`export {}`を付ける必要があります。(マイグレーションファイルをインポートさせないため、空のexportをする必要がある。)

この時点でTypeScriptのエラーが発生するが一旦無視してすすめる。

build

一度buildを実行し、typesを生成する。

npm run postinstall

`types/truffle-contracts/*.d.ts`が生成され、migrations-ts上のエラーが消える。

マイグレーションファイルのトランスパイル

truffleのmigationコマンドはjsファイルしか読めないので、migration-ts 内のtsファイルをjs形式に変更します。

$ npm run build-migration-files

上記のコマンドが実行されると、`migirations`というjsファイルが入ったディレクトリができるので、以降、`truffle migrate`でマイグレーションする場合はそちらのファイルを参照することになります。

migration-ts内のファイルを更新した場合は都度上記のコマンドを実行しjsを更新することになります。(実際はmigrationファイルを更新する頻度は少ないですが)

マイグレーションを実行する場合はGanache等Ethereumのクライアントを立ち上げ、マイグレーションコマンド npm run migrate を実行します。

テストの準備

とりあえず、テストが動作することを確かめるためテストファイルを追加します。

$ touch test/migration.test.ts

下記のようにします

const MigrationsContract = artifacts.require("Migrations");

contract("Migrations", () => {
  it("has been deployed successfully", async () => {
    const migrations = await MigrationsContract.deployed();
    assert(migrations, "contracut was not deployed");
  });
});

テストを実行し、動作することを確認します。

$ npm run test

まとめ

typescriptでtruffleのテンプレート環境を作る部分を説明しました。

ファイルを更新するたびにコンパイルが必要だったりするので、なにかファイルをwatchする機能をつけたほうが効率ではあります、時間があればそのあたりも詰めていきたですね。

Written by Kyohei Tsukuda who lives and works in Tokyo 🇯🇵 , building useful things 🔧.