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()
}