Sigil supports custom fungible tokens as native transactions. A custom token is not a contract; it is a typed state record validated by the executor. This is what removes the wrapped-token problem.

Token model

A custom token is identified by a TokenId derived from (issuer_did, token_name, creation_height). Token holders are indexed by DID.
pub struct CustomTokenRecord {
    pub token_id: [u8; 32],
    pub issuer_did: Did,
    pub name: String,           // canonical, lowercased
    pub symbol: String,         // up to 8 chars
    pub decimals: u8,           // 0..=18
    pub total_supply: u128,
    pub mintable: bool,
    pub burnable: bool,
    pub created_at_height: u64,
}

Transactions

VariantPurpose
CreateCustomTokenRegister a new token with initial supply credited to the issuer.
MintCustomTokenMint additional supply (only if mintable = true).
BurnCustomTokenBurn from the caller’s balance (only if burnable = true).
TransferCustomTokenMove tokens between DIDs.

Creation

use sigil_sdk::token::create_custom_token;

let tx = create_custom_token(
    &wallet,
    /* name = */ "demo-token",
    /* symbol = */ "DEMO",
    /* decimals = */ 6,
    /* initial_supply = */ 1_000_000_000_000,
    /* mintable = */ true,
    /* burnable = */ true,
)?;
let receipt = client.submit_and_wait(tx).await?;
let token_id = receipt.events[0].as_token_created().token_id;
Creation costs a flat fee of 100 MINT (debited to the treasury) plus the standard fee market.

Transfer

use sigil_sdk::token::transfer_custom_token;

let tx = transfer_custom_token(
    &wallet,
    /* token_id = */ token_id,
    /* to = */ "did:oas:sigil:agent:bob".parse()?,
    /* amount = */ 100_000_000,
)?;
client.submit_and_wait(tx).await?;
Balances are stored under token/<token_id>/holder/<did> and indexed by token/by-holder/<did>/<token_id>.

Why not a contract

A native typed token is:
  • Uniform across wallets and explorers without per-contract integration code.
  • Free of common bug classes (re-entry, integer overflow, ABI mismatch).
  • Gas-free for transfers — only the flat fee-market cost applies.
  • Indexed at the state-partition level for fast RPC reads.
When you need policy beyond mint, burn, and transfer (vesting curves, on-chain governance hooks, complex transfer rules), wrap a native token in a contract deployed in your zone.

Token discovery

MethodReturns
sigil_getCustomTokenToken record by token_id.
sigil_listTokensByIssuerAll tokens issued by a DID.
sigil_getTokenBalanceBalance of a token for a DID.
sigil_listTokensByHolderAll tokens held by a DID.

Limits

LimitValue
Name3–64 chars, [a-z0-9-]
Symbol1–8 chars, ASCII uppercase
Decimals0..=18
Max supply2^128 − 1

Implementation

  • Types: node/sigil-core/src/custom_token.rs.
  • Executor: node/sigil-node/src/executor_custom_token.rs.
  • RPC: node/sigil-rpc/src/methods/custom_token.rs.

See also