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 swap program’s primary account types work together to enable secure, atomic swaps between configured assets.

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 two configured assets with settings specific to each capital provider, while LpStableConfig tracks the capital provider’s stablecoin-specific pause state. Token custody is managed through capital provider vault token accounts owned by a capital provider’s VaultAuthority PDA, with protocol fees collected in fee vault token accounts owned by the global ProgramAuthority PDA. 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.

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 Reference

Program-wide settings and their effects on integrations

2. AssetConfig Account

PDA Seeds: ["asset", mint_address] Per-token configuration storing NAV pricing sources and asset-level controls.

Asset Types

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 Reference

Per-token NAV sources, classification, and pause state

3. Pair Account

PDA Seeds: ["pair", liquidity_provider, quote_mint, base_mint] Trading pair state linking two configured assets with configuration specific to each capital provider.

Core Responsibilities

  • Fee Configuration: Store redemption and discount fees for each capital provider
  • Pair Identity: Link specific quote and base tokens
  • Capital Provider Ownership: Track the capital 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] Configuration per capital provider and stablecoin for controlling multiple pairs at once.

Core Responsibilities

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

5. Vault Accounts

VaultAuthority PDA Seeds: ["vault_authority", liquidity_provider] Capital Provider Vault Token Account: Associated token account for (mint_address, vault_authority) ProgramAuthority PDA Seeds: ["program_authority"] Fee Vault Token Account: Associated token account for (mint_address, program_authority) Token accounts for custody and fee collection.
For permissioned mints, both the listed Capital Provider address and its listed Vault Authority (PDA) must be separately whitelisted (allowlisted) by the token issuer. Whitelisting the capital provider does not whitelist its PDA. The capital provider’s token account and PDA-owned vault ATA must also be thawed before liquidity or swap transfers can succeed.

Vault (Liquidity Custody)

  • Holds liquidity for a specific capital provider/token combination
  • Owned by the capital provider’s vault_authority PDA, not by the global program authority
  • Derived as the associated token account for the token mint and vault_authority
  • Shared across multiple pairs using the same capital provider and token
  • Tracked by UserVaultInfo account for usage counting

Fee Vault (Protocol Fees)

  • Created per asset when asset config is initialized
  • Owned by the global program_authority PDA
  • Protocol fees accumulate in the configured fee-token vault
  • 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.

7. Vault and Program Authorities

VaultAuthority

PDA Seeds: ["vault_authority", liquidity_provider] The vault authority is a capital provider’s signer PDA used to own and authorize outbound transfers from capital provider liquidity vaults. Every vault for the same capital provider is an associated token account owned by this PDA.

ProgramAuthority

PDA Seeds: ["program_authority"] The program authority is a global signer PDA used for protocol fee vaults. It authorizes outbound transfers from fee vaults during claim_fees. It does not own capital provider liquidity vaults. The capital provider’s protocol-fee token account is owned by a separate PDA derived from ["lp_fee_vault_authority", liquidity_provider]. Swaps debit this account to fund the global fee vault.

8. LpProtocolFeeConfig Account

PDA Seeds: ["lp_protocol_fee_config", liquidity_provider] This optional account stores the capital provider’s protocol-fee overrides and treasury_enabled flag. Without it, swaps use the global fee settings and Treasury routing is disabled. The admin sets fee overrides; the capital provider controls Treasury routing.

Treasury Accounts

The Treasury program maintains separate accounts under its own program ID: For swap-integrated Treasury routing, the position owner is the capital provider’s swap vault-authority PDA. The capital provider opts in through set_lp_treasury_enabled; eligible stablecoin inputs can be deposited into Treasury, and stablecoin output shortfalls can be redeemed from it. The Pair Management page describes the routing and withdrawal behavior.

Operational Flow

Swap Execution Flow

The program supports four types of NAV (Net Asset Value) pricing sources:

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 as (max_nav - min_nav) / max_nav
  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, unless a capital provider protocol-fee configuration overrides the global defaults:
  • Range: 0-9900 basis points (0% - 99%)
  • Applied to all swaps regardless of direction
  • Paid from the capital provider fee-token ATA into the configured global fee vault
  • Claimed to fee_wallet via claim_fees instruction

Capital Provider Fees

Configured per pair by the capital provider:

Fee Calculation Order

Quote → Base (QuoteToBase):
  1. Calculate the pair fee and protocol spread charge from the quote input
  2. Deduct both from the input amount
  3. Apply the NAV exchange rate to the post-fee amount
Base → Quote (BaseToQuote):
  1. Apply the NAV exchange rate
  2. Apply the pair fee and protocol spread charge to the quote equivalent
  3. Transfer the resulting quote output to the user
Both directions pay protocol fees separately from the capital provider fee-token ATA. RWA/RWA pairs use the sum of both pair fee fields in either direction. Quote/base follows the stored mint order, not an asset-type label.

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
  • Configure capital provider protocol-fee overrides
  • Set pause state for assets and capital provider configs

Capital Provider Role

Identified by: Pair and vault ownership Permissions:
  • Initialize pairs and update pair configuration (fees, pause state)
  • Close pairs they own
  • Add and remove liquidity from their vaults
  • Set pause state for their capital provider 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

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 Pair

  1. Capital Provider Action: Call init_pair specifying the two mints in canonical byte order
  2. Vaults Created: Automatic vault creation if needed
  3. Capital Provider Configuration: The capital provider calls update_pair to adjust fees or pause state as needed
  4. Add Liquidity: The capital provider 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