MintCap

A MintCap is an object that serves to guarantee minting authority over a certain type.

For each type T created for a Collection there is a corresponding type MintCap<T>. It stands for Mint Capability, and it is object that gives its owner the ability to mint NFTs from its type.

/// `MintCap<T>` delegates the capability of it's owner to mint `T`
struct MintCap<phantom T> has key, store {
    /// `MintCap` ID
    id: UID,
    /// ID of the `Collection` that `MintCap` controls.
    ///
    /// Intended for discovery.
    collection_id: ID,
    /// Supply that `MintCap` can mint
    supply: Option<Supply>,
}

// ...
// Where

/// `Supply` tracks supply parameters
///
/// `Supply` can be frozen, therefore making it impossible to change the
/// maximum supply.
struct Supply has store, drop {
    frozen: bool,
    max: u64,
    current: u64,
}

Limited vs. Unlimited Supply

A MintCap<T> objects can either have the ability to mint an unlimited number of NFTs of its type T, or a limited amount. This property is defined by its field supply. Whenever the option mint_cap.supply is None it means the supply is unlimited and Some it means it is limited.

Creating Mint Caps

There are essentially two ways to create a Mintcap from scratch: We can create it from the Delegated Witness or via the Publisher object.

In the first scenario, you need to acquire DelegatedWitness<T> and call mint_cap::new(). Alternatively, we can create the MintCap in conjunction with the collection object by calling collection::create_with_mint_cap().

Usually this step is done in the init function of the contract, but it can also be done at a later stage just by calling the functions in a transaction.

Fungibility

One interest feature of MintCap<T> is that two mint cap objects of the same type T are fungible. To split two MintCaps we can call mint_cap::split(), and to merge we can call mint_cap::merge().

Minting Function

The minting function must exist in the contract that is deployed by the creator, and therefore there is no such function in the OriginByte protocol. The reason for this is due to how Move works intrinsically, and only the contract that defines its type is responsible for generating objects of such types. That being said, the purpose of the MintCap is to be used in your mint function interface.

When minting NFTs with limited supply, we add &mut MintCap<T> to the function signature:

public entry fun mint_avatar(
    name: String,
    color: String,
    mood: String,
    url: vector<u8>,
    // Need to be mut because supply is limited at 10_000 Avatars
    mint_cap: &mut MintCap<Avatar>,
    warehouse: &mut Warehouse<Avatar>,
    ctx: &mut TxContext,
) {
    let nft = Avatar {
        id: object::new(ctx),
        name,
        url: url::new_unsafe_from_bytes(url),
        color,
        mood,
    };

    mint_event::mint_limited(mint_cap, &nft);
    warehouse::deposit_nft(warehouse, nft);
}

Whereas when minting NFTs with unlimited supply, we only need to add &MintCap<T>:

public entry fun mint_hat(
    type: String,
    // Does not need to be mut because supply is unlimited
    mint_cap: &MintCap<Hat>,
    warehouse: &mut Warehouse<Hat>,
    ctx: &mut TxContext,
) {
    let nft = Hat {
        id: object::new(ctx),
        type,
    };

    mint_event::mint_unlimited(mint_cap, &nft);
    warehouse::deposit_nft(warehouse, nft);
}

Last updated