Meteora Dynamic AMM SDK
Getting started
NPM: https://www.npmjs.com/package/@meteora-ag/dynamic-amm-sdk
SDK: https://github.com/MeteoraAg/dynamic-amm-sdk
Discord: https://discord.com/channels/841152225564950528/864859354335412224
Installation
# NPM
npm i @meteora-ag/dynamic-amm-sdk @coral-xyz/anchor @solana/web3.js @solana/spl-token
# YARN
yarn add @meteora-ag/dynamic-amm-sdk @coral-xyz/anchor @solana/web3.js @solana/spl-token
# Or, use any package manager of your choice.
Pool Types
The Dynamic AMM SDK supports three types of pools:
Constant Product Pool (Volatile Pool)
Memecoin Pool (M3M3 Pool)
Stable Pool
Usage Examples
Initialize AmmImpl instance
import AmmImpl, { MAINNET_POOL } from '@meteora-ag/dynamic-amm-sdk';
import { Connection, Keypair, PublicKey } from '@solana/web3.js';
import { AnchorProvider, Wallet } from '@coral-xyz/anchor';
// Connection, Wallet, and AnchorProvider to interact with the network
const mainnetConnection = new Connection('https://api.mainnet-beta.solana.com');
const mockWallet = new Wallet(new Keypair());
const provider = new AnchorProvider(mainnetConnection, mockWallet, {
commitment: 'confirmed',
});
// Alternatively, to use Solana Wallet Adapter
// Create single instance
const constantProductPool = await AmmImpl.create(mainnetConnection, MAINNET_POOL.USDC_SOL);
const stablePool = await AmmImpl.create(mainnetConnection, MAINNET_POOL.USDT_USDC);
// Or with any other pool address, refer to the pool creation section below
const pool = await AmmImpl.create(mainnetConnection, new PublicKey('...'));
// If you need to create multiple, can consider using `createMultiple`
const pools = [MAINNET_POOL.USDC_SOL, MAINNET_POOL.USDT_USDC];
const [constantProductPool, stablePool] = await AmmImpl.createMultiple(mainnetConnection, pools);
Creating New Pools
Note: If the Dynamic AMM Pool is being launched with an Alpha Vault, SOL or USDC must be used as the quote token.
1. Create Constant Product Pool
import AmmImpl, { PROGRAM_ID } from '@meteora-ag/dynamic-amm-sdk';
import { derivePoolAddressWithConfig } from '@meteora-ag/dynamic-amm-sdk/dist/cjs/src/amm/utils';
import { BN } from 'bn.js';
// Token A/B address of the pool.
const tokenAMint = new PublicKey('...');
const tokenBMint = new PublicKey('...');
// Configuration address for the pool. It will decide the fees of the pool.
const config = new PublicKey('...');
// Amount of token A and B to be deposited to the pool.
const tokenAAmount = new BN(100_000);
const tokenBAmount = new BN(500_000);
// Get pool address
const programId = new PublicKey(PROGRAM_ID);
const poolPubkey = derivePoolAddressWithConfig(tokenAMint, tokenBMint, config, programId);
// Create pool
const transactions = await AmmImpl.createPermissionlessConstantProductPoolWithConfig(
provider.connection,
mockWallet.publicKey, // payer
tokenAMint,
tokenBMint,
tokenAAmount,
tokenBAmount,
config,
);
// Or if you need to set the activation point earlier than the default derived from the config
const startTime = '...';
const transactions = await AmmImpl.createPermissionlessConstantProductPoolWithConfig2(
provider.connection,
mockWallet.publicKey, // payer
tokenAMint,
tokenBMint,
tokenAAmount,
tokenBAmount,
config,
{
activationPoint: startTime !== 'now' ? new BN(Math.floor(new UTCDate(startTime).getTime() / 1000)) : undefined,
},
);
for (const transaction of transactions) {
transaction.sign(mockWallet.payer);
const txHash = await provider.connection.sendRawTransaction(transaction.serialize());
await provider.connection.confirmTransaction(txHash, 'finalized');
console.log('transaction %s', txHash);
}
2. Create Stable Pool
import AmmImpl, { derivePoolAddress } from '@meteora-ag/dynamic-amm-sdk';
import { BN } from 'bn.js';
// Token A/B address of the pool.
const tokenAMint = new PublicKey('...');
const tokenBMint = new PublicKey('...');
const tokenADecimal = 6;
const tokenBDecimal = 6;
const feeBps = new BN(1); // 0.01%
// Get pool address
const poolPubkey = derivePoolAddress(
provider.connection,
tokenAMint,
tokenBMint,
tokenADecimal,
tokenBDecimal,
true, // stable
feeBps,
);
// Create pool
const transactions = await AmmImpl.createPermissionlessPool(
provider.connection,
mockWallet.publicKey, // payer
tokenAMint,
tokenBMint,
tokenAAmount,
tokenBAmount,
true, // stable,
feeBps,
);
for (const transaction of transactions) {
transaction.sign(mockWallet.payer);
const txHash = await provider.connection.sendRawTransaction(transaction.serialize());
await provider.connection.confirmTransaction(txHash, 'finalized');
console.log('transaction %s', txHash);
}
3. Create Memecoin Pool
import AmmImpl, { PROGRAM_ID } from '@meteora-ag/dynamic-amm-sdk';
import { derivePoolAddressWithConfig } from '@meteora-ag/dynamic-amm-sdk/dist/cjs/src/amm/utils';
import { BN } from 'bn.js';
import { roundToNearestMinutes } from 'date-fns';
// Token A/B address of the pool.
const memecoinMint = new PublicKey('...');
const tokenBMint = new PublicKey('...');
const memecoinAmount = new BN(100_000);
const tokenBAmount = new BN(500_000);
// Get pool address
const poolAddress = derivePoolAddressWithConfig(memecoinMint, tokenBMint, feeConfig.publicKey, programId);
// Create pool
const programId = new PublicKey(PROGRAM_ID);
const isNow = true;
const CONFIG_KEY = new PublicKey('..');
const feeConfigurations = await AmmImpl.getFeeConfigurations(provider.connection, {
programId,
});
const feeConfig = feeConfigurations.find(({ publicKey }) => publicKey.equals(CONFIG_KEY));
const transactions = await AmmImpl.createPermissionlessConstantProductMemecoinPoolWithConfig(
provider.connection,
mockWallet.publicKey, // payer
memecoinMint,
tokenBMint,
memecoinAmount,
tokenBAmount,
feeConfig.publicKey,
{ isMinted: true },
);
// with M3M3 vault
const feeDurationInDays = 7;
const numOfStakers = 1000;
const feeClaimStartTime = roundToNearestMinutes(new Date(), {
nearestTo: 30,
});
const cooldownDurationInHours = 6;
const transactions = await AmmImpl.createPermissionlessConstantProductMemecoinPoolWithConfig(
provider.connection,
mockWallet.publicKey, // payer
memecoinMint,
tokenBMint,
memecoinAmount,
tokenBAmount,
feeConfig.publicKey,
{ isMinted: true },
{
feeVault: {
secondsToFullUnlock: feeDurationInDays ? new BN(feeDurationInDays * 86400) : new BN(0),
topListLength: numOfStakers || 0,
startFeeDistributeTimestamp: feeClaimStartTime ? new BN(feeClaimStartTime.getTime() / 1000) : null,
unstakeLockDuration: cooldownDurationInHours ? new BN(cooldownDurationInHours * 3600) : new BN(0),
},
// other options
},
);
for (const transaction of transactions) {
transaction.sign(mockWallet.payer);
const txHash = await provider.connection.sendRawTransaction(transaction.serialize());
await provider.connection.confirmTransaction(txHash, 'finalized');
console.log('transaction %s', txHash);
}
Note: For Alpha Vault integration, please refer to Create Dynamic Pool With Permissionless Alpha Vault.
Common Operations
Get Lp Supply
// To refetch the pool's latest supply
// Alternatively, use `AmmImpl.poolState.lpSupply`
const lpSupply = await pool.getLpSupply();
Check Pool Balance
// Get the user's ATA LP balance
const userLpBalance = await pool.getUserBalance(mockWallet.publicKey);
Update Pool State (It's recommended to update the deposit before perform any quotation)
await pool.updateState();
Constant Product Pool Operations
Deposit
const balance = true;
const slippage = 0.1; // Max to 2 decimal place
const inAmountALamport = new BN(1 * 10 ** constantProductPool.tokenAMint.decimals);
// Get deposit quote
const { poolTokenAmountOut, tokenAInAmount, tokenBInAmount } = constantProductPool.getDepositQuote(
inAmountALamport,
new BN(0),
balance,
slippage,
);
const depositTx = await constantProductPool.deposit(
mockWallet.publicKey,
tokenAInAmount,
tokenBInAmount,
poolTokenAmountOut,
); // Web3 Transaction Object
const depositResult = await provider.sendAndConfirm(depositTx); // Transaction hash
Withdraw
const slippage = 0.1; // Max to 2 decimal place
const outTokenAmountLamport = new BN(0.1 * 10 ** constantProductPool.decimals);
const { poolTokenAmountIn, tokenAOutAmount, tokenBOutAmount } = constantProductPool.getWithdrawQuote(
outTokenAmountLamport,
slippage,
); // use lp balance for full withdrawal
const withdrawTx = await constantProductPool.withdraw(
mockWallet.publicKey,
poolTokenAmountIn,
tokenAOutAmount,
tokenBOutAmount,
); // Web3 Transaction Object
const withdrawResult = await provider.sendAndConfirm(withdrawTx); // Transaction hash
Swap
const slippage = 0.1; // Max to 2 decimal place
const inAmountLamport = new BN(0.1 * 10 ** constantProductPool.tokenB.decimals);
const { minSwapOutAmount } = constantProductPool.getSwapQuote(
new PublicKey(constantProductPool.tokenB.address),
inAmountLamport,
slippage,
);
const swapTx = await constantProductPool.swap(
mockWallet.publicKey,
new PublicKey(constantProductPool.tokenB.address),
inAmountLamport,
minSwapOutAmount,
);
const swapResult = await provider.sendAndConfirm(swapTx);
Stable Pool Operations
Balanced Deposit
const slippage = 0.1; // Max to 2 decimal place
const balance = true;
const inAmountALamport = new BN(0.1 * 10 ** stablePool.tokenA.decimals);
const { poolTokenAmountOut, tokenAInAmount, tokenBInAmount } = stablePool.getDepositQuote(
inAmountALamport,
new BN(0),
balance,
slippage,
);
const depositTx = await stablePool.deposit(mockWallet.publicKey, tokenAInAmount, tokenBInAmount, poolTokenAmountOut); // Web3 Transaction Object
const depositResult = await provider.sendAndConfirm(depositTx); // Transaction hash
Double Side Imbalance Deposit
const slippage = 0.1; // Max to 2 decimal place
const balance = false;
const inAmountALamport = new BN(0.1 * 10 ** stablePool.tokenA.decimals);
const inAmountBLamport = new BN(0.1 * 10 ** stablePool.tokenB.decimals);
const { poolTokenAmountOut, tokenAInAmount, tokenBInAmount } = stablePool.getDepositQuote(
inAmountALamport,
inAmountBLamport,
balance,
slippage,
); // Web3 Transaction Object
const depositTx = await stablePool.deposit(mockWallet.publicKey, tokenAInAmount, tokenBInAmount, poolTokenAmountOut);
const depositResult = await provider.sendAndConfirm(depositTx); // Transaction hash
Single Side Imbalance Deposit
const slippage = 0.1; // Max to 2 decimal place
const balance = false;
const inAmountALamport = new BN(0.1 * 10 ** stablePool.tokenA.decimals);
const { poolTokenAmountOut, tokenAInAmount, tokenBInAmount } = stablePool.getDepositQuote(
inAmountALamport,
new BN(0),
balance,
slippage,
); // Web3 Transaction Object
const depositTx = await stablePool.deposit(mockWallet.publicKey, tokenAInAmount, tokenBInAmount, poolTokenAmountOut);
const depositResult = await provider.sendAndConfirm(depositTx); // Transaction hash
Balanced Withdraw
const slippage = 0.1; // Max to 2 decimal place
const outTokenAmountLamport = new BN(0.1 * 10 ** stablePool.decimals);
const { poolTokenAmountIn, tokenAOutAmount, tokenBOutAmount } = stablePool.getWithdrawQuote(
outTokenAmountLamport,
slippage,
); // use lp balance for full withdrawal
const withdrawTx = await stablePool.withdraw(mockWallet.publicKey, poolTokenAmountIn, tokenAOutAmount, tokenBOutAmount); // Web3 Transaction Object
const withdrawResult = await provider.sendAndConfirm(withdrawTx);
Imbalanced Withdraw
const slippage = 0.1; // Max to 2 decimal place
const outTokenAmountLamport = new BN(0.1 * 10 ** stablePool.decimals);
const { poolTokenAmountIn, tokenAOutAmount, tokenBOutAmount } = stablePool.getWithdrawQuote(
outTokenAmountLamport,
slippage,
new PublicKey(stablePool.tokenA.address), // Pass in token A/B mint to perform imbalanced withdraw
);
const withdrawTx = await stablePool.withdraw(mockWallet.publicKey, poolTokenAmountIn, tokenAOutAmount, tokenBOutAmount); // Web3 Transaction Object
const withdrawResult = await provider.sendAndConfirm(withdrawTx);
Swap
const slippage = 0.1; // Max to 2 decimal place
const inAmountLamport = new BN(0.1 * 10 ** stablePool.tokenB.decimals);
const { minSwapOutAmount } = stablePool.getSwapQuote(
new PublicKey(stablePool.tokenB.address),
inAmountLamport,
slippage,
);
const swapTx = await stablePool.swap(
mockWallet.publicKey,
new PublicKey(stablePool.tokenB.address),
inAmountLamport,
minSwapOutAmount,
);
const swapResult = await provider.sendAndConfirm(swapTx);
Memecoin Pool Operations
Deposit
const balance = true;
const slippage = 0.1; // Max to 2 decimal place
const inAmountALamport = new BN(1 * 10 ** memecoinPool.tokenA.decimals);
// Get deposit quote for constant product
const { poolTokenAmountOut, tokenAInAmount, tokenBInAmount } = memecoinPool.getDepositQuote(
inAmountALamport,
new BN(0),
balance,
slippage,
);
const depositTx = await memecoinPool.deposit(mockWallet.publicKey, tokenAInAmount, tokenBInAmount, poolTokenAmountOut); // Web3 Transaction Object
const depositResult = await provider.sendAndConfirm(depositTx); // Transaction hash
Withdraw
const slippage = 0.1; // Max to 2 decimal place
const outTokenAmountLamport = new BN(0.1 * 10 ** memecoinPool.decimals);
const { poolTokenAmountIn, tokenAOutAmount, tokenBOutAmount } = memecoinPool.getWithdrawQuote(
outTokenAmountLamport,
slippage,
); // use lp balance for full withdrawal
const withdrawTx = await memecoinPool.withdraw(
mockWallet.publicKey,
poolTokenAmountIn,
tokenAOutAmount,
tokenBOutAmount,
); // Web3 Transaction Object
const withdrawResult = await provider.sendAndConfirm(withdrawTx); // Transaction hash
Swap
const slippage = 0.1; // Max to 2 decimal place
const inAmountLamport = new BN(0.1 * 10 ** memecoinPool.tokenB.decimals);
const { minSwapOutAmount } = memecoinPool.getSwapQuote(
new PublicKey(memecoinPool.tokenB.address),
inAmountLamport,
slippage,
);
const swapTx = await memecoinPool.swap(
mockWallet.publicKey,
new PublicKey(memecoinPool.tokenB.address),
inAmountLamport,
minSwapOutAmount,
);
const swapResult = await provider.sendAndConfirm(swapTx);