Skip to main content

System Overview

The Multiliquid Program is built on a modular, account-based architecture that enables atomic swaps between multiple permissioned Real World Asset (RWA) tokens and multiple stablecoins on Solana. The system is designed for institutional-grade operations with comprehensive access controls, transparent fee structures, and flexible pricing mechanisms.

Design Principles

  1. Account-Based State: All state stored in Program-Derived Address (PDA) accounts
  2. Anchor Framework: Type-safe program development with automatic serialization
  3. Atomicity: All operations either fully succeed or fully revert within a transaction
  4. Transparency: All state changes emit comprehensive events via Anchor’s event system
  5. Extensibility: New assets can be integrated without program upgrades

Core Account System

The program consists of five primary account types that work together to enable secure, atomic swaps between RWAs and stablecoins.

How the Accounts Work Together

At the heart of the system, GlobalConfig acts as the central configuration holding program-wide settings including the admin, fee wallet, and protocol fees. When an admin registers a new token, an AssetConfig account is created to store the token’s NAV pricing sources and configuration. When a trading pair is created, a Pair account links an RWA to a stablecoin with LP-specific settings, while LpStableConfig tracks the LP’s stablecoin-specific pause state. Token custody is managed through Vault accounts derived from the LP and token mint, with protocol fees collected in FeeVault accounts per asset. This separation of concerns ensures each account focuses on its specialized responsibility while maintaining atomic execution.

1. GlobalConfig Account

PDA Seeds: ["global_config"] The central configuration account managing program-wide settings.
pub struct GlobalConfig {
    pub admin: Pubkey,                      // Program administrator
    pub fee_wallet: Pubkey,                 // Protocol fee collection wallet
    pub protocol_fees_bps: u16,             // Protocol fees (0-9900 basis points)
    pub paused: bool,                       // Program-wide pause flag
    pub pending_new_admin: Option<Pubkey>,  // Two-step admin transfer
    pub bump: u8,                           // PDA bump seed
}

Core Responsibilities

  • Admin Management: Track current admin and pending admin transfer
  • Fee Configuration: Store protocol fee percentage
  • Global Pause: Control program-wide pause state
  • Fee Wallet: Destination for claimed protocol fees

View GlobalConfig Instructions

Complete instruction details for global configuration management

2. AssetConfig Account

PDA Seeds: ["asset", mint_address] Per-token configuration storing NAV pricing sources and asset-level controls.
pub struct AssetConfig {
    pub mint_address: Pubkey,               // Token mint address
    pub nav_data: Vec<NavData>,             // Up to 5 NAV pricing sources
    pub price_difference_bps: u16,          // Maximum price divergence tolerance
    pub paused: bool,                       // Asset-level pause flag
    pub version: u8,                        // Configuration version
    pub asset_type: AssetType,              // Rwa or Stable
    pub used_in_pairs_count: u16,           // Number of pairs using this asset
    pub bump: u8,                           // PDA bump seed
}

Asset Types

pub enum AssetType {
    Rwa,     // Real World Asset token
    Stable,  // Stablecoin token
}

Core Responsibilities

  • NAV Pricing: Store and manage up to 5 pricing sources per asset
  • Price Validation: Enforce maximum price divergence between sources
  • Asset Pause: Independent pause control per asset
  • Usage Tracking: Track how many pairs reference this asset

View AssetConfig Instructions

Complete instruction details for asset configuration

3. Pair Account

PDA Seeds: ["pair", liquidity_provider, stable_mint, asset_mint] Trading pair state linking an RWA to a stablecoin with LP-specific configuration.
pub struct Pair {
    pub redemption_fee_bps: u16,            // Fee for Stable → RWA swaps
    pub discount_rate_bps: u16,             // Fee for RWA → Stable swaps
    pub stable_coin_mint_address: Pubkey,   // Stablecoin token mint
    pub asset_token_mint_address: Pubkey,   // RWA token mint
    pub liquidity_provider: Pubkey,         // LP owner address
    pub paused: bool,                       // Pair-level pause flag
    pub bump: u8,                           // PDA bump seed
}

Core Responsibilities

  • Fee Configuration: Store LP-specific redemption and discount fees
  • Pair Identity: Link specific RWA and stablecoin tokens
  • LP Ownership: Track the liquidity provider controlling this pair
  • Pair Pause: Independent pause control per pair

View Pair Instructions

Complete instruction details for pair management

4. LpStableConfig Account

PDA Seeds: ["lp_stable_config", stable_mint, liquidity_provider] Per-LP, per-stablecoin configuration for controlling multiple pairs at once.
pub struct LpStableConfig {
    pub stable_coin_mint_address: Pubkey,   // Stablecoin mint
    pub paused: bool,                       // Pause all pairs with this config
    pub liquidity_provider: Pubkey,         // LP address
    pub bump: u8,                           // PDA bump seed
}

Core Responsibilities

  • Batch Pause Control: Pause all pairs for a specific LP/stablecoin combination
  • LP Identification: Link configuration to specific liquidity provider
  • Stablecoin Association: Scope configuration to specific stablecoin

5. Vault Accounts

Vault PDA Seeds: ["vault", mint_address, liquidity_provider] Fee Vault PDA Seeds: ["fee_vault", mint_address] Token accounts for custody and fee collection.

Vault (Liquidity Custody)

  • Holds liquidity for a specific LP/token combination
  • Shared across multiple pairs using the same LP and token
  • Tracked by UserVaultInfo account for usage counting

Fee Vault (Protocol Fees)

  • Created per asset when asset config is initialized
  • Protocol fees accumulate only in stablecoin fee vaults, since fees are always denominated in stablecoins
  • Claimed via claim_fees instruction to fee wallet

6. UserVaultInfo Account

PDA Seeds: ["user_vault_info", mint_address, liquidity_provider] Tracks vault usage across pairs.
pub struct UserVaultInfo {
    pub user: Pubkey,                       // LP wallet
    pub mint_address: Pubkey,               // Token mint
    pub used: u16,                          // Number of pairs using this vault
    pub bump: u8,                           // PDA bump seed
}

7. Program Authority

PDA Seeds: ["program_authority"] The program authority is a signer PDA used to authorize all outbound token transfers from vaults and fee vaults via CPI. It holds no state — it exists solely as a signing authority for the program.

Operational Flow

Swap Execution Flow

The program supports three types of NAV (Net Asset Value) pricing sources:
pub enum NavData {
    /// Read price from a fixed on-chain account address
    U64FixedAddress {
        nav_account_address: Pubkey,        // Account containing price
        nav_price_offset: u16,              // Byte offset in account data
        price_decimals: u8,                 // Price decimals (0-9)
    },

    /// Static hardcoded price value
    Hardcoded {
        hardcoded_price: u64,               // Fixed price value
        price_decimals: u8,                 // Price decimals (0-9)
    },

    /// Pyth oracle push-based pricing
    PythPush {
        pyth_push_account_address: Pubkey,  // Pyth oracle account
        nav_price_offset: u16,              // Price location offset
        decimals_offset: u16,               // Decimal exponent location
    },
}

Price Aggregation

When multiple NAV sources are configured:
  1. All prices are normalized to 9 decimal places
  2. Price divergence is validated against price_difference_bps
  3. If divergence exceeds threshold, the function returns 0 (blocking swaps)
  4. Average price is returned if all sources agree within tolerance

View Price Source Details

Complete documentation on NAV pricing configuration

Fee Structure

Protocol Fees

Configured in GlobalConfig.protocol_fees_bps:
  • Range: 0-9900 basis points (0% - 99%)
  • Applied to all swaps regardless of direction
  • Collected in stablecoin fee vaults
  • Claimed to fee_wallet via claim_fees instruction

LP Fees

Configured per pair by the liquidity provider:
Fee TypeDirectionDescription
redemption_fee_bpsStable → RWAFee charged when redeeming stablecoin for RWA
discount_rate_bpsRWA → StableFee charged when swapping RWA for stablecoin

Fee Calculation Order

Stable → RWA (StableToAsset):
  1. Calculate protocol fees and redemption fee simultaneously from input
  2. Deduct both fees from input amount
  3. Apply NAV exchange rate to post-fee amount
RWA → Stable (AssetToStable):
  1. Apply NAV exchange rate
  2. Apply discount rate to output
  3. Deduct protocol fees from discounted amount

Permission Model

The program implements a comprehensive permission model:

Admin Role

Controlled by: GlobalConfig.admin Permissions:
  • Initialize and update global configuration
  • Set and confirm new admin (two-step transfer)
  • Initialize asset configurations
  • Update asset configurations
  • Initialize pairs on behalf of LPs
  • Set pause state for assets and LP configs

Liquidity Provider Role

Identified by: Pair and vault ownership Permissions:
  • Update pair configuration (fees, pause state)
  • Close pairs they own
  • Add and remove liquidity from their vaults
  • Set pause state for their LP stable configs

User Role (Permissionless)

Anyone can:
  • Execute swaps on active pairs
  • Claim protocol fees (sent to fee_wallet)

Permission Hierarchy

Event System

The program emits events for all significant state changes using Anchor’s event system:

Swap Events

#[event]
pub struct SwapExecuted {
    pub requestor: Pubkey,          // User executing swap
    pub amount_in: u64,             // Input amount
    pub protocol_fee_amount: u64,   // Protocol fees collected
    pub discount_bps: u16,          // LP fee applied
    pub amount_out: u64,            // Output amount
    pub pair: Pubkey,               // Pair account address
    pub swap_direction: SwapDirection,
    pub swap_type: SwapType,
}

Administrative Events

Events are emitted for configuration changes, pair updates, liquidity operations, and pause state changes.

Extensibility

The program’s modular architecture enables straightforward extension:

Adding a New Token

  1. Admin Action: Call init_asset_config_account with NAV sources
  2. Fee Vault Created: Automatic fee vault creation for the asset
  3. Configure NAV: Set appropriate pricing sources (Pyth, hardcoded, etc.)
  4. Test Integration: Validate NAV reads correctly

Adding a New Pair

  1. Admin Action: Call init_pair specifying LP, RWA, and stablecoin
  2. Vaults Created: Automatic vault creation if needed
  3. LP Configuration: LP calls update_pair to set fees and unpause
  4. Add Liquidity: LP adds tokens to vaults
  5. Enable Trading: Pair is ready for swaps

Next: Security & Access Control

Review the comprehensive security measures, access controls, and pause mechanisms