The Token Program

On Solana everything token related is handled by the SPL Token Program and the Token2022 Program: Solana's native token framework that defines how all tokens are created, managed, and transferred.
It's a single, unified program that handles all token operations across the network, ensuring consistency and interoperability.
Let's start by installing the required package to work with the SPL Token program using Web3.js:
npm i @solana/spl-tokenMint and Token Accounts
Under the hood, creating a Mint and Token account is quite "complicated". There are different instruction that requires different inputs and accounts; the account needs to be made rent exempt before we can actually initialize it, ...
Mint Account
Without any abstraction, creating a Mint account would look like this:
import {
Keypair,
sendAndConfirmTransaction,
SystemProgram,
Transaction,
} from "@solana/web3.js";
import {
createInitializeMint2Instruction,
MINT_SIZE,
getMinimumBalanceForRentExemptMint,
TOKEN_PROGRAM_ID,
} from "@solana/spl-token";
const mint = Keypair.generate();
const mintRent = await getMinimumBalanceForRentExemptMint(connection);
const createAccountInstruction = SystemProgram.createAccount({
fromPubkey: feePayer.publicKey,
newAccountPubkey: mint.publicKey,
space: MINT_SIZE,
lamports: mintRent,
programId: TOKEN_PROGRAM_ID
});
const initializeMintInstruction = createInitializeMint2Instruction(
mint.publicKey, // mint pubkey
6, // decimals
feePayer.publicKey, // mint authority
null, // freeze authority
TOKEN_PROGRAM_ID
);
const transaction = new Transaction().add(
createAccountInstruction,
initializeMintInstruction,
);
const signature = await sendAndConfirmTransaction(connection, transaction, [keypair, mint]);
console.log(`Mint created! Check out your TX here: https://explorer.solana.com/tx/${signature}?cluster=devnet`);Thankfully, the @solana/spl-token package has some abstraction. So we can create a Mint account with a single createMint() function like so:
const mint = await createMint(
connection, // connection
keypair, // payer
keypair.publicKey, // mint authority
null, // freeze authority
6 // decimals
);Token Account
Same goes with the Token account. If we would to create it without any abstractions it would look like this:
import {
Keypair,
sendAndConfirmTransaction,
SystemProgram,
Transaction,
} from "@solana/web3.js";
import {
createInitializeAccount3Instruction,
ACCOUNT_SIZE,
getMinimumBalanceForRentExemptAccount,
TOKEN_PROGRAM_ID,
} from "@solana/spl-token";
const token = Keypair.generate();
const tokenRent = await getMinimumBalanceForRentExemptAccount(connection);
const createAccountInstruction = SystemProgram.createAccount({
fromPubkey: feePayer.publicKey,
newAccountPubkey: token.publicKey,
space: ACCOUNT_SIZE,
lamports: tokenRent,
programId: TOKEN_PROGRAM_ID
});
const initializeTokenInstruction = createInitializeAccount3Instruction(
token.publicKey, // token pubkey
mint.publicKey, // mint pubkey
feePayer.publicKey, // owner pubkey
TOKEN_PROGRAM_ID
);
const transaction = new Transaction().add(
createAccountInstruction,
initializeTokenInstruction,
);
const signature = await sendAndConfirmTransaction(connection, transaction, [keypair, token]);
console.log(`Token created! Check out your TX here: https://explorer.solana.com/tx/${signature}?cluster=devnet`);But same as the Mint account, the @solana/spl-token package has some abstraction to create the Token account. We can use the createAccount() function like so:
const token = await createAccount(
connection, // connection
keypair, // payer
mint.publicKey, // mint pubkey
keypair.publicKey, // owner pubkey
);Associated Token Account
Same goes for the Associated Token account, but the abstraction is not related to the creation of the accounts like for the Mint and Token account, it's mainly related to the address derivation.
So here's how we create an Associated Token account without any abstractions:
import {
sendAndConfirmTransaction,
Transaction,
} from "@solana/web3.js";
import {
TOKEN_PROGRAM_ID,
createAssociatedTokenAccountIdempotentInstruction,
getAssociatedTokenAddress,
} from "@solana/spl-token";
const associatedTokenAccount = await getAssociatedTokenAddress(
mint.publicKey, // mint pubkey
keypair.publicKey, // owner pubkey
false, // allow owner off-curve
TOKEN_PROGRAM_ID
);
// Create ATA creation instructions for all accounts
const createAtaInstruction = createAssociatedTokenAccountIdempotentInstruction(
keypair.publicKey, // payer
associatedTokenAccount, // associated token account address
keypair.publicKey, // owner
mint.publicKey, // mint
TOKEN_PROGRAM_ID
);
const transaction = new Transaction().add(
createAtaInstruction,
);
const signature = await sendAndConfirmTransaction(connection, transaction, [keypair]);
console.log(`Associated Token created! Check out your TX here: https://explorer.solana.com/tx/${signature}?cluster=devnet`);And here's how it looks with abstractions:
const ata = await getOrCreateAssociatedTokenAccount(
connection, // connection
keypair, // payer
mint, // mint pubkey
keypair.publicKey // owner pubkey
);