Skip to main content

Overview

The Multiliquid SVM program does not implement a native laddered pricing model on chain. Instead, each pair stores one live discount rate and one live redemption fee. An LP can still build a laddered pricing model on top of those fields by using an off-chain worker to monitor rolling volume and update fees as thresholds are crossed.
  • Each Pair has one redemption_fee_bps and one discount_rate_bps, which can be updated by the LP admin every block if needed
  • Each Pair sources liquidity from two vaults: one vault for the stablecoin and one vault for the RWA
  • Swaps consume whatever fee values are currently stored in the pair
Given that design, a laddered pricing model has to be enforced operationally.
This page uses discount_rate_bps for the primary example, but the same approach can be mirrored onto redemption_fee_bps.
Example scenario: An LP admin wants to keep up to $2,500,000 of live stablecoin inventory available for RWA1 while applying a tiered discount schedule across rolling 24-hour AssetToStable volume. The first ~$2.5M should clear at a 1% discount, giving the user 99% of the RWA1 NAV value in stablecoin. From $2.5M to $5M, the discount is set at 5%. From $5M to $10M, the discount is set at 15%.
Rolling 24-hour cumulative volumeActive discount_rate_bpsDiscount
$0 to < $2.5M1001.00%
$2.5M to < $5M5005.00%
$5M to < $10M150015.00%
This pricing model is enforced by an off-chain worker that tracks cumulative rolling 24-hour volume for swaps on RWA1.
  1. The LP keeps between $1,000,000 and $2,500,000 of live stablecoin inventory in the vault at any given time
  2. An off-chain worker measures rolling 24-hour volume
  3. The worker decides which tier is currently active
  4. When a threshold is crossed, the worker updates discount_rate_bps via update_pair
  5. The LP uses add_liquidity to top up the stablecoin vault when balances fall below the chosen threshold, for example $1,000,000, potentially sourcing capital from a yield-generating product such as Liquid Treasury

What The Program Gives You

Pair Fee Fields

The pair stores only the currently active fee values:
pub struct Pair {
    pub redemption_fee_bps: u16,
    pub discount_rate_bps: u16,
    pub stable_coin_mint_address: Pubkey,
    pub asset_token_mint_address: Pubkey,
    pub liquidity_provider: Pubkey,
    pub paused: bool,
    pub bump: u8,
}
Operationally, this means:
  • redemption_fee_bps is the live fee for StableToAsset
  • discount_rate_bps is the live fee for AssetToStable
  • the current ladder rung is represented by the current value stored in the pair

Live Fee Updates

The LP can rotate the active rung with update_pair:
pub fn update_pair(
    ctx: Context<UpdatePair>,
    redemption_fee_bps: u16,
    discount_rate_bps: u16,
    paused: bool,
) -> Result<()>
This is the key mechanism that makes the ladder possible despite only having one fee field per direction.

Shared Vault Liquidity

Liquidity is not stored per pair. It is stored per LP + mint:
  • one vault per LP and stable mint
  • one vault per LP and RWA mint
So:
  • add_liquidity deposits into the LP’s vault for a mint
  • remove_liquidity withdraws from that same vault
  • if the LP has multiple pairs using the same mint, those pairs share the same vault balance
This shared-vault model is what lets the LP keep only a bounded amount of capital on chain while still supporting more cumulative daily turnover.

Directional Fee And Inventory Mechanics

The two fee fields are directional:
Swap directionPair field usedInventory that leaves LP vaultInventory that enters LP vault
StableToAssetredemption_fee_bpsRWAStablecoin
AssetToStablediscount_rate_bpsStablecoinRWA
For the scenario in this page, the ladder is a discount ladder, so the relevant direction is:
  • user sells RWA to the LP
  • LP pays out stablecoin
  • the live price lever is discount_rate_bps
  • the constrained inventory is the LP’s stablecoin vault
That is why this model can be run with:
  • a rolling 24-hour counter off chain
  • periodic update_pair calls that change only discount_rate_bps
  • periodic stablecoin add_liquidity and remove_liquidity calls
In many deployments, redemption_fee_bps can stay fixed while only discount_rate_bps changes with the ladder. If the LP also wants a ladder on the opposite direction, the same pattern applies:
  • maintain a separate rolling notional book for StableToAsset
  • choose the active redemption_fee_bps from that book
  • pass both the current redemption_fee_bps and current discount_rate_bps into update_pair
In other words, the pair does not store an entire schedule. It stores the currently active rung for each direction.

Reference Ladder

For the example strategy, define the active discount_rate_bps from rolling 24-hour notional:
Rolling 24-hour cumulative volumeActive discount_rate_bpsDiscount
$0 to < $2,500,0001001.00%
$2,500,000 to < $5,000,0005005.00%
$5,000,000 to < $10,000,000150015.00%
This should be read as:
  • there is one active rung at any point in time
  • the worker recomputes the rolling 24-hour total
  • the worker updates the pair to the fee corresponding to the current band
The program does not transition bands automatically. The LP’s worker does.

How To Measure The Rolling 24-Hour Volume

For a discount ladder on AssetToStable, the cleanest operational metric is:
stable_outflow_per_fill = amount_out + protocol_fee_amount
Why this works:
  • on AssetToStable, the user receives stablecoin from the LP stable vault
  • protocol fees are also paid out of that same stable vault
  • so amount_out + protocol_fee_amount is the total stable inventory consumed by the fill
That makes the rolling ladder straightforward to compute:
rolling_24h_stable_outflow =
  Σ(amount_out + protocol_fee_amount)
  for all AssetToStable swaps in the last 24 hours
For a $1.00 stablecoin such as USDC, that rolling stable outflow is already a practical dollar proxy.
For AssetToStable, do not rely on the raw amount_in field from the SwapExecuted event as your primary volume metric. In this direction, the useful inventory measure is stablecoin consumed from the LP vault, which is amount_out + protocol_fee_amount.

How The Live Inventory Band Works

Assume the LP wants to keep up to $2,500,000 of stablecoin live in the vault, and refill when the balance drops below $1,000,000. Define:
  • target stable vault balance: $2,500,000
  • refill floor: $1,000,000
  • refill amount: target - current_vault_balance
Then the worker applies the following policy:
  • if the stable vault balance is below $1,000,000, call add_liquidity with the delta back to $2,500,000
  • if the stable vault balance is above $2,500,000, call remove_liquidity for the excess
This keeps the live capital band between $1,000,000 and $2,500,000 while allowing the LP to manage on-chain inventory independently from the rolling fee ladder. That is the core distinction:
  • live liquidity is what is currently sitting in the vault
  • rolling 24-hour volume is what has traded through the vault over time
The LP can therefore run a rolling ladder that tops out at $10,000,000 while keeping between $1,000,000 and $2,500,000 of stablecoin inventory on chain, replenishing inventory as needed during the day.

Why remove_liquidity Matters

remove_liquidity is just as important as add_liquidity. In this model:
  • AssetToStable flow drains stablecoin from the stable vault and accumulates RWA in the RWA vault
  • StableToAsset flow does the opposite: it adds stablecoin to the stable vault and drains RWA from the RWA vault
That means the worker can use remove_liquidity in two practical ways:
  • sweep excess stablecoin out of the stable vault when reverse flow pushes it above the $2,500,000 cap
  • sweep accumulated RWA out of the RWA vault after users sell RWA into the LP
This lets the LP keep only the intended amount of on-chain capital exposed to the pair while moving the rest back to custody, treasury, or an execution wallet.

Single-Pair And Multi-Pair Variants

Single Pair

For one RWA / stablecoin pair, the model is simple:
  • track rolling 24-hour volume for that pair
  • update that pair’s discount_rate_bps
  • manage the pair’s shared stable vault balance

Multiple Pairs Sharing The Same Stablecoin

If the LP wants one ladder across several pairs that all share the same stablecoin:
  • the stable vault is already shared across those pairs because the vault is keyed by LP + stable mint
  • the worker should aggregate rolling notional across the full set of managed pairs
  • the worker should push the same active discount_rate_bps to every pair in that set
  • stablecoin rebalancing is done once at the shared stable vault
This is the cleanest version of a cross-pair ladder on the current program.

Multiple Pairs Across Different Stablecoins

If the LP spans multiple stablecoins:
  • each stablecoin still has its own vault
  • the worker must normalize fills into a common USD measure off chain
  • update_pair must still be called per pair
  • liquidity rebalancing must still be done per stable vault
So the ladder can still be global across the LP’s book, but the accounting is entirely off chain. Contact the Multiliquid team for guidance on building an off-chain worker that tracks rolling 24-hour volume, rotates pair fees with update_pair, and rebalances vault inventory with add_liquidity and remove_liquidity.

What To Do At 10M Rolling Volume

Because this page assumes no pause controls, the $10,000,000 level should be treated as a soft operating budget, not as a hard protocol-enforced stop. In practice, the worker usually does one or both of the following once rolling 24-hour volume reaches the final band:
  • keep the pair on the highest configured discount tier
  • stop topping the stable vault back up after it drains below the LP’s desired exposure
That is enough to express the pricing model operationally, but it is important to be precise about the limit:
  • the fee schedule is controllable
  • the live inventory band is controllable
  • the exact rolling-volume ceiling is not enforced atomically by the program
Without an on-chain rolling-volume counter, fee-tier transitions are not atomic with swap execution. A trade can cross a threshold before the worker’s next update_pair transaction lands. The model works well as an LP-admin policy, but it is not a hard on-chain invariant.

Practical Summary

The current SVM swap program is sufficient to run this laddered model today:
  • use discount_rate_bps as the current active rung for AssetToStable
  • keep redemption_fee_bps fixed unless the LP also wants a ladder on StableToAsset
  • measure rolling 24-hour stable outflow off chain
  • update the pair fee when the rolling total enters a new band
  • keep only $1,000,000 to $2,500,000 of live stablecoin inventory in the vault with add_liquidity and remove_liquidity
  • if the ladder spans multiple pairs, aggregate volume off chain and push the selected rung to each managed pair
  • treat the $10,000,000 threshold as an operational target rather than a hard on-chain invariant
That is the correct way to implement a laddered LP pricing model on the current protocol without adding any new on-chain state.

Pair Management

Full reference for pair instructions, account structures, and liquidity management

Integration Guide

SDK installation, quoting, and swap execution