Turbin3 / poseidon

A Transpiler to convert your Solana programs from Typescript to Anchor
https://turbin3.github.io/poseidon/
47 stars 16 forks source link

No Transpilation for Token Transfer Logic #34

Closed ritikbhatt20 closed 1 day ago

ritikbhatt20 commented 1 day ago

Found out that the issue is specifically in this line:

   sourceAta.derive(mint, owner.key).initIfNeeded(owner);

Poseidon Code:

import { AssociatedTokenAccount, Mint, Pubkey, Signer, TokenProgram, u64 } from '@solanaturbine/poseidon';

export default class TransferTokensProgram {
  static PROGRAM_ID = new Pubkey('CSqtsYXnt2UfXttszwG6rGFFY7EedJ5kmn4xEyas4LeE');

  transferTokens(
    owner: Signer,
    sourceAta: AssociatedTokenAccount,
    destination: Pubkey,
    destinationAta: AssociatedTokenAccount,
    mint: Mint,
    transferAmount: u64,
  ) {
    sourceAta.derive(mint, owner.key).initIfNeeded(owner);
    destinationAta.derive(mint, destination).initIfNeeded(owner);

    TokenProgram.transfer(sourceAta, destinationAta, owner, transferAmount);
  }
}

Transpiled Anchor Code:

use anchor_lang::prelude::*;
use anchor_spl::{
    associated_token::AssociatedToken,
    token::{Token, Mint, TokenAccount},
};
declare_id!("CSqtsYXnt2UfXttszwG6rGFFY7EedJ5kmn4xEyas4LeE");
#[program]
pub mod transfer_tokens_program {
    use super::*;
}

The Expected Anchor Program should be:

use anchor_lang::prelude::*;
use anchor_spl::{
    associated_token::AssociatedToken,
    token::{Transfer as TransferSPL, Mint, transfer as transfer_spl, TokenAccount, Token},
};
declare_id!("CSqtsYXnt2UfXttszwG6rGFFY7EedJ5kmn4xEyas4LeE");
#[program]
pub mod transfer_tokens_program {
    use super::*;
    pub fn transfer_tokens(
        ctx: Context<TransferTokensContext>,
        transfer_amount: u64,
    ) -> Result<()> {
        let cpi_accounts = TransferSPL {
            from: ctx.accounts.source_ata.to_account_info(),
            to: ctx.accounts.destination_ata.to_account_info(),
            authority: ctx.accounts.owner.to_account_info(),
        };
        let cpi_ctx = CpiContext::new(
            ctx.accounts.token_program.to_account_info(),
            cpi_accounts,
        );
        transfer_spl(cpi_ctx, transfer_amount)?;
        Ok(())
    }
}
#[derive(Accounts)]
pub struct TransferTokensContext<'info> {
    #[account(mut)]
    pub owner: Signer<'info>,
    #[account(
        init_if_needed,
        payer = owner,
        associated_token::mint = mint,
        associated_token::authority = destination,
    )]
    pub destination_ata: Account<'info, TokenAccount>,
    #[account()]
    pub mint: Account<'info, Mint>,
    #[account(
        init_if_needed,
        payer = owner,
        associated_token::mint = mint,
        associated_token::authority = owner,
    )]
    pub source_ata: Account<'info, TokenAccount>,
    /// CHECK: Not necessary to enforce authority verification here
    #[account(mut)]
    pub destination: UncheckedAccount<'info>,
    pub associated_token_program: Program<'info, AssociatedToken>,
    pub token_program: Program<'info, Token>,
    pub system_program: Program<'info, System>,
}
ShrinathNR commented 1 day ago

hey, you need to pass the destination as some account type (System Account in your case mostly) and get the key property. In solana we need to pass all accounts that will be used for the instruction not just as pubkey. the Poseidon instruction should look like:

import { AssociatedTokenAccount, Mint, Pubkey, Signer, SystemAccount, TokenProgram, u64, UncheckedAccount } from '@solanaturbine/poseidon';

export default class TransferTokensProgram {
  static PROGRAM_ID = new Pubkey('CSqtsYXnt2UfXttszwG6rGFFY7EedJ5kmn4xEyas4LeE');

  transferTokens(
    owner: Signer,
    sourceAta: AssociatedTokenAccount,
    destination: SystemAccount,
    destinationAta: AssociatedTokenAccount,
    mint: Mint,
    transferAmount: u64,
  ) {
    sourceAta.derive(mint, owner.key).initIfNeeded(owner);
    destinationAta.derive(mint, destination.key).initIfNeeded(owner);

    TokenProgram.transfer(sourceAta, destinationAta, owner, transferAmount);
  }
}
ritikbhatt20 commented 1 day ago

hey, you need to pass the destination as some account type (System Account in your case mostly) and get the key property. In solana we need to pass all accounts that will be used for the instruction not just as pubkey. the Poseidon instruction should look like:

import { AssociatedTokenAccount, Mint, Pubkey, Signer, SystemAccount, TokenProgram, u64, UncheckedAccount } from '@solanaturbine/poseidon';

export default class TransferTokensProgram {
  static PROGRAM_ID = new Pubkey('CSqtsYXnt2UfXttszwG6rGFFY7EedJ5kmn4xEyas4LeE');

  transferTokens(
    owner: Signer,
    sourceAta: AssociatedTokenAccount,
    destination: SystemAccount,
    destinationAta: AssociatedTokenAccount,
    mint: Mint,
    transferAmount: u64,
  ) {
    sourceAta.derive(mint, owner.key).initIfNeeded(owner);
    destinationAta.derive(mint, destination.key).initIfNeeded(owner);

    TokenProgram.transfer(sourceAta, destinationAta, owner, transferAmount);
  }
}

Aghh gotcha.. thanks a lot for correcting buddy.