ERC20 トークンを試す(その1)

 イーサリアムトークン標準規格であるERC20に準拠したトークンを試作する.今回はLinuxを使う.

 まずnode.jsをインストールする.バージョンは以下のとおり.

$ sudo apt-get install nodejs, npm
$ nodejs -v
v10.19.0
$ npm -v
7.18.1

続いて truffle をインストールする.

$ sudo npm install -g truffle
$ truffle version
Truffle v5.3.12 (core: 5.3.12)
Solidity v0.5.16 (solc-js)
Node v10.19.0
Web3.js v1.3.6

truffle の初期化

$ mkdir erc; cd erc
$ truffle init

ERC20トークンの作成に便利なライブラリである openzeppelin をダウンロードする.

$ npm install @openzeppelin/contracts

node_modules/@openzeppelin/contracts/build/contracts の中にコンパイル済みのファイルがたくさん入っているのでこれらを利用する.

$ mkdir -p build/contracts
$ cp node_modules/@openzeppelin/contracts/build/contracts/*  build/contracts

開発用チェーンを起動する.

$ truffle develop

今回は ERC20 プリセットファイルの,ERC20PresetFixedSupply.json を使う.

> tkn = await ERC20PresetFixedSupply.new('My Token', 'MTK', '1000000000000000000000', accounts[0])

最初の引数はトークンの名前,次がトークンの記号,次が発行枚数,最後がトークンの所有者のアドレスである.発行枚数は10^21にしたが,10^18 を1単位としているため(decimals関数でわかる),1000単位の枚数に相当する.

> await tkn.name()
'My Token'
> await tkn.symbol()
'MTK'
> (await tkn.decimals()).toString()
'18'
> (await tkn.balanceOf(accounts[0])).toString()
'1000000000000000000000'
> await web3.utils.fromWei('1000000000000000000000', 'ether')
'1000'

balanceOf でアカウントの残高が表示でき,上のように fromWei を使うと 10^18 を1単位として表示できる.全供給量は totalSupply() でわかる.

> (await tkn.totalSupply()).toString()
'1000000000000000000000'

アカウント0からアカウント1へ,transfer により100単位のトークンを送金する.

> await tkn.transfer(accounts[1], "100000000000000000000")
> (await tkn.balanceOf(accounts[0])).toString()
'900000000000000000000'
> (await tkn.balanceOf(accounts[1])).toString()
'100000000000000000000'

approve 関数はあるアカウントに,別のアカウントの残高を使う権利を与える.

> await tkn.approve(accounts[1], '200000000000000000000')

によって,アカウント1はアカウント0の残高から200単位のトークンを引き出すことができる.使える額を調べるには allowance を使う.

> (await tkn.allowance(accounts[0], accounts[1])).toString()
'200000000000000000000'

実際にアカウント1がアカウント0の残高からトークンを引き出すには tresnferFrom 関数を使う.アカウント0の残高からアカウント2へ50単位のトークンを送金してみる.

> await tkn.transferFrom(accounts[0], accounts[2], '50000000000000000000', {from: accounts[1]})
> (await tkn.balanceOf(accounts[0])).toString()
'850000000000000000000'
> (await tkn.balanceOf(accounts[2])).toString()
'50000000000000000000'
> (await tkn.allowance(accounts[0], accounts[1])).toString()
'150000000000000000000'

approve によってアカウント1は200単位のトークンを使えたが,50単位を使ったことによって残り150単位になった.

 このプリセットにはトークンをバーン(供給量を減らす)する関数も用意されている.アカウント0の残高から400単位ほどバーンしてみる.

> await tkn.burn('400000000000000000000')
> (await tkn.balanceOf(accounts[0])).toString()
'450000000000000000000'
> (await tkn.totalSupply()).toString()
'600000000000000000000'

allowance で示される額を,別のアカウントからバーンできる burnFrom 関数もある.アカウント1がアカウント0の残高から150単位のトークンをバーンしてみる.

> await tkn.burnFrom(accounts[0], '150000000000000000000', {from: accounts[1]})
> (await tkn.balanceOf(accounts[0])).toString()
'300000000000000000000'
> (await tkn.totalSupply()).toString()
'450000000000000000000'
> (await tkn.allowance(accounts[0], accounts[1])).toString()
'0'

allowance が0なのは,50単位を送金に使い,150単位をバーンしたので合計200単位を「使った」からである.