Agent index (llms.txt) — fetch this first, then the page it names.
Token factory
x/token lets anyone create a token without writing a contract. A token is a bank denom named factory/<creator address>/<subdenom> and its balances live in the normal bank module.
Creating a token
CreateToken takes:
- +
subdenom, 2 to 44 characters - +
name(up to 64),symbol(up to 16),description(up to 256) - +capability flags:
mint,freeze,permanent_delegate,transfer_fee_bps(0 to 10,000),non_transferable,pause - +
transfer_hook, the bech32 address of an existing CosmWasm contract (--transfer-hookon the command line), or empty for none
It burns a 10 ORAMA creation fee and locks a metadata deposit of 68,359 norama per byte of the text fields (about 0.07 ORAMA per KiB). Deleting the token returns 99% of the deposit to earnings and burns 1%.
What the creator can do
| Message | Rule |
|---|---|
Mint | The creator, while it still holds the mint capability |
Burn | Burns from the signer's own bank balance |
Transfer | A bank send with the pause, non-transferable, freeze and transfer-fee checks. from must be the signer unless the signer is the permanent delegate |
SetFrozen, SetPaused | The creator, while it holds those capabilities |
Renounce | Gives a capability up for good. The permanent delegate alone renounces its own |
SetShieldable | A one-way flag. Refused while freeze, permanent delegate or pause is held. The shielded pool moves ORAMA only, so this does not shield tokens |
DeleteToken | Only when supply is zero |
Capabilities can only be dropped, never added or reassigned. There is no module-level admin key.
What it cannot do
- +A token cannot mint
norama. Onlyx/emissioncan, and a mint of anorama-named denom here is refused. - +A contract can create, mint and burn tokens through the
tokenbinding, again nevernorama. See Contracts.
The transfer hook
A token can name a contract as its transfer hook. The address is checked when the token is created (it must already be a contract), is fixed from then on, and can only be renounced. On every Transfer of that token the chain calls the contract's sudo entry with {"transfer_hook":{"denom","from","to","amount"}} under a gas cap of 100,000.
- +If the contract returns an error, the transfer is refused.
- +If it needs more than the cap, the transfer fails with "transfer hook exceeded gas cap".
- +Either way nothing moves, and whatever the contract wrote is dropped. Its writes are kept only when the transfer succeeds.
- +A build without the contract VM (Contracts) refuses to create a token with a hook.
Because the hook and the transfer fee run only inside Transfer, a bank send of such a token (MsgSend, MsgMultiSend, a contract's BankMsg) is refused. Use Transfer.
Queries
Params, Token and Frozen are public. The invariants tie each token's issued to the bank supply and each deposit to its token/{denom} entry. There is no list query: the explorer lists tokens from the bank's denoms (TotalSupply) and their holders from DenomOwners.