Quick start
An empty project reaches a confirmed devnet swap in five short steps, with the SDK resolving every account.
Updated Nov 9, 2026
Install
npm install --save-exact @omnipair/dusk-sdk@2.21.0-next.20261109 @coral-xyz/anchor @solana/web3.jsThe package is strict ESM and published to npm, with devnet builds under the next tag. Pin an exact version, as these commands do: the app pins 2.21.0-next.20261109, and the IDL inside the package is what your transactions are built against.
Create a client
import { AnchorProvider } from "@coral-xyz/anchor"
import { Connection } from "@solana/web3.js"
import { Dusk } from "@omnipair/dusk-sdk"
const connection = new Connection(process.env.SOLANA_RPC_URL!, "confirmed")
const provider = new AnchorProvider(connection, wallet, {
commitment: "confirmed",
})
export const dusk = new Dusk({
provider,
indexerBaseUrl: "https://api.indexer.omnipair.fi/api/v1",
})A Dusk instance is split by source of truth: dusk.write builds instructions and transactions, dusk.get reads accounts and runs typed previews over RPC, and dusk.fetch calls the indexer for history. The raw Anchor program is on dusk.program.
Find a market
Markets are program-derived addresses of the base mint, the quote mint and the creator's parameter hash. During the beta there is one market, VETO / META; the app shows its address on the market page.
import { PublicKey } from "@solana/web3.js"
const market = new PublicKey(
"ErW95UhxqJ3zF1KodfVJQodnDAb6p1aPHNCEywMwMjW6",
)
const account = await dusk.get.market(market)
console.log(account.baseSide.assetMint.toBase58())
console.log(account.quoteSide.assetMint.toBase58())
console.log(account.config.swapFeeBps)To derive an address for a market you know the mints of, use dusk.get.pda.market(baseMint, quoteMint, paramsHash); the hash comes from deriveMarketParamsHash with the creator's namespace and label. Never sort the mints yourself.
Preview a swap
Quotes are on-chain previews: the SDK simulates the preview_swap instruction and decodes its typed return data, so the number you show is the number the program would execute.
import { BN } from "@coral-xyz/anchor"
const quote = await dusk.get.previewSwap({
market,
assetInMint: account.quoteSide.assetMint,
assetOutMint: account.baseSide.assetMint,
exactAssetIn: new BN(5_000_000), // 5 USDC, six decimals
})
quote.amountOut // raw base atoms after fees
quote.netAmountOut // received, after the output token's transfer fee
quote.baseFee // fee components, in the fee asset
quote.divergenceFee
quote.volatilityFeeAmounts are raw integer atoms. Apply a slippage tolerance to netAmountOut to get the minAssetOut the recipient must actually receive.
Send the swap
// Accept up to 3% less than the quote.
const minAssetOut = quote.netAmountOut.muln(97).divn(100)
const transaction = await dusk.write.buildSwapTransaction({
market,
trader: wallet.publicKey,
assetInMint: account.quoteSide.assetMint,
assetOutMint: account.baseSide.assetMint,
exactAssetIn: 5_000_000n,
minAssetOut: minAssetOut.toString(), // bigint, number or string
})
const signature = await provider.sendAndConfirm(transaction)buildSwapTransaction derives the reserve vaults, your associated token accounts and the token programs from the market and the two mints, and TypeScript checks every field. It also fetches the market: when either hLP vault has supply or residual exposure it prepends the five accounts the program needs to reconcile the vaults, exactly once, before any Token-2022 transfer-hook extras you pass as remainingAccounts. buildSwapInstruction returns the bare instruction.
Where to go next
- Reading state and quotes: every read and preview.
- Writing transactions: liquidity, borrowing, leverage, orders, operator bundles.
- SDK guide: the module map.