UNPKG

client-aftermath-ts-sdk

Version:
406 lines (405 loc) 20.5 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Pool = void 0; const cmmmCalculations_1 = require("./utils/cmmmCalculations"); const caller_1 = require("../../general/utils/caller"); const _1 = require("."); const utils_1 = require("../../general/utils"); /** * Represents a pool object and provides methods for interacting with the pool. * @class */ class Pool extends caller_1.Caller { /** * Creates a new instance of the Pool class. * @constructor * @param {PoolObject} pool - The pool object. * @param {SuiNetwork} [network] - The network to use. */ constructor(pool, config, Provider) { super(config, `pools/${pool.objectId}`); this.pool = pool; this.Provider = Provider; /** * Retrieves the volume in the last 24 hours for the pool. * @returns A promise that resolves to the volume in the last 24 hours. */ this.getVolume24hrs = () => __awaiter(this, void 0, void 0, function* () { return this.fetchApi("volume-24hrs"); }); // ========================================================================= // Calculations // ========================================================================= /** * Calculates the spot price for the pool. * @param {Object} inputs - The inputs for the method. * @param {CoinType} inputs.coinInType - The input coin type. * @param {CoinType} inputs.coinOutType - The output coin type. * @param {boolean} [inputs.withFees] - Whether to include fees in the calculation. * @returns {number} The spot price for the pool. */ this.getSpotPrice = (inputs) => { const spotPriceWithDecimals = cmmmCalculations_1.CmmmCalculations.calcSpotPriceWithFees(utils_1.Helpers.deepCopy(this.pool), inputs.coinInType, inputs.coinOutType, !inputs.withFees); return ((spotPriceWithDecimals * Number(this.pool.coins[inputs.coinOutType].decimalsScalar)) / Number(this.pool.coins[inputs.coinInType].decimalsScalar)); }; // TODO: account for referral discount for all calculations /** * Calculates the output amount for a trade. * @param {Object} inputs - The inputs for the method. * @param {CoinType} inputs.coinInType - The input coin type. * @param {Balance} inputs.coinInAmount - The input coin amount. * @param {CoinType} inputs.coinOutType - The output coin type. * @param {boolean} [inputs.referral] - Whether the trade includes a referral. * @returns {Balance} The output amount for the trade. */ this.getTradeAmountOut = (inputs) => { const pool = utils_1.Helpers.deepCopy(this.pool); const coinInPoolBalance = pool.coins[inputs.coinInType].balance; const coinOutPoolBalance = pool.coins[inputs.coinOutType].balance; const coinInAmountWithFees = this.getAmountWithDAOFee({ amount: _1.Pools.getAmountWithProtocolFees({ amount: inputs.coinInAmount, }), }); if (Number(coinInAmountWithFees) / Number(coinInPoolBalance) >= _1.Pools.constants.bounds.maxTradePercentageOfPoolBalance - Pool.constants.percentageBoundsMarginOfError) throw new Error("coinInAmountWithFees / coinInPoolBalance >= maxTradePercentageOfPoolBalance"); const coinOutAmount = cmmmCalculations_1.CmmmCalculations.calcOutGivenIn(pool, inputs.coinInType, inputs.coinOutType, coinInAmountWithFees); if (coinOutAmount <= 0) throw new Error("coinOutAmount <= 0"); if (Number(coinOutAmount) / Number(coinOutPoolBalance) >= _1.Pools.constants.bounds.maxTradePercentageOfPoolBalance - Pool.constants.percentageBoundsMarginOfError) throw new Error("coinOutAmount / coinOutPoolBalance >= maxTradePercentageOfPoolBalance"); return coinOutAmount; }; /** * Calculates the input amount for a trade. * @param {Object} inputs - The inputs for the method. * @param {CoinType} inputs.coinInType - The input coin type. * @param {Balance} inputs.coinOutAmount - The output coin amount. * @param {CoinType} inputs.coinOutType - The output coin type. * @param {boolean} [inputs.referral] - Whether the trade includes a referral. * @returns {Balance} The input amount for the trade. */ this.getTradeAmountIn = (inputs) => { const pool = utils_1.Helpers.deepCopy(this.pool); const coinInPoolBalance = pool.coins[inputs.coinInType].balance; const coinOutPoolBalance = pool.coins[inputs.coinOutType].balance; if (Number(inputs.coinOutAmount) / Number(coinOutPoolBalance) >= _1.Pools.constants.bounds.maxTradePercentageOfPoolBalance - Pool.constants.percentageBoundsMarginOfError) throw new Error("coinOutAmount / coinOutPoolBalance >= maxTradePercentageOfPoolBalance"); const coinInAmount = cmmmCalculations_1.CmmmCalculations.calcInGivenOut(pool, inputs.coinInType, inputs.coinOutType, inputs.coinOutAmount); if (coinInAmount <= 0) throw new Error("coinInAmount <= 0"); if (Number(coinInAmount) / Number(coinInPoolBalance) >= _1.Pools.constants.bounds.maxTradePercentageOfPoolBalance - Pool.constants.percentageBoundsMarginOfError) throw new Error("coinInAmount / coinInPoolBalance >= maxTradePercentageOfPoolBalance"); const coinInAmountWithoutFees = this.getAmountWithoutDAOFee({ amount: _1.Pools.getAmountWithoutProtocolFees({ amount: coinInAmount, }), }); return coinInAmountWithoutFees; }; /** * Calculates the LP amount and ratio for a deposit. * @param {Object} inputs - The inputs for the method. * @param {CoinsToBalance} inputs.amountsIn - The input amounts. * @param {boolean} [inputs.referral] - Whether the deposit includes a referral. * @returns {Object} The LP amount and ratio for the deposit. */ this.getDepositLpAmountOut = (inputs) => { const calcedLpRatio = cmmmCalculations_1.CmmmCalculations.calcDepositFixedAmounts(this.pool, Object.entries(inputs.amountsIn).reduce((acc, [coin, amount]) => (Object.assign(Object.assign({}, acc), { [coin]: this.getAmountWithDAOFee({ amount }) })), {})); if (calcedLpRatio >= utils_1.Casting.Fixed.fixedOneB) throw new Error("lpRatio >= 1"); const lpRatio = utils_1.Casting.bigIntToFixedNumber(calcedLpRatio); const lpAmountOut = BigInt(Math.floor(Number(this.pool.lpCoinSupply) * (1 / lpRatio - 1))); return { lpAmountOut, lpRatio, }; }; /** * Calculates the output amounts for a withdraw. * @param {Object} inputs - The inputs for the method. * @param {number} inputs.lpRatio - The LP ratio. * @param {CoinsToBalance} inputs.amountsOutDirection - The output amounts. * @param {boolean} [inputs.referral] - Whether the withdraw includes a referral. * @returns {CoinsToBalance} The output amounts for the withdraw. */ this.getWithdrawAmountsOut = (inputs) => { const amountsOut = cmmmCalculations_1.CmmmCalculations.calcWithdrawFlpAmountsOut(this.pool, inputs.amountsOutDirection, inputs.lpRatio); for (const coin of Object.keys(amountsOut)) { if (!(coin in inputs.amountsOutDirection) || inputs.amountsOutDirection[coin] <= BigInt(0)) continue; const amountOut = amountsOut[coin]; if (amountOut <= BigInt(0)) throw new Error(`amountsOut[${coin}] <= 0 `); if (amountOut / this.pool.coins[coin].balance >= _1.Pools.constants.bounds.maxWithdrawPercentageOfPoolBalance) throw new Error("coinOutAmount / coinOutPoolBalance >= maxWithdrawPercentageOfPoolBalance"); amountsOut[coin] = this.getAmountWithDAOFee({ amount: amountOut, }); } return amountsOut; }; this.getWithdrawAmountsOutSimple = (inputs) => { const { lpCoinAmountIn, coinTypesOut, referral } = inputs; const lpCoinSupply = this.pool.lpCoinSupply; let withdrawAmountsEstimates = {}; coinTypesOut.forEach((poolCoin) => { const poolCoinAmountInPool = this.pool.coins[utils_1.Helpers.addLeadingZeroesToType(poolCoin)] .balance; const poolCoinAmount = Number(poolCoinAmountInPool) * (Number(lpCoinAmountIn) / Number(lpCoinSupply)); withdrawAmountsEstimates[utils_1.Helpers.addLeadingZeroesToType(poolCoin)] = BigInt(Math.floor(poolCoinAmount)); }); const lpRatio = this.getMultiCoinWithdrawLpRatio({ lpCoinAmountIn, }); const amountsOut = this.getWithdrawAmountsOut({ lpRatio, amountsOutDirection: withdrawAmountsEstimates, referral, }); for (const coin of Object.keys(amountsOut)) { if (!coinTypesOut .map((coinOut) => utils_1.Helpers.addLeadingZeroesToType(coinOut)) .includes(coin)) continue; const amountOut = amountsOut[coin]; if (amountOut <= BigInt(0)) throw new Error(`amountsOut[${coin}] <= 0 `); if (amountOut / this.pool.coins[coin].balance >= _1.Pools.constants.bounds.maxWithdrawPercentageOfPoolBalance) throw new Error("coinOutAmount / coinOutPoolBalance >= maxWithdrawPercentageOfPoolBalance"); amountsOut[coin] = this.getAmountWithDAOFee({ amount: amountOut, }); } return amountsOut; }; /** * Calculates the output amounts for an all coin withdraw. * @param {Object} inputs - The inputs for the method. * @param {number} inputs.lpRatio - The LP ratio. * @param {boolean} [inputs.referral] - Whether the withdraw includes a referral. * @returns {CoinsToBalance} The output amounts for the all coin withdraw. */ this.getAllCoinWithdrawAmountsOut = (inputs) => { if (inputs.lpRatio >= 1) throw new Error("lpRatio >= 1"); const amountsOut = Object.entries(this.pool.coins).reduce((acc, [coin, info]) => { return Object.assign(Object.assign({}, acc), { [coin]: this.getAmountWithDAOFee({ amount: BigInt(Math.floor(Number(info.balance) * inputs.lpRatio)), }) }); }, {}); return amountsOut; }; /** * Calculates the LP ratio for a multi-coin withdraw. * @param {Object} inputs - The inputs for the method. * @param {bigint} inputs.lpCoinAmountIn - The LP coin amount out. * @returns {number} The LP ratio for the multi-coin withdraw. */ this.getMultiCoinWithdrawLpRatio = (inputs) => Number(this.pool.lpCoinSupply - inputs.lpCoinAmountIn) / Number(this.pool.lpCoinSupply); /** * Calculates the LP ratio for an all coin withdraw. * @param {Object} inputs - The inputs for the method. * @param {bigint} inputs.lpCoinAmountIn - The LP coin amount out. * @returns {number} The LP ratio for the all coin withdraw. */ this.getAllCoinWithdrawLpRatio = (inputs) => Number(inputs.lpCoinAmountIn) / Number(this.pool.lpCoinSupply); // ========================================================================= // Getters // ========================================================================= this.coins = () => { return Object.keys(this.pool.coins).sort((a, b) => a.localeCompare(b)); }; this.poolCoins = () => { return Object.entries(this.pool.coins) .sort((a, b) => a[0].localeCompare(b[0])) .map((data) => data[1]); }; this.poolCoinEntries = () => { return Object.entries(this.pool.coins).sort((a, b) => a[0].localeCompare(b[0])); }; this.daoFeePercentage = () => { return this.pool.daoFeePoolObject ? utils_1.Casting.bpsToPercentage(this.pool.daoFeePoolObject.feeBps) : undefined; }; this.daoFeeRecipient = () => { var _a; return (_a = this.pool.daoFeePoolObject) === null || _a === void 0 ? void 0 : _a.feeRecipient; }; // ========================================================================= // Private Helpers // ========================================================================= this.getAmountWithDAOFee = (inputs) => { const daoFeePercentage = this.daoFeePercentage(); if (!daoFeePercentage) return inputs.amount; return BigInt(Math.floor(Number(inputs.amount) * (1 - daoFeePercentage))); }; this.getAmountWithoutDAOFee = (inputs) => { const daoFeePercentage = this.daoFeePercentage(); if (!daoFeePercentage) return inputs.amount; return BigInt(Math.floor(Number(inputs.amount) * (1 / (1 - daoFeePercentage)))); }; this.useProvider = () => { var _a; const provider = (_a = this.Provider) === null || _a === void 0 ? void 0 : _a.Pools(); if (!provider) throw new Error("missing AftermathApi Provider"); return provider; }; this.pool = pool; } // ========================================================================= // Transactions // ========================================================================= /** * Fetches the deposit transaction for the pool. * @async * @param {ApiPoolDepositBody} inputs - The inputs for the method. * @returns {Promise<Transaction>} The deposit transaction for the pool. */ getDepositTransaction(inputs) { return __awaiter(this, void 0, void 0, function* () { return this.useProvider().fetchBuildDepositTx(Object.assign(Object.assign({}, inputs), { pool: this })); }); } /** * Fetches the withdraw transaction for the pool. * @async * @param {ApiPoolWithdrawBody} inputs - The inputs for the method. * @returns {Promise<Transaction>} The withdraw transaction for the pool. */ getWithdrawTransaction(inputs) { return __awaiter(this, void 0, void 0, function* () { return this.useProvider().fetchBuildWithdrawTx(Object.assign(Object.assign({}, inputs), { pool: this })); }); } /** * Fetches the all coin withdraw transaction for the pool. * @async * @param {ApiPoolAllCoinWithdrawBody} inputs - The inputs for the method. * @returns {Promise<Transaction>} The all coin withdraw transaction for the pool. */ getAllCoinWithdrawTransaction(inputs) { return __awaiter(this, void 0, void 0, function* () { return this.useProvider().fetchBuildAllCoinWithdrawTx(Object.assign(Object.assign({}, inputs), { pool: this })); }); } /** * Fetches the trade transaction for the pool. * @async * @param {ApiPoolTradeBody} inputs - The inputs for the method. * @returns {Promise<Transaction>} The trade transaction for the pool. */ getTradeTransaction(inputs) { return __awaiter(this, void 0, void 0, function* () { return this.useProvider().fetchBuildTradeTx(Object.assign(Object.assign({}, inputs), { pool: this })); }); } getUpdateDaoFeeTransaction(inputs) { var _a; return __awaiter(this, void 0, void 0, function* () { const daoFeePoolId = (_a = this.pool.daoFeePoolObject) === null || _a === void 0 ? void 0 : _a.objectId; if (!daoFeePoolId) throw new Error("this pool has no DAO fee"); return this.useProvider().buildDaoFeePoolUpdateFeeBpsTx(Object.assign(Object.assign({}, inputs), { daoFeePoolId, lpCoinType: this.pool.lpCoinType, newFeeBps: utils_1.Casting.percentageToBps(inputs.newFeePercentage) })); }); } getUpdateDaoFeeRecipientTransaction(inputs) { var _a; return __awaiter(this, void 0, void 0, function* () { const daoFeePoolId = (_a = this.pool.daoFeePoolObject) === null || _a === void 0 ? void 0 : _a.objectId; if (!daoFeePoolId) throw new Error("this pool has no DAO fee"); return this.useProvider().buildDaoFeePoolUpdateFeeRecipientTx(Object.assign(Object.assign({}, inputs), { daoFeePoolId, lpCoinType: this.pool.lpCoinType, newFeeRecipient: utils_1.Helpers.addLeadingZeroesToType(inputs.newFeeRecipient) })); }); } // ========================================================================= // Inspections // ========================================================================= /** * Fetches the pool statistics. * @async * @returns {Promise<PoolStats>} The pool statistics. */ getStats() { return __awaiter(this, void 0, void 0, function* () { const stats = yield this.fetchApi("stats"); this.setStats(stats); return stats; }); } /** * Sets the pool statistics. * @param {PoolStats} stats - The pool statistics. */ setStats(stats) { this.stats = stats; } /** * Fetches the volume data for the pool. * @async * @param {Object} inputs - The inputs for the method. * @param {PoolGraphDataTimeframeKey} inputs.timeframe - The timeframe for the data. * @returns {Promise<PoolDataPoint[]>} The volume data for the pool. */ getVolumeData(inputs) { return __awaiter(this, void 0, void 0, function* () { return this.fetchApi(`volume/${inputs.timeframe}`); }); } /** * Fetches the fee data for the pool. * @async * @param {Object} inputs - The inputs for the method. * @param {PoolGraphDataTimeframeKey} inputs.timeframe - The timeframe for the data. * @returns {Promise<PoolDataPoint[]>} The fee data for the pool. */ getFeeData(inputs) { return __awaiter(this, void 0, void 0, function* () { return this.fetchApi(`fees/${inputs.timeframe}`); }); } // ========================================================================= // Events // ========================================================================= getInteractionEvents(inputs) { return __awaiter(this, void 0, void 0, function* () { return this.fetchApiIndexerEvents("interaction-events-by-user", inputs); }); } } exports.Pool = Pool; /** * Private constants used in the class. */ Pool.constants = { percentageBoundsMarginOfError: 0.001, // 0.1% };