Skip to main content

Overview

Pair accounts link two registered tokens, including RWA/stablecoin and RWA/RWA pairs, enabling trading between them. Each pair is owned by a specific capital provider who controls its configuration, fees, and liquidity.

Account Structures

Pair Account

PDA Seeds: ["pair", liquidity_provider, quote_mint, base_mint] New pairs require quote/base mints in ascending byte order. Existing pairs retain their stored order; quote does not necessarily mean stablecoin.

LpStableConfig Account

PDA Seeds: ["lp_stable_config", stable_mint, liquidity_provider]

UserVaultInfo Account

PDA Seeds: ["user_vault_info", mint_address, liquidity_provider]

VaultAuthority PDA

PDA Seeds: ["vault_authority", liquidity_provider]
For permissioned mints (tokens), the issuer must separately whitelist (allowlist) both the liquidity_provider address and the derived vault_authority PDA. The capital provider address owns the source token account; the PDA owns the destination vault ATA. Approval of one address does not apply to the other.The corresponding capital provider’s token account and PDA-owned vault ATA must also be thawed before a transfer can succeed. Creating the pair or vault ATA does not perform issuer whitelisting or thawing.
The vault_authority PDA is specific to each capital provider and owns that capital provider’s vault token accounts. The vault token accounts themselves are associated token accounts for (mint, vault_authority), so they are keyed by capital provider and mint without using the global program authority.

Pair Instructions

init_pair

Create a new trading pair. The capital provider signs and pays for all account creation.

Parameters

Required Accounts

Behavior

  • Creates Pair PDA account, paid for by the capital provider
  • Validates distinct mints in canonical byte order; both assets may be RWAs
  • Creates or updates LpStableConfig for each Stable mint in the pair
  • Creates vault ATAs owned by the capital provider’s vault_authority PDA if they don’t exist
  • Creates UserVaultInfo accounts to track vault usage
  • Increments used_in_pairs_count on both asset configs
  • Initializes redemption_fee_bps and discount_rate_bps from the instruction arguments
  • Requires program to be unpaused
  • Pair pause state defaults to unpaused unless the capital provider later pauses it with update_pair

Access Control

Access: Capital provider (signs as liquidity_provider).
Swaps still require every pause gate to be open: global config, both asset configs, applicable capital provider stable configs, the fee asset, and the pair itself.

Example

lpStableConfigQuote and lpStableConfigBase are supplied for Stable sides and null for RWA sides.

update_pair

Update pair configuration (fees and pause state).

Parameters

Required Accounts

Behavior

  • Updates fee configuration
  • Updates pause state
  • Requires program to be unpaused
  • Validates both fee values are <= 9900 and their sum is < 10000

Access Control

Access: Capital provider (pair owner) only

Example


close_pair

Permanently close a trading pair. The capital provider signs and receives the reclaimed rent for the pair account and any closed vault accounts; the configured global-config admin is referenced as a non-signing account and checked by has_one.

Required Accounts

Behavior

  • Closes Pair account
  • Requires program to be unpaused
  • Decrements used_in_pairs_count on both asset configs
  • Requires the capital provider’s Treasury position to be empty, even if Treasury routing has been disabled
  • Returns remaining vault tokens to the capital provider’s recipient token accounts
  • Closes vault ATAs if no longer used by other pairs
  • Closes the corresponding UserVaultInfo PDAs when their used count reaches 0
  • Returns reclaimed rent (Pair PDA, closed vault ATAs, and closed UserVaultInfo PDAs) to the capital provider
Closing a pair reclaims rent and clears the pair’s configuration (fees, pause state). The capital provider can re-initialize a pair for the same (stable, asset) combination later via init_pair, but it will start with fresh configuration — prior fee settings are not restored.

Access Control

Access: Capital provider (pair owner). The admin account must be provided and is verified against global_config.admin via has_one, but admin does not sign.

set_paused_for_lp_stable_config

Set pause state for all pairs of a capital provider/stablecoin combination.

Parameters

Required Accounts

Behavior

  • Updates pause state on LpStableConfig
  • Affects ALL pairs using this capital provider/stablecoin combination
  • Can be updated while the program is paused

Access Control

Access: Admin OR capital provider (config owner)

Liquidity Instructions

Treasury Routing

The capital provider controls routing through set_lp_treasury_enabled(enabled: bool). The flag is stored in LpProtocolFeeConfig, derived from ["lp_protocol_fee_config", liquidity_provider]. Enabling routing funds the capital provider vault-authority PDA for Treasury account rent; it does not move existing token balances by itself. Disabling routing does not redeem an existing position. When the configuration is first created, its protocol-fee rates are copied from the global configuration. The admin can set those rates independently through set_lp_protocol_fee_config. Routing requires an unpaused Treasury program and an unpaused asset registered as Stable in Treasury. For eligible assets, add_liquidity can deposit the entire post-transfer vault balance into Treasury, subject to its 1minimumNAVvalue.Duringswaps,onlyStableinputsareswept,andonlyStableoutputshortfallsareredeemed;RWAinventoryremainsinthecapitalprovidervault.Aswapsweeprequiresatleastonewholetoken,atleast1 minimum NAV value. During swaps, only Stable inputs are swept, and only Stable output shortfalls are redeemed; RWA inventory remains in the capital provider vault. A swap sweep requires at least one whole token, at least 1 of NAV value, and available pending-deposit capacity. Otherwise the input remains in the capital provider vault. Existing idle output liquidity is used before Treasury redemption. The Treasury position and receipt-token account belong to the capital provider’s swap vault-authority PDA. The Treasury manager configures supported assets and their NAV sources separately from the swap program.

add_liquidity

Treasury account counts are zero when Treasury routing is unused. amount_threshold is an optional minimum receipt output for the Treasury deposit. The optional argument must be encoded even when omitted (None). Deposit tokens into a vault.

Parameters

Required Accounts

Behavior

  • Transfers tokens from the capital provider’s account to vault
  • Vault is the mint’s ATA owned by the capital provider’s vault_authority PDA
  • Requires program, asset, and applicable capital provider stable config to be unpaused
  • Amount must be greater than 0
  • Deposits the whole post-transfer vault balance into Treasury when routing is enabled, Treasury and its Stable asset configuration are unpaused, and pending-deposit capacity is available

Access Control

Access: Capital provider (vault owner) only

Example


remove_liquidity

With Treasury routing, exact_mode selects value in Treasury token units (ExactIn) or asset output (ExactOut). amount_threshold bounds minimum asset output or maximum Treasury tokens actually burned respectively; without Treasury routing, amount is the asset amount. Withdraw tokens from a vault.

Parameters

Required Accounts

The common accounts are the capital provider, mint, capital provider token account, vault token account, capital provider vault authority, global config, capital provider protocol-fee config, and token program. Treasury routing uses the same Treasury accounts as add_liquidity, except that treasury_latest_apy_entry replaces treasury_system_program. remove_liquidity does not take swap asset_config or lp_stable_config accounts. Exact account ordering is defined in the Program IDL.

Behavior

  • Transfers tokens from vault to the capital provider’s account
  • Vault is the mint’s ATA owned by the capital provider’s vault_authority PDA
  • Requires program to be unpaused
  • Amount must be greater than 0
  • Direct withdrawal requires sufficient idle vault balance
  • Treasury-backed ExactOut uses idle vault liquidity first and redeems only the shortfall
  • Treasury-backed ExactIn transfers the assets received from redemption; receipt tokens are burned only for the principal consumed, while yield is accounted for in the position

Access Control

Access: Capital provider (vault owner) only

Closing Treasury and Fee Accounts

After withdrawing and settling the Treasury position, the capital provider can call close_treasury_position to recover its rent. Principal, accumulated yield, and pending deposits must all be zero. The instruction also closes the receipt-token account when empty and returns the capital provider vault-authority PDA’s lamports to the capital provider. close_lp_fee_account returns any remaining fee-token balance and closes the capital provider fee account. The capital provider closes its pairs first, because swaps require that fee account. Both instructions require the swap program to be unpaused.

Vault Architecture

Shared Vault Model

Vaults are shared across pairs for the same capital provider/token combination. Each capital provider has a vault_authority PDA, and each vault is the associated token account for (mint, vault_authority):

UserVaultInfo Tracking

The UserVaultInfo account tracks how many pairs use each vault:
  • Incremented when pair is created
  • Decremented when pair is closed
  • Vault closed only when used reaches 0
This ensures vaults aren’t closed while still in use by other pairs.

Error Codes


Next: Price Sources

Learn about NAV pricing sources and oracle integration