0

I have a sender program, and a receiver program. What I want to do is, sender program has a account, data_account. I want sender program to call modify_data of receiver program, which in turn mutates the data of data account, to be used back in the sender program. Is something like this possible? Or, the better way is to pass the required data as account itself in the sender program with some validations ? Can I get some light here please

#[program]
pub mod receiver {
    use super::*;

    pub fn modify_data(ctx: Context<ModifyData>) -> Result<()> {
        let mut data_account = ctx.accounts.data_account.try_borrow_mut_data()?;
        let new_data = // SOME_DATA_VEC ;
        data_account[..new_data.len()].copy_from_slice(&new_data);
        Ok(())
    }
}

#[derive(Accounts)]
pub struct ModifyData<'info> {
    #[account(mut)]
    pub data_account: Account<'info, DataAccount>,
}

#[account]
#[derive(Default)]
pub struct DataAccount {
    pub value: u64,
}
#[program]
pub mod caller {
    use super::*;

    pub fn initialize(ctx: Context<Initialize>, initial_value: u64) -> Result<()> {
        let mut data_account = ctx.accounts.data_account.try_borrow_mut_data()?;
        let initial_data = initial_value.to_le_bytes();
        data_account[..initial_data.len()].copy_from_slice(&initial_data);
        Ok(())
    }

    pub fn call_modify_data(ctx: Context<CallModifyData>, new_value: u64) -> Result<()> {
        // Serialize the arguments
        let args = ModifyDataArgs { new_value };
        let mut encoded_data = vec![0; args.try_to_vec().unwrap().len()];
        args.serialize(&mut encoded_data).unwrap();

        // Derive the discriminator for the modify_data method using sighash
        let discriminator = sighash("global", "modify_data");

        let mut instruction_data = Vec::new();
        instruction_data.extend_from_slice(&discriminator);
        instruction_data.extend_from_slice(&encoded_data);

        // Create the instruction
        let instruction = Instruction {
            program_id: ctx.accounts.receiver_program.key(),
            accounts: vec![AccountMeta::new(ctx.accounts.data_account.key(), false)],
            data: instruction_data,
        };

        // Invoke the instruction
        let account_infos = vec![
            ctx.accounts.receiver_program.to_account_info(),
            ctx.accounts.data_account.to_account_info(),
        ];
        invoke(&instruction, &account_infos)?;

        // Fetch and verify the modified data
        let data_account = ctx.accounts.data_account.try_borrow_data()?;
        let modified_value = u64::from_le_bytes(data_account[..8].try_into().unwrap());
        msg!("Modified value: {}", modified_value);

        Ok(())
    }
}

#[derive(Accounts)]
pub struct Initialize<'info> {
    #[account(init, payer = user, space = 8 + 8)]
    pub data_account: Account<'info, DataAccount>,
    #[account(mut)]
    pub user: Signer<'info>,
    pub system_program: Program<'info, System>,
}

#[derive(Accounts)]
pub struct CallModifyData<'info> {
    #[account(mut)]
    pub data_account: Account<'info, DataAccount>,
    /// CHECK: This account is the Receiver program's ID
    pub receiver_program: AccountInfo<'info>,
}

#[derive(BorshSerialize, BorshDeserialize, Clone)]
pub struct ModifyDataArgs {
    pub new_value: u64,
}

pub fn sighash(namespace: &str, name: &str) -> Vec<u8> {
    let preimage = format!("{}:{}", namespace, name);
    let mut sighash = [0u8; 8];
    sighash.copy_from_slice(
        &anchor_lang::solana_program::hash::hash(preimage.as_bytes()).to_bytes()[..8],
    );
    sighash.to_vec()
}

1 Answer 1

0

Only the program that owns an account can modify it. So in this case, you want receiver_program to modify the data in an account owned by sender_program, which is not possible.

If DataAccount has an owner field of a Pubkey and is owned by receiver_program, then receiver_program can check for a signature from a PDA derived from sender_program, and that way the account is owned and modified by receiver_program, but sender_program permits it through the PDA signature.

Or you can come up with something better!

You can read more about the account model at https://solana.com/docs/core/accounts

1
  • Got it, thank you!
    – woodland
    Commented May 21 at 1:32

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