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:
- The
Admin
mixin - The transfer policy mixins
- The base class; you must inherit the base class (such as
NFT
) before its related mint and burn mixins - 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
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
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
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:
mixin | description |
---|---|
Admin | Provides the is_administrator method and the set_administrator entrypoint. |
BurnNft | An 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. |
BurnFungible | Same for the Fungible base class. The entrypoint does not remove the token_metadata when burning a token. |
BurnSingleAsset | Same for the SingleAsset base class. The entrypoint does not remove the token_metadata when burning a token. |
ChangeMetadata | Provides the set_metadata entrypoint to change the contract's metadata. Requires the Admin mixin. |
MintNft | An example of a mint entrypoint for the Nft base class. |
MintFungible | Same for the Fungible base class. |
MintSingleAsset | Same for the Fungible base class. |
OnchainviewBalanceOf | Non-standard get_balance_of on-chain view that the mimics balance_of entrypoint logic with a view. |
OffChainViewTokenMetadata | Provides 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. |
WithdrawMutez | Provides 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:
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 tokensmetadata
: The token metadata
Example:
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 mintto_
: The address to receive the new tokenstoken
: A variant with 2 possible values:"new"
: The token metadata"existing"
: The token ID of an existing token
Example:
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 mintto_
: The address to receive the new tokens
Example:
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)