Skip to content

Commit 264170d

Browse files
CIP-0068 | Support multi-asset metadata a la CIP-0025 (#1112)
Add version 4 metadata support with 721-ERC-style mappings to NFT (222), FT (333) and RFT (444) standards, ensuring consistency across all asset classes. Changes: - Add metadata_field union type supporting both direct and 721-map formats - Add __RESERVE_KEYWORD_721_V4__ marker for 721-style detection - Update retrieval steps to handle both metadata formats - Support version 4 in FT standard - Support version 3/4 in RFT standard - Add 721-style JSON example for NFT standard - Update pattern descriptions with asset_name terminology - Fix URI support to include [* bounded_bytes] for RFT
1 parent 22b4636 commit 264170d

File tree

1 file changed

+142
-22
lines changed

1 file changed

+142
-22
lines changed

CIP-0068/README.md

Lines changed: 142 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -155,16 +155,20 @@ The `user token` represents an NFT (non-fungible token).
155155

156156
##### Pattern
157157

158-
The `user token` and `reference NFT` MUST have an identical name, preceded by the `asset_name_label` prefix.
158+
The `user token` and `reference NFT` MUST have an identical name (heretofore entitled `asset_name`), preceded by the `asset_name_label` prefix.
159159

160160
Example:\
161161
`user token`: `(222)Test123`\
162162
`reference NFT`: `(100)Test123`
163163

164164
##### Metadata
165165

166-
This is a low-level representation of the metadata, following closely the structure of CIP-0025. All UTF-8 encoded keys
167-
and values need to be converted into their respective byte's representation when creating the datum on-chain.
166+
This is either:
167+
168+
1. A low-level direct representation of the metadata, following closely the structure of CIP-0025
169+
2. A 721-ERC-style token mapping exactly matching the structure of CIP-0025
170+
171+
All UTF-8 encoded keys and values need to be converted into their respective byte's representation when creating the datum on-chain.
168172

169173
```
170174
files_details =
@@ -188,6 +192,26 @@ metadata =
188192
; ... Additional properties are allowed
189193
}
190194
195+
metadata_map =
196+
{
197+
__RESERVE_KEYWORD_721_V4__ : bool, ; Long name to avoid conflict
198+
199+
"721":
200+
{
201+
; As many of the below as needed based on which reference tokens are added
202+
"<policy_id>":
203+
{
204+
"<asset_name_1>" : metadata,
205+
; ...
206+
"<asset_name_n>" : metadata,
207+
}
208+
}
209+
}
210+
211+
metadata_field =
212+
metadata ; For backwards-compatibility in v4 onward, a map itself is valid metadata
213+
/ metadata_map ; Multi-metadata is now supported as in CIP-0025
214+
191215
; A valid Uniform Resource Identifier (URI) as a UTF-8 encoded bytestring.
192216
; The URI scheme must be one of `https` (HTTP), `ipfs` (IPFS), `ar` (Arweave) or `data` (on-chain).
193217
; Data URLs (on-chain data) must comply to RFC2397.
@@ -198,12 +222,12 @@ uri = bounded_bytes / [ * bounded_bytes ] ; UTF-8
198222
; and needs to be at least Unit/Void: #6.121([])
199223
extra = plutus_data
200224
201-
datum = #6.121([metadata, version, extra])
225+
datum = #6.121([metadata_field, version, extra])
202226
203-
version = 1 / 2 / 3
227+
version = 1 / 2 / 3 / 4
204228
```
205229

206-
Example datum as JSON:
230+
Example datum as JSON (direct metadata):
207231

208232
```json
209233
{
@@ -236,6 +260,45 @@ Example datum as JSON:
236260
}
237261
```
238262

263+
Example datum as JSON (721-style):
264+
265+
```json
266+
{
267+
"constructor": 0,
268+
"fields": [
269+
{
270+
"map": [
271+
{
272+
"k": { "bytes": "373231" },
273+
"v": {
274+
"map": [
275+
{
276+
"k": { "bytes": "5370616365427564204131" },
277+
"v": {
278+
"map": [
279+
{
280+
"k": { "bytes": "6E616D65" },
281+
"v": { "bytes": "5370616365427564" }
282+
},
283+
{
284+
"k": { "bytes": "696D616765" },
285+
"v": { "bytes": "697066733A2F2F74657374" }
286+
}
287+
]
288+
}
289+
}
290+
]
291+
}
292+
}
293+
]
294+
},
295+
{
296+
"int": 4
297+
}
298+
]
299+
}
300+
```
301+
239302
##### Retrieve metadata as 3rd party
240303

241304
A third party has the following NFT `d5e6bf0500378d4f0da4e8dde6becec7621cd8cbf5cbb9b87013d4cc.(222)TestToken` they want
@@ -244,7 +307,9 @@ to lookup. The steps are
244307
1. Construct `reference NFT` from `user token`: `d5e6bf0500378d4f0da4e8dde6becec7621cd8cbf5cbb9b87013d4cc.(100)TestToken`
245308
2. Look up `reference NFT` and find the output it's locked in.
246309
3. Get the datum from the output and lookup metadata by going into the first field of constructor 0.
247-
4. Convert to JSON and encode all string entries to UTF-8 if possible, otherwise leave them in hex.
310+
4. Determine whether this is a direct metadata or the CIP-0025 map style using the `__RESERVE_KEYWORD_721_V4__` map value (if present, default false)
311+
5. Convert to JSON and encode all string entries to UTF-8 if possible, otherwise leave them in hex.
312+
6. For multi-map style metadata, return only the JSON values inside the matching path: `721`->>`policy_id`->>`asset_name`
248313

249314
##### Retrieve metadata from a Plutus validator
250315

@@ -274,17 +339,20 @@ The `user token` is an FT (fungible token).
274339

275340
##### Pattern
276341

277-
The `user token` and `reference NFT` MUST have an identical name, preceded by the `asset_name_label` prefix.
342+
The `user token` and `reference NFT` MUST have an identical name (heretofore called `asset_name`), preceded by the `asset_name_label` prefix.
278343

279344
Example:\
280345
`user token`: `(333)Test123`\
281346
`reference NFT`: `(100)Test123`
282347

283348
##### Metadata
284349

285-
This is a low-level representation of the metadata, following closely the structure of the Cardano foundation off-chain
286-
metadata registry. All UTF-8 encoded keys and values need to be converted into their respective byte's representation
287-
when creating the datum on-chain.
350+
This is either:
351+
352+
1. A low-level direct representation of the metadata, following closely the structure of the Cardano foundation off-chain metadata registry
353+
2. A 721-ERC-style token mapping exactly matching the structure of CIP-0025
354+
355+
All UTF-8 encoded keys and values need to be converted into their respective byte's representation when creating the datum on-chain.
288356

289357
```
290358
; Explanation here: https://developers.cardano.org/docs/native-tokens/token-registry/cardano-token-registry/
@@ -304,6 +372,26 @@ metadata =
304372
; ... Additional properties are allowed
305373
}
306374
375+
metadata_map =
376+
{
377+
__RESERVE_KEYWORD_721_V4__ : bool, ; Long name to avoid conflict
378+
379+
"721":
380+
{
381+
; As many of the below as needed based on which reference tokens are added
382+
"<policy_id>":
383+
{
384+
"<asset_name_1>" : metadata,
385+
; ...
386+
"<asset_name_n>" : metadata,
387+
}
388+
}
389+
}
390+
391+
metadata_field =
392+
metadata ; For backwards-compatibility in v4 onward, a map itself is valid metadata
393+
/ metadata_map ; Multi-metadata is now supported as in CIP-0025
394+
307395
; A valid Uniform Resource Identifier (URI) as a UTF-8 encoded bytestring.
308396
; The URI scheme must be one of `https` (HTTP), `ipfs` (IPFS), `ar` (Arweave) or `data` (on-chain).
309397
; Data URLs (on-chain data) must comply to RFC2397.
@@ -314,9 +402,9 @@ uri = bounded_bytes / [ * bounded_bytes ] ; UTF-8
314402
; and needs to be at least Unit/Void: #6.121([])
315403
extra = plutus_data
316404
317-
datum = #6.121([metadata, version, extra])
405+
datum = #6.121([metadata_field, version, extra])
318406
319-
version = 1 / 2 / 3
407+
version = 1 / 2 / 3 / 4
320408
```
321409

322410
Example datum as JSON:
@@ -360,7 +448,9 @@ to lookup. The steps are
360448
1. Construct `reference NFT` from `user token`: `d5e6bf0500378d4f0da4e8dde6becec7621cd8cbf5cbb9b87013d4cc.(100)TestToken`
361449
2. Look up `reference NFT` and find the output it's locked in.
362450
3. Get the datum from the output and lookup metadata by going into the first field of constructor 0.
363-
4. Convert to JSON and encode all string entries to UTF-8 if possible, otherwise leave them in hex.
451+
4. Determine whether this is a direct metadata or the CIP-0025 map style using the `__RESERVE_KEYWORD_721_V4__` map value (if present, default false)
452+
5. Convert to JSON and encode all string entries to UTF-8 if possible, otherwise leave them in hex.
453+
6. For multi-map style metadata, return only the JSON values inside the matching path: `721`->>`policy_id`->>`asset_name`
364454

365455
##### Retrieve metadata from a Plutus validator
366456

@@ -403,9 +493,12 @@ Example:\
403493

404494
##### Metadata
405495

406-
This is a low-level representation of the metadata, following closely the structure of CIP-0025 with the optional
407-
decimals field added. All UTF-8 encoded keys and values need to be converted into their respective byte's representation
408-
when creating the datum on-chain.
496+
This is either:
497+
498+
1. A low-level direct representation of the metadata, following closely the structure of CIP-0025 with the optional decimals field added
499+
2. A 721-ERC-style token mapping exactly matching the structure of CIP-0025
500+
501+
All UTF-8 encoded keys and values need to be converted into their respective byte's representation when creating the datum on-chain.
409502

410503
```
411504
files_details =
@@ -430,19 +523,39 @@ metadata =
430523
; ... Additional properties are allowed
431524
}
432525
526+
metadata_map =
527+
{
528+
__RESERVE_KEYWORD_721_V4__ : bool, ; Long name to avoid conflict
529+
530+
"721":
531+
{
532+
; As many of the below as needed based on which reference tokens are added
533+
"<policy_id>":
534+
{
535+
"<asset_name_1>" : metadata,
536+
; ...
537+
"<asset_name_n>" : metadata,
538+
}
539+
}
540+
}
541+
542+
metadata_field =
543+
metadata ; For backwards-compatibility in v4 onward, a map itself is valid metadata
544+
/ metadata_map ; Multi-metadata is now supported as in CIP-0025
545+
433546
; A valid Uniform Resource Identifier (URI) as a UTF-8 encoded bytestring.
434547
; The URI scheme must be one of `https` (HTTP), `ipfs` (IPFS), `ar` (Arweave) or `data` (on-chain).
435548
; Data URLs (on-chain data) must comply to RFC2397.
436-
uri = bounded_bytes ; UTF-8
549+
uri = bounded_bytes / [ * bounded_bytes ] ; UTF-8
437550
438551
; Custom user defined plutus data.
439552
; Setting data is optional, but the field is required
440553
; and needs to be at least Unit/Void: #6.121([])
441554
extra = plutus_data
442555
443-
datum = #6.121([metadata, version, extra])
556+
datum = #6.121([metadata_field, version, extra])
444557
445-
version = 3
558+
version = 3 / 4
446559
```
447560

448561
Example datum as JSON:
@@ -502,7 +615,9 @@ to lookup. The steps are
502615
1. Construct `reference NFT` from `user token`: `d5e6bf0500378d4f0da4e8dde6becec7621cd8cbf5cbb9b87013d4cc.(100)TestToken`
503616
2. Look up `reference NFT` and find the output it's locked in.
504617
3. Get the datum from the output and lookup metadata by going into the first field of constructor 0.
505-
4. Convert to JSON and encode all string entries to UTF-8 if possible, otherwise leave them in hex.
618+
4. Determine whether this is a direct metadata or the CIP-0025 map style using the `__RESERVE_KEYWORD_721_V4__` map value (if present, default false)
619+
5. Convert to JSON and encode all string entries to UTF-8 if possible, otherwise leave them in hex.
620+
6. For multi-map style metadata, return only the JSON values inside the matching path: `721`->>`policy_id`->>`asset_name`
506621

507622
##### Retrieve metadata from a Plutus validator
508623

@@ -551,7 +666,8 @@ version of these tokens from any point in time with the following format:
551666
1. [6d897eb](https://github.com/cardano-foundation/CIPs/tree/6d897eb60805a58a3e54821fe61284d5c5903764/CIP-XXXX)
552667
2. [45fa23b](https://github.com/cardano-foundation/CIPs/tree/45fa23b60806367a3e52231e552c4d7654237678/CIP-XXXX)
553668
3. [bfc6fde](https://github.com/cardano-foundation/CIPs/tree/bfc6fde340280d8b51f5a7131b57f4cc6cc5f260/CIP-XXXX)
554-
4. **Current**
669+
4. [YYYYYYY](https://github.com/cardano-foundation/CIPs/tree/abcdefabcdefabcdefabcdefabcdefabcdefabcd/CIP-XXXX)
670+
5. **Next Editor**
555671
```
556672

557673
Each time a new version is introduced the previous version's link MUST be updated to match the last commit corresponding
@@ -578,6 +694,10 @@ versions of the affected tokens. `asset_name_labels` **MUST** only be marked obs
578694

579695
- Added [* bounded_bytes] support to the image and src tags on the metadata
580696

697+
#### version 4
698+
699+
- Add backwards-compatible support for multi-asset 721-ERC-style metadata mappings
700+
581701
## Rationale: how does this CIP achieve its goals?
582702

583703
Without separation of `reference NFT` and `user token` you lose all flexibility and moving the `user token` would be

0 commit comments

Comments
 (0)