@meteora-ag/dlmm-pro-sdk builds DLMM Pro transactions and reads DLMM Pro accounts. It also quotes swaps with the same math as the program.
DLMM Pro SDK
Source, tests and the full function reference (
docs.md).npm Package
Published versions of
@meteora-ag/dlmm-pro-sdk.Prerequisites
The package is developed and published with Node 22, and its CI runs on it. The pages here were also run on Node 24. These are the versionspackage.json declares, with the versions the repository’s lockfile resolves in brackets.
The installation commands below add the first three packages next to the SDK. The rest come with the SDK or are only needed for type checking and running scripts.
Installation
- npm
- pnpm
- yarn
@solana/web3.js 1.x and bn.js for amounts. @solana/spl-token is only needed if you read mints yourself, as the example below does. To type check your code, also install typescript, @types/bn.js and @types/node as dev dependencies.
TypeScript Configuration
Thistsconfig.json type-checks every script on these pages with TypeScript 7.0.2. Check your own copy with npx tsc --noEmit.
moduleESNextwithmoduleResolutionBundleris the configuration the examples were checked with.moduleandmoduleResolutionboth set toNodeNextalso type-checks the.mtsscripts.- Top-level
awaitcompiled with the target set toES2022and toES2020. skipLibCheckis needed. Without ittscreports an error inside the declarations of@solana/buffer-layout, a dependency of web3.js, that has nothing to do with your code.- The scripts type-check without
esModuleInterop, but the SDK’s own configuration sets it andimport BN from "bn.js"is written with it in mind. process.envneeds@types/nodeinstalled and"types": ["node"]in the tsconfig.- The scripts use top-level
await, so they must run as ES modules. A.tsfile in a CommonJS package fails undertsxwithTop-level await is currently not supported with the "cjs" output format. Rename it to.mtsor set"type": "module"inpackage.json.
CommonJS and ESM
The package ships both builds. Itsexports map sends import to dist/index.js and require to dist/index.cjs, and both expose the same API.
- With
moduleset toCommonJSandmoduleResolutionset toBundler, a.ctsfile can import the package normally. - With
moduleandmoduleResolutionset toNode16, a CommonJS TypeScript file that imports the package fails withTS1479. The package declares"type": "module"and has one set of type declarations, which TypeScript reads as an ES module, so it refuses therequirecall it would emit. Import the package from an.mtsfile instead, switch toNodeNextorBundler, or use a dynamicimport(), which type-checks underNode16(with the sametypessetting as above, because it readsprocess.env) and runs.
Create a Client
The program ID is the same on mainnet and devnet, so the same client works on both; point the connection at the cluster you want.
new DlmmProClient(connection, commitment, programId) takes an optional commitment (default "confirmed") and program ID for other deployments.
Fund a Devnet Wallet and Find a Pool
To try the SDK without real funds, pointRPC_URL at devnet, https://api.devnet.solana.com, and use a throwaway wallet. This script creates one and prints its address and a WALLET_SECRET_KEY line for your shell.
requestAirdrop answers with a 410 error that says the RPC faucet is closed and points to https://faucet.solana.com, so request SOL there for the address. A wallet with no SOL fails the first transaction: see Troubleshooting.
Then pick a pool. This script lists the pools on the cluster by their account discriminator and prints the first ten that have liquidity and have swaps and deposits enabled. The static config with index 0 exists on devnet too, so you can also create your own pool from tokens you hold.
POOL_ADDRESS to one of the printed addresses. A few things decide whether the quote and swap script works against it:
- Devnet tokens are test tokens. The script sells one whole token X, so you need a balance of the pool’s token X, or pick a pool whose token X is wrapped SOL: the builder wraps the SOL this script sells. The second half of the wrapped SOL example shows a purchase paid in SOL.
- Liquidity is thin on many test pools. When one whole token X is more than the pool can take, the script stops with
Not enough liquidity for this input. LowerinputAmount. extensionsis a bitmask: 1 isLiquidityMiningand 2 isActivationAccess. A pool with activation rules can reject swaps until its activation point withInvalidActivationAccess.
Quote and Swap
This script reads a pool, prints its price, quotes selling one whole token X, and sends the swap with 0.5% slippage. It uses top-levelawait, so save it as swap.mts and run it with npx tsx swap.mts.
quoteExactInloads the tick arrays the swap will cross and returns them; pass them toswapunchanged. Ifquote.amountLeftis not zero, the loaded arrays ran out of liquidity and the swap would fail. RaisemaxTickArraysor reduce the input.- The quote reads the fee at the current time. Scheduled and dynamic fees can change before the transaction lands, which is one more reason to leave room in
minimumOutputAmount. transferFeeExcludedOutAmountis what the wallet receives after any Token 2022 transfer fee on the output mint, and it is whatminimumOutputAmountis compared with.
What the Script Does
The script has four steps. The names in brackets are the values each one produces.- Read the pool.
fetchPoolreturns the decodedPoolaccount: the two mints, their token program flags (0 is the SPL Token program and 1 is Token 2022), the current ticktickCurrentId, the tick spacing, the fee settings and the pool’s status.getTokenProgramturns a flag into the program ID thatgetMintneeds, andgetMintgives the decimals.tickUiPriceconverts the tick into a UI price,1.0001 ** tickscaled by10 ** (decimalsX - decimalsY), so the log line prints token Y per token X. The pool’s exact price lies between this tick and the next, so the printed price is close but not exact. - Quote.
inputAmountis one whole token X in atoms.client.pool.quoteExactInreads the pool, its tick arrays, the mints for transfer fees and the clock, and runs the program’s swap math. It returnsquote(the fields below),tickArrays(the addresses of the tick arrays the swap crosses, in the order the program wants them) andtickArrayBitmapExtension(an address when the swap needs it, otherwisenull).swapperonly matters before a pool with activation rules opens, when a whitelisted wallet may swap early. By default the quote loads the first 3 tick arrays with liquidity, andmaxTickArraysraises that. - Check
amountLeft. A non-zero value means the loaded tick arrays ran out of liquidity before the input was used up. The swap would fail withNotConsumingFullAmountIn, so the script stops. - Swap.
client.pool.swapbuilds the transaction from the accounts the quote chose.minimumOutputAmountis the quoted output less 0.5%:muln(9_950).divn(10_000)multiplies by 9,950 and divides by 10,000, rounding down. The result is an unsignedTransaction.sendAndConfirmTransactionadds a recent blockhash, signs with the wallet, sends and waits for confirmation at the connection’s commitment. It returns the signature, and the script prints it.
EvtSwap event, see Read Events From a Transaction. When amountLeft is zero and nothing changes between the quote and the swap, the amounts match the quote.
Quote Result Fields
quote is a QuoteExactInResult. Amounts are in atoms. The output of the quote is already net of the trading fee.
Choosing Slippage
minimumOutputAmount is the floor you accept for transferFeeExcludedOutAmount. If the swap would pay less when it lands, the program fails it with ExceededSlippage (6019) and no swap happens. A floor of 0 accepts any output. Take the floor from a fresh quote.
- Other swaps move the price and use up liquidity in your direction.
- The dynamic fee rises with volatility, so a pool that has just moved charges more.
- A time-based fee schedule only falls, which helps you.
- A Token 2022 transfer fee can change at an epoch boundary.
quote.nextTickId with the pool’s current tick: a large gap means the input crosses many ticks, and a smaller input or a pool with more liquidity gives a better price. Quote right before you build the swap. A quote only describes the pool at the time it was read.
How Builders Work
Every builder returns{ tx, ... }, where tx is an unsigned Transaction with the fee payer set and no recent blockhash. sendAndConfirmTransaction fills in the blockhash. Each builder’s reference entry lists who must sign; new NFT mints (positions and limit orders) sign too.
- Token accounts. User token accounts default to the wallet’s associated token accounts. A missing one is created in the same transaction, paid by the fee payer.
- Wrapped SOL. When a wallet pays or receives SOL through its default token account, the builder wraps or unwraps it in the same transaction. An account you pass explicitly is used as is.
- Accounts the program needs.
swaptakes its tick arrays fromquoteExactIn, position builders derive theirs from thetickRangesyou pass, and limit order builders resolve their own. The bitmap extension and Token 2022 transfer hook accounts are resolved when you leave them out. - Compute budget. Builders add no compute budget instructions. Opening or expanding a position with many ranges can need more than the default 200,000 compute units, so add
ComputeBudgetProgram.setComputeUnitLimitto those transactions, andsetComputeUnitPricewhen you want a priority fee. - Operator and admin instructions are not wrapped. Build them with
client.program.methods.<instruction>(...)if you need them.
Errors
Builders check their arguments before sending and throwPoolError. Its code uses the program’s numbering, so you can handle a builder error and a failed transaction the same way.
Troubleshooting
These are the failures people hit first, as they appear and what to check. See Handle Errors to map a failed transaction to a program error name, and Program Errors for every code.Next Steps
SDK Examples
Create a pool, open a shaped position, place limit orders and run rewards.
SDK Reference
Every service method and helper, with signers and defaults.

