Skip to content

Commit 4695493

Browse files
committed
docs: added documentation for CIP-67 and CIP-68
1 parent b820eb5 commit 4695493

File tree

4 files changed

+66
-16
lines changed

4 files changed

+66
-16
lines changed

pycardano/cip/cip67.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,17 @@ class InvalidCIP67Token(Exception):
1010

1111

1212
class CIP67TokenName(AssetName):
13+
"""Implementation of CIP67 token naming scheme.
14+
15+
This class enforces the CIP67 token naming format for Cardano native assets, requiring
16+
a 4-byte token label with CRC8 checksum and brackets.
17+
18+
For more information:
19+
https://github.com/cardano-foundation/CIPs/tree/master/CIP-0067
20+
21+
Args:
22+
data: The token name as 'bytes', 'str', or 'AssetName'
23+
"""
1324
def __repr__(self):
1425
return f"{self.__class__.__name__}({self.payload})"
1526

pycardano/cip/cip68.py

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,17 @@ class InvalidCIP68ReferenceNFT(Exception):
1313

1414

1515
class CIP68TokenName(CIP67TokenName):
16+
"""Generates a CIP-68 reference token name from an input asset name.
17+
18+
The reference_token property generates a reference token name by slicing off the label
19+
portion of the asset name and assigning the (100) label hex value.
20+
21+
For more information on CIP-68 labels:
22+
https://github.com/cardano-foundation/CIPs/tree/master/CIP-0068
23+
24+
Args:
25+
data: The token name as bytes, str, or AssetName
26+
"""
1627
@property
1728
def reference_token(self) -> "CIP68ReferenceNFTName":
1829
ref_token = self.payload.hex()[0] + "00643b" + self.payload.hex()[7:]
@@ -21,6 +32,7 @@ def reference_token(self) -> "CIP68ReferenceNFTName":
2132

2233

2334
class CIP68ReferenceNFTName(CIP68TokenName):
35+
"""Validates that an asset name has the 100 label for reference NFTs."""
2436
def __init__(self, data: Union[bytes, str, AssetName]):
2537
super().__init__(data)
2638

@@ -29,6 +41,7 @@ def __init__(self, data: Union[bytes, str, AssetName]):
2941

3042

3143
class CIP68UserNFTName(CIP68TokenName):
44+
"""Validates that an asset name has the 222 label for NFTs."""
3245
def __init__(self, data: Union[bytes, str, AssetName]):
3346
super().__init__(data)
3447

@@ -37,6 +50,10 @@ def __init__(self, data: Union[bytes, str, AssetName]):
3750

3851

3952
class CIP68UserNFTFiles(TypedDict, total=False):
53+
"""Multiple files may be included in metadata by using a list of dictionaries.
54+
55+
Example: files: [file_dict_1, file_dict_2]
56+
"""
4057
name: bytes
4158
mediaType: Required[bytes]
4259
src: Required[bytes]
@@ -50,6 +67,7 @@ class CIP68UserNFTMetadata(TypedDict, total=False):
5067

5168

5269
class CIP68UserFTName(CIP68TokenName):
70+
"""Validates that an asset name has the 333 label for FTs."""
5371
def __init__(self, data: Union[bytes, str, AssetName]):
5472
super().__init__(data)
5573

@@ -67,6 +85,7 @@ class CIP68UserFTMetadata(TypedDict, total=False):
6785

6886

6987
class CIP68UserRFTName(CIP68TokenName):
88+
"""Validates that an asset name has the 444 label for RFTs."""
7089
def __init__(self, data: Union[bytes, str, AssetName]):
7190
super().__init__(data)
7291

@@ -82,36 +101,54 @@ class CIP68UserRFTMetadata(TypedDict, total=False):
82101

83102
@dataclass
84103
class CIP68Datum(PlutusData):
85-
"""Wrapper class for CIP-68 metadata to be used as inline datum"""
104+
"""Wrapper class for CIP-68 metadata to be used as inline datum.
105+
106+
For detailed information on CIP-68 metadata structure and token types:
107+
https://github.com/cardano-foundation/CIPs/tree/master/CIP-0068
108+
109+
This class wraps metadata dictionaries in a PlutusData class for attaching to a
110+
reference NFT transaction as an inline datum.
111+
112+
Args:
113+
metadata: A metadata dictionary. TypedDict classes are provided to define required
114+
fields for each token type.
115+
version: Metadata version number as 'int'
116+
extra: Required - must be a PlutusData, or Unit() for empty PlutusData.
117+
118+
Example:
119+
metadata = {
120+
b"name": b"My NFT",
121+
b"image": b"ipfs://...",
122+
b"files": [{"mediaType": b"image/png", "src": b"ipfs://..."}]
123+
}
124+
datum = CIP68Datum(metadata=metadata, version=1, extra=Unit())
125+
"""
86126
CONSTR_ID = 0
87127

88128
metadata: Dict[bytes, Any]
89129
version: int
90130
extra: Any # This should be PlutusData or Unit() for empty PlutusData
91131

92132
def __post_init__(self):
93-
# Convert string keys to bytes in metadata
94133
converted_metadata: Dict[bytes, Any] = {}
95134
for k, v in self.metadata.items():
96135
key = k.encode() if isinstance(k, str) else k
97-
# Handle nested dictionaries (like in files)
98136
if isinstance(v, dict):
99137
v = dict((k.encode() if isinstance(k, str) else k, v) for k, v in v.items())
100-
# Handle lists of dictionaries (allows multiple files)
101138
elif isinstance(v, list):
102139
v = IndefiniteList([dict((k.encode() if isinstance(k, str) else k, v) for k, v in item.items())
103140
if isinstance(item, dict) else item for item in v])
104141
converted_metadata[key] = v
105142
self.metadata = converted_metadata
106143

107144
def to_shallow_primitive(self) -> CBORTag:
145+
"""Wraps PlutusData in 'extra' field in an indefinite list when converted to a CBOR primitive."""
108146
primitives: Primitive = super().to_shallow_primitive()
109147
if isinstance(primitives, CBORTag):
110148
value = primitives.value
111149
if value:
112150
extra = value[2]
113151
if isinstance(extra, Unit):
114-
# Convert Unit to CBORTag with IndefiniteList([])
115152
extra = CBORTag(121, IndefiniteList([]))
116153
elif isinstance(extra, CBORTag):
117154
extra = CBORTag(extra.tag, IndefiniteList(extra.value))

test/pycardano/test_cip67.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@
55

66

77
@pytest.mark.parametrize("valid_token", [
8-
("000643b0617273656372797074", 100), # Reference NFT with label 100
9-
("000643b04d7943617264", 100), # Another reference NFT with label 100
10-
("000de1404d794e4654", 222), # User NFT with label 222
11-
("000de140556e697175654e4654", 222), # Another user NFT with label 222
12-
("0014df10546f6b656e31", 333), # User FT with label 333
8+
("000643b0617273656372797074", 100), # Reference NFTs with label 100
9+
("000643b04d7943617264", 100),
10+
("000de1404d794e4654", 222), # NFTs with label 222
11+
("000de140556e697175654e4654", 222),
12+
("0014df10546f6b656e31", 333), # FTs with label 333
1313
("0014df10436f696e31", 333),
14-
('001bc280546f6b656e31', 444), # RFT with label 444
15-
('001bc2804d7943617264', 444), # User RFT with label 444
14+
('001bc280546f6b656e31', 444), # RFTs with label 444
15+
('001bc2804d7943617264', 444),
1616
])
1717

1818
def test_CIP67_token_name_format(valid_token):
@@ -29,11 +29,11 @@ def test_CIP67_token_name_format(valid_token):
2929
"000643b0617273656372797074a", # Too long
3030
])
3131

32-
def test_invalid_token_name_format(invalid_token):
32+
def test_cip67_invalid_token_name_format(invalid_token):
3333
with pytest.raises((InvalidCIP67Token, IndexError, ValueError)):
3434
CIP67TokenName(invalid_token)
3535

36-
def test_input_types():
36+
def test_cip67_input_types():
3737
token_str = "000643b0617273656372797074"
3838
CIP67TokenName(token_str) # string input
3939
CIP67TokenName(bytes.fromhex(token_str)) # bytes input

test/pycardano/test_cip68.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import pytest
2-
from cbor2 import CBORTag
32
from dataclasses import dataclass
43

54
from pycardano.cip.cip68 import (
@@ -96,6 +95,9 @@ def test_cip68_multiple_files():
9695
assert b"mediaType" in datum.metadata[b"files"][1]
9796
assert b"src" in datum.metadata[b"files"][1]
9897
assert_roundtrip(datum)
98+
restored = datum.from_cbor(datum.to_cbor_hex())
99+
print(restored)
100+
print(datum)
99101

100102

101103
def test_cip68_with_extra():
@@ -111,7 +113,7 @@ class CustomData(PlutusData):
111113
count: int
112114

113115
extra_data = CustomData(value=b"test value", count=42)
114-
116+
115117
datum_with_extra = CIP68Datum(
116118
metadata=metadata,
117119
version=1,

0 commit comments

Comments
 (0)