Covenant tokens are the only Kaspa token type still missing metadata

KRC-20 and KRC-721 tokens have carried metadata for a year: KRC-20 has ticker and decimals, KRC-721 has the ERC-721 shape (name, description, image, attributes, with images pinned by ipfs). Covenant tokens are the one Kaspa token type with none of it. KCC20 keeps to accounting and transfer, which is right, and its Descriptor artifact carries template identity and state layout for tooling, but no human metadata: no name, ticker, decimals, or art. So an aggregator that already lists KRC and KCC tokens side by side can show a name and logo for the KRC ones and nothing for the covenant ones.

We have been running a convention in production at kascov to close that, read from the deploy (genesis) transaction payload:

{
"name": "My Token",
"ticker": "MTK",
"image": "https://.../art.png",
"image_hash": "sha256 hex of the image bytes"
}

Committed once in the genesis payload, plain or hex JSON, under 4KB. symbol aliases ticker. It borrows KRC-721’s field shape (name, image) and adds the fungible fields KRC-20 has (ticker, decimals). The one twist: instead of requiring ipfs like KRC-721, it allows a normal URL plus an image_hash (sha256 of the bytes), so a launchpad can keep hosting on its own CDN and the art is still pinned. kascov fetches the image once, checks the hash, then serves it immutably, so art cannot be swapped after launch. ipfs images work too. Names are claims, not unique.

Live, not theoretical: KaspaRocket adopted it the same day, so tokens launched there show a verified name and art in any tool that reads the convention.

Open questions, genuinely before anyone writes a spec:

  • In 0020 or beside it: KRC-20 and ERC-20 carry ticker and decimals inside the token standard, so metadata could fold into 0020, or stay a sibling convention reusable by a future covenant NFT. Either way, since covenant tokens are UTXO based with no contract storage for a name, it has to anchor to the genesis payload or the Descriptor. Which shape do the authors prefer?
  • Fields: name, ticker, decimals, image, image_hash. Align exactly with KRC-721 field names, or diverge where covenant reality differs?
  • Image pinning: require ipfs like KRC-721, allow url plus hash, or both?
  • Encoding: plain JSON, hex JSON, or something more compact?

If there is appetite I am happy to write it up. I mostly want covenant tokens readable by any tool the way KRC tokens already are, not reinvented per app.

3 Likes

I’d lean toward a sibling KCC rather than folding this into KCC-0020. That keeps accounting and transfer minimal, while allowing the metadata convention to be reused by future covenant NFTs and other asset classes.

The covenant ID should remain the canonical asset identity, with names and tickers treated as non-unique display claims.

For tooling reuse, I’d align field names with KRC-721 wherever the semantics match, adding fungible-specific fields such as ticker and decimals. For images, supporting both content-addressed URIs and HTTPS + hash seems pragmatic.

On encoding, one canonical UTF-8 JSON representation would be cleanest; it can still be hex-encoded at the transport layer where required.

KCC-0020 defines asset behavior; this convention would define asset identity, discovery, and provenance.

3 Likes

Wrote it up: KCC-0021: Covenant Token Metadata Specification by Knitser · Pull Request #6 · kaspanet/kccs · GitHub . It is KCC-0021, a sibling to 0020, against kaspanet/kccs.

It follows what we landed on here: sibling rather than folded in, Covenant ID as canonical identity with name and ticker as non-unique claims, KRC-721 field names plus the fungible fields (ticker, decimals), one canonical UTF-8 JSON with hex as a transport encoding, and the genesis payload as the anchor. Andreas, your identity / behavior / provenance split ended up being the spine of it.

Two places I went a step past the thread and would want the authors’ eyes on:

  • Images: https is location plus image_hash with full byte verification, and ipfs stays an accepted scheme but is scoped as a claim for v1 (the consumer must re-derive the CID, full gateway serving is deferred), since a CID is not sha256 of the gateway bytes.
  • decimals is bounded 0 to 255 (ERC-20’s uint8), and the number and category (0021, Covenant vs Asset Standards) are maintainer calls, flagged in the PR body.

Tear it apart.

3 Likes

Really glad the distinction was useful, and I appreciate you turning it into something concrete this quickly. The sibling KCC, canonical covenant identity, and genesis-anchored metadata model still feel like the right shape to me.

On the two open points:

  • The IPFS scoping makes sense. Since a CID commits to the underlying content-addressed structure rather than simply being a SHA-256 hash of the gateway response bytes, allowing ipfs:// in v1 while treating it as a claimed content-addressed reference - unless the consumer can fully resolve and verify the CID - seems like the honest approach.

  • Bounding decimals to 0–255 also feels like a sensible interoperability choice and aligns well with the established uint8 convention.

I’ll go through the full PR carefully, especially the Descriptor relationship and canonicalization rules. Great work turning the discussion into something implementers can actually converge around…

I can imagine situations in which a developer wishes to create a composable token covenant and not care about giving it a specific ticker or an image.
IMO, the KCC20 spec should not enforce an on-chain identity.
A token (or any covenant for that matter) has a unique cov-id which is its true identifier (much like a contract address on Ethereum).

So yeah, I’d go with a different standard.

2 Likes

In regards to this genesis metadata convention proposal heres an updated convention proposal.

The following metadata remains permanently immutable:

  • name
  • ticker
  • supply
  • decimals
  • genesis tx ID
  • metadata authority public key

Only the image may be updated through subsequent txs:

{
  "protocol": "kcc20-metadata",
  "version": 1,
  "op": "update-image",
  "genesis_txid": "...",
  "covenant_id": "...",
  "sequence": 1,
  "previous_update_txid": "...",
  "image": "https://example.com/new-logo.png",
  "image_hash": "sha256...",
  "signature": "..."
}

The signature must be produced by the metadata authority key defined at genesis. Indexers should only accept an update when:

  • operation is
update-image
  • signature is valid
  • genesis tx and covenant IDs match
  • sequence number is valid and strictly increasing
  • the SHA256 hash matches the referenced image
    Attempts to modify the ticker, name, supply or decimals must be marked invalid.Previous images and updates remain permanently visible in the on chain history.

Indexers can resolve the latest valid image update without changing token balances, ownership states or transfer behavior. The genesis tx itself can never be modified. Instead a later authorized image-update tx would be linked to the original genesis tx.

I understand the need for token metadata management, this topic has been discussed here before and it’s a good topic to discuss.
Your proposal though does not speak covenant language. What is this metadata artifact? Where is it published? What do you mean by image update protocol? How this relates to the kcc20 protocol?

@kasbtc coming back to your update-image proposal, sorry for the slow reply. The problem you point at is real and I can now put numbers on it: on one live launchpad list we cross-checked, 5 of 19 published logo URLs were dead within days and 3 more served HTML instead of an image. Discord attachment links expire by design. Image hosting rots fast.

Where I land differently is the fix. The one thing this convention buys a wallet is that the genesis commitment can never change out from under it. An authority key that can re-point the image reopens exactly the swap that image_hash exists to close, and it inherits Manyfest’s questions above: what is the update artifact, where is it published, who indexes it, and what happens when two indexers disagree on the latest sequence.

What we shipped instead in kascov, and what I would offer for your use case, is layering rather than mutation. A reader carries two tiers side by side: claimed_* fields parsed from the immutable genesis payload, and listed_* fields from a launchpad’s signed token list, which is mutable by re-signing and well suited to metadata that legitimately needs to evolve. The tiers are never merged, both are labeled claims, and the covenant id stays the only identity. That gives updatable presentation today with zero new on-chain protocol, while the genesis payload stays the anchor a wallet can trust forever. If you want on-chain updatability specifically, I think it belongs in a separate extension KCC with the genesis object as canonical fallback. KCC-0021’s Mutability section deliberately reserves that space, and I would gladly help shape a draft.

Meanwhile PR #6 got a revision reflecting a month of production:

  • The reference Reader closed two of its five divergences: the https/ipfs scheme rule is enforced at parse (a live payload with a javascript: URL made that case), and decimals is consumed end to end, integer or string, 0 to 255, out of range treated as undeclared rather than clamped.
  • New section on coexistence with signed token lists, the claimed/listed model above.
  • ipfs:// images can now be paired with an image_hash so readers without a CID pipeline verify and serve them through the same sha256 path as https.
  • Honest scoping on pruning: reading an old genesis payload needs an archival or tx-indexed node, but no trusted party.

The first wallet integration ask for exactly this data landed recently, a good reminder that wallets are the real consumers here. If you build a wallet and have opinions on the field set, now is the time. @Andreas if the descriptor-relationship review is still on your list, the PR is a stable target now.

4 Likes