2021.04.05
DeFi(分散型金融)でのMoney Legoの実践
こんにちは。次世代システム研究室のL.W.です。
仮想通貨の相場の好調により、人々はDeFiにの注目をいっそう集めていて、DeFiでロックされている金額(TVL, Total Value Locked (USD))は増えつつあり、400億ドルを超えています。Lego(レゴ)のように、新しく創造的に組み合わされる可能な各プロトコルは雨後の筍のようにどんどん出て来て、成熟に成長しつつあり、全世界を席巻しました。
DeFiでのMoney(トークン、仮想アセット、仮想通貨、暗号資産のこと)は各プロトコルにより次々と発行されていて、分散型取引所(DEX)の二次市場でも盛んに流通されています。特筆すべきのは、昨年9月にDEXのUniswapの取引量はCoinbaseを上回り、世界で4番目に大きな取引所となり、DeFiの時代の幕開けを告げました。
一方、保有するトークンをさらに各DeFiプロトコルに投資して一般的な市場よりも高いリターンを求めるというYield farming / Liquidity miningの収益革命もブームになっています。
DeFiの一番目新しいイノベーションと言える無担保融資のFlashLoanは、去年の相次いでいたアタックでブロックチェーン界隈の方々に知られて、アビトラ、異なるレンディングプロトコル間の担保品のスイッチ、同一レンディングプロトコルでの担保品のスワップ、レンディングプロトコルでの自己清算(Self Liquidation)など、色々な方面でFlashLoanが活用されています。FlashLoanはMoney Legoを戯れる最強武器だと思っています。
今回は、Zoomでのトークイベントにて紹介した「DeFi(分散型金融)でのMoney Legoの実践」を、時間の都合上お話できなかった部分の補足などを交えて取り上げたいと思います。
1.「DeFi(分散型金融)でのMoney Legoの実践」の発表資料
[slideshare id=245666321&doc=thepracticeofdefimoneylego-210404050348]
2.発表資料への補足
DeFiモデル
DeFi(Decentralized Finance)は次世代のファイナンシャルサービスと言われて、現行のファイナンスを取って代わるか。やっぱり、中央集権型の銀行側はどのようにDeFiを評価しているか気になりますね。
アメリカ邦準備制度理事会(FRB)の地区連邦準備銀行であるセントルイス銀行(St. Louis Fed)が、DeFiに関する調査レポートを公開しました。中央集権型の銀行側の出したDeFiのレポートだからこそ、参考価値があるかと思います。
DeFiモデルというと、統一な図式がないだろうと思いますが、このレポートでの図式はより明白にDeFiの仕組みを表しましたので、採用させて頂きました。
レポートでは、DeFiエコシステムには4つの機会と6つのリスクがあると書いてあります。Efficiency(効率性)、Transparency(透明性)、Accessibility(アクセス可能性)、Composability(構成可能性)のは機会です。一方、Smart Contract Execution(スマートコントラクトの実行)、Operational Security(オペレーションセキュリティ)、Dependencies(依存性)、External Data(オラクル)、Illicit Activity(不法活動)、Scalability(安定性)はリスクとして挙げられました。DeFiのリスクをクリアできれば金融業界にパラダイムシフトを起こすと結論づけました。
DeFiレゴ(DeFi Lego)
イーサリアムでのDeFiのプロトコルは、同じセトルメントレイヤの上に構築され、同じトークンプロトコル(ERC20)をサポートすることで、複数のプロトコルを組み合わせることによって新しくエキサイティングなサービスを作成できます。スマートコントラクト同士を互いに統合できる特徴はDeFiの構成可能性(コンポーザビリティ)と言われています。
これでDeFiプロトコルはよくLegoに喩えられますね。
既存のDeFiプロトコルの再利用で、新規開発にもコスト減に繋がります。 この柔軟性により、オープンファイナンシャルエンジニアリングに莫大な可能性を秘めています。
今回のセッションでは、DeFi Legoの基本のパーツ、DEXとLending Marketを主に解説していました。アセットマネジメント、デリバティブ、アグリゲーターなどのプロトコルは時間の都合で割愛させて頂きました。
そして、DeFiレゴの組み合わせの運用例としては、Curveとyearn.financeもよく挙げられます。
DEXのCurveの場合、取引所として機能しながら、CompoundやAaveといったレンディングマーケットと組み合わせて、ユーザの預けたトークンでより多めの金利も得ることができます。
yearn.financeの場合も、レンディングマーケット、DEXなどのプロトコルと組み合わせて、イールドファーミング戦略を通して、高い収益を生み出せます。
流動性プール(Liquidity Pool)
DeFiプロトコルでの流動性は、DeFiマネー(トークン、仮想アセット、仮想通貨、暗号資産のこと)のトレードの円滑さを表しています。流動性が高ければ高いほど、DeFiマネーのトレードが滞りなく円滑に行われます。
流動性プールは、スマートコントラクトにロックされたDeFiマネーの集まりです。 DEX、レンディングなどのプロトコルによく使用されます。
プールにDeFiマネーを提供する側は流動性提供者(流動性プロバイダー、Liquidity Provider)と呼ばれます。誰もが流動性プロバイダーになることができます。
流動性プールからDeFiマネーをスワップあるいはレンディングするユーザには、カウンターパーティは流動性プロバイダーではなく、流動性プールとなります。
LPトークン(Liquidity Provider Token)
Liquidity Providerトークンのことで、債権として機能するトークンです。
トークンが流動性プールに預け入れられると、プロトコルは、預託者がそのプールで所有するシェアを表す新しいトークンを自動的に生成します。 これはLPトークンと呼ばれます。
LPトークンがプロトコルに返却され、焼却(burn)されることと共に、流動性プロバイダーに元金と利子を送ります。ですから、有利子派生トークン(interest-bearing derivative tokens)とも呼ばれます。
プロトコルによっては、トークンのシンボル、名称、機能が違います。
ガバナンストークン(Governance Token)
トークン所有者がプロトコルの未来を形作るのを助けるために開発者が作成するトークンです。 ガバナンストークンの所有者は、新機能の提案や決定、さらにはガバナンスシステム自体の変更など、プロジェクトに関する決定に影響を与える可能性があります。
多くの場合、ガバナンストークンを使用してアクセスされるオンチェーンガバナンスを通じて提案され、精査され、投票された変更は、スマートコントラクトにより自動的に適用されます。
ガバナンストークンの発行上限、割り当て方法、時期ですが、プロジェクトによって、異なります。詳しくは、各プロジェクトの公式サイトあるいはコミュニティに参照して頂ければと思います。
変動損失(Impermanent Loss)
変動損失に訳したのは妥当か知りませんが、直訳すると一時的損失でしょう。簡単にいうと流動性を提供した場合と、提供せずにホールドしていた場合の損失を指します。
流動性プールでのトークンの価格が相対的に変更した時、DEXとCEXの間は価格差が出てくるので、トレーダーはこの価格差で裁定取引を行って、利益を手に入れたことで、流動性プロバイダーに損失を被らせました。
変動損失は、DEXの特性とよく言われます。レンディングでは発生しません。
この文章を読めば、仕組みが大体分かるんでしょう。
3.デモと結果の分析
DeFiのMoney Legoの実践をやりたかったですが、何をしたらいいか迷っていたことがあります。
各プロトコルをアクセスするためには、多くの種類のDeFiマネーが欠かせないので、どのように揃えて入手できるかも困っていました。FlashLoanで無担保融資できるので、使えるかなぁ半信半疑。
アビトラ、異なるレンディングプロトコル間の担保品のスイッチ、同一レンディングプロトコルでの担保品のスワップ、レンディングプロトコルでの自己清算(Self Liquidation)など、色々な方面でFlashLoanが活用されています。
DeFiのアビトラですが、実質的にリスクなしで受動的な収入が得られるし、そして、いかなる予測アルゴリズムやストップロス戦略も必要とせないとよく言われます。
自作のスマートコントラクトで、FlashLoanを活用で必要な各種トークンを入手し、既存のプロトコルと組み合わせて、アビトラで儲けるかも。
では、FlashLoanでMoney Legoを戯れてみました。
FlashLoanのプロバイダーは流動性高いUniswapまたはSushiswapにして、借りたトークンはUniswapV1で裁定取引を試みました。
UniswapV1にした理由は取引は少なく、Uniswap/Sushiswapとの価格差が出やすいかと思っていました。
まずは取引ペアDAI/ETHで試しました。
※ ソースはgithubで共有しますので、ここではコメント付きの疑似コードを貼ります。
メインネットでの取引データのモニタリング
この三つDEX(Uniswap V1, Uniswap V2, Sushiswap)の公式サイトで取引データが見られますが、node.jsスクリプトで一括取得するも可能です。
取引データからすると、二つのことが分かりました。
① UniswapV2、Sushiswapは頻繁に利用されています。これに対して、UniswapV1の利用は想定通りに取引数は少ないです。
② 取引額は小額の場合はほとんどです。皆さんはスリッページ(Slippage)のことを意識しているか。
// まずはこの三つDEXのそれぞれの流動性プールのコントラクトアドレスを取得 const uniswapV2Exchange = "0xA478c2975Ab1Ea89e8196811F51A7B7Ade33eB11"; const sushiswapExchange = "0xC3D03e4F041Fd4cD388c549Ee2A29a9E5075882f"; const uniswapV1Exchange = "0x2a1530C4C41db0B0b2bB646CB5Eb1A67b7158667"; ... ... // ABIを定義する const uniswapAbi = [ "event Swap(address indexed sender, uint amount0In, uint amount1In, uint amount0Out, uint amount1Out, address indexed to)", ]; const uniswapV1Abi = [ "event TokenPurchase(address indexed buyer, uint256 indexed eth_sold, uint256 indexed tokens_bought)", "event EthPurchase(address indexed buyer, uint256 indexed tokens_sold, uint256 indexed eth_bought)" ]; const uniswapContract = new ethers.Contract( uniswapV2Exchange, uniswapAbi, provider, ); const filteruniV2 = uniswapContract.filters.Swap(); ... ... // contract.on方法を利用する uniswapContract.on(filteruniV2, (from, a0in, a0out, a1in, a1out, to, event) => { const blockNumber = event.blockNumber; const { price, token_volume, eth_volume } = convertSwapEventToPrice({ swapArgs: event.args, // the DAI ERC20 uses 18 decimals token0Decimals: 18, // the WETH ERC20 uses 18 decimals token1Decimals: 18, }); // データを取りまとめる console.log({ blockNumber, DEX: 'Uniswap V2', price, token_volume, eth_volume, tokenin }); });
これでまとめた取引データの結果の形は以下の通りです。(このファイルを参照してください)
※Swap DAI for ETH -> tokenin: true ※Swap ETH for DAI -> tokenin: false monitor-dai-weth-on-uniswapV1-uniswapV2-sushiswap start. { blockNumber: 12145927, DEX: 'Sushiswap', price: 1807.519922202831, token_volume: 1763.9556232231157, eth_volume: 0.9758983021738299, tokenin: false } { blockNumber: 12145929, DEX: 'Uniswap V2', price: 1801.8283378020176, token_volume: 1344.506488897233, eth_volume: 0.7461901118379267, tokenin: false } ... ... { blockNumber: 12145955, DEX: 'Uniswap V1', price: 1812.6049330073326, token_volume: 6189.9242364873535, eth_volume: 3.414932908859248, tokenin: false }
メインネットでのアビトラの機会を探す
スマートコントラクト
contract FlashLoanFromDex { ... ... // gets tokens/WETH via a Uniswap V2 or Sushiswap flashloan, swaps for the ETH/tokens on V1, // repays Uniswap V2 or Sushiswap, and keeps the rest weth, oh yeah! function uniswapV2Call(address sender, uint amount0, uint amount1, bytes calldata data) external { // DAIなどのトークンを融資した場合 // UniswapV1でトークンでETHとスワップする // スワップしたETHからFlashLoanプロバイダーに返済のETH部分を差し引く // 残りのETHはトレーダーの収益となる // ETH(またはWETH)を融資した場合 // FlashLoanプロバイダーに返済するトークン数を試算する // UniswapV1でETHで上の返済のトークン数を取得するためスワップする。 // 融資したETHから上でスワップされたETH分を差し引く // 残りのETHはトレーダーの収益となる }
Node.jsスクリプト
アビトラのボットはブロックごとに(15秒勝負)流動性プールのトークンの価格の変化に目を光らせて、一定の価格差が出たら、収益を試算し、ガスコストにカバーできるならば、スマートコントラクトを実施させる。
provider.on('block', async (blockNumber) => { // 価格取得(TOKEN/ETH price of uniswap v2, v1, sushiswap) // 一定の価格差でなければ、次のブロックへ // トレード戦略を練ります。例えば、どこから、どのトークンをFlashloan融資するか定める。 aribitrage() } const aribitrage = async () => { // アビトラの収益(Profit)を試算する // estimateGasでガス費用を試算する const gasLimit = await pairExe.estimateGas.swap(); const gasCost = Number(ethers.utils.formatEther(gasPrice.mul(gasLimit))); // Profit > gasCostの場合、アービトラージコントラクトを呼び出す if (Profit > gasCost) { const tx = await pairExe.swap(flashLoanerAddress); } }
Node.jsスクリプトの実行結果
流動性プールのDAI/ETH, USDC/ETH, MKR/ETH, BOND/ETH, ZRX/ETHにアビトラの機会を探してみましたが、見込みの収益が出ましたが、なかなかガスコストにカバーできず、一度もアービトラージコントラクトの呼び出しを実現できませんでした。
DAI/ETHの場合、一度もガスコストにカバーできず。
Bot started! OK Start aribitrage block by block BlockNumber => 12137986 , Tue Mar 30 2021 11:43:34 GMT+0900 (GMT+09:00) Uniswap V1 ETH Reserves => 205.03240722813115 Uniswap V1 TOKEN Reserves => 371088.3966602167 Uniswap ETH Reserves => 29612.800135379617 Uniswap TOKEN Reserves => 52966713.628053516 Sushiswap ETH Reserves => 109842.37878139074 Sushiswap TOKEN Reserves => 196946786.041794 Uniswap V1 TOKEN/ETH => 1809.9011842909392 Uniswap V2 TOEKN/ETH => 1788.6425257290016 Sushiswap TOKEN/ETH => 1792.9945457004278 Need to start flashswap from Uniswap V2, borrow ETH Find aribitrage oppoturnity => 1 times If FlashLoan ETHs => 0.6 ETH Require to return flashloan source DEX tokens => 1076.436569945202169764 To get the tokens, need to send Uniswap V1 WETH X => 0.598273868147728778 Profit = (FlashLoan ETHs) - X => 0.0017261318522712177 Time: Tue Mar 30 2021 11:43:37 GMT+0900 (GMT+09:00) Swap costs gas is 240000 (232309) GasPrice is 125g. Gas cost estimated 0.03 ETH. Profit - GasCost = -0.02827386814772878 Make gasPrice 10 times. Gas cost estimated 0.3 ETH. Profit - GasCost = -0.29827386814772877 Find aribitrage oppoturnity => 2 times If FlashLoan ETHs => 0.7 ETH Require to return flashloan source DEX tokens => 1255.846905914112614936 To get the tokens, need to send Uniswap V1 WETH X => 0.698327139460265691 Profit = (FlashLoan ETHs) - X => 0.0016728605397342555 Time: Tue Mar 30 2021 11:43:39 GMT+0900 (GMT+09:00) Swap costs gas is 240000 (232309) GasPrice is 125g. Gas cost estimated 0.03 ETH. Profit - GasCost = -0.028327139460265743 Make gasPrice 10 times. Gas cost estimated 0.3 ETH. Profit - GasCost = -0.29832713946026573 OK, to NEXT block
BOND/ETHの場合、ガスコスト(gasPriceは平均値にした場合)にカバーできたことがありますが、他のボットとの競争で優位性を保つためには、gasPriceを10倍にした場合、残念ですが、最終の利益を出せず。
Bot started! OK Start aribitrage block by block BlockNumber => 12152983 , Thu Apr 01 2021 19:06:39 GMT+0900 (GMT+09:00) Uniswap V1 ETH Reserves => 63.66196397363225 Uniswap V1 TOKEN Reserves => 7118.593241957829 Uniswap ETH Reserves => 237.8463053635348 Uniswap TOKEN Reserves => 28173.871531113426 Sushiswap ETH Reserves => 4153.400476030955 Sushiswap TOKEN Reserves => 489229.44518001395 Uniswap V1 TOKEN/ETH => 111.8186244600659 Uniswap V2 TOEKN/ETH => 118.45410626854697 Sushiswap TOKEN/ETH => 117.79009705501072 Need to start flashswap from Uniswap V2, borrow TOKEN Find aribitrage oppoturnity => 1 times If FlashLoan Tokens => 160.0 With the flashloan tokens, Uniswap V1 will get ETH Y => 1.395328178535183404 Require to return flashloan to source DEX ETH X => 1.362536362445098735 Profit = Y - X => 0.032791816090084636 Time: Thu Apr 01 2021 19:06:42 GMT+0900 (GMT+09:00) Swap costs gas is 190000 (188199) GasPrice is 158g. Gas cost estimated 0.03002 ETH. Profit - GasCost = 0.002771816090084634 Make gasPrice 10 times. Gas cost estimated 0.3002 ETH. Profit - GasCost = -0.2674081839099154 Find aribitrage oppoturnity => 2 times If FlashLoan Tokens => 170.0 With the flashloan tokens, Uniswap V1 will get ETH Y => 1.48050810009578704 Require to return flashloan to source DEX ETH X => 1.448211847505593598 Profit = Y - X => 0.03229625259019353 Time: Thu Apr 01 2021 19:06:44 GMT+0900 (GMT+09:00) Swap costs gas is 190000 (188199) GasPrice is 158g. Gas cost estimated 0.03002 ETH. Profit - GasCost = 0.002276252590193529 Make gasPrice 10 times. Gas cost estimated 0.3002 ETH. Profit - GasCost = -0.2679037474098065 OK, to NEXT block
ローカルノードでのアビトラの実施をシミュレーション
① メインネットのデータをローカルにフォークする。
npx ganache-cli --fork https://mainnet.infura.io/v3/<Your PJ ID> -i 1337 -e 100000 -m "<Your Mnemonic Phrase>"
② アビトラのコントラクトをデプロイする。(1955364のガスが掛かりました。)
Replacing 'FlashLoanFromDex' ---------------------------- > transaction hash: 0x4020a9a79ebcb815435b0b18c82cc85a4f746de48fafd803580ad5a09b9e332f > Blocks: 0 Seconds: 0 > contract address: 0xa2be6260F6929e90d8b9F58344A10d2F21dEa8Ac > block number: 12177419 > block timestamp: 1617595528 > account: 0xA75A18e2c1A214754648FB2900501329090794f3 > balance: 99999.80357194 > gas used: 1955364 (0x1dd624) > gas price: 20 gwei > value sent: 0 ETH > total cost: 0.03910728 ETH
③ ユーザはUniswapで500ETHでDAIとスワップすることを模擬する。(自作のswap.jsを利用)
// node swap.js 500 U Uniswap router address -> 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D ETH -> DAI SWAP started! GasLimit is -> 150797 GasPrice is -> 20000000000 GasCost is -> 0.00301594 swapExactETHForTokens start SWAP EXECUTED! PENDING TX TO BE MINED TX hash: 0x25f01c9fbc24d3e0da5010cb16be084ff18d65f51e24eaf906960ac92eff0490 SUCCESS! TX MINED
④ アビトラボットをスタートする
設計したトレード戦略の通りにアビトラを実施できたことが確認できました。
実行の結果はこのファイルに参照して頂ければと思います。
4.まとめ
DeFiのプロトコルの組み合わせで、どのような目新しいサービスが世に出せるか楽しみにしていますね。
FlashLoanはまだ実験的に運用されていますが、この武器の強さは益々大方に認識されているんでしょう。
僕のデモでFlashLoanでアビトラを試みましたが、最終の利益に繋がるためには改善する余地が多くあると認識しています。これから、より多くのプロトコルを深掘りし、自作のアビトラコントラクトに組み込んで、トレード戦略も練った上で、敢えて再挑戦に行きたいです。
5.最後に
次世代システム研究室では、グループ全体のインテグレーションを支援してくれるアーキテクトを募集しています。アプリケーション開発者の方、次世代システム研究室にご興味を持って頂ける方がいらっしゃいましたら、ぜひ募集職種一覧からご応募をお願いします。
皆さんのご応募をお待ちしています。
グループ研究開発本部の最新情報をTwitterで配信中です。ぜひフォローください。
Follow @GMO_RD