Token Program

A Fungible Token program on the Solana blockchain.

This program provides an interface and implementation that third parties can utilize to create and use their tokens.

Background

Solana's programming model and the definitions of the Solana terms used in this document are available at:

Source

The Token Program's source is available on github

Interface

The on-chain Token Program is written in Rust and available on crates.io as spl-token. The program's instruction interface documentation can also be found there.

Auto-generated C bindings are also available for the on-chain Token Program and available here

JavaScript bindings are available that support loading the Token Program on to a chain and issue instructions.

Command-line Utility

The spl-token command-line utility can be used to experiment with SPL tokens. Once you have Rust installed, run:

$ cargo install spl-token-cli

Run spl-token --help for a full description of available commands.

Configuration

The spl-token configuration is shared with the solana command-line tool.

Current Configuration

solana config get
Config File: ${HOME}/.config/solana/cli/config.yml
RPC URL: https://api.mainnet-beta.solana.com
WebSocket URL: wss://api.mainnet-beta.solana.com/ (computed)
Keypair Path: ${HOME}/.config/solana/id.json

Cluster RPC URL

See Solana clusters for cluster-specific RPC URLs

solana config set --url https://devnet.solana.com

Default Keypair

See [Keypair conventions] (https://docs.solana.com/cli/conventions#keypair-conventions) for information on how to setup a keypair if you don't already have one.

Keypair File

solana config set --keypair ${HOME}/new-keypair.json

Hardware Wallet URL (See URL spec)

solana config set --keypair usb://ledger/

Example: Creating your own Token

$ spl-token create-token
Creating token AQoKYV7tYpTrFZN6P5oUufbQKAUr9mNYGe1TTJC9wajM
Signature: 47hsLFxWRCg8azaZZPSnQR8DNTRsGyPNfUK7jqyzgt7wf9eag3nSnewqoZrVZHKm8zt3B6gzxhr91gdQ5qYrsRG4

The unique identifier of the token is AQoKYV7tYpTrFZN6P5oUufbQKAUr9mNYGe1TTJC9wajM.

Tokens when initially created by spl-token have no supply:

spl-token supply AQoKYV7tYpTrFZN6P5oUufbQKAUr9mNYGe1TTJC9wajM
0

Let's mint some. First create an account to hold a balance of the new AQoKYV7tYpTrFZN6P5oUufbQKAUr9mNYGe1TTJC9wajM token:

$ spl-token create-account AQoKYV7tYpTrFZN6P5oUufbQKAUr9mNYGe1TTJC9wajM
Creating account 7UX2i7SucgLMQcfZ75s3VXmZZY4YRUyJN9X1RgfMoDUi
Signature: 42Sa5eK9dMEQyvD9GMHuKxXf55WLZ7tfjabUKDhNoZRAxj9MsnN7omriWMEHXLea3aYpjZ862qocRLVikvkHkyfy

7UX2i7SucgLMQcfZ75s3VXmZZY4YRUyJN9X1RgfMoDUi is now an empty account:

$ spl-token balance 7UX2i7SucgLMQcfZ75s3VXmZZY4YRUyJN9X1RgfMoDUi
0

Mint 100 tokens into the account:

$ spl-token mint AQoKYV7tYpTrFZN6P5oUufbQKAUr9mNYGe1TTJC9wajM 100 \
7UX2i7SucgLMQcfZ75s3VXmZZY4YRUyJN9X1RgfMoDUi
Minting 100 tokens
Token: AQoKYV7tYpTrFZN6P5oUufbQKAUr9mNYGe1TTJC9wajM
Recipient: 7UX2i7SucgLMQcfZ75s3VXmZZY4YRUyJN9X1RgfMoDUi
Signature: 41mARH42fPkbYn1mvQ6hYLjmJtjW98NXwd6pHqEYg9p8RnuoUsMxVd16RkStDHEzcS2sfpSEpFscrJQn3HkHzLaa

The token supply and account balance now reflect the result of minting:

$ spl-token supply AQoKYV7tYpTrFZN6P5oUufbQKAUr9mNYGe1TTJC9wajM
100
$ spl-token balance 7UX2i7SucgLMQcfZ75s3VXmZZY4YRUyJN9X1RgfMoDUi
100

Example: View all Tokens that you own

$ spl-token accounts
Account Token Balance
-------------------------------------------------------------------------------------------------
2ryb53FGVLVYFXmAemN7avawevuNFXwTVetMpH9ag3XZ 7e2X5oeAAJyUTi4PfSGXFLGhyPw2H8oELm1mx87ZCgwF 84
7UX2i7SucgLMQcfZ75s3VXmZZY4YRUyJN9X1RgfMoDUi AQoKYV7tYpTrFZN6P5oUufbQKAUr9mNYGe1TTJC9wajM 100
CqAxDdBRnawzx9q4PYM3wrybLHBhDZ4P6BTV13WsRJYJ AQoKYV7tYpTrFZN6P5oUufbQKAUr9mNYGe1TTJC9wajM 0
JAopo117aj6HMwCRjXSyNpZfGDJRi7ukqHgs2inXD8Rc AQoKYV7tYpTrFZN6P5oUufbQKAUr9mNYGe1TTJC9wajM 0

Example: Wrapping SOL in a Token

$ spl-token wrap 1
Wrapping 1 SOL into GJTxcnA5Sydy8YRhqvHxbQ5QNsPyRKvzguodQEaShJje
Signature: 4f4s5QVMKisLS6ihZcXXPbiBAzjnvkBcp2A7KKER7k9DwJ4qjbVsQBKv2rAyBumXC1gLn8EJQhwWkybE4yJGnw2Y

To unwrap the Token back to SOL:

$ spl-token unwrap GJTxcnA5Sydy8YRhqvHxbQ5QNsPyRKvzguodQEaShJje
Unwrapping GJTxcnA5Sydy8YRhqvHxbQ5QNsPyRKvzguodQEaShJje
Amount: 1 SOL
Recipient: vines1vzrYbzLMRdu58ou5XTby4qAqVRLmqo36NKPTg
Signature: f7opZ86ZHKGvkJBQsJ8Pk81v8F3v1VUfyd4kFs4CABmfTnSZK5BffETznUU3tEWvzibgKJASCf7TUpDmwGi8Rmh

Example: Transferring tokens

$ spl-token create-account AQoKYV7tYpTrFZN6P5oUufbQKAUr9mNYGe1TTJC9wajM
Creating account CqAxDdBRnawzx9q4PYM3wrybLHBhDZ4P6BTV13WsRJYJ
Signature: 4yPWj22mbyLu5mhfZ5WATNfYzTt5EQ7LGzryxM7Ufu7QCVjTE7czZdEBqdKR7vjKsfAqsBdjU58NJvXrTqCXvfWW
$ spl-token accounts AQoKYV7tYpTrFZN6P5oUufbQKAUr9mNYGe1TTJC9wajM
Account Token Balance
-------------------------------------------------------------------------------------------------
7UX2i7SucgLMQcfZ75s3VXmZZY4YRUyJN9X1RgfMoDUi AQoKYV7tYpTrFZN6P5oUufbQKAUr9mNYGe1TTJC9wajM 100
CqAxDdBRnawzx9q4PYM3wrybLHBhDZ4P6BTV13WsRJYJ AQoKYV7tYpTrFZN6P5oUufbQKAUr9mNYGe1TTJC9wajM 0
$ spl-token transfer 7UX2i7SucgLMQcfZ75s3VXmZZY4YRUyJN9X1RgfMoDUi 50 CqAxDdBRnawzx9q4PYM3wrybLHBhDZ4P6BTV13WsRJYJ
Transfer 50 tokens
Sender: 7UX2i7SucgLMQcfZ75s3VXmZZY4YRUyJN9X1RgfMoDUi
Recipient: CqAxDdBRnawzx9q4PYM3wrybLHBhDZ4P6BTV13WsRJYJ
Signature: 5a3qbvoJQnTAxGPHCugibZTbSu7xuTgkxvF4EJupRjRXGgZZrnWFmKzfEzcqKF2ogCaF4QKVbAtuFx7xGwrDUcGd
$ spl-token accounts AQoKYV7tYpTrFZN6P5oUufbQKAUr9mNYGe1TTJC9wajM
Account Token Balance
-------------------------------------------------------------------------------------------------
7UX2i7SucgLMQcfZ75s3VXmZZY4YRUyJN9X1RgfMoDUi AQoKYV7tYpTrFZN6P5oUufbQKAUr9mNYGe1TTJC9wajM 50
CqAxDdBRnawzx9q4PYM3wrybLHBhDZ4P6BTV13WsRJYJ AQoKYV7tYpTrFZN6P5oUufbQKAUr9mNYGe1TTJC9wajM 50

Operational overview

Creating a new token type

A new token type can be created by initializing a new Mint with the InitializeMint instruction. The Mint is used to create or "mint" new tokens, and these tokens are stored in Accounts. A Mint is associated with each Account, which means that the total supply of a particular token type is equal to the balances of all the associated Accounts.

It's important to note that the InitializeMint instruction does not require the Solana account being initialized also be a signer. The InitializeMint instruction should be atomically processed with the system instruction that creates the Solana account by including both instructions in the same transaction.

Once a Mint is initialized, the mint_authority can create new tokens using the MintTo instruction. As long as a Mint contains a valid mint_authority, the Mint is considered to have a non-fixed supply, and the mint_authority can create new tokens with the MintTo instruction at any time. The SetAuthority instruction can be used to irreversibly set the Mint's authority to None, rendering the Mint's supply fixed. No further tokens can ever be Minted.

Token supply can be reduced at any time by issuing a Burn instruction which removes and discards tokens from an Account.

Creating accounts

Accounts hold token balances and are created using the InitializeAccount instruction. Each Account has an owner who must be present as a signer in some instructions.

Balances can be transferred between Accounts using the Transfer instruction. The owner of the source Account must be present as a signer in the Transfer instruction.

An Account's owner may transfer ownership of an account to another using the SetAuthority instruction.

It's important to note that the InitializeAccount instruction does not require the Solana account being initialized also be a signer. The InitializeAccount instruction should be atomically processed with the system instruction that creates the Solana account by including both instructions in the same transaction.

Burning

The Burn instruction decreases an Account's token balance without transferring to another Account, effectively removing the token from circulation permanently.

Authority delegation

Account owners may delegate authority over some or all of their token balance using the Approve instruction. Delegated authorities may transfer or burn up to the amount they've been delegated. Authority delegation may be revoked by the Account's owner via the Revoke instruction.

Multisignatures

M of N multisignatures are supported and can be used in place of Mint authorities or Account owners or delegates. Multisignature authorities must be initialized with the InitializeMultisig instruction. Initialization specifies the set of N public keys that are valid and the number M of those N that must be present as instruction signers for the authority to be legitimate.

It's important to note that the InitializeMultisig instruction does not require the Solana account being initialized also be a signer. The InitializeMultisig instruction should be atomically processed with the system instruction that creates the Solana account by including both instructions in the same transaction.

Freezing accounts

The Mint may also contain a freeze_authority which can be used to issue FreezeAccount instructions that will render an Account unusable. Token instructions that include a frozen account will fail until the Account is thawed using the ThawAccount instruction. The SetAuthority instruction can be used to change a Mint's freeze_authority. If a Mint's freeze_authority is set to None then account freezing and thawing is permanently disabled and all currently frozen accounts will also stay frozen permanently.

Wrapping SOL

The Token Program can be used to wrap native SOL. Doing so allows native SOL to be treated like any other Token program token type and can be useful when being called from other programs that interact with the Token Program's interface.

Accounts containing wrapped SOL are associated with a specific Mint called the "Native Mint" using the public key So11111111111111111111111111111111111111112.

These accounts have a few unique behaviors

  • InitializeAccount sets the balance of the initialized Account to the SOL balance of the Solana account being initialized, resulting in a token balance equal to the SOL balance.
  • Transfers to and from not only modify the token balance but also transfer an equal amount of SOL from the source account to the destination account.
  • Burning is not supported
  • When closing an Account the balance may be non-zero.

In spl-token v2, the Native Mint supply will always report 0, regardless of how much SOL is currently wrapped.

Rent-exemption

To ensure a reliable calculation of supply, a consistency valid Mint, and consistently valid Multisig accounts all Solana accounts holding a Account, Mint, or Multisig must contain enough SOL to be considered rent exempt

Closing accounts

An account may be closed using the CloseAccount instruction. When closing an Account, all remaining SOL will be transferred to another Solana account (doesn't have to be associated with the Token Program). Non-native Accounts must have a balance of zero to be closed.