Voltr
  • Voltr
    • Introduction to Voltr
    • How It Works
    • Key Participants
  • For Users
    • User Overview
    • User Interface Guide
    • Web Application
  • For Vault Owners
    • Owner Overview
    • Current Integrations
    • Fees & Accounting
    • Vault Initialization Guide
      • Prerequisites
      • Vault Creation
      • Strategies Initialization
    • Fund Allocation Guide
      • Prerequisites
      • Fund Allocation
      • AI Agent Plugin
        • Solana Agent Kit
        • AI16Z
        • Zerebro
    • Frontend Integration Guide
      • Prerequisites
      • Frontend Integration
    • Client SDK Docs
    • Github Codebase
  • For Defi Protocols
    • DeFi Protocol Overview
    • Adaptor Creation Guide
      • Core Components Implementation
      • Security Considerations
    • Example Implementations
  • Security
    • Best Practices
    • Deployed Programs
    • Security Audits
    • Terms of Use
    • Disclaimer
Powered by GitBook
On this page
  • Voltr Protocol - Security Considerations for Custom Adaptor Development
  • Account Security
  • State Management Security
  • Protocol Integration Security
  • Error Handling
  • Operational Security
  • Testing Requirements
  • Security Checklist
  1. For Defi Protocols
  2. Adaptor Creation Guide

Security Considerations

Voltr Protocol - Security Considerations for Custom Adaptor Development

This guide outlines critical security considerations and best practices when developing custom adaptors for the Voltr Protocol.

Account Security

1. Authority Validation

// Always validate authorities and signers
require!(
    ctx.accounts.vault_strategy_auth.key() == expected_auth,
    AdaptorError::InvalidAccountOwner
);

// Verify protocol program ownership
require!(
    ctx.accounts.protocol_program.key() == strategy.protocol_program,
    AdaptorError::InvalidProtocolProgram
);

Key areas to validate:

  • Strategy authority signatures

  • Protocol program ownership

  • Token account authorities

  • Account derivation paths

  • PDA validation

2. Token Account Safety

// Example token account validation pattern
fn validate_token_accounts(
    reserve_info: &AccountInfo,
    vault_asset_mint: Pubkey,
    reserve_collateral_mint_account: Pubkey,
    user_destination_collateral: Pubkey,
    vault_strategy_auth: Pubkey,
    collateral_token_program: Pubkey
) -> Result<()> {
    // Verify mints match expected values
    require!(
        reserve_liquidity_mint == vault_asset_mint.key(),
        AdaptorError::InvalidReserveAccount
    );

    // Validate ATA derivation
    require!(
        get_associated_token_address_with_program_id(
            &vault_strategy_auth.key(),
            &reserve_collateral_mint_account.key(),
            &collateral_token_program.key()
        ) == user_destination_collateral.key(),
        AdaptorError::InvalidAccountInput
    );
    
    Ok(())
}

Critical checks:

  • Verify token mint associations

  • Validate token account authorities

  • Check ATA derivation

  • Enforce token program consistency

  • Verify token account state

3. PDA Derivation Security

// Example PDA derivation and validation
[strategy] = PublicKey.findProgramAddressSync(
    [SEEDS.STRATEGY, counterparty_asset_ta.key().as_ref()],
    DEFAULT_ADAPTOR_PROGRAM_ID
);

// Validate PDA derivation in accounts struct
#[account(
    seeds = [constants::STRATEGY_SEED, strategy.load()?.counterparty_asset_ta.key().as_ref()],
    bump = strategy.load()?.bump
)]
pub strategy: AccountLoader<'info, Strategy>,

Key considerations:

  • Use consistent seed ordering

  • Store and validate bumps

  • Check PDA ownership

  • Verify seed values

  • Validate authority PDAs

State Management Security

1. Position Value Tracking

fn calculate_current_amount(
    collateral_amount: u64,
    reserve_info: &AccountInfo
) -> Result<u64> {
    // Always handle potential overflows
    let total_liquidity = available_amount
        .checked_add(borrowed_amount)
        .ok_or(AdaptorError::MathOverflow)?;
        
    // Use checked math operations
    let liquidity_amount = (collateral_amount as u128)
        .checked_mul(total_liquidity)
        .ok_or(AdaptorError::MathOverflow)?
        .checked_div(total_supply)
        .ok_or(AdaptorError::MathOverflow)? as u64;

    Ok(liquidity_amount)
}

Critical aspects:

  • Use checked math operations

  • Handle decimal precision

  • Track position changes atomically

  • Validate calculations

  • Handle underflow/overflow

2. State Updates

impl Strategy {
    pub fn update_position(&mut self, value: u64) -> Result<()> {
        // Validate new state
        require!(value >= 0, AdaptorError::InvalidAmount);
        
        // Update atomically
        self.position_value = value;
        self.last_updated_ts = Clock::get()?.unix_timestamp;
        
        Ok(())
    }
}

Best practices:

  • Atomic updates

  • State validation

  • Version tracking

  • State consistency checks

  • Timestamp validation

Protocol Integration Security

1. CPI Safety

// Example safe CPI pattern
fn perform_protocol_operation(
    ctx: Context,
    args: ProtocolArgs
) -> Result<()> {
    // Validate CPI accounts
    validate_protocol_accounts(ctx.remaining_accounts)?;
    
    // Create CPI with correct signers
    let cpi_ctx = CpiContext::new_with_signer(
        ctx.accounts.protocol_program.to_account_info(),
        protocol_accounts,
        &[&authority_seeds]
    );
    
    // Perform CPI
    protocol::cpi::operation(cpi_ctx, args)?;
    
    Ok(())
}

Security measures:

  • Validate all CPI accounts

  • Sign with correct authority

  • Check return values

  • Handle CPI errors

  • Validate program IDs

2. Protocol State Validation

fn validate_protocol_state(
    protocol_account: &AccountInfo,
    expected_state: ProtocolState
) -> Result<()> {
    let state = ProtocolState::try_from_slice(&protocol_account.data.borrow())?;
    
    // Validate protocol constraints
    require!(
        state.is_valid_for_operation(),
        AdaptorError::InvalidProtocolState
    );
    
    // Check protocol specific rules
    validate_protocol_constraints(&state)?;
    
    Ok(())
}

Key checks:

  • Verify protocol state

  • Validate constraints

  • Check protocol limits

  • Handle protocol errors

  • Validate protocol accounts

Error Handling

1. Comprehensive Error Types

#[error_code]
pub enum AdaptorError {
    #[msg("Invalid amount provided.")]
    InvalidAmount,
    
    #[msg("Invalid account owner.")]
    InvalidAccountOwner,
    
    #[msg("Invalid token mint.")]
    InvalidTokenMint,
    
    #[msg("Math overflow.")]
    MathOverflow,
    
    #[msg("Invalid protocol state.")]
    InvalidProtocolState,
    
    // Protocol-specific errors
    #[msg("Protocol constraint violated.")]
    ProtocolConstraintViolation,
}

Error handling practices:

  • Descriptive error types

  • Protocol-specific errors

  • Clear error messages

  • Error propagation

  • State validation errors

2. Input Validation

fn validate_operation_inputs(
    amount: u64,
    args: &OperationArgs
) -> Result<()> {
    // Amount validation
    require!(amount > 0, AdaptorError::InvalidAmount);
    require!(amount <= max_amount, AdaptorError::InvalidAmount);
    
    // Args validation
    if let Some(args) = args {
        validate_args(args)?;
    }
    
    Ok(())
}

Important checks:

  • Validate all inputs

  • Check amount ranges

  • Verify arguments

  • Validate timestamps

  • Check protocol limits

Operational Security

1. Transaction Atomicity

// Example atomic operation
pub fn handle_protocol_operation(ctx: Context) -> Result<()> {
    // 1. Validate pre-state
    let pre_state = validate_pre_state(ctx)?;
    
    // 2. Perform operation atomically
    protocol_operation(ctx)?;
    
    // 3. Validate post-state
    validate_post_state(ctx, pre_state)?;
    
    Ok(())
}

Key considerations:

  • Atomic operations

  • State validation

  • Transaction rollback

  • Error recovery

  • State consistency

2. Upgrade Safety

#[account(zero_copy(unsafe))]
pub struct Strategy {
    pub version: u8,
    // Add fields with padding for future upgrades
    pub _reserved: [u8; 64],
}

Upgrade considerations:

  • Version tracking

  • State migration

  • Backward compatibility

  • Feature flags

  • Reserved space

Testing Requirements

  1. Security Tests

    • Authority validation

    • Account validation

    • State consistency

    • Error handling

    • Edge cases

  2. Integration Tests

    • Protocol interactions

    • State transitions

    • Error conditions

    • Upgrade paths

    • Multi-instruction scenarios

  3. Fuzzing Tests

    • Input validation

    • State mutations

    • Account combinations

    • Error conditions

    • Protocol interactions

Security Checklist

Before deployment, verify:

  1. Account Security

  2. State Management

  3. Protocol Integration

  4. Testing

PreviousCore Components ImplementationNextExample Implementations

Last updated 3 months ago