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

webページで簡単にEtherやTokenの残高が表示できるようにしてほしい。
という話からまた色々探してみる。

# Geth JSON-RPCを使う
最初に考えたのがGethを使って繋ぎこむ方法。
とはいえ今まで得意とする分野のphpを使っての繋ぎこみは難しく、調べていくうちにたどり着いたのがJSON-RPC。

```
PHP → GETH（JSON-RPCサーバ）→　Ethereumノード
```

この形でEthereumから残高を取得できると考えました。
私が得意とするPHPの場合、curlを使えばJSON-RPCを簡単に送れるというのもありましたので、PHPでJSON形式をPOSTする方法を参考に致しました。
接続先は、Gethを```--rpc```の起動オプションをつけてRPCを有効な状態にして起動させている自身のLocalhostを指定しています。

```web3balance.php

function postJson($json){
    //
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, 'https://127.0.0.1:7545');
    curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json'));
    curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
    curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($json));
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    $result = curl_exec($ch);
    curl_close($ch);
    return $result;
}

    // getBalance
    $data = [
        "jsonrpc" => "2.0",
        "method" => "eth_getBalance",
        "params" => [$address,"latest"],
        "id" => 65756,
    ];
    //
    $response = postJson($data);
````

ここで問題が発生。
自身の開発環境のPC上で組んだ後、サーバ上で動作させようとして、そこでgethのインストールが上手くいかないという事態が発生しました。
またGethがインストール出来たとしてもノードの同期も行う必要があり、その分容量を使ってしまう。
インストールが対処出来ても容量問題が厄介です。
何かGethを上手くインストールする方法はないものか、同期させる必要はどうするか？

# INFURAのJSON-RPC APIを使ってみる
他の方のWeb WalletやスマホWalletがどうしているのか調べてみたら解決は早かったです。
「INFURAがJSON-RPCに対応している」
ということがわかれば十分でした。
INFURAを使えば同期させる必要もGethをインストールする必要も無くなります。
ただし、問題はINFURAのサービスに乗っかった状態のままでも良いのか、ということです。
いずれはJSON-RPCのサーバを立ててノードに繋いでおく必要があるとは考えます。

今は利用してでも表示させることを優先しました

```web3balance.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>web3.getBalance</title>
    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
</head>
<body>
<h1>web3.getBalance</h1>
<form id="myForm">
    ETHアドレス<br/>
    <input type="text" id="address" name="address" size="64" value="Ether address"><br />
    ETH残高<br/>
    <input type="text" id="ethbalance" name="ethbalance" 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);
                    }
                    else{
                        console.log("failer");
                    }
                },
                error : function(data) {
                    console.log("error");
                    console.log(JSON.stringify(data));
                }
            });
        });
    });
</script>
</body>
</html>
```

HTMLと同じ階層にJSON-RPCを送信するPHPも設置します。

```web3balance.php

<?php
//
function postJson($json){
    //
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, 'https://ropsten.infura.io/');
    curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json'));
    curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
    curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($json));
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    $result = curl_exec($ch);
    curl_close($ch);
    return $result;
}
//
function decodeHex($hex){
    $dec = null;
    if(substr($hex, 0, 2)=='0x') {
        $hex = substr($hex, 2);
    }
    if(preg_match('/[0-9a-f]+/', $hex)) {
        $dec = hexdec($hex) / pow(10, 18);
    }
    return $dec;
}
//
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);
    $jsonData = [
        "address" => $address,
        "ethBalance" => $ethbalance,
        "status" => "success"
    ];
    return $jsonData;
}
//
$result = false;
$jsonString = file_get_contents('php://input');
$jsonData = json_decode($jsonString);
if(isset($jsonData->address)) {
    $address = $jsonData->address;
    //
    $result = main($address);
}
if($result) {
    $json = $result;
}else{
    $json = [
        "address" => $address,
        "status" => "error",
    ];
}
//
header('Content-Type: application/json');
echo json_encode($json);
```

このコードはテストのこともあるのでRopstenのTestnetに接続を行いEther残高を返してもらうことにしています。Liveの場合は、CURLOPT_URLのアドレスをInfuraのLiveに変更するだけです。

curlでJSONを送る場合、```Content-Type: application/json```の指定がないとエラーが表示されてダメな様子。
以前はなくても行けたようですが厳格になったのだと思います。

```
    curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json'));
```

JSONで送る内容は残高を取得する```eth_getBalance```のメソッド。
こちらの配列をjson_encodeしてから送信しています。

```
    // getBalance
    $data = [
        "jsonrpc" => "2.0",
        "method" => "eth_getBalance",
        "params" => [$address,"latest"],
        "id" => 65756,
    ];
```

パラメータの内容についてはまだ勉強中です。

ブラウザから```web3balance.htm```にアクセスしてEtherアドレスを入力して```check```ボタンを押す。
ローカルの```web3balance.php```へEtherのアドレスが送信されて、それを受け取った後、InfuraのRopsten JSON-RPCへメソッドとパラメータをPOST。
Infuraから正常にレスポンスを取得して、Etherの残高をJson形式に整形してHTMLへレスポンスとして戻す。
それを受け取ってからETH残高の欄に表示させる。

こうのようなことでWebページにEtherの残高を表示することが出来ます。
結構色々な方々がJSON-RPCのことを書かれていますので参考になると思います。

![web3balance201804241650.png](https://qiita-image-store.s3.amazonaws.com/0/243376/fe7373cd-dac5-aa91-6e74-0f52955c5322.png)

次は、これにコントラクトした独自トークンの残高を表示させます。


#参考
以下のサイトを参考にさせて頂きました。ありがとうございます。
https://github.com/ethereum/wiki/wiki/JSON-RPC
https://infura.io/
https://infura.io/docs

[JSON-RPC API で geth を便利に使う](https://blockchain-jp.com/tech/375)
[Ethereum(Geth)でJSON RPCを使って外部からアクセスする](https://gootablog.com/geth-jsonrpc)