aftermath-ts-sdk
Version:
Aftermath TypeScript SDK
858 lines (857 loc) • 47 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.PoolsApi = void 0;
const transactions_1 = require("@mysten/sui/transactions");
const utils_1 = require("@mysten/sui/utils");
const casting_1 = require("../../../general/utils/casting");
const pools_1 = require("../pools");
const utils_2 = require("../../../general/utils");
const coin_1 = require("../../coin");
const eventsApiHelpers_1 = require("../../../general/apiHelpers/eventsApiHelpers");
const bcs_1 = require("@mysten/sui/bcs");
/**
* This file contains the implementation of the PoolsApi class, which provides methods for interacting with the Aftermath protocol's pools.
* @packageDocumentation
*/
/**
* Provides methods to interact with the Pools API.
*/
class PoolsApi {
// =========================================================================
// Constructor
// =========================================================================
/**
* Creates an instance of PoolsApi.
* @param {AftermathApi} Provider - An instance of AftermathApi.
* @throws {Error} Throws an error if not all required addresses have been set in AfSdk
*/
constructor(Provider) {
this.Provider = Provider;
// =========================================================================
// Public Methods
// =========================================================================
// =========================================================================
// Objects
// =========================================================================
this.fetchOwnedDaoFeePoolOwnerCaps = (inputs) => __awaiter(this, void 0, void 0, function* () {
const { walletAddress } = inputs;
if (!this.objectTypes.daoFeePoolOwnerCap)
throw new Error("dao fee pool addresses have not been set in provider");
return this.Provider.Objects().fetchCastObjectsOwnedByAddressOfType({
walletAddress,
objectType: this.objectTypes.daoFeePoolOwnerCap,
objectFromSuiObjectResponse: casting_1.Casting.pools.daoFeePoolOwnerCapObjectFromSuiObjectResponse,
});
});
// =========================================================================
// Transaction Commands
// =========================================================================
/**
* Executes a trade transaction on the specified pool.
* @param inputs An object containing the necessary inputs for the trade transaction.
* @returns A `TransactionObjectArgument` representing the trade transaction.
*/
this.tradeTx = (inputs) => {
const { tx, poolId, coinInId, coinInType, expectedCoinOutAmount, coinOutType, lpCoinType, slippage, withTransfer, } = inputs;
return tx.moveCall({
target: utils_2.Helpers.transactions.createTxTarget(withTransfer
? this.addresses.pools.packages.ammInterface
: this.addresses.pools.packages.amm, withTransfer
? PoolsApi.constants.moduleNames.interface
: PoolsApi.constants.moduleNames.swap, "swap_exact_in"),
typeArguments: [lpCoinType, coinInType, coinOutType],
arguments: [
tx.object(poolId),
tx.object(this.addresses.pools.objects.poolRegistry),
tx.object(this.addresses.pools.objects.protocolFeeVault),
tx.object(this.addresses.pools.objects.treasury),
tx.object(this.addresses.pools.objects.insuranceFund),
tx.object(this.addresses.referralVault.objects.referralVault),
typeof coinInId === "string" ? tx.object(coinInId) : coinInId,
tx.pure.u64(expectedCoinOutAmount.toString()),
tx.pure.u64(pools_1.Pools.normalizeInvertSlippage(slippage)),
],
});
};
/**
* Creates a transaction object argument for depositing multiple coins into a pool.
*
* @param inputs - An object containing the necessary parameters for the deposit transaction.
* @returns A transaction object argument representing the deposit transaction.
*/
this.multiCoinDepositTx = (inputs) => {
const { tx, poolId, coinIds, coinTypes, expectedLpRatio, lpCoinType, slippage, withTransfer, } = inputs;
const poolSize = coinTypes.length;
return tx.moveCall({
target: utils_2.Helpers.transactions.createTxTarget(withTransfer
? this.addresses.pools.packages.ammInterface
: this.addresses.pools.packages.amm, withTransfer
? PoolsApi.constants.moduleNames.interface
: PoolsApi.constants.moduleNames.deposit, `deposit_${poolSize}_coins`),
typeArguments: [lpCoinType, ...coinTypes],
arguments: [
tx.object(poolId),
tx.object(this.addresses.pools.objects.poolRegistry),
tx.object(this.addresses.pools.objects.protocolFeeVault),
tx.object(this.addresses.pools.objects.treasury),
tx.object(this.addresses.pools.objects.insuranceFund),
tx.object(this.addresses.referralVault.objects.referralVault),
...coinIds.map((coinId) => typeof coinId === "string" ? tx.object(coinId) : coinId),
tx.pure.u128(expectedLpRatio.toString()),
tx.pure.u64(pools_1.Pools.normalizeInvertSlippage(slippage)),
],
});
};
/**
* Withdraws multiple coins from a pool.
* @param inputs An object containing the necessary parameters for the transaction.
* @returns A TransactionObjectArgument representing the transaction.
*/
this.multiCoinWithdrawTx = (inputs) => {
const { tx, poolId, lpCoinId, expectedAmountsOut, coinTypes, lpCoinType, slippage, withTransfer, } = inputs;
const poolSize = coinTypes.length;
return tx.moveCall({
target: utils_2.Helpers.transactions.createTxTarget(withTransfer
? this.addresses.pools.packages.ammInterface
: this.addresses.pools.packages.amm, withTransfer
? PoolsApi.constants.moduleNames.interface
: PoolsApi.constants.moduleNames.withdraw, `withdraw_${poolSize}_coins`),
typeArguments: [lpCoinType, ...coinTypes],
arguments: [
tx.object(poolId),
tx.object(this.addresses.pools.objects.poolRegistry),
tx.object(this.addresses.pools.objects.protocolFeeVault),
tx.object(this.addresses.pools.objects.treasury),
tx.object(this.addresses.pools.objects.insuranceFund),
tx.object(this.addresses.referralVault.objects.referralVault),
typeof lpCoinId === "string" ? tx.object(lpCoinId) : lpCoinId,
tx.pure(bcs_1.bcs
.vector(bcs_1.bcs.u64())
.serialize(expectedAmountsOut.map((amount) => amount.toString()))),
tx.pure.u64(pools_1.Pools.normalizeInvertSlippage(slippage)),
],
});
};
/**
* Withdraws all coins from a liquidity pool.
* @param inputs - The inputs required for the transaction.
* @param inputs.tx - The transaction block.
* @param inputs.poolId - The ID of the liquidity pool.
* @param inputs.lpCoinId - The ID of the LP coin.
* @param inputs.lpCoinType - The type of the LP coin.
* @param inputs.coinTypes - An array of coin types.
* @param inputs.withTransfer - Whether or not to include a transfer.
* @returns An array of transaction objects.
*/
this.allCoinWithdrawTx = (inputs) => {
const { tx, poolId, lpCoinId, coinTypes, lpCoinType, withTransfer } = inputs;
const poolSize = coinTypes.length;
return tx.moveCall({
target: utils_2.Helpers.transactions.createTxTarget(withTransfer
? this.addresses.pools.packages.ammInterface
: this.addresses.pools.packages.amm, withTransfer
? PoolsApi.constants.moduleNames.interface
: PoolsApi.constants.moduleNames.withdraw, `all_coin_withdraw_${poolSize}_coins`),
typeArguments: [lpCoinType, ...coinTypes],
arguments: [
tx.object(poolId),
tx.object(this.addresses.pools.objects.poolRegistry),
tx.object(this.addresses.pools.objects.protocolFeeVault),
tx.object(this.addresses.pools.objects.treasury),
tx.object(this.addresses.pools.objects.insuranceFund),
tx.object(this.addresses.referralVault.objects.referralVault),
typeof lpCoinId === "string" ? tx.object(lpCoinId) : lpCoinId,
],
});
};
/**
* Publishes a transaction block for creating a liquidity pool coin.
* @param inputs An object containing the transaction block and the decimal value of the liquidity pool coin.
* @returns A promise that resolves to the result of the transaction publishing.
*/
this.publishLpCoinTx = (inputs) => {
var _a;
const compilations = (_a = this.addresses.pools.other) === null || _a === void 0 ? void 0 : _a.createLpCoinPackageCompilations;
if (!compilations)
throw new Error("not all required addresses have been set in provider for lp coin publishing (requires package compilations)");
const { tx, lpCoinDecimals } = inputs;
const compiledModulesAndDeps = JSON.parse(compilations[lpCoinDecimals]);
return tx.publish({
modules: compiledModulesAndDeps.modules.map((m) => Array.from((0, utils_1.fromB64)(m))),
dependencies: compiledModulesAndDeps.dependencies.map((addr) => (0, utils_1.normalizeSuiObjectId)(addr)),
});
};
// TODO: handle bounds checks here instead of just on-chain ?
/**
* Creates a transaction to create a new pool.
* @param inputs - An object containing the necessary inputs to create the pool.
* @returns A transaction block to create the pool.
*/
this.createPoolTx = (inputs) => {
const { tx, lpCoinType, createPoolCapId, coinsInfo, lpCoinMetadata, lpCoinDescription, lpCoinIconUrl, withTransfer, } = inputs;
const poolSize = coinsInfo.length;
const coinTypes = coinsInfo.map((coin) => coin.coinType);
const decimals = coinsInfo.map((coin) => coin.decimals);
return tx.moveCall({
target: utils_2.Helpers.transactions.createTxTarget(withTransfer
? this.addresses.pools.packages.ammInterface
: this.addresses.pools.packages.amm, withTransfer
? PoolsApi.constants.moduleNames.interface
: PoolsApi.constants.moduleNames.poolFactory, `create_pool_${poolSize}_coins`),
typeArguments: [lpCoinType, ...coinTypes],
arguments: [
typeof createPoolCapId === "string"
? tx.object(createPoolCapId)
: createPoolCapId,
tx.object(this.addresses.pools.objects.poolRegistry),
tx.pure(bcs_1.bcs
.vector(bcs_1.bcs.u8())
.serialize(casting_1.Casting.u8VectorFromString(inputs.poolName))),
tx.pure(bcs_1.bcs
.vector(bcs_1.bcs.u8())
.serialize(casting_1.Casting.u8VectorFromString(lpCoinMetadata.name.toString()))),
tx.pure(bcs_1.bcs
.vector(bcs_1.bcs.u8())
.serialize(casting_1.Casting.u8VectorFromString(lpCoinMetadata.symbol.toString().toUpperCase()))),
tx.pure(bcs_1.bcs
.vector(bcs_1.bcs.u8())
.serialize(casting_1.Casting.u8VectorFromString(lpCoinDescription))),
tx.pure(bcs_1.bcs
.vector(bcs_1.bcs.u8())
.serialize(casting_1.Casting.u8VectorFromString(lpCoinIconUrl))), // lp_icon_url
tx.pure(bcs_1.bcs
.vector(bcs_1.bcs.u64())
.serialize(coinsInfo.map((coin) => coin.weight))),
tx.pure.u64(inputs.poolFlatness),
tx.pure(bcs_1.bcs
.vector(bcs_1.bcs.u64())
.serialize(coinsInfo.map((coin) => coin.tradeFeeIn))),
tx.pure(bcs_1.bcs
.vector(bcs_1.bcs.u64())
.serialize(coinsInfo.map((coin) => coin.tradeFeeOut))),
tx.pure(bcs_1.bcs
.vector(bcs_1.bcs.u64())
.serialize(coinsInfo.map((coin) => coin.depositFee))),
tx.pure(bcs_1.bcs
.vector(bcs_1.bcs.u64())
.serialize(coinsInfo.map((coin) => coin.withdrawFee))),
...coinsInfo.map((coin) => typeof coin.coinId === "string"
? tx.object(coin.coinId)
: coin.coinId),
tx.pure(bcs_1.bcs
.option(bcs_1.bcs.vector(bcs_1.bcs.u8()))
.serialize(decimals.includes(undefined)
? undefined
: decimals)), // decimals
tx.pure.bool(inputs.respectDecimals), // respect_decimals
tx.pure(bcs_1.bcs.option(bcs_1.bcs.u8()).serialize(inputs.forceLpDecimals)), // force_lp_decimals
],
});
};
/**
* Returns the pool object ID for a given LP coin type transaction.
* @param inputs - An object containing the transaction block and LP coin type.
* @returns The pool object ID.
*/
this.poolObjectIdForLpCoinTypeTx = (inputs) => {
const { tx, lpCoinType } = inputs;
return tx.moveCall({
target: utils_2.Helpers.transactions.createTxTarget(this.addresses.pools.packages.amm, PoolsApi.constants.moduleNames.poolRegistry, "lp_type_to_pool_id"),
typeArguments: [lpCoinType],
arguments: [tx.object(this.addresses.pools.objects.poolRegistry)],
});
};
this.daoFeePoolNewTx = (inputs) => {
const { tx, poolId } = inputs;
if (!this.addresses.daoFeePools)
throw new Error("dao fee pool addresses have not been set in provider");
return tx.moveCall({
target: utils_2.Helpers.transactions.createTxTarget(this.addresses.daoFeePools.packages.amm, PoolsApi.constants.moduleNames.pool, "new"),
typeArguments: [inputs.lpCoinType],
arguments: [
typeof poolId === "string" ? tx.object(poolId) : poolId, // Pool
tx.object(this.addresses.daoFeePools.objects.version),
tx.pure.u16(Number(inputs.feeBps)),
tx.pure.address(inputs.feeRecipient),
],
});
};
this.daoFeePoolUpdateFeeBpsTx = (inputs) => {
const { tx } = inputs;
if (!this.addresses.daoFeePools)
throw new Error("dao fee pool addresses have not been set in provider");
return tx.moveCall({
target: utils_2.Helpers.transactions.createTxTarget(this.addresses.daoFeePools.packages.amm, PoolsApi.constants.moduleNames.pool, "update_fee_bps"),
typeArguments: [inputs.lpCoinType],
arguments: [
tx.object(inputs.daoFeePoolOwnerCapId), // OwnerCap
tx.object(inputs.daoFeePoolId), // DaoFeePool
tx.object(this.addresses.daoFeePools.objects.version),
tx.pure.u16(Number(inputs.newFeeBps)),
],
});
};
this.daoFeePoolUpdateFeeRecipientTx = (inputs) => {
const { tx } = inputs;
if (!this.addresses.daoFeePools)
throw new Error("dao fee pool addresses have not been set in provider");
return tx.moveCall({
target: utils_2.Helpers.transactions.createTxTarget(this.addresses.daoFeePools.packages.amm, PoolsApi.constants.moduleNames.pool, "update_fee_recipient"),
typeArguments: [inputs.lpCoinType],
arguments: [
tx.object(inputs.daoFeePoolOwnerCapId), // OwnerCap
tx.object(inputs.daoFeePoolId), // DaoFeePool
tx.object(this.addresses.daoFeePools.objects.version),
tx.pure.address(inputs.newFeeRecipient),
],
});
};
/**
* Executes a trade transaction on the specified pool.
* @param inputs An object containing the necessary inputs for the trade transaction.
* @returns A `TransactionObjectArgument` representing the trade transaction.
*/
this.daoFeePoolTradeTx = (inputs) => {
const { tx, daoFeePoolId, coinInId, coinInType, expectedCoinOutAmount, coinOutType, lpCoinType, slippage, } = inputs;
if (!this.addresses.daoFeePools)
throw new Error("dao fee pool addresses have not been set in provider");
return tx.moveCall({
target: utils_2.Helpers.transactions.createTxTarget(this.addresses.daoFeePools.packages.amm, PoolsApi.constants.moduleNames.swap, "swap_exact_in"),
typeArguments: [lpCoinType, coinInType, coinOutType],
arguments: [
tx.object(daoFeePoolId),
tx.object(this.addresses.daoFeePools.objects.version),
tx.object(this.addresses.pools.objects.poolRegistry),
tx.object(this.addresses.pools.objects.protocolFeeVault),
tx.object(this.addresses.pools.objects.treasury),
tx.object(this.addresses.pools.objects.insuranceFund),
tx.object(this.addresses.referralVault.objects.referralVault),
typeof coinInId === "string" ? tx.object(coinInId) : coinInId,
tx.pure.u64(expectedCoinOutAmount.toString()),
tx.pure.u64(pools_1.Pools.normalizeInvertSlippage(slippage)),
],
});
};
/**
* Creates a transaction object argument for depositing multiple coins into a pool.
*
* @param inputs - An object containing the necessary parameters for the deposit transaction.
* @returns A transaction object argument representing the deposit transaction.
*/
this.daoFeePoolMultiCoinDepositTx = (inputs) => {
const { tx, daoFeePoolId, coinIds, coinTypes, expectedLpRatio, lpCoinType, slippage, } = inputs;
if (!this.addresses.daoFeePools)
throw new Error("dao fee pool addresses have not been set in provider");
const poolSize = coinTypes.length;
return tx.moveCall({
target: utils_2.Helpers.transactions.createTxTarget(this.addresses.daoFeePools.packages.amm, PoolsApi.constants.moduleNames.deposit, `deposit_${poolSize}_coins`),
typeArguments: [lpCoinType, ...coinTypes],
arguments: [
tx.object(daoFeePoolId),
tx.object(this.addresses.daoFeePools.objects.version),
tx.object(this.addresses.pools.objects.poolRegistry),
tx.object(this.addresses.pools.objects.protocolFeeVault),
tx.object(this.addresses.pools.objects.treasury),
tx.object(this.addresses.pools.objects.insuranceFund),
tx.object(this.addresses.referralVault.objects.referralVault),
...coinIds.map((coinId) => typeof coinId === "string" ? tx.object(coinId) : coinId),
tx.pure.u128(expectedLpRatio.toString()),
tx.pure.u64(pools_1.Pools.normalizeInvertSlippage(slippage)),
],
});
};
/**
* Withdraws all coins from a liquidity pool.
* @param inputs - The inputs required for the transaction.
* @param inputs.tx - The transaction block.
* @param inputs.poolId - The ID of the liquidity pool.
* @param inputs.lpCoinId - The ID of the LP coin.
* @param inputs.lpCoinType - The type of the LP coin.
* @param inputs.coinTypes - An array of coin types.
* @returns An array of transaction objects.
*/
this.daoFeePoolAllCoinWithdrawTx = (inputs) => {
const { tx, daoFeePoolId, lpCoinId, coinTypes, lpCoinType } = inputs;
if (!this.addresses.daoFeePools)
throw new Error("dao fee pool addresses have not been set in provider");
const poolSize = coinTypes.length;
return tx.moveCall({
target: utils_2.Helpers.transactions.createTxTarget(this.addresses.daoFeePools.packages.amm, PoolsApi.constants.moduleNames.withdraw, `all_coin_withdraw_${poolSize}_coins`),
typeArguments: [lpCoinType, ...coinTypes],
arguments: [
tx.object(daoFeePoolId),
tx.object(this.addresses.daoFeePools.objects.version),
tx.object(this.addresses.pools.objects.poolRegistry),
tx.object(this.addresses.pools.objects.protocolFeeVault),
tx.object(this.addresses.pools.objects.treasury),
tx.object(this.addresses.pools.objects.insuranceFund),
tx.object(this.addresses.referralVault.objects.referralVault),
typeof lpCoinId === "string" ? tx.object(lpCoinId) : lpCoinId,
],
});
};
// =========================================================================
// Transaction Builders
// =========================================================================
/**
* Fetches a transaction block for trading in a pool.
* @async
* @param {SuiAddress} inputs.walletAddress - The wallet address of the user trading in the pool.
* @param {Pool} inputs.pool - The pool to trade in.
* @param {CoinType} inputs.coinInType - The coin type of the coin being traded in.
* @param {Balance} inputs.coinInAmount - The amount of the coin being traded in.
* @param {CoinType} inputs.coinOutType - The coin type of the coin being traded out.
* @param {Slippage} inputs.slippage - The slippage of the trade.
* @param {SuiAddress} [inputs.referrer] - The referrer of the trade.
* @param {boolean} [inputs.isSponsoredTx] - Whether the transaction is sponsored.
* @returns {Promise<Transaction>} A promise that resolves to the fetched transaction block.
*/
this.fetchBuildTradeTx = (inputs) => __awaiter(this, void 0, void 0, function* () {
const { walletAddress, pool, coinInAmount, coinInType, coinOutType, slippage, referrer, isSponsoredTx, } = inputs;
const tx = new transactions_1.Transaction();
tx.setSender(walletAddress);
if (referrer)
this.Provider.ReferralVault().updateReferrerTx({
tx,
referrer,
});
const amountOut = pool.getTradeAmountOut({
coinInAmount,
coinInType,
coinOutType,
referral: referrer !== undefined,
});
const coinInId = yield this.Provider.Coin().fetchCoinWithAmountTx({
tx,
walletAddress,
coinType: coinInType,
coinAmount: coinInAmount,
isSponsoredTx,
});
if (pool.pool.daoFeePoolObject) {
const coinOutId = this.daoFeePoolTradeTx({
tx,
coinInId,
daoFeePoolId: pool.pool.daoFeePoolObject.objectId,
expectedCoinOutAmount: amountOut,
lpCoinType: pool.pool.lpCoinType,
coinInType,
coinOutType,
slippage,
});
tx.transferObjects([coinOutId], walletAddress);
}
else {
this.tradeTx({
tx,
coinInId,
poolId: pool.pool.objectId,
expectedCoinOutAmount: amountOut,
lpCoinType: pool.pool.lpCoinType,
coinInType,
coinOutType,
slippage,
withTransfer: true,
});
}
return tx;
});
this.fetchAddTradeTx = (inputs) => __awaiter(this, void 0, void 0, function* () {
const { tx, coinInId, coinInAmount, coinInType, coinOutType, slippage, pool, referrer, } = inputs;
const amountOut = pool.getTradeAmountOut({
coinInAmount,
coinInType,
coinOutType,
referral: referrer !== undefined,
});
return this.tradeTx({
tx,
coinInId,
poolId: pool.pool.objectId,
expectedCoinOutAmount: amountOut,
lpCoinType: pool.pool.lpCoinType,
coinInType,
coinOutType,
slippage,
});
});
/**
* Fetches a transaction block for depositing in a pool.
* @async
* @param {SuiAddress} inputs.walletAddress - The wallet address of the user depositing in the pool.
* @param {Pool} inputs.pool - The pool to deposit in.
* @param {CoinsToBalance} inputs.amountsIn - The amounts of coins being deposited.
* @param {Slippage} inputs.slippage - The slippage of the deposit.
* @param {SuiAddress} [inputs.referrer] - The referrer of the deposit.
* @param {boolean} [inputs.isSponsoredTx] - Whether the transaction is sponsored.
* @returns {Promise<Transaction>} A promise that resolves to the fetched transaction block.
*/
this.fetchBuildDepositTx = (inputs) => __awaiter(this, void 0, void 0, function* () {
const { walletAddress, pool, amountsIn, slippage, referrer, isSponsoredTx, } = inputs;
const tx = new transactions_1.Transaction();
tx.setSender(walletAddress);
if (referrer)
this.Provider.ReferralVault().updateReferrerTx({
tx,
referrer,
});
const { coins: coinTypes, balances: coinAmounts } = coin_1.Coin.coinsAndBalancesOverZero(amountsIn);
const { lpRatio } = pool.getDepositLpAmountOut({
amountsIn,
referral: referrer !== undefined,
});
// TODO: move this somewhere else and into its own func
const expectedLpRatio = casting_1.Casting.numberToFixedBigInt(lpRatio);
const coinIds = yield this.Provider.Coin().fetchCoinsWithAmountTx(Object.assign(Object.assign({}, inputs), { tx,
coinTypes,
coinAmounts,
isSponsoredTx }));
if (pool.pool.daoFeePoolObject) {
const lpCoinId = this.daoFeePoolMultiCoinDepositTx({
tx,
daoFeePoolId: pool.pool.daoFeePoolObject.objectId,
lpCoinType: pool.pool.lpCoinType,
coinIds,
coinTypes,
expectedLpRatio,
slippage,
});
tx.transferObjects([lpCoinId], walletAddress);
}
else {
this.multiCoinDepositTx({
tx,
poolId: pool.pool.objectId,
lpCoinType: pool.pool.lpCoinType,
coinIds,
coinTypes,
expectedLpRatio,
slippage,
withTransfer: true,
});
}
return tx;
});
/**
* Fetches a transaction block for withdrawing from a pool.
* @async
* @param {SuiAddress} inputs.walletAddress - The wallet address of the user withdrawing from the pool.
* @param {Pool} inputs.pool - The pool to withdraw from.
* @param {CoinsToBalance} inputs.amountsOutDirection - The amounts of coins being withdrawn.
* @param {Balance} inputs.lpCoinAmount - The amount of LP tokens being withdrawn.
* @param {Slippage} inputs.slippage - The slippage of the withdrawal.
* @param {SuiAddress} [inputs.referrer] - The referrer of the withdrawal.
* @returns {Promise<Transaction>} A promise that resolves to the fetched transaction block.
*/
this.fetchBuildWithdrawTx = (inputs) => __awaiter(this, void 0, void 0, function* () {
const { walletAddress, pool, amountsOutDirection, lpCoinAmount, slippage, referrer, } = inputs;
const tx = new transactions_1.Transaction();
tx.setSender(walletAddress);
if (referrer)
this.Provider.ReferralVault().updateReferrerTx({
tx,
referrer,
});
const lpRatio = pool.getMultiCoinWithdrawLpRatio({
lpCoinAmountIn: lpCoinAmount,
});
const amountsOut = pool.getWithdrawAmountsOut({
lpRatio,
amountsOutDirection,
referral: referrer !== undefined,
});
const { coins: coinTypes, balances: coinAmounts } = coin_1.Coin.coinsAndBalancesOverZero(amountsOut);
const lpCoinId = yield this.Provider.Coin().fetchCoinWithAmountTx({
tx,
walletAddress,
coinType: pool.pool.lpCoinType,
coinAmount: lpCoinAmount,
});
if (pool.pool.daoFeePoolObject) {
// TODO: handle dao fee pool
// TODO: handle transfer
}
else {
this.multiCoinWithdrawTx({
tx,
poolId: pool.pool.objectId,
lpCoinType: pool.pool.lpCoinType,
expectedAmountsOut: coinAmounts,
coinTypes: coinTypes,
lpCoinId,
slippage,
withTransfer: true,
});
}
return tx;
});
/**
* Fetches a transaction block that withdraws all coins from a pool in exchange for the corresponding LP tokens.
* @param inputs An object containing the wallet address, pool, LP coin amount, and optional referrer.
* @returns A promise that resolves to a Transaction object.
*/
this.fetchBuildAllCoinWithdrawTx = (inputs) => __awaiter(this, void 0, void 0, function* () {
const { walletAddress, pool, lpCoinAmount, referrer } = inputs;
const tx = new transactions_1.Transaction();
tx.setSender(walletAddress);
if (referrer)
this.Provider.ReferralVault().updateReferrerTx({
tx,
referrer,
});
const lpCoinId = yield this.Provider.Coin().fetchCoinWithAmountTx({
tx,
walletAddress,
coinType: pool.pool.lpCoinType,
coinAmount: lpCoinAmount,
});
const coinTypes = Object.keys(pool.pool.coins);
if (pool.pool.daoFeePoolObject) {
const withdrawnCoinIds = this.daoFeePoolAllCoinWithdrawTx({
tx,
daoFeePoolId: pool.pool.daoFeePoolObject.objectId,
lpCoinType: pool.pool.lpCoinType,
coinTypes,
lpCoinId,
});
tx.transferObjects(coinTypes.map((_, index) => withdrawnCoinIds[index]), walletAddress);
}
else {
this.allCoinWithdrawTx({
tx,
poolId: pool.pool.objectId,
lpCoinType: pool.pool.lpCoinType,
coinTypes,
lpCoinId,
withTransfer: true,
});
}
return tx;
});
/**
* Builds a transaction block for publishing an LP coin.
* @param inputs - The input parameters for the transaction.
* @returns The built transaction block.
*/
this.buildPublishLpCoinTx = (inputs) => {
const { lpCoinDecimals } = inputs;
const tx = new transactions_1.Transaction();
tx.setSender(inputs.walletAddress);
const upgradeCap = this.publishLpCoinTx({ tx, lpCoinDecimals });
tx.transferObjects([upgradeCap], inputs.walletAddress);
return tx;
};
this.buildDaoFeePoolUpdateFeeBpsTx = utils_2.Helpers.transactions.createBuildTxFunc(this.daoFeePoolUpdateFeeBpsTx);
this.buildDaoFeePoolUpdateFeeRecipientTx = utils_2.Helpers.transactions.createBuildTxFunc(this.daoFeePoolUpdateFeeRecipientTx);
// =========================================================================
// Event Types
// =========================================================================
this.tradeEventType = () => eventsApiHelpers_1.EventsApiHelpers.createEventType(this.addresses.pools.packages.events, PoolsApi.constants.moduleNames.events, PoolsApi.constants.eventNames.swap);
this.depositEventType = () => eventsApiHelpers_1.EventsApiHelpers.createEventType(this.addresses.pools.packages.events, PoolsApi.constants.moduleNames.events, PoolsApi.constants.eventNames.deposit);
this.withdrawEventType = () => eventsApiHelpers_1.EventsApiHelpers.createEventType(this.addresses.pools.packages.events, PoolsApi.constants.moduleNames.events, PoolsApi.constants.eventNames.withdraw);
this.tradeV2EventType = () => eventsApiHelpers_1.EventsApiHelpers.createEventType(this.addresses.pools.packages.eventsV2, PoolsApi.constants.moduleNames.events, PoolsApi.constants.eventNames.swapV2);
this.depositV2EventType = () => eventsApiHelpers_1.EventsApiHelpers.createEventType(this.addresses.pools.packages.eventsV2, PoolsApi.constants.moduleNames.events, PoolsApi.constants.eventNames.depositV2);
this.withdrawV2EventType = () => eventsApiHelpers_1.EventsApiHelpers.createEventType(this.addresses.pools.packages.eventsV2, PoolsApi.constants.moduleNames.events, PoolsApi.constants.eventNames.withdrawV2);
const pools = Provider.addresses.pools;
const referralVault = Provider.addresses.referralVault;
const daoFeePools = Provider.addresses.daoFeePools;
if (!pools || !referralVault)
throw new Error("not all required addresses have been set in provider");
this.addresses = {
pools,
referralVault,
daoFeePools,
};
this.objectTypes = {
pool: `${pools.packages.events}::pool::Pool`,
daoFeePool: daoFeePools
? `${daoFeePools.packages.amm}::pool::DaoFeePool`
: undefined,
daoFeePoolOwnerCap: daoFeePools
? `${daoFeePools.packages.amm}::pool::OwnerCap`
: undefined,
};
this.eventTypes = {
trade: this.tradeEventType(),
deposit: this.depositEventType(),
withdraw: this.withdrawEventType(),
tradeV2: this.tradeV2EventType(),
depositV2: this.depositV2EventType(),
withdrawV2: this.withdrawV2EventType(),
};
this.moveErrors = Object.assign({ [this.addresses.pools.packages.amm]: {
[PoolsApi.constants.moduleNames.pool]: {
/// A user provides a input that should be between 0 and `FIXED_ONE` but isn't.
0: "Flatness Not Normalized",
/// A user attempts to create a Pool with a `flatness` parameter we do not support yet.
1: "Flatness Not Supported",
/// A user attempts to create a pool with weights that don't sum to `FIXED_ONE`.
2: "Weights Not Normalized",
/// A user attempts to create a Pool with an individual weight outside of the
/// range [MIN_WEIGHT, MAX_WEIGHT].
3: "Invalid Weight",
/// A user attempts to create a Pool with an individual fee outside of the
/// range [MIN_FEE, MAX_FEE].
4: "Invalid Fee",
/// A user provides an input vector (with length m != n) for a pool of size n.
5: "Bad Vector Length",
/// A user tries to create a Pool but provides an initial deposit that equates to less than
/// `MIN_LP_SUPPLY` worth of LP Coins.
6: "Not Enough Initial Liquidity",
/// A user attempts to create a Pool with an LP `TreasuryCap` that has already minted Coins.
7: "Non Zero Total Supply",
/// A user attempts to interact with the Pool and specifies a type that isn't in the Pool.
8: "Bad Type",
/// A user attempts to create a pool with invalid decimal scalars
9: "Bad Decimals",
/// A user attempts to create a pool with type names which are not sorted
10: "Not Sorted",
},
[PoolsApi.constants.moduleNames.poolRegistry]: {
/// A user tries to create a Pool and the generic parameters of `create_pool_n_coins` were
/// provided in nonlexicographical order.
60: "Not Sorted",
/// A user tries to create a Pool with exact parameters as an already active Pool.
61: "Duplicate Pool",
/// A user tries to upgrade the `PoolRegistry` to a value
62: "Invalid Upgrade",
},
[PoolsApi.constants.moduleNames.deposit]: {
/// A user attempts to perform a `deposit` with an older contract.
20: "Invalid Protocol Version",
/// A user attempts to perform `deposit-n-coins` on a Pool with a size `m` < `n`.
21: "Invalid Pool Size",
/// A user attempts to perform a deposit and provides a coin with a value of zero.
22: "Zero Value",
// A user calls `deposit_n_coins` or `all_coin_deposit_n_coins` and provides the same generic
// at least twice.
23: "Duplicate Types",
},
[PoolsApi.constants.moduleNames.poolFactory]: {
/// A user attempts to create a pool on an older contract.
10: "Invalid Protocol Version",
/// A user attempts to create a Pool and provides a coin with a value of zero.
11: "Zero Value",
},
[PoolsApi.constants.moduleNames.price]: {
/// A user attempts to query spot/oracle price using an old contract.
10: "Invalid Protocol Version",
},
[PoolsApi.constants.moduleNames.swap]: {
/// A user attempts to perform a `swap` with an older contract.
40: "Invalid Protocol Version",
/// A user attempts to perform `multi-swap-exact-in/out-n-to-m` on a Pool with a size
/// `s` < `n` + `m`.
41: "Invalid Pool Size",
/// A user attempts to perform swap and providing provides a coin with a
/// value of zero.
42: "Zero Value",
/// A user attempts to perform a multi-coin withdraw and provides an `amounts_out`
/// vector whose length does
43: "Bad Vector Length",
/// A user attempts to swap attempts to swap `Coin<CI>` for `amount_out` of `Coin<CO>`
/// but its value is insufficient.
44: "Insufficient Coin In",
// A user calls `multi_swap_exact_in_1_to_n` or `multi_swap_exact_out_1_to_n` and provides the same
// generic at least twice.
45: "Duplicate Types",
/// Something went wrong with the internal calculations
46: "Internal Error",
/// An external app is trying to call authorized functions without permission.
47: "Not Authorized",
},
[PoolsApi.constants.moduleNames.withdraw]: {
/// A user attempts to perform a `withdraw` with an older contract.
30: "Invalid Protocol Version",
/// A user attempts to perform `withdraw-n-coins` on a Pool with a size `m` < `n`.
31: "Invalid PoolSize",
/// A user attempts to perform a withdraw and provides an LP coin with a value of zero.
32: "Zero Value",
/// A user attempts to perform a multi-coin withdraw and provides an `amounts_out`
/// vector whose length does
33: "Bad Vector Length",
// A user calls `withdraw_n_coins` or `all_coin_withdraw_n_coins` and provides the same generic
// at least twice.
34: "Duplicate Types",
},
[PoolsApi.constants.moduleNames.math]: {
// TODO: change error code in move
/// A user tries to create a Pool that would result in the Pool's invariant equalling zero.
// 51: "ZeroInvariant",
/// A user tries to perform an action with the Pool that results in too much slippage.
51: "Slippage",
/// A user tries to perform a swap that would result in more than `MAX_SWAP_AMOUNT_IN` worth of
/// one of the Pool's coins entering the Pool.
52: "Invalid Swap Amount In",
/// A user tries to perform a swap that would result in more than `MAX_SWAP_AMOUNT_OUT` worth of
/// one of the Pool's coins exiting the Pool.
53: "Invalid Swap Amount Out",
/// A user tries to perform a `swap_exact_out` with a value for `amount_out` that equates to
/// zero amount of `Coin<CI>`.
54: "Zero Amount In",
/// A user tries to perform a `swap_exact_in` with an amount of `Coin<CI>` that equates to
/// zero amount of `Coin<CO>`.
55: "Zero Amount Out",
/// A user tries to deposit into a Pool with a deposit that is worth zero LP coins.
56: "Zero Lp Out",
/// A user tries to invest with an lp ratio of 0
57: "Zero Lp Ratio",
},
[PoolsApi.constants.moduleNames.geometricMeanCalculations]: {},
[PoolsApi.constants.moduleNames.stableCalculations]: {},
} }, (this.addresses.daoFeePools
? {
[this.addresses.daoFeePools.packages.amm]: {
version: {
/// A user tried to interact with an old contract.
0: "Invalid Version",
/// `init_package_version` has been called outside of this packages `init` function.
1: "Version Object Already Created",
},
},
}
: {}));
}
}
exports.PoolsApi = PoolsApi;
// =========================================================================
// Constants
// =========================================================================
/**
* Constants used in the pools API.
*/
PoolsApi.constants = {
moduleNames: {
interface: "amm_interface",
pool: "pool",
swap: "swap",
deposit: "deposit",
withdraw: "withdraw",
events: "events",
poolRegistry: "pool_registry",
routerWrapper: "router",
poolFactory: "pool_factory",
math: "math",
geometricMeanCalculations: "geometric_mean_calculations",
stableCalculations: "stable_calculations",
price: "price",
},
eventNames: {
swap: "SwapEvent",
deposit: "DepositEvent",
withdraw: "WithdrawEvent",
swapV2: "SwapEventV2",
depositV2: "DepositEventV2",
withdrawV2: "WithdrawEventV2",
},
defaultLpCoinIconImageUrl: "https://aftermath.finance/coins/lp/af_lp.svg",
};