katonobo’s blog

プログラミング中心の雑記ブログ

 お知らせ

 プログラミングスクールの口コミサイト「プロログ」をリリースしました プロログ

 プログラミングに興味ある方はぜひご覧ください!

Dappsをフロントエンドまで作ろう!【Truffle】【Infura】【Metamask】【Vue.js】【npm】

f:id:katonobo:20180725115641j:plain

 

現在、Dappsを作るために便利なツールが揃ってきています。

しかし、フロントエンドまで作成し、実際にブラウザ画面でDappsを体験できるところまで案内している記事は少ないのが現状です。

そこで、ブロックチェーン初心者でもフロントエンドまで作成することを目標にした記事を書くことにしました。

使ってるパソコンはMacです。windowsはわかりません。

ブロックチェーンの技術は進歩が凄まじいので、この記事の内容もすぐ古くなってしまう可能性があるのでご注意ください。最後に参考にした記事や書籍も紹介します。

 

今回作成するDappsの完成形のイメージ

今回作成するDappsは、truffleのコニュニティが作成した「Vue-box」を参考にしています。

vue-box Box | Truffle Suite

 

<ブラウザ画面>

f:id:katonobo:20180724120337p:plain

このDappsは、数字を入力し「Update value in the contract」を押すとメタマスクが起動しコントラクトを生成します。そして「Valu read from the contract:」で入力した数字を表示させます。

 画像の赤い①が、デプロイしたコントラクトのアドレス。②が現在接続しているMetaMaskのコントラクトアドレス。③が、数値を入力して、コントラクトに入った数字を表示させています。

 

今回作成するにあたり利用する環境、ライブラリなど

Truffle

 Truffeは、イーサリアムの総合開発フレームワークです。コンパイル、テスト、マイグレーションなどが簡単に行えるため、現在のイーサリアムの開発でメジャーとなっています。大変便利です。

Truffle Suite - Your Ethereum Swiss Army Knife

Infura

Infuraを使えば、イーサリアムのノードを自分で立てずに済み、API経由で無料でアクセスできます。

Infura - Scalable Blockchain Infrastructure

Metamask

metamaskはブラウザの拡張機能で、自分のブラウザでイーサリアムのブロックチェーンとやりとりすることができるようになります。

*現在クロームでメタマスクがインストールできないようです。Operaではできるようです。注意してください。(2018/7/26)

 

MetaMask

Vue.js 

Vue.jsは、フロントエンドのJavascriptのフレームワークです。少ないコード量でフロントエンドの開発ができます。

Vue.js

npm

npmは、Node.jsのパッケージ管理ツールです。様々ライブラリをインストールするときに使います。

npm

 

事前準備

開発を行うまえに、事前準備をしましょう。

パッケージ管理マネージャーのnpmを使えるようにするため、Node.jsをインストールしましょう。

Node.js

そして、そのNode.jsをインストールするために、Homebrewを使います。

macOS 用パッケージマネージャー — macOS 用パッケージマネージャー

つまり、

 

①Homebrew → ②Node.js 

 

という順番でセッティングします。

以下の記事を参考にセッティングしてください。

qiita.com 

スタート

Truffleをインストール

まずはMacのターミナルを開きましょう!

次にTruffleをインストールします

 

$ npm install -g truffle

($は省いて、npm install -g truffleをコピーして貼り付けてくださいね )

 

これでTruffleを使えるようになりました。次にプロジェクトを作成します。

今回は、「truffle-frontend」と言う名前のプロジェクトで作ります。

 

$ mkdir truffle-frontend

$ cd truffle-frontend

 

mkdirは、ディレクトリ(フォルダ)の作成を指示するコマンドです。

cdは、ディレクトリの移動を指示します。ここでは、新しく作成したtruffle-frontendと言うディレクトリに移動してねというコマンドになります。

truffleプロジェクトの新規作成

さて次に、truffle-frontendディレクトリ内に、truffleのプロジェクトを作成します。

 

$ truffle init

 

作成すると、いくつかのファイルが自動で作られたと思います。これが雛形となります。

.
├── contracts
│ └── Migrations.sol
├── migrations
│ └── 1_initial_migration.js
├── test
├── truffle-config.js
└── truffle.js

 

ここに幾つのかのファイルを加えて行きます。

 SimplStore.solと2_simple_store.jsファイルの作成

SolidityのコードがなければDappsは作れません。今回は、「SimpleStore.sol」と言うベーシックなコントラクトコードを使います。

 

Web3、LoomProviderとTruffle · Loom SDK

 

contractsフォルダの中に、SimpleStore.solという名のファイルを作成します。

そして、そこに下記コードを入力します。

 

contracts/SimpleStore.sol

 

pragma solidity ^0.4.22;

contract SimpleStore {

  uint value;

  event NewValueSet(uint _value);

  function set(uint _value) public {

    value = _value;

    emit NewValueSet(value);

  }

  function get() public view returns (uint) {

    return value;

  }

}

 

 

次に、migrationフォルダに、2_simple_store.jsファイルを作成します。

そして下記コードを入力します。

 

migrations/2_simple_store.js

var SimpleStore = artifacts.require("./SimpleStore.sol");

  module.exports = function(deployer) {
  deployer.deploy(SimpleStore);
};

 

 

 

Metamaskと、Infraの登録を行う 

続いて、MetamaskとInfraの登録を行います。

 

metamaskは、フロントエンドとイーサリアムを繋ぐ架け橋のような役割をしてくれ、Infuraはイーサリアムのノードをこちらで立てずに使えるようにしてくれるものです。

今回は、Metamaskをインストールし、さらにテストネットである「Ropsten」に設定し、Etherをゲットする必要があるので、下記リンクを参考に設定してください。

 

qiita.com

続いて、Infuraの登録です。こちらはメールアドレスを使って登録する必要があります。

ただ、登録は簡単です。

infura.io

登録したメールアドレスにあなた用のURLが送られたはずです。これは後々使います。

*現在仕様が変更され、APIを取得する形式に変わったようです(2018/7/26)。

 

これでMetamaskとInfuraの準備ができました。

 

truffle.jsを変更する

次に、必要なライブラリと、truffle.jsの中身を変更します。

まずは、truffle.jsを下記のように変更してください。

 

truffle.js

 

var HDWalletProvider = require("truffle-hdwallet-provider");
var mnemonic = your.metamask.mnemonic;
var accessToken = your.Infra.accessToken;


module.exports = {
networks:{
  development:{
    host: "localhost",
    port: 8545,
  network_id:"10"
  },
ropsten:{
  provider: function(){
  return new HDWalletProvider(
    mnemonic,
    "https://ropsten.infura.io/" + accessToken
  );
},
  network_id: 3,
  gas: 500000
  }
 }
};

 

 

上記のコードの赤い文字のところは、自身のMetamaskの「mnemonic」とInfuraで付与されたURLで、「https://ropsten.infura.io/」の後に書かれている文字を入れてください。その際「""(ダブルクォーテーション)」で囲むことを忘れずに。

 

(mnemonicの場所が変わらない場合はこちらを参照してください

https://makionaire.com/metamask-trust/

 

truffle-hdwallet-providerを使うのでインストール

 

$ npm install truffle-hdwallet-provider

 

 

Ropstenネットワークへデプロイします。

 

$ truffle migrate --network ropsten 

 

これでエラーがなければRopstenにデプロイできました。

 

フロントエンドを作っていく

これで一応Dappsはできたました。ここからはフロントエンドを実装して行きます。

 

Vue.jsの使う

今回のフロントエンドはVue.jsで作って行きます。

まずは、Vue-cliを使います

 

$ npm install -g vue-cli 

 

インストールできたら、truffle-frontendのディレクトリ内で、以下のコマンドを打ちます

 

$vue init webpack-simple

 

こちらを打つと、いくつか選択肢がでます。全部エンターでOKで、最後の「Use sass?」だけ、「y」と打ってください。

 

インストールが完了したら、

 

$npm install

$npm run dev 

 

を実行してください。

下のような大きなV字が書かれた画面が出ましたか?表示されたら、これでVue.jsが使えるようになりました!

f:id:katonobo:20180724234239p:plain

 

あとは、このフロントエンドと、スマートコントラクトを連携するように作って行きます。

Web3.jsとtruffle-contract

ブラウザ側からコントラクトに指示をするために、JavascriptのAPIである「Web3.js」をインストールします。

 

$npm install web3

 

 続いて「truffle-contract」と言う便利なライブラリをインストールします。

truffle-contract - npm

 

$npm install truffle-contract

 

 

 App.vueの編集

フロントエンドを編集します。App.vueと言うファイルが先ほどの画面なので、このApp.vueを編集します。

このコードはほぼvue-boxの、SimpleStorege.vueのコードになります。

 

src/App.vue

 

<template>

  <div class="app">

    <div class="content">

      <h3>Example of a simple storage contract</h3>

      <p v-if="contractAddress">The contract is deployed at {{contractAddress}}</p>

      <p v-if="!contractAddress">No contracts found</p>

      <p v-if="account">Current account: {{account}}</p>

      <p v-if="!account">No accounts found</p>

      <input v-model="newValue" type="number">

      <button @click="updateValue">Update value in the contract</button>

      <p v-if="currentNumber">Value read from the contract: {{currentNumber}}</p>

      <p v-if="!currentNumber">Value not set</p>

    </div>

    <div class="message" v-if="message">{{message}}</div>

  </div>

</template>

 

<script>

import Web3 from 'web3'

import contract from 'truffle-contract'

import artifacts from '../build/contracts/SimpleStore.json'

const SimpleStore = contract(artifacts)

 

export default {

  name: 'app',

  data () {

    return {

      message: null,

      contractAddress: null,

      account: null,

      newValue: 0,

      currentNumber: 0

 

    }

  },

  created(){

    if (typeof web3 !== 'undefined') {

      // Use Mist/MetaMask's provider

      web3 = new Web3(web3.currentProvider);

  } else {

    console.warn("No web3 detected. Falling back to http://127.0.0.1:8545. You should remove this fallback when you deploy live, as it's inherently insecure. Consider switching to Metamask for development. More info here: http://truffleframework.com/tutorials/truffle-and-metamask")

    // fallback - use your fallback strategy (local node / hosted node + in-dapp id mgmt / fail)

    web3 = new Web3(new Web3.providers.HttpProvider("http://127.0.0.1:8545"))

      }

      SimpleStore.setProvider(web3.currentProvider)

      web3.eth.getAccounts( (err, accs) => {

      if (err != null) {

        console.error(err)

        this.message = "There was an error fetching your accounts. Do you have Metamask, Mist installed or an Ethereum node running? If not, you might want to look into that"

        return

      }

      if (accs.length == 0) {

        this.message = "Couldn't get any accounts! Make sure your Ethereum client is configured correctly."

        return

      }

      this.account = accs[0];

      SimpleStore.deployed()

        .then( (instance) => instance.address)

        .then( (address) => {

          this.contractAddress = address

          this.updateCurrentNumber()

        })

    })

 

  },

  methods: {

      updateValue() {

        this.message = "Transaction started";

        return SimpleStore.deployed()

          .then( (instance) => instance.set(this.newValue, {from: this.account}))

          .then( () => {

            this.message = "Transaction done"

            this.updateCurrentNumber()

          })

          .catch( (e) => {

            console.error(e)

            this.message = "Transaction failed"

          })

      },

      updateCurrentNumber() {

        SimpleStore.deployed().then( (instance) => instance.get()).then( (r) => {

          console.log(r.toNumber())

          this.currentNumber = r.toNumber()

        });

      },

    },

 

}

</script>

 

<style lang="scss">

#app {

  font-family: 'Avenir', Helvetica, Arial, sans-serif;

  -webkit-font-smoothing: antialiased;

  -moz-osx-font-smoothing: grayscale;

  text-align: center;

  color: #2c3e50;

  margin-top: 60px;

}

 

h1, h2 {

  font-weight: normal;

}

 

ul {

  list-style-type: none;

  padding: 0;

}

 

li {

  display: inline-block;

  margin: 0 10px;

}

 

a {

  color: #42b983;

}

</style>

 

 

 

 Vue.jsのコードに関してはこの記事だとまったく収まらないので、最後の参考書籍を呼んでください。ここでは、<script>内のコントラクトとのやりとりに関係あるコードについて説明します。

 

import Web3 from 'web3'

import contract from 'truffle-contract'

import artifacts from '../build/contracts/SimpleStore.json'

const SimpleStore = contract(artifacts)

 この4行は、App.vueで「web3」「truffle-contract」のライブラリを使えるように設定しており、「SimpleStore.json」のファイルを参照できるようにし、SimpleStoreとして使えるようにしています。

 

created(){   }の中のコードについて説明します。created()は、ファイルを読み込む時に自動的に実行してくれるコードです。ここで、web3.jsと、Metamaskの連携が行われているかの判定を行い、接続してない場合はその旨を伝えます。

    if (typeof web3 !== 'undefined') {

      // Use Mist/MetaMask's provider

      web3 = new Web3(web3.currentProvider);

  } else {

    console.warn("No web3 detected. Falling back to http://127.0.0.1:8545. You should remove this fallback when you deploy live, as it's inherently insecure. Consider switching to Metamask for development. More info here: http://truffleframework.com/tutorials/truffle-and-metamask")

    // fallback - use your fallback strategy (local node / hosted node + in-dapp id mgmt / fail)

    web3 = new Web3(new Web3.providers.HttpProvider("http://127.0.0.1:8545"))

      }

      SimpleStore.setProvider(web3.currentProvider)

      web3.eth.getAccounts( (err, accs) => {

      if (err != null) {

        console.error(err)

        this.message = "There was an error fetching your accounts. Do you have Metamask, Mist installed or an Ethereum node running? If not, you might want to look into that"

        return

      }

      if (accs.length == 0) {

        this.message = "Couldn't get any accounts! Make sure your Ethereum client is configured correctly."

        return

      }

      this.account = accs[0];

      SimpleStore.deployed()

        .then( (instance) => instance.address)

        .then( (address) => {

          this.contractAddress = address

          this.updateCurrentNumber()

        })

    })

 

 

その後、現在のコントラクトアドレスと、このプロジェクトのコントラクトアドレスを取得します。

 

ボタンを押した時のアクションです。

 

  methods: {

      updateValue() {

        this.message = "Transaction started";

        return SimpleStore.deployed()

          .then( (instance) => instance.set(this.newValue, {from: this.account}))

          .then( () => {

            this.message = "Transaction done"

            this.updateCurrentNumber()

          })

          .catch( (e) => {

            console.error(e)

            this.message = "Transaction failed"

          })

      },

      updateCurrentNumber() {

        SimpleStore.deployed().then( (instance) => instance.get()).then( (r) => {

          console.log(r.toNumber())

          this.currentNumber = r.toNumber()

        });

      },

    },

 

数値を入力して、「Update value in the contract」ボタンを押すと実行されます。数字をコントラクトに送り、データを更新します。

 

実行

さて、これで準備が整いました。

再度、

$npm run dev

を実行してください。

 

ブラウザが立ち上がり、metamaskのコントラクトアドレスと、プロジェクトのコントラクトアドレスの画面が表示されましたか? 

実際に数字を入力して色々いじってみてください。

 

まとめ

お疲れ様でした!ここからFirebaseを使ってデプロイまですることも可能です。

これでフロントエンドとイーサリアムのコントラクトの連携ができたので、あとは自分の作りたいDappsに挑戦してみてください!

 

学習するのにオススメする書籍、記事

 

【イーサリアム】

 

はじめてのブロックチェーン・アプリケーション Ethereumによるスマートコントラクト開発入門 (DEV Engineer's Books)

イーサリアムの基本がわかります。gethの使用方法など、仕組みがわかるのでオススメです。

 

 

ブロックチェーンアプリケーション開発の教科書

 ブロックチェーンエンジニア必読の書です。エンジニア以外にも暗号通貨に興味ある人でも体系的に学ぶことができます。他のブログでもみなさん絶賛されていますね。本当にすごいですこの本。

 

<イーサリアム・アドイベントカレンダー>

qiita.com

様々な方が執筆されています。こちらの記事は全部目を通しておくといいと思います。

 

 <クリプトゾンビ>

cryptozombies.io

コードを実際に書きながらスマートコントラクトの勉強ができます。

 

loomx.io

 今回はこちらのSimpleStore.solを使わせてもらいました。

 

 <Trruffle Boxes>

truffleframework.com

Truffleの実際のサンプルがたくさんあります。ここのプロジェクトのコードはとても参考になります。

 

<まつしんのブログ>

matsushin11.com

丁寧な解説があり、大変勉強になるブログです。

 

<DAppsの勉強として分散型Tweetサイト、Dtwitterを作りました> 

qiita.com

分散型ツイッターの記事です。GitHubも載せてくれているので、とても勉強になります。

 

【Vue.js】

 

www.katonobo.com

 

Dappsのフロントエンドは、Reactが中心のようですが、Vue.jsもサンプルがあります。ただ、フレームワークを使っている例が多いため、どちらかは習得しておくのがいいと思います。

 

Vue.jsとFirebaseで作るミニWebサービス (技術書典シリーズ(NextPublishing))

 Vue.jsの入門にはこちらがぴったりです。私も最初この本でVue.jsを学習しました。

 

基礎から学ぶ Vue.js

 

本格的にVue.jsを学習するなら本書です。基礎から応用まで詳しく説明してくれています。