前回のサンプルアプリ作成ではRailsからスマートコントラクトの連携をさせて独自トークンを発行するサンプルアプリを作成しました。
今回はサーバーサイドは利用せずReact.jsと連携させて掲示板のサンプルアプリを作成してみました。
サーバサイドを利用せずフロントエンドからのみ連携させた理由としては、React.jsのようなJacaScriptのフレームワークを使った経験が少ないのでその学習も兼ねているためです。
フレームワークは他にも有名なVue.jsにしようか少し迷ったのですが、よりReact.jsの方が一般的という印象があったのであまり深く考えずReactを選んでいます。
また最近CSSフレームワークのBulmaが人気と噂で聞いたのでおまけで使ってみました。
今回作ったコードはこちらにおいています。
Contents
サンプルアプリのコードから得られる知識
- ERC721の利用方法
- React.jsの基本
- フロントエンドからのスマートコントラクトとの連携方法
- Bulmaの利用方法
急に「ERC721」と出てきていますが、スマートコントラクトの規格の1つになります。サンプルアプリでは掲示板への投稿の1つ1つがERC721に準拠したトークンという扱いになります。
スマートコントラクト内で代替え不可能なトークン(Non-Fungible Token=NFT)を扱えるように規格を定められている。
ERC721の規格を用いることで、イーサリアムブロックチェーンでNFTの所有権や取引履歴を記録できます。
掲示板の仕様
匿名掲示板への投稿と一覧表示のみできるシンプルな作りとなっています。
- 掲示板への投稿
- 掲示板の一覧表示
動作環境
動作させた環境は以下になります。
- React.js v16.3.2
- Bulma v0.7.1
- yarn v1.6.0
- solidity v0.4.23
- OpenZeppelin v1.9.0
- truffle v4.1.7
- Ganache v1.1.0
サンプルアプリの動作確認
動作方法
リポジトリをクローン
1 |
$ git clone git@github.com:Matsushin/dapps-react-bbs.git |
各ライブラリのインストール
1 |
$ yarn install |
コントラクトコードのコンパイルを実行
1 |
$ truffle compile |
Ganacheを起動
コントラクトコードのマイグレートを実行
1 |
$ truffle migrate |
JavascriptとCSSファイルのビルドを行う
1 |
$ yarn run webpack |
ローカルサーバを起動
1 |
$ yarn run webpack-dev-server |
最後にトップ画面(http://localhost:3000)にアクセス。エラーが発生しなければOK!
それでは次に動作を確認していきましょう。
動作確認
トップ画面にアクセスして投稿フォームにタイトルと本文を入力して投稿する
投稿後に投稿一覧に表示されればOK!
動作が確認できましたので次は実装のポイントを見ていきます。
実装のポイント
ERC721準拠したコントラクトコード
前回作成した独自トークンのサンプルアプリ同様にzeppelin-solidityライブラリを使用することで簡単に実現できます。
メソッドとしてはmint、getPost、getAllPostsの3メソッドを追加しただけになります。処理としてもシンプルなものになりました。
contracts/PostToken.sol
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
pragma solidity ^0.4.23; import 'zeppelin-solidity/contracts/token/ERC721/ERC721Token.sol'; contract PostToken is ERC721Token { struct Post { string title; string content; address mintedBy; uint64 mintedAt; } Post[] posts; event Mint(address owner, uint256 tokenId); function PostToken(string _name, string _symbol) public ERC721Token(_name, _symbol) {} function mint(string _title, string _content) external returns (uint256) { require(msg.sender != address(0)); Post memory post = Post({ title: _title, content: _content, mintedBy: msg.sender, mintedAt: uint64(now) }); uint256 tokenId = posts.push(post) - 1; super._mint(msg.sender, tokenId); Mint(msg.sender, tokenId); return tokenId; } function getPost(uint64 _tokenId) external view returns (string title, string content, address mintedBy, uint64 mintedAt) { Post memory post = posts[_tokenId]; title = post.title; content = post.content; mintedBy = post.mintedBy; mintedAt = post.mintedAt; } function getAllPosts() external view returns (uint256[]) { return allTokens; } } |
フロント側からSolidityの連携
フロントからの連携はReact.jsを使っていても以前書いた記事とあまり変わらない感じですね。
App.js ではスマートコントラクト側のgetAllPostsメソッドで全投稿IDを取得後にgetPostメソッドを呼び出して1つの投稿情報を取得することで画面の更新を行なっています。
src/App.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
updatePosts() { const contract = require('truffle-contract') const postToken = contract(PostTokenContract) postToken.setProvider(this.state.web3.currentProvider) let postTokenInstance this.state.web3.eth.getAccounts((error, accounts) => { postToken.deployed().then((instance) => { postTokenInstance = instance return postTokenInstance.getAllPosts({from: accounts[0]}) }).then((response) => { for (let i = 0; i < response.length; i++) { postTokenInstance.getPost(response[i], {from: accounts[0]}) .then((response) => { let posts = this.state.posts const post = { "title": response[0].toString(), "content": response[1].toString(), "mintedBy": response[2].toString(), "mintedAt": response[3].toString() } posts.unshift(post) this.setState({ posts: posts }) }).catch((e) => { console.log('Error getPost') console.error(e) }) } }).catch((e) => { console.log('Error getAllPosts') console.error(e) }) }) } |
開発モード
実際の開発ではローカルサーバを起動する際は下記のようなコマンドを利用していました。 configオプションを利用しています。
1 |
$ yarn run webpack-dev-server --config webpack.development.config.js |
web pack.development.config.js
1 2 3 4 |
module.exports = [ { mode: 'development', ... |
このように明確にdevelopmentモードとすることでコード編集後の画面更新が素早く行うことができるようになります。
まとめ
今回でReact.jsの基本とフロントからスマートコントラクトの連携方法の基本がが学べました。
次はReduxも使ってみたいですし、スマートコントラクトをReact/Reduxで扱うフレームワークのDrizzleの利用や、さらには実際のサービスを開発する場合はサーバーサイド側との連携も行うと思うので、ReactとRailsの連携も試してみたい。
まつしん様 これからDappsで掲示板を作ろうと思っており、参考にさせて頂きます!!
ぜひ参考にしてみて下さいー!