You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ATA所有权变更为Token Program导致PDA无法转账的问题求助

问题:ATA账户所有者变为Token Program,导致PDA无法转出代币

我花了几小时排查,发现我的ATA地址所有者突然变成了Token Program,而非预期的账户地址。原本计划使用vaultInfoPDA从它的ATA账户中转出代币,完成Vault移除操作,但由于PDA不再是该ATA的所有者,操作无法执行。以下是我用Anchor进行测试的控制台日志及脚本,寻求解决方案。


Mint测试结果与脚本

测试结果

Mint: A2ojTC6aQZYP6bwUq1FmWN9kwaQTB7NKQmMs89j4FUkx
Sender ATA: 2KcR41e2NxnYY5DWDzvgzHiKpSoaZJ55kvBiqU111DaY
Sender ATA owner: 7QzoE1okkpgsn7Rx5pxyGDkXMSc3nsqhWitDHc6c8rKb
program ATA: H9SEYZsU5ao1WoUNoVTQjVMBbJLNjJmKA5N1cGfjxLqE
Supply: 100
PDA: 10
User: 90
    ✔ Mint token! (7001ms)

测试脚本

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)

  })

移除Vault测试结果与脚本

测试结果

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

测试脚本

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);



  });

我期望vaultInfoPDA作为该ATA的所有者,将代币转出给用户以完成Vault移除操作,求指点。


内容的提问来源于stack exchange,提问作者Syahmi Shaarani

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 17:45:44