Skip to content
This repository was archived by the owner on Mar 11, 2025. It is now read-only.

Commit c6689ea

Browse files
committed
Add associated-token-account documentation
1 parent d624117 commit c6689ea

File tree

3 files changed

+111
-83
lines changed

3 files changed

+111
-83
lines changed

docs/sidebars.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ module.exports = {
55
"introduction",
66
"token",
77
"token-swap",
8+
"associated-token-account",
89
"memo",
910
"shared-memory",
1011
],

docs/src/associated-token-account.md

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
---
2+
title: Associated Token Account Program
3+
---
4+
5+
This program defines the convention and the provides the mechanism for mapping
6+
the user's wallet address to the associated token accounts they hold.
7+
8+
It also enables sender-funded token transfers.
9+
10+
See the [SPL Token](token.md) program for more information about tokens in
11+
general.
12+
13+
## Background
14+
15+
Solana's programming model and the definitions of the Solana terms used in this
16+
document are available at:
17+
18+
- https://docs.solana.com/apps
19+
- https://docs.solana.com/terminology
20+
21+
## Source
22+
23+
The Associated Token Account Program's source is available on
24+
[github](https://github.com/solana-labs/solana-program-library).
25+
26+
27+
## Interface
28+
The Associated Token Account Program is written in Rust and available on
29+
[crates.io](https://crates.io/crates/spl-associated-token-account) and
30+
[docs.rs](https://docs.rs/spl-associated-token-account).
31+
32+
33+
### Finding the Associated Token Account address
34+
The associated token account for a given wallet address is simply a
35+
program-derived account consisting of the wallet address itself and the token mint.
36+
37+
The [get_associated_token_address](https://github.com/solana-labs/solana-program-library/blob/associated-token-account-v1.0.0/associated-token-account/program/src/lib.rs#L35)
38+
Rust function may be used by clients to derive the wallet's associated token address.
39+
40+
41+
The associated account address can be derived in Javascript with:
42+
```js
43+
import {PublicKey, PublicKeyNonce} from '@solana/web3.js';
44+
45+
const SPL_TOKEN_PROGRAM_ID: PublicKey = new PublicKey(
46+
'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA',
47+
);
48+
const SPL_ASSOCIATED_TOKEN_ACCOUNT_PROGRAM_ID: PublicKey = new PublicKey(
49+
'ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL',
50+
);
51+
52+
async function findAssociatedTokenAddress(
53+
walletAddress: Pubkey,
54+
tokenMintAddress: Pubkey
55+
): Promise<PublicKey> {
56+
return PublicKey.findProgramAddress(
57+
[
58+
walletAddress.toBuffer(),
59+
SPL_TOKEN_PROGRAM_ID.toBuffer(),
60+
tokenMintAddress.toBuffer(),
61+
],
62+
SPL_ASSOCIATED_TOKEN_ACCOUNT_PROGRAM_ID
63+
)[0];
64+
}
65+
```
66+
67+
68+
### Creating an Associated Token Account
69+
70+
If the associated token account for a given wallet address does not yet exist,
71+
it may be created by *anybody* by issuing a transaction containing the
72+
instruction return by [create_associated_token_account](https://github.com/solana-labs/solana-program-library/blob/associated-token-account-v1.0.0/associated-token-account/program/src/lib.rs#L54).
73+
74+
Regardless of creator the new associated token account will be fully owned by
75+
the wallet, as if the wallet itself had created it.

docs/src/token.md

Lines changed: 35 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -21,20 +21,19 @@ The Token Program's source is available on
2121

2222
## Interface
2323

24-
The on-chain Token Program is written in Rust and available on crates.io as
25-
[spl-token](https://docs.rs/spl-token). The program's [instruction interface
26-
documentation](https://docs.rs/spl-token/2.0.4/spl_token/instruction/enum.TokenInstruction.html)
27-
can also be found there.
24+
The Token Program is written in Rust and available on [crates.io](https://crates.io/crates/spl-token) and [docs.rs](https://docs.rs/spl-token).
2825

29-
Auto-generated C bindings are also available for the on-chain Token Program and
30-
available
26+
Auto-generated C bindings are also available
3127
[here](https://github.com/solana-labs/solana-program-library/blob/master/token/program/inc/token.h)
3228

3329
[JavaScript
3430
bindings](https://github.com/solana-labs/solana-program-library/blob/master/token/js/client/token.js)
3531
are available that support loading the Token Program on to a chain and issue
3632
instructions.
3733

34+
See the [SPL Associated Token Account](associated-token-account.md) program for
35+
convention around wallet address to token account mapping and funding.
36+
3837
## Command-line Utility
3938

4039
The `spl-token` command-line utility can be used to experiment with SPL
@@ -71,9 +70,8 @@ solana config set --url https://devnet.solana.com
7170

7271
#### Default Keypair
7372

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

7876
Keypair File
7977
```
@@ -161,7 +159,7 @@ Unwrapping GJTxcnA5Sydy8YRhqvHxbQ5QNsPyRKvzguodQEaShJje
161159
Signature: f7opZ86ZHKGvkJBQsJ8Pk81v8F3v1VUfyd4kFs4CABmfTnSZK5BffETznUU3tEWvzibgKJASCf7TUpDmwGi8Rmh
162160
```
163161

164-
### Example: Transferring tokens to another user, with sender-funding
162+
### Example: Transferring tokens to another user
165163
First the receiver uses `spl-token create-account` to create their associated
166164
token account for the Token type. Then the receiver obtains their wallet
167165
address by running `solana address` and provides it to the sender.
@@ -228,9 +226,6 @@ Account Token
228226
CqAxDdBRnawzx9q4PYM3wrybLHBhDZ4P6BTV13WsRJYJ AQoKYV7tYpTrFZN6P5oUufbQKAUr9mNYGe1TTJC9wajM 50
229227
```
230228

231-
### Example: Transferring tokens with sender funding
232-
If the recipient a
233-
234229
### Example: Create a non-fungible token
235230

236231
Create the token type,
@@ -526,115 +521,70 @@ Although all SPL Token accounts do have their own address on-chain, there's no
526521
need to surface these additional addresses to the user.
527522

528523
There are two programs that are used by the wallet:
529-
* SPL Token program - generic program that is used by all SPL Tokens
530-
* SPL Associated Token Account program - this program defines the convention and the
531-
provides the mechanism for mapping the user's wallet address to the associated
532-
token accounts they hold.
533-
534-
### Associated Token Account
535-
The associated token account convention allows all tokens to have the same
536-
destination address, allowing the user share their main wallet address to
537-
receive any SPL token.
538-
539-
The following Rust function can be used to derive the address of a user's
540-
associated token account for a given SPL Token mint:
541-
```rust
542-
/// Finds the associated token address for a given wallet
543-
/// address and SPL Token mint
544-
pub fn get_associated_token_address(
545-
wallet_address: &Pubkey,
546-
spl_token_mint_address: &Pubkey,
547-
) -> Pubkey {
548-
Pubkey::find_program_address(
549-
&[
550-
&primary_account_address.to_bytes(),
551-
&spl_token::id().to_bytes(),
552-
&spl_token_mint_address.to_bytes(),
553-
],
554-
&spl_associated_token_account::id()
555-
).0
556-
}
557-
```
558-
559-
560-
Javascript equivalent:
561-
```
562-
import {PublicKey, PublicKeyNonce} from '@solana/web3.js';
563-
564-
async function findAssociatedTokenAddress(
565-
walletAddress: Pubkey,
566-
tokenMintAddress: Pubkey
567-
): Promise<PublicKey> {
568-
return PublicKey.findProgramAddress(
569-
[
570-
walletAddress.toBuffer(),
571-
TOKEN_PROGRAM_ID.toBuffer(),
572-
tokenMintAddress.toBuffer(),
573-
],
574-
SPL_ASSOCIATED_TOKEN_ACCOUNT_PROGRAM_ID
575-
)[0];
576-
}
577-
```
524+
* SPL Token program: generic program that is used by all SPL Tokens
525+
* [SPL Associated Token Account](associated-token-account.md) program: defines
526+
the convention and provides the mechanism for mapping the user's wallet
527+
address to the associated token accounts they hold.
578528

579529
### How to fetch and display token holdings
580530
The [getTokenAccountsByOwner](https://docs.solana.com/apps/jsonrpc-api#gettokenaccountsbyowner)
581531
JSON RPC method can be used to fetch all token accounts for a wallet address.
582532

583-
For each token mint, the wallet could have be multiple token accounts: the
533+
For each token mint, the wallet could have multiple token accounts: the
584534
associated token account and/or other ancillary token accounts
585535

586536
By convention it is suggested that wallets roll up the balances from all token
587537
accounts of the same token mint into a single balance for the user to shield the
588-
user from this complexity. See the
589-
[Garbage Collecting Ancillary Token Accounts](#garbage-collecting-ancillary-token-accounts)
590-
section for suggestions on how the wallet should clean up ancillary token accounts on the user's
538+
user from this complexity.
539+
540+
See the [Garbage Collecting Ancillary Token Accounts](#garbage-collecting-ancillary-token-accounts)
541+
section for suggestions on how the wallet should clean up ancillary token accounts on the user's behalf.
591542

592543
### Associated Token Account
593-
Before the user can receive tokens their associated token account must be created
544+
Before the user can receive tokens, their associated token account must be created
594545
on-chain, requiring a small amount of SOL to mark the account as rent-exempt.
595546

596547
There's no restriction on who can create a user's associated token account. It
597548
could either be created by the wallet on behalf of the user or funded by a 3rd
598549
party through an airdrop campaign.
599550

600-
Ultimately the
601-
`spl_associated_token_account::create_associated_token_account()` instruction
602-
just needs to be executed by some party.
551+
The creation process is described [here](associated-token-account.md#creating-an-associated-token-account).
603552

604553
#### Sample "Add Token" workflow
605-
When the user wants to receive tokens, they should fund their associated token
606-
account.
554+
The user should first fund their associated token when they want to receive tokens of a certain type.
607555

608-
To do so, the wallet should provide a UI that allow the users to "add a token".
556+
The wallet should provide a UI that allow the users to "add a token".
609557
The user selects the kind of token, and is presented with information about how
610-
much SOL it will cost to add the token. Upon confirmation, the wallet sends a
611-
transaction with the
612-
`spl_associated_token_account::create_associated_token_account()` instruction.
558+
much SOL it will cost to add the token.
559+
560+
Upon confirmation, the wallet creates the associated token type as the described
561+
[here](associated-token-account.md#creating-an-associated-token-account).
613562

614563
#### Sample "Airdrop campaign" workflow
615564
For each recipient wallet addresses, send a transaction containing:
616-
1. `spl_associated_token_account::create_associated_token_account()` to create
617-
the recipient's associated token account if necessary
618-
2. `TokenInstruction::Transfer` to complete the airdrop
565+
1. Create the associated token account on the recipient's behalf.
566+
2. Use `TokenInstruction::Transfer` to complete the transfer
619567

620568
#### Associated Token Account Ownership
621-
The wallet should never use `TokenInstruction::SetAuthority` to set the
569+
⚠️ The wallet should never use `TokenInstruction::SetAuthority` to set the
622570
`AccountOwner` authority of the associated token account to another address.
623571

624572
### Ancillary Token Accounts
625573
At any time ownership of an existing SPL Token account may be assigned to the
626574
user. One way to accomplish this is with the
627-
`spl-token authorize <TOKEN_ADDRESS> owner <USER_ADDRESS>` command.
575+
`spl-token authorize <TOKEN_ADDRESS> owner <USER_ADDRESS>` command. Wallets
576+
should be prepared to gracefully manage token accounts that they themselves did
577+
not create for the user.
628578

629579
### Transferring Tokens Between Wallets
630580
The preferred method of transferring tokens between wallets is to transfer into
631581
associated token account of the recipient.
632582

633583
The recipient must provide their main wallet address to the sender. The sender
634584
then:
635-
1. Derives the associated token account for the recipient using `spl_associated_token_account::get_associated_token_address`
585+
1. Derives the associated token account for the recipient
636586
1. Fetches the recipient's associated token account over RPC and checks that it exists.
637-
1. If the recipient's associated token accountdoes not exist, the sender wallet may choose to first fund the recipient's wallet at their expense
587+
1. If the recipient's associated token account does not exist, the sender wallet may choose to first fund the recipient's wallet at their expense
638588
1. Use `TokenInstruction::Transfer` to complete the transfer.
639589

640590
### Registry for token details
@@ -663,3 +613,5 @@ Cleanup Pseudo Steps:
663613
If adding one or more of clean up instructions cause the transaction to exceed
664614
the maximum allowed transaction size, remove those extra clean up instructions.
665615
They can be cleaned up during the next send operation.
616+
617+
The `spl-token gc` command provides an example implementation of this cleanup process.

0 commit comments

Comments
 (0)