1. Abstract
KCC-23 defines a way to bind JSON metadata to a covenant ID. Deployment adds a version 1 preparation transaction carrying a 0x00 codec byte followed by a UTF-8 JSON object in its payload. The transaction creates an output that the genesis transaction spends to initialize the covenant. The covenant ID commits to the spent outpoint, whose transaction ID commits to the metadata. The transactions can be shared as a launch proof, allowing readers to verify the binding independently.
2. Motivation
Covenant applications may wish to publish descriptive information that their spending rules do not enforce. A KCC-20 token deployer may want to declare a name, symbol, or number of decimal places. These properties describe the token as a whole and should not have to be repeated in every token UTXO or carried through every transfer.
KCC-23 uses KIP-20's covenant ID hashing mechanism to bind the declaration to the application's identity at genesis. Readers can then verify which metadata was declared for a given covenant ID, regardless of who supplies it.
3. Specification
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174.
3.1 Declaration
The metadata declaration is carried in the payload of a version 1 transaction that creates an output to be spent by the covenant's genesis transaction. This is the preparation transaction.
The preparation transaction payload MUST start with a one-byte codec prefix. The value 0x00 denotes a UTF-8 JSON object. For this prefix, the remaining payload bytes MUST contain exactly one JSON object, with no wrapper or required property. This KCC defines no other codec values. Readers MUST reject other prefix values unless a later specification defines them. Field names and their meanings are left to ecosystem conventions.
The JSON object MUST conform to I-JSON (RFC 7493) and MUST NOT be preceded by a byte-order mark (BOM). Numbers MUST convert to finite IEEE-754 binary64 values. Object/array nesting MUST NOT exceed 64 levels, counting the root object as depth 1.
If an API represents payload bytes as a hexadecimal string, that string encodes the prefix byte followed by the UTF-8 bytes. For example, the API hex string for {} is 007b7d; the transaction payload contains the bytes 00 7b 7d.
The commitment covers the exact payload bytes, including the codec prefix, whitespace, and property ordering. The declaration is fixed for that covenant ID.
3.2 Deployment
Deployment MUST use the following two transactions:
- A version 1 preparation transaction carrying the metadata in its payload and creating an output to be spent at genesis.
- A genesis transaction spending that output to authorize the application's genesis output group under KIP-20.
The preparation transaction's ID commits to the payload. Under KIP-20's genesis hashing rule, the covenant ID commits to the spent outpoint and the genesis output group. Together, these commitments bind the metadata to the covenant.
3.3 Verification
Both transactions MAY be shared off chain as a launch proof, identifying the output spent at genesis and the genesis output group. Verification is OPTIONAL and does not depend on who supplies the proof.
A version 1 transaction ID combines two separately computed digests: one of the payload and one of the remaining transaction fields used for identity:
payload_digest = PayloadDigest(preparation.payload)
rest_digest = TransactionRest(rest_preimage)
txid = TransactionV1Id(payload_digest || rest_digest)Given the payload and rest_digest, a reader can recompute the payload digest and reconstruct the transaction ID without the full transaction body. KIP-24 (draft) defines the hash functions and canonical encoding.
To verify the binding to an expected covenant ID, a reader MUST:
- Confirm that the preparation transaction is a version 1 transaction and its payload satisfies Section 3.1.
- Recompute its ID from the original transaction fields and payload bytes using the version 1 transaction-ID calculation above.
- Check that the genesis group's authorizing input spends an existing output of that preparation transaction, using the recomputed ID and output index.
- Recompute the covenant ID from that outpoint and the complete genesis output group under KIP-20, and require it to match the expected covenant ID and the group's declared covenant ID.
These checks establish the metadata binding; they do not establish transaction validity or on-chain acceptance.
4. Example: token metadata
A KCC-20 token deployer places the prefix byte 0x00 to indicate UTF-8 JSON, followed by the UTF-8 bytes of the following JSON in the payload of a version 1 preparation transaction creating an output:
{
"name": "Example Token",
"symbol": "EXT",
"decimals": 8
}To represent the payload in hex:
payload_bytes = 0x00 || UTF8(JSON(metadata))
payload_hex = Hex(payload_bytes)The deployer then spends that output to authorize the initial token outputs in the genesis transaction. The deployer can share both transactions as the launch proof.
An application following these field conventions could label the token "Example Token" and display a raw amount of 100000000 as 1 EXT. Token transfers require no metadata input or output. The field names and display behavior are illustrative.
5. Rationale
The preparation transaction binds metadata through KIP-20's existing genesis commitment without persistent metadata UTXOs or additional covenant state. Requiring version 1 gives readers one transaction-ID calculation to support. UTF-8 JSON provides a common format without an application schema. The codec prefix identifies that format and reserves other byte values for future specifications to define.
The on-chain payload can also serve as a publication hint. When observing a covenant genesis, a reader could follow its authorizing outpoint to the preparation transaction and decode its payload according to the codec prefix for a description of the application. Ecosystem conventions determine how to recognize and interpret that description.
6. Conformance Vectors
The authoritative machine-readable vectors are in kcc-0023/vectors/conformance.json. Byte strings are lowercase hexadecimal. These are synthetic commitment fixtures, with placeholder outpoints and scripts.
The binding vector uses the prefix byte 0x00 followed by the example metadata serialized exactly as follows, without a trailing newline:
{"name":"Example Token","symbol":"EXT","decimals":8}The preparation transaction has one input spending index 0 of transaction ID 11 repeated 32 times, and one output of 100000000 sompi. The genesis transaction spends preparation output 0 through input 0 and creates one output of 90000000 sompi, bound to the resulting covenant ID. Both transactions are version 1, use the native subnetwork, and have zero lock time, gas, input sequence, compute budget, and storage mass. Signature scripts are empty; both output scripts are version 0 with bytes 51. The genesis payload is empty.
preparation transaction ID = 206a0c31dbe45384b86de451a177fd7c8e986d278f2a86724d941937443113ef
covenant ID = c86366cec738e9a1578b2d871ee493dcaabfd79156810f13f3b62429859e394eKeeping the genesis transaction and expected covenant ID unchanged while replacing "decimals":8 with "decimals":9 in the preparation payload MUST fail binding verification. A version 0 preparation transaction MUST also fail.
The declaration vectors cover:
| Payload bytes | Interpretation | Valid declaration |
|---|---|---|
007b7d | {} | Yes |
007b226e616d65223a22c3a9227d | {"name":"é"} | Yes |
7b7d | Missing codec prefix | No |
017b7d | Unknown codec prefix | No |
005b5d | [] | No, not an object |
007b2278223a22ff227d | Invalid UTF-8 | No |
7. Security Considerations
KCC-23 binds descriptive metadata to a covenant ID. It adds no spending authority and does not change the covenant's validation rules. Applications determine how to interpret and use the metadata.
8. Copyright
Copyright and related rights waived via CC0.