💪

XRPレジャーの価格オラクル機能

2023/01/08に公開

はじめに

この記事はXLS-47dとして提案されているPriceOracleを紹介するものです。

原文

この提案はまだ確定しているものではないため、今後変更される可能性があります。

XRP Ledgerでの価格オラクル

概要

この提案は、XRP LedgerにオンチェーンのPriceOracleオブジェクトを追加するものです。ブロックチェーンのオラクルとは、ブロックチェーン上の分散型アプリケーション(dApps)にオフチェーンのデータや情報を提供し、ブロックチェーンネットワークと外部世界との橋渡しをするシステムやサービスのことです。オラクルは、例えば市場価格、為替レート、金利、天候などの実世界のデータをブロックチェーン上にもたらし、dAppsがブロックチェーンの外部に存在する情報にアクセスして利用できるようにするために使用されます。このドキュメントでは、XRP Ledger上の価格オラクルの新しいプロトコルを紹介し、開発者やシステムアーキテクトがこのソリューションを効果的に実装・活用するためのガイドラインを提供します。この提案では、新しいオンレジャーのPriceOracleオブジェクトと、PriceOracleを作成、削除、更新するためのトランザクションを導入します。また、get_aggregate_priceAPIを追加し、提供されたプライスオラクルのaggregate meantrimmed meanmedian を取得します。この機能にはAmendmentが必要です。

用語

  • オラクルプロバイダ: 外部データや現実世界の出来事をブロックチェーンネットワークに統合できるサービスや技術。
  • dApp(分散型アプリケーション): ブロックチェーンネットワーク上に構築され、スマートコントラクトやその他の仕組みやプロトコルを使用して機能するアプリケーション。

XRPL上でのPriceOracleインスタンスの作成

オンレジャーのデータ構造

PriceOracleオブジェクト

PriceOracleレジャーエントリは、XRP Ledger上のPriceOracleオブジェクトを表し、次のフィールドを含みます。

フィールド名 必須? JSONの型 内部の型
LedgerEntryType string UINT16
Owner string ACCOUNTID
Provider string BLOB
PriceDataSeries array ARRAY
LastUpdateTime number UINT32
URI string BLOB
AssetClass string BLOB
PreviousTxnID string HASH256
PreviousTxnLgrSeq number UINT32
  • LedgerEntryTypeは、レジャーオブジェクトのタイプを示します。この提案では、予約されたエントリタイプとして 0x0080 を利用しています。

  • Ownerはこのオブジェクトを所有し、更新と削除の権限を持つアカウントです。このアカウントには関連する署名者リストを持つことが推奨されます。

  • ProviderはOracleプロバイダを示します。URIまたは任意のデータ、例えば文字列chainlinkを指定することができます。ASCIIの16進エンコードされた最大256文字(0x20-0x7E)の文字列です。

  • PriceDataSeriesは最大10個のPriceDataオブジェクトの配列です。5個以上のPriceDataオブジェクトを持つPriceOracleには2つのオーナーリザーブが必要です。PriceDataには次のフィールドが含まれます。

    フィールド名 必須? JSONの型 内部の型
    BaseAsset string CURRENCY
    QuoteAsset string CURRENCY
    AssetPrice number UINT64
    Scale number UINT8
    • BaseAssetとは、取引ペア内の基準資産のことです。これは、対象資産(Quote Asset)の価格が提示される際の基準となる資産です。BaseAssetは通常「基本」資産とみなされ、取引の基準となります。株式シンボル、債券CUSIP、通貨コードなど、有効な識別子であればどのようなものでも許可され、レジャーの他の資産識別子と同様に解釈されます。例えば、BTC/USDのペアではBTCがBaseAssetとなり、912810RR9/BTCでは912810RR9がBaseAssetとなります。CURRENCYフィールドをサポートするために、新しい型STI_CURRENCYが導入されました(詳細は付録をご覧ください)。
    • QuoteAssetは取引ペアにおける補助資産または提示資産を表します。これは基準資産(BaseAsset)1単位の価格を表します。提示資産の価値は、基準資産で表されます。通貨や暗号通貨コードなど、有効な識別子であればどのようなものでも許可され、レジャーの他の資産識別子と同様に解釈されます。例えば、BTC/USDのペアではUSDがQuoteAssetとなり、912810RR9/BTCではBTCがQuoteAssetとなります。新しいenum値STI_CURRENCYがCURRENCYフィールドをサポートするために導入されました(詳細は付録をご覧ください)。BaseAssetQuoteAssetは組み合わせて取引ペアを形成し、その関係によってある資産が別の資産と交換できる価格が決まります。
    • AssetPriceは資産価格を表すもので、スケール係数を適用した後の価格です。これは任意のフィールドです。最後の更新トランザクションにBaseAsset/QuoteAssetペアが含まれていない場合は除外されます。
    • Scaleは価格のスケール係数です。これは価格の精度レベルを表します。例えば、Scale6で、元の価格が0.155ならば、スケーリングされた価格は155000となります。正式にはscaledPrice = originalPrice*{10}^{scale}となります。有効なScaleの範囲は{0-10}です。これは任意フィールドです。最後の更新トランザクションにBaseAsset/QuoteAssetペアが含まれていない場合は除外されます。
  • URIは任意のURIフィールドで、チェーン外の価格データを参照するためのものです。256バイトの制限があります。

  • AssetClassは資産の種類を表します。例えば、"currency"、"commodity"、"index"などです。これは最大16文字のASCII16進エンコード文字列(0x20-0x7E)です。

  • LastUpdateTimeはデータが最後に更新された時刻です。LastUpdateTimeはUnix Timeで表され、1970年1月1日(UTC 00:00)からの秒数です。

  • PreviousTxnID は、このエントリを変更した直前のトランザクションのハッシュです(このフィールドを持つ他のオブジェクトと同じです)。

  • PreviousTxnLgrSeqは、このオブジェクトが最近更新/作成されたときのレジャーインデックスです(このフィールドを持つ他のオブジェクトと同じです)。

PriceOracleオブジェクトIDのフォーマット

PriceOracleのオブジェクトIDは、以下の値のSHA-512Halfを順番に連結したものとして計算します。

  • Oracleスペースキー(0x52)
  • Ownerによって表されるのアカウントID
  • OracleDocumentIDで表されるOracleドキュメントのID。このフィールドは、指定したアカウントに対する一意なPrice Oracleインスタンスを表します。OracleドキュメントIDはオラクルプロバイダによって管理されます。

OwnerOracleDocumentIDPriceOracleオブジェクトを一意に識別するため、Oracleトランザクションに渡す必要があります。

PriceOracleのJSONの例

{
    "LedgerEntryType": "PriceOracle",
    "Owner": "rsA2LpzuawewSBQXkiju3YQTMzW13pAAdW",
    // "provider"
    "Provider": "70726F7669646572",
    // "currency"
    "AssetClass": "63757272656E6379",
    "PriceDataSeries": [
      {
        "PriceData": {
          "BaseAsset": "XRP",
          "QuoteAsset": "USD",
          "AssetPrice": 74,
          "Scale": 2,
        }
      },
    ],
    "LastUpdateTime": 743609414,
    "PreviousTxnID": "C53ECF838647FA5A4C780377025FEC7999AB4182590510CA461444B207AB74A9",
    "PreviousTxnLgrSeq": 56865244
}

トランザクション

この提案では、PriceOracleオブジェクトの作成、更新、削除を可能にするために、いくつかの新しいトランザクションを導入します。

PriceOracleインスタンスの作成または更新のトランザクション

PriceOracleインスタンスを作成または更新するための新しいトランザクションOracleSetを定義します。新しいPriceOracleインスタンスを作成するためにトランザクションを送信する前に、オラクルプロバイダは以下を実行する必要があります。

  • 準備金と取引手数料の要件を満たすのに十分なXRP残高を持つOwnerをXRPL上に作成または所有します。
  • オラクルプロバイダはOwnerアカウントの公開鍵を公開し、dAppsによる検証に使用できるようにします。
  • オラクルプロバイダは、利用可能なPriceOracleのレジストリを一意のOracleDocumentIDとともに公開しなければなりません。OwnerOracleDocumentIDのハッシュは、PriceOracleのオンレジャーオブジェクトを一意に識別します。

OracleSetトランザクションのJSONの例

{
    "TransactionType": "OracleSet",
    "Account": "rsA2LpzuawewSBQXkiju3YQTMzW13pAAdW",
    "OracleDocumentID": 34,
    // "provider"
    "Provider": "70726F7669646572",
    "LastUpdateTime": 743609014,
    // "currency"
    "AssetClass": "63757272656E6379",
    "PriceDataSeries": [
      {
        "PriceData": {
          "BaseAsset": "XRP",
          "QuoteAsset": "USD",
          "AssetPrice": 740,
          "Scale": 3
        }
      }
    ]
}

OracleSetトランザクションのフィールド

フィールド名 必須? JSONの型 内部の型
TransactionType string UINT16
Account string ACCOUNTID
OracleDocumentID string UINT32
Provider string BLOB
URI string BLOB
AssetClass string BLOB
LastUpdateTime number UINT32
PriceDataSeries array ARRAY
BaseAsset string CURRENCY
QuoteAsset string CURRENCY
AssetPrice number UINT64
Scale number UINT8
  • TransactionTypeは新しいトランザクションタイプOracleSetを示します。
  • Accountは設定されているOracleの更新・削除権限を持つXRPLアカウントです。このフィールドはPriceOracleレジャーオブジェクトのOwnerフィールドに対応します。
  • OracleDocumentIDは、指定されたアカウントの価格オラクルの一意の識別子です。
  • ProviderはOracleプロバイダを示します。ProviderPriceOracleの新しいインスタンスを作成するときに含める必要があります。任意フィールドとして更新時に含めることもできますが、その場合は現在のProviderの値と一致しなければなりません。
  • URIは価格データをオフチェーンで参照するための任意フィールドです。
  • AssetClassは資産の種類を表します。AssetClassPriceOracleの新しいインスタンスを作成するときに含める必要があります。任意フィールドとして更新時に含めることもできますが、その場合は現在のAssetClassの値と一致する必要があります。
  • LastUpdateTimeはデータが最後に更新された時刻です。LastUpdateTimeはUnix Timeで表されます。
  • PriceDataSeriesは最大10個のPriceDataオブジェクトの配列です。PriceDataには次のフィールドが含まれます。
    • BaseAssetは価格が指定される資産です。
    • QuoteAssetは価格を表す単位です。
    • AssetPriceは資産価格を調整したもので、スケール係数を適用した後の価格です。
    • Scaleは価格のスケール係数です。

次の場合、トランザクションは失敗します。

  • 必須フィールドが存在しない。
  • 準備金が不足している。Oracleインスタンスのトークンペアが5つ以下の場合、必要な準備金は1つで、それ以外の場合、必要な準備金は2つです。
  • 新しいオラクルインスタンスを作成する際、トランザクションのPriceDataSeries配列のサイズが空もしくは10を超えている。
  • PriceDataSeriesに重複したトークンペアが存在する。
  • PriceDataSeriesの配列要素にAssetPriceがなく、トークンペアが既存のトークンペアと一致しない。
  • Oracleインスタンスの更新時に、Accountアカウントが存在しないか、AccountOwnerフィールドが等しくない。
  • トランザクションがAccountアカウントまたはそのアカウントのマルチ署名者によって署名されていない。
  • URIフィールドの長さが256バイトを超えている。
  • Providerフィールドの長さが256バイトを超えている。
  • 更新時にProviderフィールドが現在のProviderフィールドと一致しない。
  • AssetClassフィールドの長さが16バイトを超えている。
  • AssetClassフィールドが更新時に現在のAssetClassフィールドと一致しない。
  • LastUpdateTimeフィールドが前回のLastUpdateTimeより小さいか、または前回のクローズ時刻に30秒を加算した時刻より大きい。

OracleSetトランザクションはPriceOracleオブジェクトAccountフィールドとOracleDocumentIDフィールドで一意に識別します。そのようなオブジェクトがまだレジャーに存在しない場合は、そのオブジェクトが作成されます。そうでない場合は、既存のオブジェクトが更新されます。Providerフィールド、URIフィールド、AssetClassフィールドが存在する場合は、トランザクションから直接コピーされます。オブジェクトを作成する場合は、ProviderAssetClassをトランザクションに含める必要があります。

トランザクションのPriceDataSeriesフィールドは新しく作成されたPriceOracleオブジェクトにコピーされるか、既存のオブジェクトを更新します。

  • (BaseAssetQuoteAsset)トークンペアのPriceDataオブジェクトがオブジェクトにコピーされます。
  • トランザクションとオブジェクトの両方に存在するトークンペアのPriceDataはオブジェクトに上書きされます。
  • トランザクションとオブジェクトの両方に存在し、トランザクションでAssetPriceが欠落しているトークンペアのPriceDataオブジェクトはオブジェクトから削除されます。
  • オブジェクト内にのみ存在するトークンペアのPriceDataオブジェクトは変更されません。

トークンペアはPriceOracleオブジェクトのPriceDataSeries配列内のPriceDataオブジェクトの場所を一意に識別するので、トランザクション内のトークンペアの順番は重要ではありません。

PreviousTxnIDPreviousTxnLgrSeqAccountSetトランザクションと同じ方法で設定されます。

アカウントの所有者準備金は、トランザクションの適用前と適用後のPriceDataSeriesのサイズの差に応じて更新されます。0の場合はなし、1~5の場合は1、6~10の場合は2となります。

PriceOracleインスタンスの削除のトランザクション

Oracleインスタンスを削除するための新しいトランザクションOracleDeleteを定義します。

OracleDeleteトランザクションのJSONの例

{
    "TransactionType": "OracleDelete",
    "Account": "rsA2LpzuawewSBQXkiju3YQTMzW13pAAdW",
    "OracleDocumentID": 34
}

OracleDeleteトランザクションのフィールド

フィールド名 必須? JSONの型 内部の型
TransactionType string UINT16
Account string ACCOUNTID
OracleDocumentID string UINT32
  • TransactionTypeは新しいトランザクションタイプOracleDeleteを表します。
  • Accountはオラクルの更新と削除の権限を持つアカウントです。このフィールドはPriceOracleレジャーオブジェクトのOwnerフィールドに対応します。
  • OracleDocumentIDは指定したAccountのPrice Oracleの一意な識別子です。

OracleDeleteトランザクションは、レジャーからPriceOracleオブジェクトを削除します。

次の場合、トランザクションは失敗します。

  • 指定したOracle Object IDを持つオブジェクトが存在しません。
  • Accountが存在しないか、AccountOwnerフィールドが等しくありません。
  • トランザクションがAccountアカウントまたはそのアカウントのマルチ署名者によって署名されていません。

トランザクションが成功すると、PriceOracleオブジェクトが削除され、PriceDataSeries配列のサイズに応じて所有者の準備金が1つまたは2つ減ります。

API

オラクル情報の取得

オラクルオブジェクトは、accountoracle_document_idを指定してledger_entryAPIコールで取得できます。

ledger_entry APIのJSONの例
リクエストのJSON
{
    "method": "ledger_entry",
    "params" : [
      {
        "oracle" : {
          "account": "rsA2LpzuawewSBQXkiju3YQTMzW13pAAdW",
          "oracle_document_id":  34,
        },
        "ledger_index": "validated"
      }
    ]
}
Response JSON
{
    "index" : "CF2C20122022DE908C4F521A96DC2C1E5EFFD1EFD47AA244E9EE9A442451162E",
    "ledger_current_index" : 23,
    "node" : {
      "Flags" : 0,
      "LastUpdateTime" : 743609014,
      "LedgerEntryType" : "Oracle",
      "Owner" : "rp847ow9WcPmnNpVHMQV5A4BF6vaL9Abm6",
      // "currency"
      "AssetClass" : "63757272656E6379",
      // "provider"
      "Provider": "70726F7669646572",
      "PreviousTxnID" : "6F120537D0D212FEA6E11A0DCC5410AFCA95BD98D451D046832E6C4C4398164D",
      "PreviousTxnLgrSeq" : 22,
      "PriceDataSeries": [
        {
          "PriceData": {
            "QuoteAsset" : {
                "currency" : "USD"
            },
            "BaseAsset" : {
                "currency" : "XRP"
            },
            "Scale" : 1,
            "AssetPrice" : "740",
          }
        }
      ],
      "index" : "CF2C20122022DE908C4F521A96DC2C1E5EFFD1EFD47AA244E9EE9A442451162E"
    },
    "status" : "success",
    "validated" : true
}

オラクルのアグリゲーション

get_aggregate_priceRPCは、指定されたPriceOracleオブジェクトの価格を集計し、平均値、中央値、およびtrimパラメータがリクエストに含まれている場合は平均値を切り詰めた値の3種類の統計情報を返します。PriceOracleオブジェクトは、所有者アカウント(account)とOracle Document ID(oracle_document_id)フィールドで識別されます。

get_aggregate_price APIのJSONリクエストの例
{
    "method": "get_aggregate_price",
    "params": [
        {
            "ledger_index": "current",
            "base_asset": "XRP",
            "quote_asset": "USD",
            "trim": 20,
            "oracles": [
              {
                "account": "rp047ow9WcPmnNpVHMQV5A4BF6vaL9Abm6",
                "oracle_document_id": 34
              },
              {
                "account": "rp147ow9WcPmnNpVHMQV5A4BF6vaL9Abm7",
                "oracle_document_id": 56
              },
              {
                "account": "rp247ow9WcPmnNpVHMQV5A4BF6vaL9Abm8",
                "oracle_document_id": 2
              },
              {
                "account": "rp347ow9WcPmnNpVHMQV5A4BF6vaL9Abm9",
                "oracle_document_id": 7
              },
              {
                "account": "rp447ow9WcPmnNpVHMQV5A4BF6vaL9Abm0",
                "oracle_document_id": 109
              }
            ]
        }
    ]
}
get_aggregate_price APIのJSONレスポンスの例
{
  "entire_set" : {
      "mean" : "74.75",
      "size" : 10,
      "standard_deviation" : "0.1290994448735806"
  },
  "ledger_current_index" : 25,
  "median" : "74.75",
  "status" : "success",
  "trimmed_set" : {
    "mean" : "74.75",
    "size" : 6,
    "standard_deviation" : "0.1290994448735806"
  },
  "validated" : false,
  "time" : 78937648
}

APIの入力フィールド

フィールド名 必須? JSONの型
ledger_index string またはnumber(正の整数)
ledger_hash string
base_asset string
quote_asset string
oracles array
trim number
time_threshold number
  • ledger_indexは使用するレジャーインデックス、またはレジャーを自動的に選択するためのショートカット文字列です。

  • ledger_hashは使用する最大レジャーのバージョンを表す20バイトの16進文字列です。

  • base_assetは価格を算出する資産です。

  • quote_assetは価格を表示する額面です。

  • oraclesは集約するoracleオブジェクトの配列です。oracleオブジェクトには2つのフィールドがあります。

    フィールド名 必須? JSONの型
    account string
    oracle_document_id number
    • account はオラクルのアカウントです。
    • oracle_document_idは指定されたアカウントの価格オラクルの一意な識別子です。
  • trimはトリムする外れ値の割合です。有効なtrimの値の範囲は1~25です。このパラメータが含まれている場合、APIはトリミングされたデータの統計情報を返します。

  • time_thresholdは、古い価格データをフィルタリングする時間範囲を秒単位で指定します。このパラメータは任意であり、デフォルトでは0です。

集約する価格データは、特定の条件に基づいて選択されます。指定されたオラクルに対して、最新のPrice Oracleオブジェクトが取得されます。すべてのオブジェクトの中で最も新しいLastUpdateTimeが上限の時間しきい値として選択されます。Price Oracleオブジェクトは、指定の base_asset/quote_assetペア(AssetPriceフィールドを含む)を含み、そのLastUpdateTimeが(upper threshold - time threshold)の時間範囲から上限しきい値までの範囲内にあるという条件を満たす場合に、集計データセットに含まれます。Price Oracleオブジェクトが指定されたトークンペアのAssetPriceを含んでいない場合、最大3つ前のPrice Oracleオブジェクトが調べられ、条件を満たす最新のものが含まれます。

get_aggregate_priceは次の場合に失敗します。

  • oracles配列のサイズが0または200以上です。
  • oracles配列のオブジェクトにaccountまたはoracle_document_idが含まれていないか、これらのフィールドの値が無効です。
  • base_assetまたはquote_assetがありません。
  • trimまたはtime_thresholdに無効なuint値が含まれています。
  • 結果のデータセットが空です。

出力フィールド

成功すると、レスポンスデータには次のフィールドが含まれます。

  • entire_setは以下のフィールドからなるオブジェクトです:
    • sizeは統計量を計算するために使用するデータセットのサイズです。
    • meanは単純平均。
    • standard_deviationは標準偏差。
  • trimmed_setはオブジェクトで、trimフィールドが設定されている場合にレスポンスに含まれます。このオブジェクトは以下のフィールドを持ちます。
    • sizeは統計量を計算するために使用するデータセットのサイズ。
    • meanは単純平均。
    • standard_deviationは標準偏差。
  • medianは中央値。
  • timeは全てのLastUpdateTime値のうち、最新のタイムスタンプ。

付録

付録1. STI_CURRENCY

新しい型STI_CURRENCYBaseAssetQuoteAssetフィールドのCURRENCY型をサポートするために導入されました。この型は標準的な通貨コードであるXRPや任意の資産を160ビット(40文字)の16進文字列で表すことができます。この型は一般的にXRPLの通貨コードに準拠しています。以下はBaseAssetがCUSIPコード912810RR9を160ビットの16進文字列で表し、QuoteAssetが標準通貨コードUSDを表すJSONの例です。

    {
      "PriceData" : {
        // "912810RR9"
        "BaseAsset" : "3931323831305252390000000000000000000000",
        "QuoteAsset" : "USD",
        "Scale" : 1,
        "SymbolPrice" : 740
      }
    }

Discussion