Skip to main content

Senior and Junior LP tokens are standard SPL token mints. They can be transferred between wallets, held by vaults, paired in AMMs, or accepted by external programs. The LP token itself does not expose a vault preview interface. The mint is only the transferable claim token. The tranching market account is the source of truth for NAV, utilization, coverage, fees, and lifecycle state. LP mints are initialized with the same decimals as the linked SY mint. Fetch mint metadata when displaying balances, and keep raw LP amounts in mint units when building instructions.

Token Addresses

TokenSDK helperAccount field
Senior LP mintmarket.lpMint(TrancheSide.Senior) or market.mintLpSeniormint_lp_senior
Junior LP mintmarket.lpMint(TrancheSide.Junior) or market.mintLpJuniormint_lp_junior
User Senior LP ATAmarket.lpAta(TrancheSide.Senior, owner)Derived from Senior LP mint
User Junior LP ATAmarket.lpAta(TrancheSide.Junior, owner)Derived from Junior LP mint
SY mint backing the marketmarket.syMintsy_mint
Market SY escrowmarket.tokenSyEscrowtoken_sy_escrow
See Addresses and Token Accounts for SDK helpers and ExponentTranchingMarket for raw account fields.
Transfers do not run onchain market sync. market.reload() only refreshes the SDK’s local account state; it does not update NAV onchain. For LP pricing, read the latest market account state. Deposit and withdrawal instructions run their own market-update path during execution.

State and Field Map

The following fields are the core inputs for DeFi integrations. The SDK column shows the TypeScript surface. The Rust column shows the account fields after deserializing ExponentTranchingMarket.
PurposeSDK helpers or fieldsRust account fieldsRaw dimensionReference
Lifecycle statestate.marketState, state.statusFlagsmarket.market_state, market.status_flagsEnum and bitmaskMarket State, Status Flags
Raw NAVgetSrNetAssetValue(), getJrNetAssetValue()market.financials.sr_raw_net_asset, market.financials.jr_raw_net_assetNumber NAV derived from raw SY unitsNAV Accounting, TranchingMarketFinancials
Effective NAVgetSrEffNetAssetValue(), getJrEffNetAssetValue()market.financials.sr_effective_net_asset, market.financials.jr_effective_net_assetNumber NAV after waterfall accountingNAV Accounting, LP Pricing
LP supplystate.trancheSupplyState.totalSeniorLpSupply, state.trancheSupplyState.totalJuniorLpSupplymarket.tranche_supply_state.total_senior_lp_supply, market.tranche_supply_state.total_junior_lp_supplyRaw LP mint unitsTrancheSupplyState, LP Pricing
SY assigned to each tranchestate.trancheAssetState.seniorSyAmount, state.trancheAssetState.juniorSyAmountmarket.tranche_asset_state.senior_sy_amount, market.tranche_asset_state.junior_sy_amountRaw SY token unitsTrancheAssetState
CapacitygetSrRemainingCapacityNetAssetValue(), getJrRemainingCapacityNetAssetValue()Derived from NAV, supply, and risk fields. See Rust Capacity FunctionRaw Number NAV. LP capacity helpers return raw LP unitsCapacity Helpers, Restrictions
Utilizationstate.financials.utilizationmarket.financials.utilizationNumber ratio. 1_000_000_000_000 means 1.0Utilization
Coverage requirementstate.riskConfig.minCoverage, state.riskConfig.betamarket.risk_config.min_coverage, market.risk_config.betaNumber ratiosCoverage, TranchingRiskConfig
Observation windowstate.riskConfig.fixedTermDurationSec, state.financials.fixedTermEndTsmarket.risk_config.fixed_term_duration_sec, market.financials.fixed_term_end_tsSeconds and Unix timestamp secondsRecovery Period, TranchingRiskConfig
Feesstate.protocolFeeConfig.*, pending fee share fieldsmarket.protocol_fee_config.*, market.tranche_supply_state.pending_*_protocol_fee_lp_sharesFee rates are Number ratios. Pending fee shares are raw LP unitsFee Structure, Units and Fees
Return allocationstate.returnModel, state.financials.currentJuniorReturnSharemarket.return_model_storage, market.financials.current_junior_return_share, market.financials.tw_junior_return_share_accruedCurve data and Number ratiosReturn Curves, ReturnModel

Rust Field Example

Rust integrations usually start from the deserialized market account and then read the same inputs used by the SDK helpers.
use exponent_tranching::{
    ExponentTranchingMarket,
    MARKET_STATUS_FLAG_PAUSED,
};
use precise_number::Number;

fn read_market_inputs(
    market: &ExponentTranchingMarket,
) -> (bool, Number, Number, u64, u64, Number, i64) {
    let is_paused = (market.status_flags & MARKET_STATUS_FLAG_PAUSED) != 0;

    let senior_effective_nav: Number = market.financials.sr_effective_net_asset;
    let junior_effective_nav: Number = market.financials.jr_effective_net_asset;

    let senior_lp_supply = market.tranche_supply_state.total_senior_lp_supply;
    let junior_lp_supply = market.tranche_supply_state.total_junior_lp_supply;

    let utilization: Number = market.financials.utilization;
    let fixed_term_end_ts = market.financials.fixed_term_end_ts;

    (
        is_paused,
        senior_effective_nav,
        junior_effective_nav,
        senior_lp_supply,
        junior_lp_supply,
        utilization,
        fixed_term_end_ts,
    )
}
For the LP price formula that combines effective_nav with total_*_lp_supply, see LP Pricing.

Rust Capacity Function

Capacity is derived. There is no single ExponentTranchingMarket field that equals getSrRemainingCapacityNetAssetValue() or getJrRemainingCapacityNetAssetValue().
use exponent_tranching::ExponentTranchingMarket;
use precise_number::Number;

struct CapacityPreview {
    senior_remaining_nav: Number,
    junior_remaining_nav: Option<Number>,
}

// `lp_price`, `lp_out`, and `mul_div_number` should mirror program rounding.
// `mul_div_number(..., true)` rounds up; `false` rounds down.
fn calculate_capacity(market: &ExponentTranchingMarket) -> Option<CapacityPreview> {
    let financials = &market.financials;
    let supply = &market.tranche_supply_state;
    let risk = &market.risk_config;

    let senior_lp_price = lp_price(
        financials.sr_effective_net_asset,
        supply.total_senior_lp_supply,
    )?;
    let junior_lp_price = lp_price(
        financials.jr_effective_net_asset,
        supply.total_junior_lp_supply,
    )?;

    let beta_adjusted_junior_nav =
        mul_div_number(financials.jr_raw_net_asset, risk.beta, Number::ONE, true)?;
    let current_protected_exposure =
        financials.sr_raw_net_asset.checked_add(&beta_adjusted_junior_nav)?;
    let max_protected_exposure = if risk.min_coverage == Number::ZERO
        || financials.jr_effective_net_asset == Number::ZERO
    {
        Number::ZERO
    } else {
        mul_div_number(
            financials.jr_effective_net_asset,
            Number::ONE,
            risk.min_coverage,
            false,
        )?
    };
    let senior_coverage_remaining_nav = max_protected_exposure
        .checked_sub(&current_protected_exposure)
        .unwrap_or(Number::ZERO);

    let remaining_coverage_lp = lp_out(
        senior_coverage_remaining_nav,
        supply.total_senior_lp_supply,
        financials.sr_effective_net_asset,
    )?;
    let coverage_lp_capacity = supply
        .total_senior_lp_supply
        .checked_add(remaining_coverage_lp)?;
    let senior_lp_capacity = if supply.max_senior_lp_supply == 0 {
        coverage_lp_capacity
    } else {
        supply.max_senior_lp_supply.min(coverage_lp_capacity)
    };
    let senior_remaining_lp_capacity =
        senior_lp_capacity.saturating_sub(supply.total_senior_lp_supply);
    let senior_remaining_nav_by_lp =
        senior_lp_price.checked_mul(&Number::from(senior_remaining_lp_capacity as u128))?;
    let senior_remaining_nav = if senior_remaining_nav_by_lp <= senior_coverage_remaining_nav {
        senior_remaining_nav_by_lp
    } else {
        senior_coverage_remaining_nav
    };

    let junior_remaining_nav = if supply.max_junior_lp_supply == 0 {
        None
    } else {
        let junior_remaining_lp_capacity =
            supply.max_junior_lp_supply.saturating_sub(supply.total_junior_lp_supply);
        Some(junior_lp_price.checked_mul(&Number::from(
            junior_remaining_lp_capacity as u128,
        ))?)
    };

    Some(CapacityPreview {
        senior_remaining_nav,
        junior_remaining_nav,
    })
}
For lp_price, see LP Pricing. For lp_out, see Deposit Previews. fixedTermDurationSec is the fixed-term observation period duration used by Recovery Period accounting. If it is 0, fixed-term recovery is disabled. fixedTermEndTs is the timestamp when the current recovery window ends. tranchingFromNumber and tranchingNumberToRaw only convert the Number fixed-point encoding. In Rust, use precise_number::Number; one unit is Number::DENOM, or 1_000_000_000_000. Apply token mint decimals separately when showing SY, LP, or NAV amounts to users.

Token Integration Notes

AreaGuidance
TransfersLP tokens are transferable SPL tokens. A transfer does not change market NAV or utilization
CustodyVaults and lending protocols can hold LP token accounts directly
PricingPrice balances from effective NAV, not from raw SY balance alone
RedemptionRedemption rules depend on market state, utilization, and tranche side
Risk displayShow Senior and Junior separately. They do not have the same risk profile
For pricing formulas and examples, see Pricing and Previews.