From ce1a0b9bd4dcd93c462d32819c9af1cb3df8e2a7 Mon Sep 17 00:00:00 2001 From: George Flerovsky Date: Tue, 24 Jan 2023 05:44:31 -0500 Subject: [PATCH 1/8] Demote top level headers to H2 + add H1 title https://github.com/cardano-foundation/CIPs/pull/430#issuecomment-1386607038 --- CIP-????/README.md | 47 +++++++++++++++++++++++----------------------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/CIP-????/README.md b/CIP-????/README.md index 7f2e844093..4d64c2d2b5 100644 --- a/CIP-????/README.md +++ b/CIP-????/README.md @@ -15,12 +15,13 @@ Discussions: Created: 2022-11-01 License: CC-BY-4.0 --- +# CIP-????: NFT Metadata Update Oracles -# Abstract +## Abstract This proposal extends the CIP-25 standard for defining and updating token metadata via transaction metadata, by providing a new mechanism to update token metadata without having to mint or burn tokens, while maintaining full backward compatibility with CIP-25. The new mechanism is capable of expressing metadata updates more efficiently than CIP-25 updates. -# Motivation +## Motivation On Cardano’s eUTxO ledger, native tokens exist without any inherently attached metadata. The ledger does not provide a direct method for preserving any information associated with an asset class of native tokens, as transactions move the tokens from one UTxO to another. @@ -42,7 +43,7 @@ Our NFT gaming application is leveraging the Cardano immutable ledger, rather th We expect that this proposal will be useful to many other applications that need to track dynamic on-chain metadata for large NFT collections, particularly in the growing NFT gaming sector. It may also be useful for artists to update on-chain metadata about their art NFTs (e.g. royalty payment receiving address) without having to burn or mint anything. -# Specification +## Specification Our proposal extends CIP-25 with a new update mechanism: @@ -59,7 +60,7 @@ However, we recommend that CIP-???? adopters use the new metadata update mechani Our proposal only affects the `????` top-level CBOR tag of the metadata field in Cardano transactions. (Note: we’re using `????` as a stand-in for the CIP number that will eventually be assigned to this proposal.) -## Assigning a metadata oracle for a token policy ID +### Assigning a metadata oracle for a token policy ID A token metadata oracle is defined via two addresses: @@ -83,7 +84,7 @@ A metadata oracle can be explicitly assigned to a policy ID by setting the follo While a metadata oracle is not explicitly assigned to a native-script-based policy ID, the policy ID is implicitly assigned a metadata oracle with both addresses set to an address derived from the native script. Specifically, they are both set to an Enterprise address constructed by setting the payment key to the verification key from the native script and keeping the staking key empty. -## Updating an oracle assignment +### Updating an oracle assignment The metadata oracle assignment for a policy ID can be updated via a transaction signed by the oracle main address key. The transaction must only send ADA from the oracle main address to itself and must not mint any tokens, but it may contain any number of inputs and outputs. Otherwise, the transaction is ignored for the purposes of metadata oracle assignment. @@ -106,7 +107,7 @@ The `main_address` or the `update_address` fields for a `` can be omit If a metadata oracle was implicitly assigned to a policy ID before the assignment update, then the implicit assignment is replaced by the new explicit assignment. -## Simple metadata updates +### Simple metadata updates A simple metadata update transaction must only send ADA from the oracle update address to itself and must not mint any tokens, but it may contain any number of inputs and outputs. Otherwise, the transaction is ignored for the purposes of token metadata. @@ -128,7 +129,7 @@ The schema for simple metadata updates in CIP-???? is similar to the CIP-25 sche To remove a metadata field, set its value explicitly to `null` in the metadata update. -## Regex metadata updates +### Regex metadata updates The schema for regex metadata updates is as follows: @@ -170,7 +171,7 @@ The regular expression pattern in `` is defined according to the - European Computer Manufacturers Association, "ECMAScript Language Specification 5.1 Edition", ECMA Standard ECMA-262, June 2011. Section 15.10. [https://www.ecma-international.org/wp-content/uploads/ECMA-262_5.1_edition_june_2011.pdf](https://www.ecma-international.org/wp-content/uploads/ECMA-262_5.1_edition_june_2011.pdf) -## Tabular metadata updates +### Tabular metadata updates Tabular metadata updates use a condensed rectangular format to specify new values for a fixed set of fields for a large number of assets. Specifically, we use the comma-separated values (CSV) format: @@ -271,7 +272,7 @@ The CSV format is defined by the following standard: - Internet Engineering Task Force, “Common Format and MIME Type for Comma-Separated Values (CSV) Files", Request for Comments 4180, October 2005. [https://www.ietf.org/rfc/rfc4180.txt](https://www.ietf.org/rfc/rfc4180.txt) -## Order of application for updates +### Order of application for updates Up to network consensus, the Cardano blockchain imposes a total ordering on transactions added to the chain — each transaction can be indexed by the slot number of the block that added it to the chain, and the transaction’s index within that block. Network nodes may disagree about which blocks have been added most recently to the blockchain; however, the disagreement about whether a particular transaction was added at a particular position in the total order decreases exponentially as more and more blocks are added to the chain. @@ -290,7 +291,7 @@ A transaction can contain CIP-???? token metadata updates of different types, pl We recommend that token metadata oracle operators not mix multiple update types in the same transaction, unless they have a clear understanding of the outcome of applying the updates in the above sequence. -## Token metadata indexer +### Token metadata indexer The CIP-???? token metadata indexer begins with a configuration of the policy IDs for which it will be tracking metadata. Optionally, it can be configured to track metadata for all tokens on Cardano. @@ -308,7 +309,7 @@ To be able to handle blockchain rollbacks, the indexer keeps track of past metad For compatibility with existing applications that are already relying on CIP-25 metadata indexers, the CIP-???? indexer provides a similar API so that those applications can get and display the current CIP-???? token metadata in the same way that they have been for CIP-25 metadata. The indexer indicates that it is following the CIP-???? standard. -# Rationale +## Rationale We pursued the following design goals in our solution: @@ -321,7 +322,7 @@ We pursued the following design goals in our solution: 7. Minimize the time and resource usage required for an indexer to apply CIP-25 and CIP-???? updates for an asset class and then serve the resulting token metadata to applications. 8. Gracefully handle blockchain rollbacks that modify the sequence of CIP-25 and CIP-???? metadata updates for an asset class. -## Backward compatibility +### Backward compatibility We maintain full backward compatibility with CIP-25: @@ -329,13 +330,13 @@ We maintain full backward compatibility with CIP-25: - CIP-???? updates are namespaced under a different top-level CBOR tag than CIP-25, in order to prevent any clashes between field names, policy IDs, and token names. - The CIP-???? indexer provides the accumulated CIP-25 and CIP-???? metadata via the same API as the CIP-25 indexer. -## Using an assigned oracle for token metadata updates +### Using an assigned oracle for token metadata updates We recognize CIP-???? updates only if they are issued by an oracle currently assigned for the corresponding policy IDs. This assignment is either directly authorized by the token issuer (explicitly or implicitly) or else indirectly authorized by the token issuer via the delegated authority that the token issuer placed in the originally assigned oracle to transfer the assignment to other oracles. Therefore, all authority to post valid CIP-???? updates about a token originates from the token issuer. An alternative design could have oracles that declare themselves as sources of metadata for tokens, without authorization from anyone, and then users could voluntarily subscribe to the metadata oracles that they wish to follow. However, such an approach would make it very difficult for the Cardano ecosystem to converge on a single objective metadata state for a token, as each user would have his own subjective view of token metadata based on his oracles subscriptions. This alternative approach could be interesting to allow secondary/auxiliary metadata to be defined for tokens, but it is unsuitable for the primary metadata that CIP-25 and CIP-???? seek to manage. -## Identifying oracles by addresses +### Identifying oracles by addresses We use two addresses to identify an oracle when assigning it to a policy ID. It would be simpler to use a single oracle address, but we chose to separate the main address (authorized to reassign the oracle) from the update address (authorized to post updates) for an oracle. We did this to mitigate the risk of using the update address in an automated process on a network machine, and to allow the update address to be safely rotated via a transaction that can only be signed on a cold storage or hardware wallet device using the main address. @@ -343,35 +344,35 @@ Instead of using addresses to identify oracles, we could have identified oracles This minting-policy-based alternative for identifying oracles may be more advantageous for more flexibly managing oracle authorization (including rate-limiting, time-boxing, etc.) and proving data provenance to on-chain scripts. These advantages are relevant for oracles that provide information in utxo datums meant for use in smart contracts, but they are not as relevant for this CIP, where we seek to provide a method to provide updateable token metadata via transaction metadata (as a direct extension of CIP-25). Furthermore, it is easier to track transactions originating from a given address in an indexer than to keep track of all the people who control various authorization tokens, at a given time. -## Restricting CIP-???? update transactions +### Restricting CIP-???? update transactions We prohibit CIP-???? oracle assignment updates and metadata updates from occurring in transactions that mint tokens, in order to avoid awkward clashes with CIP-25 metadata transactions. Also, it does not make sense conceptually for CIP-25 metadata transactions to coincide with CIP-???? updates. CIP-25 should be used to define the initial metadata for an asset class, and then CIP-???? updates should be used for any subsequent changes to that metadata. We require CIP-???? updates to occur in transactions that only send ADA from an oracle address (main or update, as appropriate), to prevent unforeseen interactions with other mechanisms that may have negative consequences. CIP-???? update transactions should have the singular purpose of interacting with the CIP-???? update mechanism. -## Implicit oracle assignment +### Implicit oracle assignment The implicit method of assigning a metadata oracle is needed to allow existing token issuers to opt into the CIP-???? update mechanism. Their minting policies may no longer allow any more token minting or burning, which would prevent the token issuers from being able to explicitly assign an oracle via a CIP-25 update for those policies. The implicit assignment method bootstraps the CIP-???? update mechanism for these policies. The implicit address is of the Enterprise address type, to avoid having to deal with staking keys. If needed, the metadata oracle operator can send ADA to the Enterprise address, and then spend it if the operator still controls the payment key of that Enterprise address. -## Opting out of CIP-???? +### Opting out of CIP-???? Opting out of the CIP-???? update mechanism can be done by explicitly assigning an oracle with addresses from which ADA cannot be spent (e.g. Plutus AlwaysFails). If the minting policy does not allow any more minting or burning, then this is an irreversible opt-out. -## Regex metadata updates +### Regex metadata updates When managing large collections of thousands of NFTs, one often needs to set a given field to the same value for many NFTs. Doing this individually for each NFT via CIP-25 updates or CIP-???? simple updates is inefficient, so we have proposed the regex metadata update as a succinct way to specify a mapping from multiple token names to a single metadata update. -## Tabular metadata updates +### Tabular metadata updates Another common use case for dynamic token metadata involves having a set of volatile fields that should receive relatively frequent updates, but where those updates should be different for each NFT. Labeling each field value update with its field name for each NFT is very verbose, especially if the field is deeply nested within the metadata schema for the NFT. For this use case, we have proposed the tabular metadata update format as a way to avoid this repetition — field names/paths are defined once in the column names of a rectangular table and applied consistently for each row of updated metadata field values. Rectangular tables are a standard format used in the data analytics field for these situations, and the CSV format is the most widely used and interoperable rectangular data format. -# Path to Active +## Path to Active -## Acceptance Criteria +### Acceptance Criteria This proposal may be considered active if: @@ -379,7 +380,7 @@ This proposal may be considered active if: 2. The indexer and simple tools to construct CIP-???? update transactions (as described in the [Specification](https://www.notion.so/Specification-2cdbc357edda4b08b581b25d63968e3c) section) are fully implemented and provided in an open-source (Apache 2.0 licensed) repository with sufficient documentation. 3. The CIP-???? metadata format, indexer, and/or indexer API are used by several stakeholders in the Cardano ecosystem, including dApps, blockchain explorers, analytics platforms, etc. -## Implementation Plan +### Implementation Plan Equine and MLabs are collaborating on developing the indexer described in this CIP and the Equine NFT gaming application will be using CIP-???? updates to manage metadata updates for its large collection of thousands of NFTs under multiple minting policies. @@ -387,7 +388,7 @@ We will include detailed documentation, example configurations, and tutorials on We are actively engaged in discussions with other stakeholders in the Cardano ecosystem that are interested in adopting this CIP to their projects, platforms, and tools. -# Copyright +## Copyright This CIP is licensed under the Creative Commons Attribution 4.0 International Public License ([CC-BY-4.0](https://creativecommons.org/licenses/by/4.0/legalcode)). From 7a3c2170b5585f22ba479a4262eeaf17d281f59e Mon Sep 17 00:00:00 2001 From: George Flerovsky Date: Tue, 24 Jan 2023 05:49:12 -0500 Subject: [PATCH 2/8] Fix internal section links https://github.com/cardano-foundation/CIPs/pull/430#discussion_r1084572077 --- CIP-????/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CIP-????/README.md b/CIP-????/README.md index 4d64c2d2b5..a0c8a50530 100644 --- a/CIP-????/README.md +++ b/CIP-????/README.md @@ -301,7 +301,7 @@ The indexer continues to monitor minting transactions for the policy IDs that it For each oracle main address currently assigned to a policy ID, the indexer monitors the blockchain for non-minting transactions that only send ADA from the oracle main address to itself and contain oracle assignment updates in their metadata. The indexer updates its database to reflect these explicit oracle assignments and removes any implicit assignments that were replaced by explicit assignments. -For each oracle update address currently assigned to a policy ID, the indexer monitors the blockchain for non-minting transactions that only send ADA from the oracle update address to itself and contain CIP-???? token metadata updates. The indexer applies these metadata updates in the order defined in [Order of application for updates](https://www.notion.so/Order-of-application-for-updates-07b8a74001c9484698f400f9c5e1c7c8). CIP-???? metadata updates are applied to the asset classes and metadata fields that they target, while keeping all other fields the same. +For each oracle update address currently assigned to a policy ID, the indexer monitors the blockchain for non-minting transactions that only send ADA from the oracle update address to itself and contain CIP-???? token metadata updates. The indexer applies these metadata updates in the order defined in [Order of application for updates](#order-of-application-for-updates). CIP-???? metadata updates are applied to the asset classes and metadata fields that they target, while keeping all other fields the same. For tabular metadata updates, the bytestring CSV value may get broken up into an array of bytestring chunks in the CBOR representation. When this happens, the indexer recombines the chunks into the whole CSV table before applying the tabular metadata update. @@ -376,8 +376,8 @@ Rectangular tables are a standard format used in the data analytics field for th This proposal may be considered active if: -1. The solution meets the design goals listed in the [Rationale](https://www.notion.so/Rationale-4c5ae115646841539e734672fd67ba22) section to a satisfactory degree. -2. The indexer and simple tools to construct CIP-???? update transactions (as described in the [Specification](https://www.notion.so/Specification-2cdbc357edda4b08b581b25d63968e3c) section) are fully implemented and provided in an open-source (Apache 2.0 licensed) repository with sufficient documentation. +1. The solution meets the design goals listed in the [Rationale](#rationale) section to a satisfactory degree. +2. The indexer and simple tools to construct CIP-???? update transactions (as described in the [Specification](#specification) section) are fully implemented and provided in an open-source (Apache 2.0 licensed) repository with sufficient documentation. 3. The CIP-???? metadata format, indexer, and/or indexer API are used by several stakeholders in the Cardano ecosystem, including dApps, blockchain explorers, analytics platforms, etc. ### Implementation Plan From b9a38a45a03d80d81a1b2d7acb6b65e8adc14ae2 Mon Sep 17 00:00:00 2001 From: George Flerovsky Date: Tue, 24 Jan 2023 05:55:00 -0500 Subject: [PATCH 3/8] Fix link/code typos --- CIP-????/README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CIP-????/README.md b/CIP-????/README.md index a0c8a50530..62c315b6a2 100644 --- a/CIP-????/README.md +++ b/CIP-????/README.md @@ -8,8 +8,8 @@ Authors: - George Flerovsky - Samuel Williams Implementors: - - Equine <[https://www.equine.gg/](https://www.equine.gg/)> - - MLabs <[https://mlabs.city/](https://mlabs.city/)> + - Equine + - MLabs Discussions: - https://github.com/cardano-foundation/CIPs/pull/430 Created: 2022-11-01 @@ -180,6 +180,7 @@ Tabular metadata updates use a condensed rectangular format to specify new value "????": { "tabular_metadata_update": { "": "" + } } } ``` From 2cd9ee7ebf99f68bda8600ceb79efcbc6612097c Mon Sep 17 00:00:00 2001 From: George Flerovsky Date: Tue, 24 Jan 2023 09:15:14 -0500 Subject: [PATCH 4/8] Add CDDL draft file --- CIP-????/cddl/main.cddl | 136 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 CIP-????/cddl/main.cddl diff --git a/CIP-????/cddl/main.cddl b/CIP-????/cddl/main.cddl new file mode 100644 index 0000000000..f2bc3e1f6a --- /dev/null +++ b/CIP-????/cddl/main.cddl @@ -0,0 +1,136 @@ +; "????" to be replaced by the CIP number, as a `uint`. +metadata = { ???? : uint => label_metadata } + +; ========================================================================= +; CIP-???? actions +action = + { + ? assign_metadata_oracle : action_oracle, + ? simple_metadata_update : action_simple, + ? regex_metadata_update : action_regex, + ? tabular_metadata_update : action_tabular + } + +action_oracle = { * policy_id => oracle_assignment } + +oracle_assignment = + { + ? main_address : address, + ? update_address : address + } + +action_simple = { * policy_id => { * asset_name => metadata_details } } + +action_regex = { * policy_id => { * asset_regex => metadata_details } } + +action_tabular = { * policy_id => csv_update_opaque } + +; Either fixed-sized text (CIP-25v1) or fixed-sized bytes (CIP-25v2) +; The CIP-???? indexer should normalize all labels to bytes internally. +; It can also provide an API option to format labels as text in its +; response to a client request for current token metadata, if possible. +policy_id = label_64 +asset_name = label_64 +asset_regex = regex_64 + +; ========================================================================= +; Backwards compatibility with CIP-25 (simple and regex metadata updates) +; Definitions for the following fields in `metadata_details` should follow +; the same schema as in CIP-25. +; Other fields can have arbitrary `transaction_metadatum` values. +metadata_details = + { + ? name : text_64, + ? image : text_extendable, + ? mediaType : text_64, + ? description : text_extendable, + ? files : [* files_details], + * (label_64 => transaction_metadatum) + } + +files_details = + { + name : text_64, + mediaType : text_64, + src : text_extendable + } + +; ========================================================================= +; Tabular updates' CSV schema + +; Cardano ledger imposes a fixed size of 64 on text and bytestrings, +; which prevents us from directly encoding a CSV table as a single long +; text. This means that, formally, the CSV in a tabular update +; is just an opaque extendable text (i.e. a fixed text or an array of fixed +; texts). +csv_update_opaque = text_extendable + +; Informally, if we concatenate the `csv_update_opaque` value to a single long +; text, and then split it on unescaped newline characters, +; then it should comply with the following cddl schema. +; (Newline characters inside of a double-quoted field value are considered +; escaped, which means that they do no indicate the start of a new record.) +; +; csv_update = [header, * record] +; header = ["tokenName", * header_field] +; record = [text_64, * record_field] +; header_field = text +; record_field = text + +; For a given `policy_id`, a `csv_update` value can be transformed into a +; `metadata_details` value as follows: +; 1. Pair each `record_field` with its corresponding `header_field` +; (i.e. like zipping two lists). +; 2. Transform each `header_field` into a `[header_field_part]` array, by +; splitting it on the '.' character. +; 3. For each pair of `record_field` and `[header_field_part]` values, construct +; the following nested object: +; csv_nested_object = { header_field_part[0] => +; { header_field_part[1] => +; { header_field_part[2] => +; ... +; { header_field_part[N] => `record_field` } +; ... +; } +; } +; } +; 4. For each record, combine and normalize its record fields' constructed +; nested objects into a single unified object for that record. Nest the +; unified object under the record's "tokenName" value: +; csv_record_object = { text_64 => Union([csv_nested_object]) } +; 5. Unify the `record_object`s into a single object, and then nest it under +; the `policy_id`: +; csv_policy_object = { policy_id => Union([csv_record_object]) } +; 6. Combine the `action_simple_single` values into a single `action_simple` +; value: +; csv_update_simple = Union([csv_policy_object]) +; +; The effect of a `csv_update_opaque` on the token metadata state in the +; CIP-???? indexer must be the same as the effect of the corresponding +; `csv_update_simple`. + +; ========================================================================= +; Imported from cardano-ledger/.../babbage.cddl +transaction_metadatum = + { * transaction_metadatum => transaction_metadatum } + / [ * transaction_metadatum ] + / int + / bytes_64 + / text_64 + +address = bytes + +; ========================================================================= +; Convenient type aliases + +regex_64 = bytes_64 .regexp + +; Fixed-size text and bytes +label_64 = bytes_64 / text_64 + +bytes_64 = bytes .size (0..64) +text_64 = text .size (0..64) + +text_extendable = text_64 / [ * text_64 ] +bytes_extendable = bytes_64 / [ * bytes 64] + From 0042fa182a65446af95c136a7b33ab55fa9bac6e Mon Sep 17 00:00:00 2001 From: George Flerovsky Date: Tue, 24 Jan 2023 14:40:19 -0500 Subject: [PATCH 5/8] Isolate CDDL for text-based (policy_id,asset_name) This corresponds to the CIP-25's version_1.cddl. --- CIP-????/cddl/{main.cddl => version_1.cddl} | 73 +++++++++++++-------- 1 file changed, 45 insertions(+), 28 deletions(-) rename CIP-????/cddl/{main.cddl => version_1.cddl} (68%) diff --git a/CIP-????/cddl/main.cddl b/CIP-????/cddl/version_1.cddl similarity index 68% rename from CIP-????/cddl/main.cddl rename to CIP-????/cddl/version_1.cddl index f2bc3e1f6a..24464178ce 100644 --- a/CIP-????/cddl/main.cddl +++ b/CIP-????/cddl/version_1.cddl @@ -1,8 +1,9 @@ ; "????" to be replaced by the CIP number, as a `uint`. -metadata = { ???? : uint => label_metadata } +metadata = { ???? => action } ; ========================================================================= ; CIP-???? actions + action = { ? assign_metadata_oracle : action_oracle, @@ -25,18 +26,19 @@ action_regex = { * policy_id => { * asset_regex => metadata_details } } action_tabular = { * policy_id => csv_update_opaque } -; Either fixed-sized text (CIP-25v1) or fixed-sized bytes (CIP-25v2) -; The CIP-???? indexer should normalize all labels to bytes internally. -; It can also provide an API option to format labels as text in its -; response to a client request for current token metadata, if possible. -policy_id = label_64 -asset_name = label_64 -asset_regex = regex_64 +; Technically, both policy IDs and asset names should be 32 bytes long. +; However, this isn't enforced for asset names, and CIP-25 already treats +; these as `text_64`, so we don't enforce the more narrow `bytes_32` type +; here. +policy_id = text_64 +asset_name = text_64 + +asset_regex = text_regex_extendable ; ========================================================================= ; Backwards compatibility with CIP-25 (simple and regex metadata updates) ; Definitions for the following fields in `metadata_details` should follow -; the same schema as in CIP-25. +; the same schema as in CIP-25, except that `name` and `image` are optional. ; Other fields can have arbitrary `transaction_metadatum` values. metadata_details = { @@ -66,16 +68,15 @@ files_details = csv_update_opaque = text_extendable ; Informally, if we concatenate the `csv_update_opaque` value to a single long -; text, and then split it on unescaped newline characters, -; then it should comply with the following cddl schema. +; text, and then split it on unescaped newline characters, then it should comply +; with the following cddl schema. ; (Newline characters inside of a double-quoted field value are considered ; escaped, which means that they do no indicate the start of a new record.) -; -; csv_update = [header, * record] -; header = ["tokenName", * header_field] -; record = [text_64, * record_field] -; header_field = text -; record_field = text +csv_update = [header, * record] +header = ["tokenName", * header_field] +record = [text_64, * record_field] +header_field = text +record_field = text ; For a given `policy_id`, a `csv_update` value can be transformed into a ; `metadata_details` value as follows: @@ -85,15 +86,16 @@ csv_update_opaque = text_extendable ; splitting it on the '.' character. ; 3. For each pair of `record_field` and `[header_field_part]` values, construct ; the following nested object: -; csv_nested_object = { header_field_part[0] => -; { header_field_part[1] => -; { header_field_part[2] => -; ... -; { header_field_part[N] => `record_field` } -; ... +; csv_nested_object = +; { header_field_part[0] => +; { header_field_part[1] => +; { header_field_part[2] => +; ... +; { header_field_part[N] => `record_field` } +; ... +; } ; } ; } -; } ; 4. For each record, combine and normalize its record fields' constructed ; nested objects into a single unified object for that record. Nest the ; unified object under the record's "tokenName" value: @@ -107,7 +109,7 @@ csv_update_opaque = text_extendable ; ; The effect of a `csv_update_opaque` on the token metadata state in the ; CIP-???? indexer must be the same as the effect of the corresponding -; `csv_update_simple`. +; `csv_update_simple` (applied as a simple update action). ; ========================================================================= ; Imported from cardano-ledger/.../babbage.cddl @@ -123,14 +125,29 @@ address = bytes ; ========================================================================= ; Convenient type aliases -regex_64 = bytes_64 .regexp - ; Fixed-size text and bytes -label_64 = bytes_64 / text_64 +label_32 = bytes_32 / text_32 +bytes_32 = bytes .size (0..32) +text_32 = bytes .size (0..32) +label_64 = bytes_64 / text_64 bytes_64 = bytes .size (0..64) text_64 = text .size (0..64) +; Extendable text and bytes text_extendable = text_64 / [ * text_64 ] bytes_extendable = bytes_64 / [ * bytes 64] +; Regex (fixed-size) +; Tag 35 is for regular expressions in Perl Compatible Regular +; Expressions (PCRE) / JavaScript syntax [ECMA262]. +; https://www.rfc-editor.org/rfc/rfc7049#section-2.4.4.3 +; https://www.ecma-international.org/publications-and-standards/standards/ecma-262/ +text_regex = #6.35(text_64) + +; Regex (extendable size) +; Technically, CBOR maps can have arrays as keys. This prevents them from being +; directly convertable to JSON, but we can recover JSON-convertability by +; concatenating the array-valued key into a single UTF-8 text. +; The resulting concatenated text should be interpreted as `#6.35(text)`. +text_regex_extendable = text_extendable From 839218ccabbfde30257077f8e33706cc90e475de Mon Sep 17 00:00:00 2001 From: George Flerovsky Date: Tue, 24 Jan 2023 14:52:48 -0500 Subject: [PATCH 6/8] Add support for bytestring (policy_id, asset_name) This corresponds to CIP-25's version_2.cddl. Note that regex and tabular updates are not supported under this version 2 mode. --- CIP-????/cddl/version_1.cddl | 12 ++--- CIP-????/cddl/version_2.cddl | 85 ++++++++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+), 6 deletions(-) create mode 100644 CIP-????/cddl/version_2.cddl diff --git a/CIP-????/cddl/version_1.cddl b/CIP-????/cddl/version_1.cddl index 24464178ce..069d69fe2d 100644 --- a/CIP-????/cddl/version_1.cddl +++ b/CIP-????/cddl/version_1.cddl @@ -27,7 +27,7 @@ action_regex = { * policy_id => { * asset_regex => metadata_details } } action_tabular = { * policy_id => csv_update_opaque } ; Technically, both policy IDs and asset names should be 32 bytes long. -; However, this isn't enforced for asset names, and CIP-25 already treats +; However, this isn't enforced for asset names, and CIP-25v1 already treats ; these as `text_64`, so we don't enforce the more narrow `bytes_32` type ; here. policy_id = text_64 @@ -47,7 +47,7 @@ metadata_details = ? mediaType : text_64, ? description : text_extendable, ? files : [* files_details], - * (label_64 => transaction_metadatum) + * ( label_64 => transaction_metadatum ) } files_details = @@ -72,9 +72,9 @@ csv_update_opaque = text_extendable ; with the following cddl schema. ; (Newline characters inside of a double-quoted field value are considered ; escaped, which means that they do no indicate the start of a new record.) -csv_update = [header, * record] -header = ["tokenName", * header_field] -record = [text_64, * record_field] +csv_update = [ header, * record ] +header = [ "tokenName", * header_field ] +record = [ text_64, * record_field ] header_field = text record_field = text @@ -136,7 +136,7 @@ text_64 = text .size (0..64) ; Extendable text and bytes text_extendable = text_64 / [ * text_64 ] -bytes_extendable = bytes_64 / [ * bytes 64] +bytes_extendable = bytes_64 / [ * bytes 64 ] ; Regex (fixed-size) ; Tag 35 is for regular expressions in Perl Compatible Regular diff --git a/CIP-????/cddl/version_2.cddl b/CIP-????/cddl/version_2.cddl new file mode 100644 index 0000000000..353b5671ab --- /dev/null +++ b/CIP-????/cddl/version_2.cddl @@ -0,0 +1,85 @@ +; "????" to be replaced by the CIP number, as a `uint`. +metadata = { ???? => action } + +; ========================================================================= +; CIP-???? actions + +; When version 2 mode is enabled for a CIP-???? action, all `policy_id` and +; `asset_name` values are interpreted as `bytes_64`, similar to CIP-25v2. +action = + { + version = 2, + ? assign_metadata_oracle : action_oracle, + ? simple_metadata_update : action_simple, + } + +; Regex and tabular updates are disallowed in version 2, because it is unclear +; how to apply regular expressions to non-UTF-8 bytestrings (or their +; corresponding hex encodings) and it is unclear how to embed raw bytestrings +; in CSV. + +action_oracle = { * policy_id => oracle_assignment } + +oracle_assignment = + { + ? main_address : address, + ? update_address : address + } + +action_simple = { * policy_id => { * asset_name => metadata_details } } + +; Technically, both policy IDs and asset names should be 32 bytes long. +; However, this isn't enforced for asset names, and CIP-25v2 already treats +; these as `bytes_64`, so we don't enforce the more narrow `bytes_32` type +; here. +policy_id = bytes_64 +asset_name = bytes_64 + +; ========================================================================= +; Backwards compatibility with CIP-25 (simple and regex metadata updates) +; Definitions for the following fields in `metadata_details` should follow +; the same schema as in CIP-25, except that `name` and `image` are optional. +; Other fields can have arbitrary `transaction_metadatum` values. +metadata_details = + { + ? name : text_64, + ? image : text_extendable, + ? mediaType : text_64, + ? description : text_extendable, + ? files : [* files_details], + * ( label_64 => transaction_metadatum ) + } + +files_details = + { + name : text_64, + mediaType : text_64, + src : text_extendable + } + +; ========================================================================= +; Imported from cardano-ledger/.../babbage.cddl +transaction_metadatum = + { * transaction_metadatum => transaction_metadatum } + / [ * transaction_metadatum ] + / int + / bytes_64 + / text_64 + +address = bytes + +; ========================================================================= +; Convenient type aliases + +; Fixed-size text and bytes +label_32 = bytes_32 / text_32 +bytes_32 = bytes .size (0..32) +text_32 = bytes .size (0..32) + +label_64 = bytes_64 / text_64 +bytes_64 = bytes .size (0..64) +text_64 = text .size (0..64) + +; Extendable text and bytes +text_extendable = text_64 / [ * text_64 ] +bytes_extendable = bytes_64 / [ * bytes 64 ] From 2fc06b668453f9a59a0f82895d264e0aa46381cf Mon Sep 17 00:00:00 2001 From: Nicolas Ayotte Date: Tue, 24 Jan 2023 22:09:18 -0500 Subject: [PATCH 7/8] Update version_1.cddl typo in text_32 definition --- CIP-????/cddl/version_1.cddl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CIP-????/cddl/version_1.cddl b/CIP-????/cddl/version_1.cddl index 069d69fe2d..8126221444 100644 --- a/CIP-????/cddl/version_1.cddl +++ b/CIP-????/cddl/version_1.cddl @@ -128,7 +128,7 @@ address = bytes ; Fixed-size text and bytes label_32 = bytes_32 / text_32 bytes_32 = bytes .size (0..32) -text_32 = bytes .size (0..32) +text_32 = text .size (0..32) label_64 = bytes_64 / text_64 bytes_64 = bytes .size (0..64) From 182ccd127147bfddbf71eee0373bd21cd833deb9 Mon Sep 17 00:00:00 2001 From: Nicolas Ayotte Date: Tue, 24 Jan 2023 22:09:40 -0500 Subject: [PATCH 8/8] Update version_2.cddl typo in text_32 definition --- CIP-????/cddl/version_2.cddl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CIP-????/cddl/version_2.cddl b/CIP-????/cddl/version_2.cddl index 353b5671ab..99e7eb15a1 100644 --- a/CIP-????/cddl/version_2.cddl +++ b/CIP-????/cddl/version_2.cddl @@ -74,7 +74,7 @@ address = bytes ; Fixed-size text and bytes label_32 = bytes_32 / text_32 bytes_32 = bytes .size (0..32) -text_32 = bytes .size (0..32) +text_32 = text .size (0..32) label_64 = bytes_64 / text_64 bytes_64 = bytes .size (0..64)