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.