NFTs
A collection with a size that never changes, and items that can move. Like tokens it is a module built into the protocol rather than code uploaded to the chain, and owning an item touches nothing about who votes.
Making one
./baklava collection -keystore wallet.json -symbol BAKART -name "Baklava Art" -size 10000Or /collection BAKART 10000 Baklava Art from the console. The id comes back straight away — derived from your address and the nonce that made it, so nobody picks it, including the command you just ran.
Ten thousand items. One leaf.
Creating a collection writes a single row, whatever its size. An item that has never moved has no leaf at all, and the rule is that such an item belongs to the collection's creator. The first transfer writes a leaf; a transfer that sends an item back to the creator deletes it again.
That last part is not tidiness. A stored leaf saying “the creator owns it” and no leaf at all would be two encodings of one state, and two encodings of one state are two roots — the same reason a zero balance and a drained account are not rows either.
So the chain cannot tell an item that never moved from one that moved and came home, and neither can you. That is the design and not a gap: they are the same state, and one state has one encoding.
| The size is final | There is no mint transition, for the reason a token has none: a holder never has to wonder what the creator might do next. The alternatives were minting every item at creation — ten thousand permanent rows in one block, which may not fit — or an issuer who may add items later, which is exactly the trust the token module refused. Writing the number once and defaulting the owner is the first one's promise at the second one's price. |
|---|---|
| The creator cannot change | Nothing rewrites a collection record. It could not be allowed to: the creator is the default owner of every item that has never moved, so a transition that changed it would silently move the whole unmoved remainder of the collection at once. |
| It costs 10 BKLV | Paid to the treasury, on top of the fee, and it does not come back — the same price a token pays, because it buys the same thing: one row every node carries for the life of the chain. The rows a collection adds later are bounded by transactions, and every transaction pays a fee. |
| Fees stay in BKLV | Moving an item costs a BKLV fee like everything else, so a wallet holding an item and no BKLV cannot move it. Fees are what pays the committee. |
| An NFT buys nothing | It does not enter weight, does not open the registry and is not collateral. Weight is maturity times reliability, and even the registration stake stays out of it. |
Metadata: 32 bytes, and no URI
A collection carries one 32-byte commitment to the metadata of every item in it, fixed at creation. By convention it is the merkle root over the per-item metadata hashes in index order. The chain does not check it and cannot — the manifest lives off the chain, the way a receipt does.
What the chain does guarantee is the part that matters: the root was fixed at creation and no transition moves it, so a creator cannot change what item 4 is after somebody has bought it.
There is no URI field, deliberately. A URI is a promise about somebody else's server that the chain has no way to keep and no way to check. A wallet showing you a picture is trusting whoever served the bytes; all the chain will ever confirm is that those bytes hash into the collection's committed root.
Moving one, and looking one up
./baklava send-nft -keystore wallet.json -collection <id> -item 42 -to bkx1...
./baklava nft-info -item 42 <id>The ownership answer carries two proofs, and the second one is not padding. An item with no leaf of its own is owned by the creator — so an absence proof alone does not say “nobody owns it”, it says “the creator does”, and who that is lives in the collection record. A client handed only the absence proof would have to take the creator's address on the node's word. Both leaves sit in the same tree, so both paths fold to one root and the answer is checked in one step.
Where the items live
In the same tree tokens added, not a fourth one. That is what makes this the cheapest module the chain will build: tokens paid for the third sparse merkle tree and for a versioned fold, and NFTs spend neither again. state_root commits to exactly what rule version 3 already made it commit to.
The table now holds four kinds of leaf — a token record, a token balance, a collection record and an item's owner — told apart by the width of their encoding, the way a registry entry's two encodings already were. The four widths are distinct and a test holds them that way; a decoder never sizes a read from a number a peer chose.
Rule version 3, alongside tokens on baklava-testnet-5.
A rule version is a batch rather than a rule. No chain had activated version 3 when this was written, so NFTs went in beside tokens rather than becoming a version of their own — the same door slashing went through into version 2. That door is now shut: version 3 activated at height 2500, and the next rule to change a state root was a version of its own. See Upgrades and readiness.
The reasoning in full, including why an issuer who may mint later was rejected and what a per-item metadata hash would have cost, is under NFTs in the protocol document.