【CryptoZombiesを触ってみた】Lesson6で学んだこと

【CryptoZombiesとは】

Solidityでスマートコントラクトの構築を学習できるサイトです。日本語で丁寧に説明してくれるので、プログラミング未経験の人でも学習できます。

cryptozombies.io

【はじめに】

Solidityは未経験ですが、JavaScriptは触ったことがあります。そんな人が自分用の学習メモとして書いています。

【学んだこと】

Web3.js

イーサリアムのノードにアクセスできるJavaScriptライブラリです。フロントエンド(Webページ)からスマートコントラクトの関数を呼び出す場合に使用します。

まずは、Web3.jsをダウンロードして、htmlのheadタグ内にscriptタグを追加します。

<script language="javascript" type="text/javascript" src="web3.min.js"></script>

Web3プロバイダとMetamask

続いて、Web3プロバイダの設定(どのノードを使用すれば良いか教えてくれる)が必要になります。また、ブロックチェーンに書き込みを行う場合は秘密鍵を使って署名するので、秘密鍵の安全な管理も必要になります。これら全てを自前で実装することも可能ですが、今はMetamaskを使用するのがデファクトスタンダードになっています。MetamaskがインストールされていればMetamaskで使用しているWeb3プロバイダをそのまま使用することができ、イーサリアムのアカウントと秘密鍵も安全に管理してくれます。
Metamaskのインストール方法や使い方は他の方々がブログで紹介しているので、そちらを参考にしてください。

window.addEventListener('load', function() {
  // MetamaskがJavaScriptのグローバルオブジェクト web3 にWeb3プロバイダを設定するので
  // web3が設定されているかを確認すればMetamaskのインストール状況を判断できます。
  if (typeof web3 !== 'undefined') {
    // Web3が設定されていればMetamaskで使用しているWeb3プロバイダを設定
    web3js = new Web3(web3.currentProvider);
  } else {
    // web3が設定されていなければMetamaskをインストールするメッセージを表示
  }
  // 処理開始
  startApp()
})

コントラクトアドレスとABI

Web3.jsを使用してスマートコントラクトにアクセスするには
・スマートコントラクトをデプロイする際に付与されるコントラクトアドレス
・スマートコントラクトをコンパイルする際に作成されるABI(Application Binary Interface)
 ※ABIは関数の定義(関数名や引数など)がJSON形式で記載されています。
が必要になります。

var myContract;
function startApp() {
  // デプロイする際に付与されたコントラクトアドレス
  var myContractAddress = "YOUR_CONTRACT_ADDRESS";
  // コンパイルする際に作成されたABI
  var myContractABI = "YOUR_CONTRACT_ABI";
  // コントラクトアドレスとABIを使用してコントラクトを初期化
  myContract = new web3js.eth.Contract(myContractABI, myContractAddress);
}

call

Web3.jsを使用してスマートコントラクトのview関数、pure関数を呼び出します。読み取り専用なのでブロックチェーンへのトランザクションは発生しません。

myContract.methods.myMethod(argument1, argument2, argument3).call()

send

Web3.jsを使用してスマートコントラクトのview関数、pure関数以外の関数を呼び出します。ブロックチェーンのデータを更新するのでトランザクションが発生します。当然、ガス(Gas)の支払いや署名が必要になりますが、Metamaskがインストールされていれば全てMetamaskが行ってくれます。

myContract.methods.myMethod(argument1, argument2, argument3).send()

アカウント取得

Web3プロバイダを設定したグローバルオブジェクト web3 からユーザーのアカウントを取得することができます。Metamaskを使用している場合、Metamaskでアクティブになっているユーザーのアカウントを取得します。

var userAccount = web3.eth.accounts[0]

ユーザーのアカウントが変更されているかチェックしたい場合は、setInterval(JavaScriptのループ関数)を使います。

var accountInterval = setInterval(function() {
  // アカウントが変更されているかチェック
  if (web3.eth.accounts[0] !== userAccount) {
    userAccount = web3.eth.accounts[0];
    // 変更後のアカウントで行いたい処理
  }
}, 100);

トランザクションの送信

トランザクションが大量に保留されていたり、設定したガス代が安すぎると数ブロック待つ必要があるため、非同期処理で記述する必要があります。

function createRandomZombie(name) {
  // しばらく時間がかかるので、ユーザーにトランザクションが送信されたことを知らせる
  $("#txStatus").text("Creating new zombie on the blockchain. This may take a while...");
  // トランザクションをコントラクトに送信する
  return cryptoZombies.methods.createRandomZombie(name)
  .send({ from: userAccount })
  // トランザクションがブロックに含まれるとreceiptが発行される
  .on("receipt", function(receipt) {
    // トランザクションがブロックチェーンに取り込まれたことを知らせる
    $("#txStatus").text("Successfully created " + name + "!");
    getZombiesByOwner(userAccount).then(displayZombies);
  })
  .on("error", function(error) {
    // トランザクションが失敗したことをユーザーに知らせる
    $("#txStatus").text(error);
  });
}

Wei

イーサ(イーサリアムの通貨)の最小単位
1 wei = 0.000000000000000001 ether

// payable関数を呼び出す際、etherではなくweiで指定する必要があるので
// toWeiを使用してetherをweiに変換する
cryptoZombies.methods.levelUp(zombieId)
.send({ from: userAccount, value: web3js.utils.toWei("0.001", "ether") })

eventをトリガーにする

Web3.jsではスマートコントラクトのイベントをトリガーにすることができます。

// スマートコントラクト側(Solidity)
// eventを設定
event NewZombie(uint zombieId, string name, uint dna);

// フロントエンド側(javascript)
// eventをトリガーとして処理を行います。
cryptoZombies.events.NewZombie()
.on("data", function(event) {
  let zombie = event.returnValues;
  console.log("A new zombie was born!", zombie.zombieId, zombie.name, zombie.dna);
}).on("error", console.error);

indexedを使用すればイベントのフィルタリングができます。

// スマートコントラクト側(Solidity)
// indexedで引数を設定しておきます
event Transfer(address indexed _from, address indexed _to, uint256 _tokenId);

// フロントエンド側(javascript)
// '_to'が'userAccount'と同じ場合のみ処理が行われます。
cryptoZombies.events.Transfer({ filter: { _to: userAccount } })
.on("data", function(event) {
  let data = event.returnValues;
}).on("error", console.error);

【できたもの】

今回のLessonはフロントエンド(javascript)がメインだったので比較的分かりやすかったです。Metamaskのお面カワイイ!
f:id:takuyafujita:20181014194805j:plain

現在はLesson6で終了ですが、もうすぐseason2が登場しそうなので楽しみです!