Skip to main content

Security Overview

The Multiliquid Program is built with institutional-grade security as a core requirement. Every instruction, account validation, and state transition has been designed with security-first principles, incorporating multiple layers of protection and comprehensive access controls.

Program Security

Anchor Framework

The program is built exclusively using the Anchor framework, providing: Type Safety:
  • Automatic account serialization and deserialization
  • Compile-time account constraint validation
  • Strong typing for all instruction parameters
Account Validation:
  • Automatic owner checks on all accounts
  • PDA derivation verification via seeds constraints
  • has_one constraints for relationship validation
Security Features:
  • Built-in discriminator checks to prevent account confusion
  • Automatic rent-exemption verification
  • Safe arithmetic operations with checked math

Core Security Mechanisms

1. Program-Derived Addresses (PDAs)

All program accounts are derived deterministically using PDAs:
// Example: Pair account derivation
#[account(
    seeds = [
        PAIR_PREFIX,
        liquidity_provider.key().as_ref(),
        stable_mint.key().as_ref(),
        asset_mint.key().as_ref()
    ],
    bump = pair.bump,
)]
pub pair: Account<'info, Pair>,
Security Benefits:
  • Accounts cannot be spoofed or substituted
  • Deterministic derivation enables verification
  • No external account addresses stored unnecessarily

2. Signer Validation

All privileged operations require appropriate signatures:
// Admin-only operation
#[account(
    constraint = global_config.admin == admin.key()
        @ ErrorCode::Unauthorized
)]
pub admin: Signer<'info>,

// LP-only operation
#[account(
    has_one = liquidity_provider,
)]
pub pair: Account<'info, Pair>,
pub liquidity_provider: Signer<'info>,

3. Integer Overflow Protection

All arithmetic operations use checked math:
// Safe multiplication with overflow check
let result = amount
    .checked_mul(price)
    .ok_or(ErrorCode::MathOverflow)?;

// Safe division with zero check
let output = numerator
    .checked_div(denominator)
    .ok_or(ErrorCode::MathOverflow)?;

4. Input Validation

Every instruction validates inputs before execution:
  • Amounts must be greater than zero
  • Basis points must be within valid range (0-10000)
  • NAV sources must have valid decimals (0-9)
  • Asset types must match expected values

Token Security

SPL Token Integration

The program uses Anchor’s SPL token helpers for safe token operations:
// Safe token transfer using CPI (checked variant)
transfer_checked(
    CpiContext::new(
        token_program.to_account_info(),
        TransferChecked {
            from: user_token_account.to_account_info(),
            to: vault.to_account_info(),
            authority: user.to_account_info(),
            mint: mint.to_account_info(),
        },
    ),
    amount,
    decimals,
)?;
Security Features:
  • Automatic account ownership validation
  • Mint address verification
  • Sufficient balance checks

Token-2022 Support

The program supports both SPL Token and Token-2022:
  • Automatic program detection based on mint owner
  • Compatible with Token-2022 extensions
  • Safe handling of both token standards

Access Control System

The program implements a sophisticated multi-tier permission model:

Admin Role

Holder: GlobalConfig.admin Permissions:
OperationDescription
init_global_configInitialize program configuration (one-time)
update_global_configUpdate fees, fee wallet, pause state
set_new_adminPropose new admin address
confirm_new_adminAccept admin role (new admin)
init_asset_config_accountRegister new tokens
update_asset_config_accountUpdate token NAV sources
init_pairCreate trading pairs
set_paused_for_assetPause/unpause assets
set_paused_for_lp_stable_configPause/unpause LP configs
Security Considerations:
  • Admin should be a multi-signature wallet
  • Two-step transfer prevents accidental handover
  • Program starts paused by default

Liquidity Provider Role

Holder: Address specified as liquidity_provider in pair creation Permissions:
OperationDescription
update_pairConfigure fees and pause state
close_pairPermanently close a pair
add_liquidityDeposit tokens to vault
remove_liquidityWithdraw tokens from vault
set_paused_for_lp_stable_configPause own LP config
Security Considerations:
  • Each LP controls only their own pairs
  • Cannot affect other LPs’ configurations
  • Pairs start paused (LP must explicitly enable)

User Role (Permissionless)

Holder: Any wallet Permissions:
OperationDescription
swapExecute token swaps
claim_feesTrigger fee distribution to fee wallet
Security Considerations:
  • Swaps validated against multiple pause states
  • Slippage protection via min/max amount parameters
  • Fees always sent to configured fee wallet (not caller)

Pause Control System

The program implements a comprehensive four-level pause system:

Pause Hierarchy

Level 1: Global Pause

Controlled by: Admin via update_global_config Effects:
  • Blocks ALL swap operations
  • Blocks liquidity operations
  • Blocks fee claims
  • Admin operations still accessible
Use Cases:
  • Emergency halt during security incident
  • Program maintenance or upgrade preparation
  • Regulatory requirement

Level 2: Asset Pause

Controlled by: Admin via set_paused_for_asset Effects:
  • Blocks swaps involving this specific asset
  • Other assets remain operational
  • Affects all pairs using this asset
Use Cases:
  • Token-specific security issue
  • NAV oracle malfunction
  • Compliance requirement for specific asset

Level 3: LP Stable Config Pause

Controlled by: Admin OR LP via set_paused_for_lp_stable_config Effects:
  • Blocks all pairs for this LP/stablecoin combination
  • Other LPs unaffected
  • Other stablecoins for same LP unaffected
Use Cases:
  • LP-specific operational issue
  • Stablecoin-specific concern for one LP
  • LP maintenance period

Level 4: Pair Pause

Controlled by: LP via update_pair Effects:
  • Blocks only this specific trading pair
  • All other pairs remain operational
Use Cases:
  • Liquidity rebalancing
  • Fee adjustment period
  • Individual pair maintenance

Swap Validation

Every swap validates ALL four pause levels:
// Pause checks in swap instruction
require!(!global_config.paused, ErrorCode::ProgramPaused);
require!(!pair.paused, ErrorCode::PairPaused);
require!(!rwa_config.paused, ErrorCode::RwaPaused);
require!(!stable_config.paused, ErrorCode::StablePaused);
require!(!lp_stable_config.paused, ErrorCode::StablePaused);
If ANY level is paused, the swap is rejected.

Two-Step Admin Transfer

The program implements a secure two-step admin transfer mechanism to prevent accidental or malicious admin handover:

Step 1: Propose New Admin

Current admin calls set_new_admin:
pub fn set_new_admin(
    ctx: Context<SetNewAdmin>,
    new_admin: Pubkey,
) -> Result<()>
Effects:
  • Sets pending_new_admin to proposed address
  • Current admin remains in control
  • No immediate transfer occurs

Step 2: Confirm New Admin

New admin calls confirm_new_admin:
pub fn confirm_new_admin(
    ctx: Context<ConfirmNewAdmin>,
) -> Result<()>
Requirements:
  • Caller must match pending_new_admin
  • Caller must sign the transaction
Effects:
  • admin updated to new address
  • pending_new_admin cleared
  • Transfer complete

Security Benefits

  • No Accidental Transfer: Typo in address won’t transfer control
  • Recipient Verification: New admin must actively accept
  • Revocable: Current admin can propose different address before confirmation

Error Handling

The program defines comprehensive error codes for security validation:
#[error_code]
pub enum ErrorCode {
    #[msg("Unauthorized")]
    Unauthorized,

    #[msg("Program paused")]
    ProgramPaused,

    #[msg("Pair paused")]
    PairPaused,

    #[msg("RWA paused")]
    RwaPaused,

    #[msg("Stable paused")]
    StablePaused,

    #[msg("Invalid NAV")]
    InvalidNav,

    #[msg("Math Overflow")]
    MathOverflow,

    #[msg("Math Underflow")]
    MathUnderflow,

    #[msg("Insufficient liquidity")]
    InsufficientLiquidity,

    #[msg("Amount in too high")]
    AmountInTooHigh,

    #[msg("Amount out too low")]
    AmountOutTooLow,

    #[msg("Fees out of range")]
    FeesOutOfRange,

    #[msg("Price decimals too large")]
    PriceDecimalsTooLarge,

    // ... additional validation and operational error codes
}

Operational Security Best Practices

For institutions integrating with the program:

Key Management

  • Use Hardware Wallets: For all signing operations
  • Multi-Signature: Admin should be a multi-sig wallet
  • Key Rotation: Periodic admin transfer to fresh keys
  • Backup Procedures: Secure backup of all signing keys

Transaction Security

  • Simulation: Use Solana’s transaction simulation before signing
  • Verification: Double-check all account addresses
  • Priority Fees: Set appropriate priority fees for time-sensitive operations
  • Recent Blockhash: Use recent blockhashes to prevent replay

Monitoring

  • Event Tracking: Monitor program events for all state changes
  • Balance Monitoring: Track vault and fee vault balances
  • Pause State: Alert on any pause state changes
  • Admin Changes: Alert on admin transfer initiation

Known Limitations and Assumptions

Token Compatibility

The program assumes:
  • Tokens follow SPL Token or Token-2022 standards
  • Tokens do not have transfer fees that break atomicity
  • NAV oracles remain available and accurate
  • Token decimals are correctly configured

Price Oracle Assumptions

  • NAV sources return valid prices within configured decimals
  • Price divergence threshold is appropriately set
  • At least one NAV source is always available
  • Pyth oracle accounts are correctly configured

Operational Assumptions

  • Admin wallet is secure and properly managed
  • LPs manage their liquidity appropriately
  • Fee vault balances are claimed periodically
  • Pairs are closed properly before decommissioning

Security Contacts

For security vulnerabilities or concerns:
DO NOT disclose security vulnerabilities publicly. Contact the Multiliquid team directly through secure channels.

This security documentation is a living document and will be updated as the program evolves and new security measures are implemented.

Next: Swap Instruction

Explore the main swap instruction managing all trading operations