Web3アプリ「Universal Base」について
最近、自分が個人で開発した「Universal Base(リンク先参照)」の最初のバージョンをリリースしました。
当記事で、どのようなアプリか簡単に紹介させていただければと思います。
Uniswapについて
Uniswapは、最も人気のあるイーサリアムの分散型取引所(DEX)の一つです。
イーサリアムのネイティブトークンであるETHや、1ドルと等価なUSDC、USDT、DAIなど人気なステーブルコインから、SHIBやPEPEなどミームトークンなど、さまざまなトークンをスワップ(交換)することができます。
Uniswapの問題点
Uniswapを使うトレーダーは、一般的にUniswapのアプリを使ってトークンをスワップ(交換)します。
しかし、ブロックチェーンにおいて長所である取引の透明性については、その複雑な仕組みのため何が起こっているの分かりにくくなっています。
そのため、多くのトレーダーは、スワップが正しく行われたかについてはUniswapアプリを信頼するしかありません。
その主な理由としては、まずUniversal Routerというコントラクトを介してトークンがスワップされるのですが、その内容がエンコード(符号化)されていることがあげられます。
どのようにエンコードされてるかは、英語となりますが、「こちら」の本家のレファレンスをご覧ください。
Uniswap側の理由としては、このエンコードにより文字列が省略されガス代を抑えているという側面があるようです。
Universal Baseで解決したこと
以下にて解決したことを簡単に説明します。
取引データのデコード
まず、「uniswap-universal-decorder」というモジュールを作り、ほぼ全てのUniversal Routerのコマンドをデコードしています(一部のレアコマンドについてはデータがないためテスト未実施)。
これによって、誰でもイーサリアムノードを持っていれば、デコードできるようにしました。
例)デコード例
?デコード前のデータ
0x3593564c000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000006561d94f00000000000000000000000000000000000000000000000000000000000000040a01050c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000003a00000000000000000000000000000000000000000000000000000000000000160000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000ffffffffffffffffffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000658963f900000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fc91a3afd70395cd496c647d5a6cc9d4b2b7fad000000000000000000000000000000000000000000000000000000006561de0100000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000415f0511ba3fa712da37ec36ee9a253b62a633045c94307f1199fbbfbe5208e64e631a4964e505db3f74227bab7d03166084939b2e38ec7a312983cccee3a06fdf1c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000001bcc15e33d1b800000000000000000000000000000000000000000000000000000000000f97ce35a00000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc20001f4a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000037a8f295612602f2774d331e562be9e61b83a327000000000000000000000000000000000000000000000000000aa87bee538000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000001bc16d674ec80000
?デコードされたデータ
{
contents: [
{
command: '0a',
value: 'PERMIT2_PERMIT',
inputType: [
'tuple((address,uint160,uint48,uint48),address,uint256)',
'bytes'
],
decodedInput: [
[
[
'0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
1461501637330902918203684832716283019655932542975n,
1703502841n,
0n
],
'0x3fc91a3afd70395cd496c647d5a6cc9d4b2b7fad',
1700912641n
],
'0x5f0511ba3fa712da37ec36ee9a253b62a633045c94307f1199fbbfbe5208e64e631a4964e505db3f74227bab7d03166084939b2e38ec7a312983cccee3a06fdf1c'
]
},
{
command: '01',
value: 'V3_SWAP_EXACT_OUT',
inputType: [ 'address', 'uint256', 'uint256', 'bytes', 'bool' ],
decodedInput: [
'0x0000000000000000000000000000000000000002',
2003000000000000000n,
4185711450n,
[
'0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2',
500n,
'0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48'
],
true
]
},
{
command: '05',
value: 'TRANSFER',
inputType: [ 'address', 'address', 'uint256' ],
decodedInput: [
'0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2',
'0x37a8f295612602f2774d331e562be9e61b83a327',
3000000000000000n
]
},
{
command: '0c',
value: 'UNWRAP_WETH',
inputType: [ 'address', 'uint256' ],
decodedInput: [
'0x0000000000000000000000000000000000000001',
2000000000000000000n
]
}
],
deadline: 1700911439n
}
しかし、一般的なトレーダーがイーサリアムノードを立ち上げて、このモジュールで各自でデコードするには少し荷が思いため、誰もがアクセスできるようにシステム化も行いました。
オープンソースでUniswapのデコードデータを格納するDBシステムの提供
過去のデータから、現在のデータおよび、これからのデータ(トランザクションプールのデータ)がデータベースに格納されているとトレーダーは、その情報を取引に活かすことができます。
しかし、EtherscanやイーサリアムノードからUniswapのデータを抽出するのは、多くの人が面倒に感じるはずです。
トランザクションプールのデータも含み、GraphQLを使った問い合わせやDBへ格納する仕組みを「uniswap-universal-base」で提供しています。
こちらは、オープンソースで公開いているので誰でも平等に利用することができます。
有向グラフによるリアルタイム可視化
上記は、現在から過去にわたるUniswapの取引データを提供する基盤となっていますが、データはJSON型で保存されており、人間が確認するには、ややわかりにくいのは言うまでもありません。
そこでリアルタイムに有向グラフで可視化を行いました。
有向グラフとは、方向のある矢印でノード(図)とノード(図)をつなぎ合わせ直観的にわかりやすいグラフです。
以下では、有向グラフのリアルタイム可視化によって可能になったことを説明します。
トランザクションプールデータのブロックへの包含
ペンディングデータ(トランザクションプールにあるがブロックに含れていないデータ)がブロックに含まれることをリアルタイムで視認できます。
どのようなトランザクションプールのデータがブロックに含まれるかわかると、現在のガス代の把握等の確認に役立ちます。
※ブロックに包含されていないと、ブロックとトランザクション間に矢印(エッジ)がありません。また、blockNumberの箇所が「Pending」となります。
トランザクションの混雑状況
トランザクションが混み合っていると、あっという間にグラフデータが大量に増えていきます。
「混んでいる=ガス代が高い」ため、取引を控えることの判断にも使えます。
または、何らかのトレードが盛況になるイベントが発生しているのかもしれません。
どのトークンの取引が熱いかわかる
トークンアドレスへ伸びているグラフの数が多いと取引しているアドレスも多いとこになります(もちろん、取引アマウントの確認も必要です)。
取引が熱いトークンはボラティリティが高くなるので取引のチャンスになり得ます(下図は、「USDT=ステーブルコイン」なため、価格はほぼ一定なのでご注意ください)。
トラッキング機能でトラックすることが可能
ブロック番号、トランザクションハッシュ、ウォレットアドレス、コントラクトアドレスなどを入力欄に入れるとトラッキングすることができます。
パーティクル(粒子)が取引パスに沿って動くので、どのようなトレーダーが、どのブロックで、どのトークンを、どのくらいのアマウントで取引をしているのか視認することができます。
これらの情報はトレードのチャンスの判断で役立つのではないでしょうか?
※下図では、USDCのコントラクトアドレスをトラッキングしています。
今後の実装予定
今後は、トランザクションデータの検索可能にして、それを有向グラフで可視化したり、Universal Routerのトークン取引ボリュームにおける統計の可視化、Uniswapコマンド統計の可視化等を考えています。
また、他のL2チェーンへの対応や、Uniswap V4への対応も考えています
ゆくゆくは、有向グラフの可視化についてもオープンソースで公開しようと思っています(コード整理中)。
しかし、機能の追加においては、思いのほかサーバーにスペックが必要になりそうですので、支援したい等ありましたら、こちらのイーサリアムアドレス「0x5bdb6895532099E64C2e0013EB7d0b4A2e35e337」に寄付していただけると助かります。
また、ご質問、実装してほしいアイデア、バグがあれば、TwitterかGitHubでイシューを作成する等を通して、お気軽にお問い合わせください(様々な方に使って頂きたいため、前向きに検討します)。
是非、トレードツールとして「Universal Base」を使っていただければと思います。