Blocknative with Flashbotsで mempoolと戯れる #1

Yuya Sugano
41 min readDec 6, 2022

MEV(旧 Miner Extractable Value、現 Maximal Extractable Value)はEthereumなどのブロックチェーンで主にマイナーがトランザクションを任意に含めたり、除外したり、並べ替えたりすることを通じて得られる利益とされています。Flashbotsの登場でSearchersはトランザクションの入札を直接マイナーへ支払うことができるようになりました。

BlocknativeのmempoolエクスプローラによってSearchersは、オンチェーンとして確定する以前の状態をmempoolから確認することができるようになります。Flashbots Auctionと組み合わせることで、アービトラージなどのトランザクションをmempoolの情報と統合してMEV Relayersへ送出することができるようになりました。本記事ではまずBlocknativeのエクスプローラからmempoolを確認します。

次にBlocknative’s mempool APIやSDKを活用してアービトラージの機会を検出するようなスクリプトの作成を検討します。Blocknative’s mempool APIflashbots private relayを利用したアービトラージのスマートコントラクトの例は以降の記事でリサーチおよび疑似コードの作成をすることとしたいと思います。※本記事はEthereumブロックチェーンやMEVに関する前提知識を必要とします

flashbots with blocknative

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. This article was written for educational and entertaining purpose only.

目次

  • MEVとFlashbots
  • Mempoolを見ることの意味
  • Mempoolエクスプローラを見る
  • Mempool SDKでアービトラージ

MEVとFlashbots

通常のEthereumのトランザクションプールでは、ユーザはトランザクションをブロックチェーンのネットワークにブロードキャストし、実行したいトランザクションに対して支払うガス価格を指定します。マイナーは受け取ったトランザクションを集め、ガス価格順などでオーダーを並び替え、トランザクション手数料を最大化しようとするブロックを作成します。このメカニズムはEnglish auctionall-pay auctionの中間であると説明されており、3つの問題点があると説明されています。[1]

※Flashbots AlphaからFlashbots Auctionへ名前が変更されています。

  1. 通常のトランザクションプールのオープンな性質は、トランザクションのオーダリングの入札バトルを引き起こし、ネットワークの輻輳やガス価格の変動の原因となります。これは洗練されていないネットワーク参加者に不利益をもたらす可能性があります。
  2. all-pay auctionの性質から失敗したビッドはチェーン上でリバートされます。これは不必要なブロックスペースの消費を発生させ、実行リスクのため入札者が入札の価格を低くし、最終的には人為的なブロックスペースの不足とマイナーのリワードの減少につながります。
  3. ガス価格に依存しているため、入札者はブロックの最上位のオーダーに制限され、きめ細かい注文設定を実現できません。このことによって、入札に勝つ可能性を高めるためスパムなどの代替の戦略が行われ、デットウェイト損失がさらに増加し​​ます。

Flashbots Auctionは、上記のようなメカニズムではなく first-price sealed-bid auction を採用しています。ユーザはビッドに失敗した場合に手数料を支払う必要がなく、入札内容と取引注文の詳細をプライベートな通信チャネルで伝えることができます。このメカニズムによってマイナーのペイオフを最大化できると同時に、特定のMEVの価値に関する価格発見のための効率的な機会を提供することができるようになりました。[2]

Flashbots AuctionによってSearchersはトランザクションを通常のEthereumネットワークにブロードキャストすることなく、MEV-geth(PoSへ移行後ではMEV-boost)へ送出することで内容をピアトゥピアネットワークから見えなくすることができます。手数料をマイナーの coinbase アドレスへ直接支払い、ガスの支払いを行わないように設定できるため、これによりトランザクションの成功を条件としてやり取りを行うことができるため、失敗した入札に対して支払う必要もなくなります。

Flashbots AuctionやFlashbotsのサービスの目的はMEVを民主化しオープンにすることでした。MEVは大規模なハッシュレートにアクセスできる一部のダークプールに限定されていたり、大口トレーダーと一部マイナー間の一方的なオフチェーンの取引を通じて、少数のプレーヤーに集中化されてます。MEVを民主化することで、パーミッションレス・分散性という特性を侵害せずにプレイヤーは低レベルな金融プリミティブに平等にアクセスできるようになります。

参考文献 [3]

Mempoolを見ることの意味

Flashbotsを利用することでMEVを活用したアービトラージと通常のDapps利用および送金のトランザクションは分離され、結果としてマイナー手数料は最適化されると同時にガス価格は安定してきます。アービトラージのトランザクションは通常のノードへ送出されず、プライベートネットワーク経由でマイナーの coinbase アドレスへ直接届けられます。

ユーザとしては以下のようなケースでFlashbotsを利用する可能性があると紹介されています。

  1. アービトラージやリクイデーションボットなどの用途でブロックスペースへ早くまたリスクフリーなアクセスが必要となるようなケース(典型的なボットのユースケース)
  2. 送出するトランザクションにおいてフロントランニングに対する防衛が必要なケース(UniswapなどのDEXのアドバンスドなユーザ)
  3. Dappsにおけるアカウントアブストラクションやガスレストランザクション等の発展的なユースケース

FlashbotsのMediumのパブリケーションに、Flashbotsのインフラを使用したMEV抽出やアービトラージの実際のトランザクションが紹介されています。またFlashbotsを使用した高額な手数料のトランザクションはこのTwitter Botで情報収集できるのでフォローしておくと便利です。以下の例では101.112 ETHものトランザクション手数料をマイナーへ直接支払っています。

2021年の3月30日にUniswap V2に上場した$MARSHの流動性提供を検知して大量購入し、売り抜けることで利益を上げたトランザクションです。ボットで新規の流動性供給を監視および検知できるようにしていたものと考えられます。250 WETHで$MARSHを購入し、それらを売却することで莫大な利益を上げています。トランザクション手数料は0 Ethでマイナーへ直接101.112 ETHを送金しています。これが今現在最も高額なマイナーへの直接支払いのようです。

The most expensive tip to a miner

Flashbots AuctionによってMEVへのアクセスができるようになるわけですが、依然としてアービトラージなどの裁定取引には情報の非対称性による一部のユーザの優位性が残っています。それがmempoolへのアクセスです。プロフィッタブルなアービトラージのトランザクションを成功させるには 1) トランザクションをより早く、もしくはノード近傍から送出、2) アービトラージの機会をいち早く検出、の両方もしくは片方を最適化していくことが基本となってきます。

mempool(gethではトランザクションプールの呼称)へのアクセスが可能となることで既にステートとして確定しているオンチェーンデータではなく、ペンディングトランザクションなどインザフライの情報をもとにアービトラージの機会を探ることができるようになります。よってアービトラージの機会を早く検出することができ、フロントランニングやバックランニングの成功確率がより高まります。

MEVによって利益を得たいSearchersにとってはmempoolへのアクセスが死活問題です。mempoolは各マイナーのインメモリに滞留しているものなので、マイナーおよび一部の特権的なユーザしか従来はアクセスすることができませんでした。BlocknativeはmempoolエクスプローラやAPI、SDK等を開発し一般のユーザが簡単にmempoolの情報へアクセスできるようなインフラを提供しています。[5]

Blocknativeの主なサービスの一覧です。

mempoolは各ノードのインメモリ内に存在する情報であるため、世界中のノードそれぞれが別の情報を持っています。ブロックとしてトランザクションが確定するまで、ノードの設定(ガス設定やmempoolのサイズ制限など)によってmempoolの内容はおのおの異なっている状態です。あるノードがピアへトランザクションを送出する際にもそれらのトランザクションは置きかえられたり、キャンセルされたりする可能性が存在します。

BlocknativeはEthereum、Binance、xDai、Bitcoinなどのノードのグローバル ネットワークを運用することで、新しいトランザクションを発生起点の近くで検出することができ、グローバルピアツーピアネットワーク全体での情報伝播を監視します。さらには様々なクライアントタイプ、複数の設定などクライアントノードの多様性を持たせることでグローバルなmempoolの条件として正確な視点を提供できるように努めているとのことです。[6] [7]

Mempoolエクスプローラを見る

Blocknative Mempool Explorerは数万から数十万あるといわれるmempoolのトランザクションに関するインサイトを提供することが可能です。またその3倍から5倍の数存在すると言われているスマートコントラクト間のやり取りとある内部トランザクション(Internal Transactions)もその対象に含まれます。

Mempoolエクスプローラは、Blocknativeのグローバルインフラによるリアルタイムなトランザクションデータフィードを提供します。特定のウォレットやスマートコントラクトアドレスをサブスクライブするだけでイベントをフィルターすることができ、トレードやDappsに必要なデータだけフィードすることが可能です。[8]

Mempool Explorer

まずはmempoolエクスプローラをブラウザで見て、どのようなデータフィードが取得できるかおよびフィルターできるかを見てみましょう。Mempool Explorerへアクセスして、サインアップします。ログインするとサブスクライブの設定を行うことができる画面へ遷移します。

以下がmempoolエクスプローラのデフォルトのUIで、ネットワークはEtehereumメインネットに設定されています。Watch top DEXes for pending transactionsをクリックしてライブサンプルを見てみました。イベントは最大50個まで出て停止します。

Mempool Default View Ethereum Mainnet

最後の50個目に出力されたトランザクションを見てみます。ステータスはpendingでUniswap V3: Router 2のコントラクトの呼び出しであることが分かります。"2022-11-03T07:22:39.258Z" がpending時点でのタイムスタンプ、Etherscan上でオンチェーンとなったトランザクションを見るとタイムスタンプは Nov-03-2022 07:22:47 AM + UTC となっていることから、pending状態であったトランザクションが8秒後にはオンチェーンに取り込まれて記録されていることが読み取れます(Etherscanの記録時間)。

※出力の長いフィールドは内容を省略しています

{
"status": "pending",
"monitorId": "nethermind_1_a1_prod",
"monitorVersion": "0.117.1",
"pendingTimeStamp": "2022-11-03T07:22:39.258Z",
"pendingBlockNumber": 15887979,
"hash": "0x03d8f2f8023226bf0ed010b176eaec3347af230890483aacf97410256893245b",
"from": "0x4871de2F75464A6cf57463601b2F1F4e90dC2E6A",
"to": "0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45",
"value": "0",
"gas": 266881,
"nonce": 148,
"blockHash": null,
"blockNumber": null,
"v": "0x1",
"r": "0xc76b98f7e5b63018606a911d925f5f78977fda2abb0bed5bdd7fa50b433573fd",
"s": "0xc31238e7dafafef4ae647a0d372241366c332ce48c98136188b8ca18314ae62",
"input": "0x<xxx>",
"type": 2,
"maxFeePerGas": "21004227538",
"maxFeePerGasGwei": 21,
"maxPriorityFeePerGas": "1500000000",
"maxPriorityFeePerGasGwei": 1.5,
"transactionIndex": null,
"asset": "",
"estimatedBlocksUntilConfirmed": 1,
"watchedAddress": "0x68b3465833fb72a70ecdf485e0e4c7bd8665fc45",
"direction": "incoming",
"counterparty": "0x4871de2F75464A6cf57463601b2F1F4e90dC2E6A",
"serverVersion": "0.151.4",
"eventCode": "txPool",
"timeStamp": "2022-11-03T07:22:39.258Z",
"dispatchTimestamp": "2022-11-03T07:22:39.331Z",
"system": "ethereum",
"network": "main",
"contractCall": {
"contractType": "multicall",
"contractAddress": "0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45",
"methodName": "multicall",
"params": {
"deadline": "1667461931",
"data": [
"0x<xxx>",
"0x<xxx>"
]
},
"subCalls": [
{
"data": {
"methodName": "swapExactTokensForTokens",
"params": {
"amountIn": "7917217719057997015383",
"amountOutMin": "255484197500943703",
"path": [
"0xe4815AE53B124e7263F08dcDBBB757d41Ed658c6",
"0xdAC17F958D2ee523a2206206994597C13D831ec7",
"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
],
"to": "0x0000000000000000000000000000000000000002"
}
},
"contractType": "Uniswap V3: Router 2"
},
{
"data": {
"methodName": "unwrapWETH9",
"params": {
"amountMinimum": "255484197500943703",
"recipient": "0x4871de2F75464A6cf57463601b2F1F4e90dC2E6A"
}
},
"contractType": "Uniswap V3: Router 2"
}
]
}
}
Transaction in Etherscan

新規のサブスクリプションの作成は対象となるウォレットやコントラクトアドレスを入力するだけです。Subscription Filtersで特定のフィールドの条件によるフィルタを、Subscription Selectsを使用してフィルターしたイベントの特定のフィールドのみを表示できます。またMempoolエクスプローラはカスタムコントラクトABIをサポートしているため、トランザクション入力をオンザフライでデコードおよびフィルタリングすることができるように設定できます。

以下の画像の例はUniswap Auto Routerのコントラクトアドレスに対するイベントに対して、statusがpendingのイベントのみをフィルタしstatus、timestamp、hash、contractCall.methodName、contractCall.contractType、contractCall.subCalls.data.methodNameのみをストリームに表示するように設定しています。SaveをクリックするとDefault API Keyを使用してサブスクリプションが保存されます。

mempoolエクスプローラのストリームはwebhookを使用することで、任意のフロントエンドやバックエンドのインフラへ送出することができます。シンプルな用途としてSlackチャンネルやDiscordサーバ、またTelegramへ情報を連携することができます。簡単なモニタリング用途であればこの機能で十分でしょう。

カスタムABIの統合方法やwebhookの使用方法はYouTubeで説明されています。アカウントページのDefault API Keyや追加した別のAPI Keyにwebhookの設定を行うだけでフィルタしたストリームをSlackチャンネルなどへ流すことができます。Mempool APIを使用するとwebhookの操作・設定をAPI経由で実行可能です。[9]

Mempool Explorer [#1] — Walk Through & Quickstart (Updated MPEX UI)

Mempool Explorer [#2] — How To Work With Custom ABIs

Mempool Explorer [#3] — Composability Via Webhooks

Mempool SDKでアービトラージ

Mempool Explorerでデータフィードを定義してリアルタイムにmempoolの情報を見ることができることが分かりました。またwebhookを利用してデータフィードを受け取ることができることが分かりました。本章では、Mempoolエクスプローラで設定したAPI KeyをエクスポートしてMempool SDKで使用してみたいと思います。

具体的にはmempoolのデータをフィルターし、ペンディングトランザクションの情報を統合することでFlashbotsを使用したアービトラージ戦略を実行できそうか検討します。まずはMempoolエクスプローラのAccountからAdd new API keyをクリックして新規のAPI Keyを作成します。次にこのAPI Keyにサブスクリプションを設定します。

Account

mempoolで監視するトランザクションはUniswapなどAMMの流動性プールのバランスの変化としましょう。ある流動性プールAにおいてトークンAからトークンBのスワップが発生するとき、他のDEXの流動性プールB(同じトークンペア)ではこの価格影響を受けていないと仮定します。このスワップが次のブロックで取り込まれるとき、トークンAは流動性プールAでは安くなるためトークンAを流動性プールBでトークンBへとスワップして、流動性プールAで交換したトークンBをトークンAへとスワップする戦略が成り立ち得ます。

mempoolである流動性プールAにおけるトークンAからトークンBへのスワップのトランザクションを検知することができれば、次のブロックでこのトランザクションが取り込まれるときと同時に上記のようなプロフィッタブルなアービトラージのトランザクションを同じブロック高でMEV RelayersへFlashbots Bundleとして送出できます。※ここでは流動性プールでのスリッページや手数料は考慮していません、よって現実的に成り立つような戦略とは限らないことをご了承ください

次に具体的にどのスマートコントラクトをサブスクライブして、どのようなデータフィードをモニタリングするかを検討しましょう。まずUniswap Auto Router、SushiSwap Routerのスマートコントラクトをサブスクライブして、Global Filtersでpending-simulationを設定します。

EthereumメインネットのUniswap Auto RouterやSushiSwap RouterではSimulated Eventsがサポートされます。pending-simulationをフィルターすることで対象のスマートコントラクトと内部トランザクションによる現時点のブロックハイトへの効果をシミュ―レーションした結果を受け取ることができるようになります。

Simulated Eventsが検知できるBlocknative Simulation Platformについて説明を追加します。Simulation Platformはサブスクライブされているスマートコントラクトによる内部トランザクションの影響を可視化します。Blocknativeによって最適化されたEthereumノードによって内部トランザクションはトレースされ、以下の2つのルールによってシミュ―レーションの適格性が評価されます。[10] [11]

  1. トランザクションがスマートコントラクトへ送信され、内部トランザクションの発生する可能性があるか
  2. トランザクションに市場性があるかどうか(市場性のあるトランザクションは、次のブロックに入るのに競争力を持つガス価格を持つかどうかで評価されます)

上記の条件が満たされた場合に、Simulation Platformは保留中のシミュレーションされたペイロードをデータフィードに配信します。トランザクションがシミュレートされたブロックの高さは、pendingBlockNumberとしてペイロードに表示されます。

pending-simulationのステータスのトランザクションによって、サブスクライブしているペンディングトランザクションのコントラクトの呼び出しによって発生する内部トランザクションに関するペイロードがデータフィードに出力されます。

またサブスクライブしているアドレスが内部トランザクションの一部ではあるものの、ベースペイロードの from もしくは to のアドレスに一致しない場合にも当該ペイロードは internalTransactions の構造を含むことができます。

internalTransactions およびnetBalanceChanges のペイロードがpending-simulationのステータスのトランザクションでは出力されますが、今回注目したいのは netBalanceChanges のペイロードです。これは関連する内部トランザクションによるバランスの変化を補足することができます。

Uniswap Auto RouterやSushiSwap Routerに対するコントラクトコールによる内部トランザクションによって流動性プールのバランスも変化します。ペンディングトランザクションに対する netBalanceChanges ペイロードを監視することで現時点のブロック高から、mempoolに入っているスワップによる流動性プールのバランスの変化の予測をモニタリングできます。つまり次ブロックにおいて取り込まれる可能性があり、そのことによって発生するであろう流動性プールのバランス変化をペンディングブロック高において知ることができます。※ただしBlocknativeによって説明されるとおりシミュレーションは”speculative execution”、つまり推測的な実行です。トランザクションはオンチェーン上で初めて確定します

"netBalanceChanges": Object

netBalanceChangesのオブジェクトは内部トランザクションに関連する各アドレスに対するエントリの配列で成り立っています。以下のようなデータ構造です。具体的なpending-simulationの例を以下で見てみましょう。

"netBalanceChanges": [
{
"address": String,
"balanceChanges": [
{
"delta": String,
"asset": {
"contractAddress": String
"symbol": String,
"type": String
},
"breakdown": [
{
"amount": String,
"counterparty": String
},
...
]
}
]
},
...
]
HEX to WETH Swap

https://gist.github.com/yuyasugano/867d19f995c5fc8cb16d02106676c18d

上記のgistは以下のUniswap V3 Routerを使用したHEXからWETHへのスワップがpending-simulationとして検知されたJSONデータです。HEXというトークン 44145.92889310を0.973422865283299445 WETHへと交換しています。各コントラクト間の内部トランザクションは internalTransactions のペイロードにシミュレーションされています。 netBalanceChanges の配列は順番にHEX/WETHの流動性プール、Uniswap V3 Router、トランザクションの送信者、そしてWETHのコントラクトアドレスのバランス変化を表しています。

ここで注目したいのはHEX/WETHの流動性プールのバランス変化です。Uniswap V3 Router上でHEXからWETHへスワップされるとき、HEXは相対的にUniswap上で安くなるため、HEXをSushiSwapでWETHへスワップしUniswapでWETHからHEXへとスワップするトランザクションを次ブロック向けに送出することでHEXのアービトラージを狙うことができます。これはシミュレーション結果に基づくもので他のアクターよりも早い段階でこのアービトラージの機会に気が付くことができるはずです。

"netBalanceChanges": [
{
"address": "0x9e0905249ceefffb9605e034b534544684a58be6",
"balanceChanges": [
{
"delta": "-973422865283299445",
"asset": {
"type": "erc20",
"symbol": "WETH",
"contractAddress": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"
},
"breakdown": [
{
"counterparty": "0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45",
"amount": "-973422865283299445"
}
]
},
{
"delta": "4414592889310",
"asset": {
"type": "erc20",
"symbol": "HEX",
"contractAddress": "0x2b591e99afe9f32eaa6214f7b7629768c40eeb39"
},
"breakdown": [
{
"counterparty": "0x4065149108A615930114Bb511818fc0909AA9269",
"amount": "4414592889310"
}
]
}
]
},
{
"address": "0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45",
"balanceChanges": [
{
"delta": "973422865283299445",
"asset": {
"type": "erc20",
"symbol": "WETH",
"contractAddress": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"
},
"breakdown": [
{
"counterparty": "0x9e0905249ceefffb9605e034b534544684a58be6",
"amount": "973422865283299445"
}
]
}
]
},
{
"address": "0x4065149108A615930114Bb511818fc0909AA9269",
"balanceChanges": [
{
"delta": "-4414592889310",
"asset": {
"type": "erc20",
"symbol": "HEX",
"contractAddress": "0x2b591e99afe9f32eaa6214f7b7629768c40eeb39"
},
"breakdown": [
{
"counterparty": "0x9e0905249CeEFfFB9605E034b534544684A58BE6",
"amount": "-4414592889310"
}
]
},
{
"delta": "973422865283299445",
"asset": {
"type": "ether",
"symbol": "ETH"
},
"breakdown": [
{
"counterparty": "0x68b3465833fb72a70ecdf485e0e4c7bd8665fc45",
"amount": "973422865283299445"
}
]
}
]
},
{
"address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
"balanceChanges": [
{
"delta": "-973422865283299445",
"asset": {
"type": "ether",
"symbol": "ETH"
},
"breakdown": [
{
"counterparty": "0x68b3465833fb72a70ecdf485e0e4c7bd8665fc45",
"amount": "-973422865283299445"
}
]
}
]
}
]

netBalanceChangesペイロードにおける流動性プールのバランス変化の条件は以下のようにまとめることができると思います。簡単に表現すると netBalanceChanges の各要素の中でどれが流動性プールのものであるかを判別できれば良いということになるでしょう。

  • addresstransaction.fromtransaction.to と一致しない
  • netBalanceChanges.balanceChanges.length が2つである
  • netBalanceChanges.balanceChanges の2つの要素の asset.contractAddress が存在する(また contractAddressは実際のERC20のスマートコントラクトのアドレスである)

さらに今回モニタリングしているUniswap Auto Router、SushiSwap Routerのいずれかにおいて流動性プールのバランス変動を検知した際に、対向のAMMにおいても対象のトークンペアの流動性プールが存在するかを判別しなければなりません。

前述のmempoolエクスプローラで見たUniswap V3 Router上のHEXとWETHのスワップの場合、SushiSwap Routerを利用してアービトラージをしようとするとSushiSwapのAMM上にもHEX/WETHの流動性プールがあらかじめ存在していることが前提条件となります。

前置きが長くなりましたがこれからnode.jsのSDKを使用して上記の条件を満たすpending-simulationのステータスのトランザクションを抽出するスクリプトを書いていきます。mempoolエクスプローラでサブスクリプション設定ファイルおよびSDK設定ファイルをエクスポートして、SDKからイニシャライズできます。SDKのイニシャライズ方法は以下を参考にしました。

手順

  1. サブスクリプションの設定をmempoolエクスプローラで実施
  2. サブスクリプション設定ファイル(configuration.json)およびSDK設定ファイル(sdk-setup.js)をエクスポート
  3. Mempool SDKとエクスポートしたファイルを使用してコーディング

まずMempoolエクスプローラからUniswap Auto RouterとSushiSwap Routerをサブスクライブして設定を新規に作成したAPI Keyに保存します。またグローバルフィルターにpending-simulationのステータスを追加しました。ここではBlocknative-MEVという名前のAPI Keyにサブスクリプションを保存しています。

mempoolエクスプローラの縦の3点ボタンを押下して、Export Configurationをクリックすると configuration.json sdk-setup.js をダウンロードすることができます。エクスポートしたファイルをMempool SDKで設定ファイルとして使用することで、簡単にフィルターしたイベントを取得するスクリプトを記述できます。

Subscribe Uniswap Auto Router and SushiSwap Router
Export configuration.json and sdk-setup.js

configuration.json sdk-setup.js をMempool SDKを使用するプロジェクト内で使用します。作成したスクリプト index.js はgithubへリポジトリとして内容をまとめました。実行するとコンソール上に以下のような結果が表示されます。USDC、USDTやETH/WETHなどの流動性ペアのスワップの結果と対向のAMMに存在する流動性プールのアドレスが表示されます。

https://github.com/yuyasugano/blocknative-mev [13]

$ node index.js
Transaction pending block at 15932172: counter party is 0xcc444e2Cf1a68255A6001fe0953a42A3c5361168
Index: 0, Address: 0xcc444e2Cf1a68255A6001fe0953a42A3c5361168
Index: 1, Address: 0xaf119546a2391F0D2d3deCb5eda6D54b75367380
Token USDC: -693197670, Token WETH: 573722685245977209
Liquidity Pool exists at 0x397FF1542f962076d0BFE58eA045FfA2d347ACa0

Transaction pending block at 15932172: counter party is 0x411693000cb076778097fE3A420e4B8C41FeBeDa
Index: 0, Address: 0x11b815efb8f581194ae79006d24e0d814b7697f6
Transaction pending block at 15932172: counter party is 0x395A74BB9d0Cd4DD4A7208dD5d4Eb8E9Ca92E75e
Index: 0, Address: 0x395A74BB9d0Cd4DD4A7208dD5d4Eb8E9Ca92E75e
Index: 1, Address: 0x7610301d5d6A56EdBDC353cF65fe6C30Ea091F00
Token USDT: -1210658042, Token ETH: 1000000000000000000
Liquidity Pool exists at 0x06da0fd433C1A5d7a4faa01111c044910A184553
...
Transaction pending block at 15932228: counter party is 0x8e36ba811cdd78f900022C0Fe195aa5278DDDFc0
Index: 0, Address: 0x9a772018fbd77fcd2d25657e5c547baff3fd7d16
Index: 1, Address: 0x8e36ba811cdd78f900022C0Fe195aa5278DDDFc0
Index: 2, Address: 0x7858e59e0c01ea06df3af3d20ac7b0003275d4bf
Token USDT: -988056836, Token USDC: 987705063
Liquidity Pool exists at 0xD86A120a06255Df8D4e2248aB04d4267E23aDfaA

bitFlyer Advent Calendar 2022の記事 #1 として、今回はここまでとします。目的としていたBlocknative’s mempool APIやSDKを活用してアービトラージの機会を検出するスクリプトを作成できました。記事が長くなったため flashbots private relayを利用したアービトラージのスマートコントラクトへの応用は次の記事でリサーチおよび疑似コードの作成として発行です。次はBlocknativeのFlashbotsに関する記事を参考にします。[14]

おわり

本記事ではMEVとFlashbotsについておさらいした後に、mempoolへのアクセスにアービトラージの発見の優位性が残っていること、アービトラージの機会を早く捉えるためにmempoolの情報、またBlocknativeのpending-simulationのトランザクション情報などが有益であることを確認しました。また実際にpending-simulationのステータスのトランザクションから、アービトラージの機会と考えられるような流動性プールのバランスの変化をオンチェーン確定に先んじて取得するスクリプトを作成しました。

FlashbotsによってMEVが民主化されたように、多くの人がBlocknativeのインフラを使用し始めるにつれて、Blocknativeを使用するボット内での競争・競合が激化してくる点に注意してください。すでにpending-simulationのトランザクションを見てアービトラージを行う単純なボットは賞味期限切れと見てよいでしょう。Blocknativeを利用してプロフィットを生み出すようなアービトラージを行うには現段階からもう一工夫必要かと思われます。

本記事が少しでも暗黒森林の探索のお役に立ちましたら幸いです。

--

--

Yuya Sugano

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