UNPKG

@ferra-labs/clmm

Version:

SDK for concentrated liquidity market maker

1,282 lines (1,270 loc) 288 kB
import { normalizeSuiObjectId, isValidSuiAddress, normalizeSuiAddress, isValidSuiObjectId, normalizeStructTag } from '@mysten/sui/utils'; import { Transaction, coinWithBalance } from '@mysten/sui/transactions'; import BN4 from 'bn.js'; import { fromHEX, fromB64 } from '@mysten/bcs'; import { Ed25519Keypair } from '@mysten/sui/keypairs/ed25519'; import { Secp256k1Keypair } from '@mysten/sui/keypairs/secp256k1'; import Decimal2 from 'decimal.js'; import { SuiClient } from '@mysten/sui/client'; import { Graph, GraphVertex, GraphEdge } from '@syntsugar/cc-graph'; /* CLMM SDK v1.0.0 */ var __defProp = Object.defineProperty; var __name = (target, value) => __defProp(target, "name", { value, configurable: true }); // src/utils/cached-content.ts var cacheTime5min = 5 * 60 * 1e3; var cacheTime24h = 24 * 60 * 60 * 1e3; function getFutureTime(interval) { return Date.parse((/* @__PURE__ */ new Date()).toString()) + interval; } __name(getFutureTime, "getFutureTime"); var _CachedContent = class _CachedContent { constructor(value, overdueTime = 0) { this.overdueTime = overdueTime; this.value = value; } isValid() { if (this.value === null) { return false; } if (this.overdueTime === 0) { return true; } if (Date.parse((/* @__PURE__ */ new Date()).toString()) > this.overdueTime) { return false; } return true; } }; __name(_CachedContent, "CachedContent"); var CachedContent = _CachedContent; Decimal2.config({ precision: 64, rounding: Decimal2.ROUND_DOWN, toExpNeg: -64, toExpPos: 64 }); var decimal_default = Decimal2; // src/errors/errors.ts var _ClmmpoolsError = class _ClmmpoolsError extends Error { constructor(message, errorCode) { super(message); this.message = message; this.errorCode = errorCode; } static isClmmpoolsErrorCode(e, code) { return e instanceof _ClmmpoolsError && e.errorCode === code; } }; __name(_ClmmpoolsError, "ClmmpoolsError"); var ClmmpoolsError = _ClmmpoolsError; // src/math/utils.ts var ZERO = new BN4(0); var ONE = new BN4(1); var TWO = new BN4(2); var U128 = TWO.pow(new BN4(128)); var U64_MAX = TWO.pow(new BN4(64)).sub(ONE); var U128_MAX = TWO.pow(new BN4(128)).sub(ONE); var _MathUtil = class _MathUtil { static toX64_BN(num) { return num.mul(new BN4(2).pow(new BN4(64))); } static toX64_Decimal(num) { return num.mul(decimal_default.pow(2, 64)); } static toX64(num) { return new BN4(num.mul(decimal_default.pow(2, 64)).floor().toFixed()); } static fromX64(num) { return new decimal_default(num.toString()).mul(decimal_default.pow(2, -64)); } static fromX64_Decimal(num) { return num.mul(decimal_default.pow(2, -64)); } static fromX64_BN(num) { return num.div(new BN4(2).pow(new BN4(64))); } static shiftRightRoundUp(n) { let result = n.shrn(64); if (n.mod(U64_MAX).gt(ZERO)) { result = result.add(ONE); } return result; } static divRoundUp(n0, n1) { const hasRemainder = !n0.mod(n1).eq(ZERO); if (hasRemainder) { return n0.div(n1).add(new BN4(1)); } return n0.div(n1); } static subUnderflowU128(n0, n1) { if (n0.lt(n1)) { return n0.sub(n1).add(U128_MAX); } return n0.sub(n1); } static checkUnsignedSub(n0, n1) { const n = n0.sub(n1); if (n.isNeg()) { throw new ClmmpoolsError("Unsigned integer sub overflow", "UnsignedIntegerOverflow" /* UnsignedIntegerOverflow */); } return n; } static checkMul(n0, n1, limit) { const n = n0.mul(n1); if (this.isOverflow(n, limit)) { throw new ClmmpoolsError("Multiplication overflow", "MultiplicationOverflow" /* MulOverflow */); } return n; } static checkMulDivFloor(n0, n1, denom, limit) { if (denom.eq(ZERO)) { throw new ClmmpoolsError("Devide by zero", "DivideByZero" /* DivideByZero */); } const n = n0.mul(n1).div(denom); if (this.isOverflow(n, limit)) { throw new ClmmpoolsError("Multiplication div overflow", "MulDivOverflow" /* MulDivOverflow */); } return n; } static checkMulDivCeil(n0, n1, denom, limit) { if (denom.eq(ZERO)) { throw new ClmmpoolsError("Devide by zero", "DivideByZero" /* DivideByZero */); } const n = n0.mul(n1).add(denom.sub(ONE)).div(denom); if (this.isOverflow(n, limit)) { throw new ClmmpoolsError("Multiplication div overflow", "MulDivOverflow" /* MulDivOverflow */); } return n; } static checkMulDivRound(n0, n1, denom, limit) { if (denom.eq(ZERO)) { throw new ClmmpoolsError("Devide by zero", "DivideByZero" /* DivideByZero */); } const n = n0.mul(n1.add(denom.shrn(1))).div(denom); if (this.isOverflow(n, limit)) { throw new ClmmpoolsError("Multiplication div overflow", "MulDivOverflow" /* MulDivOverflow */); } return n; } static checkMulShiftRight(n0, n1, shift, limit) { const n = n0.mul(n1).div(new BN4(2).pow(new BN4(shift))); if (this.isOverflow(n, limit)) { throw new ClmmpoolsError("Multiplication shift right overflow", "MulShiftRightOverflow" /* MulShiftRightOverflow */); } return n; } static checkMulShiftRight64RoundUpIf(n0, n1, limit, roundUp) { const p = n0.mul(n1); const shoudRoundUp = roundUp && p.and(U64_MAX).gt(ZERO); const result = shoudRoundUp ? p.shrn(64).add(ONE) : p.shrn(64); if (this.isOverflow(result, limit)) { throw new ClmmpoolsError("Multiplication shift right overflow", "MulShiftRightOverflow" /* MulShiftRightOverflow */); } return result; } static checkMulShiftLeft(n0, n1, shift, limit) { const n = n0.mul(n1).shln(shift); if (this.isOverflow(n, limit)) { throw new ClmmpoolsError("Multiplication shift left overflow", "MulShiftLeftOverflow" /* MulShiftLeftOverflow */); } return n; } static checkDivRoundUpIf(n0, n1, roundUp) { if (n1.eq(ZERO)) { throw new ClmmpoolsError("Devide by zero", "DivideByZero" /* DivideByZero */); } if (roundUp) { return this.divRoundUp(n0, n1); } return n0.div(n1); } static isOverflow(n, bit) { return n.gte(TWO.pow(new BN4(bit))); } static sign(v) { const signBit = v.testn(127) ? 1 : 0; return signBit; } static is_neg(v) { return this.sign(v) === 1; } static abs_u128(v) { if (v.gt(ZERO)) { return v; } return this.u128_neg(v.subn(1)); } static u128_neg(v) { return v.uxor(new BN4("ffffffffffffffffffffffffffffffff", 16)); } static neg(v) { if (this.is_neg(v)) { return v.abs(); } return this.neg_from(v); } static abs(v) { if (this.sign(v) === 0) { return v; } return this.u128_neg(v.sub(new BN4(1))); } static neg_from(v) { if (v.eq(ZERO)) { return v; } return this.u128_neg(v).add(new BN4(1)).or(new BN4(1).shln(127)); } }; __name(_MathUtil, "MathUtil"); var MathUtil = _MathUtil; // src/types/clmm-pool.ts function transClmmpoolDataWithoutTicks(pool) { const poolData = { coinA: pool.coinTypeA, // string coinB: pool.coinTypeB, // string currentSqrtPrice: new BN4(pool.current_sqrt_price), // BN currentTickIndex: pool.current_tick_index, // number feeGrowthGlobalA: new BN4(pool.fee_growth_global_a), // BN feeGrowthGlobalB: new BN4(pool.fee_growth_global_b), // BN feeProtocolCoinA: new BN4(pool.fee_protocol_coin_a), // BN feeProtocolCoinB: new BN4(pool.fee_protocol_coin_b), // BN feeRate: new BN4(pool.fee_rate), // number liquidity: new BN4(pool.liquidity), // BN tickIndexes: [], // number[] tickSpacing: Number(pool.tickSpacing), // number ticks: [], // Array<TickData> collection_name: "" }; return poolData; } __name(transClmmpoolDataWithoutTicks, "transClmmpoolDataWithoutTicks"); function newBits(index) { const index_BN = new BN4(index); if (index_BN.lt(ZERO)) { return { bits: index_BN.neg().xor(new BN4(2).pow(new BN4(64)).sub(new BN4(1))).add(new BN4(1)).toString() }; } return { bits: index_BN.toString() }; } __name(newBits, "newBits"); var MAX_TICK_INDEX = 443636; var MIN_TICK_INDEX = -443636; var MAX_SQRT_PRICE = "79226673515401279992447579055"; var TICK_ARRAY_SIZE = 64; var MIN_SQRT_PRICE = "4295048016"; var FEE_RATE_DENOMINATOR = new BN4(1e6); // src/types/sui.ts var CLOCK_ADDRESS = "0x0000000000000000000000000000000000000000000000000000000000000006"; var ClmmPartnerModule = "partner"; var ClmmIntegratePoolModule = "pool_script"; var ClmmIntegrateRouterModule = "router"; var ClmmIntegrateRouterWithPartnerModule = "router_with_partner"; var ClmmFetcherModule = "fetcher_script"; var ClmmExpectSwapModule = "expect_swap"; var ClmmIntegrateUtilsModule = "utils"; var CoinInfoAddress = "0x1::coin::CoinInfo"; var CoinStoreAddress = "0x1::coin::CoinStore"; var getDefaultSuiInputType = /* @__PURE__ */ __name((value) => { if (typeof value === "string" && value.startsWith("0x")) { return "object"; } if (typeof value === "number" || typeof value === "bigint") { return "u64"; } if (typeof value === "boolean") { return "bool"; } throw new ClmmpoolsError(`Unknown type for value: ${value}`, "InvalidType" /* InvalidType */); }, "getDefaultSuiInputType"); // src/types/clmm-type.ts var ClmmPositionStatus = /* @__PURE__ */ ((ClmmPositionStatus2) => { ClmmPositionStatus2["Deleted"] = "Deleted"; ClmmPositionStatus2["Exists"] = "Exists"; ClmmPositionStatus2["NotExists"] = "NotExists"; return ClmmPositionStatus2; })(ClmmPositionStatus || {}); function getPackagerConfigs(packageObj) { if (packageObj.config === void 0) { throw new ClmmpoolsError(`package: ${packageObj.package_id} not config in sdk SdkOptions`, "InvalidConfig" /* InvalidConfig */); } return packageObj.config; } __name(getPackagerConfigs, "getPackagerConfigs"); var poolFilterEvenTypes = ["RemoveLiquidityEvent", "SwapEvent", "AddLiquidityEvent"]; // src/types/liquidity.ts var SwapDirection = /* @__PURE__ */ ((SwapDirection2) => { SwapDirection2["A2B"] = "a2b"; SwapDirection2["B2A"] = "b2a"; return SwapDirection2; })(SwapDirection || {}); var BIT_PRECISION = 14; var LOG_B_2_X32 = "59543866431248"; var LOG_B_P_ERR_MARGIN_LOWER_X64 = "184467440737095516"; var LOG_B_P_ERR_MARGIN_UPPER_X64 = "15793534762490258745"; var TICK_BOUND = 443636; function signedShiftLeft(n0, shiftBy, bitWidth) { const twosN0 = n0.toTwos(bitWidth).shln(shiftBy); twosN0.imaskn(bitWidth + 1); return twosN0.fromTwos(bitWidth); } __name(signedShiftLeft, "signedShiftLeft"); function signedShiftRight(n0, shiftBy, bitWidth) { const twoN0 = n0.toTwos(bitWidth).shrn(shiftBy); twoN0.imaskn(bitWidth - shiftBy + 1); return twoN0.fromTwos(bitWidth - shiftBy); } __name(signedShiftRight, "signedShiftRight"); function tickIndexToSqrtPricePositive(tick) { let ratio; if ((tick & 1) !== 0) { ratio = new BN4("79232123823359799118286999567"); } else { ratio = new BN4("79228162514264337593543950336"); } if ((tick & 2) !== 0) { ratio = signedShiftRight(ratio.mul(new BN4("79236085330515764027303304731")), 96, 256); } if ((tick & 4) !== 0) { ratio = signedShiftRight(ratio.mul(new BN4("79244008939048815603706035061")), 96, 256); } if ((tick & 8) !== 0) { ratio = signedShiftRight(ratio.mul(new BN4("79259858533276714757314932305")), 96, 256); } if ((tick & 16) !== 0) { ratio = signedShiftRight(ratio.mul(new BN4("79291567232598584799939703904")), 96, 256); } if ((tick & 32) !== 0) { ratio = signedShiftRight(ratio.mul(new BN4("79355022692464371645785046466")), 96, 256); } if ((tick & 64) !== 0) { ratio = signedShiftRight(ratio.mul(new BN4("79482085999252804386437311141")), 96, 256); } if ((tick & 128) !== 0) { ratio = signedShiftRight(ratio.mul(new BN4("79736823300114093921829183326")), 96, 256); } if ((tick & 256) !== 0) { ratio = signedShiftRight(ratio.mul(new BN4("80248749790819932309965073892")), 96, 256); } if ((tick & 512) !== 0) { ratio = signedShiftRight(ratio.mul(new BN4("81282483887344747381513967011")), 96, 256); } if ((tick & 1024) !== 0) { ratio = signedShiftRight(ratio.mul(new BN4("83390072131320151908154831281")), 96, 256); } if ((tick & 2048) !== 0) { ratio = signedShiftRight(ratio.mul(new BN4("87770609709833776024991924138")), 96, 256); } if ((tick & 4096) !== 0) { ratio = signedShiftRight(ratio.mul(new BN4("97234110755111693312479820773")), 96, 256); } if ((tick & 8192) !== 0) { ratio = signedShiftRight(ratio.mul(new BN4("119332217159966728226237229890")), 96, 256); } if ((tick & 16384) !== 0) { ratio = signedShiftRight(ratio.mul(new BN4("179736315981702064433883588727")), 96, 256); } if ((tick & 32768) !== 0) { ratio = signedShiftRight(ratio.mul(new BN4("407748233172238350107850275304")), 96, 256); } if ((tick & 65536) !== 0) { ratio = signedShiftRight(ratio.mul(new BN4("2098478828474011932436660412517")), 96, 256); } if ((tick & 131072) !== 0) { ratio = signedShiftRight(ratio.mul(new BN4("55581415166113811149459800483533")), 96, 256); } if ((tick & 262144) !== 0) { ratio = signedShiftRight(ratio.mul(new BN4("38992368544603139932233054999993551")), 96, 256); } return signedShiftRight(ratio, 32, 256); } __name(tickIndexToSqrtPricePositive, "tickIndexToSqrtPricePositive"); function tickIndexToSqrtPriceNegative(tickIndex) { const tick = Math.abs(tickIndex); let ratio; if ((tick & 1) !== 0) { ratio = new BN4("18445821805675392311"); } else { ratio = new BN4("18446744073709551616"); } if ((tick & 2) !== 0) { ratio = signedShiftRight(ratio.mul(new BN4("18444899583751176498")), 64, 256); } if ((tick & 4) !== 0) { ratio = signedShiftRight(ratio.mul(new BN4("18443055278223354162")), 64, 256); } if ((tick & 8) !== 0) { ratio = signedShiftRight(ratio.mul(new BN4("18439367220385604838")), 64, 256); } if ((tick & 16) !== 0) { ratio = signedShiftRight(ratio.mul(new BN4("18431993317065449817")), 64, 256); } if ((tick & 32) !== 0) { ratio = signedShiftRight(ratio.mul(new BN4("18417254355718160513")), 64, 256); } if ((tick & 64) !== 0) { ratio = signedShiftRight(ratio.mul(new BN4("18387811781193591352")), 64, 256); } if ((tick & 128) !== 0) { ratio = signedShiftRight(ratio.mul(new BN4("18329067761203520168")), 64, 256); } if ((tick & 256) !== 0) { ratio = signedShiftRight(ratio.mul(new BN4("18212142134806087854")), 64, 256); } if ((tick & 512) !== 0) { ratio = signedShiftRight(ratio.mul(new BN4("17980523815641551639")), 64, 256); } if ((tick & 1024) !== 0) { ratio = signedShiftRight(ratio.mul(new BN4("17526086738831147013")), 64, 256); } if ((tick & 2048) !== 0) { ratio = signedShiftRight(ratio.mul(new BN4("16651378430235024244")), 64, 256); } if ((tick & 4096) !== 0) { ratio = signedShiftRight(ratio.mul(new BN4("15030750278693429944")), 64, 256); } if ((tick & 8192) !== 0) { ratio = signedShiftRight(ratio.mul(new BN4("12247334978882834399")), 64, 256); } if ((tick & 16384) !== 0) { ratio = signedShiftRight(ratio.mul(new BN4("8131365268884726200")), 64, 256); } if ((tick & 32768) !== 0) { ratio = signedShiftRight(ratio.mul(new BN4("3584323654723342297")), 64, 256); } if ((tick & 65536) !== 0) { ratio = signedShiftRight(ratio.mul(new BN4("696457651847595233")), 64, 256); } if ((tick & 131072) !== 0) { ratio = signedShiftRight(ratio.mul(new BN4("26294789957452057")), 64, 256); } if ((tick & 262144) !== 0) { ratio = signedShiftRight(ratio.mul(new BN4("37481735321082")), 64, 256); } return ratio; } __name(tickIndexToSqrtPriceNegative, "tickIndexToSqrtPriceNegative"); var _TickMath = class _TickMath { static priceToSqrtPriceX64(price, decimalsA, decimalsB) { return MathUtil.toX64(price.mul(decimal_default.pow(10, decimalsB - decimalsA)).sqrt()); } static sqrtPriceX64ToPrice(sqrtPriceX64, decimalsA, decimalsB) { return MathUtil.fromX64(sqrtPriceX64).pow(2).mul(decimal_default.pow(10, decimalsA - decimalsB)); } static tickIndexToSqrtPriceX64(tickIndex) { if (tickIndex > 0) { return new BN4(tickIndexToSqrtPricePositive(tickIndex)); } return new BN4(tickIndexToSqrtPriceNegative(tickIndex)); } static sqrtPriceX64ToTickIndex(sqrtPriceX64) { if (sqrtPriceX64.gt(new BN4(MAX_SQRT_PRICE)) || sqrtPriceX64.lt(new BN4(MIN_SQRT_PRICE))) { throw new ClmmpoolsError("Provided sqrtPrice is not within the supported sqrtPrice range.", "InvalidSqrtPrice" /* InvalidSqrtPrice */); } const msb = sqrtPriceX64.bitLength() - 1; const adjustedMsb = new BN4(msb - 64); const log2pIntegerX32 = signedShiftLeft(adjustedMsb, 32, 128); let bit = new BN4("8000000000000000", "hex"); let precision = 0; let log2pFractionX64 = new BN4(0); let r = msb >= 64 ? sqrtPriceX64.shrn(msb - 63) : sqrtPriceX64.shln(63 - msb); while (bit.gt(new BN4(0)) && precision < BIT_PRECISION) { r = r.mul(r); const rMoreThanTwo = r.shrn(127); r = r.shrn(63 + rMoreThanTwo.toNumber()); log2pFractionX64 = log2pFractionX64.add(bit.mul(rMoreThanTwo)); bit = bit.shrn(1); precision += 1; } const log2pFractionX32 = log2pFractionX64.shrn(32); const log2pX32 = log2pIntegerX32.add(log2pFractionX32); const logbpX64 = log2pX32.mul(new BN4(LOG_B_2_X32)); const tickLow = signedShiftRight(logbpX64.sub(new BN4(LOG_B_P_ERR_MARGIN_LOWER_X64)), 64, 128).toNumber(); const tickHigh = signedShiftRight(logbpX64.add(new BN4(LOG_B_P_ERR_MARGIN_UPPER_X64)), 64, 128).toNumber(); if (tickLow === tickHigh) { return tickLow; } const derivedTickHighSqrtPriceX64 = _TickMath.tickIndexToSqrtPriceX64(tickHigh); if (derivedTickHighSqrtPriceX64.lte(sqrtPriceX64)) { return tickHigh; } return tickLow; } static tickIndexToPrice(tickIndex, decimalsA, decimalsB) { return _TickMath.sqrtPriceX64ToPrice(_TickMath.tickIndexToSqrtPriceX64(tickIndex), decimalsA, decimalsB); } static priceToTickIndex(price, decimalsA, decimalsB) { return _TickMath.sqrtPriceX64ToTickIndex(_TickMath.priceToSqrtPriceX64(price, decimalsA, decimalsB)); } static priceToInitializableTickIndex(price, decimalsA, decimalsB, tickSpacing) { return _TickMath.getInitializableTickIndex(_TickMath.priceToTickIndex(price, decimalsA, decimalsB), tickSpacing); } static getInitializableTickIndex(tickIndex, tickSpacing) { return tickIndex - tickIndex % tickSpacing; } /** * * @param tickIndex * @param tickSpacing * @returns */ static getNextInitializableTickIndex(tickIndex, tickSpacing) { return _TickMath.getInitializableTickIndex(tickIndex, tickSpacing) + tickSpacing; } static getPrevInitializableTickIndex(tickIndex, tickSpacing) { return _TickMath.getInitializableTickIndex(tickIndex, tickSpacing) - tickSpacing; } }; __name(_TickMath, "TickMath"); var TickMath = _TickMath; function getTickDataFromUrlData(ticks) { const tickdatas = []; for (const tick of ticks) { const td = { objectId: tick.objectId, index: Number(asIntN(BigInt(tick.index)).toString()), sqrtPrice: tick.sqrtPrice, liquidityNet: new BN4(BigInt.asIntN(128, BigInt(BigInt(tick.liquidityNet.toString()))).toString()), liquidityGross: tick.liquidityGross, feeGrowthOutsideA: tick.feeGrowthOutsideA, feeGrowthOutsideB: tick.feeGrowthOutsideB, rewardersGrowthOutside: [ new BN4(tick.rewardersGrowthOutside[0]), new BN4(tick.rewardersGrowthOutside[1]), new BN4(tick.rewardersGrowthOutside[2]) ] }; tickdatas.push(td); } return tickdatas; } __name(getTickDataFromUrlData, "getTickDataFromUrlData"); function tickScore(tickIndex) { return d(tickIndex).add(d(TICK_BOUND)); } __name(tickScore, "tickScore"); // src/math/apr.ts var D365 = new BN4(365); var H24 = new BN4(24); var S3600 = new BN4(3600); var B05 = new BN4(0.5); function estPoolAPR(preBlockReward, rewardPrice, totalTradingFee, totalLiquidityValue) { const annualRate = D365.mul(H24).mul(S3600).mul(B05); const APR = annualRate.mul(preBlockReward.mul(rewardPrice).add(totalTradingFee).div(totalLiquidityValue)); return APR; } __name(estPoolAPR, "estPoolAPR"); function calculatePoolValidTVL(amountA, amountB, decimalsA, decimalsB, coinAPrice, coinBPrice) { const poolValidAmountA = new Decimal2(amountA.toString()).div(new Decimal2(10 ** decimalsA)); const poolValidAmountB = new Decimal2(amountB.toString()).div(new Decimal2(10 ** decimalsB)); const TVL = poolValidAmountA.mul(coinAPrice).add(poolValidAmountB.mul(coinBPrice)); return TVL; } __name(calculatePoolValidTVL, "calculatePoolValidTVL"); function estPositionAPRWithDeltaMethod(currentTickIndex, lowerTickIndex, upperTickIndex, currentSqrtPriceX64, poolLiquidity, decimalsA, decimalsB, decimalsRewarder0, decimalsRewarder1, decimalsRewarder2, feeRate, amountAStr, amountBStr, poolAmountA, poolAmountB, swapVolumeStr, poolRewarders0Str, poolRewarders1Str, poolRewarders2Str, coinAPriceStr, coinBPriceStr, rewarder0PriceStr, rewarder1PriceStr, rewarder2PriceStr) { const amountA = new Decimal2(amountAStr); const amountB = new Decimal2(amountBStr); const swapVolume = new Decimal2(swapVolumeStr); const poolRewarders0 = new Decimal2(poolRewarders0Str); const poolRewarders1 = new Decimal2(poolRewarders1Str); const poolRewarders2 = new Decimal2(poolRewarders2Str); const coinAPrice = new Decimal2(coinAPriceStr); const coinBPrice = new Decimal2(coinBPriceStr); const rewarder0Price = new Decimal2(rewarder0PriceStr); const rewarder1Price = new Decimal2(rewarder1PriceStr); const rewarder2Price = new Decimal2(rewarder2PriceStr); const lowerSqrtPriceX64 = TickMath.tickIndexToSqrtPriceX64(lowerTickIndex); const upperSqrtPriceX64 = TickMath.tickIndexToSqrtPriceX64(upperTickIndex); const lowerSqrtPriceD = MathUtil.toX64_Decimal(MathUtil.fromX64(lowerSqrtPriceX64)).round(); const upperSqrtPriceD = MathUtil.toX64_Decimal(MathUtil.fromX64(upperSqrtPriceX64)).round(); const currentSqrtPriceD = MathUtil.toX64_Decimal(MathUtil.fromX64(currentSqrtPriceX64)).round(); let deltaLiquidity; const liquidityAmount0 = amountA.mul(new Decimal2(10 ** decimalsA)).mul(upperSqrtPriceD.mul(lowerSqrtPriceD)).div(upperSqrtPriceD.sub(lowerSqrtPriceD)).round(); const liquidityAmount1 = amountB.mul(new Decimal2(10 ** decimalsB)).div(upperSqrtPriceD.sub(lowerSqrtPriceD)).round(); if (currentTickIndex < lowerTickIndex) { deltaLiquidity = liquidityAmount0; } else if (currentTickIndex > upperTickIndex) { deltaLiquidity = liquidityAmount1; } else { deltaLiquidity = Decimal2.min(liquidityAmount0, liquidityAmount1); } const deltaY = deltaLiquidity.mul(currentSqrtPriceD.sub(lowerSqrtPriceD)); const deltaX = deltaLiquidity.mul(upperSqrtPriceD.sub(currentSqrtPriceD)).div(currentSqrtPriceD.mul(upperSqrtPriceD)); const posValidTVL = deltaX.div(new Decimal2(10 ** decimalsA)).mul(coinAPrice).add(deltaY.div(new Decimal2(10 ** decimalsB).mul(coinBPrice))); const poolValidTVL = calculatePoolValidTVL(poolAmountA, poolAmountB, decimalsA, decimalsB, coinAPrice, coinBPrice); const posValidRate = posValidTVL.div(poolValidTVL); const feeAPR = deltaLiquidity.eq(new Decimal2(0)) ? new Decimal2(0) : new Decimal2(feeRate / 1e4).mul(swapVolume).mul(new Decimal2(deltaLiquidity.toString()).div(new Decimal2(poolLiquidity.toString()).add(new Decimal2(deltaLiquidity.toString())))).div(posValidTVL); const aprCoe = posValidRate.eq(new Decimal2(0)) ? new Decimal2(0) : posValidRate.mul(new Decimal2(36500 / 7)).div(posValidTVL); const posRewarder0APR = poolRewarders0.div(new Decimal2(10 ** decimalsRewarder0)).mul(rewarder0Price).mul(aprCoe); const posRewarder1APR = poolRewarders1.div(new Decimal2(10 ** decimalsRewarder1)).mul(rewarder1Price).mul(aprCoe); const posRewarder2APR = poolRewarders2.div(new Decimal2(10 ** decimalsRewarder2)).mul(rewarder2Price).mul(aprCoe); return { feeAPR, posRewarder0APR, posRewarder1APR, posRewarder2APR }; } __name(estPositionAPRWithDeltaMethod, "estPositionAPRWithDeltaMethod"); function estPositionAPRWithMultiMethod(lowerUserPrice, upperUserPrice, lowerHistPrice, upperHistPrice) { const retroLower = Math.max(lowerUserPrice, lowerHistPrice); const retroUpper = Math.min(upperUserPrice, upperHistPrice); const retroRange = retroUpper - retroLower; const userRange = upperUserPrice - lowerUserPrice; const histRange = upperHistPrice - lowerHistPrice; const userRangeD = new Decimal2(userRange.toString()); const histRangeD = new Decimal2(histRange.toString()); const retroRangeD = new Decimal2(retroRange.toString()); let m = new Decimal2("0"); if (retroRange < 0) { m = new Decimal2("0"); } else if (userRange === retroRange) { m = histRangeD.div(retroRangeD); } else if (histRange === retroRange) { m = retroRangeD.div(userRangeD); } else { m = retroRangeD.mul(retroRangeD).div(histRangeD).div(userRangeD); } return m; } __name(estPositionAPRWithMultiMethod, "estPositionAPRWithMultiMethod"); var _SwapUtils = class _SwapUtils { /** * Get the default sqrt price limit for a swap. * * @param a2b - true if the swap is A to B, false if the swap is B to A. * @returns The default sqrt price limit for the swap. */ static getDefaultSqrtPriceLimit(a2b) { return new BN4(a2b ? MIN_SQRT_PRICE : MAX_SQRT_PRICE); } /** * Get the default values for the otherAmountThreshold in a swap. * * @param amountSpecifiedIsInput - The direction of a swap * @returns The default values for the otherAmountThreshold parameter in a swap. */ static getDefaultOtherAmountThreshold(amountSpecifiedIsInput) { return amountSpecifiedIsInput ? ZERO : U64_MAX; } }; __name(_SwapUtils, "SwapUtils"); var SwapUtils = _SwapUtils; function getLowerSqrtPriceFromCoinA(amount, liquidity, sqrtPriceX64) { const numerator = liquidity.mul(sqrtPriceX64).shln(64); const denominator = liquidity.shln(64).add(amount.mul(sqrtPriceX64)); return MathUtil.divRoundUp(numerator, denominator); } __name(getLowerSqrtPriceFromCoinA, "getLowerSqrtPriceFromCoinA"); function getUpperSqrtPriceFromCoinA(amount, liquidity, sqrtPriceX64) { const numerator = liquidity.mul(sqrtPriceX64).shln(64); const denominator = liquidity.shln(64).sub(amount.mul(sqrtPriceX64)); return MathUtil.divRoundUp(numerator, denominator); } __name(getUpperSqrtPriceFromCoinA, "getUpperSqrtPriceFromCoinA"); function getLowerSqrtPriceFromCoinB(amount, liquidity, sqrtPriceX64) { return sqrtPriceX64.sub(MathUtil.divRoundUp(amount.shln(64), liquidity)); } __name(getLowerSqrtPriceFromCoinB, "getLowerSqrtPriceFromCoinB"); function getUpperSqrtPriceFromCoinB(amount, liquidity, sqrtPriceX64) { return sqrtPriceX64.add(amount.shln(64).div(liquidity)); } __name(getUpperSqrtPriceFromCoinB, "getUpperSqrtPriceFromCoinB"); // src/math/clmm.ts function toCoinAmount(a, b) { return { coinA: new BN4(a.toString()), coinB: new BN4(b.toString()) }; } __name(toCoinAmount, "toCoinAmount"); function getDeltaA(sqrtPrice0, sqrtPrice1, liquidity, roundUp) { const sqrtPriceDiff = sqrtPrice0.gt(sqrtPrice1) ? sqrtPrice0.sub(sqrtPrice1) : sqrtPrice1.sub(sqrtPrice0); const numberator = liquidity.mul(sqrtPriceDiff).shln(64); const denomminator = sqrtPrice0.mul(sqrtPrice1); const quotient = numberator.div(denomminator); const remainder = numberator.mod(denomminator); const result = roundUp && !remainder.eq(ZERO) ? quotient.add(new BN4(1)) : quotient; return result; } __name(getDeltaA, "getDeltaA"); function getDeltaB(sqrtPrice0, sqrtPrice1, liquidity, roundUp) { const sqrtPriceDiff = sqrtPrice0.gt(sqrtPrice1) ? sqrtPrice0.sub(sqrtPrice1) : sqrtPrice1.sub(sqrtPrice0); if (liquidity.eq(ZERO) || sqrtPriceDiff.eq(ZERO)) { return ZERO; } const p = liquidity.mul(sqrtPriceDiff); const shoudRoundUp = roundUp && p.and(U64_MAX).gt(ZERO); const result = shoudRoundUp ? p.shrn(64).add(ONE) : p.shrn(64); if (MathUtil.isOverflow(result, 64)) { throw new ClmmpoolsError("Result large than u64 max", "IntegerDowncastOverflow" /* IntegerDowncastOverflow */); } return result; } __name(getDeltaB, "getDeltaB"); function getNextSqrtPriceAUp(sqrtPrice, liquidity, amount, byAmountIn) { if (amount.eq(ZERO)) { return sqrtPrice; } const numberator = MathUtil.checkMulShiftLeft(sqrtPrice, liquidity, 64, 256); const liquidityShl64 = liquidity.shln(64); const product = MathUtil.checkMul(sqrtPrice, amount, 256); if (!byAmountIn && liquidityShl64.lte(product)) { throw new ClmmpoolsError("getNextSqrtPriceAUp - Unable to divide liquidityShl64 by product", "DivideByZero" /* DivideByZero */); } const nextSqrtPrice = byAmountIn ? MathUtil.checkDivRoundUpIf(numberator, liquidityShl64.add(product), true) : MathUtil.checkDivRoundUpIf(numberator, liquidityShl64.sub(product), true); if (nextSqrtPrice.lt(new BN4(MIN_SQRT_PRICE))) { throw new ClmmpoolsError("getNextSqrtPriceAUp - Next sqrt price less than min sqrt price", "CoinAmountMinSubceeded " /* CoinAmountMinSubceeded */); } if (nextSqrtPrice.gt(new BN4(MAX_SQRT_PRICE))) { throw new ClmmpoolsError("getNextSqrtPriceAUp - Next sqrt price greater than max sqrt price", "CoinAmountMaxExceeded" /* CoinAmountMaxExceeded */); } return nextSqrtPrice; } __name(getNextSqrtPriceAUp, "getNextSqrtPriceAUp"); function getNextSqrtPriceBDown(sqrtPrice, liquidity, amount, byAmountIn) { const deltaSqrtPrice = MathUtil.checkDivRoundUpIf(amount.shln(64), liquidity, !byAmountIn); const nextSqrtPrice = byAmountIn ? sqrtPrice.add(deltaSqrtPrice) : sqrtPrice.sub(deltaSqrtPrice); if (nextSqrtPrice.lt(new BN4(MIN_SQRT_PRICE)) || nextSqrtPrice.gt(new BN4(MAX_SQRT_PRICE))) { throw new ClmmpoolsError("getNextSqrtPriceAUp - Next sqrt price out of bounds", "SqrtPriceOutOfBounds" /* SqrtPriceOutOfBounds */); } return nextSqrtPrice; } __name(getNextSqrtPriceBDown, "getNextSqrtPriceBDown"); function getNextSqrtPriceFromInput(sqrtPrice, liquidity, amount, aToB) { return aToB ? getNextSqrtPriceAUp(sqrtPrice, liquidity, amount, true) : getNextSqrtPriceBDown(sqrtPrice, liquidity, amount, true); } __name(getNextSqrtPriceFromInput, "getNextSqrtPriceFromInput"); function getNextSqrtPriceFromOutput(sqrtPrice, liquidity, amount, a2b) { return a2b ? getNextSqrtPriceBDown(sqrtPrice, liquidity, amount, false) : getNextSqrtPriceAUp(sqrtPrice, liquidity, amount, false); } __name(getNextSqrtPriceFromOutput, "getNextSqrtPriceFromOutput"); function getDeltaUpFromInput(currentSqrtPrice, targetSqrtPrice, liquidity, a2b) { const sqrtPriceDiff = currentSqrtPrice.gt(targetSqrtPrice) ? currentSqrtPrice.sub(targetSqrtPrice) : targetSqrtPrice.sub(currentSqrtPrice); if (liquidity.lte(ZERO) || sqrtPriceDiff.eq(ZERO)) { return ZERO; } let result; if (a2b) { const numberator = new BN4(liquidity).mul(new BN4(sqrtPriceDiff)).shln(64); const denomminator = targetSqrtPrice.mul(currentSqrtPrice); const quotient = numberator.div(denomminator); const remainder = numberator.mod(denomminator); result = !remainder.eq(ZERO) ? quotient.add(ONE) : quotient; } else { const product = new BN4(liquidity).mul(new BN4(sqrtPriceDiff)); const shoudRoundUp = product.and(U64_MAX).gt(ZERO); result = shoudRoundUp ? product.shrn(64).add(ONE) : product.shrn(64); } return result; } __name(getDeltaUpFromInput, "getDeltaUpFromInput"); function getDeltaDownFromOutput(currentSqrtPrice, targetSqrtPrice, liquidity, a2b) { const sqrtPriceDiff = currentSqrtPrice.gt(targetSqrtPrice) ? currentSqrtPrice.sub(targetSqrtPrice) : targetSqrtPrice.sub(currentSqrtPrice); if (liquidity.lte(ZERO) || sqrtPriceDiff.eq(ZERO)) { return ZERO; } let result; if (a2b) { const product = liquidity.mul(sqrtPriceDiff); result = product.shrn(64); } else { const numberator = liquidity.mul(sqrtPriceDiff).shln(64); const denomminator = targetSqrtPrice.mul(currentSqrtPrice); result = numberator.div(denomminator); } return result; } __name(getDeltaDownFromOutput, "getDeltaDownFromOutput"); function computeSwapStep(currentSqrtPrice, targetSqrtPrice, liquidity, amount, feeRate, byAmountIn) { if (liquidity === ZERO) { return { amountIn: ZERO, amountOut: ZERO, nextSqrtPrice: targetSqrtPrice, feeAmount: ZERO }; } const a2b = currentSqrtPrice.gte(targetSqrtPrice); let amountIn; let amountOut; let nextSqrtPrice; let feeAmount; if (byAmountIn) { const amountRemain = MathUtil.checkMulDivFloor( amount, MathUtil.checkUnsignedSub(FEE_RATE_DENOMINATOR, feeRate), FEE_RATE_DENOMINATOR, 64 ); const maxAmountIn = getDeltaUpFromInput(currentSqrtPrice, targetSqrtPrice, liquidity, a2b); if (maxAmountIn.gt(amountRemain)) { amountIn = amountRemain; feeAmount = MathUtil.checkUnsignedSub(amount, amountRemain); nextSqrtPrice = getNextSqrtPriceFromInput(currentSqrtPrice, liquidity, amountRemain, a2b); } else { amountIn = maxAmountIn; feeAmount = MathUtil.checkMulDivCeil(amountIn, feeRate, FEE_RATE_DENOMINATOR.sub(feeRate), 64); nextSqrtPrice = targetSqrtPrice; } amountOut = getDeltaDownFromOutput(currentSqrtPrice, nextSqrtPrice, liquidity, a2b); } else { const maxAmountOut = getDeltaDownFromOutput(currentSqrtPrice, targetSqrtPrice, liquidity, a2b); if (maxAmountOut.gt(amount)) { amountOut = amount; nextSqrtPrice = getNextSqrtPriceFromOutput(currentSqrtPrice, liquidity, amount, a2b); } else { amountOut = maxAmountOut; nextSqrtPrice = targetSqrtPrice; } amountIn = getDeltaUpFromInput(currentSqrtPrice, nextSqrtPrice, liquidity, a2b); feeAmount = MathUtil.checkMulDivCeil(amountIn, feeRate, FEE_RATE_DENOMINATOR.sub(feeRate), 64); } return { amountIn, amountOut, nextSqrtPrice, feeAmount }; } __name(computeSwapStep, "computeSwapStep"); function computeSwap(aToB, byAmountIn, amount, poolData, swapTicks) { let remainerAmount = amount; let currentLiquidity = poolData.liquidity; let { currentSqrtPrice } = poolData; const swapResult = { amountIn: ZERO, amountOut: ZERO, feeAmount: ZERO, refAmount: ZERO, nextSqrtPrice: ZERO, crossTickNum: 0 }; let targetSqrtPrice; let signedLiquidityChange; const sqrtPriceLimit = SwapUtils.getDefaultSqrtPriceLimit(aToB); for (const tick of swapTicks) { if (aToB && poolData.currentTickIndex < tick.index) { continue; } if (!aToB && poolData.currentTickIndex >= tick.index) { continue; } if (tick === null) { continue; } if (aToB && sqrtPriceLimit.gt(tick.sqrtPrice) || !aToB && sqrtPriceLimit.lt(tick.sqrtPrice)) { targetSqrtPrice = sqrtPriceLimit; } else { targetSqrtPrice = tick.sqrtPrice; } const stepResult = computeSwapStep(currentSqrtPrice, targetSqrtPrice, currentLiquidity, remainerAmount, poolData.feeRate, byAmountIn); if (!stepResult.amountIn.eq(ZERO)) { remainerAmount = byAmountIn ? remainerAmount.sub(stepResult.amountIn.add(stepResult.feeAmount)) : remainerAmount.sub(stepResult.amountOut); } swapResult.amountIn = swapResult.amountIn.add(stepResult.amountIn); swapResult.amountOut = swapResult.amountOut.add(stepResult.amountOut); swapResult.feeAmount = swapResult.feeAmount.add(stepResult.feeAmount); if (stepResult.nextSqrtPrice.eq(tick.sqrtPrice)) { signedLiquidityChange = tick.liquidityNet.mul(new BN4(-1)); if (aToB) { if (MathUtil.is_neg(signedLiquidityChange)) { currentLiquidity = currentLiquidity.add(new BN4(asUintN(BigInt(signedLiquidityChange.toString()), 128))); } else { currentLiquidity = currentLiquidity.add(signedLiquidityChange); } } else if (MathUtil.is_neg(signedLiquidityChange)) { currentLiquidity = currentLiquidity.sub(new BN4(asUintN(BigInt(signedLiquidityChange.toString()), 128))); } else { currentLiquidity = currentLiquidity.sub(signedLiquidityChange); } currentSqrtPrice = tick.sqrtPrice; } else { currentSqrtPrice = stepResult.nextSqrtPrice; } swapResult.crossTickNum += 1; if (remainerAmount.eq(ZERO)) { break; } } swapResult.amountIn = swapResult.amountIn.add(swapResult.feeAmount); swapResult.nextSqrtPrice = currentSqrtPrice; return swapResult; } __name(computeSwap, "computeSwap"); function estimateLiquidityForCoinA(sqrtPriceX, sqrtPriceY, coinAmount) { const lowerSqrtPriceX64 = BN4.min(sqrtPriceX, sqrtPriceY); const upperSqrtPriceX64 = BN4.max(sqrtPriceX, sqrtPriceY); const num = MathUtil.fromX64_BN(coinAmount.mul(upperSqrtPriceX64).mul(lowerSqrtPriceX64)); const dem = upperSqrtPriceX64.sub(lowerSqrtPriceX64); return !num.isZero() && !dem.isZero() ? num.div(dem) : new BN4(0); } __name(estimateLiquidityForCoinA, "estimateLiquidityForCoinA"); function estimateLiquidityForCoinB(sqrtPriceX, sqrtPriceY, coinAmount) { const lowerSqrtPriceX64 = BN4.min(sqrtPriceX, sqrtPriceY); const upperSqrtPriceX64 = BN4.max(sqrtPriceX, sqrtPriceY); const delta = upperSqrtPriceX64.sub(lowerSqrtPriceX64); return !delta.isZero() ? coinAmount.shln(64).div(delta) : new BN4(0); } __name(estimateLiquidityForCoinB, "estimateLiquidityForCoinB"); var _ClmmPoolUtil = class _ClmmPoolUtil { /** * Update fee rate. * @param clmm - clmmpool data * @param feeAmount - fee Amount * @param refRate - ref rate * @param protocolFeeRate - protocol fee rate * @param iscoinA - is token A * @returns percentage */ static updateFeeRate(clmm, feeAmount, refRate, protocolFeeRate, iscoinA) { const protocolFee = MathUtil.checkMulDivCeil(feeAmount, new BN4(protocolFeeRate), FEE_RATE_DENOMINATOR, 64); const refFee = refRate === 0 ? ZERO : MathUtil.checkMulDivFloor(feeAmount, new BN4(refRate), FEE_RATE_DENOMINATOR, 64); const poolFee = feeAmount.mul(protocolFee).mul(refFee); if (iscoinA) { clmm.feeProtocolCoinA = clmm.feeProtocolCoinA.add(protocolFee); } else { clmm.feeProtocolCoinB = clmm.feeProtocolCoinB.add(protocolFee); } if (poolFee.eq(ZERO) || clmm.liquidity.eq(ZERO)) { return { refFee, clmm }; } const growthFee = poolFee.shln(64).div(clmm.liquidity); if (iscoinA) { clmm.feeGrowthGlobalA = clmm.feeGrowthGlobalA.add(growthFee); } else { clmm.feeGrowthGlobalB = clmm.feeGrowthGlobalB.add(growthFee); } return { refFee, clmm }; } /** * Get token amount fron liquidity. * @param liquidity - liquidity * @param curSqrtPrice - Pool current sqrt price * @param lowerSqrtPrice - position lower sqrt price * @param upperSqrtPrice - position upper sqrt price * @param roundUp - is round up * @returns */ static getCoinAmountFromLiquidity(liquidity, curSqrtPrice, lowerSqrtPrice, upperSqrtPrice, roundUp) { const liq = new decimal_default(liquidity.toString()); const curSqrtPriceStr = new decimal_default(curSqrtPrice.toString()); const lowerPriceStr = new decimal_default(lowerSqrtPrice.toString()); const upperPriceStr = new decimal_default(upperSqrtPrice.toString()); let coinA; let coinB; if (curSqrtPrice.lt(lowerSqrtPrice)) { coinA = MathUtil.toX64_Decimal(liq).mul(upperPriceStr.sub(lowerPriceStr)).div(lowerPriceStr.mul(upperPriceStr)); coinB = new decimal_default(0); } else if (curSqrtPrice.lt(upperSqrtPrice)) { coinA = MathUtil.toX64_Decimal(liq).mul(upperPriceStr.sub(curSqrtPriceStr)).div(curSqrtPriceStr.mul(upperPriceStr)); coinB = MathUtil.fromX64_Decimal(liq.mul(curSqrtPriceStr.sub(lowerPriceStr))); } else { coinA = new decimal_default(0); coinB = MathUtil.fromX64_Decimal(liq.mul(upperPriceStr.sub(lowerPriceStr))); } if (roundUp) { return { coinA: new BN4(coinA.ceil().toString()), coinB: new BN4(coinB.ceil().toString()) }; } return { coinA: new BN4(coinA.floor().toString()), coinB: new BN4(coinB.floor().toString()) }; } /** * Estimate liquidity and token amount from one amounts * @param lowerTick - lower tick * @param upperTick - upper tick * @param coinAmount - token amount * @param iscoinA - is token A * @param roundUp - is round up * @param isIncrease - is increase * @param slippage - slippage percentage * @param curSqrtPrice - current sqrt price. * @return IncreaseLiquidityInput */ static estLiquidityAndcoinAmountFromOneAmounts(lowerTick, upperTick, coinAmount, iscoinA, roundUp, slippage, curSqrtPrice) { const currentTick = TickMath.sqrtPriceX64ToTickIndex(curSqrtPrice); const lowerSqrtPrice = TickMath.tickIndexToSqrtPriceX64(lowerTick); const upperSqrtPrice = TickMath.tickIndexToSqrtPriceX64(upperTick); let liquidity; if (currentTick < lowerTick) { if (!iscoinA) { throw new ClmmpoolsError("lower tick cannot calculate liquidity by coinB", "NotSupportedThisCoin" /* NotSupportedThisCoin */); } liquidity = estimateLiquidityForCoinA(lowerSqrtPrice, upperSqrtPrice, coinAmount); } else if (currentTick > upperTick) { if (iscoinA) { throw new ClmmpoolsError("upper tick cannot calculate liquidity by coinA", "NotSupportedThisCoin" /* NotSupportedThisCoin */); } liquidity = estimateLiquidityForCoinB(upperSqrtPrice, lowerSqrtPrice, coinAmount); } else if (iscoinA) { liquidity = estimateLiquidityForCoinA(curSqrtPrice, upperSqrtPrice, coinAmount); } else { liquidity = estimateLiquidityForCoinB(curSqrtPrice, lowerSqrtPrice, coinAmount); } const coinAmounts = _ClmmPoolUtil.getCoinAmountFromLiquidity(liquidity, curSqrtPrice, lowerSqrtPrice, upperSqrtPrice, roundUp); const tokenLimitA = roundUp ? d(coinAmounts.coinA.toString()).mul(1 + slippage).toString() : d(coinAmounts.coinA.toString()).mul(1 - slippage).toString(); const tokenLimitB = roundUp ? d(coinAmounts.coinB.toString()).mul(1 + slippage).toString() : d(coinAmounts.coinB.toString()).mul(1 - slippage).toString(); return { coinAmountA: coinAmounts.coinA, coinAmountB: coinAmounts.coinB, tokenMaxA: roundUp ? new BN4(decimal_default.ceil(tokenLimitA).toString()) : new BN4(decimal_default.floor(tokenLimitA).toString()), tokenMaxB: roundUp ? new BN4(decimal_default.ceil(tokenLimitB).toString()) : new BN4(decimal_default.floor(tokenLimitB).toString()), liquidityAmount: liquidity, fix_amount_a: iscoinA }; } /** * Estimate liquidity from token amounts * @param curSqrtPrice - current sqrt price. * @param lowerTick - lower tick * @param upperTick - upper tick * @param tokenAmount - token amount * @return */ static estimateLiquidityFromcoinAmounts(curSqrtPrice, lowerTick, upperTick, tokenAmount) { if (lowerTick > upperTick) { throw new ClmmpoolsError("lower tick cannot be greater than lower tick", "InvalidTwoTickIndex" /* InvalidTwoTickIndex */); } const currTick = TickMath.sqrtPriceX64ToTickIndex(curSqrtPrice); const lowerSqrtPrice = TickMath.tickIndexToSqrtPriceX64(lowerTick); const upperSqrtPrice = TickMath.tickIndexToSqrtPriceX64(upperTick); if (currTick < lowerTick) { return estimateLiquidityForCoinA(lowerSqrtPrice, upperSqrtPrice, tokenAmount.coinA); } if (currTick >= upperTick) { return estimateLiquidityForCoinB(upperSqrtPrice, lowerSqrtPrice, tokenAmount.coinB); } const estimateLiquidityAmountA = estimateLiquidityForCoinA(curSqrtPrice, upperSqrtPrice, tokenAmount.coinA); const estimateLiquidityAmountB = estimateLiquidityForCoinB(curSqrtPrice, lowerSqrtPrice, tokenAmount.coinB); return BN4.min(estimateLiquidityAmountA, estimateLiquidityAmountB); } /** * Estimate coin amounts from total amount * @param lowerTick * @param upperTick * @param decimalsA * @param decimalsB * @param curSqrtPrice * @param totalAmount * @param tokenPriceA * @param tokenPriceB * @returns */ static estCoinAmountsFromTotalAmount(lowerTick, upperTick, curSqrtPrice, totalAmount, tokenPriceA, tokenPriceB) { const { ratioA, ratioB } = _ClmmPoolUtil.calculateDepositRatioFixTokenA(lowerTick, upperTick, curSqrtPrice); const amountA = d(totalAmount).mul(ratioA).div(tokenPriceA); const amountB = d(totalAmount).mul(ratioB).div(tokenPriceB); return { amountA, amountB }; } static calculateDepositRatioFixTokenA(lowerTick, upperTick, curSqrtPrice) { const coinAmountA = new BN4(1e8); const { coinAmountB } = _ClmmPoolUtil.estLiquidityAndcoinAmountFromOneAmounts( lowerTick, upperTick, coinAmountA, true, true, 0, curSqrtPrice ); const currPrice = TickMath.sqrtPriceX64ToPrice(curSqrtPrice, 0, 0); const transformAmountB = d(coinAmountA.toString()).mul(currPrice); const totalAmount = transformAmountB.add(coinAmountB.toString()); const ratioA = transformAmountB.div(totalAmount); const ratioB = d(coinAmountB.toString()).div(totalAmount); return { ratioA, ratioB }; } }; __name(_ClmmPoolUtil, "ClmmPoolUtil"); var ClmmPoolUtil = _ClmmPoolUtil; // src/utils/hex.ts var HEX_REGEXP = /^[-+]?[0-9A-Fa-f]+\.?[0-9A-Fa-f]*?$/; function addHexPrefix(hex) { return !hex.startsWith("0x") ? `0x${hex}` : hex; } __name(addHexPrefix, "addHexPrefix"); function removeHexPrefix(hex) { return hex.startsWith("0x") ? `${hex.slice(2)}` : hex; } __name(removeHexPrefix, "removeHexPrefix"); function shortString(str, start = 4, end = 4) { const slen = Math.max(start, 1); const elen = Math.max(end, 1); return `${str.slice(0, slen + 2)} ... ${str.slice(-elen)}`; } __name(shortString, "shortString"); function shortAddress(address, start = 4, end = 4) { return shortString(addHexPrefix(address), start, end); } __name(shortAddress, "shortAddress"); function checkAddress(address, options = { leadingZero: true }) { if (typeof address !== "string") { return false; } let str = address; if (options.leadingZero) { if (!address.startsWith("0x")) { return false; } str = str.substring(2); } return HEX_REGEXP.test(str); } __name(checkAddress, "checkAddress"); function toBuffer(v) { if (!Buffer.isBuffer(v)) { if (Array.isArray(v)) { v = Buffer.from(v); } else if (typeof v === "string") { if (exports.isHexString(v)) { v = Buffer.from(exports.padToEven(exports.stripHexPrefix(v)), "hex"); } else { v = Buffer.from(v); } } else if (typeof v === "number") { v = exports.intToBuffer(v); } else if (v === null || v === void 0) { v = Buffer.allocUnsafe(0); } else if (v.toArray) { v = Buffer.from(v.toArray()); } else { throw new ClmmpoolsError(`Invalid type`, "InvalidType" /* InvalidType */); } } return v; } __name(toBuffer, "toBuffer"); function bufferToHex(buffer) { return addHexPrefix(toBuffer(buffer).toString("hex")); } __name(bufferToHex, "bufferToHex"); function hexToNumber(binaryData) { const buffer = new ArrayBuffer(4); const view = new DataView(buffer); for (let i = 0; i < binaryData.length; i++) { view.setUint8(i, binaryData.charCodeAt(i)); } const number = view.getUint32(0, true); return number; } __name(hexToNumber, "hexToNumber"); function utf8to16(str) { let out; let i; let c; let char2; let char3; out = ""; const len = str.length; i = 0; while (i < len) { c = str.charCodeAt(i++); switch (c >> 4) { case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: out += str.charAt(i - 1); break; case 12: case 13: char2 = str.charCodeAt(i++); out += String.fromCharCode((c & 31) << 6 | char2 & 63); break; case 14: char2 = str.charCodeAt(i++); char3 = str.charCodeAt(i++); out += String.fromCharCode((c & 15) << 12 | (char2 & 63) << 6 | (char3 & 63) << 0); break; } } return out; } __name(utf8to16, "utf8to16"); function hexToString(str) { let val = ""; const newStr = removeHexPrefix(str); const len = newStr.length / 2; for (let i = 0; i < len; i++) { val += String.fromCharCode(parseInt(newStr.substr(i * 2, 2), 16)); } return utf8to16(val); } __name(hexToString, "hexToString"); // src/utils/contracts.ts var EQUAL = 0; var LESS_THAN = 1; var GREATER_THAN = 2; function cmp(a, b) { if (a === b) { return EQUAL; } if (a < b) { return LESS_THAN; } return GREATER_THAN; } __name(cmp, "cmp"); function compare(symbolX, symbolY) { let i = 0; const len = symbolX.length <= symbolY.length ? symbolX.length : symbolY.length; const lenCmp = cmp(symbolX.length, symbolY.length); while (i < len) { const elemCmp = cmp(symbolX.charCodeAt(i), symbolY.charCodeAt(i)); i += 1; if (elemCmp !== 0) { return elemCmp; } } return lenCmp; } __name(compare, "compare"); function isSortedSymbols(symbolX, symbolY) { return compare(symbolX, symbolY) === LESS_THAN; } __name(isSortedSymbols, "isSortedSymbols"); function composeType(address, ...args) { const generics = Array.isArray(args[args.length - 1]) ? args.pop() : []; const chains = [address, ...args].filter(Boolean); let result = chains.join("::"); if (generics && generics.length) { result += `<${generics.join(", ")}>`; } return result; } __name(composeType, "composeType"); function extractAddressFromType(type) { return type.split("::")[0]; } __name(extractAddressFromType, "extractAddressFromType"); function extractStructTagFromType(type) { try { let _type = type.replace(/\s/g, ""); const genericsString = _type.match(/(<.+>)$/); const generics = genericsString?.[0]?.match(/(\w+: