Skip to content

Commit 7e8ddea

Browse files
committed
Renamed CIP68UserNFTFile for clarification and improved tests
1 parent 4695493 commit 7e8ddea

File tree

4 files changed

+84
-70
lines changed

4 files changed

+84
-70
lines changed

pycardano/cip/cip67.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,4 +50,4 @@ def __init__(self, data: Union[bytes, str, AssetName]):
5050

5151
@property
5252
def label(self) -> int:
53-
return int.from_bytes(self.payload[:3], "big") >> 4
53+
return int.from_bytes(self.payload[:3], "big") >> 4

pycardano/cip/cip68.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,21 +49,22 @@ def __init__(self, data: Union[bytes, str, AssetName]):
4949
raise InvalidCIP68ReferenceNFT("User NFT must have label 222.")
5050

5151

52-
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-
"""
52+
class CIP68UserNFTFile(TypedDict, total=False):
53+
"""Metadata for a single file in NFT metadata."""
5754
name: bytes
5855
mediaType: Required[bytes]
5956
src: Required[bytes]
6057

6158

6259
class CIP68UserNFTMetadata(TypedDict, total=False):
60+
"""Metadata for a user NFT.
61+
62+
Multiple files can be included as a list of dictionaries or CIP68UserNFTFile objects.
63+
"""
6364
name: Required[bytes]
6465
image: Required[bytes]
6566
description: bytes
66-
files: Union[List[Dict[bytes, bytes]], None]
67+
files: Union[List[CIP68UserNFTFile], None]
6768

6869

6970
class CIP68UserFTName(CIP68TokenName):

test/pycardano/test_cip67.py

Lines changed: 47 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,61 @@
11
import pytest
22

33
from pycardano.cip.cip67 import CIP67TokenName, InvalidCIP67Token
4-
from pycardano.transaction import AssetName
5-
6-
7-
@pytest.mark.parametrize("valid_token", [
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
13-
("0014df10436f696e31", 333),
14-
('001bc280546f6b656e31', 444), # RFTs with label 444
15-
('001bc2804d7943617264', 444),
16-
])
17-
18-
def test_CIP67_token_name_format(valid_token):
19-
token_str, expected_label = valid_token
20-
token = CIP67TokenName(token_str)
21-
assert token.label == expected_label
22-
23-
24-
@pytest.mark.parametrize("invalid_token", [
25-
"100643b0617273656372797074", # Invalid first hex
26-
"000643b1617273656372797074", # Invalid last hex
27-
"00064300617273656372797074", # Invalid checksum
28-
"000643b", # Too short
29-
"000643b0617273656372797074a", # Too long
4+
from pycardano.transaction import AssetName, Value, MultiAsset, Asset
5+
from pycardano.hash import ScriptHash
6+
7+
8+
@pytest.mark.parametrize("token_data", [
9+
# Valid tokens
10+
("000643b0617273656372797074", 100), # Reference NFT with label 100
11+
("000de1404d794e4654", 222), # NFT with label 222
12+
("0014df10546f6b656e31", 333), # FT with label 333
13+
("001bc280546f6b656e31", 444), # RFT with label 444
14+
# Invalid tokens
15+
pytest.param(
16+
("100643b0617273656372797074", None), # Invalid first hex
17+
marks=pytest.mark.xfail(raises=InvalidCIP67Token),
18+
id="invalid_first_hex"
19+
),
20+
pytest.param(
21+
("000643b1617273656372797074", None), # Invalid last hex
22+
marks=pytest.mark.xfail(raises=InvalidCIP67Token),
23+
id="invalid_last_hex"
24+
),
25+
pytest.param(
26+
("00064300617273656372797074", None), # Invalid checksum
27+
marks=pytest.mark.xfail(raises=InvalidCIP67Token),
28+
id="invalid_checksum"
29+
),
30+
pytest.param(
31+
("000643b", None), # Too short
32+
marks=pytest.mark.xfail(raises=(InvalidCIP67Token, IndexError)),
33+
id="too_short"
34+
),
3035
])
36+
def test_cip67_token_name_format(token_data):
37+
token_str, expected_label = token_data
38+
# Create a Value object with asset names and dummy policyID
39+
policy = ScriptHash.from_primitive("00000000000000000000000000000000000000000000000000000000")
40+
asset = Asset()
41+
asset[AssetName(token_str)] = 1
42+
multi_asset = MultiAsset()
43+
multi_asset[policy] = asset
44+
value = Value(0, multi_asset)
45+
# Extract the AssetName from the Value object and create CIP67TokenName
46+
token_name = next(iter(next(iter(value.multi_asset.values())).keys()))
47+
token = CIP67TokenName(token_name)
48+
49+
if expected_label is not None:
50+
assert token.label == expected_label
3151

32-
def test_cip67_invalid_token_name_format(invalid_token):
33-
with pytest.raises((InvalidCIP67Token, IndexError, ValueError)):
34-
CIP67TokenName(invalid_token)
3552

3653
def test_cip67_input_types():
3754
token_str = "000643b0617273656372797074"
3855
CIP67TokenName(token_str) # string input
3956
CIP67TokenName(bytes.fromhex(token_str)) # bytes input
4057
CIP67TokenName(AssetName(bytes.fromhex(token_str))) # AssetName input
58+
4159
with pytest.raises(TypeError):
4260
CIP67TokenName(123) # int input should fail
4361
with pytest.raises(TypeError):

test/pycardano/test_cip68.py

Lines changed: 29 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,10 @@
99
CIP68UserRFTName,
1010
CIP68Datum,
1111
InvalidCIP68ReferenceNFT,
12-
CIP68UserNFTFiles,
12+
CIP68UserNFTFile,
1313
CIP68UserNFTMetadata
1414
)
15+
from pycardano.cip.cip67 import InvalidCIP67Token
1516
from pycardano.plutus import Unit, PlutusData
1617

1718

@@ -22,48 +23,38 @@ def assert_roundtrip(obj: PlutusData) -> None:
2223
assert serialized == reserialized
2324

2425

25-
@pytest.mark.parametrize("reference_nft", [
26-
("000643b04d794e4654", "000643b04d794e4654"), # Reference NFT (100) -> Reference NFT (100)
27-
("000de1404d794e4654", "000643b04d794e4654"), # User NFT (222) -> Reference NFT (100)
28-
("0014df10546f6b656e", "000643b0546f6b656e"), # User FT (333) -> Reference NFT (100)
29-
("001bc280546f6b656e", "000643b0546f6b656e"), # User RFT (444) -> Reference NFT (100)
26+
@pytest.mark.parametrize("token_name,token_class,expected_label,expected_reference_token", [
27+
# (token_name, token_class, expected_label, expected_reference_token)
28+
("000643b04d794e4654", CIP68ReferenceNFTName, 100, "000643b04d794e4654"), # Reference NFT (100)
29+
("000de1404d794e4654", CIP68UserNFTName, 222, "000643b04d794e4654"), # User NFT (222)
30+
("0014df10546f6b656e", CIP68UserFTName, 333, "000643b0546f6b656e"), # User FT (333)
31+
("001bc280546f6b656e", CIP68UserRFTName, 444, "000643b0546f6b656e"), # User RFT (444)
3032
])
31-
32-
def test_reference_token(reference_nft):
33-
token_name, expected_reference_token = reference_nft
34-
token = CIP68TokenName(token_name)
33+
def test_cip68_label_and_reference(token_name, token_class, expected_label, expected_reference_token):
34+
# Label validation
35+
token = token_class(token_name)
36+
assert token.label == expected_label
37+
# Reference token generation
3538
ref_token = token.reference_token
3639
assert ref_token.payload == bytes.fromhex(expected_reference_token)
3740
assert ref_token.label == 100
3841

39-
40-
@pytest.mark.parametrize("token_class,valid_token,expected_label", [
41-
(CIP68ReferenceNFTName, "000643b04d794e4654", 100),
42-
(CIP68UserNFTName, "000de1404d794e4654", 222),
43-
(CIP68UserFTName, "0014df10546f6b656e", 333),
44-
(CIP68UserRFTName, "001bc280546f6b656e", 444),
45-
])
46-
47-
def test_cip68_token_label_validation(token_class, valid_token, expected_label):
48-
# Test valid labels
49-
token = token_class(valid_token)
50-
assert token.label == expected_label
51-
# Test invalid label
42+
# Test Invalid label - fails checksum
5243
invalid_token = "000000004d794e4654"
5344
with pytest.raises(InvalidCIP68ReferenceNFT):
54-
token_class(invalid_token)
45+
CIP68ReferenceNFTName(invalid_token)
5546

5647

5748
def test_cip68_string_key_conversion():
58-
files = CIP68UserNFTFiles(
49+
files = CIP68UserNFTFile(
5950
mediaType=b"image/png",
6051
src=b"ipfs://QmXoypizjW3WknFiJnKLwHCnL72vedxjQkDDP1mXWo6uco"
6152
)
6253
metadata = CIP68UserNFTMetadata(
6354
name=b"My NFT",
6455
image=b"https://example.com/image.jpeg",
6556
description=b"This is a description of my NFT",
66-
files=[files]
57+
files=[files]
6758
)
6859
datum = CIP68Datum(metadata=metadata, version=1, extra=Unit())
6960
assert b"name" in datum.metadata
@@ -76,11 +67,11 @@ def test_cip68_string_key_conversion():
7667

7768

7869
def test_cip68_multiple_files():
79-
files1 = CIP68UserNFTFiles(
70+
files1 = CIP68UserNFTFile(
8071
mediaType=b"image/png",
8172
src=b"ipfs://QmXoypizjW3WknFiJnKLwHCnL72vedxjQkDDP1mXWo6uco"
8273
)
83-
files2 = CIP68UserNFTFiles(
74+
files2 = CIP68UserNFTFile(
8475
mediaType=b"image/png",
8576
src=b"ipfs://QmXoypizjW3WknFiJnKLwHCnL72vedxjQkDDP1mXWo6uco"
8677
)
@@ -95,9 +86,6 @@ def test_cip68_multiple_files():
9586
assert b"mediaType" in datum.metadata[b"files"][1]
9687
assert b"src" in datum.metadata[b"files"][1]
9788
assert_roundtrip(datum)
98-
restored = datum.from_cbor(datum.to_cbor_hex())
99-
print(restored)
100-
print(datum)
10189

10290

10391
def test_cip68_with_extra():
@@ -126,12 +114,19 @@ class CustomData(PlutusData):
126114

127115

128116
@pytest.mark.parametrize("onchain_datum", [
129-
# ADA Handle
117+
# ADA Handle: $handle
130118
"d8799fab446e616d65472468616e646c6545696d6167655838697066733a2f2f7a646a3757687465384638454d666a54625541637036356f574c426f5445677934647a64386b4c61784239394a55437847496d65646961547970654a696d6167652f6a706567426f6700496f675f6e756d626572004672617269747946636f6d6d6f6e466c656e677468064a63686172616374657273476c657474657273516e756d657269635f6d6f64696669657273404b68616e646c655f747970654668616e646c654776657273696f6e0101b4527265736f6c7665645f616464726573736573a04862675f696d6167655f5840697066733a2f2f62616679626569676e376e71367971786c64786d61677274766b6779326368737561706d78686e3566616b6d766c6966637a6c6f747a736c6d426971ff497066705f696d6167654046706f7274616c5838697066733a2f2f7a6232726857666d6433416d795646784368626b766a75363241447539714a7047325545514246587341725747677276374864657369676e65725838697066733a2f2f7a623272686377626b6536326e634b326e5239686e704e4a743165564a666d424e536473594e313647455550714843614b47736f6369616c735838697066733a2f2f7a623272685a4d50315457466234366f7842766369314c666b6d3146386f5a4c6369555768736e6a417245784e4d72684c4676656e646f72404764656661756c74004e7374616e646172645f696d6167655838697066733a2f2f7a623272686d6f503932516973576468733736655559734c62483835636673346d6b4a7a596d363965413145505a595753536c6173745f7570646174655f616464726573735839018e41aa027f2351ee8e0279ab05e7d92acaa4a2735650bd51c6564413c67e12eb7cf98da0d2fa795fb7c20060c964f2ceeba0feae4d5c9b2d4c76616c6964617465645f6279581c4da965a049dfd15ed1ee19fba6e2974a0b79fc416dd1796a1f97f5e14a696d6167655f686173685820c102fe43ea1c6919bcffb570c6cc7eaf07cfcdb98fdc32a1e26398cddaf725d9537374616e646172645f696d6167655f686173685820e134411636b3a147dde4763cff01d651aacd1a5a397c11736810020cf95cf3074b7376675f76657273696f6e46332e302e31354c6167726565645f7465726d735768747470733a2f2f68616e646c652e6d652f242f746f75546d6967726174655f7369675f726571756972656400446e7366770045747269616c004a707a5f656e61626c6564014862675f6173736574582eb06e84cae01ef5871a6fe6ac556134e21b4b8eb55b833cd3dac95126001bc28048616e646c652043617264203238ff",
131-
# NFT
119+
# ADA Handle: $steelswap
120+
"d8799fab446e616d654a24737465656c7377617045696d6167655838697066733a2f2f7a623272686b6a4a334e595465747068736e7a624e797667763134366f34684472654861677437434a366e6b6d6474694e496d65646961547970654a696d6167652f6a706567426f6700496f675f6e756d6265720046726172697479456261736963466c656e677468094a63686172616374657273476c657474657273516e756d657269635f6d6f64696669657273404776657273696f6e014b68616e646c655f747970654668616e646c6501af4e7374616e646172645f696d6167655838697066733a2f2f7a623272686b6a4a334e595465747068736e7a624e797667763134366f34684472654861677437434a366e6b6d6474694e537374616e646172645f696d6167655f686173685820d14c7af907d68d30e64367ea3a3e67e94158817172d5a4ce45d234a75788f28b4a696d6167655f686173685820d14c7af907d68d30e64367ea3a3e67e94158817172d5a4ce45d234a75788f28b46706f7274616c404864657369676e65724047736f6369616c73404676656e646f72404764656661756c7400536c6173745f7570646174655f61646472657373583901661ae4b23b24ba9656d78b7637e6a66e889fa788c16c88017e494052c2c5baab297046f996aea6faa54eb92b6005bdb22c8288de08064e374c76616c6964617465645f6279581c4da965a049dfd15ed1ee19fba6e2974a0b79fc416dd1796a1f97f5e14b7376675f76657273696f6e45332e302e384c6167726565645f7465726d735768747470733a2f2f68616e646c652e6d652f242f746f75546d6967726174655f7369675f72657175697265640045747269616c00446e73667700ff",
121+
# NFT: Space Bud
132122
"d8799fa5446e616d654e5370616365427564202338313034467472616974739f4a4368657374706c6174654442656c744e436f76657265642048656c6d65744a576f6f6c20426f6f747346416e63686f72ff447479706545416c69656e45696d6167655f5840697066733a2f2f6261666b726569626e77647635646f6f706536636d796e36726d6865776e6b6672706e777361376a71353770376f78686f686f6c6664683475423571ff4673686132353658202db0ebd1b9cf2784cc37d161c966a8b17b6d207d30efdff75cee3b96519f94ec01d87980ff",
123+
# NFT: Baby Sneklet
124+
pytest.param(
125+
"d8799fa6446e616d655042616279536e616b6c657420233830334566696c65739fa3437372635835697066733a2f2f516d546d533361676a43385a6833586a78625166666448686a685973336669375a375a396d666435756843684473446e616d655342616279536e616b6c6574303830332e706e67496d656469615479706549696d6167652f706e67ff45696d6167655835697066733a2f2f516d546d533361676a43385a6833586a78625166666448686a685973336669375a375a396d6664357568436844734757656273697465581968747470733a2f2f62616279736e656b6c6574732e66756e2f496d656469615479706549696d6167652f706e674a61747472696275746573a844426f64794f5065726977696e6b6c6520426c756544457965734f416c77617973205761746368696e674448656164464d7573736564445461696c4e546f756368646f776e2042616c6c445479706547526567756c6172454d6f75746848426967204269746547436c6f7468657354507572706c65205a6f6d62696520486f6f6469654a4261636b67726f756e644b4f72616e6765205065656c01ff",
126+
marks=pytest.mark.xfail(reason="Missing empty PlutusData in extra field"),
127+
id="babysneklet"
128+
),
133129
])
134-
135130
def test_cip68_onchain_datum(onchain_datum):
136131
datum = CIP68Datum.from_cbor(bytes.fromhex(onchain_datum))
137132
assert_roundtrip(datum)

0 commit comments

Comments
 (0)