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
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);
close_account(cpi_account)?;
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),
ownerSigner.publicKey,
ownerSigner.publicKey
);
const tx = await new Transaction().add(closeIX);
let txHash = await sendAndConfirmTransaction(conn, tx, [ownerSigner]);
console.log(txHash);
}
closeAcc().then().catch(console.error);
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 likeclose_account
in anchor) and then call that instruction from web3.js. Jimii's answer below has an example of this.– McBainCommented Jul 11 at 8:59