TSP-2 — Card Standard
PLUMB implementation for unique assets. See PLUMB for the shared token framework.
Conservation law: owner_count(id) = 1.
See the Gold Standard for design rationale and skill architecture.
What Differs from TSP-1
- Leaf represents an asset (unique item), not an account balance
- Invariant: uniqueness, not divisible supply
- No divisible arithmetic — no
balance, no range checks, no splitting - Per-asset state — metadata, royalty, creator, flags live in the leaf
- Creator immutability —
creator_idis set at mint and can never change - Flag-gated operations — transferable, burnable, updatable bits control which PLUMB operations are allowed per asset
Operations are still Pay, Lock, Update, Mint, Burn. What changes is what the circuit enforces inside each.
Asset Leaf — 10 field elements
leaf = hash(asset_id, owner_id, nonce, auth_hash, lock_until,
collection_id, metadata_hash, royalty_bps, creator_id, flags)
| Field | Type | Description |
|---|---|---|
asset_id |
Field | Globally unique asset identifier |
owner_id |
Field | Current owner (account_id hash) |
nonce |
Field | Monotonic counter |
auth_hash |
Field | Hash of owner's authorization secret |
lock_until |
Field | Timestamp lock (0 = unlocked) |
collection_id |
Field | Collection membership (0 = standalone) |
metadata_hash |
Field | Hash of item metadata |
royalty_bps |
Field | Royalty basis points (0-10000) |
creator_id |
Field | Original creator (immutable after mint) |
flags |
Field | Bitfield controlling allowed operations |
First 5 fields occupy the same positions as TSP-1. Last 5 — reserved zeros in TSP-1 — carry per-asset state in TSP-2.
Flags Bitfield
| Bit | Name | When set | When clear |
|---|---|---|---|
| 0 | TRANSFERABLE |
Pay (transfer) allowed | Pay rejected |
| 1 | BURNABLE |
Burn allowed | Burn rejected |
| 2 | UPDATABLE |
Metadata update allowed | Metadata frozen forever |
| 3 | LOCKABLE |
Lock (time-lock) allowed | Lock rejected |
| 4 | MINTABLE |
Re-mint into collection allowed | Collection closed |
Flags are set at mint time and cannot be changed after creation.
A soulbound credential: flags = 0. A game item: flags = 31
(all operations). A standard collectible: flags = 11 (transferable +
burnable + lockable).
Collection Binding
When collection_id != 0, the asset belongs to a collection identified
by its config hash. Collection membership is immutable after mint.
Creator Immutability
creator_id is set at mint and preserved by every subsequent operation.
Provides an unforgeable provenance chain. The Royalties skill reads
royalty_bps from the leaf and royalty_receiver from collection
metadata.
Token Config — 10 field elements
See PLUMB Config.
Collection Metadata — 10 field elements
metadata = hash(name_hash, description_hash, image_hash, site_hash, custom_hash,
max_supply, royalty_receiver, 0, 0, 0)
| Field | Type | Description |
|---|---|---|
name_hash |
Field | Hash of collection name |
description_hash |
Field | Hash of collection description |
image_hash |
Field | Hash of collection image/avatar |
site_hash |
Field | Hash of collection website URL |
custom_hash |
Field | Hash of application-specific data |
max_supply |
Field | Maximum number of assets (0 = unlimited) |
royalty_receiver |
Field | Account that receives royalties on transfers |
| reserved | Field x3 | Extension space |
Merkle Tree
See PLUMB Merkle Tree.
Global Public State
| Field | Type | Description |
|---|---|---|
state_root |
Digest | Merkle root of all assets |
asset_count |
Field | Total number of assets in tree |
config_hash |
Digest | Token configuration commitment |
metadata_hash |
Digest | Collection metadata commitment |
current_time |
Field | Block timestamp for time-lock checks |
Operations
All operations follow the PLUMB proof envelope.
Op 0: Pay (Transfer Ownership)
Constraints:
- Config verified,
pay_authandpay_hookextracted - Asset leaf verifies against
old_root hash(secret) == leaf.auth_hash- If
pay_auth != 0, dual auth required current_time >= leaf.lock_untilleaf.flags & TRANSFERABLEcollection_id,creator_id,royalty_bps,metadata_hash,flagsunchanged- New leaf:
owner_id = new_owner,auth_hash = new_auth,nonce += 1 - New leaf produces
new_root - Nullifier emitted:
hash(asset_id, nonce)
Op 1: Lock (Time-Lock Asset)
Constraints:
- Config verified,
lock_authandlock_hookextracted - Owner auth required
- If
lock_auth != 0, dual auth required leaf.flags & LOCKABLElock_until_time >= leaf.lock_until(extend only)- All immutable fields unchanged
- Leaf:
lock_until = lock_until_time,nonce += 1
Op 2: Update (Config or Metadata)
Config update:
old_root == new_root(state unchanged)- Admin auth,
admin_auth != 0 - New config fields hash to
new_config
Metadata update:
- Owner auth required
flags & UPDATABLE- Only
metadata_hashchanges nonce += 1
Op 3: Mint (Originate)
Constraints:
- Config verified,
mint_authandmint_hookextracted mint_auth != 0(minting enabled)- Mint authorization verified
asset_idnot in tree (non-membership proof)creator_id = minter_id(immutable forever)collection_id,flags,royalty_bpsset (immutable after mint)flags & MINTABLEnonce = 0,lock_until = 0- New leaf produces
new_root new_asset_count == old_asset_count + 1- If
max_supply != 0:new_asset_count <= max_supply
Op 4: Burn (Release)
Constraints:
- Config verified,
burn_authandburn_hookextracted - Owner auth required
- If
burn_auth != 0, dual auth required current_time >= leaf.lock_untilleaf.flags & BURNABLE- Leaf removed (Merkle deletion)
new_asset_count == old_asset_count - 1- Nullifier emitted:
hash(asset_id, nonce)
Hooks
See PLUMB Hook System. All 5 hook slots are available. See Skill Reference for standard hook programs.
Security Properties
All PLUMB framework security properties apply.
Additional TSP-2 properties:
- Uniqueness — non-membership proof at mint, exactly one leaf per
asset_id - Creator immutability —
creator_idset at mint, preserved by all operations - Flag enforcement — operations rejected if the corresponding flag bit is clear
- Supply cap — if
max_supply != 0, minting rejected whenasset_count >= max_supply - Immutable fields —
collection_id,creator_id,royalty_bps,flagsnever change after mint