DEV Community

Cover image for Calling Anchor Program From Rust
Swaroop Maddu
Swaroop Maddu

Posted on

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];
Enter fullscreen mode Exit fullscreen mode

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,
}
Enter fullscreen mode Exit fullscreen mode

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.

Anchor Instruction

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,
};
Enter fullscreen mode Exit fullscreen mode

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),
       ],
    );
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

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.

Top comments (1)

Collapse
 
cenwadike profile image
cenwadike

Thanks for the guide. How does one get the discriminates of other functions?