@exponent-labs/market-three-math
v0.1.8
Published
Mathematical simulation package for Exponent CLMM (Concentrated Liquidity Market Maker) markets.
Readme
@exponent-labs/market-three-math
Mathematical simulation package for Exponent CLMM (Concentrated Liquidity Market Maker) markets.
Overview
This package provides TypeScript implementations of the CLMM mathematical functions from the Exponent protocol. It enables client-side simulation of:
- Swap operations: Simulate PT ↔ SY trades with accurate pricing and fee calculations
- Liquidity deposits: Calculate required token amounts for concentrated liquidity positions
- Price calculations: Convert between effective prices, implied rates, and tick indices
The implementations are direct ports from the Rust on-chain program code in solana/programs/exponent_clmm.
Installation
yarn add @exponent-labs/market-three-mathUsage
Simulating a Swap
import { MarketThreeState, SwapDirection, simulateSwap } from "@exponent-labs/market-three-math"
// Prepare market state
const marketState: MarketThreeState = {
financials: {
expirationTs: Date.now() / 1000 + 86400, // 1 day from now
ptBalance: 1000000,
syBalance: 1000000,
liquidityBalance: 1000000,
},
configurationOptions: {
lnFeeRateRoot: 0.001,
rateScalarRoot: 5.0,
treasuryFeeBps: 2000, // 20%
lastLnImpliedRate: 0.05,
epsilonClamp: 0.000001,
minLpTickAmount: 1000,
maxLpSupply: 10000000000,
tickSpace: 100,
priceDecimals: 4,
},
ticks: {
currentTick: 500,
currentSpotPrice: 0.05,
feeGrowthIndexGlobalPt: 0,
feeGrowthIndexGlobalSy: 0,
ticks: [
// ... tick data
],
market: "marketAddress",
},
currentSyExchangeRate: 1.0,
}
// Simulate buying PT with SY
const swapResult = simulateSwap(marketState, {
direction: SwapDirection.SyToPt,
amountIn: 100000, // 100k SY
syExchangeRate: 1.0,
isCurrentFlashSwap: false,
priceSpotLimit: 0.06, // Maximum price willing to pay
})
console.log("PT received:", swapResult.amountOut)
console.log("Fees paid:", swapResult.lpFeeChargedOutToken + swapResult.protocolFeeChargedOutToken)
console.log("Final price:", swapResult.finalSpotPrice)Simulating Liquidity Deposit
import { estimateBalancedDeposit, simulateAddLiquidity } from "@exponent-labs/market-three-math"
// Estimate balanced amounts for a target liquidity
const { ptNeeded, syNeeded } = estimateBalancedDeposit(
marketState,
100000, // Target liquidity
4.5, // Lower tick APY (%)
5.5, // Upper tick APY (%)
)
// Simulate the actual deposit
const depositResult = simulateAddLiquidity(marketState, {
lowerTick: 45000, // 4.5% in basis points
upperTick: 55000, // 5.5% in basis points
maxSy: syNeeded,
maxPt: ptNeeded,
syExchangeRate: 1.0,
})
console.log("Liquidity added:", depositResult.deltaL)
console.log("PT spent:", depositResult.ptSpent)
console.log("SY spent:", depositResult.sySpent)Working with Effective Prices
import { EffSnap, normalizedTimeRemaining } from "@exponent-labs/market-three-math"
const secondsRemaining = 86400 // 1 day
const syExchangeRate = 1.0
const snap = new EffSnap(normalizedTimeRemaining(secondsRemaining), syExchangeRate)
// Convert ln implied rate to effective price
const lnImpliedRate = 0.05 // 5%
const effectivePrice = snap.getEffectivePrice(lnImpliedRate)
// Convert back from effective price to implied rate
const recoveredRate = snap.impliedRateFromEffectivePrice(effectivePrice)Key Concepts
Effective Price Model
The CLMM uses an effective price model where:
C = e^(-τ * u) / rWhere:
C= effective price (PT per SY)τ= time factor (normalized time to expiry)u= ln implied rate (spot price)r= SY exchange rate
Tick-Based Liquidity
Liquidity is concentrated in tick ranges, similar to Uniswap v3:
- Each tick represents a specific implied rate
- Liquidity is active only when the current price is within the tick range
- Ticks store principal PT and SY for accurate accounting
Fee Structure
Fees are calculated as:
- LP fee: Retained by liquidity providers
- Protocol fee: Sent to treasury (typically 20% of total fee)
- Total fee rate increases as expiration approaches
API Reference
Types
MarketThreeState: Complete market state required for simulationsSwapArgs: Arguments for swap simulationSwapOutcome: Results of a swap simulationAddLiquidityArgs: Arguments for liquidity deposit simulationAddLiquidityOutcome: Results of liquidity deposit simulationTick: Individual tick data structureTicks: Complete ticks array with metadata
Functions
Swap Functions
simulateSwap(marketState, args): Simulate a swap operationgetSwapQuote(marketState, amountIn, direction): Quick quote for a swap
Liquidity Functions
simulateAddLiquidity(marketState, args): Simulate liquidity depositestimateBalancedDeposit(marketState, targetLiquidity, lowerTickApy, upperTickApy): Estimate balanced PT/SY amountscomputeLiquidityTargetAndTokenNeeds(...): Low-level liquidity calculation
Utility Functions
EffSnap: Effective price snapshot classcalculateFeeRate(lnFeeRateRoot, secondsRemaining): Calculate current fee ratenormalizedTimeRemaining(secondsRemaining): Normalize time to [0,1]getLnImpliedRate(tickKey): Convert tick key to implied rateconvertApyToApyBp(apyPercent)/convertApyBpToApy(apyBp): APY conversion utilities
Relationship to On-Chain Code
This package is a direct port of the Rust implementations from:
solana/programs/exponent_clmm/src/state/market_three/helpers/swap.rssolana/programs/exponent_clmm/src/state/market_three/helpers/add_liquidity.rssolana/programs/exponent_clmm/src/utils/math.rs
The TypeScript implementations maintain mathematical equivalence with the on-chain code to ensure accurate simulations.
License
AGPL-3.0
