Price Impact
Calculate and manage price impact for swaps in CLMM pools.
Quick Start
// Calculate price impact before swap
const pool = await sdk.Pool.getPool(poolId)
const ticks = await sdk.Pool.fetchTicks({
pool_id: poolId,
coinTypeA: pool.coinTypeA,
coinTypeB: pool.coinTypeB
})
const result = sdk.Swap.calculateRates({
currentPool: pool,
coinTypeA: pool.coinTypeA,
coinTypeB: pool.coinTypeB,
decimalsA: 9,
decimalsB: 6,
a2b: true,
byAmountIn: true,
amount: new BN('1000000000'), // 1 SUI
swapTicks: ticks
})
console.log(`Price Impact: ${result.priceImpactPct.toFixed(2)}%`)
Understanding Price Impact
Price impact occurs when your trade moves the pool price:
Small trades: Minimal impact (<0.1%)
Medium trades: Noticeable impact (0.1-1%)
Large trades: Significant impact (>1%)
Calculate Methods
Method 1: Local Calculation
async function calculatePriceImpact(
poolId: string,
amount: string,
a2b: boolean,
byAmountIn: boolean
) {
// 1. Get pool and ticks
const pool = await sdk.Pool.getPool(poolId)
const ticks = await sdk.Pool.fetchTicks({
pool_id: poolId,
coinTypeA: pool.coinTypeA,
coinTypeB: pool.coinTypeB
})
// 2. Calculate swap result
const result = sdk.Swap.calculateRates({
currentPool: pool,
coinTypeA: pool.coinTypeA,
coinTypeB: pool.coinTypeB,
decimalsA: 9,
decimalsB: 6,
a2b,
byAmountIn,
amount: new BN(amount),
swapTicks: ticks
})
return {
priceImpact: result.priceImpactPct,
currentPrice: TickMath.sqrtPriceX64ToPrice(
pool.current_sqrt_price, 9, 6
),
endPrice: TickMath.sqrtPriceX64ToPrice(
result.estimatedEndSqrtPrice, 9, 6
),
isExceed: result.isExceed
}
}
Method 2: From PreSwap
async function getImpactFromPreSwap(
pool: Pool,
amount: string,
a2b: boolean
) {
// Get current price
const currentPrice = TickMath.sqrtPriceX64ToPrice(
pool.current_sqrt_price,
9, 6
)
// Simulate swap
const preSwap = await sdk.Swap.preswap({
pool,
coinTypeA: pool.coinTypeA,
coinTypeB: pool.coinTypeB,
decimalsA: 9,
decimalsB: 6,
a2b,
byAmountIn: true,
amount,
currentSqrtPrice: pool.current_sqrt_price
})
// Calculate end price
const endPrice = TickMath.sqrtPriceX64ToPrice(
new BN(preSwap.estimatedEndSqrtPrice),
9, 6
)
// Price impact = |endPrice - currentPrice| / currentPrice * 100
const impact = Math.abs(
endPrice.minus(currentPrice).div(currentPrice).mul(100).toNumber()
)
return {
impact,
currentPrice: currentPrice.toNumber(),
endPrice: endPrice.toNumber()
}
}
Router Price Impact
Calculate impact across multiple pools:
async function calculateRouterImpact(splitPaths: SplitPath[]) {
// Use SDK's built-in method
const totalImpact = sdk.Swap.calculateSwapPriceImpact(splitPaths)
console.log(`Total route impact: ${totalImpact}%`)
// Or calculate manually for each path
let weightedImpact = 0
splitPaths.forEach(path => {
const pathWeight = path.percent / 100
let pathImpact = 0
if (path.basePaths.length === 1) {
// Single hop
const exchangeRate = path.outputAmount / path.inputAmount
const marketPrice = path.basePaths[0].currentPrice
pathImpact = calculateSingleImpact(exchangeRate, marketPrice)
} else {
// Multi-hop
const totalExchangeRate = path.outputAmount / path.inputAmount
const marketPrice = path.basePaths.reduce(
(acc, bp) => acc.mul(bp.currentPrice),
new Decimal(1)
)
pathImpact = calculateSingleImpact(totalExchangeRate, marketPrice)
}
weightedImpact += pathImpact * pathWeight
})
return weightedImpact
}
Impact Thresholds
Set appropriate warnings based on impact:
function getPriceImpactSeverity(impactPercent: number) {
if (impactPercent < 0.1) return { level: 'low', color: 'green' }
if (impactPercent < 0.5) return { level: 'medium', color: 'yellow' }
if (impactPercent < 1.0) return { level: 'high', color: 'orange' }
return { level: 'severe', color: 'red' }
}
// Usage
const impact = await calculatePriceImpact(poolId, amount, true, true)
const severity = getPriceImpactSeverity(impact.priceImpact)
if (severity.level === 'severe') {
console.warn('⚠️ High price impact! Consider reducing trade size.')
}
Minimize Price Impact
1. Split Large Trades
async function splitTradeForBetterPrice(
totalAmount: BN,
maxImpactPercent: number
) {
const chunks = []
let remainingAmount = totalAmount
while (remainingAmount.gt(new BN(0))) {
// Find chunk size with acceptable impact
const chunkSize = await findMaxAmountForImpact(
poolId,
maxImpactPercent
)
if (chunkSize.gte(remainingAmount)) {
chunks.push(remainingAmount)
break
}
chunks.push(chunkSize)
remainingAmount = remainingAmount.sub(chunkSize)
}
return chunks
}
2. Use Multiple Pools
async function findLowImpactRoute(
amount: BN,
fromCoin: string,
toCoin: string
) {
// Router automatically minimizes impact
const bestRoute = await sdk.Router.getBestInternalRouter(
fromCoin,
toCoin,
amount,
true,
0.005, // 0.5% slippage
''
)
// Check if multi-hop has lower impact
if (bestRoute.paths[0].poolAddress.length > 1) {
console.log('Using multi-hop route for lower impact')
}
return bestRoute
}
Complete Example
async function executeSwapWithImpactCheck(
poolId: string,
amount: string,
maxImpactPercent: number
) {
// 1. Calculate impact
const impact = await calculatePriceImpact(
poolId,
amount,
true,
true
)
console.log(`Price Impact: ${impact.priceImpact.toFixed(3)}%`)
console.log(`Price: ${impact.currentPrice} → ${impact.endPrice}`)
// 2. Check threshold
if (impact.priceImpact > maxImpactPercent) {
throw new Error(
`Price impact ${impact.priceImpact}% exceeds max ${maxImpactPercent}%`
)
}
// 3. Warn user
const severity = getPriceImpactSeverity(impact.priceImpact)
if (severity.level !== 'low') {
console.warn(`${severity.level.toUpperCase()} price impact detected`)
}
// 4. Execute swap with slippage
const slippage = Math.max(0.5, impact.priceImpact * 1.5)
const swapParams = {
pool_id: poolId,
coinTypeA: pool.coinTypeA,
coinTypeB: pool.coinTypeB,
a2b: true,
by_amount_in: true,
amount,
amount_limit: calculateMinOutput(amount, slippage)
}
const tx = await sdk.Swap.createSwapTransactionPayload(swapParams)
return tx
}
Price Impact Formula
// Basic formula
priceImpact = |endPrice - startPrice| / startPrice * 100
// For CLMM
function calculateCLMMImpact(
startSqrtPrice: BN,
endSqrtPrice: BN,
decimalsA: number,
decimalsB: number
): number {
const startPrice = TickMath.sqrtPriceX64ToPrice(
startSqrtPrice, decimalsA, decimalsB
)
const endPrice = TickMath.sqrtPriceX64ToPrice(
endSqrtPrice, decimalsA, decimalsB
)
return Math.abs(
endPrice.minus(startPrice)
.div(startPrice)
.mul(100)
.toNumber()
)
}
Important Notes
Price impact increases with trade size
Impact is higher in low liquidity pools
Concentrated liquidity affects impact differently
Always set appropriate slippage tolerance
Consider splitting large trades
Monitor impact in real-time for better UX
Last updated