UNPKG

@ferra-xyz/dlmm

Version:
1,468 lines (1,452 loc) 140 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var client = require('@mysten/sui/client'); var utils = require('@mysten/sui/utils'); var bcs = require('@mysten/bcs'); var ed25519 = require('@mysten/sui/keypairs/ed25519'); var secp256k1 = require('@mysten/sui/keypairs/secp256k1'); var Decimal2 = require('decimal.js'); var transactions = require('@mysten/sui/transactions'); var BN = require('bn.js'); var big_js = require('big.js'); function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; } var Decimal2__default = /*#__PURE__*/_interopDefault(Decimal2); var BN__default = /*#__PURE__*/_interopDefault(BN); /* DLMM SDK - Discrete Liquidity Market Maker v1.0.0 */ var __defProp = Object.defineProperty; var __name = (target, value) => __defProp(target, "name", { value, configurable: true }); var __accessCheck = (obj, member, msg) => { if (!member.has(obj)) throw TypeError("Cannot " + msg); }; var __privateGet = (obj, member, getter) => { __accessCheck(obj, member, "read from private field"); return getter ? getter.call(obj) : member.get(obj); }; var __privateAdd = (obj, member, value) => { if (member.has(obj)) throw TypeError("Cannot add the same private member more than once"); member instanceof WeakSet ? member.add(obj) : member.set(obj, value); }; var __privateSet = (obj, member, value, setter) => { __accessCheck(obj, member, "write to private field"); member.set(obj, value); return value; }; // 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; // src/math/coin-assist.ts var COIN_TYPE = "0x2::coin::Coin"; var COIN_TYPE_ARG_REGEX = /^0x2::coin::Coin<(.+)>$/; var DEFAULT_GAS_BUDGET_FOR_SPLIT = 1e3; var DEFAULT_GAS_BUDGET_FOR_MERGE = 500; var DEFAULT_GAS_BUDGET_FOR_TRANSFER = 100; var DEFAULT_GAS_BUDGET_FOR_TRANSFER_SUI = 100; var DEFAULT_GAS_BUDGET_FOR_STAKE = 1e3; var GAS_TYPE_ARG = "0x2::sui::SUI"; var GAS_TYPE_ARG_LONG = "0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI"; var GAS_SYMBOL = "SUI"; var DEFAULT_NFT_TRANSFER_GAS_FEE = 450; var SUI_SYSTEM_STATE_OBJECT_ID = "0x0000000000000000000000000000000000000005"; var _CoinAssist = class _CoinAssist { /** * Get the coin type argument from a SuiMoveObject. * * @param obj The SuiMoveObject to get the coin type argument from. * @returns The coin type argument, or null if it is not found. */ static getCoinTypeArg(obj) { const res = obj.type.match(COIN_TYPE_ARG_REGEX); return res ? res[1] : null; } /** * Get whether a SuiMoveObject is a SUI coin. * * @param obj The SuiMoveObject to check. * @returns Whether the SuiMoveObject is a SUI coin. */ static isSUI(obj) { const arg = _CoinAssist.getCoinTypeArg(obj); return arg ? _CoinAssist.getCoinSymbol(arg) === "SUI" : false; } /** * Get the coin symbol from a coin type argument. * * @param coinTypeArg The coin type argument to get the symbol from. * @returns The coin symbol. */ static getCoinSymbol(coinTypeArg) { return coinTypeArg.substring(coinTypeArg.lastIndexOf(":") + 1); } /** * Get the balance of a SuiMoveObject. * * @param obj The SuiMoveObject to get the balance from. * @returns The balance of the SuiMoveObject. */ static getBalance(obj) { return BigInt(obj.fields.balance); } /** * Get the total balance of a list of CoinAsset objects for a given coin address. * * @param objs The list of CoinAsset objects to get the total balance for. * @param coinAddress The coin address to get the total balance for. * @returns The total balance of the CoinAsset objects for the given coin address. */ static totalBalance(objs, coinAddress) { let balanceTotal = BigInt(0); objs.forEach((obj) => { if (coinAddress === obj.coinAddress) { balanceTotal += BigInt(obj.balance); } }); return balanceTotal; } /** * Get the ID of a SuiMoveObject. * * @param obj The SuiMoveObject to get the ID from. * @returns The ID of the SuiMoveObject. */ static getID(obj) { return obj.fields.id.id; } /** * Get the coin type from a coin type argument. * * @param coinTypeArg The coin type argument to get the coin type from. * @returns The coin type. */ static getCoinTypeFromArg(coinTypeArg) { return `${COIN_TYPE}<${coinTypeArg}>`; } /** * Get the FaucetCoin objects from a SuiTransactionBlockResponse. * * @param suiTransactionResponse The SuiTransactionBlockResponse to get the FaucetCoin objects from. * @returns The FaucetCoin objects. */ static getFaucetCoins(suiTransactionResponse) { const { events } = suiTransactionResponse; const faucetCoin = []; events?.forEach((item) => { const { type } = item; if (extractStructTagFromType(type).name === "InitEvent") { const fields = item.parsedJson; faucetCoin.push({ transactionModule: item.transactionModule, suplyID: fields.suplyID, decimals: fields.decimals }); } }); return faucetCoin; } /** * Get the CoinAsset objects for a given coin type. * * @param coinType The coin type to get the CoinAsset objects for. * @param allSuiObjects The list of all SuiMoveObjects. * @returns The CoinAsset objects for the given coin type. */ static getCoinAssets(coinType, allSuiObjects) { const coins = []; allSuiObjects.forEach((anObj) => { if (normalizeCoinType(anObj.coinAddress) === normalizeCoinType(coinType)) { coins.push(anObj); } }); return coins; } /** * Get whether a coin address is a SUI coin. * * @param coinAddress The coin address to check. * @returns Whether the coin address is a SUI coin. */ static isSuiCoin(coinAddress) { return extractStructTagFromType(coinAddress).full_address === GAS_TYPE_ARG; } /** * Select the CoinAsset objects from a list of CoinAsset objects that have a balance greater than or equal to a given amount. * * @param coins The list of CoinAsset objects to select from. * @param amount The amount to select CoinAsset objects with a balance greater than or equal to. * @param exclude A list of CoinAsset objects to exclude from the selection. * @returns The CoinAsset objects that have a balance greater than or equal to the given amount. */ static selectCoinObjectIdGreaterThanOrEqual(coins, amount, exclude = []) { const selectedResult = _CoinAssist.selectCoinAssetGreaterThanOrEqual(coins, amount, exclude); const objectArray = selectedResult.selectedCoins.map((item) => item.coinObjectId); const remainCoins = selectedResult.remainingCoins; const amountArray = selectedResult.selectedCoins.map((item) => item.balance.toString()); return { objectArray, remainCoins, amountArray }; } /** * Select the CoinAsset objects from a list of CoinAsset objects that have a balance greater than or equal to a given amount. * * @param coins The list of CoinAsset objects to select from. * @param amount The amount to select CoinAsset objects with a balance greater than or equal to. * @param exclude A list of CoinAsset objects to exclude from the selection. * @returns The CoinAsset objects that have a balance greater than or equal to the given amount. */ static selectCoinAssetGreaterThanOrEqual(coins, amount, exclude = []) { const sortedCoins = _CoinAssist.sortByBalance(coins.filter((c) => !exclude.includes(c.coinObjectId))); const total = _CoinAssist.calculateTotalBalance(sortedCoins); if (total < amount) { return { selectedCoins: [], remainingCoins: sortedCoins }; } if (total === amount) { return { selectedCoins: sortedCoins, remainingCoins: [] }; } let sum = BigInt(0); const selectedCoins = []; const remainingCoins = [...sortedCoins]; while (sum < total) { const target = amount - sum; const coinWithSmallestSufficientBalanceIndex = remainingCoins.findIndex((c) => c.balance >= target); if (coinWithSmallestSufficientBalanceIndex !== -1) { selectedCoins.push(remainingCoins[coinWithSmallestSufficientBalanceIndex]); remainingCoins.splice(coinWithSmallestSufficientBalanceIndex, 1); break; } const coinWithLargestBalance = remainingCoins.pop(); if (coinWithLargestBalance.balance > 0) { selectedCoins.push(coinWithLargestBalance); sum += coinWithLargestBalance.balance; } } return { selectedCoins: _CoinAssist.sortByBalance(selectedCoins), remainingCoins: _CoinAssist.sortByBalance(remainingCoins) }; } /** * Sort the CoinAsset objects by their balance. * * @param coins The CoinAsset objects to sort. * @returns The sorted CoinAsset objects. */ static sortByBalance(coins) { return coins.sort((a, b) => a.balance < b.balance ? -1 : a.balance > b.balance ? 1 : 0); } static sortByBalanceDes(coins) { return coins.sort((a, b) => a.balance > b.balance ? -1 : a.balance < b.balance ? 0 : 1); } /** * Calculate the total balance of a list of CoinAsset objects. * * @param coins The list of CoinAsset objects to calculate the total balance for. * @returns The total balance of the CoinAsset objects. */ static calculateTotalBalance(coins) { return coins.reduce((partialSum, c) => partialSum + c.balance, BigInt(0)); } }; __name(_CoinAssist, "CoinAssist"); var CoinAssist = _CoinAssist; // src/errors/errors.ts var _DlmmPairsError = class _DlmmPairsError extends Error { constructor(message, errorCode) { super(message); this.message = message; this.errorCode = errorCode; } static isClmmpoolsErrorCode(e, code) { return e instanceof _DlmmPairsError && e.errorCode === code; } }; __name(_DlmmPairsError, "DlmmPairsError"); var DlmmPairsError = _DlmmPairsError; // 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 DlmmPairsError(`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+::\w+::\w+)(?:<.*?>(?!>))?/g); if (generics) { _type = _type.slice(0, _type.indexOf("<")); const tag = extractStructTagFromType(_type); const structTag2 = { ...tag, type_arguments: generics.map((item) => extractStructTagFromType(item).source_address) }; structTag2.type_arguments = structTag2.type_arguments.map((item) => { return CoinAssist.isSuiCoin(item) ? item : extractStructTagFromType(item).source_address; }); structTag2.source_address = composeType(structTag2.full_address, structTag2.type_arguments); return structTag2; } const parts = _type.split("::"); const isSuiCoin = _type === GAS_TYPE_ARG || _type === GAS_TYPE_ARG_LONG; const structTag = { full_address: _type, address: isSuiCoin ? "0x2" : utils.normalizeSuiObjectId(parts[0]), module: parts[1], name: parts[2], type_arguments: [], source_address: "" }; structTag.full_address = `${structTag.address}::${structTag.module}::${structTag.name}`; structTag.source_address = composeType(structTag.full_address, structTag.type_arguments); return structTag; } catch (error) { return { full_address: type, address: "", module: "", name: "", type_arguments: [], source_address: type }; } } __name(extractStructTagFromType, "extractStructTagFromType"); function normalizeCoinType(coinType) { return extractStructTagFromType(coinType).source_address; } __name(normalizeCoinType, "normalizeCoinType"); function fixSuiObjectId(value) { if (value.toLowerCase().startsWith("0x")) { return utils.normalizeSuiObjectId(value); } return value; } __name(fixSuiObjectId, "fixSuiObjectId"); var fixCoinType = /* @__PURE__ */ __name((coinType, removePrefix = true) => { const arr = coinType.split("::"); const address = arr.shift(); let normalizeAddress = utils.normalizeSuiObjectId(address); if (removePrefix) { normalizeAddress = removeHexPrefix(normalizeAddress); } return `${normalizeAddress}::${arr.join("::")}`; }, "fixCoinType"); function patchFixSuiObjectId(data) { for (const key in data) { const type = typeof data[key]; if (type === "object") { patchFixSuiObjectId(data[key]); } else if (type === "string") { const value = data[key]; if (value && !value.includes("::")) { data[key] = fixSuiObjectId(value); } } } } __name(patchFixSuiObjectId, "patchFixSuiObjectId"); function d(value) { if (Decimal2__default.default.isDecimal(value)) { return value; } return new Decimal2__default.default(value === void 0 ? 0 : value); } __name(d, "d"); function decimalsMultiplier(decimals) { return d(10).pow(d(decimals).abs()); } __name(decimalsMultiplier, "decimalsMultiplier"); // src/utils/objects.ts function getSuiObjectData(resp) { return resp.data; } __name(getSuiObjectData, "getSuiObjectData"); function getObjectDeletedResponse(resp) { if (resp.error && "object_id" in resp.error && "version" in resp.error && "digest" in resp.error) { const { error } = resp; return { objectId: error.object_id, version: error.version, digest: error.digest }; } return void 0; } __name(getObjectDeletedResponse, "getObjectDeletedResponse"); function getObjectNotExistsResponse(resp) { if (resp.error && "object_id" in resp.error && !("version" in resp.error) && !("digest" in resp.error)) { return resp.error.object_id; } return void 0; } __name(getObjectNotExistsResponse, "getObjectNotExistsResponse"); function getObjectReference(resp) { if ("reference" in resp) { return resp.reference; } const exists = getSuiObjectData(resp); if (exists) { return { objectId: exists.objectId, version: exists.version, digest: exists.digest }; } return getObjectDeletedResponse(resp); } __name(getObjectReference, "getObjectReference"); function getObjectId(data) { if ("objectId" in data) { return data.objectId; } return getObjectReference(data)?.objectId ?? getObjectNotExistsResponse(data); } __name(getObjectId, "getObjectId"); function getObjectVersion(data) { if ("version" in data) { return data.version; } return getObjectReference(data)?.version; } __name(getObjectVersion, "getObjectVersion"); function isSuiObjectResponse(resp) { return resp.data !== void 0; } __name(isSuiObjectResponse, "isSuiObjectResponse"); function isSuiObjectDataWithContent(data) { return data.content !== void 0; } __name(isSuiObjectDataWithContent, "isSuiObjectDataWithContent"); function getMovePackageContent(data) { const suiObject = getSuiObjectData(data); if (suiObject?.content?.dataType !== "package") { return void 0; } return suiObject.content.disassembled; } __name(getMovePackageContent, "getMovePackageContent"); function getMoveObject(data) { const suiObject = "data" in data ? getSuiObjectData(data) : data; if (!suiObject || !isSuiObjectDataWithContent(suiObject) || suiObject.content.dataType !== "moveObject") { return void 0; } return suiObject.content; } __name(getMoveObject, "getMoveObject"); function getMoveObjectType(resp) { return getMoveObject(resp)?.type; } __name(getMoveObjectType, "getMoveObjectType"); function getObjectType(resp) { const data = isSuiObjectResponse(resp) ? resp.data : resp; if (!data?.type && "data" in resp) { if (data?.content?.dataType === "package") { return "package"; } return getMoveObjectType(resp); } return data?.type; } __name(getObjectType, "getObjectType"); function getObjectPreviousTransactionDigest(resp) { return getSuiObjectData(resp)?.previousTransaction; } __name(getObjectPreviousTransactionDigest, "getObjectPreviousTransactionDigest"); function getObjectOwner(resp) { return getSuiObjectData(resp)?.owner; } __name(getObjectOwner, "getObjectOwner"); function getObjectDisplay(resp) { const display = getSuiObjectData(resp)?.display; if (!display) { return { data: null, error: null }; } return display; } __name(getObjectDisplay, "getObjectDisplay"); function getObjectFields(object) { const fields = getMoveObject(object)?.fields; if (fields) { if ("fields" in fields) { return fields.fields; } return fields; } return void 0; } __name(getObjectFields, "getObjectFields"); function hasPublicTransfer(data) { return getMoveObject(data)?.hasPublicTransfer ?? false; } __name(hasPublicTransfer, "hasPublicTransfer"); // src/utils/common.ts function toDecimalsAmount(amount, decimals) { const mul = decimalsMultiplier(d(decimals)); return Number(d(amount).mul(mul)); } __name(toDecimalsAmount, "toDecimalsAmount"); function asUintN(int, bits = 32) { return BigInt.asUintN(bits, BigInt(int)).toString(); } __name(asUintN, "asUintN"); function asIntN(int, bits = 32) { return Number(BigInt.asIntN(bits, BigInt(int))); } __name(asIntN, "asIntN"); function fromDecimalsAmount(amount, decimals) { const mul = decimalsMultiplier(d(decimals)); return Number(d(amount).div(mul)); } __name(fromDecimalsAmount, "fromDecimalsAmount"); function secretKeyToEd25519Keypair(secretKey, ecode = "hex") { if (secretKey instanceof Uint8Array) { const key = Buffer.from(secretKey); return ed25519.Ed25519Keypair.fromSecretKey(new Uint8Array(key)); } const hexKey = ecode === "hex" ? bcs.fromHEX(secretKey) : bcs.fromB64(secretKey); return ed25519.Ed25519Keypair.fromSecretKey(hexKey); } __name(secretKeyToEd25519Keypair, "secretKeyToEd25519Keypair"); function secretKeyToSecp256k1Keypair(secretKey, ecode = "hex") { if (secretKey instanceof Uint8Array) { const key = Buffer.from(secretKey); return secp256k1.Secp256k1Keypair.fromSecretKey(new Uint8Array(key)); } const hexKey = ecode === "hex" ? bcs.fromHEX(secretKey) : bcs.fromB64(secretKey); return secp256k1.Secp256k1Keypair.fromSecretKey(hexKey); } __name(secretKeyToSecp256k1Keypair, "secretKeyToSecp256k1Keypair"); function buildNFT(objects) { const fields = getObjectDisplay(objects).data; const nft = { creator: "", description: "", image_url: "", link: "", name: "", project_url: "" }; if (fields) { nft.creator = fields.creator; nft.description = fields.description; nft.image_url = fields.image_url; nft.link = fields.link; nft.name = fields.name; nft.project_url = fields.project_url; } return nft; } __name(buildNFT, "buildNFT"); Decimal2__default.default.config({ precision: 64, rounding: Decimal2__default.default.ROUND_DOWN, toExpNeg: -64, toExpPos: 64 }); var decimal_default = Decimal2__default.default; var ZERO = new BN__default.default(0); var ONE = new BN__default.default(1); var TWO = new BN__default.default(2); var U128_ = TWO.pow(new BN__default.default(128)); var U64_MAX = TWO.pow(new BN__default.default(64)).sub(ONE); var U128_MAX = TWO.pow(new BN__default.default(128)).sub(ONE); var _MathUtil = class _MathUtil { static toX64_BN(num) { return num.mul(new BN__default.default(2).pow(new BN__default.default(64))); } static toX64_Decimal(num) { return num.mul(decimal_default.pow(2, 64)); } static toX64(num) { return new BN__default.default(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 BN__default.default(2).pow(new BN__default.default(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 BN__default.default(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 DlmmPairsError("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 DlmmPairsError("Multiplication overflow", "MultiplicationOverflow" /* MulOverflow */); } return n; } static checkMulDivFloor(n0, n1, denom, limit) { if (denom.eq(ZERO)) { throw new DlmmPairsError("Devide by zero", "DivideByZero" /* DivideByZero */); } const n = n0.mul(n1).div(denom); if (this.isOverflow(n, limit)) { throw new DlmmPairsError("Multiplication div overflow", "MulDivOverflow" /* MulDivOverflow */); } return n; } static checkMulDivCeil(n0, n1, denom, limit) { if (denom.eq(ZERO)) { throw new DlmmPairsError("Devide by zero", "DivideByZero" /* DivideByZero */); } const n = n0.mul(n1).add(denom.sub(ONE)).div(denom); if (this.isOverflow(n, limit)) { throw new DlmmPairsError("Multiplication div overflow", "MulDivOverflow" /* MulDivOverflow */); } return n; } static checkMulDivRound(n0, n1, denom, limit) { if (denom.eq(ZERO)) { throw new DlmmPairsError("Devide by zero", "DivideByZero" /* DivideByZero */); } const n = n0.mul(n1.add(denom.shrn(1))).div(denom); if (this.isOverflow(n, limit)) { throw new DlmmPairsError("Multiplication div overflow", "MulDivOverflow" /* MulDivOverflow */); } return n; } static checkMulShiftRight(n0, n1, shift, limit) { const n = n0.mul(n1).div(new BN__default.default(2).pow(new BN__default.default(shift))); if (this.isOverflow(n, limit)) { throw new DlmmPairsError("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 DlmmPairsError("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 DlmmPairsError("Multiplication shift left overflow", "MulShiftLeftOverflow" /* MulShiftLeftOverflow */); } return n; } static checkDivRoundUpIf(n0, n1, roundUp) { if (n1.eq(ZERO)) { throw new DlmmPairsError("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 BN__default.default(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 BN__default.default("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 BN__default.default(1))); } static neg_from(v) { if (v.eq(ZERO)) { return v; } return this.u128_neg(v).add(new BN__default.default(1)).or(new BN__default.default(1).shln(127)); } }; __name(_MathUtil, "MathUtil"); var MathUtil = _MathUtil; // src/math/bin.ts var _BinMath = class _BinMath { /** * @static * Returns the price of bin given its id and the bin step * Price is returned as tokenY/tokenX accounting for decimals * * @param {number} id - The bin id * @param {number} binStep * @param {number} tokenXDecimals - Decimals of token X * @param {number} tokenYDecimals - Decimals of token Y * @returns {number} */ static getPriceFromId(id, binStep, tokenXDecimals, tokenYDecimals) { const rawPrice = (1 + binStep / 1e4) ** (id - 8388608); const decimalAdjustment = Math.pow(10, tokenXDecimals - tokenYDecimals); return rawPrice * decimalAdjustment; } /** * @static * Returns the bin id given its price and the bin step * Price should be provided as tokenY/tokenX accounting for decimals * * @param {number} price - The price of the bin (tokenY/tokenX) * @param {number} binStep * @param {number} tokenXDecimals - Decimals of token X * @param {number} tokenYDecimals - Decimals of token Y * @returns {number} */ static getIdFromPrice(price, binStep, tokenXDecimals, tokenYDecimals) { const decimalAdjustment = Math.pow(10, tokenXDecimals - tokenYDecimals); const rawPrice = price / decimalAdjustment; return Math.trunc(Math.log(rawPrice) / Math.log(1 + binStep / 1e4)) + 8388608; } /** * @static * Returns idSlippage given slippage tolerance and the bin step * Note: This function doesn't need decimals as it works with percentage slippage * * @param {number} priceSlippage - Price slippage as a decimal (e.g., 0.01 for 1%) * @param {number} binStep * @returns {number} */ static getIdSlippageFromPriceSlippage(priceSlippage, binStep, tokenXDecimals, tokenYDecimals) { const decimalAdjustment = Math.pow(10, tokenXDecimals - tokenYDecimals); const rawPrice = priceSlippage / decimalAdjustment; return Math.floor(Math.log(1 + rawPrice) / Math.log(1 + binStep / 1e4)); } }; __name(_BinMath, "BinMath"); var BinMath = _BinMath; // src/types/sui.ts var CLOCK_ADDRESS = "0x0000000000000000000000000000000000000000000000000000000000000006"; var DlmmFactoryModule = "lb_factory"; var DlmmPairModule = "lb_pair"; var DlmmQuoterModule = "lb_quoter"; var DlmmRouterModule = "lb_router"; var DlmmTokenModule = "lb_token"; 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 DlmmPairsError(`Unknown type for value: ${value}`, "InvalidType" /* InvalidType */); }, "getDefaultSuiInputType"); // src/utils/transaction-util.ts var _TransactionUtil = class _TransactionUtil { /** * Create a new liquidity position NFT * @param pair - The LBPair to create position for * @param sdkOptions - SDK configuration options * @param tx - Optional existing transaction to add to * @returns Tuple of [Transaction, position object] */ static createLbPosition(pair, sdkOptions, tx) { const { dlmm_pool: { package_id, config } } = sdkOptions; const { global_config } = config ?? {}; if (!global_config) { throw new DlmmPairsError("Global config is not set", "InvalidConfig" /* InvalidConfig */); } tx ?? (tx = new transactions.Transaction()); const [bucket] = tx.moveCall({ target: `${package_id}::lb_pair::open_position`, arguments: [tx.object(global_config), tx.object(pair.id), tx.pure.u64(0)], typeArguments: [pair.tokenXType, pair.tokenYType] }); return [tx, bucket]; } /** * Add liquidity to a position * @param pair - The LBPair to add liquidity to * @param params - Liquidity addition parameters * @param params.deltaIds - Array of bin IDs to add liquidity to * @param params.distributionX - Distribution of token X across bins * @param params.distributionY - Distribution of token Y across bins * @param params.amountX - Token X amount to add * @param params.amountY - Token Y amount to add * @param params.position - Position object to add liquidity to * @param sdkOptions - SDK configuration options * @param tx - Optional existing transaction to add to * @returns Transaction object with liquidity addition */ static addLiquidity(pair, { deltaIds, distributionX, distributionY, amountX, amountY, position, minAmountX, minAmountY }, sdkOptions, tx) { const { dlmm_pool: { package_id, config } } = sdkOptions; const { global_config } = config ?? {}; if (!global_config) { throw new DlmmPairsError("Global config is not set", "InvalidConfig" /* InvalidConfig */); } tx ?? (tx = new transactions.Transaction()); tx.moveCall({ target: `${package_id}::lb_pair::add_liquidity`, arguments: [ tx.object(global_config), tx.object(pair.id), position, tx.pure.vector("u32", deltaIds), tx.pure.vector("u64", distributionX), tx.pure.vector("u64", distributionY), amountX, amountY, tx.pure.u64(minAmountX ?? 0), tx.pure.u64(minAmountY ?? 0), tx.object(CLOCK_ADDRESS) ], typeArguments: [pair.tokenXType, pair.tokenYType] }); return tx; } /** * Remove liquidity from a position * @param pair - The LBPair to remove liquidity from * @param params - Liquidity removal parameters * @param params.positionId - ID of the position to remove from * @param params.binIds - Array of bin IDs to remove liquidity from * @param params.binAmounts - Array of amounts to remove from each bin * @param sdkOptions - SDK configuration options * @param tx - Optional existing transaction to add to * @returns Tuple of [Transaction, coinA output, coinB output] */ static removeLiquidity(pair, { binIds, positionId }, sdkOptions, tx) { const { dlmm_pool: { package_id, config } } = sdkOptions; const { global_config } = config ?? {}; if (!global_config) { throw new DlmmPairsError("Global config is not set", "InvalidConfig" /* InvalidConfig */); } tx ?? (tx = new transactions.Transaction()); const [coinA, coinB] = tx.moveCall({ target: `${package_id}::lb_pair::remove_liquidity`, arguments: [ tx.object(global_config), tx.object(pair.id), tx.object(positionId), tx.pure.vector("u32", binIds), tx.pure.u64(0), tx.pure.u64(0), tx.object(CLOCK_ADDRESS) ], typeArguments: [pair.tokenXType, pair.tokenYType] }); return [tx, coinA, coinB]; } static closePosition(pair, { positionId }, sdkOptions, tx) { const { dlmm_pool: { package_id, config } } = sdkOptions; const { global_config } = config ?? {}; if (!global_config) { throw new DlmmPairsError("Global config is not set", "InvalidConfig" /* InvalidConfig */); } tx ?? (tx = new transactions.Transaction()); tx.moveCall({ target: `${package_id}::lb_pair::close_position`, arguments: [ tx.object(global_config), tx.object(pair.id), tx.object(positionId) ], typeArguments: [pair.tokenXType, pair.tokenYType] }); return [tx]; } /** Swap Operations */ /** * Create a swap transaction * @param params - Swap parameters * @param params.pairId - ID of the pair to swap on * @param params.xtoy - Direction of swap (true = X to Y) * @param params.recipient - Address to receive output tokens * @param params.coinX - Input coin X object * @param params.coinY - Input coin Y object * @param params.coinTypeX - Type of token X * @param params.coinTypeY - Type of token Y * @param sdkOptions - SDK configuration options * @param tx - Optional existing transaction to add to * @returns Tuple of [Transaction, coinX receipt, coinY receipt] */ static createSwapTx({ coinX, coinY, pairId, xtoy, minAmountOut, coinTypeX, coinTypeY }, sdkOptions, tx) { const { dlmm_pool: { package_id, config } } = sdkOptions; const { global_config } = config ?? {}; if (!global_config) { throw new DlmmPairsError("Global config is not set", "InvalidConfig" /* InvalidConfig */); } tx ?? (tx = new transactions.Transaction()); const [coinXReceipt, coinYReceipt] = tx.moveCall({ target: `${package_id}::lb_pair::swap`, arguments: [ tx.object(global_config), tx.object(pairId), tx.pure.bool(xtoy), tx.pure.u64(minAmountOut ?? 0n), coinX, coinY, tx.object(CLOCK_ADDRESS) ], typeArguments: [coinTypeX, coinTypeY] }); return [tx, coinXReceipt, coinYReceipt]; } /** Coin Management */ /** * Build a coin object with specific amount from user's coin assets * @param tx - Transaction object * @param coinAssets - Array of user's coin assets * @param coinType - Type of coin to build * @param amount - Amount needed * @returns Transaction result with coin object */ static buildCoinAmount(tx, coinAssets, coinType, amount) { if (CoinAssist.isSuiCoin(coinType)) { if (amount === BigInt(0)) { return _TransactionUtil.callMintZeroValueCoin(tx, coinType); } const [amountCoin] = tx.splitCoins(tx.gas, [tx.pure.u64(amount)]); return amountCoin; } const { targetCoin } = this.buildSpitTargeCoin(tx, amount, coinAssets, true); return targetCoin; } /** * Build a coin object by selecting and merging user's coins * @param tx - Transaction object * @param amount - Amount needed * @param coinAssets - Available coin assets * @param fixAmount - Whether to split exact amount * @returns Object with target coin and metadata */ static buildSpitTargeCoin(tx, amount, coinAssets, fixAmount) { const selectedCoinsResult = CoinAssist.selectCoinObjectIdGreaterThanOrEqual( coinAssets, amount ); const totalSelectedCoinAmount = selectedCoinsResult.amountArray.reduce((a, b) => Number(a) + Number(b), 0).toString(); const coinObjectIds = selectedCoinsResult.objectArray; const [primaryCoinA, ...mergeCoinAs] = coinObjectIds; const primaryCoinAObject = tx.object(primaryCoinA); let targetCoin = primaryCoinAObject; const tragetCoinAmount = selectedCoinsResult.amountArray.reduce((a, b) => Number(a) + Number(b), 0).toString(); let originalSplitedCoin; if (mergeCoinAs.length > 0) { tx.mergeCoins( primaryCoinAObject, mergeCoinAs.map((coin) => tx.object(coin)) ); } if (fixAmount && Number(totalSelectedCoinAmount) > Number(amount)) { targetCoin = tx.splitCoins(primaryCoinAObject, [tx.pure.u64(amount)]); originalSplitedCoin = primaryCoinAObject; } return { originalSplitedCoin, targetCoin, tragetCoinAmount, selectedCoinsResult, coinObjectIds }; } static collectPositionRewards({ pairId, positionId, rewardCoin, typeX, typeY }, sdkOptions, tx) { const { dlmm_pool: { package_id, config } } = sdkOptions; const { global_config, reward_vault } = config ?? {}; if (!global_config) { throw new DlmmPairsError("Global config is not set", "InvalidConfig" /* InvalidConfig */); } if (!reward_vault) { throw new DlmmPairsError("Reward vault is not set", "InvalidConfig" /* InvalidConfig */); } tx ?? (tx = new transactions.Transaction()); const coin = tx.moveCall({ target: `${package_id}::lb_pair::collect_position_rewards`, arguments: [tx.object(global_config), tx.object(pairId), tx.object(positionId), tx.object(reward_vault), tx.object(CLOCK_ADDRESS)], typeArguments: [typeX, typeY, rewardCoin] }); return [tx, coin]; } static async getPositionRewards({ pairId, positionId, rewardCoin, typeX, typeY }, sdkOptions, tx) { const { dlmm_pool: { package_id } } = sdkOptions; tx ?? (tx = new transactions.Transaction()); const amount = tx.moveCall({ target: `${package_id}::lb_pair::get_pending_rewards`, arguments: [tx.object(pairId), tx.object(positionId), tx.object(CLOCK_ADDRESS)], typeArguments: [typeX, typeY, rewardCoin] }); return [tx, amount]; } static collectPositionFees({ pairId, positionId, binIds, typeX, typeY }, sdkOptions, tx) { const { dlmm_pool: { package_id, config } } = sdkOptions; const { global_config, reward_vault } = config ?? {}; if (!global_config) { throw new DlmmPairsError("Global config is not set", "InvalidConfig" /* InvalidConfig */); } if (!reward_vault) { throw new DlmmPairsError("Reward vault is not set", "InvalidConfig" /* InvalidConfig */); } tx ?? (tx = new transactions.Transaction()); const [coinX, coinY] = tx.moveCall({ target: `${package_id}::lb_pair::collect_position_fees`, arguments: [ tx.object(global_config), tx.object(pairId), tx.object(positionId), tx.pure.vector("u32", binIds), tx.object(CLOCK_ADDRESS) ], typeArguments: [typeX, typeY] }); return [tx, coinX, coinY]; } static lockPosition({ positionId, untilTimestamp, pairId, typeX, typeY }, sdkOptions, tx) { const { dlmm_pool: { package_id, config } } = sdkOptions; const { global_config, reward_vault } = config ?? {}; if (!global_config) { throw new DlmmPairsError("Global config is not set", "InvalidConfig" /* InvalidConfig */); } tx ?? (tx = new transactions.Transaction()); tx.moveCall({ target: `${package_id}::lb_pair::lock_position`, arguments: [ tx.object(global_config), tx.object(pairId), tx.object(positionId), tx.pure.u64(untilTimestamp), tx.object(CLOCK_ADDRESS) ], typeArguments: [typeX, typeY] }); return [tx]; } static async getPositionFees({ pairId, positionId, binIds, typeX, typeY }, sdkOptions, tx) { const { dlmm_pool: { package_id } } = sdkOptions; tx ?? (tx = new transactions.Transaction()); const amount = tx.moveCall({ target: `${package_id}::lb_pair::get_total_pending_fees`, arguments: [tx.object(pairId), tx.object(positionId), tx.pure.vector("u32", binIds)], typeArguments: [typeX, typeY] }); return [tx, amount]; } }; __name(_TransactionUtil, "TransactionUtil"); /** Factory Operations */ /** * Create a new DLMM factory * @param params - Factory creation parameters * @param params.owner - Address of the factory owner * @param params.feeRecipient - Address to receive protocol fees * @param params.flashLoanFee - Fee percentage for flash loans * @param sdkOptions - SDK configuration options * @returns Transaction object for factory creation * @throws Error if addresses are invalid or fee is not provided */ _TransactionUtil.createFatory = /* @__PURE__ */ __name((params, sdkOptions) => { const { dlmm_pool: { package_id } } = sdkOptions; const { feeRecipient, flashLoanFee, owner } = params; if (!utils.isValidSuiAddress(owner)) { throw new Error("Invalid owner address"); } if (!utils.isValidSuiAddress(feeRecipient)) { throw new Error("Invalid fee recipient address"); } const loanFee = Decimal2__default.default(flashLoanFee); if (!loanFee) { throw new Error("Invalid flash loan fee"); } const tx = new transactions.Transaction(); tx.moveCall({ target: `${package_id}::lb_factory::new`, arguments: [ tx.pure.address(owner), tx.pure.address(feeRecipient), tx.pure.u256(flashLoanFee) ] }); return tx; }, "createFatory"); /** * Creates a new LB pair on the DLMM factory * @param params - Parameters for creating the LB pair * @param params.tokenXType - Type of token X (must be < tokenYType) * @param params.tokenYType - Type of token Y (must be > tokenXType) * @param params.activeId - Initial active bin ID * @param params.binStep - Bin step in basis points * @param sdkOptions - SDK configuration options * @param tx - Optional existing transaction to add to * @returns Transaction object with pair creation * @throws Error if parameters are invalid */ _TransactionUtil.createLBPair = /* @__PURE__ */ __name((params, sdkOptions, tx) => { const { tokenXType, tokenYType, activeId, binStep } = params; const { dlmm_pool: { package_id, config } } = sdkOptions; const { global_config, pairs_id } = config ?? {}; if (!global_config) throw new Error("Global Config ID is required"); if (!pairs_id) throw new Error("Pairs ID is required"); if (!tokenXType) throw new Error("Token X type is required"); if (!tokenYType) throw new Error("Token Y type is required"); if (tokenXType === tokenYType) throw new Error("Tokens must be different"); if (activeId < 0 || activeId > 16777215) throw new Error("Invalid active ID"); if (binStep < 1) throw new Error("Bin step must be at least 1"); tx ?? (tx = new transactions.Transaction()); tx.moveCall({ target: `${package_id}::lb_factory::create_pair`, typeArguments: [tokenXType, tokenYType], arguments: [ tx.object(global_config), tx.object(pairs_id), tx.pure.u32(activeId), tx.pure.u16(binStep), tx.pure.u32(params.initialBins ?? 0), tx.object(CLOCK_ADDRESS) ] }); return tx; }, "createLBPair"); /** * Create a zero-value coin object * @param txb - Transaction builder * @param coinType - Type of coin to create * @returns Zero-value coin object */ _TransactionUtil.callMintZeroValueCoin = /* @__PURE__ */ __name((txb, coinType) => { return txb.moveCall({ target: "0x2::coin::zero", typeArguments: [coinType] })[0]; }, "callMintZeroValueCoin"); var TransactionUtil = _TransactionUtil; function checkInvalidSuiAddress(address) { if (!address.startsWith("0x") || address.length !== 66) { return false; } return true; } __name(checkInvalidSuiAddress, "checkInvalidSuiAddress"); var _TxBlock = class _TxBlock { constructor() { this.txBlock = new transactions.Transaction(); } /** * Transfer sui to many recipoents. * @param {string[]}recipients The recipient addresses. * @param {number[]}amounts The amounts of sui coins to be transferred. * @returns this */ transferSuiToMany(recipients, amounts) { if (recipients.length !== amounts.length) { throw new DlmmPairsError("The length of recipients and amounts must be the same", "InvalidRecipientAndAmountLength" /* InvalidRecipientAndAmountLength */); } for (const recipient of recipients) { if (!checkInvalidSuiAddress(recipient) === false) { throw new DlmmPairsError("Invalid recipient address", "InvalidRecipientAddress" /* InvalidRecipientAddress */); } } const tx = this.txBlock; const coins = tx.splitCoins( tx.gas, amounts.map((amount) => tx.pure.u64(amount)) ); recipients.forEach((recipient, index) => { tx.transferObjects([coins[index]], tx.pure.address(recipient)); }); return this; } /** * Transfer sui to one recipient. * @param {string}recipient recipient cannot be empty or invalid sui address. * @param {number}amount * @returns this */ transferSui(recipient, amount) { if (!checkInvalidSuiAddress(recipient) === false) { throw new DlmmPairsError("Invalid recipient address", "InvalidRecipientAddress" /* InvalidRecipientAddress */); } return this.transferSuiToMany([recipient], [amount]); } /** * Transfer coin to many recipients. * @param {string}recipient recipient cannot be empty or invalid sui address. * @param {number}amount amount cannot be empty or invalid sui address. * @param {string[]}coinObjectIds object ids of coins to be transferred. * @returns this * @deprecated use transferAndDestoryZeroCoin instead */ transferCoin(recipient, amount, coinObjectIds) { if (!checkInvalidSuiAddress(recipient) === false) { throw new DlmmPairsError("Invalid recipient address", "InvalidRecipientAddress" /* InvalidRecipientAddress */); } const tx = this.txBlock; const [primaryCoinA, ...mergeCoinAs] = coinObjectIds; const primaryCoinAInput = tx.object(primaryCoinA); if (mergeCoinAs.length > 0) { tx.mergeCoins( primaryCoinAInput, mergeCoinAs.map((coin) => tx.object(coin)) ); } const spitAmount = tx.splitCoins(primaryCoinAInput, [tx.pure.u64(amount)]); tx.transferObjects([spitAmount], tx.pure.address(recipient)); return this; } }; __name(_TxBlock, "TxBlock"); var TxBlock = _TxBlock; exports.DistributionUtils = void 0; ((DistributionUtils2) => {