Package Exports
- @cks-systems/manifest-sdk
- @cks-systems/manifest-sdk/dist/cjs/index.js
- @cks-systems/manifest-sdk/dist/esm/index.js
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (@cks-systems/manifest-sdk) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
Manifest TypeScript Client
TypeScript SDK for interacting with the Manifest decentralized exchange on Solana.
Installation
yarn add @cks-systems/manifest-sdkOverview
The SDK provides these main classes:
- ManifestClient - Primary class for building transactions and reading market data
- Market - Deserializes and queries market state (orderbook, balances, seats)
- Wrapper - Caches a trader's open orders across markets
- Global - Manages global account state for cross-market liquidity
Quick Start
For UI Applications (Read-Only)
import { Connection, PublicKey } from '@solana/web3.js';
import { ManifestClient, Market } from '@cks-systems/manifest-sdk';
const connection = new Connection('https://api.mainnet-beta.solana.com');
const marketAddress = new PublicKey('YOUR_MARKET_ADDRESS');
// Load market data (no wallet needed)
const market = await Market.loadFromAddress({
connection,
address: marketAddress,
});
// Read orderbook
const bids = market.bids();
const asks = market.asks();
console.log('Best bid:', market.bestBidPrice());
console.log('Best ask:', market.bestAskPrice());For Trading Bots (Full Access)
import { Connection, Keypair, PublicKey } from '@solana/web3.js';
import { ManifestClient, OrderType } from '@cks-systems/manifest-sdk';
const connection = new Connection('https://api.mainnet-beta.solana.com');
const trader = Keypair.fromSecretKey(/* your keypair */);
const marketAddress = new PublicKey('YOUR_MARKET_ADDRESS');
// Creates wrapper + claims seat automatically if needed
const client = await ManifestClient.getClientForMarket(
connection,
marketAddress,
trader,
);
// Now ready to trade
const placeOrderIx = client.placeOrderIx({
numBaseTokens: 1.0,
tokenPrice: 100.0,
isBid: true,
lastValidSlot: 0, // No expiration
orderType: OrderType.Limit,
clientOrderId: 1,
});UI Integration Examples
Finding Markets
import { ManifestClient } from '@cks-systems/manifest-sdk';
// List all market addresses
const marketPubkeys = await ManifestClient.listMarketPublicKeys(connection);
// Find markets for specific token pair
const baseMint = new PublicKey('So11111111111111111111111111111111111111112'); // SOL
const quoteMint = new PublicKey('EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v'); // USDC
const markets = await ManifestClient.listMarketsForMints(
connection,
baseMint,
quoteMint,
);Loading Market Data
import { Market } from '@cks-systems/manifest-sdk';
// Method 1: Load from address (fetches from chain)
const market = await Market.loadFromAddress({
connection,
address: marketAddress,
});
// Method 2: Load from existing buffer (for subscriptions)
const accountInfo = await connection.getAccountInfo(marketAddress);
const market = Market.loadFromBuffer({
address: marketAddress,
buffer: accountInfo.data,
});
// Access market info
console.log('Base mint:', market.baseMint().toBase58());
console.log('Quote mint:', market.quoteMint().toBase58());
console.log('Base decimals:', market.baseDecimals());
console.log('Quote decimals:', market.quoteDecimals());Reading the Orderbook
// Get all orders
const bids = market.bids(); // Sorted by price descending
const asks = market.asks(); // Sorted by price ascending
// Get best prices
const bestBid = market.bestBidPrice();
const bestAsk = market.bestAskPrice();
// Each order contains:
// - price: number (in quote tokens per base token)
// - numBaseTokens: number
// - clientOrderId: number
// - trader: PublicKey
// - sequenceNumber: number
// - lastValidSlot: numberSubscribing to Market Updates
// Subscribe to real-time market changes
connection.onAccountChange(marketAddress, (accountInfo) => {
const market = Market.loadFromBuffer({
address: marketAddress,
buffer: accountInfo.data,
});
// Update your UI
updateOrderbook(market.bids(), market.asks());
updateBestPrices(market.bestBidPrice(), market.bestAskPrice());
});Reading Trader Balances
// Get a trader's balance on a specific market
const traderPubkey = new PublicKey('TRADER_ADDRESS');
// Withdrawable balance (deposited - locked in orders)
const baseBalance = market.getWithdrawableBalanceTokens(traderPubkey, true);
const quoteBalance = market.getWithdrawableBalanceTokens(traderPubkey, false);
// Check if trader has a seat
const hasSeat = market.hasSeat(traderPubkey);Wallet Integration (No Private Key)
For browser wallets like Phantom, use getSetupIxs and getClientForMarketNoPrivateKey:
import { Transaction } from '@solana/web3.js';
import { ManifestClient } from '@cks-systems/manifest-sdk';
async function setupAndGetClient(
connection: Connection,
marketAddress: PublicKey,
walletPubkey: PublicKey,
sendTransaction: (tx: Transaction) => Promise<string>,
) {
// Check if setup is needed (wrapper creation + seat claim)
const { setupNeeded, instructions, wrapperKeypair } =
await ManifestClient.getSetupIxs(connection, marketAddress, walletPubkey);
if (setupNeeded) {
const tx = new Transaction().add(...instructions);
tx.recentBlockhash = (await connection.getLatestBlockhash()).blockhash;
tx.feePayer = walletPubkey;
// Sign with wrapper keypair if creating new wrapper
if (wrapperKeypair) {
tx.partialSign(wrapperKeypair);
}
// Send via wallet adapter
await sendTransaction(tx);
// Wait for confirmation
await new Promise((resolve) => setTimeout(resolve, 5000));
}
// Create client (read-only, instructions must be signed by wallet)
const client = await ManifestClient.getClientForMarketNoPrivateKey(
connection,
marketAddress,
walletPubkey,
);
return client;
}Trading Bot Examples
Complete Bot Setup Flow
import {
Connection,
Keypair,
PublicKey,
Transaction,
sendAndConfirmTransaction,
ComputeBudgetProgram,
} from '@solana/web3.js';
import { ManifestClient, OrderType } from '@cks-systems/manifest-sdk';
const connection = new Connection('https://api.mainnet-beta.solana.com');
const trader = Keypair.fromSecretKey(Uint8Array.from(/* your key */));
const marketAddress = new PublicKey('YOUR_MARKET_ADDRESS');
// Step 1: Initialize client (auto-creates wrapper + claims seat)
const client = await ManifestClient.getClientForMarket(
connection,
marketAddress,
trader,
);
console.log('Market loaded:', client.market.address.toBase58());
console.log('Base mint:', client.market.baseMint().toBase58());
console.log('Quote mint:', client.market.quoteMint().toBase58());Depositing Funds
// Deposit base tokens (e.g., SOL)
const depositBaseIx = client.depositIx(
trader.publicKey,
client.market.baseMint(),
10.0, // Amount in tokens (not atoms)
);
// Deposit quote tokens (e.g., USDC)
const depositQuoteIx = client.depositIx(
trader.publicKey,
client.market.quoteMint(),
1000.0, // Amount in tokens
);
// Send deposit transaction
const depositTx = new Transaction().add(depositBaseIx, depositQuoteIx);
const depositSig = await sendAndConfirmTransaction(connection, depositTx, [
trader,
]);
console.log('Deposited:', depositSig);Placing Orders
// Place a limit bid
const bidIx = client.placeOrderIx({
numBaseTokens: 1.0,
tokenPrice: 95.0, // Price in quote per base
isBid: true,
lastValidSlot: 0, // 0 = no expiration
orderType: OrderType.Limit,
clientOrderId: 1, // Your reference ID
});
// Place a limit ask
const askIx = client.placeOrderIx({
numBaseTokens: 1.0,
tokenPrice: 105.0,
isBid: false,
lastValidSlot: 0,
orderType: OrderType.Limit,
clientOrderId: 2,
});
// Send orders
const orderTx = new Transaction().add(bidIx, askIx);
const orderSig = await sendAndConfirmTransaction(connection, orderTx, [trader]);Order Types
// Limit Order - standard order that can take or provide liquidity
const limitOrder = client.placeOrderIx({
numBaseTokens: 1.0,
tokenPrice: 100.0,
isBid: true,
lastValidSlot: 0,
orderType: OrderType.Limit,
clientOrderId: 1,
});
// Post-Only Order - rejected if it would immediately match
const postOnlyOrder = client.placeOrderIx({
numBaseTokens: 1.0,
tokenPrice: 100.0,
isBid: true,
lastValidSlot: 0,
orderType: OrderType.PostOnly,
clientOrderId: 2,
});
// Immediate-or-Cancel - fills what it can, cancels the rest
const iocOrder = client.placeOrderIx({
numBaseTokens: 1.0,
tokenPrice: 100.0,
isBid: true,
lastValidSlot: 0,
orderType: OrderType.ImmediateOrCancel,
clientOrderId: 3,
});
// Global Order - uses global account for cross-market liquidity
const globalOrder = client.placeOrderIx({
numBaseTokens: 1.0,
tokenPrice: 100.0,
isBid: true,
lastValidSlot: 0,
orderType: OrderType.Global,
clientOrderId: 4,
});Cancelling Orders
// Cancel by client order ID
const cancelIx = client.cancelOrderIx(1); // clientOrderId
// Cancel all orders on this market
const cancelAllIx = client.cancelAllIx();
// Cancel all bids only
const cancelBidsIx = client.cancelBidsOnCoreIx();
// Cancel all asks only
const cancelAsksIx = client.cancelAsksOnCoreIx();Withdrawing Funds
// Withdraw specific amount
const withdrawBaseIx = client.withdrawIx(
trader.publicKey,
client.market.baseMint(),
5.0, // Amount in tokens
);
// Withdraw all funds from market
const withdrawAllIx = client.withdrawAllIx();
const withdrawTx = new Transaction().add(...withdrawAllIx);
await sendAndConfirmTransaction(connection, withdrawTx, [trader]);Place Order with Auto-Deposit
Automatically deposits required funds if balance is insufficient:
const instructions = await client.placeOrderWithRequiredDepositIxs({
numBaseTokens: 1.0,
tokenPrice: 100.0,
isBid: true,
lastValidSlot: 0,
orderType: OrderType.Limit,
clientOrderId: 1,
});
// instructions array may include deposit ix before place order ix
const tx = new Transaction().add(...instructions);
await sendAndConfirmTransaction(connection, tx, [trader]);Complete Trading Loop Example
async function tradingBot() {
const client = await ManifestClient.getClientForMarket(
connection,
marketAddress,
trader,
);
while (true) {
// Reload market data
await client.market.reload(connection);
const bestBid = client.market.bestBidPrice();
const bestAsk = client.market.bestAskPrice();
const spread = bestAsk && bestBid ? (bestAsk - bestBid) / bestBid : null;
console.log(
`Best Bid: ${bestBid}, Best Ask: ${bestAsk}, Spread: ${spread}`,
);
// Check our balances
const baseBalance = client.market.getWithdrawableBalanceTokens(
trader.publicKey,
true,
);
const quoteBalance = client.market.getWithdrawableBalanceTokens(
trader.publicKey,
false,
);
console.log(`Balances - Base: ${baseBalance}, Quote: ${quoteBalance}`);
// Your trading logic here...
await new Promise((resolve) => setTimeout(resolve, 1000));
}
}Global Account Operations
Global accounts allow traders to share liquidity across multiple markets.
Setup Global Account
import { Global, ManifestClient } from '@cks-systems/manifest-sdk';
const mint = new PublicKey('TOKEN_MINT_ADDRESS');
// Add trader to global account (one-time setup)
const addTraderIx = await ManifestClient.createGlobalAddTraderIx(
connection,
trader.publicKey,
mint,
);
const tx = new Transaction().add(addTraderIx);
await sendAndConfirmTransaction(connection, tx, [trader]);Deposit to Global Account
// Deposit to global account (available across all markets for this token)
const globalDepositIx = await ManifestClient.globalDepositIx(
connection,
trader.publicKey,
mint,
100.0, // Amount in tokens
);
const tx = new Transaction().add(globalDepositIx);
await sendAndConfirmTransaction(connection, tx, [trader]);Withdraw from Global Account
const globalWithdrawIx = await ManifestClient.globalWithdrawIx(
connection,
trader.publicKey,
mint,
50.0, // Amount in tokens
);
const tx = new Transaction().add(globalWithdrawIx);
await sendAndConfirmTransaction(connection, tx, [trader]);Reading Global Account State
import { Global } from '@cks-systems/manifest-sdk';
// Load global account
const globalAddress = Global.findGlobalAddress(mint);
const global = await Global.loadFromAddress({
connection,
address: globalAddress,
});
// Check balances
const balance = await global.getGlobalBalanceTokens(
connection,
trader.publicKey,
);
console.log('Global balance:', balance);
// Check if trader has global seat
const hasSeat = global.hasSeat(trader.publicKey);Advanced Patterns
Batch Order Updates
// Cancel and replace multiple orders in one transaction
const batchIx = client.batchUpdateIx({
cancels: [{ clientOrderId: 1 }, { clientOrderId: 2 }],
orders: [
{
numBaseTokens: 1.0,
tokenPrice: 96.0,
isBid: true,
lastValidSlot: 0,
orderType: OrderType.Limit,
clientOrderId: 3,
},
{
numBaseTokens: 1.0,
tokenPrice: 104.0,
isBid: false,
lastValidSlot: 0,
orderType: OrderType.Limit,
clientOrderId: 4,
},
],
});Loading All Markets for a Trader
// Get clients for all markets where trader has a seat
const clients = await ManifestClient.getClientsReadOnlyForAllTraderSeats(
connection,
trader.publicKey,
);
for (const client of clients) {
console.log('Market:', client.market.address.toBase58());
const baseBalance = client.market.getWithdrawableBalanceTokens(
trader.publicKey,
true,
);
console.log('Base balance:', baseBalance);
}Fill Feed (Monitoring Trades)
import { FillFeed } from '@cks-systems/manifest-sdk';
const fillFeed = new FillFeed(connection);
// Subscribe to fills (runs indefinitely)
fillFeed.on('fill', (fill) => {
console.log('Fill:', {
market: fill.market.toBase58(),
maker: fill.maker.toBase58(),
taker: fill.taker.toBase58(),
baseTokens: fill.baseTokens,
quoteTokens: fill.quoteTokens,
price: fill.price,
takerIsBuy: fill.takerIsBuy,
});
});
await fillFeed.parseLogs(); // Starts monitoringError Handling
try {
const tx = new Transaction().add(client.placeOrderIx(/* ... */));
await sendAndConfirmTransaction(connection, tx, [trader]);
} catch (error) {
if (error.message.includes('InsufficientFunds')) {
console.log('Need to deposit more funds');
} else if (error.message.includes('PostOnlyWouldTake')) {
console.log('Post-only order would have crossed the spread');
} else if (error.message.includes('InvalidOrderType')) {
console.log('Order type not allowed');
} else {
throw error;
}
}Token2022 Support
The SDK automatically handles Token2022 tokens. No special configuration needed:
// Works the same for both SPL Token and Token2022
const client = await ManifestClient.getClientForMarket(
connection,
marketAddress, // Market with Token2022 tokens
trader,
);
// Token program is detected automatically
console.log('Is base Token2022:', client.isBase22);
console.log('Is quote Token2022:', client.isQuote22);
// All operations work identically
const depositIx = client.depositIx(
trader.publicKey,
client.market.baseMint(),
10.0,
);API Reference
ManifestClient
| Method | Description |
|---|---|
getClientForMarket(connection, marketPk, keypair) |
Create client with auto-setup |
getClientForMarketNoPrivateKey(connection, marketPk, trader) |
Create read-only client |
getSetupIxs(connection, marketPk, trader) |
Get setup instructions for wallet integration |
listMarketPublicKeys(connection) |
List all market addresses |
listMarketsForMints(connection, base, quote) |
Find markets for token pair |
depositIx(payer, mint, amount) |
Deposit tokens to market |
withdrawIx(payer, mint, amount) |
Withdraw tokens from market |
withdrawAllIx() |
Withdraw all funds |
placeOrderIx(params) |
Place an order |
cancelOrderIx(clientOrderId) |
Cancel specific order |
cancelAllIx() |
Cancel all orders |
batchUpdateIx(params) |
Batch cancel and place orders |
Market
| Method | Description |
|---|---|
loadFromAddress({connection, address}) |
Load market from chain |
loadFromBuffer({address, buffer}) |
Load from account data |
reload(connection) |
Refresh market data |
bids() |
Get bid orders |
asks() |
Get ask orders |
bestBidPrice() |
Get best bid price |
bestAskPrice() |
Get best ask price |
getWithdrawableBalanceTokens(trader, isBase) |
Get trader's available balance |
hasSeat(trader) |
Check if trader has seat |
baseMint() / quoteMint() |
Get token mints |
baseDecimals() / quoteDecimals() |
Get token decimals |
Global
| Method | Description |
|---|---|
loadFromAddress({connection, address}) |
Load global account |
findGlobalAddress(mint) |
Derive global account PDA |
getGlobalBalanceTokens(connection, trader) |
Get trader's global balance |
hasSeat(trader) |
Check if trader has global seat |
tokenMint() |
Get token mint |