diff --git a/CIP-????/cddl/version_1.cddl b/CIP-????/cddl/version_1.cddl new file mode 100644 index 0000000000..8126221444 --- /dev/null +++ b/CIP-????/cddl/version_1.cddl @@ -0,0 +1,153 @@ +; "????" to be replaced by the CIP number, as a `uint`. +metadata = { ???? => action } + +; ========================================================================= +; 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 } + +; Technically, both policy IDs and asset names should be 32 bytes long. +; 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 +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, 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 + } + +; ========================================================================= +; 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` (applied as a simple update action). + +; ========================================================================= +; 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 = text .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 diff --git a/CIP-????/cddl/version_2.cddl b/CIP-????/cddl/version_2.cddl new file mode 100644 index 0000000000..99e7eb15a1 --- /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 = text .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 ]