Skip to main content

Issue a Token

This guide covers the full MLS-01 token lifecycle in Python: issuing, minting, transferring, and managing supply and authority. The same workflow exists for the command line (which explains the underlying concepts: token id, authority address, reserve vs circulating supply), Go, JavaScript, and Rust.

Prerequisites: a funded wallet and a running wallet-rpc-daemon plus indexer (see Developer Setup for ports and authentication).

Issuing

from mintlayer.wallet import Client, IssueTokenParams, TokenMetadata, TokenSupply

wc = Client("http://127.0.0.1:3034")

authority_addr = wc.new_address(0)

result = wc.issue_token(
IssueTokenParams(
account=0,
destination_address=authority_addr,
metadata=TokenMetadata(
token_ticker="MYTOKEN",
number_of_decimals=8,
metadata_uri="https://example.com/mytoken.json",
token_supply=TokenSupply(type="Lockable"),
is_freezable=False,
),
)
)
print(f"token id: {result.token_id} tx: {result.tx_id}")

Supply policies: TokenSupply(type="Lockable") (unlimited minting until locked), "Unlimited", or "Fixed" with a supply amount for a hard cap. The destination address becomes the token authority: the key that controls future operations (minting, freezing, authority transfer). Keep it secure.

Metadata

Publish metadata at the metadata URI following the Token Metadata Standards (MLS-01 schema) so wallets and explorers can render your token. The URI can be updated later by the authority.

Minting and unminting

Wait for the issuance transaction to confirm before minting. Minting moves tokens from the reserve into circulation; unminting reverses it.

from mintlayer.wallet import Amount, MintParams, UnmintParams

mint_result = wc.mint_tokens(
MintParams(
account=0,
token_id=result.token_id,
address=recipient_addr,
amount=Amount(atoms="100000"), # in smallest token units
)
)

wc.unmint_tokens(
UnmintParams(
account=0,
token_id=result.token_id,
amount=Amount(atoms="50000"),
)
)

Transferring and burning

from mintlayer.wallet import TokenSendParams

wc.send_token(
TokenSendParams(
account=0,
token_id=result.token_id,
address=recipient_addr,
amount=Amount(atoms="10000"),
)
)

Authority, freeze, and supply lock

All management operations require the token authority key:

from mintlayer.wallet import ChangeAuthorityParams, FreezeParams, LockSupplyParams, UnfreezeParams

# Irreversible: fixes the supply at the current circulating amount.
# Note the field is account_index, not account.
wc.lock_token_supply(LockSupplyParams(account_index=0, token_id=result.token_id))

wc.freeze_token(FreezeParams(account=0, token_id=result.token_id, is_unfreezable=True))
wc.unfreeze_token(UnfreezeParams(account=0, token_id=result.token_id))
wc.change_token_authority(
ChangeAuthorityParams(account=0, token_id=result.token_id, address=new_authority_addr)
)

Reading token state

from mintlayer.indexer import Client as IndexerClient

idx = IndexerClient("http://127.0.0.1:3000")

token = idx.get_token(result.token_id)
print(f"ticker: {token.token_ticker} circulating: {token.circulating_supply.decimal}")

Manual transaction building

For full custody without the wallet daemon, the wasm module encodes issuance, mint, and freeze inputs/outputs directly and exposes the protocol fee functions (fungible_token_issuance_fee, token_supply_change_fee, token_freeze_fee, token_change_authority_fee). See Tokens and NFTs and Forging custom transactions.