I know it is technically possible to create an associated token account for a seed account, by setting the seed account as the owner and the allowOwnerOffCurve parameter to true when calling the getOrCreateAssociatedTokenAccount function (if necessary, if the seed account is off the curve). However, in order to close the ATA, we need the signature of the owner. How can I get the signature or keypair for the token account in order to close the ATA? Or is it not really feasible / logical to make ATAs for seed accounts (especially if they're off the curve)?

2 Answers 2


As mentioned by the answer above, it's not feasible with an off-curve ATA, you'll need to do this within the program,

You can utilize the CloseAccount within anchor

use anchor_lang::prelude::*;
use anchor_spl::{
    token::{close_account, CloseAccount},
 let cpi_program = ctx.accounts.token_program.to_account_info();

 let cpi_accounts = anchor_spl::token::CloseAccount {
     account: ctx.accounts.vault.to_account_info().clone(),
     destination: ctx.accounts.authority.to_account_info().clone(),
     authority: ctx.accounts.vault.to_account_info().clone(),

 let signer_seeds = [] // todo(OP)
 let cpi_ctx = CpiContext::new_with_signer(cpi_program.clone(), cpi_account, signer_seeds);

Note that your ATA needs to be empty or the instruction fails.

Here's how you'd use this IX with an on-curve address

async function closeAcc() {
    let mint = new PublicKey("Ao7ucCrBERm5tgQwM6tfXLbDA1Fg9DTznVu3SMYrpFot"); // spl token program

    let closeIX = await createCloseAccountInstruction(
        getAssociatedTokenAddressSync(mint, ownerSigner.publicKey),

    const tx = await new Transaction().add(closeIX);
    let txHash = await sendAndConfirmTransaction(conn, tx, [ownerSigner]);


When you say seed accounts, I'm guessing you mean PDAs. You're correct in saying that to make a PDA authorize something we can't make it sign. Solana uses the PDA seeds for this. In native Solana you can call functions with a PDA as a signer using invoke_signed, in anchor the equivalent is with_signer. To answer your question, if you want to close a ATA ownede by a PDA, you just need to call close_account using one of the two.

In anchor this is partially abstracted away though, and you can just use their close_account which should make it easier.

  • When I said seed accounts I was referring to this function from the cookbook. I'm not sure if it's the same as or different from PDAs. Also, is there an invoke_signed function in the JavaScript web3.js (or related) libraries? Commented Jul 11 at 0:17
  • yes, they mean a PDA. And no, PDAs can only be controlled by the program itself. You'll need to add an instruction inside your program that calls invoke_signed (or an abstraction like close_account in anchor) and then call that instruction from web3.js. Jimii's answer below has an example of this.
    – Ahri
    Commented Jul 11 at 8:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.