I have basically converted a Crowd Funding Campaign written in Native Rust (Solana CLI) into an Anchor Version. So my tests are running fine except the donation test.

Please if some Solana super shadowy dev can help me figure this out, I shall be grateful. I have spent almost a week debugging, but unable to figure out. Obviously somewhere my logic or syntax is wrong, but I am unable to understand.

Honestly, I feel my logic is right, because I have read the code so many times. But surely, something is wrong......

lib.rs

use anchor_lang::solana_program::system_program;
use anchor_lang::solana_program::program::{invoke /* , invoke_signed */};
use anchor_lang::solana_program::system_instruction;
use anchor_lang::solana_program::program_error::ProgramError;
declare_id!("HwHzMftiyTEYy6w8K6E3AipuF3vgswS1d7c6T6hUeRxf");


#[program]
pub mod solanacrowdfundingproject {
    use super::*;
    
    // `seeds` and `bump` tell us that our `writing_account` is a PDA that can be derived from their respective values
    pub fn initialize(ctx: Context<Initialize>, writing_account_bump: u8) -> ProgramResult {
        let writing_account = &mut ctx.accounts.writing_account;
        let authority = &mut ctx.accounts.authority;
        
        writing_account.bump = writing_account_bump;
        writing_account.count = 0;
        writing_account.authority = *authority.key; 
        writing_account.campaign_details = Vec::new();
        writing_account.withdraw_request = Vec::new();
        
        Ok(())
    }

    
    pub fn create_campaign
    (
        ctx : Context<CreateCampaign>, 
        name : String, 
        description : String, 
        image_link: String,      
    ) 
        -> ProgramResult {
               
        let writing_account = &mut ctx.accounts.writing_account;
        let authority = &mut ctx.accounts.authority;
        
        if name.len()  > 30 || description.len() > 50 {
            return Err(ErrorCode::NameOrDescriptionTooLong.into())
        }

        let campaign_data = CampaignDetails {
            admin : *authority.key,
            name : name.to_string(),
            description : description.to_string(),
            image_link : image_link.to_string(),
            amount_donated : 0,       
        };

        writing_account.count += 1;
        writing_account.campaign_details.push(campaign_data);
        
        Ok(())
    }
    
    
    pub fn withdraw(ctx : Context<Withdraw>, amount : u64) -> ProgramResult {
        let writing_account = &mut ctx.accounts.writing_account;
        let authority = &mut ctx.accounts.authority;
        
        
        let withdraw_data = WithdrawRequest {
            amount_withdrawn : amount,
            admin : *authority.to_account_info().key,
        };

        writing_account.withdraw_request.push(withdraw_data);
         
         **writing_account.to_account_info().try_borrow_mut_lamports()? -= amount;
         **authority.to_account_info().try_borrow_mut_lamports()? += amount;
        
        Ok(())

    }

    
    pub fn donate(ctx : Context<Donate>, amount : u64, donator_program_account_bump : u8) -> ProgramResult {
       
        let writing_account = &mut ctx.accounts.writing_account;
        let donator_program_account = &mut ctx.accounts.donator_program_account;
        let authority = &mut ctx.accounts.authority;

        donator_program_account.amount_donated = amount;
        donator_program_account.bump = donator_program_account_bump;
        

       let transfer_ix = system_instruction::transfer(
            &authority.to_account_info().key(),
            &donator_program_account.to_account_info().key(),
            amount,
       );

       #[warn(unused_must_use)]
       invoke(
           &transfer_ix, 
           &[
               authority.to_account_info(),
               donator_program_account.to_account_info(),
           ],
       )?;

        let mut campaign_data = CampaignDetails::try_from_slice(*writing_account.to_account_info().try_borrow_mut_data()?)
        .expect("Error deserializing data");
        campaign_data.amount_donated += **donator_program_account.to_account_info().lamports.borrow();

        **writing_account.to_account_info().try_borrow_mut_lamports()? += **donator_program_account.to_account_info().lamports.borrow();
        **donator_program_account.to_account_info().try_borrow_mut_lamports()? = 0;
        *donator_program_account.to_account_info().try_borrow_mut_data()? = &mut []; 
       
        Ok(())
    }


    #[derive(Accounts)]
    #[instruction(writing_account_bump : u8)]
    pub struct Initialize<'info> {
        #[account(init, 
            seeds = [b"please_____".as_ref(), authority.key().as_ref()], 
            bump = writing_account_bump, 
            payer = authority, 
            space = 9000)]
            pub writing_account : Account<'info, CampaignState>,
            #[account(mut)]
            pub authority : Signer<'info>,
            #[account(address = system_program::ID)]
            pub system_program : AccountInfo<'info>,
            
    }
    

    #[derive(Accounts)] 
    pub struct CreateCampaign<'info> {
       #[account(mut, has_one = authority)]
        pub writing_account  : Account<'info, CampaignState>,
        #[account(mut)]
        pub authority : Signer<'info>,         
    }


    #[derive(Accounts)]
    pub struct Withdraw<'info> {
        #[account(mut, has_one = authority)]
        pub writing_account : Account<'info, CampaignState>,
        #[account(mut)]
        pub authority : Signer<'info>,         
    }


  
    #[derive(Accounts)]
    #[instruction(donator_program_account_bump : u8)]
    pub struct Donate<'info> {
        #[account(mut)]
        pub writing_account : Account<'info, CampaignState>,
        #[account(mut)]
        pub authority : Signer<'info>,
        #[account(init,
            seeds = [b"donate____".as_ref(),
            authority.key().as_ref()], 
            bump = donator_program_account_bump, 
            payer = authority, 
            space = 100)]
        pub donator_program_account : Account<'info, DonatorProgramAccount>,
        #[account(address = system_program::ID)]
        pub system_program : AccountInfo<'info>,
    }

    

    #[derive(Debug, Clone, AnchorSerialize, AnchorDeserialize)]
    pub struct CampaignDetails  {
        pub admin: Pubkey,
        pub name: String,
        pub description: String,
        pub image_link: String,
        pub amount_donated: u64,          
    }



    #[derive(Debug, Clone, AnchorSerialize, AnchorDeserialize)]
    pub struct WithdrawRequest {
        pub amount_withdrawn : u64,
        pub admin : Pubkey,        
    }


    #[account]
    pub struct CampaignState {    
       pub campaign_details : Vec<CampaignDetails>,
       pub bump : u8,
       pub count : u8,
       pub authority: Pubkey,  
       pub withdraw_request : Vec<WithdrawRequest>,         
    }

    
    #[account]
    pub struct DonatorProgramAccount {
        pub amount_donated : u64,
        bump : u8,
    }
   
    
    #[error]
    pub enum ErrorCode {    
       
        #[msg("Name cannot be more than 30 characters and Description cannot be more than 50 characters")]
            NameOrDescriptionTooLong,
    }



} 

also my tests as below

const anchor = require('@project-serum/anchor');
const { PublicKey, Connection } = require("@solana/web3.js");
//const cluster = "http://localhost:8899";
const cluster = "https://api.devnet.solana.com";
const connection = new Connection(cluster, "confirmed");
const { SystemProgram, Keypair, /*SYSVAR_RENT_PUBKEY*/ } = anchor.web3; 
const { Buffer } = require('buffer');



// Specify provider environment. 
const provider = anchor.Provider.env();
//Set provider.
anchor.setProvider(provider);
//Specify the workspace 
const program = anchor.workspace.Solanacrowdfundingproject;
//const programID = await connection.programID(program);
const programID = new PublicKey("HwHzMftiyTEYy6w8K6E3AipuF3vgswS1d7c6T6hUeRxf");
// const otherUser (i.e Donator)
const donator = Keypair.generate();



describe('Solanacrowdfundingproject', () => {

  console.log(" Starting tests...");
  try {
    it('gets initialized', async () => {
      const { writingAccount, bump } = await getProgramDerivedCampaignWritingAccountAddress();
      let tx = await program.rpc.initialize(new anchor.BN(bump), {
        accounts: {
          writingAccount: writingAccount,
          authority: provider.wallet.publicKey,
          systemProgram: SystemProgram.programId,
          
        },

      });
      //Console.log the Transaction signature of the Initialization procedure. 
      console.log("Initialization transaction signature : ", tx);

      //Asserts and console.logs
      const account = await program.account.campaignState.fetch(writingAccount);
      console.log(" Created A Writing Account : ", account);
      assert.equal(account.authority.toBase58(), provider.wallet.publicKey.toBase58());
      console.log(" Account's count is :", account.count);
    });
  } catch (error) {
    console.log(error);
  }


  try {
    it('Creates a campaign', async () => {

      const { writingAccount } = await getProgramDerivedCampaignWritingAccountAddress();
      //Lets invocate the createCampaign function using provider.wallet.publicKey
      let tx = await program.rpc.createCampaign("Suveett", "Blockchain Speaker", "Enter a fancy giflink for Campaign",
        {
          accounts: {
            writingAccount: writingAccount,
            authority: provider.wallet.publicKey,
            

          },

        });
      //Asserts and Console Logs
      //Console.log the Transaction signature of the Initialization procedure. 
      console.log("Your CreateCampaign transaction signature", tx);
      let account = await program.account.campaignState.fetch(writingAccount);
      console.log("Writing Account after Campaign Creation :", account);
      console.log("This Writing account's address is : ", writingAccount.toBase58());
      console.log("This Writing account's admin is : ", account.campaignDetails[0].admin.toBase58());
      console.log("This Writing account's Campaign Details contains `name` :", account.campaignDetails[0].name);
      console.log("This Writing account's Campaign Details contains `description` :", account.campaignDetails[0].description);
      assert.equal(account.authority.toBase58(), provider.wallet.publicKey.toBase58());
      

    });

  } catch (error) {
    console.log(error);
  }



  try {
    it('Can Make a Donation', async () => {
      const signature = await connection.requestAirdrop(donator.publicKey, 1000000000);
      await connection.confirmTransaction(signature);
      console.log("Airdrop confirmed :", await connection.getBalance(donator.publicKey));
      const { writingAccount } = await getProgramDerivedCampaignWritingAccountAddress();
      const { donatorProgramAccount, bump } = await getProgramDerivedDonatorProgramAccountAddress();
      
      
      let balanceOfCampaignCreatorPreDonation = await connection.getBalance(writingAccount);
       console.log("Balance of Campaign before Donation : ", balanceOfCampaignCreatorPreDonation);
      
      let donateTx = await program.rpc.donate(new anchor.BN(1000000), new anchor.BN(bump),
        {
          accounts: {
            writingAccount: writingAccount,
            authority: donator.publicKey,
            donatorProgramAccount: donatorProgramAccount,
            systemProgram: SystemProgram.programId,
            
           
          },
           signers: [donator],
        });
      //Asserts and Console Logs
      //Console.log the Transaction signature of the Donation procedure. 
      let account = await program.account.donatorProgramAccount.fetch(donatorProgramAccount);
      console.log(" Created a New Donator Program Account : ", account);
      console.log(" Your Donation transaction signature is : ", donateTx);
     
      let balanceOfCampaignCreatorPostDonation = await connection.getBalance(writingAccount);
      console.log("Balance of Campaign after Donation : ", balanceOfCampaignCreatorPostDonation);

    });
  } catch (error) {
    console.log(error);
  }



  try {
    it('Can Make a Withdrawal', async () => {
      const { writingAccount } = await getProgramDerivedCampaignWritingAccountAddress();

      let withdrawTx = await program.rpc.withdraw(new anchor.BN(50000),
        {
          accounts: {
            writingAccount: writingAccount,
            authority: provider.wallet.publicKey,
            
          }

        });
      //Asserts and Console Logs
      //Console.log the Transaction signature of the Withdrawal procedure.
      console.log("Your Withdrawal transaction signature", withdrawTx);
      let balanceOfCampaignCreator = await connection.getBalance(writingAccount);
      console.log("Balance of Campaign after Withdrawal: ", balanceOfCampaignCreator);


    });
  } catch (error) {
    console.log(error);
  }


});



async function getProgramDerivedCampaignWritingAccountAddress() {
  const [writingAccount, bump] = await PublicKey.findProgramAddress(
    [Buffer.from('please_____'), provider.wallet.publicKey.toBuffer()],
    programID
  );

  console.log(`Got ProgramDerivedWritingAccountAddress: bump: ${bump}, pubkey: ${writingAccount.toBase58()}`);
  return { writingAccount, bump };

};


async function getProgramDerivedDonatorProgramAccountAddress() {
  const [donatorProgramAccount, bump] = await PublicKey.findProgramAddress(
    [Buffer.from('donate____'), donator.publicKey.toBuffer()],
    programID
  );

  console.log(`Got ProgramDerivedDonatorProgramAccountAddress: bump: ${bump}, pubkey: ${donatorProgramAccount.toBase58()}`);
  return { donatorProgramAccount, bump };

};

Can someone go through the code and help me? Also, the line Code below (where I am getting the error):

https://github.com/Suveett/solana-crowd-funding-master-using-Anchor/blob/ad87fb2226c800fce1faabd355eb88b812441e0c/tests/solanacrowdfundingproject.js#L91

1

There are 1 best solutions below

1
On

Try to add mut in your declaration:

#[account(init, mut,seeds = [b"please_____".as_ref(), authority.key().as_ref()],bump = writing_account_bump, payer = authority,space = 9000)]