@mercurial-finance/dynamic-amm-sdk
Version:
Mercurial Vaults SDK is a typescript library that allows you to interact with Mercurial v2's AMM.
946 lines (945 loc) • 108 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const anchor_1 = require("@coral-xyz/anchor");
const web3_js_1 = require("@solana/web3.js");
const spl_token_1 = require("@solana/spl-token");
const vault_sdk_1 = __importStar(require("@mercurial-finance/vault-sdk"));
const m3m3_1 = __importStar(require("@meteora-ag/m3m3"));
const invariant_1 = __importDefault(require("invariant"));
const types_1 = require("./types");
const constants_1 = require("./constants");
const curve_1 = require("./curve");
const constant_product_1 = require("./curve/constant-product");
const utils_1 = require("./utils");
const bytes_1 = require("@coral-xyz/anchor/dist/cjs/utils/bytes");
const bn_sqrt_1 = __importDefault(require("bn-sqrt"));
const getAllPoolState = async (poolMints, program) => {
const poolStates = (await (0, utils_1.chunkedFetchMultiplePoolAccount)(program, poolMints));
(0, invariant_1.default)(poolStates.length === poolMints.length, 'Some of the pool state not found');
const poolLpMints = poolStates.map((poolState) => poolState.lpMint);
const lpMintAccounts = await (0, utils_1.chunkedGetMultipleAccountInfos)(program.provider.connection, poolLpMints);
return poolStates.map((poolState, idx) => {
const lpMintAccount = lpMintAccounts[idx];
(0, invariant_1.default)(lpMintAccount, constants_1.ERROR.INVALID_ACCOUNT);
const lpSupply = new anchor_1.BN(spl_token_1.MintLayout.decode(lpMintAccount.data).supply.toString());
return { ...poolState, lpSupply };
});
};
const getPoolState = async (poolMint, program) => {
const poolState = (await program.account.pool.fetchNullable(poolMint));
(0, invariant_1.default)(poolState, `Pool ${poolMint.toBase58()} not found`);
const account = await program.provider.connection.getTokenSupply(poolState.lpMint);
(0, invariant_1.default)(account.value.amount, constants_1.ERROR.INVALID_ACCOUNT);
return { ...poolState, lpSupply: new anchor_1.BN(account.value.amount) };
};
const getFeeVaultState = async (publicKey, program) => {
const feeVaultState = await program.account.feeVault.fetchNullable(publicKey);
return feeVaultState;
};
const decodeAccountTypeMapper = (type) => {
const decoder = {
[types_1.AccountType.VAULT_A_RESERVE]: (accountData) => new anchor_1.BN(spl_token_1.AccountLayout.decode(accountData).amount.toString()),
[types_1.AccountType.VAULT_B_RESERVE]: (accountData) => new anchor_1.BN(spl_token_1.AccountLayout.decode(accountData).amount.toString()),
[types_1.AccountType.VAULT_A_LP]: (accountData) => new anchor_1.BN(spl_token_1.MintLayout.decode(accountData).supply.toString()),
[types_1.AccountType.VAULT_B_LP]: (accountData) => new anchor_1.BN(spl_token_1.MintLayout.decode(accountData).supply.toString()),
[types_1.AccountType.POOL_VAULT_A_LP]: (accountData) => new anchor_1.BN(spl_token_1.AccountLayout.decode(accountData).amount.toString()),
[types_1.AccountType.POOL_VAULT_B_LP]: (accountData) => new anchor_1.BN(spl_token_1.AccountLayout.decode(accountData).amount.toString()),
[types_1.AccountType.POOL_LP_MINT]: (accountData) => new anchor_1.BN(spl_token_1.MintLayout.decode(accountData).supply.toString()),
[types_1.AccountType.SYSVAR_CLOCK]: (accountData) => new anchor_1.BN(accountData.readBigInt64LE(32).toString()),
};
return decoder[type];
};
const getAccountsBuffer = async (connection, accountsToFetch) => {
const accounts = await (0, utils_1.chunkedGetMultipleAccountInfos)(connection, accountsToFetch.map((account) => account.pubkey));
return accountsToFetch.reduce((accMap, account, index) => {
const accountInfo = accounts[index];
accMap.set(account.pubkey.toBase58(), {
type: account.type,
account: accountInfo,
});
return accMap;
}, new Map());
};
const deserializeAccountsBuffer = (accountInfoMap) => {
return Array.from(accountInfoMap).reduce((accValue, [publicKey, { type, account }]) => {
const decodedAccountInfo = decodeAccountTypeMapper(type);
accValue.set(publicKey, decodedAccountInfo(account.data));
return accValue;
}, new Map());
};
class AmmImpl {
address;
program;
vaultProgram;
tokenAMint;
tokenBMint;
poolState;
poolInfo;
vaultA;
vaultB;
accountsInfo;
swapCurve;
depegAccounts;
opt = {
cluster: 'mainnet-beta',
};
constructor(address, program, vaultProgram, tokenAMint, tokenBMint, poolState, poolInfo, vaultA, vaultB, accountsInfo, swapCurve, depegAccounts, opt) {
this.address = address;
this.program = program;
this.vaultProgram = vaultProgram;
this.tokenAMint = tokenAMint;
this.tokenBMint = tokenBMint;
this.poolState = poolState;
this.poolInfo = poolInfo;
this.vaultA = vaultA;
this.vaultB = vaultB;
this.accountsInfo = accountsInfo;
this.swapCurve = swapCurve;
this.depegAccounts = depegAccounts;
this.opt = {
...this.opt,
...opt,
};
}
static async createConfig(connection, payer, tradeFeeBps, protocolFeeBps, vaultConfigKey, activationDuration, poolCreatorAuthority, activationType, partnerFeeNumerator, opt) {
const { ammProgram } = (0, utils_1.createProgram)(connection, opt?.programId);
const configs = await this.getFeeConfigurations(connection, opt);
let index = 0;
while (true) {
const configPda = (0, utils_1.deriveConfigPda)(new anchor_1.BN(index), ammProgram.programId);
if (!configs.find((c) => c.publicKey.equals(configPda))) {
const createConfigTx = await ammProgram.methods
.createConfig({
// Default fee denominator is 100_000
tradeFeeNumerator: tradeFeeBps.mul(new anchor_1.BN(10)),
protocolTradeFeeNumerator: protocolFeeBps.mul(new anchor_1.BN(10)),
vaultConfigKey,
activationDuration,
poolCreatorAuthority,
index: new anchor_1.BN(index),
activationType,
partnerFeeNumerator,
})
.accounts({
config: configPda,
systemProgram: web3_js_1.SystemProgram.programId,
admin: payer,
})
.transaction();
return new web3_js_1.Transaction({
feePayer: payer,
...(await ammProgram.provider.connection.getLatestBlockhash(ammProgram.provider.connection.commitment)),
}).add(createConfigTx);
}
else {
index++;
}
}
}
static async searchPoolsByToken(connection, tokenMint) {
const { ammProgram } = (0, utils_1.createProgram)(connection);
const [poolsForTokenAMint, poolsForTokenBMint] = await Promise.all([
ammProgram.account.pool.all([
{
memcmp: {
offset: 8 + 32,
bytes: tokenMint.toBase58(),
},
},
]),
ammProgram.account.pool.all([
{
memcmp: {
offset: 8 + 32 + 32,
bytes: tokenMint.toBase58(),
},
},
]),
]);
return [...poolsForTokenAMint, ...poolsForTokenBMint];
}
async partnerClaimFees(partnerAddress, maxAmountA, maxAmountB) {
let preInstructions = [];
const [[partnerTokenA, createPartnerTokenAIx], [partnerTokenB, createPartnerTokenBIx]] = await this.createATAPreInstructions(partnerAddress, [this.poolState.tokenAMint, this.poolState.tokenBMint]);
createPartnerTokenAIx && preInstructions.push(createPartnerTokenAIx);
createPartnerTokenBIx && preInstructions.push(createPartnerTokenBIx);
const claimTx = await this.program.methods
.partnerClaimFee(maxAmountA, maxAmountB)
.accounts({
pool: this.address,
aVaultLp: this.poolState.aVaultLp,
protocolTokenAFee: this.poolState.protocolTokenAFee,
protocolTokenBFee: this.poolState.protocolTokenBFee,
partnerTokenA,
partnerTokenB,
tokenProgram: spl_token_1.TOKEN_PROGRAM_ID,
partnerAuthority: partnerAddress,
})
.preInstructions(preInstructions)
.transaction();
return new web3_js_1.Transaction({
feePayer: partnerAddress,
...(await this.program.provider.connection.getLatestBlockhash(this.program.provider.connection.commitment)),
}).add(claimTx);
}
static async createCustomizablePermissionlessConstantProductPool(connection, payer, tokenAMint, tokenBMint, tokenAAmount, tokenBAmount, customizableParams, opt) {
const { vaultProgram, ammProgram } = (0, utils_1.createProgram)(connection, opt?.programId);
const [{ vaultPda: aVault, tokenVaultPda: aTokenVault, lpMintPda: aLpMintPda }, { vaultPda: bVault, tokenVaultPda: bTokenVault, lpMintPda: bLpMintPda },] = [(0, vault_sdk_1.getVaultPdas)(tokenAMint, vaultProgram.programId), (0, vault_sdk_1.getVaultPdas)(tokenBMint, vaultProgram.programId)];
const [aVaultAccount, bVaultAccount] = await Promise.all([
vaultProgram.account.vault.fetchNullable(aVault),
vaultProgram.account.vault.fetchNullable(bVault),
]);
let aVaultLpMint = aLpMintPda;
let bVaultLpMint = bLpMintPda;
let preInstructions = [];
if (!aVaultAccount) {
const createVaultAIx = await vault_sdk_1.default.createPermissionlessVaultInstruction(connection, payer, tokenAMint);
createVaultAIx && preInstructions.push(createVaultAIx);
}
else {
aVaultLpMint = aVaultAccount.lpMint; // Old vault doesn't have lp mint pda
}
if (!bVaultAccount) {
const createVaultBIx = await vault_sdk_1.default.createPermissionlessVaultInstruction(connection, payer, tokenBMint);
createVaultBIx && preInstructions.push(createVaultBIx);
}
else {
bVaultLpMint = bVaultAccount.lpMint; // Old vault doesn't have lp mint pda
}
const poolPubkey = (0, utils_1.deriveCustomizablePermissionlessConstantProductPoolAddress)(tokenAMint, tokenBMint, ammProgram.programId);
const [lpMint] = web3_js_1.PublicKey.findProgramAddressSync([Buffer.from(constants_1.SEEDS.LP_MINT), poolPubkey.toBuffer()], ammProgram.programId);
const [[aVaultLp], [bVaultLp]] = [
web3_js_1.PublicKey.findProgramAddressSync([aVault.toBuffer(), poolPubkey.toBuffer()], ammProgram.programId),
web3_js_1.PublicKey.findProgramAddressSync([bVault.toBuffer(), poolPubkey.toBuffer()], ammProgram.programId),
];
const [[payerTokenA, createPayerTokenAIx], [payerTokenB, createPayerTokenBIx]] = await Promise.all([
(0, utils_1.getOrCreateATAInstruction)(tokenAMint, payer, connection),
(0, utils_1.getOrCreateATAInstruction)(tokenBMint, payer, connection),
]);
createPayerTokenAIx && preInstructions.push(createPayerTokenAIx);
createPayerTokenBIx && preInstructions.push(createPayerTokenBIx);
const [[protocolTokenAFee], [protocolTokenBFee]] = [
web3_js_1.PublicKey.findProgramAddressSync([Buffer.from(constants_1.SEEDS.FEE), tokenAMint.toBuffer(), poolPubkey.toBuffer()], ammProgram.programId),
web3_js_1.PublicKey.findProgramAddressSync([Buffer.from(constants_1.SEEDS.FEE), tokenBMint.toBuffer(), poolPubkey.toBuffer()], ammProgram.programId),
];
const payerPoolLp = await (0, utils_1.getAssociatedTokenAccount)(lpMint, payer);
if (tokenAMint.equals(spl_token_1.NATIVE_MINT)) {
preInstructions = preInstructions.concat((0, utils_1.wrapSOLInstruction)(payer, payerTokenA, BigInt(tokenAAmount.toString())));
}
if (tokenBMint.equals(spl_token_1.NATIVE_MINT)) {
preInstructions = preInstructions.concat((0, utils_1.wrapSOLInstruction)(payer, payerTokenB, BigInt(tokenBAmount.toString())));
}
const [mintMetadata, _mintMetadataBump] = (0, utils_1.deriveMintMetadata)(lpMint);
const createPermissionlessPoolTx = await ammProgram.methods
.initializeCustomizablePermissionlessConstantProductPool(tokenAAmount, tokenBAmount, customizableParams)
.accounts({
pool: poolPubkey,
tokenAMint,
tokenBMint,
aVault,
bVault,
aVaultLpMint,
bVaultLpMint,
aVaultLp,
bVaultLp,
lpMint,
payerTokenA,
payerTokenB,
protocolTokenAFee,
protocolTokenBFee,
payerPoolLp,
aTokenVault,
bTokenVault,
mintMetadata,
metadataProgram: constants_1.METAPLEX_PROGRAM,
payer,
rent: web3_js_1.SYSVAR_RENT_PUBKEY,
vaultProgram: vaultProgram.programId,
tokenProgram: spl_token_1.TOKEN_PROGRAM_ID,
systemProgram: web3_js_1.SystemProgram.programId,
associatedTokenProgram: spl_token_1.ASSOCIATED_TOKEN_PROGRAM_ID,
})
.preInstructions(preInstructions)
.transaction();
const latestBlockHash = await ammProgram.provider.connection.getLatestBlockhash(ammProgram.provider.connection.commitment);
return new web3_js_1.Transaction({
feePayer: payer,
...latestBlockHash,
}).add(createPermissionlessPoolTx);
}
static async createPermissionlessConstantProductPoolWithConfig2(connection, payer, tokenAMint, tokenBMint, tokenAAmount, tokenBAmount, config, opt) {
const { vaultProgram, ammProgram } = (0, utils_1.createProgram)(connection, opt?.programId);
const [{ vaultPda: aVault, tokenVaultPda: aTokenVault, lpMintPda: aLpMintPda }, { vaultPda: bVault, tokenVaultPda: bTokenVault, lpMintPda: bLpMintPda },] = [(0, vault_sdk_1.getVaultPdas)(tokenAMint, vaultProgram.programId), (0, vault_sdk_1.getVaultPdas)(tokenBMint, vaultProgram.programId)];
const [aVaultAccount, bVaultAccount] = await Promise.all([
vaultProgram.account.vault.fetchNullable(aVault),
vaultProgram.account.vault.fetchNullable(bVault),
]);
let aVaultLpMint = aLpMintPda;
let bVaultLpMint = bLpMintPda;
let preInstructions = [];
if (!aVaultAccount) {
const createVaultAIx = await vault_sdk_1.default.createPermissionlessVaultInstruction(connection, payer, tokenAMint);
createVaultAIx && preInstructions.push(createVaultAIx);
}
else {
aVaultLpMint = aVaultAccount.lpMint; // Old vault doesn't have lp mint pda
}
if (!bVaultAccount) {
const createVaultBIx = await vault_sdk_1.default.createPermissionlessVaultInstruction(connection, payer, tokenBMint);
createVaultBIx && preInstructions.push(createVaultBIx);
}
else {
bVaultLpMint = bVaultAccount.lpMint; // Old vault doesn't have lp mint pda
}
const poolPubkey = (0, utils_1.derivePoolAddressWithConfig)(tokenAMint, tokenBMint, config, ammProgram.programId);
const [lpMint] = web3_js_1.PublicKey.findProgramAddressSync([Buffer.from(constants_1.SEEDS.LP_MINT), poolPubkey.toBuffer()], ammProgram.programId);
const [[aVaultLp], [bVaultLp]] = [
web3_js_1.PublicKey.findProgramAddressSync([aVault.toBuffer(), poolPubkey.toBuffer()], ammProgram.programId),
web3_js_1.PublicKey.findProgramAddressSync([bVault.toBuffer(), poolPubkey.toBuffer()], ammProgram.programId),
];
const [[payerTokenA, createPayerTokenAIx], [payerTokenB, createPayerTokenBIx]] = await Promise.all([
(0, utils_1.getOrCreateATAInstruction)(tokenAMint, payer, connection),
(0, utils_1.getOrCreateATAInstruction)(tokenBMint, payer, connection),
]);
createPayerTokenAIx && preInstructions.push(createPayerTokenAIx);
createPayerTokenBIx && preInstructions.push(createPayerTokenBIx);
const [[protocolTokenAFee], [protocolTokenBFee]] = [
web3_js_1.PublicKey.findProgramAddressSync([Buffer.from(constants_1.SEEDS.FEE), tokenAMint.toBuffer(), poolPubkey.toBuffer()], ammProgram.programId),
web3_js_1.PublicKey.findProgramAddressSync([Buffer.from(constants_1.SEEDS.FEE), tokenBMint.toBuffer(), poolPubkey.toBuffer()], ammProgram.programId),
];
const payerPoolLp = await (0, utils_1.getAssociatedTokenAccount)(lpMint, payer);
if (tokenAMint.equals(spl_token_1.NATIVE_MINT)) {
preInstructions = preInstructions.concat((0, utils_1.wrapSOLInstruction)(payer, payerTokenA, BigInt(tokenAAmount.toString())));
}
if (tokenBMint.equals(spl_token_1.NATIVE_MINT)) {
preInstructions = preInstructions.concat((0, utils_1.wrapSOLInstruction)(payer, payerTokenB, BigInt(tokenBAmount.toString())));
}
const [mintMetadata, _mintMetadataBump] = (0, utils_1.deriveMintMetadata)(lpMint);
const activationPoint = opt?.activationPoint || null;
const lpAmount = (0, bn_sqrt_1.default)(tokenAAmount.mul(tokenBAmount));
const { userLockAmount, feeWrapperLockAmount } = (0, utils_1.calculateLockAmounts)(lpAmount, opt?.stakeLiquidity?.ratio);
const createPoolPostInstructions = [];
if (opt?.lockLiquidity && userLockAmount.gt(new anchor_1.BN(0))) {
const [lockEscrowPK] = (0, utils_1.deriveLockEscrowPda)(poolPubkey, payer, ammProgram.programId);
const createLockEscrowIx = await ammProgram.methods
.createLockEscrow()
.accounts({
pool: poolPubkey,
lockEscrow: lockEscrowPK,
owner: payer,
lpMint,
payer,
systemProgram: web3_js_1.SystemProgram.programId,
})
.instruction();
createPoolPostInstructions.push(createLockEscrowIx);
const [escrowAta, createEscrowAtaIx] = await (0, utils_1.getOrCreateATAInstruction)(lpMint, lockEscrowPK, connection, payer);
createEscrowAtaIx && createPoolPostInstructions.push(createEscrowAtaIx);
const lockIx = await ammProgram.methods
.lock(userLockAmount)
.accounts({
pool: poolPubkey,
lockEscrow: lockEscrowPK,
owner: payer,
lpMint,
sourceTokens: payerPoolLp,
escrowVault: escrowAta,
tokenProgram: spl_token_1.TOKEN_PROGRAM_ID,
aVault,
bVault,
aVaultLp,
bVaultLp,
aVaultLpMint,
bVaultLpMint,
})
.instruction();
createPoolPostInstructions.push(lockIx);
}
const createPermissionlessPoolTx = await ammProgram.methods
.initializePermissionlessConstantProductPoolWithConfig2(tokenAAmount, tokenBAmount, activationPoint)
.accounts({
pool: poolPubkey,
tokenAMint,
tokenBMint,
aVault,
bVault,
aVaultLpMint,
bVaultLpMint,
aVaultLp,
bVaultLp,
lpMint,
payerTokenA,
payerTokenB,
protocolTokenAFee,
protocolTokenBFee,
payerPoolLp,
aTokenVault,
bTokenVault,
mintMetadata,
metadataProgram: constants_1.METAPLEX_PROGRAM,
payer,
config,
rent: web3_js_1.SYSVAR_RENT_PUBKEY,
vaultProgram: vaultProgram.programId,
tokenProgram: spl_token_1.TOKEN_PROGRAM_ID,
systemProgram: web3_js_1.SystemProgram.programId,
associatedTokenProgram: spl_token_1.ASSOCIATED_TOKEN_PROGRAM_ID,
})
.postInstructions(createPoolPostInstructions)
.transaction();
const ixs = [];
if (preInstructions.length) {
// https://explorer.solana.com/tx/3G95TWMmTLbZ7aAgyGmZd8JFk19ye8whVB5cXhYCCsUWSUsnuVMqPMXbPiY5WaF4zE2Sz7CG5e4jTj8NQbCnUG14?cluster=devnet
// Create 2 dynamic vault consume around 190k CU. Each create ATA + Wrap SOL around 23k
const setComputeUnitLimitIx = web3_js_1.ComputeBudgetProgram.setComputeUnitLimit({
units: 300_000,
});
ixs.push([setComputeUnitLimitIx, ...preInstructions]);
}
// https://explorer.solana.com/tx/4X37hBoUNwpmHKNGpQB3M72xDA7yhFKhbYrkBQUK4skBGD7P9LdWgb2WpvFGHcxYi13e9bdwhetsqmULeW7nUDbW?cluster=devnet
// https://explorer.solana.com/tx/3xMGCQ9GAqSMZH1uhXXc1quZit61DXr1KsbVxdBN1zCkQy1GTXBGuWgxzWfMEdecdRi859m3mYQKuLyemvR18VHS?cluster=devnet
// Create dynamic pool consume around 287k, create lock escrow + lock liquidity around 84k
const setComputeUnitLimitIx = web3_js_1.ComputeBudgetProgram.setComputeUnitLimit({
units: 450_000,
});
ixs.push([setComputeUnitLimitIx, createPermissionlessPoolTx]);
if (feeWrapperLockAmount.gt(new anchor_1.BN(0))) {
const preInstructions = [];
const createFeeVaultIxs = await m3m3_1.default.createFeeVaultInstructions(connection, poolPubkey, payer, tokenAMint, tokenBMint);
preInstructions.push(...createFeeVaultIxs);
const vaultKey = (0, m3m3_1.deriveFeeVault)(poolPubkey, m3m3_1.STAKE_FOR_FEE_PROGRAM_ID);
const [lockEscrowFeeVaultPK] = (0, utils_1.deriveLockEscrowPda)(poolPubkey, vaultKey, ammProgram.programId);
const [escrowFeeVaultAta, createEscrowFeeVaultAtaIx] = await (0, utils_1.getOrCreateATAInstruction)(lpMint, lockEscrowFeeVaultPK, connection, payer);
createEscrowFeeVaultAtaIx && preInstructions.push(createEscrowFeeVaultAtaIx);
const lockTx = await ammProgram.methods
.lock(feeWrapperLockAmount)
.accounts({
pool: poolPubkey,
lockEscrow: lockEscrowFeeVaultPK,
owner: payer,
lpMint,
sourceTokens: payerPoolLp,
escrowVault: escrowFeeVaultAta,
tokenProgram: spl_token_1.TOKEN_PROGRAM_ID,
aVault,
bVault,
aVaultLp,
bVaultLp,
aVaultLpMint,
bVaultLpMint,
})
.preInstructions(preInstructions)
.transaction();
ixs.push(lockTx);
}
if (opt?.swapLiquidity) {
const protocolTokenFee = (0, utils_1.deriveProtocolTokenFee)(poolPubkey, tokenBMint, ammProgram.programId);
const swapTx = await ammProgram.methods
.swap(opt.swapLiquidity.inAmount, opt.swapLiquidity.minAmountOut)
.accounts({
aTokenVault,
bTokenVault,
aVault,
bVault,
aVaultLp,
bVaultLp,
aVaultLpMint,
bVaultLpMint,
userSourceToken: payerTokenB,
userDestinationToken: payerTokenA,
user: payer,
protocolTokenFee,
pool: poolPubkey,
tokenProgram: spl_token_1.TOKEN_PROGRAM_ID,
vaultProgram: vaultProgram.programId,
})
.transaction();
ixs.push(swapTx);
}
const resultTx = await (0, utils_1.createTransactions)(connection, ixs, payer);
return resultTx;
}
static async createPermissionlessConstantProductPoolWithConfig(connection, payer, tokenAMint, tokenBMint, tokenAAmount, tokenBAmount, config, opt) {
const { vaultProgram, ammProgram } = (0, utils_1.createProgram)(connection, opt?.programId);
const [{ vaultPda: aVault, tokenVaultPda: aTokenVault, lpMintPda: aLpMintPda }, { vaultPda: bVault, tokenVaultPda: bTokenVault, lpMintPda: bLpMintPda },] = [(0, vault_sdk_1.getVaultPdas)(tokenAMint, vaultProgram.programId), (0, vault_sdk_1.getVaultPdas)(tokenBMint, vaultProgram.programId)];
const [aVaultAccount, bVaultAccount] = await Promise.all([
vaultProgram.account.vault.fetchNullable(aVault),
vaultProgram.account.vault.fetchNullable(bVault),
]);
let aVaultLpMint = aLpMintPda;
let bVaultLpMint = bLpMintPda;
let preInstructions = [];
if (!aVaultAccount) {
const createVaultAIx = await vault_sdk_1.default.createPermissionlessVaultInstruction(connection, payer, tokenAMint);
createVaultAIx && preInstructions.push(createVaultAIx);
}
else {
aVaultLpMint = aVaultAccount.lpMint; // Old vault doesn't have lp mint pda
}
if (!bVaultAccount) {
const createVaultBIx = await vault_sdk_1.default.createPermissionlessVaultInstruction(connection, payer, tokenBMint);
createVaultBIx && preInstructions.push(createVaultBIx);
}
else {
bVaultLpMint = bVaultAccount.lpMint; // Old vault doesn't have lp mint pda
}
const poolPubkey = (0, utils_1.derivePoolAddressWithConfig)(tokenAMint, tokenBMint, config, ammProgram.programId);
const [lpMint] = web3_js_1.PublicKey.findProgramAddressSync([Buffer.from(constants_1.SEEDS.LP_MINT), poolPubkey.toBuffer()], ammProgram.programId);
const [[aVaultLp], [bVaultLp]] = [
web3_js_1.PublicKey.findProgramAddressSync([aVault.toBuffer(), poolPubkey.toBuffer()], ammProgram.programId),
web3_js_1.PublicKey.findProgramAddressSync([bVault.toBuffer(), poolPubkey.toBuffer()], ammProgram.programId),
];
const [[payerTokenA, createPayerTokenAIx], [payerTokenB, createPayerTokenBIx]] = await Promise.all([
(0, utils_1.getOrCreateATAInstruction)(tokenAMint, payer, connection),
(0, utils_1.getOrCreateATAInstruction)(tokenBMint, payer, connection),
]);
createPayerTokenAIx && !opt?.skipAAta && preInstructions.push(createPayerTokenAIx);
createPayerTokenBIx && !opt?.skipBAta && preInstructions.push(createPayerTokenBIx);
const [[protocolTokenAFee], [protocolTokenBFee]] = [
web3_js_1.PublicKey.findProgramAddressSync([Buffer.from(constants_1.SEEDS.FEE), tokenAMint.toBuffer(), poolPubkey.toBuffer()], ammProgram.programId),
web3_js_1.PublicKey.findProgramAddressSync([Buffer.from(constants_1.SEEDS.FEE), tokenBMint.toBuffer(), poolPubkey.toBuffer()], ammProgram.programId),
];
const payerPoolLp = (0, utils_1.getAssociatedTokenAccount)(lpMint, payer);
if (tokenAMint.equals(spl_token_1.NATIVE_MINT)) {
preInstructions = preInstructions.concat((0, utils_1.wrapSOLInstruction)(payer, payerTokenA, BigInt(tokenAAmount.toString())));
}
if (tokenBMint.equals(spl_token_1.NATIVE_MINT)) {
preInstructions = preInstructions.concat((0, utils_1.wrapSOLInstruction)(payer, payerTokenB, BigInt(tokenBAmount.add(opt?.swapLiquidity?.inAmount ?? new anchor_1.BN(0)).toString())));
}
const [mintMetadata, _mintMetadataBump] = (0, utils_1.deriveMintMetadata)(lpMint);
const createPoolPostInstructions = [];
if (opt?.lockLiquidity) {
const [lockEscrowPK] = (0, utils_1.deriveLockEscrowPda)(poolPubkey, payer, ammProgram.programId);
const createLockEscrowIx = await ammProgram.methods
.createLockEscrow()
.accounts({
pool: poolPubkey,
lockEscrow: lockEscrowPK,
owner: payer,
lpMint,
payer,
systemProgram: web3_js_1.SystemProgram.programId,
})
.instruction();
createPoolPostInstructions.push(createLockEscrowIx);
const [escrowAta, createEscrowAtaIx] = await (0, utils_1.getOrCreateATAInstruction)(lpMint, lockEscrowPK, connection, payer);
createEscrowAtaIx && createPoolPostInstructions.push(createEscrowAtaIx);
const lockIx = await ammProgram.methods
.lock(constants_1.U64_MAX)
.accounts({
pool: poolPubkey,
lockEscrow: lockEscrowPK,
owner: payer,
lpMint,
sourceTokens: payerPoolLp,
escrowVault: escrowAta,
tokenProgram: spl_token_1.TOKEN_PROGRAM_ID,
aVault,
bVault,
aVaultLp,
bVaultLp,
aVaultLpMint,
bVaultLpMint,
})
.instruction();
createPoolPostInstructions.push(lockIx);
}
const createPermissionlessPoolTx = await ammProgram.methods
.initializePermissionlessConstantProductPoolWithConfig(tokenAAmount, tokenBAmount)
.accounts({
pool: poolPubkey,
tokenAMint,
tokenBMint,
aVault,
bVault,
aVaultLpMint,
bVaultLpMint,
aVaultLp,
bVaultLp,
lpMint,
payerTokenA,
payerTokenB,
protocolTokenAFee,
protocolTokenBFee,
payerPoolLp,
aTokenVault,
bTokenVault,
mintMetadata,
metadataProgram: constants_1.METAPLEX_PROGRAM,
payer,
config,
rent: web3_js_1.SYSVAR_RENT_PUBKEY,
vaultProgram: vaultProgram.programId,
tokenProgram: spl_token_1.TOKEN_PROGRAM_ID,
systemProgram: web3_js_1.SystemProgram.programId,
associatedTokenProgram: spl_token_1.ASSOCIATED_TOKEN_PROGRAM_ID,
})
.postInstructions(createPoolPostInstructions)
.transaction();
const ixs = [];
if (preInstructions.length) {
// Create 2 dynamic vault consume around 190k CU. Each create ATA + Wrap SOL around 23k
const setComputeUnitLimitIx = web3_js_1.ComputeBudgetProgram.setComputeUnitLimit({
units: 300_000,
});
ixs.push([setComputeUnitLimitIx, ...preInstructions]);
}
// Create dynamic pool consume around 287k, create lock escrow + lock liquidity around 84k
const setComputeUnitLimitIx = web3_js_1.ComputeBudgetProgram.setComputeUnitLimit({
units: 450_000,
});
ixs.push([setComputeUnitLimitIx, createPermissionlessPoolTx]);
if (opt?.swapLiquidity) {
const protocolTokenFee = (0, utils_1.deriveProtocolTokenFee)(poolPubkey, tokenBMint, ammProgram.programId);
const swapTx = await ammProgram.methods
.swap(opt.swapLiquidity.inAmount, opt.swapLiquidity.minAmountOut)
.accounts({
aTokenVault,
bTokenVault,
aVault,
bVault,
aVaultLp,
bVaultLp,
aVaultLpMint,
bVaultLpMint,
userSourceToken: payerTokenB,
userDestinationToken: payerTokenA,
user: payer,
protocolTokenFee,
pool: poolPubkey,
tokenProgram: spl_token_1.TOKEN_PROGRAM_ID,
vaultProgram: vaultProgram.programId,
})
.transaction();
ixs.push(swapTx);
}
const resultTx = await (0, utils_1.createTransactions)(connection, ixs, payer);
return resultTx;
}
static async createPermissionlessConstantProductMemecoinPoolWithConfig(connection, payer, tokenAMint, tokenBMint, tokenAAmount, tokenBAmount, config, memecoinInfo, opt) {
const { vaultProgram, ammProgram } = (0, utils_1.createProgram)(connection, opt?.programId);
const createTokenIxs = [];
if (!memecoinInfo.isMinted) {
if (!memecoinInfo.keypair ||
!memecoinInfo.payer ||
!memecoinInfo.mintAuthority ||
!memecoinInfo.mintAmount ||
!memecoinInfo.assetData ||
memecoinInfo.freezeAuthority === undefined) {
throw new Error('Missing required fields for minting Memecoin.');
}
const { tx: mintTx, mintAccount } = await (0, utils_1.createMint)(connection, memecoinInfo.keypair, memecoinInfo.payer, memecoinInfo.assetData, memecoinInfo.mintAuthority, memecoinInfo.freezeAuthority, memecoinInfo.decimals || 0, spl_token_1.TOKEN_PROGRAM_ID);
createTokenIxs.push(...mintTx.instructions);
const [ata, createAtaIx] = await (0, utils_1.getOrCreateATAInstruction)(mintAccount.publicKey, memecoinInfo.mintAuthority, connection, memecoinInfo.payer);
createAtaIx && createTokenIxs.push(createAtaIx);
const mintToIx = (0, spl_token_1.createMintToInstruction)(mintAccount.publicKey, ata, memecoinInfo.mintAuthority, BigInt(memecoinInfo.mintAmount.toString()));
createTokenIxs.push(mintToIx);
const revokeMintAuthorityIx = (0, spl_token_1.createSetAuthorityInstruction)(mintAccount.publicKey, memecoinInfo.mintAuthority, 0, null);
createTokenIxs.push(revokeMintAuthorityIx);
}
let preInstructions = [...createTokenIxs];
const [{ vaultPda: aVault, tokenVaultPda: aTokenVault, lpMintPda: aLpMintPda }, { vaultPda: bVault, tokenVaultPda: bTokenVault, lpMintPda: bLpMintPda },] = [(0, vault_sdk_1.getVaultPdas)(tokenAMint, vaultProgram.programId), (0, vault_sdk_1.getVaultPdas)(tokenBMint, vaultProgram.programId)];
const [aVaultAccount, bVaultAccount] = await Promise.all([
vaultProgram.account.vault.fetchNullable(aVault),
vaultProgram.account.vault.fetchNullable(bVault),
]);
let aVaultLpMint = aLpMintPda;
let bVaultLpMint = bLpMintPda;
if (!aVaultAccount) {
const createVaultAIx = await vault_sdk_1.default.createPermissionlessVaultInstruction(connection, payer, tokenAMint);
createVaultAIx && preInstructions.push(createVaultAIx);
}
else {
aVaultLpMint = aVaultAccount.lpMint; // Old vault doesn't have lp mint pda
}
if (!bVaultAccount) {
const createVaultBIx = await vault_sdk_1.default.createPermissionlessVaultInstruction(connection, payer, tokenBMint);
createVaultBIx && preInstructions.push(createVaultBIx);
}
else {
bVaultLpMint = bVaultAccount.lpMint; // Old vault doesn't have lp mint pda
}
const poolPubkey = (0, utils_1.derivePoolAddressWithConfig)(tokenAMint, tokenBMint, config, ammProgram.programId);
const [lpMint] = web3_js_1.PublicKey.findProgramAddressSync([Buffer.from(constants_1.SEEDS.LP_MINT), poolPubkey.toBuffer()], ammProgram.programId);
const [[aVaultLp], [bVaultLp]] = [
web3_js_1.PublicKey.findProgramAddressSync([aVault.toBuffer(), poolPubkey.toBuffer()], ammProgram.programId),
web3_js_1.PublicKey.findProgramAddressSync([bVault.toBuffer(), poolPubkey.toBuffer()], ammProgram.programId),
];
const [[payerTokenA, createPayerTokenAIx], [payerTokenB, createPayerTokenBIx]] = await Promise.all([
(0, utils_1.getOrCreateATAInstruction)(tokenAMint, payer, connection),
(0, utils_1.getOrCreateATAInstruction)(tokenBMint, payer, connection),
]);
createPayerTokenAIx && !opt?.skipAAta && preInstructions.push(createPayerTokenAIx);
createPayerTokenBIx && !opt?.skipBAta && preInstructions.push(createPayerTokenBIx);
const [[protocolTokenAFee], [protocolTokenBFee]] = [
web3_js_1.PublicKey.findProgramAddressSync([Buffer.from(constants_1.SEEDS.FEE), tokenAMint.toBuffer(), poolPubkey.toBuffer()], ammProgram.programId),
web3_js_1.PublicKey.findProgramAddressSync([Buffer.from(constants_1.SEEDS.FEE), tokenBMint.toBuffer(), poolPubkey.toBuffer()], ammProgram.programId),
];
const payerPoolLp = (0, utils_1.getAssociatedTokenAccount)(lpMint, payer);
if (tokenAMint.equals(spl_token_1.NATIVE_MINT)) {
preInstructions = preInstructions.concat((0, utils_1.wrapSOLInstruction)(payer, payerTokenA, BigInt(tokenAAmount.toString())));
}
if (tokenBMint.equals(spl_token_1.NATIVE_MINT)) {
preInstructions = preInstructions.concat((0, utils_1.wrapSOLInstruction)(payer, payerTokenB, BigInt(tokenBAmount.add(opt?.swapLiquidity?.inAmount ?? new anchor_1.BN(0)).toString())));
}
const [mintMetadata, _mintMetadataBump] = (0, utils_1.deriveMintMetadata)(lpMint);
const lpAmount = (0, bn_sqrt_1.default)(tokenAAmount.mul(tokenBAmount));
const { userLockAmount, feeWrapperLockAmount } = (0, utils_1.calculateLockAmounts)(lpAmount, opt?.stakeLiquidity?.ratio);
const createPoolPostInstructions = [];
if (opt?.lockLiquidity && userLockAmount.gt(new anchor_1.BN(0))) {
const [lockEscrowPK] = (0, utils_1.deriveLockEscrowPda)(poolPubkey, payer, ammProgram.programId);
const createLockEscrowIx = await ammProgram.methods
.createLockEscrow()
.accounts({
pool: poolPubkey,
lockEscrow: lockEscrowPK,
owner: payer,
lpMint,
payer,
systemProgram: web3_js_1.SystemProgram.programId,
})
.instruction();
createPoolPostInstructions.push(createLockEscrowIx);
const [escrowAta, createEscrowAtaIx] = await (0, utils_1.getOrCreateATAInstruction)(lpMint, lockEscrowPK, connection, payer);
createEscrowAtaIx && createPoolPostInstructions.push(createEscrowAtaIx);
const lockIx = await ammProgram.methods
.lock(userLockAmount)
.accounts({
pool: poolPubkey,
lockEscrow: lockEscrowPK,
owner: payer,
lpMint,
sourceTokens: payerPoolLp,
escrowVault: escrowAta,
tokenProgram: spl_token_1.TOKEN_PROGRAM_ID,
aVault,
bVault,
aVaultLp,
bVaultLp,
aVaultLpMint,
bVaultLpMint,
})
.instruction();
createPoolPostInstructions.push(lockIx);
}
const createPermissionlessPoolTx = await ammProgram.methods
.initializePermissionlessConstantProductPoolWithConfig(tokenAAmount, tokenBAmount)
.accounts({
pool: poolPubkey,
tokenAMint,
tokenBMint,
aVault,
bVault,
aVaultLpMint,
bVaultLpMint,
aVaultLp,
bVaultLp,
lpMint,
payerTokenA,
payerTokenB,
protocolTokenAFee,
protocolTokenBFee,
payerPoolLp,
aTokenVault,
bTokenVault,
mintMetadata,
metadataProgram: constants_1.METAPLEX_PROGRAM,
payer,
config,
rent: web3_js_1.SYSVAR_RENT_PUBKEY,
vaultProgram: vaultProgram.programId,
tokenProgram: spl_token_1.TOKEN_PROGRAM_ID,
systemProgram: web3_js_1.SystemProgram.programId,
associatedTokenProgram: spl_token_1.ASSOCIATED_TOKEN_PROGRAM_ID,
})
.postInstructions(createPoolPostInstructions)
.transaction();
const ixs = [];
if (preInstructions.length) {
// Create 2 dynamic vault consume around 190k CU. Each create ATA + Wrap SOL around 23k
const setComputeUnitLimitIx = web3_js_1.ComputeBudgetProgram.setComputeUnitLimit({
units: 300_000,
});
ixs.push([setComputeUnitLimitIx, ...preInstructions]);
}
// Create dynamic pool consume around 287k, create lock escrow + lock liquidity around 84k
const setComputeUnitLimitIx = web3_js_1.ComputeBudgetProgram.setComputeUnitLimit({
units: 450_000,
});
ixs.push([setComputeUnitLimitIx, createPermissionlessPoolTx]);
if (feeWrapperLockAmount.gt(new anchor_1.BN(0))) {
const preInstructions = [];
const initFeeVaultParams = opt?.feeVault ? { ...opt.feeVault, padding: new Array(64).fill(0) } : undefined;
const createFeeVaultIxs = await m3m3_1.default.createFeeVaultInstructions(connection, poolPubkey, payer, tokenAMint, tokenBMint, initFeeVaultParams);
preInstructions.push(...createFeeVaultIxs);
const vaultKey = (0, m3m3_1.deriveFeeVault)(poolPubkey, m3m3_1.STAKE_FOR_FEE_PROGRAM_ID);
const [lockEscrowFeeVaultPK] = (0, utils_1.deriveLockEscrowPda)(poolPubkey, vaultKey, ammProgram.programId);
const [escrowFeeVaultAta, createEscrowFeeVaultAtaIx] = await (0, utils_1.getOrCreateATAInstruction)(lpMint, lockEscrowFeeVaultPK, connection, payer);
createEscrowFeeVaultAtaIx && preInstructions.push(createEscrowFeeVaultAtaIx);
const lockTx = await ammProgram.methods
.lock(feeWrapperLockAmount)
.accounts({
pool: poolPubkey,
lockEscrow: lockEscrowFeeVaultPK,
owner: payer,
lpMint,
sourceTokens: payerPoolLp,
escrowVault: escrowFeeVaultAta,
tokenProgram: spl_token_1.TOKEN_PROGRAM_ID,
aVault,
bVault,
aVaultLp,
bVaultLp,
aVaultLpMint,
bVaultLpMint,
})
.preInstructions(preInstructions)
.transaction();
ixs.push(lockTx);
}
if (opt?.swapLiquidity) {
const protocolTokenFee = (0, utils_1.deriveProtocolTokenFee)(poolPubkey, tokenBMint, ammProgram.programId);
const swapTx = await ammProgram.methods
.swap(opt.swapLiquidity.inAmount, opt.swapLiquidity.minAmountOut)
.accounts({
aTokenVault,
bTokenVault,
aVault,
bVault,
aVaultLp,
bVaultLp,
aVaultLpMint,
bVaultLpMint,
userSourceToken: payerTokenB,
userDestinationToken: payerTokenA,
user: payer,
protocolTokenFee,
pool: poolPubkey,
tokenProgram: spl_token_1.TOKEN_PROGRAM_ID,
vaultProgram: vaultProgram.programId,
})
.transaction();
ixs.push(swapTx);
}
const resultTx = await (0, utils_1.createTransactions)(connection, ixs, payer);
return resultTx;
}
static async createPermissionlessPool(connection, payer, tokenInfoA, tokenInfoB, tokenAAmount, tokenBAmount, isStable, tradeFeeBps, opt) {
const { vaultProgram, ammProgram } = (0, utils_1.createProgram)(connection, opt?.programId);
const curveType = (0, utils_1.generateCurveType)(tokenInfoA, tokenInfoB, isStable);
const tokenAMint = new web3_js_1.PublicKey(tokenInfoA.address);
const tokenBMint = new web3_js_1.PublicKey(tokenInfoB.address);
const [{ vaultPda: aVault, tokenVaultPda: aTokenVault, lpMintPda: aLpMintPda }, { vaultPda: bVault, tokenVaultPda: bTokenVault, lpMintPda: bLpMintPda },] = [(0, vault_sdk_1.getVaultPdas)(tokenAMint, vaultProgram.programId), (0, vault_sdk_1.getVaultPdas)(tokenBMint, vaultProgram.programId)];
const [aVaultAccount, bVaultAccount] = await Promise.all([
vaultProgram.account.vault.fetchNullable(aVault),
vaultProgram.account.vault.fetchNullable(bVault),
]);
let aVaultLpMint = aLpMintPda;
let bVaultLpMint = bLpMintPda;
let preInstructions = [];
const setComputeUnitLimitIx = web3_js_1.ComputeBudgetProgram.setComputeUnitLimit({
units: 600_000,
});
preInstructions.push(setComputeUnitLimitIx);
if (!aVaultAccount) {
const createVaultAIx = await vault_sdk_1.default.createPermissionlessVaultInstruction(connection, payer, new web3_js_1.PublicKey(tokenInfoA.address));
createVaultAIx && preInstructions.push(createVaultAIx);
}
else {
aVaultLpMint = aVaultAccount.lpMint; // Old vault doesn't have lp mint pda
}
if (!bVaultAccount) {
const createVaultBIx = await vault_sdk_1.default.createPermissionlessVaultInstruction(connection, payer, new web3_js_1.PublicKey(tokenInfoB.address));
createVaultBIx && preInstructions.push(createVaultBIx);
}
else {
bVaultLpMint = bVaultAccount.lpMint; // Old vault doesn't have lp mint pda
}
const poolPubkey = (0, utils_1.derivePoolAddress)(connection, tokenInfoA, tokenInfoB, isStable, tradeFeeBps, {
programId: opt?.programId,
});
const [[aVaultLp], [bVaultLp]] = [
web3_js_1.PublicKey.findProgramAddressSync([aVault.toBuffer(), poolPubkey.toBuffer()], ammProgram.programId),
web3_js_1.PublicKey.findProgramAddressSync([bVault.toBuffer(), poolPubkey.toBuffer()], ammProgram.programId),
];
const [[payerTokenA, createPayerTokenAIx], [payerTokenB, createPayerTokenBIx]] = await Promise.all([
(0, utils_1.getOrCreateATAInstruction)(tokenAMint, payer, connection),
(0, utils_1.getOrCreateATAInstruction)(tokenBMint, payer, connection),
]);
if (!opt?.skipAta) {
createPayerTokenAIx && preInstructions.push(createPayerTokenAIx);
}
createPayerTokenBIx && preInstructions.push(createPayerTokenBIx);
const [[protocolTokenAFee], [protocolTokenBFee]] = [
web3_js_1.PublicKey.findProgramAddressSync([Buffer.from(constants_1.SEEDS.FEE), tokenAMint.toBuffer(), poolPubkey.toBuffer()], ammProgram.programId),
web3_js_1.PublicKey.findProgramAddressSync([Buffer.from(constants_1.SEEDS.FEE), tokenBMint.toBuffer(), poolPubkey.toBuffer()], ammProgram.programId),
];
const [lpMint] = web3_js_1.PublicKey.findProgramAddressSync([Buffer.from(constants_1.SEEDS.LP_MINT), poolPubkey.toBuffer()], ammProgram.programId);
const payerPoolLp = await (0, utils_1.getAssociatedTokenAccount)(lpMint, payer);
if (tokenAMint.equals(spl_token_1.NATIVE_MINT)) {
preInstructions = preInstructions.concat((0, utils_1.wrapSOLInstruction)(payer, payerTokenA, BigInt(tokenAAmount.toString())));
}
if (tokenBMint.equals(spl_token_1.NATIVE_MINT)) {
preInstructions = preInstructions.concat((0, utils_1.wrapSOLInstruction)(payer, payerTokenB, BigInt(tokenBAmount.toString())));
}
const [mintMetadata, _mintMetadataBump] = (0, utils_1.deriveMintMetadata)(lpMint);
const createPermissionlessPoolTx = await ammProgram.methods
.initializePermissionlessPoolWithFeeTier(curveType, tradeFeeBps, tokenAAmount, tokenBAmount)
.accounts({
pool: poolPubkey,
tokenAMint,
tokenBMint,
aVault,
bVault,
aVaultLpMint,
bVaultLpMint,
aVaultLp,
bVaultLp,
lpMint,
payerTokenA,
payerTokenB,
protocolTokenAFee,
protocolTokenBFee,
payerPoolLp,
aTokenVault,
bTokenVault,
mintMetadata,
metadataProgram: constants_1.METAPLEX_PROGRAM,
feeOwner: constants_1.FEE_OWNER,
payer,