EthereumのBest Practiceが適用されたICO Crowdsale(クラウドセール)のコードを書いてみる

Ethereum(イーサリアム)

EthereumでICOを行う時によく使われるOpenZeppenlinTruffleいうsolidityのフレームワークがあります。

TruffleはICOでも有名なConsensysが開発したEthereumのスマートコントラクトを実装する際のデファクトスタンダードなフレームワークです。
また、OpenZeppenlinはスマートコントラクトのテストがしやくす、セキュリティのベストプラクティスが網羅されたライブラリーです。
スマートコントラクトでの実装はThe Dao事件のように脆弱性を突かれると多くのお金を失う可能性があります。
ただ、これらのフレームワークを使うことによってセキュリティが一定以上に保たれたスマートコントラクトをあまり意識せずともかけます。

今回はこれらツールを使ってcrawdsale(クラウドセール)をローカルPC上で行ってみたいと思います。

Sponsored Link


環境準備

今回も、みんな大好きDockerを使って環境準備します。母艦のPC環境よごさないのがやっぱりいいですyone!

dockerインストール

https://docs.docker.com/engine/installation/
からがんばってインストールします。

docker-composeもインストール

docker-composeも使うので落としておきます。
https://docs.docker.com/compose/install/#install-compose

依存するパッケージ

依存するパッケージは以下です。この辺りをDocker環境イメージに構築してしまいます。truffleのバージョンを4にあげてしまうと動かなくなるので注意です。

– node@8.8.1 (alpineの2017年11月3日現在の”This image has no known vulnerabilities”最新でした)
– truffle@^3.4.8 (truffle@4.Xを使うと”exceeds block gas limit”がmigrate時に出てしまうのでやめました)
– ethereumjs-testrpc@^4.1.3
– zeppelin-solidity@1.3.0

ソースをgithubに用意したのでcloneするなりダウンロードするなりしてローカルPCに落としてきます。

https://github.com/todoroki-yudai/zeppelin-crowdsale-sample

タグはbaseを指定してください。

git clone --depth 1 -b base https://github.com/todoroki-yudai/zeppelin-crowdsale-sample.git

落としてきたソースのルートディレクトリで以下コマンドを打ちイメージを作成します。

$ docker-compose build ico
 :
 :
Removing intermediate container 3efcd2be75f0

Successfully built 44c513d5db7c
Successfully tagged zeppelincrowdsalesample_ico:latest

以下のようにzeppelincrowdsalesample_icoイメージができれば成功です。

$ docker images
REPOSITORY                                           TAG                 IMAGE ID            CREATED             SIZE
zeppelincrowdsalesample_ico                          latest              44c513d5db7c        16 seconds ago      184MB

スマートコントラクトを動かす

スマートコントラクト実装の簡単な説明

まずは、トークンを作成します。

MintableTokenを使います。これは、オーナーが他のユーザーにトークンを供給する際に管理するトークンロジックです。

そしていよいよクラウドセールのコントラクトです。

たっだ、これだけでクラウドセールのコードがかけます!これも、OpenZeppelinのライブラリを使用することによってセキュリティに考慮されたクラウドセールができます。zeppelinのCrowdsale.solを使用しています。
このクラウドセールのコントラクトで以下を指定する必要があります。

– startTime : クラウドセール開始時間
– endTime : クラウドセール終了時間
– rate : WakuWakuCoinとEtherのレート
– wallet : オーナーのEthereumアドレス

次に、これらのコードを元にテスト環境でクラウドセールを動かしていきます。

テスト環境を動かす

ルートディレクトリで以下Dockerコマンドを打ち、コンテナを起動させ、そのままattachされるのでプロンプト上で作業していきます。SRC_ROOT_DIRは適宜自分の環境にあわせて変更してください。

$ docker run -it --name ico -v /SRC_ROOT_DIR/zeppelin-crowdsale-sample:/ico zeppelincrowdsalesample_ico /bin/sh

その後、testrpcを動かします。testrpcは開発する際にEthererumのRPCのダミー的に返してくれる素敵なやつです。testrpc実行時に10個のアドレスが自動的に作られています。

# testrpc -u 0
EthereumJS TestRPC v4.1.3 (ganache-core: 1.1.3)

Available Accounts
==================
 :
 :

HD Wallet
==================
Mnemonic:      alarm exercise army laptop demise tornado tube any buddy gasp clock aim
Base HD Path:  m/44'/60'/0'/0/{account_index}

Listening on localhost:8545

稼働しているコンテナにログイン

稼働しているコンテナに別ターミナルからログインします。以後の手順ではこちらのターミナルでの手順です。

$ docker exec -it ico /bin/sh

コンパイル

deployするための前準備としてソースをコンパイルします。

# truffle compile
Compiling ./contracts/Migrations.sol...
Compiling ./contracts/WakuWakuCoin.sol...
Compiling ./contracts/WakuWakuCoinCrowdsale.sol...
Compiling zeppelin-solidity/contracts/crowdsale/Crowdsale.sol...
Compiling zeppelin-solidity/contracts/math/SafeMath.sol...
Compiling zeppelin-solidity/contracts/ownership/Ownable.sol...
Compiling zeppelin-solidity/contracts/token/BasicToken.sol...
Compiling zeppelin-solidity/contracts/token/ERC20.sol...
Compiling zeppelin-solidity/contracts/token/ERC20Basic.sol...
Compiling zeppelin-solidity/contracts/token/MintableToken.sol...
Compiling zeppelin-solidity/contracts/token/StandardToken.sol...
Writing artifacts to ./build/contracts

migrate(事前deploy)

そのあとブロックチェーン上にmigrateします。migrateはコントラクトをdeployする手助けをするもので、必要に応じて事前にdeployをします。
migrateで使うファイルは今回作成するソースではmigrateフォルダにある2つで、先頭の数字が小さいものから順にdeployしていきます。
その1つである2_deploy_contracts.jsですが、以下のような内容です。ここではクラウドセールの初期値を指定しておりmigrate時にWakuWakuCoinCrowdsaleのコントラクトを先にdeployしてしまいます。

初期値の内容は

– startTime : 現在時刻(blockNumberの時間ですがほぼいっしょのため現在時刻ととらえます)
– endTime : 20日後
– rate : 1ETH=1,000WAK
– wallet : オーナーのEthereumアドレス

です。

では実際のコマンドをうってみます。これでクラウドセールがはじまります!

# truffle migrate
Using network 'development'.

Running migration: 1_initial_migration.js
  Deploying Migrations...
  ... 0x5ee5e0ff442fd311d4d3e51b61ea3b1f2608157b65cc6b7d6bb72c5cee815533
  Migrations: 0x91153005963c30a51db1cbaea2d3d5d3052d7324
Saving successful migration to network...
  ... 0x48ac64f998cff88b420a431f08eb0954b5488c980e6da6a6e6d6f7f528b326fa
Saving artifacts...
Running migration: 2_deploy_contracts.js
  Deploying WakuWakuCoinCrowdsale...
  ... 0x23d9ed9edfd6cf360e816e589ed43294fade233a2c29f4c32620e777fd6bf200
  WakuWakuCoinCrowdsale: 0x8d0e3ee0245567cc3412f87a56bf3227c3ea2240
Saving successful migration to network...
  ... 0x5d26e82ee29d7b6e61450aba80e760a940304ef49c3c235f9823d0a889734870
Saving artifacts...

consoleからクラウドセールを色々触ってみる

先ほどまでの手順でクラウドセールを開催しました。今度はコマンドラインベースで実際にクラウドセールを体験してみたいと思います。以下手順はコンパイルなどをした別でattachしているターミナルでの手順です。

まずWAKトークンを購入するアカウントをaccount1という変数に入れます。

# truffle console
> account1 = web3.eth.accounts[1]
'0x70b2711d29dd72b0e058f6b6909aae540096fb2c'

先のmigrateでdeploy済みのWakuWakuCoinCrowdsaleの内容をcrowdsale変数に割り当てて、クラウドセールのトークンアドレスを取得します。

> WakuWakuCoinCrowdsale.deployed().then(inst => { crowdsale = inst })
undefined
> crowdsale.token().then(addr => { tokenAddress = addr } )
undefined
> tokenAddress
'0x6fcbb923d9be7935b6ebef70d3dab5eac9572d12'

そのあと、WakuWakuCoinのインスタンスを作ります。以下で使用されているatメソッドに指定したクラウドセールのトークンアドレスからそのトークンインスタンスを取得します。

> wakuwakuCoinInstance = WakuWakuCoin.at(tokenAddress)
TruffleContract {
  constructor:
  :
  :

ここでこれからWAKトークンを購入する予定のaccount1アドレスWAKトークン数を確認してみると・・・

> wakuwakuCoinInstance.balanceOf(account1).then(balance => balance.toString(10))
'0'

0だということがわかります。何もトークンをこのアドレスに入れていないので当然ですね。
ではいよいよWAKトークンを5000個購入するために 5ETH(1ETH~5,000WAK) つかって購入してみます。

> WakuWakuCoinCrowdsale.deployed().then(inst => inst.sendTransaction({ from: account1, value: web3.toWei(5, "ether")}))
{ tx: '0x940917e32df0dca4bc48ce52dbcadb39da2d33bfec7fb1e660dbf36fc053a55c',
  receipt:
   { transactionHash: '0x940917e32df0dca4bc48ce52dbcadb39da2d33bfec7fb1e660dbf36fc053a55c',
     transactionIndex: 0,
     blockHash: '0x17d78c83a939d1a13ba21d8f064418b1aaa180ab8b96c8ec730a78f48b622f64',
     blockNumber: 5,
     gasUsed: 99588,
     cumulativeGasUsed: 99588,
     contractAddress: null,
     logs: [ [Object], [Object], [Object] ] },
  logs:
   [ { logIndex: 2,
       transactionIndex: 0,
       transactionHash: '0x940917e32df0dca4bc48ce52dbcadb39da2d33bfec7fb1e660dbf36fc053a55c',
       blockHash: '0x17d78c83a939d1a13ba21d8f064418b1aaa180ab8b96c8ec730a78f48b622f64',
       blockNumber: 5,
       address: '0x8d0e3ee0245567cc3412f87a56bf3227c3ea2240',
       type: 'mined',
       event: 'TokenPurchase',
       args: [Object] } ] }

eventでTokenPurchaseがでていれば(上記のログですと下から2行目)成功です。では実際に購入できたか確認してみると・・・

> wakuwakuCoinInstance.balanceOf(account1).then(balance => account1GusTokenBalance = balance.toString(10))
'5000000000000000000000'

できてますね!!ただ、ものすごく多い量に見えますが、WakuWakuCoinのコントラクトでuint256 public decimals = 18;と指定していた影響で18個0が後ろにくっついてます。実際にいつくトークン買ったかを見るにはether単位でのトークン数を見るとわかります。

> web3.fromWei(account1GusTokenBalance, "ether")
'5000'

5000トークンを買えていることがわかりますね。

まとめ

一通りクラウドセールのプログラムをtruffleとzeppelin-solidityを使って動かしてみました。これでEthereumのスマートコントラクトのベストプラクティスが考慮された状態でのクラウドセールが開催できました。
ただこれはローカルPCだけのテストなので、次はEthereumのテストネットにdeployして遊んでみようと思います。

[追記]次の記事書きました。

参考

How To Create Token and Initial Coin Offering Contracts Using Truffle + OpenZeppelin

Sponsored Link

ビットコイン(Bitcoin)、イーサリアム(Ethereum)、リップル(Ripple)、ネム(NEM)などの仮想通貨を買うならZaifがおすすめです。

特に国内でETHを購入するなら、アルトコインでも板取引に対応しているZaif(ザイフ)が割安なのでよいですよ。

コメントはまだありません

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

CAPTCHA


仮想通貨全般
Stablecoin(ステーブルコイン)とは?

最近Stablecoinのツイートをよく見ており、次の仮想通貨の本命などと言われています。 ステーブ …

仮想通貨全般
難易度調整(Difficulty Adjustment)アルゴリズムとは?

最近、Monaが攻撃を受けて被害がでた件ですが 上記、大石さんの記事を引用しますが 攻撃を容易にした …

ICO
ICO Platformはどんなものがあるか?

ICO Platform にどんなものがあるか調べてみました。 ここで取り上げているICO Plat …