ブロックチェーンの分野において、オラクルはチェーン上のスマートコントラクトに外部情報を提供できるシステムです。オラクルは、スマート コントラクトとブロックチェーンの外の世界を接続するミドルウェアとして、非常に重要なインフラストラクチャの役割を果たします。その主な機能は、ブロックチェーン内のスマート コントラクトにデータを提供することです。
たとえば、イーサリアム ネットワーク上にスマート コントラクトを作成し、このコントラクトが特定の日の原油取引量データにアクセスする必要があるとします。ただし、スマート コントラクト自体はこのオフチェーンの実世界データを取得できないため、オラクルを通じて実装する必要があります。この場合、スマート コントラクトは、必要な日付の原油取引量をイベント ログに書き込みます。その後、トランザクション内のリクエストが受信されると、このイベント ログを監視およびサブスクライブするプロセスがオフチェーンで開始されます。オンチェーントランザクションを送信し、コントラクトの関連メソッドを呼び出すことで、指定日の原油取引量情報がスマートコントラクトにアップロードされます。
データは https://defillama.com/oracles から取得しています
金網
ブロックチェーンでは、Chainlink オラクルが最大の市場シェアを持っています。 Chainlink は分散型オラクル プロジェクトであり、その役割は現実世界で生成されたデータを最も安全な方法でブロックチェーンに提供することです。基本的なオラクル原則の実装に基づいて、Chainlink は経済的インセンティブを通じて LINK トークンを中心とした好循環エコシステムを確立しました。 Chainlink オラクルは、LINK トークンの転送によってトリガーされる必要があります。 LINK は、イーサリアム ネットワーク上の ERC677 コントラクトです。 LINK ERC677トークンに基づくOracle関数はリクエスト/レスポンスモードに属します。
ERC677 トークンの transferAndCall
オラクルは本質的にサービスを提供する当事者です。 ChainLink がオラクル フレームワークを設計したとき、最初に頭に浮かんだのは、オラクルのユーザーがサービスを提供するオラクルにサービス料金を支払う方法でした。ただし、標準の同種トークンコントラクト ERC20 では支払い後のサービス提供のニーズを満たすことができないため、ChainLink 自体がオラクルサービスシナリオに適した標準である ERC677 を提案しました。
上記のコードからわかるように、ERC677 は実際には標準の ERC20 に基づいて transferAndCall メソッドを追加しているだけです。この方法では、支払いとサービスのリクエストが 1 つに結合され、オラクルのビジネス シナリオのニーズが満たされます。
ユーザが transferAndCall を実行して転送する場合、ERC20 転送に加えて、to アドレスが契約アドレスであるかどうかも判断され、そうであれば、to アドレスの onTokenTransfer メソッドが呼び出されます。 (ここでの ERC677Receiver にはメソッドが 1 つだけあります: onTokenTransfer)
Etherscan にアクセスして、LINK トークンのコントラクト ソース コードを表示することもできます: https://etherscan.io/address/0x514910771af9ca656af840dff83e8264ecf986ca#code
LINK Token が実装されると、_to アドレスの複数のペアを検証することに加えて、実際には ERC677 の transferAndCall メソッドを継承することがわかります。注: オラクルは消費者にサービスを提供する前に支払いを必要とするため、オラクル サービスをリクエストする前に、まずオラクルが信頼できるかどうかを判断する必要があります。 (誰でもオラクルサービスを提供可能)
オラクルの信頼性分類
オンチェーンオラクルリクエスト
Oracle コントラクトの onTokenTransfer メソッドがどのように実装されているかを見てみましょう。
オラクルのコンシューマが transferAndCall メソッドを使用して支払いを行い、オラクルのサービスをリクエストする場合、ここでの to アドレスはリクエストされたオラクルのアドレスです。 Oracle マシンの onTokenTransfer メソッドは、最初に転送が LINK トークン (onlyLINK) であるかどうかを検証します。これは実際には、msg.sender がリンク トークン コントラクトのアドレスであるかどうかを判断することになります。次に、_dataの長さが上限を超えているかどうかを判定します。最後に、_data内に「oracleRequest」で始まる関数セレクタがあるかどうかを判定します。もちろん、ここでの関数セレクターは、Oracle マシンが提供するサービスに応じてカスタマイズでき、「oracleRequest」である必要はありません。Oracle マシンがどのような種類のインターフェイスを外部に公開するかによって異なります。
これらの修飾子を渡す際には、現在の関数呼び出し元と転送量が_dataと同じかどうかを確認してください。これらの一連のセキュリティ チェックに合格した後、現在の Oracle コントラクトがデリゲートコールを通じて呼び出されます。もちろん、_data の関数セレクターがチェックされているため、実際には oracleRequest メソッドが呼び出されます。
まず、Oracle リクエスターと彼によって送信された nonce を連結し、それをこのリクエストの requestId としてハッシュし、コミットメント マッピングをチェックして一意の ID かどうかを確認します。確認して問題がなければ、有効期限を設定し、コミットメントに requestId を追加し、_payment、_callbackAddress、_callbackFunctionId、expiration を値として連結します。最も重要なことは、Concise Binary Object Representation (CBOR) データであるリクエスト data_data を含む OracleRequest イベントを発行することです。エンコード形式は軽量かつ簡潔で、バイナリ形式の JSON 形式として簡単に理解できます。このデータは、オフチェーン ノードの設計方法に応じて、さまざまな形式になります。
例: Chainlink: ETH/USD アグリゲータ、トランザクションには OracleRequest イベントが含まれます。
OracleRequest イベントの例
このイベントは、ETH/USD 価格アグリゲーター 0xF79D6aFBb6dA890132F9D7c355e3015f15F3406F によってオラクル 0x7e94a8a23687d8c7058ba5625db2ce358bcbd244 に送信された価格データ リクエストであることがわかります。 Oracle がリクエスト データを返すと、返されたコントラクト アドレス: 0xF79D6aFBb6dA890132F9D7c355e3015f15F3406F、呼び出す必要があるメソッド ID: 6A9705B4、および有効期限: 1618185924 を知ることができます。
オフチェーンノードの応答
3.1 オフチェーンでの filleOracleRequest の呼び出し
最初のチェック:
- onlyAuthorizedNode: 関数の呼び出し元 (msg.sender) は、コントラクトの所有者であるか、承認されたリストに含まれている必要があります。
- isValidRequest: requestId がコミットメント マッピングに存在するかどうかを引き続き確認します。
- Payment、callbackAddress、_callbackFunctionId、および有効期限を結合して、コミットメント マップ内の requestId の対応する値であるかどうかを確認します。
これらのチェックに合格すると、このリクエストのコストがdrawableTokensに蓄積され、引き出し可能な金額が記録されます。その後、_requestId がコミットメント マップから削除されます。最後に、残りのガス量を計算して、リクエストを発行したコントラクトのコールバック関数を実行するために必要な最小ガス量である MINIMUM_CONSUMER_GAS_LIMIT より大きいかどうかを確認します。
上記のチェックに合格すると、リクエスタ コントラクトのコールバック関数を call 形式で正式に呼び出すことができます。
リクエストへの応答は可能な限り高速である必要があるため、応答速度を向上させるために ZAN のノード サービス ( https://zan.top/home/node-service?chInfo=ch_WZ ) を使用することをお勧めします。ノード サービス コンソールで対応する RPC リンクを見つけて、チェーンからトランザクションを送信する速度を向上させることができます。
3.2 コールバック関数
以前は、oracleRequest からコールバック関数の ID が 6A9705B4 であることがわかっており、クエリではメソッドが "chainlinkCallback(bytes32,int256") であることがわかりました。
validateChainlinkCallback はカスタマイズ可能な関数です。修飾子は次のとおりです。
pendingRequests で、リクエストされた oracle に対応する _requestId が一致するかどうかを確認します。そしてイベント ChainlinkFulfilled を発行します。
検証に合格すると、応答をさらに処理できます。ここで、応答マッピングが更新されます。次に、それが価格オラクルの場合、応答価格データが currentPrice に割り当てられ、対応する価格更新が実行されます。
以上がユニバーサルオラクルサービスの完全なプロセスです。
Chainlink が提供する「TestnetConsumer」コントラクトの「requestEthereumPrice」メソッドを例として、価格オラクルのリクエストとレスポンスのプロセスについて簡単に説明します。この関数は次のように定義されます。
実装する機能は、指定された API (cryptocompare) から ETH/USD の取引価格を取得することです。関数によって渡されるパラメータは、指定された Oracle アドレスと jobId です。一連のリクエスト パラメータを組み立てた後、「sendChainlinkRequestTo」メソッドを呼び出してリクエストを送信します。 「 sendChainlinkRequestTo 」はChainlinkが提供するライブラリで定義されているインターフェースメソッドで、以下のように定義されています。
転送を受信した後、Oracle コントラクトは「onTokenTransfer」メソッドをトリガーし、転送の有効性をチェックし、「OracleRequest」イベントを発行してより詳細なデータ情報を記録します。
このログは、Oracle コントラクトのログにあります。チェーンの下のノードは、記録されたログ情報を取得した後、リクエストの特定の情報を解析し、ネットワーク API 呼び出しを通じてリクエストの結果を取得します。次に、トランザクションを送信すると、Oracle コントラクトの「fulfillOracleRequest」メソッドが呼び出され、データがチェーンに送信されます。
このメソッドは一連のテストを実行し、以前に記録されたコールバック アドレスとコールバック関数を通じて結果をコンシューマ コントラクトに返します。
開発者として、これらの URL を自分で指定せずに既存の通貨ペアの価格を使用したいのですが、それはできますか?
答えは「はい」です。最初の使用方法、公式のサンプルコードは次のとおりです。
まず、各取引ペアには、次のような個別の価格フィード (Aggregator とも呼ばれます) があり、実際には AggregatorProxy です。
このインターフェイスの具体的な実装は、AAVE/ETH ペアを参照できます: https://etherscan.io/address/0x6Df09E975c830ECae5bd4eD9d90f3A95a4f88012#code。
合計 5 つのクエリ メソッドがあります。
- decimals(): 返される価格データの精度の桁数、通常は 8 または 18
- description(): 通常、ETH/USD などの取引ペアの名前
- version(): 主にプロキシが指すアグリゲータのタイプを識別するために使用されます。
- getRoundData(_roundId): ラウンド ID に基づいて現在の価格データを取得します
- 最新ラウンドデータ(): 最新の価格データを取得します
ほとんどのアプリケーション シナリオでは、コントラクトは最新の価格を読み取ること、つまり最後のメソッドを呼び出すことだけが必要であり、その戻りパラメータには最新の価格が返されます。
さらに、ほとんどのアプリケーションは価格設定単位としてUSDでのトークンの価格を読み取ります。その場合、価格設定単位としての USD でのペアの精度桁数は一律 8 桁であるため、通常の状況では処理する必要はありません。異なるトークンに基づいて異なる精度の問題が発生します。