Calling Anchor Program From Rust

Calling Anchor Program From Rust

In Solana’s ecosystem, Anchor stands out as a powerful framework for building Solana programs, offering a range of utilities to streamline the development process. However, navigating the intricacies of Rust and interacting with Anchor programs can be challenging, especially when it comes to calling instructions and handling serialized data.

Having faced these challenges firsthand, I created this tutorial to provide clear guidance on calling an instruction in an Anchor program using Solana’s Rust SDK and Borsh serialization.

You can find the entire source code for the referenced example here.

Define discriminants

Anchor programs often use discriminants to identify different instructions. Initialize your discriminant as a constant array:

const INITIALIZE_DISCRIMINANT: [u8; 8] = [175, 175, 109, 31, 13, 152, 155, 237];

Define Structs

In your Rust project, define the structs representing the data passed to the instruction. You can either copy and paste them from the Anchor Program or define them yourself. These structs should derive BorshSerialize and BorshDeserialize. For example:

#[derive(BorshSerialize, BorshDeserialize)]
pub struct UserInfoParams {
pub name: String,
pub age: u8,
}

Create Instruction

In Anchor’s serialized instruction, the first 8 bytes will be used for the instruction discriminant, followed by the actual instruction data. So, we need to follow the same structure.

We create the Solana instruction using Instruction::new_with_borsh This function takes three arguments:

program_id: The public key of the Solana program associated with the instruction.

data: This is the instruction data we want to pass to it.

accounts: A vector of account public keys required by the instruction. These accounts must be included in the transaction and may be accessed by the program during execution.

Define instruction data

let params = UserInfoParams {
name: “Alice”.to_string(),
age: 25,
};

Now create an instruction with the instruction discriminant and instruction inputs. We can directly send the discriminant and Borsh-serializable data structures to this.

let ix = Instruction::new_with_borsh(
program_id,
&(INITIALIZE_DISCRIMINANT, user),
vec![
AccountMeta::new(pda_account, false),
AccountMeta::new_readonly(signer_pubkey, true),
AccountMeta::new_readonly(system_program::ID, false),
],
);

Create and Sign Transaction

Now we need to create the Transaction and sign it

let message = Message::new(&[ix], Some(&signer_pubkey));

let mut tx = Transaction::new_unsigned(message);

tx.sign(&[&signer], connection.get_latest_blockhash().unwrap());

let tx_id = connection
.send_and_confirm_transaction_with_spinner(&tx)
.map_err(|err| {
println!(“{:?}”, err);
}).unwrap();
println!(“Program uploaded successfully. Transaction ID: {}”, tx_id);

Conclusion:

This tutorial explored calling instruction in an Anchor program using Solana’s Rust SDK with Borsh serialization. By following these steps, you can interact with Anchor programs efficiently, leveraging the power of Borsh serialization for efficient data handling.

Additionally, I plan to develop a CLI tool for interacting with Anchor programs using IDL. I’ll provide updates on this project here.

Leave a Reply

Your email address will not be published. Required fields are marked *