XRPレジャーの価格オラクル機能
はじめに
この記事はXLS-47dとして提案されているPriceOracleを紹介するものです。
この提案はまだ確定しているものではないため、今後変更される可能性があります。
XRP Ledgerでの価格オラクル
概要
この提案は、XRP LedgerにオンチェーンのPriceOracle
オブジェクトを追加するものです。ブロックチェーンのオラクルとは、ブロックチェーン上の分散型アプリケーション(dApps)にオフチェーンのデータや情報を提供し、ブロックチェーンネットワークと外部世界との橋渡しをするシステムやサービスのことです。オラクルは、例えば市場価格、為替レート、金利、天候などの実世界のデータをブロックチェーン上にもたらし、dAppsがブロックチェーンの外部に存在する情報にアクセスして利用できるようにするために使用されます。このドキュメントでは、XRP Ledger上の価格オラクルの新しいプロトコルを紹介し、開発者やシステムアーキテクトがこのソリューションを効果的に実装・活用するためのガイドラインを提供します。この提案では、新しいオンレジャーのPriceOracle
オブジェクトと、PriceOracle
を作成、削除、更新するためのトランザクションを導入します。また、get_aggregate_price
APIを追加し、提供されたプライスオラクルのaggregate mean
、trimmed mean
、median
を取得します。この機能にはAmendmentが必要です。
用語
- オラクルプロバイダ: 外部データや現実世界の出来事をブロックチェーンネットワークに統合できるサービスや技術。
- dApp(分散型アプリケーション): ブロックチェーンネットワーク上に構築され、スマートコントラクトやその他の仕組みやプロトコルを使用して機能するアプリケーション。
PriceOracle
インスタンスの作成
XRPL上でのオンレジャーのデータ構造
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
フィールドをサポートするために導入されました(詳細は付録をご覧ください)。BaseAsset
とQuoteAsset
は組み合わせて取引ペアを形成し、その関係によってある資産が別の資産と交換できる価格が決まります。 -
AssetPrice
は資産価格を表すもので、スケール係数を適用した後の価格です。これは任意のフィールドです。最後の更新トランザクションにBaseAsset
/QuoteAsset
ペアが含まれていない場合は除外されます。 -
Scale
は価格のスケール係数です。これは価格の精度レベルを表します。例えば、Scale
が6
で、元の価格が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はオラクルプロバイダによって管理されます。
Owner
とOracleDocumentID
はPriceOracle
オブジェクトを一意に識別するため、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
とともに公開しなければなりません。Owner
とOracleDocumentID
のハッシュは、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プロバイダを示します。Provider
はPriceOracle
の新しいインスタンスを作成するときに含める必要があります。任意フィールドとして更新時に含めることもできますが、その場合は現在のProvider
の値と一致しなければなりません。 -
URI
は価格データをオフチェーンで参照するための任意フィールドです。 -
AssetClass
は資産の種類を表します。AssetClass
はPriceOracle
の新しいインスタンスを作成するときに含める必要があります。任意フィールドとして更新時に含めることもできますが、その場合は現在のAssetClass
の値と一致する必要があります。 -
LastUpdateTime
はデータが最後に更新された時刻です。LastUpdateTime
はUnix Timeで表されます。 -
PriceDataSeries
は最大10個のPriceData
オブジェクトの配列です。PriceData
には次のフィールドが含まれます。-
BaseAsset
は価格が指定される資産です。 -
QuoteAsset
は価格を表す単位です。 -
AssetPrice
は資産価格を調整したもので、スケール係数を適用した後の価格です。 -
Scale
は価格のスケール係数です。
-
次の場合、トランザクションは失敗します。
- 必須フィールドが存在しない。
- 準備金が不足している。Oracleインスタンスのトークンペアが5つ以下の場合、必要な準備金は1つで、それ以外の場合、必要な準備金は2つです。
- 新しいオラクルインスタンスを作成する際、トランザクションの
PriceDataSeries
配列のサイズが空もしくは10を超えている。 -
PriceDataSeries
に重複したトークンペアが存在する。 -
PriceDataSeries
の配列要素にAssetPrice
がなく、トークンペアが既存のトークンペアと一致しない。 - Oracleインスタンスの更新時に、
Account
アカウントが存在しないか、Account
とOwner
フィールドが等しくない。 - トランザクションが
Account
アカウントまたはそのアカウントのマルチ署名者によって署名されていない。 -
URI
フィールドの長さが256バイトを超えている。 -
Provider
フィールドの長さが256バイトを超えている。 - 更新時に
Provider
フィールドが現在のProvider
フィールドと一致しない。 -
AssetClass
フィールドの長さが16バイトを超えている。 -
AssetClass
フィールドが更新時に現在のAssetClass
フィールドと一致しない。 -
LastUpdateTime
フィールドが前回のLastUpdateTime
より小さいか、または前回のクローズ時刻に30秒を加算した時刻より大きい。
OracleSet
トランザクションはPriceOracleオブジェクト
をAccount
フィールドとOracleDocumentID
フィールドで一意に識別します。そのようなオブジェクトがまだレジャーに存在しない場合は、そのオブジェクトが作成されます。そうでない場合は、既存のオブジェクトが更新されます。Provider
フィールド、URI
フィールド、AssetClass
フィールドが存在する場合は、トランザクションから直接コピーされます。オブジェクトを作成する場合は、Provider
とAssetClass
をトランザクションに含める必要があります。
トランザクションのPriceDataSeries
フィールドは新しく作成されたPriceOracle
オブジェクトにコピーされるか、既存のオブジェクトを更新します。
- (
BaseAsset
、QuoteAsset
)トークンペアのPriceData
オブジェクトがオブジェクトにコピーされます。 - トランザクションとオブジェクトの両方に存在するトークンペアの
PriceData
はオブジェクトに上書きされます。 - トランザクションとオブジェクトの両方に存在し、トランザクションで
AssetPrice
が欠落しているトークンペアのPriceData
オブジェクトはオブジェクトから削除されます。 - オブジェクト内にのみ存在するトークンペアの
PriceData
オブジェクトは変更されません。
トークンペアはPriceOracle
オブジェクトのPriceDataSeries
配列内のPriceData
オブジェクトの場所を一意に識別するので、トランザクション内のトークンペアの順番は重要ではありません。
PreviousTxnID
とPreviousTxnLgrSeq
はAccountSet
トランザクションと同じ方法で設定されます。
アカウントの所有者準備金は、トランザクションの適用前と適用後の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
が存在しないか、Account
とOwner
フィールドが等しくありません。 - トランザクションが
Account
アカウントまたはそのアカウントのマルチ署名者によって署名されていません。
トランザクションが成功すると、PriceOracle
オブジェクトが削除され、PriceDataSeries
配列のサイズに応じて所有者の準備金が1つまたは2つ減ります。
API
オラクル情報の取得
オラクルオブジェクトは、account
とoracle_document_id
を指定してledger_entry
APIコールで取得できます。
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_price
RPCは、指定された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_CURRENCY
はBaseAsset
とQuoteAsset
フィールドの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