webページにEtherの残高を表示してみる(その2)


トークンの保有数を追加する

前回の「webページにEtherの残高を表示してみる」に続き、これに独自のトークンの保有数を表示をしたい。
ICOとかのサイトに設置してチェックできる機能というのは、便利なのではないだろうか

JSON-RPCでコントラクトを実行する

トークンの保有数を取得するにはトークンのコントラクトのbalanceOf(address)のメソッドを実行させる必要がある。
JSON-RPCを使ってコントラクトのFunctionを呼び出すには、eth_callでコントラクトのメソッドシグネチャとエンコードされたパラメータを送信する。
そのメソッドシグネチャについてはコントラクトのFunctionをSHA3でHASH化してその最初の4byteを使う・・・とのこと
詳しくはEthereum-Contract ABIを参照。

Geth Consoleからweb3.sha3()で、使いたいFunctionをHASH化、その先頭4byteを取得する。

geth.console
> web3.sha3('balanceOf(address)').substring(0,10)
"0x70a08231"

取得した結果を32byteデータにする
(残りの桁を0で埋める)

0x70a08231000000000000000000000000

トークンの保有数を表示させたいアドレスをメソッドシグネチャに連結する
(アドレスはデタラメの適当です)

0x70a082310000000000000000000000009876543210FedcBa9876543210FedcBa98765432

出来た結果をeth_calldataパラメータとして送信するのでjson部分を作成する

json.
{
  "jsonrpc":"2.0",
  "method":"eth_call",
  "params":
  {
    "to":"0x9876543210ffddeea00987654ffdedeEdEdFdFd012",
    "data":"0x70a082310000000000000000000000009876543210FedcBa9876543210FedcBa98765432",
    "latest",
  }
  "id":65534
}

出来たJSONをropstenに送る形に整え送信。
JSONが正常であればresponsのように返ってくる。

request.
curl -X POST -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","method":"eth_call","params":[{"to":"0x987654321...(contract_address)...","data":"0x70a082310000000000000000000000009876543210FedcBa9876543210FedcBa98765432"},"latest"],"id":65534}' https://ropsten.infura.io/
respons.
{"jsonrpc":"2.0","id":65534,"result":"0x00000000000000000000000000000000000000000000000000000000000e57e0"}

コンソールからcurlを使って正しくレスポンスを取得できるようであれば、あとは簡単です。

PHPにトークン保有数の取得を追加する

前回に作ったweb3balance.phpのmainFunction部分を書き換えてトークンの保有数の取得を追加する

web3balance.php

function main($address) {
    // check
    $address = trim($address);
    if(!$address) return false;
    if(!preg_match('/0x[0-9a-f]+/i',$address)) {
        return false;
    }
    // getBalance
    $data = [
        "jsonrpc" => "2.0",
        "method" => "eth_getBalance",
        "params" => [$address,"latest"],
        "id" => 65756,
    ];
    //
    $response = postJson($data);

    $getBalance = json_decode($response);

    $ethbalance = decodeHex($getBalance->result);

    $cHash = "0x70a08231";

    $contractHash = str_pad($cHash,34,"0").substr($address,2);

    $contract_address = "0x987654321...(ContractAddress)";

    $data = [
        "jsonrpc" => "2.0",
        "method" => "eth_call",
        "params" => [[ "to" => $contract_address, "data" => $contractHash ],"latest"],
        "id" => 65757,
    ];

    $response = postJson($data);

    $balanceOf = json_decode($response);

    $tokenbalance = decodeHex($balanceOf->result) * pow(10,16);

    $jsonData = [
        "address" => $address,
        "ethBalance" => $ethbalance,
        "tokenBalance" => $tokenbalance,
        "status" => "success"
    ];
    return $jsonData;
}

PHPのトークン保有数取得の追加にあわせて、HTML表示部分にも表示枠とレスポンスの取得・入力を追加する

web3balance.html

<form id="myForm">
    ETHアドレス<br/>
    <input type="text" id="address" name="address" size="64" value="Ethereum Address"><br />
    ETH残高<br/>
    <input type="text" id="ethbalance" name="ethbalance" size="64"><br />
    TOKEN残高<br/>
    <input type="text" id="tokenbalance" name="tokenbalance" size="64"><br />
    <input type="button" id="btnCheck" value="check">
</form>
<script type="text/javascript">
    $(function(){
        $("#ethbalance").html("Response Values");
        $("#btnCheck").click( function() {
            var jsondata = {
                address: $("#address").val()
            };
            console.log(JSON.stringify(jsondata));
            $.ajax({
                type : 'post',
                url : 'web3balance.php',
                data : JSON.stringify(jsondata),
                contentType : 'application/JSON',
                dataType : 'JSON',
                scriptCharset : 'utf-8',
                success : function(data) {
                    console.log(JSON.stringify(data));
                    if(data.status=="success") {
                        console.log("success");
                        $("#ethbalance").val(data.ethBalance);
                        $("#tokenbalance").val(data.tokenBalance);
                    }
                    else{
                        console.log("failer");
                    }
                },
                error : function(data) {
                    console.log("error");
                    console.log(JSON.stringify(data));
                }
            });
        });
    });
</script>

上記のコードは前に作ったものに修正を加えた感じにしております。
私の場合はコントラクトはRopstenにデプロイして置いたminaTokenをコントラクトとして使用しました。
またトークンのDecimalsが2に設定されているので、10進に変換するところは若干異なります。

これでアドレスを入力してCheck!とすると、Etherの残高と、トークンの保有数が表示されます。

最初に調べた際には結構簡単に見えたものですが、メソッドシグネチャを作成するなど部分で詰まったりしました。
この次は、Gasを消費するeth_sendTransactionを行いたいと思います。

参考

以下の記事を参考にさせて頂きました。ありがとうございます。
https://github.com/ethereum/wiki/wiki/JSON-RPC
https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI

JSON-RPC経由でEthereumのContractを作る
EthereumノードにJSON-RPC API経由でアクセスする