npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@uniformlabs/multiliquid-svm-sdk

v0.1.10

Published

Multiliquid SVM SDK

Downloads

1,045

Readme

@uniformlabs/multiliquid-svm-sdk

TypeScript SDK for swapping against and managing Multiliquid vaults on Solana. Handles pair discovery, NAV oracle resolution, client-side quoting with exact on-chain math replication, simulation-based quoting, and instruction/transaction building for swaps and LP-admin flows.

Current package version in this repository: 0.1.9.

Program IDs

| Network | Program ID | | ------------ | ---------------------------------------------- | | Devnet | FKeT8H2RSgsamrABNNxwT5f9g3n9msfm6D5AvocjrJAD | | Mainnet-Beta | FKeT8H2RSgsamrABNNxwT5f9g3n9msfm6D5AvocjrJAD |

Installation

npm install @uniformlabs/multiliquid-svm-sdk

Peer dependencies: @solana/web3.js ^1.95, @coral-xyz/anchor ^0.32

Quick Start

import { Connection, Keypair, PublicKey } from "@solana/web3.js";
import { BN } from "@coral-xyz/anchor";
import { MultiliquidClient, SwapDirection, SwapType } from "@uniformlabs/multiliquid-svm-sdk";

const connection = new Connection("https://api.mainnet-beta.solana.com");
const client = new MultiliquidClient({
  connection,
  cluster: "mainnet-beta",
});

const wallet = Keypair.fromSecretKey(/* ... */);
const USDC = new PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v");
const USTB = new PublicKey("CCz3SGVziFeLYk2xfEstkiqJfYkjaSWb2GCABYsVcjo2");
const LP = new PublicKey("C8Mi6kn7ajFWuNe4ZmsR9A6fdqRYhzXFoqVBGMsdJ2Uf");

// Buy USTB with 100 USDC
const { transaction } = await client.buildSwapTransaction({
  user: wallet.publicKey,
  liquidityProvider: LP,
  stableMint: USDC,
  assetMint: USTB,
  amount: new BN(100_000_000), // 100 USDC (6 decimals)
  swapDirection: SwapDirection.StableToAsset,
  swapType: SwapType.ExactIn,
  minAmountOut: new BN(41_000_000_000), // slippage protection
});

transaction.sign([wallet]);
const sig = await connection.sendTransaction(transaction);

API

Client

Stateless client that holds connection config and delegates to standalone functions.

const client = new MultiliquidClient({
  connection, // Solana Connection
  cluster: "mainnet-beta", // "devnet" | "mainnet-beta" (default: "devnet")
  commitment: "confirmed", // Commitment level for all RPC calls (default: "confirmed")
  programId: undefined, // Override program ID (defaults per cluster)
});

Pair Discovery

// Hard-coded registry lookup (no RPC)
const pairs = client.getPairs({ stableMint, assetMint, liquidityProvider });

// On-chain discovery via getProgramAccounts
const pairs = await client.discoverPairs({
  stableMint,
  assetMint,
  liquidityProvider,
});

All filters are optional and AND-combined.

Multiple LPs can list the same stableMint / assetMint pair. On mainnet, for example, both USDC / WTGXX and USDC / WTGXX (Metalayer) use the same mint pair, so include liquidityProvider when you need a specific pool.

Quoting

// Client-side quote — replicates on-chain math exactly via BigInt
const quote = await client.getQuote({
  user: wallet.publicKey,
  liquidityProvider: LP,
  stableMint: USDC,
  assetMint: RWA,
  amount: new BN(100_000_000),
  swapDirection: SwapDirection.StableToAsset,
  swapType: SwapType.ExactIn,
});
// => { amountIn, amountOut, protocolFees, discountAmount, amountInForVault, assetNav, stableNav }

// Simulation-based quote — simulates the swap on-chain without executing
const simQuote = await client.getQuoteViaSimulation(params);
// => { amountIn, amountOut, protocolFee, discountBps, pair, swapDirection, swapType, computeUnitsConsumed }

getQuoteViaSimulation also returns computeUnitsConsumed, useful for setting a tight compute budget.

Instruction & Transaction Building

// Instruction-first: returns TransactionInstruction for composability
const { instruction, setupInstructions, accounts } = await client.buildSwapInstruction(params);

// Transaction convenience: returns unsigned VersionedTransaction
const { transaction, accounts } = await client.buildSwapTransaction(params);
  • setupInstructions contains ATA creation instructions when autoCreateAta: true (default).
  • No ComputeBudgetProgram instructions are included — set compute units and priority fees yourself.
  • Set autoCreateAta: false if you manage ATA creation externally.
  • Swap builders automatically resolve oracle accounts and any Token-2022 transfer-hook accounts needed for the actual token transfers.
  • remainingAccounts is only for additional/manual accounts beyond what the SDK derives automatically.

LP Admin & Liquidity

// Update pair fees and pause state
const { instruction: updatePairIx } = await client.buildUpdatePairInstruction({
  liquidityProvider: wallet.publicKey,
  stableMint: USDC,
  assetMint: USTB,
  redemptionFeeBps: 10,
  discountRateBps: 15,
  paused: false,
});

// Deposit liquidity, deriving the LP ATA unless overridden
const { instruction: addLiquidityIx, setupInstructions } = await client.buildAddLiquidityInstruction({
  liquidityProvider: wallet.publicKey,
  mint: USDC,
  amount: new BN(1_000_000_000),
});

// Withdraw liquidity with an unsigned VersionedTransaction helper
const { transaction: removeLiquidityTx } = await client.buildRemoveLiquidityTransaction({
  liquidityProvider: wallet.publicKey,
  mint: USTB,
  amount: new BN(500_000_000),
});
  • buildUpdatePairInstruction / buildUpdatePairTransaction wrap the on-chain update_pair instruction.
  • buildAddLiquidityInstruction / buildRemoveLiquidityInstruction return setupInstructions when the LP ATA needs to be created.
  • Override lpTokenAccount if the LP uses a non-ATA token account.
  • Add/remove liquidity builders also auto-resolve Token-2022 transfer-hook accounts.
  • remainingAccounts remains available for extra/manual accounts beyond the SDK-derived set.

Swap Parameters

interface SwapParams {
  user: PublicKey;
  liquidityProvider: PublicKey;
  stableMint: PublicKey;
  assetMint: PublicKey;
  amount: BN;
  swapDirection: SwapDirection; // StableToAsset | AssetToStable
  swapType: SwapType; // ExactIn | ExactOut
  minAmountOut?: BN; // Slippage protection (ExactIn)
  maxAmountIn?: BN; // Slippage protection (ExactOut)
  userStableTokenAccount?: PublicKey; // Override ATA derivation
  userAssetTokenAccount?: PublicKey; // Override ATA derivation
  autoCreateAta?: boolean; // Default: true
  remainingAccounts?: AccountMeta[]; // Optional extra accounts to append after SDK-derived accounts
}

Account Fetching

const globalConfig = await client.fetchGlobalConfig();
const pair = await client.fetchPair(pairAddress);
const assetConfig = await client.fetchAssetConfig(configAddress);
const lpStableConfig = await client.fetchLpStableConfig(configAddress);

// Batch fetch all 5 accounts needed for a swap in a single RPC call
const state = await client.fetchSwapState(stableMint, assetMint, lp);

// Check pause status across all levels
const status = await client.checkPauseStatus(stableMint, assetMint, lp);
// => { globalPaused, pairPaused, rwaPaused, stablePaused, lpStablePaused, anyPaused, pauseReasons }

PDA Derivation

All return [PublicKey, number] (address + bump).

client.deriveGlobalConfig();
client.deriveAssetConfig(mint);
client.derivePair(lp, stableMint, assetMint);
client.deriveVault(mint, lp);
client.deriveProgramAuthority();
client.deriveFeeVault(stableMint);
client.deriveLpStableConfig(stableMint, lp);

Event Parsing

// From transaction logs
const events = client.parseSwapEventsFromLogs(logs);

// From a transaction signature
const events = await client.parseSwapEventsFromTransaction(signature);
// => SwapExecutedEvent[]
// { requestor, amountIn, protocolFeeAmount, discountBps, amountOut, pair, swapDirection, swapType }

Error Handling

try {
  await connection.sendTransaction(transaction);
} catch (err) {
  const parsed = client.parseSwapError(err);
  if (parsed) {
    console.error(`[${parsed.code}] ${parsed.name}: ${parsed.message}`);
    // parsed.category: "slippage" | "paused" | "oracle" | "input_validation" | "math" | "liquidity"
  }
}

| Category | Meaning | Recommended Action | | ------------------ | ----------------------------------- | ------------------------------- | | slippage | Output below min or input above max | Re-quote with fresh state | | paused | Program, pair, or asset is paused | Skip route until state changes | | oracle | NAV returned 0 or oracle error | Skip route | | input_validation | Invalid parameters (amount=0, etc.) | Fix input | | math | Overflow/underflow or fee config | Trade may be too small | | liquidity | Vault can't fill the swap | Try different LP or reduce size |

Amount Formatting

import { toHumanReadable, toNativeAmount } from "@uniformlabs/multiliquid-svm-sdk";

toHumanReadable(100_000_000n, 6); // "100"
toHumanReadable(99_800_000_000n, 9); // "99.8"

toNativeAmount("100", 6); // 100_000_000n
toNativeAmount("99.8", 9); // 99_800_000_000n

Standalone Functions

Every MultiliquidClient method is also available as a standalone function:

import {
  buildSwapInstruction,
  buildSwapTransaction,
  buildUpdatePairInstruction,
  buildUpdatePairTransaction,
  buildAddLiquidityInstruction,
  buildAddLiquidityTransaction,
  buildRemoveLiquidityInstruction,
  buildRemoveLiquidityTransaction,
  getQuote,
  getQuoteViaSimulation,
  getPairs,
  discoverPairs,
  fetchSwapState,
  checkPauseStatus,
  calculateSwapResults,
  calculateNav,
  resolveOracleAccounts,
  parseSwapError,
  parseSwapEventsFromLogs,
  parseSwapEventsFromTransaction,
  decodeSwapExecutedEvent,
  detectTokenProgram,
  ensureAtaInstructions,
  toHumanReadable,
  toNativeAmount,
  deriveGlobalConfig,
  deriveAssetConfig,
  derivePair,
  deriveVault,
  deriveProgramAuthority,
  deriveFeeVault,
  deriveLpStableConfig,
  PROGRAM_ID_DEVNET,
  SWAP_COMPUTE_UNITS,
  SWAP_ERROR_MAP,
} from "@uniformlabs/multiliquid-svm-sdk";

Design Principles

  • Instruction-first — Returns TransactionInstruction for composability. Compute budget is the consumer's responsibility.
  • Exact math — Client-side quoting replicates on-chain Rust math with BigInt to produce identical results.
  • Stateless — No caching beyond a single method call.
  • Commitment-consistent — All RPC calls within a single operation use the same commitment level.
  • Pass-through errors — Anchor errors propagate directly. parseSwapError is an optional utility.

License

ISC