diff --git a/CIP-0073/README.md b/CIP-0073/README.md new file mode 100644 index 0000000000..db426a7af1 --- /dev/null +++ b/CIP-0073/README.md @@ -0,0 +1,321 @@ +--- +CIP: 73 +Title: Oracle Datum Standard +Status: Proposed +Category: Tools +Authors: + - Jonas Lindgren + - Cody Butz + - Cardano DeFi Alliance +Implementors: + - Charli3 Oracles +Discussions: + - https://github.com/cardano-foundation/CIPs/pull/357 +Created: 2022-10-20 +License: CC-BY-4.0 +--- + +## Abstract + +This proposal defines a data standard for oracles to follow when placing data on-chain, as well as consumers to read the datum of produced oracle feeds. + +## Motivation + +Oracles provide a way for real-world data to be provided to a blockchain or smart contract to allow interaction with external data sources. Oracle's query, verify, and authenticate external data and then relay it to the blockchain. Oracles can provide multiple types of data feeds, for example: asset spot price, access to indexes, and statistics data for a particular blockchain. + +Oracles act as a data provider to the blockchain. As a data provider, it makes sense for the data feeds to be standardized so that they can be reused by multiple different projects, reducing fee overhead and decreasing feed setup overhead. + +Data consumers, who are reading the price data from an oracle, want to be able to support multiple data feeds from different providers for fall-back mechanisms and additional decentralization. If each oracle solution is providing a different datum/metadata structure, these particular data structures have to be supported by the data consumers' smart contracts and/or applications. By having a standard data structure for each particular data feed type, as a data consumer I can write my smart contracts/application to support that standard and expect the oracle to support that particular standard. + +Data consumers that share a common format for the data feeds they consume, may also be able to collaborate to provide more well-secured and frequently updated data feeds to share together, than they would otherwise be able to accomplish by each using their own standard. + +## Specification + +Oracles are responsible for providing multiple types of off-chain data to the blockchain. This proposal outlines an on-chain datum standard for Oracle producers to submit to the blockchain and Oracle consumers to read from the blockchain in a standardized format. + +Such a standard should accomplish a number of somewhat contradictory objectives + +* Data provided by the feed should be possible to alter over time, to add more detailed data or remove parts of the data, without major disruption to existing users of the data feed +* Data provided in the feed should be stored in an efficient manner, to avoid data duplication and excessive transaction costs +* The standard should be flexible enough to capture the majority of use-cases, even those that may not yet be conceived of at the writing of this document +* The standard should provide room for individual data providers to add their own data fields to a feed, without interfering with the common standard + +### Data Format + +The basis for this standard is the Concise Binary Object Representation (CBOR) data format, for which more information can be found here: [https://www.rfc-editor.org/rfc/rfc8949.html](https://www.rfc-editor.org/rfc/rfc8949.html) + +A central aspect of the CBOR standard that is used extensively is the concept of a Tag, which allows data consumers to identify and consume the types of data that they expect, and gracefully ignore other pieces of data that they are not interested in. + +Similar to the CBOR standard this CIP will also propose a CBOR Tags Registry. Data providers are able to provide data according to the formats provided in this registry, and data consumers can discern the different available formats to pick the exact kind of data they need out of a feed. + +To maintain compatibility with the main CBOR Tags Registry, the tags proposed in this are defined as an offset from Base Oracle Datum CIP Tag Number, which is defined later in this document. For example, Tag +5 would correspond to the actual number OracleDatumCipTagNumber + 5. + + +#### Detailed Format + +Any data feed datum matching this standard must adhere to the following overall structure. Each of these individual elements is a Tag defined further later on. + +The data structure consists of a list of Tags. This list is itself surrounded by a tag versioned to this major version of CIP. A later CIP may thus build on top of this standard by adding further datum after the initial one, using a different tag that allows older users of this CIP to disregard this new data. + +There are 3 major categories of Tags, described in further detail later on, SharedData, GenericData and ExtendedData. In the list the ordering is defined as [ ? SharedData, 1* GenericData, ? ExtendedData ]. Or in plain english, a SharedData may optionally come first, then 1 or more GenericData in no particular order, and finally an ExtendedData may optionally come last. + + +### CIP CBOR Tags Registry + +As additional use cases and data fields become necessary, this Tags Registry should be amended and updated to add new Tags and fields inside specific tags. Care should be taken to not change or remove existing Tags and fields inside specific tags, so as to maintain backwards compatibility to as great an extent as possible. + +Tags are optional; data providers may provide multiple different tags covering the same data. The standard permits oracle feed providers to be flexible about what data they provide, while adhering to the standard. This allows feed consumers to programmatically discover what information is on the feed, while ignoring information that is not relevant to their use case. + + +### SharedData(Tag +0) + +Data stored in this tag is considered to be auxiliary or supportive of the rest of the tags in the datum.. + +Data inside this tag is stored as a CBOR Mapping, the keys defined as positive integers and the values being defined on a per-case basis. The keys are defined here as enums, to give users of the standard a common understanding of what data is stored where. Each field in the mapping is optional. + +*Keys-value mappings* + + + + + + + + + + + + + + + + + +
Key + Value Data Type + Description +
0 + PriceMap + Default values for any non-overridden PriceMap values +
1 + KYCList + Default values for any non-overridden KYCList values +
+ +### ExtendedData(Tag +1) + +This tag is intended to store data provider specific data, where each data provider can define their own fields with a minimum of interference. Serves a similar purpose to SharedData, but is used for “global” data that isn’t considered broad enough in use to be defined in SharedData but still is considered valuable by a data provider. + +Please note that a data provider may instead define their own tag to provide some specific type of data, if no existing registered tags are appropriate for the use case. Avoid putting such data in ExtendedData if possible, if instead the PriceData standard may be extended with the new tag, for example. + +Key indices 0-100 are considered to be reserved for data entries defined by this CIP and future iterations of this CIP, but key indices 101 and above are considered free for any oracle provider to define as they wish. For use-cases that rely on a specific oracle providers custom data indices, please first check to ensure the ExtendedData is provided by the expected oracle provider by use of index 0 or 3. + +Data inside this tag is stored as a CBOR Mapping, the keys defined as positive integers and the values being defined on a per-case basis. The keys are defined here as enums, to give users of the standard a common understanding of what data is stored where. Each field in the mapping is optional. + +*Keys-value mappings* + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Key + Value Data Type + Description +
0 + Integer + An index of the oracle provider providing this datum, see separately included registry in this CIP. +
1 + Integer + The number of data sources involved in calculating the oracle data. +
2 + Integer + The number of data provider nodes involved in verifying or signing the oracle data. +
3 + String + POSSIBLE FUTURE ADDITION: A signature from the provider for oracle identity verification, where applicable. They must sign some data unique to this transaction that is verifiable by a datum / datum hash. Please define implementation. +
+ +### PriceMap(Tag +2) + +This tag represents a single price sample at a specific point in time. + +Data inside this tag is stored as a CBOR Mapping, the keys defined as positive integers and the values being defined on a per-case basis. The keys are defined here as enums, to give users of the standard a common understanding of what data is stored where. Each field in the mapping is optional. + +*Keys-value mappings* + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Key + Value Data Type + Description +
0 + Integer + Price, or how many Quoted Currency is received per Base Currency spent +
1 + Integer + POSIX Timestamp related to the time that the data was aggregated. +
2 + Integer + POSIX Timestamp related to the time that the oracle deems the data stale and/or expired. +
3 + Integer + Decimals of Price +
4 + Integer + ID of Base Currency +
5 + Integer + ID of Quoted Currency +
6 + String + Symbol of Base Currency +
7 + String + Symbol of Quoted Currency +
8 + String + Name of Base Currency +
9 + String + Name of Quoted Currency +
+ + + +### KYCList(Tag +3) + +This tag represents 0-X Cardano addresses and what country the controlling user is KYC’ed as being a citizen or tax resident of. + +Data inside this tag is stored as a CBOR Mapping, the keys defined as bytes representing Cardano addresses and the values being defined as a list of country codes as strings. Multiple country codes are to be interpreted as the address potentially belonging to any one of those. + + +``` +cardano_public_key = tstr +nationality = tstr +whitelisted = uint +``` + + + + + + + + + + + + + + + + + + + + + + +
+ +Key + Value Data Type + Description +
0 + String + Cardano Address Public Key +
1 + String + Nationality +
2 + Integer (boolean) + Address is whitelisted for sale +
+ +## Rationale + +This CIP is ready to be made active. + +Having a CIP to rely on would help oracle consuming projects as well as oracle providing projects exchange data in a common format. Many oracle data consumers and providers are working on competing, application-specific data formats that will divide and isolate projects. This CIP will help unify the community and allow for more interoperability within the Cardano developer community. + +The oracle provider Charli3 has committed to implementing this standard for their free-to-use Catalyst-funded oracle feeds, and will be the first to do so. Charli3 has further committed to making their libraries for interacting with oracle data according to this CIP standard available under an open source license. + +## Copyright + +This CIP is licensed under [CC-BY-4.0](https://creativecommons.org/licenses/by/4.0/legalcode) diff --git a/CIP-0073/standard.cddl b/CIP-0073/standard.cddl new file mode 100644 index 0000000000..6d791fa4e2 --- /dev/null +++ b/CIP-0073/standard.cddl @@ -0,0 +1,84 @@ +; Oracle Datum + +; The oracle datum is composed of a generic, shared and extended data. +; - With key 0: The generic data will be a list of different feed values. +; - With key 1: The shared data could not be part of the datum, but if it's +; present then carries the information about the timestamp and expiry of +; all the feeds. +; - With key 2: The extended data could not be part of the datum, but if it's +; present then carries some external information about the provider of the +; feeds. +oracle_datum = #6.121(oracle_datum_list) +oracle_datum_list = + [ ? shared_data + , 1* generic_data + , ? extended_data + ] + +; At the moment we have two types of generic data: +; - price_data, for the exchange rate between two assets. +; - kyc_data, for “Know Your Customer” related data +generic_data = price_data / kyc_data + +; A price_data entry normally defines the “Currency Pair” being priced. +; A “Currency Pair” is defined as “the first listed currency or base currency is +; bought while the second listed currency in a currency pair or quote currency is +; sold.” Each currency is defined separately in the entry, and referred to as the +; “base” and “quote” currency. +price_data = #6.123([price_map]) +price_map = + { ? 0 : price ; how many quote currency is received per base currency spent + , ? 1 : posixtime ; unix timestamp related to when the price data was created + , ? 2 : posixtime ; unix timestamp related to when the price data is expired + , ? 3 : precision ; how many decimals of precision price is specified at + , ? 4 : asset_id ; id of base + , ? 5 : asset_id ; id of quote + , ? 6 : asset_symbol ; symbol of base + , ? 7 : asset_symbol ; symbol of quote + , ? 8 : asset_name ; name of base + , ? 9 : asset_name ; name of quote + } + +precision = uint +price = uint +asset_id = uint +asset_symbol = tstr +asset_name = tstr + +; In order: +; - Timestamp of the creation of all the generic data. +; - Expiry of the creation of that data. +shared_data = #6.121(shared_map) +shared_map = + { ? 0: price_data + , ? 1: kyc_data + } + +; The extended data carries provider-specific information, and may +; be individually customized by oracle providers to provide data +; they deem relevant. It's thus not entirely defined by spec, +; but indices below 100 are "reserved" by the spec. +extended_data = #6.122(extended_map) +extended_map = + { ? 0: oracle_provider_id + , ? 1: data_source_count + , ? 2: data_signatories_count + , ? 3: oracle_provider_signature + } + +oracle_provider_id = uint +data_source_count = uint +data_signatories_count = uint +oracle_provider_signature = tstr + +; Dummy specification just for the sake of having another kind of feed. +kyc_data = #6.124(kyc_map) +Kyc_map = + { ? 0: cardano_public_key + , ? 1: nationality + , ? 2: whitelisted + } + +cardano_public_key = tstr +nationality = tstr +whitelisted = uint