寿司と雲丹で和風三角アービトラージ ~フラッシュローンを添えて~

Yuya Sugano
17 min readJan 25, 2021

--

※寿司=SushiSwap、雲丹=UniswapV2のことです、あしからず

アービトラージの機会を発見するNode.jsスクリプトとフラッシュローンを使ったアービトラージの執行を試みましたが、結論からいうと様々な要因により結果がでませんでした。DEX Aggregatorである1inchで発見されるパスがほぼUniswapであることからアービトラージ双方向の取引が単一のDEXで行われている状態です。今回は別のDEXで別のプールを経由するアービトラージで三角アービトラージを試みてみようと思います。DEXはUniswapV2(雲丹)とそのフォークであるSushiSwap(寿司)を採択します。理由はSushiSwapがUniswapのフォークでsdkやコントラクトのインターフェースが同じために開発が楽だからです。フラッシュローンの開発とメインネットでのテストには前回ご紹介したBrownieという統合フレームワークを使っていきます。[1]

Disclaimer

This article is not either an investment advice or a recommendation or solicitation to buy or sell any investment and should not be used in the evaluation of the merits of making any investment decision. It should not be relied upon for accounting, legal or tax advice or investment recommendations. The contents reflected herein are subject to change without being updated.

Sushi balls Image by Tonda Tran from Pixabay

Repository

  • DEXの選択について
  • 三角アービトラージについて
  • アービトラージ裁定スクリプト
  • Brownieフラッシュローンテスト

DEXの選択について

1inchのようなDEX Aggregatorを使用すると最適なDEXと経路を選択して、トークンスワップを行うことができます。1inchでアービトラージの裁定機会を判定するスクリプトを走らせた結果ほとんどがUniswapV2をDEXとしたトークン取引であることが判明しました。単一のDEXのアービトラージ取引では同じ流動性プールの行き帰りだけとなるので先のトークンスワップによって流動性プールのトークン比率が変わりレートに影響を及ぼしてしまう可能性があります(というか同じ流動性プールの取引)。

そこでレートの参照や影響が相互になくかつフラッシュローンの流動性に耐えられる大きなプールを持つ複数のDEXを選択する必要があると考えました。基本的には雲丹と寿司という選択になると思います。あとはKyberSwapですね。ステーブルコイン系のスワップを絡めるのであればCurve Financeのプールも検討できます。雲丹は3000億、寿司も2000億ほどのUSD建てTVLがありその規模はどんどんと拡大しています。

https://defipulse.com/

三角アービトラージについて

単一のDEXの流動性プールへ頼るのを止めることに加えて、三角アービトラージ(トライアングルアービトラージ)で複数DEXという形でやってみます。三角アービトラージとは交換所(ここではDEX)のレートが交換所間で一致しない場合に、3つのトークン間で発生するレート差を利用して行うアービトラージのことです。Investopiaの説明を見ると分かりやすいのですが、例えばUSD 1,000,000をEUR 863,100へ交換し、EUR 863,100を591,164.40 GBPへ交換、最後に591,164.40 GBPをUSD 1,001,373へ交換すると$1,373のプロフィットが発生する、というようなアービトラージ取引です。下のイメージ図を参照のこと。[2]

Triangular arbitrage is the result of a discrepancy between three foreign currencies that occurs when the currency’s exchange rates do not exactly match up. These opportunities are rare and traders who take advantage of them usually have advanced computer equipment and/or programs to automate the process. — Triangular Arbitrage Definition

https://www.investopedia.com/terms/t/triangulararbitrage.asp

三角アービトラージのDeFi DEXでの取引例を考えてみます。ここで始まりのトークンWETHと最後に売り抜けるトークンWETHを一致させる必要があります。なぜなら今回はフラッシュローンを添えて大量の流動性を確保するにあたり、貸借したトークンで手数料(2 wei)とともにプロバイダ(dYdX)へトークンを返却する必要があるからです。またここで1.と3.のDEXは一致していてもよいはずです。以下の例では1. WETH/DAIと3. WETH/LINKの流動性プールは別プールなので同じDEX上であっても非対称性が発生している可能性があります。

  1. 雲丹でWETHを売りDAIを買う(Sell WETH for DAI at Uniswap)
  2. 寿司でDAIを売りLINKを買う(Sell DAI for LINK at Sushiswap)
  3. 雲丹でLINKを売りWETHを買う(Sell LINK for WETH at Uniswap)

Arbitrage Takeaways for future improvements ~

  • An automated trading platform should be set to identify an opportunity and act on it before it disappears
    -> アービトラージの機会を認識してからトランザクションを送信するまでのタイムラグを最小とする、レイテンシを低く抑える工夫
    -> Latency and lagging should be minimized between an arbitrage opportunity is recognized and a transaction is sent to the network
  • To ensure profits, such trades should be performed quickly and should be large in size
    -> スクリプトの処理速度を最小化する、フラッシュローンを利用することで大量の流動性を確保する
    -> an efficient coding is neccesary to process fast, a flashloan is a realistic way to prepare a vast amount of liquidity
  • To transactions in such trades should be tolerable for front-running transactions in a mempool when they are confirmed in EVM
    -> ガスコストを追加してトランザクションのプライオリティを上げる
    -> Increase a gasCost when sending a transaction and it coculd be prioritized in a mempool of network

The code and document in this article do not aim to fulfill the takeaways and cope with the concerns above however those requirements must be met if you consider running a profitable arbitrage script as a professional trader or a financial institute. Please note that this is experimental and still in infancy for a private and individual use.

アービトラージ裁定スクリプト

簡単な処理フローを示します。取り扱うトークンはいつでも変更ができるようにします。前回のアービトラージと流れは同じでアービトラージ部分が1inchを使った双方向のものから寿司と雲丹のDEXを跨いだ三角アービトラージに変わっているだけとなります。前回と異なるアービトラージの部分だけコードを説明しておきます。すべての処理について説明は書いていません。コードだけ晒せ!という方はぜひリポジトリをご覧くださいませ。コメントは残しています。[3]

  1. 雲丹でWETHを売りDAIを買う(Sell WETH for DAI at Uniswap)
  2. 寿司でDAIを売りLINKを買う(Sell DAI for LINK at Sushiswap)
  3. 雲丹でLINKを売りWETHを買う(Sell LINK for WETH at Uniswap)
  4. 買ったWETHと売ったWETHの差額を計算
  5. 差額からトランザクションコストを減算、ガスコスト上乗せ
  6. 正であればフラッシュローンのコントラクトを呼び出す
  7. 上記 1–6 を繰り返していく

abiとコントラクトアドレスを使った呼び出しは使用せずにSushiswapとUniswapから提供されているsdkを使用しました。プロジェクトの初期準備は以下のインストレーションの通りです。sdkのバージョンを双方ともに3.0.0にしているのはSushiswap側はsdkの新しいバージョンがメンテされていないためです。ちなみにSushiswapのnpmパッケージ提供ページを見ると、詳しいドキュメントはuniswap.orgを見てねんと書いてある。本当この人たち楽しすぎですね 笑

$ brownie init
$ npm init -y
$ npm install web3
$ npm install dotenv
$ npm install bignumber.js
$ npm install @uniswap/sdk@3.0.0
$ npm install @sushiswap/sdk@3.0.0
$ npm install @studydefi/money-legos
$ npm install @truffle/hdwallet-provider

Uniswap公式のJavascript SDKのページを元に各エンティティをrequireして読み込んでおきます。使用したエンティティはChainId/Token/Fetcher/Trade/Route/TradeAmount/TradeTypeです。寿司と雲丹の違いはパッケージ内のRouterやFactoryのコントラクトアドレスぐらいしかないと思うのですが一応両方とも別の名前で初期化しました。寿司系はsを頭へ付与し、雲丹系はuを頭へ付けています。

寿司と雲丹でトークンを取り扱うためにTokenの定義がトークンごとに必要です。ネットワークID、ERC20トークンのスマートコントラクトのアドレスおよびデシマルからTokenを定義できます。が、Fetcherエンティティに Fetcher.fetchTokenData という便利な関数が存在します。サンプルに倣ってコントラクトアドレスから自動的にTokenを取得しました。Fetcherはこのトークンデータのフェッチとトークンペアのフェッチも行うことができます。各トークンは念のため寿司と雲丹で両方とも用意しました。[4]

次に寿司と雲丹で三角取引するトークンの3種類 A B C とその経路を定義します。

経路 A -> B -> C は例えば WETH -> DAI -> LINK となります。最後にLINKを売ってWETHを買います。このとき WETH -> DAI と LINK -> WETH には直接スワップできる経路がありますが、DAI -> LINK には直接経路がなくIndirectな取引になります。DAI -> LINK の経路のために2つの経路 DAI -> WETH と WETH -> LINK を連結することでスワップを指示する必要があります。

経路の定義は7つのトークンを順番に定義しています。WETH -> DAI には uWeth, uDAI、DAI -> LINK には sDai, sWeth, sLink、LINK -> WETH には uLink, uWeth がそれぞれ対応します。DAI -> LINK は前述のとおりIndirectスワップなので3種類記載します。ここはもっと効率的な処理の仕方があると思いますが、とりあえずこれで行きます。

ここまでで事前の準備が完了です。例えば 1.の雲丹でWETHを売りDAIを買う(Sell WETH for DAI at Uniswap)の処理は以下のように書けます。スクリプトを走らせるとコンソール上にスワップ情報がでてきます。画像では雲丹で100 WETHを116,816 DAIへ交換し、寿司で116,816 DAIを5882.795352 LINKへ交換、さらに雲丹で5882.795352 LINKを97.7861774590848 WETHへ交換できると表示されています。つまりこのブロック高にアービトラージの機会はないということですね。

Japanese Triangular Arbitrage with Uni & Sushi

最後に買ったWETHから最初に売ったWETHを引いてプラスとなっていたときにフラッシュローンを発火するトランザクションを作成するのみです。というわけで次はフラッシュローンのコントラクトを作成してBrownieでそのコントラクトが動作するかを確認します。前回の記事のように実際のメインネットをフォークしてテストしてみたいと思います。

最新のtest.jsのコンソール表示

Brownieフラッシュローンテスト

このスマートコントラクトはそれほど難しいものではありません。money-legosいうDeFiプロトコルを使用したアプリケーションの開発を助けてくれるライブラリを引き続き使用します。dYdXのフラッシュローンを実行してその中で三角アービトラージを行う処理を記述していきます。アービトラージのロジックを書く callFunction の部分は以下のようになりました。

メインネットを別コンソールでフォークして initiateFlashLoan を呼び出すテストケースを実行するとタイムアウトしてしまいます。フラッシュローンのコントラクトがおかしいのかよく分からなかったので、今度は brownie console で手打ちでもテストしてみました。エラーは『Uniswap V2: LOCKED』でこれは雲丹のReentrancy対策ganache-cliのフォークに関するエラーのいずれかではないかとのこと。

brownie console test

試しにFlashloan.solをコピーしてダミーのFlashloan2.solを作成しました。このコントラクトは雲丹で交換をしたトークンを寿司で交換し直す2 wayにしてあります。テスト結果はAssertionErrorの発生で、『Uniswap V2: LOCKED』のエラーは発生しませんでした。Reentrancyで複数回のスワップ呼び出しを制限しているのかganache-cliのフォークに関する内部的なエラーかがはっきりしません。もしスマートコントラクトから雲丹もしくは寿司を複数回呼び出すことが制限されているとすると、三角のための第3のDEXを投入する必要がありそうです。

an expected assertion error

フォークではなくローカルのチェーンへ全ての必要なコントラクトをデプロイすればエラーは出ない、という記述もありました。Reentrancy対策による呼び出し制限のようなドキュメントは見当たらなかったのでganache-cliでフォークした場合のエラーだと思いたいです。あとはスクリプトを常駐させることでアービトラージ機会を監視することができるようになります。以上、基本的な三角アービトラージの手法を把握できました。リポジトリにコードを上げています。

https://github.com/yuyasugano/sushi-uni-arbitrage

まとめ

  • 三角アービトラージ(トライアングルアービトラージ)とは交換所(DEX)のレートが交換所間で一致しない場合に、3つの通貨間で発生するレート差を利用して行うアービトラージのことである
  • DeFiのDEXにおいて雲丹(Uniswap)や寿司(Sushiswap)を中心としてKyberSwapやCurve FinanceをDEXの対象として検討できる
  • Node.jsとSolidityによる開発で寿司と雲丹をつかったアービトラージの常駐用スクリプトとスマートコントラクトを開発できた(仮)
  • BrownieはPythonベースのスマートコントラクト統合開発ツールである

--

--

Yuya Sugano
Yuya Sugano

Written by Yuya Sugano

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

No responses yet