Asset Management
Understanding how Ingot manages tokens, NFTs, and other digital assets
Asset Management
Overview
Ingot treats assets as "objects" that can be combined, updated, and transferred. The protocol supports fungible tokens, semi-fungible tokens, NFTs, and custom asset types through a flexible asset list system.
Asset List Specification
Assets are represented in payloads using the TLV_ASSET_LIST (type = 0x0101) TLV entry.
Structure
Each asset entry contains:
asset_type : u8 // 0=fungible, 1=semi-fungible, 2=nft, 3=custom
asset_id : [32] // BLAKE3 identifier or upstream asset ID
amount : u128le // For NFT use 1; semi use shares; fungible use quantity
meta_tlv : TLV[] // Bounded extensions (e.g., display/URI, etc.)
Asset Types
- Fungible (0): Interchangeable tokens (e.g., BRC-20 compatible tokens)
- Semi-Fungible (1): Partially interchangeable assets (e.g., shares, batches)
- NFT (2): Unique, non-fungible assets (e.g., ERC-721 compatible NFTs)
- Custom (3): Application-specific asset types
Limits
- Maximum 256 asset items per list
- Single
ASSET_LISTTLV total size โค 48 KiB - Exceeding limits โ indexer rejects parsing
Asset Merging
Ingot supports merging multiple assets into a single output:
- Merging Assets: Bundle multiple items (like tokens from different inputs) into one output
- Balance Conservation: L2 validation ensures input assets = output assets per token type
- Asset List: Explicit asset inventory in payload (TLV format)
- Unique Identification: Each asset instance is uniquely tied to its transaction position (outpoint)
Merging Example
When transferring assets, you can combine multiple asset types:
Input 1: 100 TOKEN_A
Input 2: 50 TOKEN_B
Output: 100 TOKEN_A + 50 TOKEN_B (merged in single Pay2Ingot output)
Asset Merkle Roots
For large asset collections or privacy-sensitive scenarios, use Merkle trees:
TLV_ASSET_MERKLE_ROOT (type = 0x0102)
Structure:
root : [32] // BLAKE3-256 Merkle root
Purpose:
- When asset count is large, only place Merkle root in payload
- Specific asset entries can be selectively revealed as leaves in witness
- Provides "partial visibility" capability
- Enables privacy-preserving asset transfers
Witness: Asset Merkle Proof
WITNESS_ASSET_PROOF structure:
leaf_bytes : TLV[] // TLV encoding identical to ASSET_LIST unit entry
merkle_path : [depth] // Depth โค 8, each step 32B hash
Validation Flow:
- Indexer calculates leaf hash:
leaf_hash = blake3(leaf_bytes) - Reconstruct Merkle root along
merkle_path - Verify reconstructed root equals
ASSET_MERKLE_ROOTin payload - Match success โ leaf considered valid reveal
- Match failure โ indexer rejects this leaf
Standard Schema Templates
Ingot provides production-ready standard schema templates:
Token Schemas
- brc20_compatible.json: BRC-20 compatible tokens (simple, community-friendly)
- trc721_advanced.json: TRC-721 advanced tokens (TLV format, governance, asset conservation)
NFT Schemas
- erc721_compatible.json: ERC-721 compatible NFTs
- music.json: Music NFTs (audio files, lyrics, copyright)
Inscription Schemas
- text.json: Text inscriptions (plain text, Markdown, code)
- image.json: Image inscriptions (SVG, PNG, JPEG, GIF, WebP)
DAO Schemas
- proposal.json: DAO proposals (parameter modifications, fund allocation, code upgrades)
- vote.json: DAO voting (weighted voting, delegation, rationale)
Application Schemas
- social_post.json: Decentralized social media posts
- identity.json: Decentralized identity (W3C DID standard)
Asset Operations
Mint
Creates the first instance of an asset:
- No
parent_instance_idrequired - Does not spend parent tip
- Generates first tip for the artifact
Transfer
Changes ownership of an asset:
- Requires
ALLOW_MUTABLE=1flag - Must spend current tip
- Creates new instance with updated ownership
- Allows
HASH_PAYLOADunchanged (only ownership/lock changes)
Attach
Appends auxiliary data to an asset:
- Requires
ALLOW_MUTABLE=1flag - Must spend current tip
- References parent tip
- Adds new data without changing core asset properties
Mutate
Modifies mutable fields of an asset:
- Requires
ALLOW_MUTABLE=1flag - Must spend current tip
- Changes object mutable fields
- Maintains asset continuity through artifact_id
Bundle
Aggregates multiple artifact_id into a composite object:
- Requires
ALLOW_MUTABLE=1flag - Must spend current tip
- Forms composite object from multiple artifacts
- Enables complex asset compositions
Asset Conservation Rules
L2 indexer validates asset conservation:
- Input Validation: Sum of input assets per
asset_id - Output Validation: Sum of output assets per
asset_id - Conservation: Input assets = Output assets (per token type)
- Violation: Indexer marks as invalid, doesn't become active tip
Partial Visibility
Indexers support partial asset disclosure:
- Merkle Proofs: Verify specific assets without downloading complete asset lists
- Selective Reveals: Only relevant assets are disclosed in witness
- Privacy-Preserving: Unrevealed assets remain hidden
- Verification: Indexers can verify partial asset reveals through Merkle proofs
Time Locks
Assets can be locked with time-based restrictions:
- Time Locks: Delay access to assets via ScriptHash locks
- Vesting Schedules: Assets locked until specific dates or conditions
- Use Cases: Useful for vesting schedules, timed releases, escrow services
- Implementation: Via ScriptHash lock type + VM scripts (OP_CHECKLOCKTIMEVERIFY/OP_CHECKSEQUENCEVERIFY)
Unique Identification
Each asset instance is uniquely identified:
-
artifact_id:
blake3("Ingot/artifact" || SCHEMA_ID || HASH_PAYLOAD)- Cross-version identifier for the same object
- Used for deduplication and reference
-
instance_id:
blake3("Ingot/instance" || artifact_id || outpoint_bytes)- Identifies this UTXO instance (a specific version of the same artifact)
- Where
outpoint_bytes = txid[32] || u32le(vout) - Uniqueness guaranteed by UTXO model
Previous: oUTXO Model | Next: Locking Mechanisms