Skip to content

Commit

Permalink
CIP-0068: Add SFT Semi-fungible token support
Browse files Browse the repository at this point in the history
  • Loading branch information
AndrewWestberg committed Apr 1, 2023
1 parent 5bcdb9b commit dec688e
Showing 1 changed file with 88 additions and 2 deletions.
90 changes: 88 additions & 2 deletions CIP-0068/README.md
Expand Up @@ -147,7 +147,7 @@ datum = #6.121([metadata, 1, extra]) ; version 1
```
Example datum as JSON:
```json
{"constructor" : 0, "fields": [{"map": [{"k": "6E616D65", "v": "5370616365427564"}, {"k": "696D616765", "v": "697066733A2F2F74657374"}]}, {"int": 1}]}
{"constructor" : 0, "fields": [{"map": [{"k": {"bytes": "6E616D65"}, "v": {"bytes": "5370616365427564"}}, {"k": {"bytes": "696D616765"}, "v": {"bytes": "697066733A2F2F74657374"}}]}, {"int": 1}]}
```

### Retrieve metadata as 3rd party
Expand Down Expand Up @@ -225,7 +225,7 @@ datum = #6.121([metadata, 1, extra]) ; version 1
```
Example datum as JSON:
```json
{"constructor" : 0, "fields": [{"map": [{"k": "6E616D65", "v": "5370616365427564"}, {"k": "6465736372697074696F6E", "v": "54686973206973206D79207465737420746F6B656E"}]}, {"int": 1}]}
{"constructor" : 0, "fields": [{"map": [{"k": {"bytes": "6E616D65"}, "v": {"bytes": "5370616365427564"}}, {"k": {"bytes": "6465736372697074696F6E"}, "v": {"bytes": "54686973206973206D79207465737420746F6B656E"}}]}, {"int": 1}]}
```

### Retrieve metadata as 3rd party
Expand All @@ -246,6 +246,92 @@ We want to bring the metadata of the FT `d5e6bf0500378d4f0da4e8dde6becec7621cd8c
3. Reference the output in the transaction. (off-chain)
4. Verify validity of datum of the referenced output by checking if policy ID of `reference NFT` and `user token` and their asset names without the `asset_name_label` prefix match. (on-chain)

## 444 SFT Standard

The third introduced standard is the `444` Semi-FT standard with the registered `asset_name_label` prefix value

| asset_name_label | class | description |
| --------------------------- | ------------ | -------------------------------------------------------------------- |
| 444 | SFT | SFT hold by the user's wallet making use of the union of CIP-0025 inner structure AND the Cardano foundation off-chain registry inner structure |

Semi-Fungible tokens don't fit cleanly into the other two FT/NFT classes of tokens and thus need their own standard. An example of a SFT would be a fractionalized NFT. The single reference NFT `(100)` represents the NFT itself, and the many `(444)` tokens represent the fractionalized shares. Minting 100 tokens and setting decimals to 2 would represent a single NFT that is split into 100 fractions.

### Class

The `user token` is an SFT (semi-fungible token).

### Pattern

The `user token` and `reference NFT` **must** have an identical name, preceded by the `asset_name_label` prefix.

Example:\
`user token`: `(444)Test123`\
`reference NFT`: `(100)Test123`

### Metadata

This is a low-level representation of the metadata, following closely the structure of CIP-0025 combined with the Cardano foundation off-chain metadata registry. All UTF-8 encoded keys and values need to be converted into their respective byte's representation when creating the datum on-chain.

```
files_details =
{
? name : bounded_bytes, ; UTF-8
mediaType : bounded_bytes, ; UTF-8
src : bounded_bytes ; UTF-8
; ... Additional properties are allowed
}
metadata =
{
name : bounded_bytes, ; UTF-8
description : bounded_bytes, ; UTF-8
image : bounded_bytes, ; UTF-8
? mediaType : bounded_bytes, ; UTF-8
? ticker: bounded_bytes, ; UTF-8
? url: bounded_bytes, ; UTF-8
? logo: uri,
? decimals: int,
? files : [* files_details]
; ... Additional properties are allowed
}
; A URI as a UTF-8 encoded bytestring.
; The URI scheme must be one of `https`, `ipfs` or `data`
; Do not encode plain file payloads as URI.
; 'logo' does not follow the explanation of the token-registry, it needs to be a valid URI and not a plain bytestring.
; Only use the following media types: `image/png`, `image/jpeg`, `image/svg+xml`
uri = bounded_bytes
; Custom user defined plutus data.
; Setting data is optional, but the field is required
; and needs to be at least Unit/Void: #6.121([])
extra = plutus_data
datum = #6.121([metadata, 1, extra]) ; version 1
```
Example datum as JSON:
```json
{"constructor" : 0, "fields": [{"map": [{"k": {"bytes": "6E616D65"}, "v": {"bytes":"5370616365427564"}}, {"k": {"bytes": "6465736372697074696F6E"}, "v": {"bytes":"54686973206973206D79207465737420746F6B656E"}}, {"k": {"bytes": "696D616765"}, "v": {"bytes": "697066733A2F2F74657374"}}, {"k": {"bytes": "646563696D616C73"}, "v": {"int": 2}}]}, {"int": 1}]}
```

### Retrieve metadata as 3rd party

A third party has the following SFT `d5e6bf0500378d4f0da4e8dde6becec7621cd8cbf5cbb9b87013d4cc.(444)TestToken` they want to lookup. The steps are

1. Construct `reference NFT` from `user token`: `d5e6bf0500378d4f0da4e8dde6becec7621cd8cbf5cbb9b87013d4cc.(100)TestToken`
2. Look up `reference NFT` and find the output it's locked in.
3. Get the datum from the output and lookup metadata by going into the first field of constructor 0.
4. Convert to JSON and encode all string entries to UTF-8 if possible, otherwise leave them in hex.

### Retrieve metadata from a Plutus validator

We want to bring the metadata of the SFT `d5e6bf0500378d4f0da4e8dde6becec7621cd8cbf5cbb9b87013d4cc.(444)TestToken` in the Plutus validator context. To do this we

1. Construct `reference NFT` from `user token`: `d5e6bf0500378d4f0da4e8dde6becec7621cd8cbf5cbb9b87013d4cc.(100)TestToken` (off-chain)
2. Look up `reference NFT` and find the output it's locked in. (off-chain)
3. Reference the output in the transaction. (off-chain)
4. Verify validity of datum of the referenced output by checking if policy ID of `reference NFT` and `user token` and their asset names without the `asset_name_label` prefix match. (on-chain)

## Rationale

Without seperation of `reference NFT` and `user token` you lose all flexibility and moving the `user token` would be quite cumbersome as you would need to add the metadata everytime to the new output where the `user token` is sent to. Hence you separate metadata and `user token` and lock the metadata inside another UTxO, so you can freely move the `user token` around.
Expand Down

0 comments on commit dec688e

Please sign in to comment.