Create a Token Account
Learn how to create and initialize token accounts in Solana programs using Anchor. Covers creating Associated Token Accounts (ATAs) and Program Derived Address (PDA) token accounts with code examples.
What is a Token Account?
A token account is an account type in Solana's Token Programs that stores information about an individual's ownership of a specific token (mint). Each token account is associated with a single mint and tracks details like the token balance and owner.
Note that in the source code, a Token account is referred to as an Account
type. Both the Token
Program
and Token Extension
Program
have the same base implementation for the Token account.
To hold tokens for a specific mint, users must first create a token account. Each token account is associated with:
- A specific mint (the token type the token account holds units of)
- An owner (the authority who can transfer tokens from the account)
Let's look at an example using USDC on Solana:
- The USDC mint address is
EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v
- Circle (the USDC issuer) has a token account at
3emsAVdmGKERbHjmGfQ6oZ1e35dkf5iYcS6U4CPKFVaa
- This token account can only hold units of the USDC token (mint)
- Circle is set as the owner at
7VHUFJHWu2CuExkJcJrzhQPJ2oygupTWkL2A2For4BmE
and can transfer these tokens
You can view the details of this token account on Solana Explorer.
The term "owner" is used in two different contexts:
-
The token account "owner" - This is an address stored in the token account's as the "owner" field of the
Account
type defined by the Token Program. The owner can transfer, burn, or delegate tokens from the account. This address is sometimes referred to as the "authority" of the token account to distinguish it from the program owner. -
The program "owner" - This refers to the program that owns the account data on Solana. For token accounts, this is always either the Token Program or Token Extension Program, as specified in the "owner" field of the base Solana Account type.
When working with token accounts, "owner" typically refers to the authority that can spend the tokens, not the program that owns the account.
What is an Associated Token Account?
An associated token account (ATA) is simply a token account with an address that is a PDA derived from and created by the Associated Token Program. You can think of an ATA as the default token account for a user to hold units of a specific token (mint).
Only token accounts created through the Associated Token Program are referred to as associated token accounts.
ATAs provide a deterministic way to find a user's token account for any given mint. You can inspect the implementation of the derivation here.
This deterministic derivation ensures that for any combination of wallet address and token mint, there exists exactly one associated token account address. This approach makes it simple to find a user's token account for any given token mint, eliminating the need to track token account addresses separately.
The Associated Token Program acts as a helper program that creates token
accounts with deterministic addresses (PDAs). When creating an associated
token account, the Associated Token Program makes a CPI (Cross-Program
Invocation) to either the Token Program or Token Extension Program. The
created account is owned by the token program and has the same Account
type
structure as defined in the token program. The Associated Token Program itself
maintains no state - it simply provides a standardized way to create token
accounts at a deterministic address.
Usage
Use the token_interface
and associated_token
modules from the anchor-spl
crate to work with ATAs compatible with either the Token Program and Token
Extension Program.
To create token accounts with PDAs derived from your program, you can use the
token::mint
, token::authority
, and token::token_program
constraints along
with the seeds
and bump
constraints.
Account Types
The
InterfaceAccount
type is a wrapper that allows the account to work with both the Token Program
and Token Extension Program.
The TokenAccount
type represents the base Account
data structure shared by
both token programs. When an account of this type is passed in, Anchor will
automatically deserialize the account data into the Account
struct, regardless
of which token program created it.
Account Constraints
Anchor provides two sets of constraints for working with token accounts:
- Use
associated_token
constraints when working with Associated Token Accounts (ATAs) - Use
token
constraints when working with token accounts that are not specifically ATAs, such as custom PDAs or token accounts with addresses that are public keys from a keypair
The appropriate constraint to use depends on your specific use case. ATAs are recommended for user wallets, while custom token accounts are useful for program controlled accounts.
associated_token
constraints
The following account constraints are used in combination to create and initialize a new associated token account:
Constraint | Description |
---|---|
init | Creates a new account by making a cross program invocation (CPI) to the System Program. This allocates the required space for the token account and transfers ownership to the appropriate token program. |
init_if_needed | Similar to init , but only creates the account if it doesn't already exist. Requires enabling the init-if-needed feature. |
payer | Specifies which account will pay the rent (SOL deposit) required to create the new account. |
associated_token::mint | Specifies the mint account that this token account will be associated with. |
associated_token::authority | Sets the authority (owner) of the token account who has permission to transfer or burn tokens. |
associated_token::token_program | Specifies which token program (Token Program or Token Extension Program) to use when creating the token account. |
token
constraints
The following account constraints are used in combination to create and initialize a new token account:
Constraint | Description |
---|---|
init | Creates a new account by making a cross program invocation (CPI) to the System Program. This allocates the required space for the token account and transfers ownership to the appropriate token program. |
init_if_needed | Similar to init , but only creates the account if it doesn't already exist. Requires enabling the init-if-needed feature. |
payer | Specifies which account will pay the rent (SOL deposit) required to create the new account. |
token::mint | Specifies the mint account that this token account will be associated with. |
token::authority | Sets the authority (owner) of the token account who has permission to transfer or burn tokens. |
token::token_program | Specifies which token program (Token Program or Token Extension Program) to use when creating the token account. |
Note that you can use the same PDA as both the token::authority
and the
token account address. Using a PDA as the token::authority
enables your
program to "sign" CPI instructions to transfer tokens from the token account.
This pattern allows for a single deterministic address for both purposes.
To use the init_if_needed
constraint, enable the init-if-needed
feature in
Cargo.toml
and replace the init
constraint with init_if_needed
.
Examples
The following examples demonstrate how to create a token account in an Anchor program using two different approaches:
-
Using an Associated Token Account (ATA) - This is the standard approach to create a token account for a specific user to hold units of a specific token (mint).
-
Using a Program Derived Address (PDA) - This approach creates a token account where the address is a custom PDA. This allows for deterministic token account addresses specific to your program. You can also set the authority (owner) as a PDA to enable your program to transfer tokens from the token account.
Both approaches are can be done entirely using account constraints.
Create Associated Token Account
Create an associated token account for a user.
Create Token Account using PDA
Create a token account using a Program Derived Address (PDA) as the address of the token account.