I have been spending hours trying to understand why my ATA address owner suddenly changed to the token program instead of my account address. I am using PDA to transfer the token from the PDA ATA account but unable to do so since the PDA is no longer the ATA owner.
I tried testing Anchor to dissect the problem and to find solutions, here are my tests console logs:
Mint test result:
Mint: A2ojTC6aQZYP6bwUq1FmWN9kwaQTB7NKQmMs89j4FUkx
Sender ATA: 2KcR41e2NxnYY5DWDzvgzHiKpSoaZJ55kvBiqU111DaY
Sender ATA owner: 7QzoE1okkpgsn7Rx5pxyGDkXMSc3nsqhWitDHc6c8rKb
program ATA: H9SEYZsU5ao1WoUNoVTQjVMBbJLNjJmKA5N1cGfjxLqE
Supply: 100
PDA: 10
User: 90
✔ Mint token! (7001ms)
Mint test script:
it("Mint token!", async () => {
mintPubkey = await createMint(
program.provider.connection, // conneciton
user, // fee payer
user.publicKey, // mint authority
user.publicKey, // freeze authority (you can use `null` to disable it. when you disable it, you can't turn it on again)
9 // decimals
);
console.log("Mint:", mintPubkey.toBase58())
let tokenAccountPubkeyUser = await getOrCreateAssociatedTokenAccount(program.provider.connection, user, mintPubkey, user.publicKey)
console.log("Sender ATA:", tokenAccountPubkeyUser.address.toBase58())
let tokenAuth = await program.provider.connection.getAccountInfo(tokenAccountPubkeyUser.address);
console.log("Sender ATA owner:", tokenAccountPubkeyUser.owner.toBase58())
let tokenAccountPubkeyPda = await getOrCreateAssociatedTokenAccount(program.provider.connection, user, mintPubkey, program.programId)
console.log("program ATA:", tokenAccountPubkeyPda.address.toBase58())
let txhash = await mintToChecked(
program.provider.connection, // connection
user, // fee payer
mintPubkey, // mint
tokenAccountPubkeyUser.address, // receiver (sholud be a token account)
user, // mint authority
100e9, // amount. if your decimals is 9, you mint 10^9 for 1 token.
9 // decimals
);
let tokenSupply = await program.provider.connection.getTokenSupply(mintPubkey);
console.log("Supply:", tokenSupply.value.uiAmount)
txhash = await transferChecked(
program.provider.connection, // connection
user, // payer
tokenAccountPubkeyUser.address, // from (should be a token account)
mintPubkey, // mint
tokenAccountPubkeyPda.address, // to (should be a token account)
user, // from's owner
10e9, // amount, if your deciamls is 9, send 10^9 for 1 token
9 // decimals
);
let tokenAmount = await program.provider.connection.getTokenAccountBalance(tokenAccountPubkeyPda.address);
console.log("PDA:", tokenAmount.value.uiAmount)
let tokenAmountUser = await program.provider.connection.getTokenAccountBalance(tokenAccountPubkeyUser.address);
console.log("User:", tokenAmountUser.value.uiAmount)
})
Remove vault test result:
Mint: A2ojTC6aQZYP6bwUq1FmWN9kwaQTB7NKQmMs89j4FUkx
userProfilePDA CanbMWdj5UT8KWCAUwsmMyZFeyG8kWQER2tZQdxTohEK
Last vault: 3
vaultAccountPDA: 8tvqq4zWMGZuoe4tsjuC85WRQY8n5qxZeoyY2Ro7UwGi
vaultInfoPDA: A5E257kztkqdwxeqrjgFzjG2uPmECNX7LD96Vp6Tve7z
tokenProgram: TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA
receiver ATA: 2KcR41e2NxnYY5DWDzvgzHiKpSoaZJ55kvBiqU111DaY
receiver (user) ATA owner: TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA
sender (VaultInfo) ATA: BQhNK47ygEYARanGqJnSjKBco3Crot9ihDMJzT8u7yLU
VaultInfo ATA supply: 10
VaultATA owner: TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA
Program owner: BPFLoaderUpgradeab1e11111111111111111111111
vaultInfoPDA owner: GsCu69BThDsobWHorHkNf8h8zobN6VsexiYkwkH2VtfV
Remove vault test script:
it("User Vault removed!", async () => {
// Add your test here.
// const tx = await program.methods.initializeUser().rpc();
console.log("user:", user.publicKey)
console.log("program:", program.programId)
console.log("token program:", TOKEN_PROGRAM_ID)
console.log("Mint:", mintPubkey.toBase58())
const [userProfilePDA] = await anchor.web3.PublicKey.findProgramAddress([
utf8.encode("USER_STATE"),
user.publicKey.toBuffer(),
],
program.programId
);
console.log("userProfilePDA", userProfilePDA.toBase58());
const userProfile = await program.account.userProfile.fetch(userProfilePDA);
// console.log("UserProfile:", userProfile)
console.log("Last vault:", userProfile.lastVault)
const [vaultAccountPDA] = await anchor.web3.PublicKey.findProgramAddress([
utf8.encode("VAULT_STATE"),
user.publicKey.toBuffer(),
new anchor.BN(0).toBuffer()
],
program.programId
);
console.log("vaultAccountPDA:", vaultAccountPDA.toBase58());
const [vaultInfoPDA] = await anchor.web3.PublicKey.findProgramAddress([
utf8.encode("INFO_STATE"),
// user.publicKey.toBuffer(),
],
program.programId
);
console.log("vaultInfoPDA:", vaultInfoPDA.toBase58());
let tokenAccountPubkeyUser = await getOrCreateAssociatedTokenAccount(program.provider.connection, user, mintPubkey, user.publicKey)
console.log("tokenProgram:", TOKEN_PROGRAM_ID.toBase58())
console.log("receiver ATA:", tokenAccountPubkeyUser.address.toBase58())
let tokenAuth = await program.provider.connection.getAccountInfo(tokenAccountPubkeyUser.address);
console.log("receiver (user) ATA owner:", tokenAuth.owner.toBase58())
let tokenAccountPubkeyVault = await getOrCreateAssociatedTokenAccount(program.provider.connection, user, mintPubkey, vaultInfoPDA, true)
console.log("sender (VaultInfo) ATA:", tokenAccountPubkeyVault.address.toBase58())
let txhash = await transferChecked(
program.provider.connection, // connection
user, // payer
tokenAccountPubkeyUser.address, // from (should be a token account)
mintPubkey, // mint
tokenAccountPubkeyVault.address, // to (should be a token account)
user, // from's owner
10e9, // amount, if your deciamls is 9, send 10^9 for 1 token
9 // decimals
);
let tokenAmount = await program.provider.connection.getTokenAccountBalance(tokenAccountPubkeyVault.address);
console.log("VaultInfo ATA supply:", tokenAmount.value.uiAmount)
tokenAuth = await program.provider.connection.getAccountInfo(tokenAccountPubkeyVault.address);
console.log("VaultATA owner:", tokenAuth.owner.toBase58())
tokenAuth = await program.provider.connection.getAccountInfo(program.programId);
console.log("Program owner:", tokenAuth.owner.toBase58())
tokenAuth = await program.provider.connection.getAccountInfo(vaultInfoPDA);
console.log("vaultInfoPDA owner:", tokenAuth.owner.toBase58())
const tx = await program.rpc.removeVault(0, {
accounts: {
authority: user.publicKey,
userProfile: userProfilePDA,
vaultAccount: vaultAccountPDA,
vaultInfo: vaultInfoPDA,
systemProgram: anchor.web3.SystemProgram.programId,
tokenProgram: TOKEN_PROGRAM_ID,
from: tokenAccountPubkeyVault.address,
to: tokenAccountPubkeyUser.address,
owner: vaultInfoPDA,
// sender: vaultInfoPDA
},
signers: []
})
console.log("Your transaction signature", tx);
});
I am expecting to use the vaultInfoPDA (which should be the owner of the ATA) to send the token out to user removing their vault.
Thanks!