UNPKG

@raydium-io/raydium-sdk-v2

Version:

An SDK for building applications on top of Raydium.

134 lines (111 loc) 3.69 kB
import BN from "bn.js" import { divRoundingUp, mulDivCeil, mulDivFloor } from "./bigNum" import { BN_ONE, BN_ZERO, Q64, RESOLUTION } from "./constants" export class SqrtPriceMath { static getNextSqrtPriceFromAmountARoundingUp( sqrtPriceX64: BN, liquidity: BN, amount: BN, add: boolean ): BN { if (amount.isZero()) { return sqrtPriceX64 } const numerator = liquidity.shln(RESOLUTION) if (add) { const product = amount.mul(sqrtPriceX64) const denominator = numerator.add(product) if (denominator.gte(numerator)) { return mulDivCeil(numerator, sqrtPriceX64, denominator) } const quotient = mulDivFloor(numerator, BN_ONE, sqrtPriceX64) return mulDivCeil(numerator, BN_ONE, quotient.add(amount)) } else { const product = amount.mul(sqrtPriceX64) if (numerator.lte(product)) { throw new Error("Insufficient liquidity for token0 removal") } const denominator = numerator.sub(product) return mulDivCeil(numerator, sqrtPriceX64, denominator) } } static getNextSqrtPriceFromAmountBRoundingDown( sqrtPriceX64: BN, liquidity: BN, amount: BN, add: boolean ): BN { if (amount.isZero()) { return sqrtPriceX64 } if (add) { const quotient = amount.shln(RESOLUTION).div(liquidity) return sqrtPriceX64.add(quotient) } else { const quotient = divRoundingUp(amount.shln(RESOLUTION), liquidity) return sqrtPriceX64.sub(quotient) } } static getNextSqrtPriceFromInput( sqrtPriceX64: BN, liquidity: BN, amountIn: BN, zeroForOne: boolean ): BN { if (!sqrtPriceX64.gt(BN_ZERO)) throw Error('sqrtPriceX64.gt(BN_ZERO)') if (!liquidity.gt(BN_ZERO)) throw Error('liquidity.gt(BN_ZERO)') if (zeroForOne) { return this.getNextSqrtPriceFromAmountARoundingUp(sqrtPriceX64, liquidity, amountIn, true) } else { return this.getNextSqrtPriceFromAmountBRoundingDown(sqrtPriceX64, liquidity, amountIn, true) } } static getNextSqrtPriceFromOutput( sqrtPriceX64: BN, liquidity: BN, amountIn: BN, zeroForOne: boolean ): BN { if (!sqrtPriceX64.gt(BN_ZERO)) throw Error('sqrtPriceX64.gt(BN_ZERO)') if (!liquidity.gt(BN_ZERO)) throw Error('liquidity.gt(BN_ZERO)') if (zeroForOne) { return this.getNextSqrtPriceFromAmountBRoundingDown(sqrtPriceX64, liquidity, amountIn, false) } else { return this.getNextSqrtPriceFromAmountARoundingUp(sqrtPriceX64, liquidity, amountIn, false) } } static getAmountADeltaUnsigned( sqrtPriceLowerX64: BN, sqrtPriceUpperX64: BN, liquidity: BN, roundUp: boolean ): BN { if (sqrtPriceLowerX64.gt(sqrtPriceUpperX64)) { [sqrtPriceLowerX64, sqrtPriceUpperX64] = [sqrtPriceUpperX64, sqrtPriceLowerX64] } const priceDelta = sqrtPriceUpperX64.sub(sqrtPriceLowerX64) const numerator = liquidity.mul(priceDelta).shln(64) const denominator = sqrtPriceLowerX64.mul(sqrtPriceUpperX64) if (roundUp) { return mulDivCeil(numerator, BN_ONE, denominator) } else { return mulDivFloor(numerator, BN_ONE, denominator) } } static getAmountBDeltaUnsigned( sqrtPriceLowerX64: BN, sqrtPriceUpperX64: BN, liquidity: BN, roundUp: boolean ): BN { if (sqrtPriceLowerX64.gt(sqrtPriceUpperX64)) { [sqrtPriceLowerX64, sqrtPriceUpperX64] = [sqrtPriceUpperX64, sqrtPriceLowerX64] } const priceDelta = sqrtPriceUpperX64.sub(sqrtPriceLowerX64) if (roundUp) { return mulDivCeil(liquidity, priceDelta, Q64) } else { return mulDivFloor(liquidity, priceDelta, Q64) } } }