ZkNoid

ZkNoid is the home for provable gaming. On the platform you can try yourself the cutting edge games utilizing Zero-Knowledge proofs or build one using the provided infrastructure. https://www.zknoid.io/

Custom Tokens on Mina

ZkNoid
ZkNoid
Published in
5 min readFeb 28, 2025

--

A token is a versatile digital asset that resides on a blockchain, capable of representing a wide array of concepts — from currency and ownership to access rights and voting power. Unlike standalone cryptocurrencies such as Bitcoin, which operate independently, tokens are typically built on existing blockchain networks and adhere to specific protocols. This flexibility allows them to serve numerous purposes: powering dApps, incentivizing user engagement, and facilitating governance within various projects.

In this series of articles, we will explore the intricacies of different types of tokens and their implementations on the Mina Blockchain. We will begin by examining custom tokens, highlighting how they differ on Mina compared to EVM networks. Additionally, we will discuss the Mina Token Standard, detailing its unique features and advantages that set it apart.

How Are Tokens on Mina Different?

Mina works differently from other blockchains. On EVM chains, fungible tokens run as ERC-20 smart contracts. While it’s possible to create a similar smart contract on Mina that stores user balances as a field, this approach would lead to significant issues with concurrency and user experience.

To solve these problems, the Mina team introduced a built-in solution for custom tokens, allowing them to function almost like the native Mina coin.

Each user has a separate account for each token. Initially, a user has no token accounts, and a new token account is created only when they first interact with a token. Creating a token account costs 1 MINA.

How to use tokens on Mina (for users)?

The easiest way to interact with tokens is through a wallet. Below, we’ll go over how to manage tokens using Auro Wallet.

In the Tokens section of the wallet, you’ll see all your available tokens. If some tokens are missing, click the “+” button to view all available tokens and add them to your main page.

Clicking on a token will display its transaction history.

If you click on the Mina token, you’ll see a full transaction history, since Mina is the native token of the network and is involved in every transaction.

To send a token, simply click the “Send” button. You’ll need to enter:

  • The recipient’s address
  • The amount of tokens to transfer
  • An optional memo (a short string that can be displayed in the explorer)
  • The transaction priority (higher priority means a higher fee)

With these simple steps, you can manage and transfer tokens easily within Auro Wallet.

How to use tokens on Mina(for developers)?

Mina provides a Custom Token API for interacting with custom tokens. However, it’s not the most convenient option, as it requires developers to write their own token contract.

Another challenge with this approach is that before using a contract, you must first compile it and then prove your contract transaction. If every developer created their own token contract, building applications that support multiple arbitrary tokens would become extremely difficult, making interoperability a major issue.

Mina Token Standard

On EVM networks, this problem was solved with the ERC-20 standard, along with well-established implementations that developers can easily reuse.

Mina follows a similar approach by introducing its own token standard, making it easier to create and integrate custom tokens without reinventing the wheel.

The contract is split into two parts: the token contract and the admin contract. This modular design allows flexibility — if you need to modify how certain functions work, you only need to update the admin contract, while the token contract remains unchanged. This ensures compatibility with other applications using the same token.

Token Contract (GitHub)

  • Handles core token functionalities such as minting, burning, and transferring. It also manages the token’s underlying structure and is the contract that users interact with.

Admin Contract (GitHub)

  • Manages admin functions, including whether the token can be minted, paused, or updated via verification key updates.

This approach makes token development on Mina more efficient while maintaining flexibility and interoperability.

Token deployment

To deploy a token you should deploy token contract, admin contract and then initialize token contract with admin address:

// Source: <https://github.com/MinaFoundation/mina-fungible-token/blob/main/examples/e2e.eg.ts>
const contract = PrivateKey.randomKeypair()
const admin = PrivateKey.randomKeypair()

const token = new FungibleToken(contract.publicKey)
const adminContract = new FungibleTokenAdmin(admin.publicKey)

console.log("Deploying token contract.")
const deployTx = await Mina.transaction({
sender: deployer,
fee,
}, async () => {
AccountUpdate.fundNewAccount(deployer, 3)
await adminContract.deploy({ adminPublicKey: admin.publicKey })
await token.deploy({
symbol: "abc",
src: "<https://github.com/MinaFoundation/mina-fungible-token/blob/main/FungibleToken.ts>",
allowUpdates: true,
})
await token.initialize(
admin.publicKey,
UInt8.from(9),
Bool(false),
)

Token integration

Interact with a token from your contract is quite straightforward. Here is an example of escrow contract — https://github.com/MinaFoundation/mina-fungible-token/blob/main/examples/escrow.eg.ts

Let’s take a look at deposit function — https://github.com/MinaFoundation/mina-fungible-token/blob/8dbf75a4a50d236d9a9ab137a7fd451bafddae41/examples/escrow.eg.ts#L42

First it takes address of our token from state, that was initialized on deployment and check that this token is equal to the tokenId, that is using for proving:

const token = new FungibleToken(this.tokenAddress.getAndRequireEquals())
token.deriveTokenId().assertEquals(this.tokenId)

Then we force sender to sign his account. Without these lines — anyone would be able to send anyone tokens:

const sender = this.sender.getUnconstrained()    
const senderUpdate = AccountUpdate.createSigned(sender)
senderUpdate.body.useFullCommitment = Bool(true)

And finally we are transferring tokens and update total deposit amount:

await token.transfer(sender, this.address, amount)

const total = this.total.getAndRequireEquals()
this.total.set(total.add(amount))

Creation of transaction requires an additional step(https://github.com/MinaFoundation/mina-fungible-token/blob/8dbf75a4a50d236d9a9ab137a7fd451bafddae41/examples/escrow.eg.ts#L178). Not only you have to call function itself:

await escrow.deposit(new UInt64(2e9))

But also you should add token account updates, that was generated during this call:

await token.approveAccountUpdate(escrow.self)

--

--

ZkNoid
ZkNoid

Published in ZkNoid

ZkNoid is the home for provable gaming. On the platform you can try yourself the cutting edge games utilizing Zero-Knowledge proofs or build one using the provided infrastructure. https://www.zknoid.io/

ZkNoid
ZkNoid

Written by ZkNoid

Platform for games with provable game process based on Mina protocol and o1js. Docs – docs.zknoid.io. Github – github.com/ZkNoid. Twitter – https://x.com/ZkNoid

No responses yet