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を指定しています。
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のサーバを立ててノードに繋いでおく必要があるとは考えます。
今は利用してでも表示させることを優先しました
<!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も設置します。
<?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のことを書かれていますので参考になると思います。
次は、これにコントラクトした独自トークンの残高を表示させます。
#参考
以下のサイトを参考にさせて頂きました。ありがとうございます。
https://github.com/ethereum/wiki/wiki/JSON-RPC
https://infura.io/
https://infura.io/docs
JSON-RPC API で geth を便利に使う
Ethereum(Geth)でJSON RPCを使って外部からアクセスする