Create and manage SPL token accounts for holding tokens on Solana. This includes creating Associated Token Accounts (ATAs) and closing empty accounts to reclaim SOL.Documentation Index
Fetch the complete documentation index at: https://docs.getpara.com/llms.txt
Use this file to discover all available pages before exploring further.
Setup Solana Libraries First
- @solana/kit
- @solana/web3.js
- Anchor
import { useParaSolanaSigner, useParaSolanaSignAndSend } from '@getpara/react-sdk';
import {
createSolanaRpc,
pipe,
createTransactionMessage,
setTransactionMessageFeePayer,
setTransactionMessageLifetimeUsingBlockhash,
appendTransactionMessageInstruction,
address
} from '@solana/kit';
import {
getCreateAssociatedTokenAccountInstruction,
findAssociatedTokenPda,
getCloseAccountInstruction
} from '@solana-program/token';
const rpc = createSolanaRpc("https://api.mainnet-beta.solana.com");
function ManageTokenAccounts() {
const { solanaSigner, isLoading } = useParaSolanaSigner({ rpc });
const { signAndSendAsync, isPending } = useParaSolanaSignAndSend(solanaSigner);
const createTokenAccount = async (mint: string, owner?: string) => {
if (!solanaSigner) return;
const mintAddress = address(mint);
const ownerAddress = owner ? address(owner) : solanaSigner.address;
const [ata] = await findAssociatedTokenPda({
mint: mintAddress,
owner: ownerAddress,
});
const accountInfo = await rpc.getAccountInfo(ata).send();
if (accountInfo.value) {
console.log("Token account already exists:", ata);
return ata;
}
const { value: latestBlockhash } = await rpc.getLatestBlockhash().send();
const transaction = pipe(
createTransactionMessage({ version: 0 }),
tx => setTransactionMessageFeePayer(solanaSigner.address, tx),
tx => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx),
tx => appendTransactionMessageInstruction(
getCreateAssociatedTokenAccountInstruction({
ata,
mint: mintAddress,
owner: ownerAddress,
payer: solanaSigner,
}),
tx
)
);
try {
const result = await signAndSendAsync({ transactions: [transaction] });
console.log("Created token account:", ata);
console.log("Transaction signature:", result);
return ata;
} catch (error) {
console.error("Failed to create token account:", error);
throw error;
}
};
const closeTokenAccount = async (tokenAccount: string) => {
if (!solanaSigner) return;
const { value: latestBlockhash } = await rpc.getLatestBlockhash().send();
const transaction = pipe(
createTransactionMessage({ version: 0 }),
tx => setTransactionMessageFeePayer(solanaSigner.address, tx),
tx => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx),
tx => appendTransactionMessageInstruction(
getCloseAccountInstruction({
account: address(tokenAccount),
destination: solanaSigner.address,
authority: solanaSigner,
}),
tx
)
);
try {
const result = await signAndSendAsync({ transactions: [transaction] });
console.log("Closed token account:", tokenAccount);
console.log("Transaction signature:", result);
return result;
} catch (error) {
console.error("Failed to close token account:", error);
throw error;
}
};
return (
<div>
<button onClick={() => createTokenAccount("USDC_MINT_ADDRESS")}>
Create USDC Account
</button>
<button onClick={() => closeTokenAccount("TOKEN_ACCOUNT_ADDRESS")}>
Close Token Account
</button>
</div>
);
}
import { useParaSolana } from './hooks/useParaSolana';
import { Transaction, PublicKey } from '@solana/web3.js';
import {
createAssociatedTokenAccountInstruction,
getAssociatedTokenAddress,
createCloseAccountInstruction,
TOKEN_PROGRAM_ID,
ASSOCIATED_TOKEN_PROGRAM_ID
} from '@solana/spl-token';
function ManageTokenAccounts() {
const { connection, signer } = useParaSolana();
const createTokenAccount = async (mint: string, owner?: string) => {
const mintPubkey = new PublicKey(mint);
const ownerPubkey = owner ? new PublicKey(owner) : signer.sender;
const ata = await getAssociatedTokenAddress(mintPubkey, ownerPubkey);
const accountInfo = await connection.getAccountInfo(ata);
if (accountInfo) {
console.log("Token account already exists:", ata.toString());
return ata;
}
const transaction = new Transaction().add(
createAssociatedTokenAccountInstruction(
signer.sender,
ata,
ownerPubkey,
mintPubkey,
TOKEN_PROGRAM_ID,
ASSOCIATED_TOKEN_PROGRAM_ID
)
);
try {
const signature = await signer.sendTransaction(transaction);
console.log("Created token account:", ata.toString());
console.log("Transaction signature:", signature);
return ata;
} catch (error) {
console.error("Failed to create token account:", error);
throw error;
}
};
const closeTokenAccount = async (tokenAccount: string) => {
const tokenAccountPubkey = new PublicKey(tokenAccount);
const transaction = new Transaction().add(
createCloseAccountInstruction(
tokenAccountPubkey,
signer.sender,
signer.sender,
[],
TOKEN_PROGRAM_ID
)
);
try {
const signature = await signer.sendTransaction(transaction);
console.log("Closed token account:", tokenAccount);
console.log("Transaction signature:", signature);
return signature;
} catch (error) {
console.error("Failed to close token account:", error);
throw error;
}
};
return (
<div>
<button onClick={() => createTokenAccount("USDC_MINT_ADDRESS")}>
Create USDC Account
</button>
<button onClick={() => closeTokenAccount("TOKEN_ACCOUNT_ADDRESS")}>
Close Token Account
</button>
</div>
);
}
Token account management uses
@solana-program/token with Codama-generated helpers:import { useParaSolanaSigner } from "@getpara/react-sdk";
import { createSolanaRpc } from "@solana/kit";
import { pipe, createTransactionMessage, setTransactionMessageFeePayerSigner,
setTransactionMessageLifetimeUsingBlockhash, appendTransactionMessageInstruction,
signAndSendTransactionMessageWithSigners } from "@solana/kit";
import { getCreateAssociatedTokenInstruction, findAssociatedTokenPda } from "@solana-program/token";
const rpc = createSolanaRpc("https://api.devnet.solana.com");
function CreateTokenAccount() {
const { solanaSigner, isLoading } = useParaSolanaSigner({ rpc });
const createAccount = async (mintAddress: string) => {
if (!solanaSigner) return;
const { value: latestBlockhash } = await rpc.getLatestBlockhash().send();
const [ata] = await findAssociatedTokenPda({
mint: mintAddress as any,
owner: solanaSigner.address as any,
});
const instruction = getCreateAssociatedTokenInstruction({
payer: solanaSigner,
owner: solanaSigner.address as any,
mint: mintAddress as any,
ata,
});
const tx = pipe(
createTransactionMessage({ version: 0 }),
tx => setTransactionMessageFeePayerSigner(solanaSigner, tx),
tx => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx),
tx => appendTransactionMessageInstruction(instruction, tx),
);
const signature = await signAndSendTransactionMessageWithSigners(tx);
console.log("Token account created:", signature);
};
if (isLoading) return <p>Loading...</p>;
return <button onClick={() => createAccount("mint-address...")}>Create Token Account</button>;
}