# Custom Tokens

> Learn how to use o1js for common token operations like minting, burning, and sending tokens. How to implement custom tokens on Mina and use the TokenContract class.

Canonical URL: https://docs.minaprotocol.com/zkapps/writing-a-zkapp/feature-overview/custom-tokens

:::info

If you want to create a fungible token you can use the
[fungible token standard](https://github.com/MinaFoundation/mina-fungible-token/blob/main/documentation/SUMMARY.md) which is built on top of the `TokenContract` class.

:::

# Custom Tokens

Blockchain applications have various use cases for custom tokens, including a real-world financial asset, stake in an on-chain protocol, or even skill points in a game.

Most blockchains, like Ethereum, do not natively support custom tokens. You implement custom tokens as smart contracts on top of the execution layer of the underlying protocol.
Token standards ensure the interoperability of applications on Ethereum. These standardisations are agreed upon in ERCs, Ethereum Requests for Comments, such as the fungible token standard [ERC-20](https://ethereum.org/en/developers/docs/standards/tokens/erc-20/).
The Ethereum community has created and agreed upon other reference implementations and standardisation that are audited and easy to configure, such as [ERC-721](https://ethereum.org/en/developers/docs/standards/tokens/erc-721/) for NFTs.

Mina supports custom token functionality at a low level in the tech stack. Mina treats custom tokens almost the same way as the native MINA token. This approach offers the following benefits:

- As a developer, you do not have to manage as many boilerplate contracts.
- Developers don't need to keep track of accounts and balances themselves.
- It is more secure because fewer vulnerabilities can result from incorrect configuration and deployment.

Each account on Mina can have tokens associated with it. With zkApps, you build smart contracts that interact with tokens, such as swapping one token for another or depositing MINA tokens. A token manager smart contract is a standard smart contract with the `TokenContract` class that manipulates tokens.

## Token manager account

The token manager account can set a token symbol (also called token name) for its token. For example, `MYTKN`. Uniqueness is not enforced for token names because the public key of the manager account is used to derive a unique identifier for each token.

A token manager smart contract sets the rules around minting, burning, and sending the custom token:

- Minting generates new tokens. The zkApp updates an account's balance by adding the newly created tokens to it. You can send minted tokens to any existing account in the network.
- Burning tokens is the opposite of minting. Burning tokens deducts the balance of a certain address by the specified amount. A zkApp cannot burn more tokens than the specified account has.
- Sending tokens between two accounts must be approved by a zkApp.

## TokenContract class

Use the `TokenContract` class to perform common token operations, such as minting, burning, and sending tokens. In o1js, the `TokenContract` class is your blueprint for custom token implementations.

As shown in this [example code](https://github.com/o1-labs/o1js/blob/main/src/lib/mina/v1/token/token-contract.unit-test.ts), you inherit from the `TokenContract` class:

```ts
class ExampleTokenContract extends TokenContract {
  // your custom token implementation
}
```

## TokenContract API

For the full signature of every method below, see the
[`TokenContract` API reference](https://docs.o1labs.org/o1js/api-reference/classes/TokenContract)
on the o1Labs docs.

The `TokenContract` comes with a set of prebuilt methods and helpers to get you started in your token journey. The base token smart contract implements the following two APIs:

- `Approvable` leaves the `approveBase()` method to be defined by the subclass
- `Transferable` a wrapper around `Approvable` that deals with transfers of token

Additionally, the token smart contract also comes with an `internal` namespace which contains helper methods that can be used from within a token contract only.

```ts
TokenContract.internal: {
    /**
     * Mints token balance to `address`. Returns the mint account update.
     */
    mint(
      address: PublicKey | AccountUpdate | SmartContract;
      amount: number | bigint | UInt64;
    ): AccountUpdate;
    /**
     * Burn token balance on `address`. Returns the burn account update.
     */
    burn(
      address: PublicKey | AccountUpdate | SmartContract;
      amount: number | bigint | UInt64;
    ): AccountUpdate;
    /**
     * Move token balance from `from` to `to`. Returns the `to` account update.
     */
    send(
      from: PublicKey | AccountUpdate | SmartContract;
      to: PublicKey | AccountUpdate | SmartContract;
      amount: number | bigint | UInt64;
    ): AccountUpdate;
}
```

### The Approvable API

Each subclass token contract that inherits the default `TokenContract` must implement the core `approveBase()` method. It has the following signature:

```ts
approveBase(forest: AccountUpdateForest): void;
```

The `TokenContract` also containts helper methods that make it easy to iterate through and approve a forest of child account updates.
The usual implementation is as easy as this:


```ts
@method async approveBase(forest: AccountUpdateForest) {
  this.checkZeroBalanceChange(forest);
}
```

However, if you want to do a custom implementation for every child account update, you can utilize the `forEachUpdate()` method.

```ts
@method async
approveBase(updates: AccountUpdateForest) {
  let totalBalanceChange = Int64.zero;

  this.forEachUpdate(updates, (accountUpdate, usesToken) => {
    totalBalanceChange = totalBalanceChange.add(
      Provable.if(usesToken, accountUpdate.balanceChange, Int64.zero)
    );
    // additional logic
  });

  // prove that the total balance change is zero
  totalBalanceChange.assertEquals(0);
}
```


The `Approvable` API also provides easy to use wrappers around `approveBase()`, such as the following:

```ts
abstract class TokenContract extends SmartContract {
  /**
    * Approve a single account update (with arbitrarily many children).
    */
  approveAccountUpdate(accountUpdate: AccountUpdate): Promise<void>;;
  /**
    * Approve a list of account updates (with arbitrarily many children).
    */
  approveAccountUpdates(accountUpdates: AccountUpdate[]): Promise<void>;;
  /**
    * Transfer `amount` of tokens from `from` to `to`.
    */
  transfer(from: PublicKey | AccountUpdate, to: PublicKey | AccountUpdate, amount: UInt64): Promise<void>;;
}
```

### The Transferable API


The `Transferable` API is a simple wrapper around the `Approvable` API. It implements the following method:

```ts
abstract class TokenContract extends SmartContract {
  /**
    * Transfer `amount` of tokens from `from` to `to`.
    */
  transfer(
    from: PublicKey | AccountUpdate,
    to: PublicKey | AccountUpdate,
    amount: UInt64 | number | bigint
  ): Promise<void>;
}
```

Which utilizes the `Approvable` API to send tokens from one account to another.

### Further examples

The o1js repository is the most reliable source of working token code, since
its examples are compiled and tested with the library:

- [`token-contract.ts`](https://github.com/o1-labs/o1js/blob/main/src/lib/mina/v1/token/token-contract.ts) — the `TokenContract` implementation itself.
- [`token-methods.ts`](https://github.com/o1-labs/o1js/blob/main/src/lib/mina/v1/token/token-methods.ts) — the underlying mint, burn and send methods.
- [`token-with-proofs.ts`](https://github.com/o1-labs/o1js/blob/main/src/examples/zkapps/token-with-proofs.ts) — approving a token transfer with a proof rather than a signature.

## Custom Token Terminology

If your zkApp interacts with custom tokens, here are the essential terms.

### Token id

Token ids are unique identifiers that distinguish between different types of custom tokens. Custom token identifiers are globally unique across the entire network.

Token ids are derived from a zkApp. To check the token id of a zkApp, use the `this.token.id` property.

### Token Accounts

Token accounts are like regular accounts, but they hold a balance of a specific custom token instead of MINA. A token account is created from an existing account and is specified by a public key _and_ a token id.

Token accounts are specific for each type of custom token, so a single public key can have many different token accounts.

A token account is automatically created for a public key whenever an existing account receives a transaction denoted with a custom token.

When a token account is created for the first time, an account creation fee must be paid the same as creating a new standard account.

In addition to sending custom tokens, a **token owner account** can mint and burn custom tokens. A token owner account is the governing zkApp account for a specific custom token.

### Token Owner

A token owner is an zkApp account that creates, facilitates, and governs how a custom token can be used. The token owner is the account that created the custom token and is the only account that can:

- Mint tokens
- Burn tokens
- Approve sending tokens between two accounts
