技術 ブログ

ConohaWINGでNode.jsを使いUNISWAP V2 APIでETH/USDTの価格履歴を取得しWordPressで表示する



はじめに

今回の記事は、以下の記事の応用となります 。今回は、UNISWAPのペア価格履歴を取得します。


ETH/USDのペア価格の履歴は、CryptCompareなどから取得可能ですが、無料の公開APIは帯域制限や商用での利用制限があります。

また、このようなAPIでは、API提供者を信用する必要性が発生します。


一方、The Graphから、Uniswapのサブグラフを使って仮想通貨ペア価格の履歴を取得可能ですが、クエリを一定数行うと有料になってしまいます。

さらに、多くのエンジニアやDeFierにとって、多額のAPI費用を払う金銭的余裕はありません。

これを解決するために、今回は激安で最速のConohaWINGのWordPressレンタルサーバにNode.jsをインストールし、バックエンドでInfuraAlchemyなどのブロックチェーン・アズ・ア・サービスを使います。

そして、直接Uniswap V2コントラクトにアクセスし、指定した期間の仮想通貨ペア価格の履歴を計算し取得します。

また、ETH/USDTのペペア価格の履歴をWordPressから簡単なJSON APIとして公開します。

これにより、無料でかつトラストレスに取得したETH/USDTのペア価格の履歴のJSONを、フロントエンドのJavaScriptで通信制限や商用利用制限に触れることなく利用することができます。

他のAPIやアプリに頼ることないので、APIサービスへの通信オーバヘッドを減らすことができます


それに加え、トラストレスに価格履歴を知る必要があるとき(DeFiボットの作成など)に必須スキルだと思われます。

以下にて、その方法をご紹介します。


手順

手順1・3・4は、「ConohaWINGでNode.jsを使いUNISWAP V2 APIでETH/USDTの最新価格を取得しWordPressで表示する」と同様です。


1. ConohaWINGへSSHログイン設定とNode.jsのインストールを行う



ConohaWINGサーバには、残念ながら管理者権限がありません。

そのため、ユーザ権限で使用できるように特殊なインストール作業が必要になります。

SSH設定と管理者権限の無いConohaWINGのユーザーでNode.jsをインストールする手順がイブさんのブログにて公開されています。


こちらを参考にして①SSH設定③Node.jsのインストールをしてください。

イブさん、有益な情報ありがとうございました!




2. Web3.jsをインストールする

ConohaWINGで以下コマンドを実行し、Web3.jsEthereum-Block-By-Dateをインストールしてください。

Ethereum-Block-By-Dateは、指定した日時でイーサリアムのブロック番号を取得するコンポーネントです。

不便なことにイーサリアムはRDB(リレーションデータベース)のSQLのように、特定の時間のブロック情報を検索することができません。

例えば、昨日の午後12時のETH/USDTの価格を知りたければ、現在のブロック番号とタイムスタンプを取得し、昨日の午後12時まで12秒ごとにブロック番号を減らいしていき、昨日の午後12時のブロック番号を計算する必要性が発生します。

これは、大変骨の折れる作業です。

Ethereum-Block-By-Dateを使うと指定した日時のブロック番号を取得することができ大変便利です。

※ただし、このコンポーネントを信用する場合は、ソースを解読する必要があることに留意してください

$ npm install web3
$ npm install ethereum-block-by-date



3. ブロックチェーン・アズ・ア・サービスでイーサリアムメインネットのAPIを作成する

InfuraAlchemyなどのブロックチェーン・アズ・ア・サービスでイーサリアムメインネットのAPIを作成してください。


ethereum.orgのわかりやすい記事がありますので、手順通りに行うとAPIが作成できます。

残念ながら、現在英語ですが、近々、日本語訳も公開予定です!


翻訳されたものがお望みでしたら、公開前の日本語訳はこちらからアクセスできます。

※ethereum.orgの翻訳ボランティアへの参加、お待ちしております。


4. UniswapV2ペアコントラクトのABI (Application Binary Interface) を取得

コントラクトのメソッドにアクセスするにはABIが必要になります。


$ curl -O https://unpkg.com/@uniswap/v2-core@1.0.0/build/IUniswapV2Pair.json



5. 指定した期間のETH/USDTの価格を取得し、JSONを出力するJavascriptコードの実装


以下では、現在から、一か月間(30日)を指定し、一日ごとのETH/USDTのペア価格を取得しています。

※ETHのタイムスタンプは秒ですので、プログラムで表示するにはミリ秒にする必要があることに留意して下さい

const fs = require('fs');
const EthDater = require('ethereum-block-by-date');
const themePath = '[テーマの出力先ディレクトリ]';
const Web3 = require('web3');
const UniswapV2Pair = require('[4.で取得したABIを配置したディレクトリ]/IUniswapV2Pair.json');
const web3 = new Web3('[3.で取得したInfuraやAlchemyのプロジェクトのURL]');
const pairAddress = '0x0d4a11d5eeaac28ec3f61d100daf4d40471f1852'; // ETH/USDTペアのUNISWAPのアドレス
const pairContract = new web3.eth.Contract(UniswapV2Pair.abi, pairAddress);
const dater = new EthDater(web3);



async function getDailyHistoricalPriceData(fromTimestamp, toTimestamp) {
    // 一日のミリ秒
    const oneDayInMilliSeconds = 86400000;
    const token0 = await pairContract.methods.token0().call();
    // const token1 = await pairContract.methods.token1().call();

    let result = []; // 結果を格納する配列
    let timestamp = fromTimestamp; 
    let ethReserve, usdtReserve;

    while (timestamp <= toTimestamp){
      var dateFormat = new Date(timestamp);

      console.log(`Output Price Date and Time: ${dateFormat.toISOString()}`)
      //日付でブロック情報を取得
      let block = await dater.getDate(dateFormat.toISOString(), true, false);

      console.log(`Block Number: ${block.block}`);

      const reserves = await pairContract.methods.getReserves().call(block.block);


      if (token0.toLowerCase() === '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2') { // WETHのアドレス
        ethReserve = reserves[0] ? reserves[0] : reserves;
        usdtReserve = reserves[1] ? reserves[1] : reserves;
      } else {
        ethReserve = reserves[1] ? reserves[1] : reserves;
        usdtReserve = reserves[0] ? reserves[0] : reserves;
      }


      const ethPrice = ((usdtReserve) / (ethReserve) ) * (10 ** 12);

      const latestEthUsdt = {"USDT":ethPrice.toFixed(2)}

      console.log(`${dateFormat.toISOString()} ETH/USDT price on Uniswap: ${ethPrice.toFixed(2)}`);
      result.push(  //timeをミリ秒に修正
            {
                time: block.timestamp * 1000, 
                price: ethPrice.toFixed(2),
                symbol: 'ETH/USDT',
                blockNumber: block.block,
            }
      );
      timestamp += oneDayInMilliSeconds;

    }
    const historyData = {'Data': result}
    console.log(historyData);
    fs.writeFile( themePath + 'EthUsdtHistory.json', JSON.stringify(historyData), (err, data) => {
            if(err) console.log(err);
            else console.log('write end');
    });
}

// 一か月前の時間の取得から
const fromTimestamp = Date.now() - 2592000000;
// 現在までを取得
const toTimestamp = Date.now();

getDailyHistoricalPriceData(fromTimestamp, toTimestamp);


UNISWAP V2 APIに関して、ethereum.orgのわかりやすい記事があります。

こちらで、計算にて価格が取得できる理由が解説されています。

残念ながら、現在英語ですが、近々、日本語訳も公開予定です!


翻訳されたものがお望みでしたら、公開前の日本語訳はこちらからアクセスできます。

※再度となりますが、ethereum.orgの翻訳ボランティアへの参加、お待ちしております。





6. cronで定期実行

ConohaWINGでは、cronのようなものが使えます。


cronを開き、ジョブをスケジュールします。


日付ごとのデータですが、ETHは基本、値動きが大きいため1時間に1回ジョブを実行することにしました。

※お好みの頻度で取得してください

$ crontab -e
0 * * * * PATH="$PATH:/home/$USER/[Node.jsインストール先]/share/nodejs/node-v14.13.1-linux-x64/bin" node ~/getHistoryEthUsdtPair.js





7. 動作確認


WordPressで出力されたJSONを取り込み、表示するプログラムを実装します。

これにより1か月分のETH/USDTの価格履歴をインターネットを通してJSONで取得できます。


以下にて、JSONを公開してますので一時間ごとに最新価格が更新されていることを確認ください。



また、サンプルとして当ホームページのトップページの2段目のグラフセクションに1か月分のETH/USDTの価格履歴を表示する折れ線グラフのガジェットを実装しています。

ご覧いただけますと幸いです。




まとめ

国内最速激安ConohaWINGレンタルサーバ(月1000円程度)にて、指定した期間のETH/USDTの価格履歴を取得する簡単なJSON APIを実装することが出来ました。

トレードの分野では、トラストレスに価格履歴を取得する必要がありますが、このような方法で実現可能です。

※AlchemyやInfuraなどのクラウドのブロックチェーンではなく、自分のノードを持っていればよりベストだと思います

また、制限の多い公開ノードを使うことなく、安定しており、比較的トラストレスなInfuraやAlchemyなどのブロックチェーン・アズ・ア・サービスを無料枠内で活用しました。

この実装の場合、(Infuraのダッシュボードを見ると)、一日でも、約4,000~5,000リクエストです。

Infuraの場合の無料枠は、上限100,000/日ですので、まだまだ無料枠を使って他の機能が実装が可能です。

最後に、ConohaWINGの契約をしたい場合は、当リンクから申し込みいただけますと幸いです


また、コードで不明な点や、改善点があれば、ご指摘いただけますと大変ありがたく存じます。


ここまで読んでくださり、ありがとうございました。




コメント投稿フォーム

メールアドレスが公開されることはありません。 が付いている欄は必須項目です