CeloのPrice Oracleの仕組みについて
はじめに
CeloにはCeloネイティブトークンを使ったアルゴリズム型のステーブルコインcUSDが存在していることをこの記事を読んで知りました。
仕組みはLUNAと同じで、1cUSDをmintしたい場合は1ドル分のCeloと交換し、1cUSDをburnすると1ドル分のCeloが返ってくるものです。
LUNAと同じ仕組みであることよりも、Price Oracleの仕組みが気になったので詳しく調べてみました。
要約
- OracleにはCelo独自のSortedOracles Smart Contractが使われており、トークン毎に価格が保存・更新されている
- oracleを提出できるアドレスは複数存在しており、各アドレスから提出された価格を全て保存し中央値をoracleとして使っている
- Celoのガス代が安いので、Chainlinkと比較するとオンチェーンの処理が多く、価格の反映が高頻度に行われる
具体的なコード
下記の順番で具体的なコードを用いながら説明します。
- Reporterの登録
- Reporterによるprice oracleの提出
- priceの取得
Reporterの登録
Oracleを提出できるアドレスはreporterと呼ばれ、SortedOraclesのownerのみがaddOracle()
でreporterを追加できます。
codeではreporterはoracleで表現されてます。
また、getOracle()
で特定のトークンの価格を提出できるアドレスのリストを取得することができます。
実際に実行してみると、cUSDのoracleには16個のアドレスが登録されています。
しかし、10番目から15番目のアドレスはreportしていないので、実質は11個のアドレスによりoracleが管理されていることになります。
また、余談にはなりますが、1~8番目のアドレスは$350後半の分のCeloを持っていたのは何か意味がありそうだなと感じました。(もしかしたら単一のエンティティーにより運営されているとか。。。)
Reporterによるprice oracleの提出
価格の提出はreport()
関数で行われます。
提出された値の中央値を計算するために、report()
を実行する場合は提出する値の一個前の値と一個後の値を提出したアドレスを引数に入れる必要があります。
また、modifierにonlyOrace
とあるように、登録されたaddressしかこの関数を叩けないようになっています。
実際の値のアップデートのロジックはinsert()
関数で行われています。
priceの取得
提出されている値はの全てのリストはgetRates()
で取得できます。
addressの配列はreportを提出したアドレス、uint256の配列はprice、uint8は提出したpriceと中央値の関係性を表しています。
中央値を直接取得する場合はmedianRate()
で取得することができます。
疑問
Reporterの登録で説明したように、Reporterの中にはアクティブではないReporterが存在しています。
Reporterの削除するためにremoveOracle()
が存在していますが、この関数にはonlyOwner
のmodifierがついています。
Reporterがoracleを提出しない、どのアドレスがreporterなのかわからなくなる、などの問題があるので、この関数はもう少し柔軟性を持って良いかと感じました。
感想
- Chainlinkとの違いがあって面白かったです
- Celoはガス代が安いからこそ各reporterがオンチェーンでoracleを提出しているけど、chainlinkはオフチェーンでまとめてoracleを提出している
- Celoは各reporterが高頻度でreportを提出しているので価格の反映が早いけど、chainlinkはまとめて提出しているので一定時間経たないと更新されない
- report()を実行する際に、前と後の値をリンクさせる必要があるので、oracle同士の衝突は起こりそうと感じました、実際に失敗しているtxはいくつかありました
参考
- explorer
- Oracles
- Contract Addresses
- SortedOracles
- AddressLinkedList
- LinkedList
- AddressSortedLinkedListWithMedian
- AddressSortedLinkedList
Discussion