Skip to content
On this page

Mixins

The FA2 library provides small classes from which you can inherit separately in order to add additional features. They are called mixins.

The mixins that you inherit determine what functionality your tokens have. For example, if you inherit the Nft base class but not the MintNft mixin, your contract has the standard entrypoints for the FA2 standard for NFTs but no mint entrypoint to create NFTs. Therefore, you must deploy the contract with all tokens already in the ledger or define your own way to mint them.

Inheriting mixins

In SmartPy (as in Python) the order in which superclasses are listed is significant. Therefore, you must inherit mixins in the correct order:

  1. The Admin mixin
  2. The transfer policy mixins
  3. The base class; you must inherit the base class (such as NFT) before its related mint and burn mixins
  4. Any other mixins, such as the off-chain and on-chain views

Only the base classes (Nft, Fungible, and SingleAsset) are mandatory if you want to create a token of that kind.

You must also call the superclass __init__() methods in the reverse order.

Use the examples below to help put the mixins in order.

Examples

To use a mixin, add it to the list of classes from which your class inherits and call it from your class's __init__() method. These examples use all of the mixins for each token kind, but you can select the mixins that you want to use.

NFT

smartpy
class ExampleFa2Nft(
    main.Admin,
    main.Nft,
    main.ChangeMetadata,
    main.WithdrawMutez,
    main.MintNft,
    main.BurnNft,
    main.OffchainviewTokenMetadata,
    main.OnchainviewBalanceOf,
):
    def __init__(self, administrator, metadata, ledger, token_metadata):
        main.OnchainviewBalanceOf.__init__(self)
        main.OffchainviewTokenMetadata.__init__(self)
        main.BurnNft.__init__(self)
        main.MintNft.__init__(self)
        main.WithdrawMutez.__init__(self)
        main.ChangeMetadata.__init__(self)
        main.Nft.__init__(self, metadata, ledger, token_metadata)
        main.Admin.__init__(self, administrator)

Fungible

smartpy
class ExampleFa2Fungible(
    main.Admin,
    main.Fungible,
    main.ChangeMetadata,
    main.WithdrawMutez,
    main.MintFungible,
    main.BurnFungible,
    main.OffchainviewTokenMetadata,
    main.OnchainviewBalanceOf,
):
    def __init__(self, administrator, metadata, ledger, token_metadata):
        main.OnchainviewBalanceOf.__init__(self)
        main.OffchainviewTokenMetadata.__init__(self)
        main.BurnFungible.__init__(self)
        main.MintFungible.__init__(self)
        main.WithdrawMutez.__init__(self)
        main.ChangeMetadata.__init__(self)
        main.Fungible.__init__(self, metadata, ledger, token_metadata)
        main.Admin.__init__(self, administrator)

Single Asset

smartpy
class SingleAssetTestFull(
    main.Admin,
    main.SingleAsset,
    main.ChangeMetadata,
    main.WithdrawMutez,
    main.MintSingleAsset,
    main.BurnSingleAsset,
    main.OffchainviewTokenMetadata,
    main.OnchainviewBalanceOf,
):
    def __init__(self, administrator, metadata, ledger, token_metadata):
        main.OnchainviewBalanceOf.__init__(self)
        main.OffchainviewTokenMetadata.__init__(self)
        main.BurnSingleAsset.__init__(self)
        main.MintSingleAsset.__init__(self)
        main.WithdrawMutez.__init__(self)
        main.ChangeMetadata.__init__(self)
        main.SingleAsset.__init__(self, metadata, ledger, token_metadata)
        main.Admin.__init__(self, administrator)

All mixins

Here are all the available mixins:

mixindescription
AdminProvides the is_administrator method and the set_administrator entrypoint.
BurnNftAn example of a burn entrypoint that relies on the transfer policy permissions for the Nft base class. The entrypoint does remove the token_metadata when burning a token.
BurnFungibleSame for the Fungible base class. The entrypoint does not remove the token_metadata when burning a token.
BurnSingleAssetSame for the SingleAsset base class. The entrypoint does not remove the token_metadata when burning a token.
ChangeMetadataProvides the set_metadata entrypoint to change the contract's metadata. Requires the Admin mixin.
MintNftAn example of a mint entrypoint for the Nft base class.
MintFungibleSame for the Fungible base class.
MintSingleAssetSame for the Fungible base class.
OnchainviewBalanceOfNon-standard get_balance_of on-chain view that the mimics balance_of entrypoint logic with a view.
OffChainViewTokenMetadataProvides the token_metadata off-chain view. If present, indexers use it to retrieve the token's metadata. Warning ⚠️ If someone can change the contract's metadata, they can change how indexers see every token metadata.
WithdrawMutezProvides the withdraw_mutez entrypoint for withdrawal of tez from the contract's balance. Requires the Admin mixin.

Mint mixins

The FA2 standard does not require a mint or burn entrypoint, so you are free to code these entrypoints in any way or not provide them at all. You may mint tokens in any number of ways or provide multiple ways to create tokens.

You could also delegate the mint logic to another "minter" contract. In this case, the mint entrypoint in the main contract simply verifies the minter's permission and registers new tokens without any other logic.

The FA2 library provides mint and burn mixins that you can use or adapt to your needs.

WARNING

The Mint* mixins in the library don't provide a way of modifying the metadata of tokens after they are minted.

The Mint* mixins require the Admin mixin.

Example:

python
class NftWithMint(FA2.Admin, FA2.MintNft, FA2.Fa2Nft):
    def __init__(self, admin, **kwargs):
        Fa2Nft.__init__(self, **kwargs)
        Admin.__init__(self, admin)

Mint (NFT)

The MintNft mixin provides a mint entrypoint that takes a list of mint actions. Each mint action is a record of:

  • to_: The address to receive the new tokens
  • metadata: The token metadata

Example:

python
fa2_admin = sp.test_account("fa2_admin")
    NFT0 = fa2.make_metadata(
        name     = "Example FA2",
        decimals = 0,
        symbol   = "EFA2" )
    NFT1 = fa2.make_metadata(
        name     = "Example FA2",
        decimals = 0,
        symbol   = "EFA2-2" )
    example_fa2_nft.mint(
        [
            sp.record(
                to_  = fa2_admin.address, # Who will receive the original mint
                metadata = NFT0
            ),
            sp.record(
                to_  = fa2_admin.address,
                metadata = NFT1
            ),
        ],
        _sender=fa2_admin)

The token ID is an incremental sp.nat.

Mint (fungible)

The MintFungible mixin provides a mint entrypoint that takes a list of mint actions. Each mint action is a record of:

  • amount: The amount of tokens to mint
  • to_: The address to receive the new tokens
  • token: A variant with 2 possible values:
    • "new": The token metadata
    • "existing": The token ID of an existing token

Example:

python
fa2_admin = sp.test_account("fa2_admin")
    TOKEN0 = fa2.make_metadata(
        name     = "Example FA2",
        decimals = 0,
        symbol   = "EFA2" )
    example_fa2_fungible.mint(
        [
            sp.record(
                to_  = fa2_admin.address, # Who will receive the original mint
                amount   = 100_000_000_000,
                token = variant("new", TOKEN0)
            ),
            sp.record(
                to_  = fa2_admin.address
                amount   = 100_000_000_000,
                token = variant("existing", 0)
            ),
        ],
        _sender=FA2_admin)

The token id is an incremental sp.nat.

Mint (single asset)

The MintSingleAsset mixin provides a mint entrypoint that takes a list of mint actions. Each mint action is a record of:

  • amount: The amount of token to mint
  • to_: The address to receive the new tokens

Example:

python
fa2_admin = sp.test_account("fa2_admin")
    alice = sp.test_account("alice")
    TOKEN0 = fa2.make_metadata(
        name     = "Example FA2",
        decimals = 0,
        symbol   = "EFA2" )
    example_fa2_fungible.mint(
        [
            sp.record(
                to_  = fa2_admin.address, # Who will receive the original mint
                amount   = 100_000_000_000,
            ),
            sp.record(
                to_  = alice.address
                amount   = 100_000_000_000,
            ),
        ],
        _sender=fa2_admin)