Skip to content

WIP: CIP67 and CIP68 Support#297

Merged
theeldermillenial merged 35 commits into
Python-Cardano:mainfrom
theeldermillenial:feat/cip67-cip68
Jun 6, 2026
Merged

WIP: CIP67 and CIP68 Support#297
theeldermillenial merged 35 commits into
Python-Cardano:mainfrom
theeldermillenial:feat/cip67-cip68

Conversation

@theeldermillenial

@theeldermillenial theeldermillenial commented Jan 11, 2024

Copy link
Copy Markdown
Contributor

This PR is a first pass implementation at handling classes for CIP67 and CIP68. These classes will streamline handling and parsing tokens utilizing these standards. This approach attempts to extend AssetName by providing additional validation to ensure CIP68 compliance for token names, as well as associated cbor classes for parsing associated metadata.

Feedback on implementation details and additional functionality is welcomed.

Todo:

  • Unit Tests
  • More rigorous validation of CIP68 fields (e.g. the uri fields)
  • Documentation

@codecov-commenter

codecov-commenter commented Jan 12, 2024

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 90.41916% with 48 lines in your changes missing coverage. Please review.
✅ Project coverage is 90.62%. Comparing base (30712f4) to head (2eea7b9).
⚠️ Report is 34 commits behind head on main.

Files with missing lines Patch % Lines
pycardano/address.py 90.67% 8 Missing and 3 partials ⚠️
pycardano/certificate.py 90.19% 4 Missing and 6 partials ⚠️
pycardano/cip/cip68.py 87.95% 4 Missing and 6 partials ⚠️
pycardano/governance.py 80.00% 4 Missing and 2 partials ⚠️
pycardano/utils.py 57.14% 2 Missing and 1 partial ⚠️
pycardano/cbor.py 50.00% 1 Missing and 1 partial ⚠️
pycardano/crypto/bip32.py 80.00% 1 Missing and 1 partial ⚠️
pycardano/witness.py 60.00% 1 Missing and 1 partial ⚠️
pycardano/plutus.py 93.33% 0 Missing and 1 partial ⚠️
pycardano/serialization.py 98.27% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #297      +/-   ##
==========================================
+ Coverage   89.94%   90.62%   +0.68%     
==========================================
  Files          33       36       +3     
  Lines        4855     5261     +406     
  Branches      733      797      +64     
==========================================
+ Hits         4367     4768     +401     
+ Misses        315      308       -7     
- Partials      173      185      +12     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@nielstron

Copy link
Copy Markdown
Contributor

This is great. I was actually thinking that PlutusData in pycardano could try to support TypedDict as type annotation for field.

Also I found that deserialization of CIP68 compliant datums fails - have not checked lately if this has been fixed but likely requires a similar fix as #293

@theeldermillenial

theeldermillenial commented Jan 12, 2024

Copy link
Copy Markdown
Contributor Author

This is great. I was actually thinking that PlutusData in pycardano could try to support TypedDict as type annotation for field.

So we just need some kind of extension of this?

class DictCBORSerializable(CBORSerializable):

Also I found that deserialization of CIP68 compliant datums fails - have not checked lately if this has been fixed but likely requires a similar fix as #293

Have any examples? I just did a query of all cip68 reference tokens and found that 99.99% of them are nfts. I'm trying to figure out a good set of test cases for it. I could use the example in the CIP68 docs, but those are extremely sparse. Ideally I could get a range of different examples.

@nielstron

Copy link
Copy Markdown
Contributor

I would rather extend the support of type annotations for fields of PlutusData here:

Also for the CIP68 datum I meant the deserialization happening when submitting a transaction with a CIP68 Datum attached - you can try this yourself easily. But don't have any examples at hand right now except for https://preprod.cardanoscan.io/transaction/36f79154eff88d73c21caaf9c5e1bedfc1ff641e39f7f80381dbdba0c104bc50

@Cat-Treat

Copy link
Copy Markdown
Contributor

I'll be working on finishing this off.

Todo:

  • Resolve merge conflicts
  • Unit tests
  • Example of CIP68 token mints

@theeldermillenial

Copy link
Copy Markdown
Contributor Author

@cffls We are close to having something ready. Just need to get builds passing.

theeldermillenial and others added 5 commits June 1, 2026 21:49
import Required from typing_extensions to support older python version
- qa: add `isort --check-only` (was only checking black)
- add `check: qa test` to run all static analyses and unit tests
- run `make format` over cip67/cip68 modules and tests to satisfy flake8/black

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Restore Makefile to its original state per request; keep CIP formatting fixes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces initial support for Cardano CIP-0067 (token name labels/checksums) and CIP-0068 (reference NFT/user token names and inline datum metadata) within pycardano, aiming to streamline parsing/validation and provide CBOR/PlutusData helpers for CIP-68 metadata.

Changes:

  • Add CIP67TokenName for CIP-67 label + CRC8 validation and label extraction.
  • Add CIP-68 token-name subclasses and a CIP68Datum PlutusData wrapper with metadata key normalization and CBOR shaping.
  • Add initial pytest coverage for CIP-67/68 behavior and update dependencies/config (e.g., crc8, Poetry config), plus a small serialization tweak for IndefiniteList handling.

Reviewed changes

Copilot reviewed 8 out of 9 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
pycardano/cip/cip67.py Implements CIP-67 token naming validation and label extraction.
pycardano/cip/cip68.py Adds CIP-68 token-name helpers and a CIP68Datum PlutusData wrapper for inline datum metadata.
pycardano/cip/__init__.py Exposes new CIP-67/68 modules from the pycardano.cip package.
pycardano/serialization.py Adjusts IndefiniteList init to handle FrozenList inputs.
pyproject.toml Adds crc8 dependency required by CIP-67 checksum validation.
poetry.lock Locks crc8 and updates lock metadata after dependency changes.
poetry.toml Configures Poetry to create virtualenvs in-project.
test/pycardano/test_cip67.py Adds tests for CIP-67 parsing/labeling and invalid token handling.
test/pycardano/test_cip68.py Adds tests for CIP-68 token-name/reference-token behavior and datum roundtrips.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread pycardano/cip/cip67.py
Comment on lines +28 to +40
def __init__(self, data: Union[bytes, str, AssetName]):
if isinstance(data, AssetName):
data = data.payload

if isinstance(data, bytes):
data = data.hex()

if data[0] != "0" or data[7] != "0":
raise InvalidCIP67Token(
"The first and eighth hex values must be 0. Instead found:\n"
+ f"first={data[0]}\n"
+ f"eigth={data[7]}"
)
Comment thread pycardano/cip/cip67.py
Comment on lines +42 to +50
checksum = crc8(bytes.fromhex(data[1:5])).hexdigest()
if data[5:7] != checksum:
raise InvalidCIP67Token(
f"Token label {data[1:5]} does not match token checksum.\n"
+ f"expected={checksum}\n"
+ f"received={data[5:7]}"
)

super().__init__(bytes.fromhex(data))
Comment thread pycardano/cip/cip68.py
Comment on lines +83 to +85
if self.label != 333:
raise InvalidCIP68ReferenceNFT("User NFT must have label 333.")

Comment thread pycardano/cip/cip68.py
Comment on lines +102 to +104
if self.label != 444:
raise InvalidCIP68ReferenceNFT("User NFT must have label 444.")

Comment thread pycardano/cip/cip68.py
Comment on lines +165 to +166
converted_metadata[key] = v
self.metadata = converted_metadata
Comment thread pycardano/cip/cip68.py
Comment on lines +179 to +180
value = [value[0], value[1], extra]
return CBORTag(121, value)
Comment on lines +32 to +36
pytest.param(
("000643b", None), # Too short
marks=pytest.mark.xfail(raises=(InvalidCIP67Token, IndexError)),
id="too_short",
),
Comment thread pycardano/cip/cip68.py
Comment on lines +139 to +141
metadata: Dict[bytes, Any]
version: int
extra: Any # This should be PlutusData or Unit() for empty PlutusData
@theeldermillenial theeldermillenial merged commit 079d091 into Python-Cardano:main Jun 6, 2026
13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants