フラッシュローンで DEX アービトラージをやってみる — 自動化 —

DeFiプロトコルでフラッシュローンを行えるスマートコントラクトである『OrFeed』を昨年ご紹介しました。OrFeedは取引を行いたい複数のDEXを指定してTriangularアービトラージを指示できるスマートコントラクトです。OrFeedの弱点はトレードのトークンや指定できるDEXが限定されていることです。今回はNode.jsでアービトラージの裁定取引を監視しつつ、取引機会が訪れたときにフラッシュローンのコントラクトへトランザクションを投げるシステムを作成してみました。元ネタはこちらです。YouTuberの方の有料講座のコードベースですがコードは無料でgithubに公開されていました。ここでテストしているトークンはステーブルコインのみですが、自由にトークンを追加することで様々な取引機会を狙えると思います。本記事および公開されているコードは個人的な実験用であり、そのままで動作することおよびその利益については保証しておりませんのでご了承ください。

Image for post
Image for post
Image by Gerd Altmann from Pixabay

作るものです。1. から 2. を呼び出すことでアービトラージの機会があったときに秒速でトランザクションを作成して発行します。Node.jsスクリプトはforeverを使って常時動作する状態にしておきます。

フラッシュローン(Flashloan)については説明いたしません。ただ今回はTriangularアービトラージではなく単純なアービトラージを対象としているのでどのような状態をアービトラージの機会として補足しているか書き残しておきます。フラッシュローンはシングルトランザクションで裁定解消できるアービトラージしか対象とできません。裁定解消に時間差のあるような取引は難しいということになります。そこで単純に現物トークンでとある取引所の価格と他のある取引所での価格に乖離のある場合を考えます。

例をあげます。ETHを使ってUSDCの取引を行う場合、取引所Aで安く買えるUSDCを他の取引所Bでは買った価格より高く売れるということが起こり得ます。この時の価格差とレバレッジした資産の額がプロフィットへ影響します。フラッシュローンを活用することで売買資金の調達から複数取引所での売買を1つのトランザクションへ内包できるため最初の取引所Aで安く買えたが取引所Bで売れなかった等というリスクが低減されるメリットもあります。返済ができなければトランザクションがリバートするだけなので。

この単純なアービトラージの場合に2つの取引所があるときには2方向の売買を評価することができます。ETH -> USDC -> ETH と取引する場合は以下の通り。

いま現在多くのDEXがあるために、すべてのDEXにおけるトークンスワップの価格の組み合わせを網羅的に調査することは難しいと思いました。ただ1inchのようなDEX AggregatorであればそれぞれのDEXで価格差があるかどうかをベストプライスで把握することができます。つまりETHでUSDCを購入する場合のレートとその購入したUSDCでETHを買い戻すベストプライスを1inchは提示してくれます。市場に歪みがあるときには両方向のスワッピングルートは異なることが多く、購入と売却におけるDEXやディストリビューションがばらつきます。ディストリビューションについては過去記事である『1inch.exchangeでトークンスワップをやってみる — EthereumDev Tutorial — 』に書いてあります。今回は1inchを使ってスワップのレート計算をしてみました。

distributionはuint256型の配列で各DEXに対するスワップの比率が格納されています。より正確には各DEXというより各コントラクトのスワップに対する比率となり、例えばETHからDAIへの交換の44%はUniswap V1で56%はUniswap V2で行う、といった良いレートで交換が成立するコントラクトの使用比率を意味します。[1]

アービトラージ機会を発見する

元ネタのコードではKyberSwapとUniswapのレートを監視してその価格差からトランザクションコストを引くことで利益を計算しています。前述のとおりこの記事では1inchでトークンの行きのスワップ(例えば ETH -> USDC)と帰りのスワップ(同様に USDC -> ETH)のレートを計算してアービトラージの機会があるかどうかを判断します。USDT/ETH、USDC/ETH、DAI/ETHを試しに見てみましたがDAI/ETHでは少額ながらアービトラージの機会が発生しているようでした。以下の画像のような結果を出力するNode.jsスクリプトを作成します。

Image for post
Image for post
1inch buy and reverse strategy

コードの抜粋で説明します。まず fromToken にETHをセットし toToken にはUSDCのトークンのアドレスを格納します。 fromTokenDecimalstoTokenDecimals はスワップ後のトークンの桁のパディングに使います。USDCはデシマルが6と中途半端なので桁数を変更する必要があるためです。これらのトークンアドレスを使って1inchのスマートコントラクトへレートを照会します。

この箇所はETHから交換先のトークンへのスワップレートを取得する部分です。returnAmountでスワップされた後に受け取るトークン量が返されます。distributionはuint256型の配列で各DEXに対するスワップの比率が格納されています。distributionが0%以上の取引だけをループでコンソール表示しています。returnAmountは戻りのスワップへと渡す予定です。

returnAmountをスワップするトークンとして逆方向のレートを取得します。順方向のreturnAmountはUSDC建てのデシマル6で、逆方向のレートはETH建てのデシマル18で計算されており、これらをドル建てにした上でトランザクションコストを減算することでプロフィットを計算します。

oneSplitRates というjsonに購入するトークンとそれを売却した際のトークンをドル建て(USDC建て)で格納しました。売却分から購入分とトランザクションコストを減算したものを profit という変数に入れています。 profit がプラスのときにデプロイしたフラッシュローンのコントラクトを呼び出してこのスワップを実行します。

dYdXでフラッシュローンを実行する

厳密にはdYdXにフラッシュローンと呼ばれる機能はありません。dYdXではSoloMarginのスマートコントラクトでWithdraw -> Call -> Depositをシングルトランザクションで実行することでフラッシュローンと同等のトランザクションを発行できます。dYdXはETHはなくWETHのサポートなので、今回はWETHを引き出して1inchで取引を行った上でまたdYdXへデポジットするという流れです。[2]

Aaveは比較的易しかったのですが、dYdXのインターフェースやスマートコントラクトを理解するには敷居が高かったです。money-legosというDeFiプロトコルを使用したアプリケーションの開発を助けてくれるライブラリがあります。『money-legosでDeFiと戯れてみる』でも紹介した通りプロトコルのABI (Application Binary Interface)やアドレスを提供してくれていて、公式サイトにはサンプルのコードも用意されています。[3]

今回はmoney-legosを使用しました。EthereumDevで紹介されているKollateralというパッケージも良さそうです。KollateralはdYdXやAaveのフラッシュローンをラップするライブラリでめちゃ簡単にフラッシュローンを実行できるようでした。[4]

Image for post
Image for post
Kollateral

スマートコントラクトはSolidityで開発します。コードはmoney-legosdYdX Flashloan Logic (Solidity)をベースに書いています。その中でもアービトラージのロジックを書いている callFunction 部分だけ抜粋してみます。 _swap は1inchで行きと帰りのスワップを実行するinternal関数です。元のトークンからdYdXへデポジットする repayAmount を減算したものを beneficiary アドレスへ送金して終わりです。

あとは完成したスマートコントラクトをコンパイルしてデプロイするだけです。Remixからもデプロイしたコントラクトが見えることを確認できました。ちなみにメインネットへコントラクトを打ちましたがガスコスト110Gweiぐらいで通しましたww

Image for post
Image for post
Deployed contract for dYdX arbitrage

最後の最後にNode.jsのスクリプトを動かす環境ですがスクリプトのままサーバ上のforeverを使って動かしています。foreverはNode.jsアプリを常駐化してログなども吐いてくれるライブラリです。Herokuを使ったりクラウドのサーバレス化でも対応できますが、アプリ自体が軽量なので今回はこのままで。ただプライベートキーなどの情報をdotenvで読み込んでしまっているのでその点は改良の余地があると思います。

$ npm install -g forever
$ forever --version
v3.0.4
$ forever <your file name>.js
$ forever list

foreverでは標準出力は ~/.forever/ 配下にログとしてファイル保存されていくのでファイルから出力結果を確認することができます。Out of Gasでトランザクションがリバートされてしまうのですが、アービトラージの機会がときたまあることは確認ができました。

Image for post
Image for post
forever index.js.prod.js
-------------------------------------------------------------
New block received. Block # 11584634
GasLimit: 12445131 and Timestamp: 1609718326
Trading DAI ...
Forward Swap
Uniswap V2: 88%
Uniswap V2 USDC: 12%
Inverse Swap
Uniswap V2: 89%
Uniswap V2 USDC: 11%
1inch Exchange DAI/ETH:
{"buy":"956415.818342323740250171","sell":"959957.4809119636"}
transaction cost: 28.22516885680787
profit: 3513.437400783047
Arbitrage opportunity found!

今回のコードリポジトリは以下です。

https://github.com/yuyasugano/arbitrage-flashloan

まとめ

Written by

Blockchain Enthusiast, techflare.blog, Vinyl DJ, Backpacker. ブロックチェーン・クラウド(AWS/Azure)関連の記事をパブリッシュ。バックパッカーとしてユーラシア大陸を陸路横断するなど旅が趣味。https://twitter.com/SuganoYuya

Blockchain Enthusiast, techflare.blog, Vinyl DJ, Backpacker. ブロックチェーン・クラウド(AWS/Azure)関連の記事をパブリッシュ。バックパッカーとしてユーラシア大陸を陸路横断するなど旅が趣味。https://twitter.com/SuganoYuya

前回はChainlinkノードおよびOracleコントラクトをデプロイするところまで到達しました。この記事では自ノードでサポートするExternal Adaptersを開発してニッチプロバイダーを目指してみたいと思います。今回構築したChinlinkノードはメインネットへ配置しChainlink Marketでの認証も完了させました。一応世界中の誰でもこのChainlinkノードを使用できる状態になっています。この記事では追加作業として認証の必要なExternal Adaptersをラップしたサーバレスアプリケーションをノードへ接続してデータ提供できるようにします。外部のAPIから値を引くスマートコントラクトExternal Adaptersのテストは既に行ったので詳しくは触れません。

Image for post
Image for post
Image by Hans Braxmeier from Pixabay

目次で …


Part 1で暗号資産の終値、Disparity(終値と移動平均の比率)、リターンの比率、単純移動平均などをChainlinkのスマートコントラクトから取得できるAPIを開発しました。Part 2ではExternal AdaptersというChainlinkノードへ機能追加できるAPIラッパーを検証できました。ここまできたら自らノードを立ち上げて、構築したExternal Adaptersをサービスインするしかないでしょう(たぶんたぶん)。今回は前作成したAPIもより洗練させて多くの暗号資産を扱い、取得できる指標や時間足も増やして実用に耐え得るサービスを構築することを目指します。Chinlinkノードはメインネットへ構築します。すべてメインネットを使用していますのでコントラクトのデプロイや


Part 1ではChainlinkのオラクルノードとジョブIDによって簡単に外部APIからスマートコントラクトへデータ取得が行えることを確認できました。使用したHttpGetやJsonparthといった操作はコアアダプターと呼ばれておりChainlinkノードネイティブです。External Adaptersとはオラクルノードに追加できるオープンソースパッケージのようなもので他のブロックチェーンとの連携など多様なカスタムのアダプター追加を可能とします。例えばWeb APIの認証なんかもExternal Adaptersを追加することで可能だとのこと。今回はこのExternal Adaptersの概要と実際のアダプターのホスティング方法について見てみたいと思います。前回のWeb API作成と …


昨年の10月にChainlinkを使用してスマートコントラクトから仮想通貨のレートを取得するという内容の記事で、分散型のオラクルとして最も有名であると思われるChainlinkとConsensysの提供するSaaSサービスであるKaleidoをご紹介しました。今回は備忘録としてオラクルやChainlinkの復習および作成したWeb APIとExternal Adaptersを使用したスマートコントラクトからのデータ取得をやってみます。ChainlinkはLINKトークンが時価総額上位(現在、7位ぐらい)に入るなどして注目を集めましたが、オラクルとしてサービスを使用している企業やサービス提供を行っているユーザはまだ少なそうです。記事は2つに分けて前半でChainlinkのノードからデータをリ …


AWS Lambda Layersは2018年に発表された機能です。Lambda関数間で共通したライブラリやコンポーネントをZipファイルにまとめ他のLambdaから呼び出して使うことができるようになります。特にこれまで1つのLambda関数ではデプロイメントパッケージのサイズに上限があり、巨大なサイズのライブラリをLambdaへ持ち込むことが出来ませんでした。Lambda Layersによって必要なライブラリを細切れにしてLambda関数で使用することができます。この記事はAWS Lambda Layersに関する個人的な備忘録とPandasのライブラリを載せたレイヤーの作成方法を書いています。ちなみにデフォルトではNumpy/Scipyがパッケージされているレイヤーのみ提供されています