0

This is the entire source code of the smart contract

use solana_program::{
    account_info::{next_account_info, AccountInfo},
    entrypoint,
    entrypoint::ProgramResult,
    msg,
    program_error::ProgramError,
    pubkey::Pubkey,
    system_instruction,
    program::invoke,
};
use borsh::{BorshDeserialize, BorshSerialize};
use std::str::FromStr;

// Define the recipient addresses as global constants
const RECIPIENT1: &str = "AmeQw3nHaRrrwaz4D2X4TdJUF3huqj6aAKsUwtp97yVF";
const RECIPIENT2: &str = "GCMNrkr4kvNXQ3iEis7GzNwa2pCwT9SkC1aLagzuNLcu";

// Define the account data structure
#[derive(BorshSerialize, BorshDeserialize, Debug)]
pub struct AccountData {
    pub balance: u64,
}

// Define the entry point
entrypoint!(process_instruction);

// The processor function
fn process_instruction(
    _program_id: &Pubkey,
    accounts: &[AccountInfo],
    instruction_data: &[u8],
) -> ProgramResult {
    let accounts_iter = &mut accounts.iter();
    let pda_account = next_account_info(accounts_iter)?;
    let user_account = next_account_info(accounts_iter)?;

    if !user_account.is_signer {
        return Err(ProgramError::MissingRequiredSignature);
    }

    if instruction_data.len() < 1 {
        return Err(ProgramError::InvalidInstructionData);
    }

    match instruction_data[0] {
        0 => deposit(pda_account, user_account, instruction_data),
        1 => get_balance(pda_account),
        _ => Err(ProgramError::InvalidInstructionData),
    }
}

fn deposit<'a>(
    pda_account: &AccountInfo<'a>,
    user_account: &AccountInfo<'a>,
    instruction_data: &[u8],
) -> ProgramResult {
    // Ensure the instruction data is at least 9 bytes (1 byte for the instruction, 8 bytes for the amount)
    if instruction_data.len() < 9 {
        return Err(ProgramError::InvalidInstructionData);
    }

    // Ensure the account data has at least 8 bytes
    if pda_account.data_len() < 8 {
        return Err(ProgramError::InvalidAccountData);
    }

    let amount = u64::from_le_bytes(instruction_data[1..9].try_into().map_err(|_| ProgramError::InvalidInstructionData)?);

    let mut account_data: AccountData = AccountData::try_from_slice(&pda_account.data.borrow())?;
    let new_balance = account_data.balance.checked_add(amount).ok_or(ProgramError::InvalidAccountData)?;
    account_data.balance = new_balance;
    account_data.serialize(&mut &mut pda_account.data.borrow_mut()[..])?;

    msg!("Deposited {} to {}", amount, pda_account.key);

    // Define the recipient addresses using the global constants
    let recipient1 = Pubkey::from_str(RECIPIENT1).map_err(|_| ProgramError::InvalidInstructionData)?;
    let recipient2 = Pubkey::from_str(RECIPIENT2).map_err(|_| ProgramError::InvalidInstructionData)?;

    // Calculate the amounts for each recipient
    let amount_recipient1 = amount * 40 / 100;
    let amount_recipient2 = amount - amount_recipient1; // Ensure the total is still equal to the original amount

    // Check if the user account has enough balance
    if **user_account.lamports.borrow() < amount {
        return Err(ProgramError::InsufficientFunds);
    }

    // Create the instructions to transfer SOL
    let transfer_instruction1 = system_instruction::transfer(
        user_account.key,
        &recipient1,
        amount_recipient1,
    );
    let transfer_instruction2 = system_instruction::transfer(
        user_account.key,
        &recipient2,
        amount_recipient2,
    );

    // Invoke the instructions
    invoke(
        &transfer_instruction1,
        &[user_account.clone(), pda_account.clone()],
    )?;
    invoke(
        &transfer_instruction2,
        &[user_account.clone(), pda_account.clone()],
    )?;

    msg!("Transferred {} to {}", amount_recipient1, recipient1);
    msg!("Transferred {} to {}", amount_recipient2, recipient2);

    Ok(())
}

fn get_balance(pda_account: &AccountInfo) -> ProgramResult {
    // Ensure the account data has at least 8 bytes
    if pda_account.data_len() < 8 {
        return Err(ProgramError::InvalidAccountData);
    }

    let account_data: AccountData = AccountData::try_from_slice(&pda_account.data.borrow())?;
    msg!("Balance of {} is {}", pda_account.key, account_data.balance);

    Ok(())
}

An exception occurred when calling the deposit method of the contract

Failed to deposit funds: SendTransactionError: failed to send transaction: Transaction simulation failed: Error processing Instruction 0: An account required by the instruction is missing

 logs: [
    'Program 2kC5Bx7a4H9gxv7PGsmRxVN9qRoQyFbxBV9xsqY4ayBh invoke [1]',
    'Program log: Deposited 1000 to 7k7c1n6MKqQ1S6V1ajTMNnNEmxBfgv5PikKpJeBEwAyY',
    'Instruction references an unknown account AmeQw3nHaRrrwaz4D2X4TdJUF3huqj6aAKsUwtp97yVF',
    'Program 2kC5Bx7a4H9gxv7PGsmRxVN9qRoQyFbxBV9xsqY4ayBh consumed 31559 of 200000 compute units',
    'Program 2kC5Bx7a4H9gxv7PGsmRxVN9qRoQyFbxBV9xsqY4ayBh failed: An account required by the instruction is missing'
  ]

1 Answer 1

1

The error you are encountering means you are trying to you are trying to transfer to an account you haven't specified on your client side.

Double-check to make sure that the user_pda and user_account addresses match the constant RECIPIENT addresses you declared. I think that's the reason your program is failing

5
  • Thank you for your help . The expectation of the contract is that the user recharges SOL to the contract, and in the recharge method, the received SOL is transferred to the two addresses defined in the contract based on comparison. Do these two receiving addresses also need to be set as parameters when calling the contract? Commented May 29 at 14:13
  • Which PDA or account is receiving the funds cause you can't send sol to a program.
    – Jimii
    Commented May 29 at 14:43
  • How can I achieve this requirement, or do I need to write a withdrawal method? Commented May 29 at 14:55
  • Create a program derived address to act as the middleman. Question. Why do you need to do this. You can send the funds to the recipients without using a third party.
    – Jimii
    Commented May 29 at 16:35
  • Yes, my idea is to transfer the deposited SOL directly to the two receiving addresses defined in the contract Commented May 30 at 13:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.