Baklava

Tokens

Anybody can make one. It is a module built into the protocol, not code uploaded to the chain — and nothing about holding one touches who votes.

Making one

a token
./baklava token -keystore wallet.json     -symbol BAK -name "Baklava Points" -supply 21000000

Or /token BAK 21000000 Baklava Points from the console. The whole supply is credited to you in the transaction that creates it, and the id comes back straight away — it is derived from your address and the nonce that made it, so nobody picks it, including the command you just ran.

The supply is finalThere is no mint transition and no owner field. A holder never has to wonder what the creator might do next, because there is nothing they can do. That is a smaller module than most chains ship and the omission is the point: a mint function makes a token's value a claim about somebody's intentions, and a chain can show balances, not intentions.
It costs 10 BKLVPaid to the treasury, on top of the fee, and it does not come back. A token is a leaf that never goes away and every holder of it is another leaf that never goes away — the retention window prunes block bodies, never state. A fee prices the block space a transaction occupies for a moment; this prices the row every node carries for the life of the chain.
Fees stay in BKLVMoving a token costs a BKLV fee like everything else, so a wallet holding a token and no BKLV cannot move it. Fees are what pays the committee, and a fee market across assets anybody can print would make what a block is worth a question about exchange rates the chain has no way to answer.
A token buys nothingIt 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 — a unit somebody printed for 10 BKLV certainly does.

The id is the identity. The symbol is a label.

Symbols and names are not unique and the chain does not check them against each other. Two tokens may both call themselves BAKLAVA and neither is the real one — there is no such thing.

That is deliberate, and it is the safer of two bad options: unique names mean a land rush and a squatting market the chain would have to police for ever. So anything that shows you a symbol without the id is showing you something anybody can copy in one transaction. This is where every fake-token scam on every chain has come from.

A logo, and why it is a commitment rather than a link

From rule version 4 a token record carries a 32-byte commitment to its metadata — its logo, most of the time. It is the same field a collection has carried since NFTs were built, which is the point: an NFT's picture could be checked against the chain and a token's could not.

a token with a logo
sha256sum logo.png                      # the commitment is just its hash
./baklava token -keystore wallet.json     -symbol BAK -supply 21000000 -meta <the 32 bytes, in hex>

Or --meta on /token from the console. There is no URI, for the reason a collection has none: a URI is a promise about another server that the chain has no way to keep and no way to check. Zero means no commitment rather than a commitment to nothing.

It is written once, with the supply, and there is no way to change it.

That is this module's own argument applied to itself. A token is worth holding here because there is nothing the creator can do next — the supply is fixed and there is no mint. A metadata field they could rewrite puts that straight back: a token could be one thing when it was bought and another when it was sold.

It matters most where a stranger's token is put in front of somebody and the picture is most of what they see. A logo a website can change without leaving a trace is a logo that can be swapped for a well-known project's the day before a sale.

Moving one, and looking one up

move and inspect
./baklava send-token -keystore wallet.json     -token <id> -to bkx1... -amount 500000

./baklava token-info -holder bkx1... <id>

token-info checks the proof rather than printing what it was told: the token leaf folds to a token root, which folds with the account root, the registry root and the parameter digest into the state root the header carries. An absent balance is a balance of zero and is proved as one — an address nobody has ever paid in a token holds none of it.

Where the balances live

In a third sparse merkle tree, beside the accounts and the participant registry, and this is the one design decision worth knowing about. A balance is keyed by a pair — which token, whose balance — and the cheap answer is to put it in the account table at a derived key.

That is disqualified by an attack. The account tree's key is the address, so a leaf at H(token ‖ holder) sits at a perfectly valid address that anybody can derive — and anybody can send BKLV to any address. A stranger could pay one Krumb into your token balance and mint with it, and no check can stop them: telling whether twenty bytes are H(token ‖ holder) for some pair means inverting a hash.

So state_root folds four things from rule version 3 rather than three, and the fold takes the rule version — a binary that always folded four would compute a root that no version 1 or version 2 chain ever had. Same problem as a registry entry's width, one level up.

Rule version 3, and baklava-testnet-5 scheduled it itself.

Tokens add a state table, so they change what state_root commits to, so they are a new rule version. What is new is that this no longer meant a new chain: the readiness threshold appended the activation to the schedule while the chain ran, and it took effect at height 2500. See Upgrades and readiness — this is the first rule that mechanism was built for, and the first one it carried.

The reasoning in full, including what a mint transition would have cost and why names are not unique, is under Tokens in the protocol document.