Solana programs Part 2: understanding SPL Associated Token Account
Following Part 1: understanding SPL Token Mint, this article introduces the technical details of the SPL associated token program, another popular official Solana smart contract.
The program provides a convenient way to manage user’s token accounts from a wallet address. Its program id: ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL
The idea is to create a PDA (i.e., program-derived account) from a user’s wallet address and a token mint. There are two main benefits:
- The PDA can serve as the user’s identity token account for each token they own (with respect to a mint)
- Tokens can be sent to any user directly using the user’s PDA as the transfer destination, e.g., in airdrop.
A few take-aways on associated token account (ATA):
- Every ATA is a PDA
- Every ATA is a token account
- Every ATA corresponds to a public key (e.g., wallet address)* and a token mint, and is owned by the *wallet address* (see below for *)
- ATA may be created by anybody (not necessarily the wallet address’ signer)
- Nested ATA may be created and the
RecoverNested
instruction can be used to close a nested ATA.
*wallet address — in fact it can be any pubkey that can be signed by an authority, e.g., a System account or a PDA (see deep dive on Solana account model).
Details
In the following, we will elaborate on two instructions:
AssociatedTokenAccountInstruction::Create
AssociatedTokenAccountInstruction::RecoverNested

Create AssociatedTokenAccount
To create a new associated token account (ATA), users need to supply the following six accounts to function process_create_associated_token_account
:

funder_info
— Funding account (must be a system account)associated_token_account_info
—the ATA address to be createdwallet_account_info
— Wallet address for the new ATAspl_token_mint_info
— The token mint for the new ATAsystem_program_info
— System programspl_token_program
—SPL Token program
The function first calls get_associated_token_address_and_bump_seed_internal
to compute the associated_token_address
(i.e., the PDA) and validates the user input:

Internally, the PDA is computed using Pubkey::find_program_address
and is uniquely determined by three addresses (in seeds
):
wallet_address
token_program_id
token_mint_address

Then, the ATA is created by calling create_pda_account
, and its program owner is set to spl_token_program_id
(i.e., only the spl_token_program
can modify the PDA account’s data):

In spl_token_2022
, it also ensures that the ATA’s owner cannot be changed by calling initialize_immutable_owner
:

Finally, the ATA (which is a Token
account) is initialized by setting its account.mint
to token_mint_address
and account.owner
to wallet_address
:


Note 1: account.owner
here is not the program-level owner (i.e., the spl_token_program
) of the ATA, but its real authority (i.e., the wallet_address
). In other words, wallet_address
fully owns the newly created ATA and the owner of wallet_address
must sign to transfer tokens from the ATA.
Note 2: If the ATA for a given wallet_address
does not yet exist, it may be created by anybody by issuing a transaction containing the AssociatedTokenAccountInstruction::Create
instruction.
RecoverNested
A caveat of using the associated token program is that users may (unintentionally) create a nested ATA:
an associated token account owned by an associated token account
Once that happened, users cannot move funds from a nested ATA because it is not owned by the user’s wallet address, but a PDA.
The RecoverNested
instruction is used to address this issue. It closes a nested ATA and transfers its tokens to the wallet’s ATA (and transfers its lamports to the wallet).

The input wallet_account_info
account must be signed, and the destination_associated_token_account_info
account is the recipient of the transferred tokens:

The transferred token amount
and mint decimals
are extracted from the nested ATA. The signer_seeds
(i.e., owner_associated_token_account_signer_seeds
) include three addresses and the bump_seed
:
wallet_account_info.key
spl_token_program_id
owner_token_mint_info.key
bump_seed

The bump_seed
is the bump seed returned from creating owner_associated_token_address
, which is the PDA owner of the nested ATA (i.e., nested_associated_token_account_info
).
In the next few articles, we will continue to highlight the technical details of a few more Solana programs that are frequently used.
Soteria audit
Soteria is founded by leading minds in the fields of blockchain security and software verification.
We are pleased to provide audit services to high-impact Dapps on Solana. Please visit soteria.dev or email [email protected]
Join Coinmonks Telegram Channel and Youtube Channel learn about crypto trading and investing