client-aftermath-ts-sdk
Version:
Client Aftermath TypeScript SDK
406 lines (405 loc) • 20.5 kB
JavaScript
"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%
};