Solana Interview Questions - Medium

Medium-level Solana interview questions covering advanced program development, optimization, and architecture.

Q1: How do you implement cross-program invocations (CPIs)?

Answer:

CPI Basics:

 1use solana_program::{
 2    program::invoke,
 3    account_info::AccountInfo,
 4};
 5
 6pub fn call_other_program(
 7    program_id: &Pubkey,
 8    accounts: &[AccountInfo],
 9    instruction_data: &[u8],
10) -> ProgramResult {
11    let instruction = Instruction {
12        program_id: *program_id,
13        accounts: accounts.to_vec(),
14        data: instruction_data.to_vec(),
15    };
16    
17    invoke(&instruction, accounts)?;
18    Ok(())
19}

CPI with Anchor:

 1use anchor_lang::prelude::*;
 2
 3#[program]
 4pub mod my_program {
 5    use super::*;
 6    
 7    pub fn call_token_program(ctx: Context<CallToken>, amount: u64) -> Result<()> {
 8        let cpi_accounts = token::Transfer {
 9            from: ctx.accounts.from.to_account_info(),
10            to: ctx.accounts.to.to_account_info(),
11            authority: ctx.accounts.authority.to_account_info(),
12        };
13        
14        let cpi_program = ctx.accounts.token_program.to_account_info();
15        let cpi_ctx = CpiContext::new(cpi_program, cpi_accounts);
16        
17        token::transfer(cpi_ctx, amount)?;
18        Ok(())
19    }
20}

Q2: How do you optimize Solana program compute units?

Answer:

Compute Optimization:

 1// Bad: Inefficient
 2for i in 0..1000 {
 3    // Expensive operation
 4}
 5
 6// Good: Batch operations
 7let batch_size = 100;
 8for i in (0..1000).step_by(batch_size) {
 9    // Process batch
10}
11
12// Use compute budget
13use solana_program::compute_budget::ComputeBudgetInstruction;
14
15let modify_compute_units = ComputeBudgetInstruction::set_compute_unit_limit(200_000);
16let modify_priority_fee = ComputeBudgetInstruction::set_compute_unit_price(1);

Q3: How do you implement account ownership and access control?

Answer:

Ownership Checks:

 1pub fn verify_owner(account: &AccountInfo, expected_owner: &Pubkey) -> ProgramResult {
 2    if account.owner != expected_owner {
 3        return Err(ProgramError::IncorrectProgramId);
 4    }
 5    Ok(())
 6}
 7
 8// Signer check
 9pub fn verify_signer(account: &AccountInfo) -> ProgramResult {
10    if !account.is_signer {
11        return Err(ProgramError::MissingRequiredSignature);
12    }
13    Ok(())
14}

Q4: How do you handle errors and program exceptions?

Answer:

Error Handling:

 1#[derive(Debug)]
 2pub enum MyError {
 3    #[error("Insufficient funds")]
 4    InsufficientFunds,
 5    #[error("Invalid account")]
 6    InvalidAccount,
 7}
 8
 9impl From<MyError> for ProgramError {
10    fn from(e: MyError) -> Self {
11        ProgramError::Custom(e as u32)
12    }
13}

Q5: How do you implement token swaps and AMM logic?

Answer:

Simple AMM:

 1pub fn swap(
 2    ctx: Context<Swap>,
 3    amount_in: u64,
 4    minimum_amount_out: u64,
 5) -> Result<()> {
 6    let pool = &mut ctx.accounts.pool;
 7    
 8    // Calculate output (constant product)
 9    let amount_out = (pool.token_b_amount * amount_in) / (pool.token_a_amount + amount_in);
10    
11    require!(amount_out >= minimum_amount_out, SwapError::SlippageExceeded);
12    
13    // Transfer tokens
14    // ...
15    
16    Ok(())
17}

Related Snippets