@ferra-labs/clmm
Version:
SDK for concentrated liquidity market maker
1,282 lines (1,270 loc) • 288 kB
JavaScript
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+: