TRUFFLE BOXES
EthereumでDAppsを開発するときに何をどうやって作ればいいかわからないことが多いですよね。そんな時はTRUFFLE BOXESを参考にするといいです。
ここにはいろんなサンプルアプリケーションがあり、Reactを使ったサンプルもあるのでモダンなアプリケーションを作る手がかりにもなるかと思います。

環境設定
バージョン
- Node.js v8.9.4
- npm v5.7.1
- solidity v0.4.17
- truffle v4.1.3
- Ganache v1.0.2
インストール
truffle unbox pet-shopで今回使用するサンプルコードをダウンロードすることができます。
$ npm install -g truffle $ mkdir pet-shop & cd pet-shop $ truffle unbox pet-shop
pet-shopアプリケーションはMetaMask経由でトランザクションを発行し、好みのペットに対して自分のアドレスを紐づけることができるようになっています。
自分が現在どのペットと紐づいているかをスマートコントラクト経由で取得することもできるようになっています。
なのでスマートコントラクトを使った更新と読み取りの基本的なアプリケーションを作ることができます。
DApps開発
スマートコントラクト
contracs/Adoption.solを実装します。
adopt()関数はこの関数を呼び出したアドレスをpetIdを紐づけることで購入者を識別します。getAdopters()は購入者全てのアドレスを返す関数です。Solidityで実装するスマートコントラクトはこれだけです。
pragma solidity ^0.4.17; contract Adoption { address[16] public adopters; // Adopting pet function adopt(uint petId) public returns (uint) { require(petId >= 0 && petId <= 15); adopters[petId] = msg.sender; return petId; } // Retrieving the adopters function getAdopters() public view returns (address[16]) { return adopters; } }
マイグレーション
migrations/2_deploy_contract.jsを作成し下記を実装します。
var Adoption = artifacts.require("Adoption"); module.exports = function(deploer) { deploer.deploy(Adoption) };
コンパイル
コンパイルは最後にWriting artifacts to ./build/contractsが表示されれば成功です。
$ truffle compile Compiling ./contracts/Adoption.sol... Compiling ./contracts/Migrations.sol... Compilation warnings encountered: /Users/private_work/pet-shop/contracts/Migrations.sol:11:3: Warning: No visibility specified. Defaulting to "public". function Migrations() { ^ Spanning multiple lines. ,/Users/private_work/pet-shop/contracts/Migrations.sol:15:3: Warning: No visibility specified. Defaulting to "public". function setCompleted(uint completed) restricted { ^ Spanning multiple lines. ,/Users/private_work/pet-shop/contracts/Migrations.sol:19:3: Warning: No visibility specified. Defaulting to "public". function upgrade(address new_address) restricted { ^ Spanning multiple lines. Writing artifacts to ./build/contracts
デプロイ
デプロイする前にGanacheを起動しておきます。Ganacheは起動するだけでローカル環境にブロックチェーンを起動してくれて、さらにアドレスを10個作ってそれぞれに100ETHずつ最初から持たせてくれます。
Ganacheを使うと開発がものすごくしやすくなるので絶対に使いましょう!
Adoption.solのデプロイはコントラクトアドレスが表示されれば成功です。
$ truffle migrate Using network 'development'. Running migration: 1_initial_migration.js Replacing Migrations... ... 0x6aad3f602ed67552ce6ecd2e4691e7e597cf53fe402ebf8b30ee2b0c2175b3bb Migrations: 0x8cdaf0cd259887258bc13a92c0a6da92698644c0 Saving successful migration to network... ... 0xd7bc86d31bee32fa3988f1c1eabce403a1b5d570340a3a9cdba53a472ee8c956 Saving artifacts... Running migration: 2_deploy_contracts.js Replacing Adoption... ... 0xf669341114c23fd66bd5d6d5597e208ff0327145172e0fd3356cd2ae25925540 Adoption: 0x345ca3e014aaf5dca488057592ee47305d9b3e10 Saving successful migration to network... ... 0xf36163615f41ef7ed8f4a8f192149a0bf633fe1a2398ce001bf44c43dc7bdda0 Saving artifacts...
Ganache上でトランザクションも確認できます。

テストコード
テストコードもSolidityで書きます。Adoption.solに実装した変数と関数に対してテストを行なっています。
pragma solidity ^0.4.17; import "truffle/Assert.sol"; import "truffle/DeployedAddresses.sol"; import "../contracts/Adoption.sol"; contract TestAdoption { Adoption adoption = Adoption(DeployedAddresses.Adoption()); // Testing the adopt() function function testUserCanAdoptPet() public { uint returned = adoption.adopt(8); uint expected = 8; Assert.equal(returned, expected, "Adoption of pet ID 8 should be recorded."); } // Testing retrieval of a single pet's owner function testGetAdopterAddressByPetId() public { // Expected owner is this contract address expected = this; address adopter = adoption.adopters(8); Assert.equal(adopter, expected, "Owner of pet ID 8 should be recorded."); } // Testing retrieval of all pet owners function testGetAdopterAddressByPetIdInArray() public { // Expected owner is this contract address expected = this; // Store adopters in memory rather than contract's storage address[16] memory adopters = adoption.getAdopters(); Assert.equal(adopters[8], expected, "Owner of pet ID 8 should be recorded."); } }
テストを実行すると3つともちゃんとテストが通りました。
$ truffle test Using network 'development'. Compiling ./contracts/Adoption.sol... Compiling ./test/TestAdoption.sol... Compiling truffle/Assert.sol... Compiling truffle/DeployedAddresses.sol... TestAdoption ✓ testUserCanAdoptPet (120ms) ✓ testGetAdopterAddressByPetId (54ms) ✓ testGetAdopterAddressByPetIdInArray (122ms) 3 passing (963ms)
フロントエンド開発
stc/app.jsをドキュメントに沿って実装します。ここはただの作業になるのでweb3jsの初期化部分だけ説明します。
web3がundefinedじゃないという状況はMetaMask内臓のweb3がちゃんとブラウザでグローバル変数として使えるときです。グルーバルなweb3が取得できればcurrentProviderを使って新たにweb3インスタンスを作成し、MetaMask経由でトランザクションを発行できるようになります。
ここら辺は最初理解しづらいですがかなり重要なところなので頑張って理解できるようになってください。
initWeb3: function() { // Is there an injected web3 instance? if (typeof web3 !== 'undefined') { App.web3Provider = web3.currentProvider; } else { // If no injected web3 instance is detected, fall back to Ganache App.web3Provider = new Web3.providers.HttpProvider('http://localhost:7545'); } web3 = new Web3(App.web3Provider); return App.initContract(); }
DAppsの起動
Truffleにはlite-serverという機能でサーバのホスティングもできるようになっています。この機能を使って実装したアプリをブラウザから確認できるようになります。
package.jsonにnpm run devでlite-serverを実行できるようにscriptsが記述されているので下記で実行します。
$ npm run dev > pet-shop@1.0.0 dev /Users/private_work/pet-shop > lite-server ** browser-sync config ** { injectChanges: false, files: [ './**/*.{html,htm,css,js}' ], watchOptions: { ignored: 'node_modules' }, server: { baseDir: [ './src', './build/contracts' ], middleware: [ [Function], [Function] ] } } [Browsersync] Access URLs: ------------------------------------- Local: http://localhost:3000 External: http://172.16.42.30:3000 ------------------------------------- UI: http://localhost:3001 UI External: http://172.16.42.30:3001 ------------------------------------- [Browsersync] Serving files from: ./src [Browsersync] Serving files from: ./build/contracts [Browsersync] Watching files...
MetaMask連携
アプリが起動したら次はMetaMask連携を行います。Custom RPCを選択し、http://127.0.0.1:7545を入力してSaveするだけです。これでMetaMaskがローカルで起動しているブロックチェーンにアクセスできるようになります。

Ganacheアカウントのインポート
DAppsで使うアカウントをGanacheからMetaMaskにインポートします。GanacheのACCOUNTから鍵マークをクリックします。

アドレスのprivate key(秘密鍵)が表示されるのでこれをコピーします。

MetaMaskのImport Accountにprivate keyを貼り付けるとGanacheで作成されたアカウントをMetaMaskから使えるようになります。

これでGanacheで起動させたブロックチェーンに対してGanacheで作られたアドレスからトランザクションを発行できます。
まとめ
想像していたよりも簡単にDAppsを作ることができました。なんでもいいからとりあえず作ってみるとかなり理解が進むのでオススメのサンプルコードだと思います。
今回はメインがSolidityのスマートコントラクトの解説だったのでフロントエンド開発も今後説明を追記していきます。
最後に
最後にブロックチェーンエンジニアって何?どうやったらなれるの?という人向けに書いた下の記事も読んでみてください。
おすすめ書籍
Ethereumを使ったDApps開発を学びたいなら今だとこの1冊が1番良いです!開発環境の構築から使うべきツール、フレームワーク、実装方法・注意点まで網羅的に解説されている書籍なのでおすすめです。出版も2018年1月ということでかなり新しい本で、DMM Bitcoinを作っているネクストカレンシー所属の方が書いているので信頼できます。
ビットコインとブロックチェーンの詳細をしっかりと学びたい方にはこちらの書籍が非常におすすめです。ウォレットの仕組み、楕円曲線暗号、P2Pプロトコル、公開鍵暗号などビットコインを支える技術について詳細に解説されています。また、サンプルコードを通して実際に手を動かして学べるので非常に濃い内容となっています。
髙妻智一
最新記事 by 髙妻智一 (全て見る)
- Polkadot(Substrate)のアドレスとトランザクションについて - 2023-03-09
- 【無料公開】「Goで始めるBitcoin」3章 Bitcoinノードとの通信 技術書典8 - 2020-03-08
- エンジニアがゼロから技術ブログを書くための方法をまとめました - 2019-05-25
細かいですが
– mkdir pet-shot & cd pet-shop
+ mkdir pet-shop & cd pet-shop
ですね。。。笑 修正しました。ご指摘ありがとうございます!