Page cover image

Token Factory

The Token Factory allows you to create your own native denoms, as recognised by the Cosmos SDK Bank Module.

This allows your protocol to issue its own token, without needing to support the CW20 standard. It means that all tokens on the Kujira network are compatible as gas-fee payments, and can be collected as protocol revenue and distributed to KUJI stakers.

CLI

Create a denom

kujirad tx denom create-denom mydenom

Mint it

kujirad tx denom mint 10000factory/kujira12345/mydenom kujira123...

and Burn it

kujirad tx denom burn 10000factory/kujira12345/mydenom 

CosmWASM Bindings

These commands can also be issued via your smart contracts. Please refer to the bindings published in kujira-rs:

Creation

In order for the contract to be able to mint and burn a denom, it will need to be created by the contract itself, often upon instantation:

use kujira::msg::{DenomMsg, KujiraMsg};

#[cfg_attr(not(feature = "library"), entry_point)]
pub fn instantiate(
    deps: DepsMut<KujiraQuery>,
    env: Env,
    _info: MessageInfo,
    msg: InstantiateMsg,
) -> Result<Response<KujiraMsg>, ContractError> {
    let addr = env.contract.address;
    let denom = format!("factory/{addr}/{denom}");
    let config = Config::new(msg.owner, denom);
    
    CONFIG.save(deps.storage, &config)?;
    Ok(Response::default()
        .add_message(DenomMsg::Create {
            subdenom: msg.denom,
        }))
}

Minting & Burning

Now your contract is the owner of the denom, we can mint and burn tokens. Here is an example contract whose purpose is to provide a permissioned list of addresses that can mint and burn, instead of just the admin:

#[cfg_attr(not(feature = "library"), entry_point)]
pub fn execute(
    deps: DepsMut<KujiraQuery>,
    _env: Env,
    info: MessageInfo,
    msg: ExecuteMsg,
) -> Result<Response<KujiraMsg>, ContractError> {
    let mut c = CONFIG.load(deps.storage)?;
    match msg {
        ExecuteMsg::Burn {} => {
            let amt = amount(&c.denom, info.funds)?;
            c.validate_permitted(info.sender)?;

            Ok(Response::default()
                .add_attributes(vec![attr("action", "burn"), attr("amount", amt)])
                .add_message(CosmosMsg::Custom(KujiraMsg::Denom(DenomMsg::Burn {
                    denom: c.denom,
                    amount: amt,
                }))))
        }
        ExecuteMsg::Mint { amount, recipient } => {
            c.validate_permitted(info.sender)?;
            Ok(Response::default()
                .add_attributes(vec![attr("action", "mint"), attr("amount", amount)])
                .add_message(CosmosMsg::Custom(KujiraMsg::Denom(DenomMsg::Mint {
                    denom: c.denom,
                    amount,
                    recipient,
                }))))
        }
        ExecuteMsg::Permit { address } => {
            c.validate_owner(info.sender)?;
            c.permit(address.clone());
            CONFIG.save(deps.storage, &c)?;
            Ok(Response::default()
                .add_attributes(vec![attr("action", "permit"), attr("address", address)]))
        }
    }
}

Last updated