Tokens on Solana
Tokens are digital assets that represent ownership over diverse categories of assets. Tokenization enables the digitalization of property rights, serving as a fundamental component for managing both fungible and non-fungible assets.
- Fungible Tokens represent interchangeable and divisible assets of the same type and value (ex. USDC).
- Non-fungible Tokens (NFT) represent ownership of indivisible assets (e.g. artwork).
This section will cover the basics of how tokens are represented on Solana. These are referred to as SPL (Solana Program Library) Tokens.
-
The Token Program contains all the instruction logic for interacting with tokens on the network (both fungible and non-fungible).
-
A Mint Account represents a specific type of token and stores global metadata about the token such as the total supply and mint authority (address authorized to create new units of a token).
-
A Token Account keeps track of individual ownership of how many units of a specific type of token (mint account) are owned by a specific address.
There are currently two versions of the Token Program. The original Token Program and the Token Extensions Program (Token2022). The Token Extensions Program functions the same as the original Token Program, but with additional features and improvements. The Token Extensions Program is the recommended version to use for creating new tokens (mint accounts).
Key Points
-
Tokens represent ownership over either fungible (interchangeable) or non-fungible (unique) assets.
-
The Token Program contains all instruction for interacting with both fungible and non-fungible tokens on the network.
-
The Token Extensions Program is a new version of the Token Program that includes additional features while maintaining the same core functionalities.
-
A Mint Account represents a unique token on the network and stores global metadata such as total supply.
-
A Token Account tracks individual ownership of tokens for a specific mint account.
-
An Associated Token Account is a Token Account created with an address derived from the owner's and mint account's addresses.
Token Program
The Token Program contains all the instruction logic for interacting with tokens on the network (both fungible and non-fungible). All tokens on Solana are effectively data accounts owned by the Token Program.
You can find the full list of Token Program instructions here.
Token Program
A few commonly used instructions include:
InitializeMint
: Create a new mint account to represent a new type of token.InitializeAccount
: Create a new token account to hold units of a specific type of token (mint).MintTo
: Create new units of a specific type of token and add them to a token account. This increases the supply of the token and can only be done by the mint authority of the mint account.Transfer
: Transfer units of a specific type of token from one token account to another.
Mint Account
Tokens on Solana are uniquely identified by the address of a Mint Account owned by the Token Program. This account is effectively a global counter for a specific token, and stores data such as:
- Supply: Total supply of the token
- Decimals: Decimal precision of the token
- Mint authority: The account authorized to create new units of the token, thus increasing the supply
- Freeze authority: The account authorized to freeze tokens from being transferred from "token accounts"
Mint Account
The full details stored on each Mint Account include the following:
For reference, here is a Solana Explorer link to the USDC Mint Account.
Token Account
To track the individual ownership of each unit of a specific token, another type of data account owned by the Token Program must be created. This account is referred to as a Token Account.
The most commonly referenced data stored on the Token Account include the following:
- Mint: The type of token the Token Account holds units of
- Owner: The account authorized to transfer tokens out of the Token Account
- Amount: Units of the token the Token Account currently holds
Token Account
The full details stored on each Token Account includes the following:
For a wallet to own units of a certain token, it needs to create a token account for a specific type of token (mint) that designates the wallet as the owner of the token account. A wallet can create multiple token accounts for the same type of token, but each token account can only be owned by one wallet and hold units of one type of token.
Account Relationship
Note that each Token Account's data includes an
owner
field used to identify who has authority over that specific Token Account. This is separate from the program owner specified in the AccountInfo, which is the Token Program for all Token Accounts.
Associated Token Account
To simplify the process of locating a token account's address for a specific mint and owner, we often use Associated Token Accounts.
An Associated Token Account is a token account whose address is deterministically derived using the owner's address and the mint account's address. You can think of the Associated Token Account as the "default" token account for a specific mint and owner.
It's important to understand that an Associated Token Account isn't a different type of token account. It's just a token account with a specific address.
Associated Token Account
This introduces a key concept in Solana development: Program Derived Address (PDA). Conceptually, a PDA provides a deterministic way to generate an address using some predefined inputs. This enables us to easily find the address of an account at a later time.
Here is a Solana Playground example that derives the USDC Associated Token Account address and owner. It will always generate the same address for the same mint and owner.
Specifically, the address for an Associated Token Account is derived using the following inputs. Here is a Solana Playground example that generates the same address as the previous example.
For two wallets to hold units of the same type of token, each wallet needs its own token account for the specific mint account. The image below demonstrates what this account relationship looks like.
Accounts Relationship Expanded
Token Examples
The spl-token
CLI can be used to experiment with
SPL tokens. In the examples below, we'll use the
Solana Playground terminal to run the CLI commands
directly in the browser without having to install the CLI locally.
Creating tokens and accounts requires SOL for account rent deposits and
transaction fees. If it is your first time using Solana Playground, created a
Playground wallet and run the solana airdrop
command in the Playground
terminal. You can also get devnet SOL using the public
web faucet.
Run spl-token --help
for a full description of available commands.
Alternatively, you can install the spl-token CLI locally using the following command. This requires first installing Rust.
In the following sections, the account addresses displayed when you run the CLI command will differ from the example output shown below. Please use the address shown in your Playground terminal when following along. For example, the address output from the
create-token
is the mint account where your Playground wallet is set as the mint authority.
Create a New Token
To create a new token (mint account) run the following command in the Solana Playground terminal.
You should see an output similar to the following below. You can inspect both
the token and transaction details on
Solana Explorer using the
Address
and Signature
.
In the example output below, the unique identifier (address) of the new token is
99zqUzQGohamfYxyo8ykTEbi91iom3CLmwCA75FK5zTg
.
New tokens initially have no supply. You can check the current supply of a token using the following command:
Running the supply
command for a newly created token will return a value of
0
:
Under the hood, creating a new Mint Account requires sending a transaction with two instructions. Here is a Javascript example on Solana Playground.
-
Invoke the System Program to create a new account with enough space for the Mint Account data and then transfer ownership to the Token Program.
-
Invoke the Token Program to initialize the data of the new account as a Mint Account
Create Token Account
To hold units of a particular token, you must first create a token account. To create a new token account, use the following command:
For example, running the following command in the Solana Playground terminal:
Returns the following output:
AfB7uwBEsGtrrBqPTVqEgzWed5XdYfM1psPNLmf7EeX9
is the address of the token account created to hold units of the token specified in thecreate-account
command.
By default the create-account
command creates an
associated token account with your wallet address
as the token account owner.
You can create a token account with a different owner using the following command:
For example, running the following command:
Returns the following output:
Hmyk3FSw4cfsuAes7sanp2oxSkE9ivaH6pMzDzbacqmt
is the address of the token account created to hold units of the token specified in thecreate-account
command (99zqUzQGohamfYxyo8ykTEbi91iom3CLmwCA75FK5zTg
) and owned by the address specified following the--owner
flag (2i3KvjDCZWxBsqcxBHpdEaZYQwQSYE6LXUMx5VjY5XrR
). This is useful when you need to create a token account for another user.
Under the hood, creating an Associated Token Account requires a single instruction that invokes the Associated Token Program. Here is a Javascript example on Solana Playground.
The Associated Token Program uses Cross Program Invocations to handle:
- Invoking the System Program to create a new account using the provided PDA as the address of the new account
- Invoking the Token Program to initialize the Token Account data for the new account.
Alternatively, creating a new Token Account using a randomly generated keypair (not an Associated Token Account) requires sending a transaction with two instructions. Here is a Javascript example on Solana Playground.
-
Invoke the System Program to create a new account with enough space for the Token Account data and then transfer ownership to the Token Program.
-
Invoke the Token Program to initialize the data of the new account as a Token Account
Mint Tokens
To create new units of a token, use the following command:
For example, running the following command:
Returns the following output:
-
99zqUzQGohamfYxyo8ykTEbi91iom3CLmwCA75FK5zTg
is the address of the mint account that tokens are being minted for (increasing total supply). -
AfB7uwBEsGtrrBqPTVqEgzWed5XdYfM1psPNLmf7EeX9
is the address of your wallet's token account that units of the token are being minted to (increasing amount).
To mint tokens to a different token account, specify the address of the intended recipient token account. For example, running the following command:
Returns the following output:
-
99zqUzQGohamfYxyo8ykTEbi91iom3CLmwCA75FK5zTg
is the address of the mint account that tokens are being minted for (increasing total supply). -
Hmyk3FSw4cfsuAes7sanp2oxSkE9ivaH6pMzDzbacqmt
is the address of the token account that units of the token are being minted to (increasing amount).
Under the hood, creating new units of a token requires invoking the MintTo
instruction on the Token Program. This instruction must be signed by the mint
authority. The instruction mints new units of the token to a Token Account and
increases the total supply on the Mint Account. Here is a Javascript example on
Solana Playground.
Transfer Tokens
To transfer units of a token between two token accounts, use the following command:
For example, running the following command:
Returns the following output:
-
AfB7uwBEsGtrrBqPTVqEgzWed5XdYfM1psPNLmf7EeX9
is the address of the token account that tokens are being transferred from. This would be the address of your token account for the specified token being transferred. -
Hmyk3FSw4cfsuAes7sanp2oxSkE9ivaH6pMzDzbacqmt
is the address of the token account that tokens are being transferred to.
Under the hood, transferring tokens requires invoking the Transfer
instruction
on the Token Program. This instruction must be signed by the owner of the
sender's Token Account. The instruction transfers units of a token from one
Token Account to another Token Account. Here is a Javascript example on
Solana Playground.
It's important to understand that both the sender and recipient must have existing token accounts for the specific type of token being transferred. The sender can include additional instructions on the transaction to create the recipient's token account, which generally is the Associated Token Account.
Create Token Metadata
The Token Extensions Program enables additional customizable metadata (such as name, symbol, link to image) to be stored directly on the Mint Account.
To use the Token Extensions CLI flags, ensure you have a local installation of the CLI, version 3.4.0 or later:
cargo install --version 3.4.0 spl-token-cli
To create a new token with the metadata extension enabled, using the following command:
The command returns the following output:
BdhzpzhTD1MFqBiwNdrRy4jFo2FHFufw3n9e8sVjJczP
is the address of the new token created with the metadata extension enabled.
Once a new token is created with the metadata extension enabled, use the following command to initialize the metadata.
The token URI is normally a link to offchain metadata you want to associate with the token. You can find an example of the JSON format here.
For example, running the following command will store the additional metadata directly on the specified mint account:
You can then look up the address of the mint account on an explorer to inspect the metadata. For example, here is a token created with the metadata extension enabled on the SolanaFm explorer.
You can learn more on the Metadata Extension Guide. For more details related to various Token Extensions, refer to the Token Extensions Getting Started Guide and the SPL documentation.