显示类型脚本客户端
TypeScript SDK 用于与 Solana 上的 Manific 分散交换交互.
安装
yarn add @cks-systems/manifest-sdk
概览
SDK提供这些主要课程:
- 显式 - 建筑交易和阅读市场数据的初级课程
- 市场 - 取消序列和查询市场状况(订货簿、余额、座位)
- 包装 - 切断交易商的市场订单
- 全球 - 管理跨市场流动资金的全球账户状况
快速启动
用于UI应用程序(只读)
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());
用于贸易箱(全程访问)
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 整合实例
寻找市场
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,
);
正在装入市场数据
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());
阅读命令书
// 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: number
订阅市场更新
// 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());
});
阅读交易员余额
// 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);
钱包集成( 无私钥)
对于“幽灵”等浏览器钱包,请使用 getSetupIxs 财务报告和审定财务报表 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;
}
交易瓶实例
完成装瓶设置流程
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());
存款
// 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);
发布命令
// 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]);
顺序类型
// 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,
});
取消命令
// 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();
撤销资金
// 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]);
带有自动保存器的位置顺序
如果余额不足,自动存入所需资金:
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]);
完整交易循环示例
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));
}
}
全球账户业务
全球账户允许贸易商在多个市场分享流动性.
设置全球账户
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 (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]);
退出全球账户
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]);
正在读取全球账户状态
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);
高级图案
批次顺序更新
// 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,
},
],
});
为交易商装入全部市场
// 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);
}
填充种子( 监测交易)
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 monitoring
处理错误
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;
}
}
托肯2022 支持
SDK自动处理Token2022令牌. 不需要特殊配置 :
// 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 参考
显式
| 方法 | 说明 |
|---|---|
getClientForMarket(connection, marketPk, keypair) | 使用自动设置创建客户端 |
getClientForMarketNoPrivateKey(connection, marketPk, trader) | 创建只读客户端 |
getSetupIxs(connection, marketPk, trader) | 获取钱包集成的设置指令 |
listMarketPublicKeys(connection) | 列出所有市场地址 |
listMarketsForMints(connection, base, quote) | 寻找对符的市场 |
depositIx(payer, mint, amount) | 市场存款 |
withdrawIx(payer, mint, amount) | 退出市场 |
withdrawAllIx() | 撤销所有资金 |
placeOrderIx(params) | 设置命令 |
cancelOrderIx(clientOrderId) | 取消特定顺序 |
cancelAllIx() | 取消所有订单 |
batchUpdateIx(params) | 批次取消并发布命令 |
市场
| 方法 | 说明 |
|---|---|
loadFromAddress({connection, address}) | 从链上装入市场 |
loadFromBuffer({address, buffer}) | 从账户数据装入 |
reload(connection) | 刷新市场数据 |
bids() | 拿到出价单 |
asks() | 请求命令 |
bestBidPrice() | 买到最好的出价 |
bestAskPrice() | 最好问价 |
getWithdrawableBalanceTokens(trader, isBase) | 找到交易商的可用余额 |
hasSeat(trader) | 检查交易商是否有座位 |
baseMint() 编号 : quoteMint() | 买点薄荷 |
baseDecimals() 编号 : quoteDecimals() | 获得符号小数 |
全球
| 方法 | 说明 |
|---|---|
loadFromAddress({connection, address}) | 装入全局账户 |
findGlobalAddress(mint) | 衍生全球账户 PDA |
getGlobalBalanceTokens(connection, trader) | 获得交易商的全球平衡 |
hasSeat(trader) | 检查交易商是否有全局位置 |
tokenMint() | 获取纪念品薄荷 |