
Drift Sdk
- 14 installs
- 610 repo stars
- Updated June 26, 2026
- alsk1992/cloddsbot
Drift SDK is a Claude Code skill for direct SDK-based perpetual-futures trading on Drift Protocol, Solana's perp DEX, without a gateway server.
About
Drift SDK is a trading skill that connects an agent directly to Drift Protocol on Solana via the native SDK, bypassing the gateway server the base Drift skill needs. A developer uses /drift commands to open long/short positions, manage limit and market orders, set leverage, and track unrealized PnL and risk metrics. It requires a DRIFT_PRIVATE_KEY and optionally a Solana RPC URL, with a DRY_RUN test mode.
- Direct SDK-based perpetual-futures trading on Drift without a gateway server
- Supports market, limit, post-only, IOC and FOK order types with per-market leverage up to 20x
- Reports risk metrics: health factor, margin usage, and liquidation prices
Drift Sdk by the numbers
- 14 all-time installs (skills.sh)
- Ranked #752 of 1,106 Finance & Trading skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
drift-sdk capabilities & compatibility
Requires DRIFT_PRIVATE_KEY and trading capital; optional custom Solana RPC; DRY_RUN test mode available. No service fee stated.
- Capabilities
- perp trading · spot trading · order management · leverage control · risk metrics
- Use cases
- trading
- Runs
- Runs locally
- Pricing
- Bring your own API key
What drift-sdk says it does
Direct SDK-based trading on Drift Protocol, Solana's leading perpetual futures DEX. Bypass the gateway requirement with native SDK integration.
**Risk Metrics** - Health factor, margin usage, liquidation prices
npx skills add https://github.com/alsk1992/cloddsbot --skill drift-sdkAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 14 |
|---|---|
| repo stars | ★ 610 |
| Last updated | June 26, 2026 |
| Repository | alsk1992/cloddsbot ↗ |
What it does
Trade Drift perpetual futures on Solana directly through the native SDK with full order types and risk metrics.
Who is it for?
Agents that need direct Drift perp/spot trading with limit, post-only, IOC, and FOK orders.
Skip if: Users without a Solana private key or who prefer the gateway-based Drift skill.
When should I use this skill?
You want native SDK trading on Drift Protocol without running a gateway server.
What you get
Direct native-SDK trading on Drift with full order types, leverage control, and live risk metrics.
By the numbers
- Order types: market, limit, post-only, IOC, FOK
- Per-market leverage 1-20x
Files
Drift Protocol SDK
Direct SDK-based trading on Drift Protocol, Solana's leading perpetual futures DEX. Bypass the gateway requirement with native SDK integration.
Quick Start
# Set credentials
export DRIFT_PRIVATE_KEY="your-solana-private-key"
export SOLANA_RPC_URL="https://api.mainnet-beta.solana.com"
# Check balance
/drift balance
# Open a position
/drift long BTC 0.1
/drift short ETH 1 2500
# Close position
/drift close BTCCommands
Trading
| Command | Description |
|---|---|
/drift long <coin> <size> [price] | Open long position |
/drift short <coin> <size> [price] | Open short position |
/drift close <coin> | Close position at market |
/drift closeall | Close all positions |
/drift leverage <coin> <1-20> | Set leverage |
Examples:
/drift long BTC 0.1 # Market buy 0.1 BTC
/drift short ETH 1 2500 # Limit sell 1 ETH at $2500
/drift leverage SOL 5 # Set SOL leverage to 5xOrders
| Command | Description |
|---|---|
/drift orders | List open orders |
/drift cancel <orderId> | Cancel order by ID |
/drift cancel <coin> | Cancel all orders for coin |
/drift cancelall | Cancel all orders |
/drift modify <orderId> [price] [size] | Modify order |
Account
| Command | Description |
|---|---|
/drift balance | Collateral, margin, health factor |
/drift positions | Open positions with PnL |
Configuration
# Required
export DRIFT_PRIVATE_KEY="base58_or_json_array"
# Optional
export SOLANA_RPC_URL="https://api.mainnet-beta.solana.com"
export DRY_RUN=true # Test modeFeatures
- Direct SDK - No gateway server required
- Perp & Spot - Trade both market types
- Order Types - Market, limit, post-only, IOC, FOK
- Position Management - Track unrealized PnL, entry prices
- Risk Metrics - Health factor, margin usage, liquidation prices
- Leverage Control - Set per-market leverage (1-20x)
Markets
| Market | Index | Max Leverage |
|---|---|---|
| BTC-PERP | 0 | 20x |
| ETH-PERP | 1 | 20x |
| SOL-PERP | 2 | 20x |
| ... | ... | ... |
Resources
/**
* Drift Protocol SDK Skill
*
* CLI commands for Drift Protocol perpetual futures trading on Solana.
* Uses direct SDK integration (no gateway required).
*/
import { Connection, Keypair } from '@solana/web3.js';
import {
executeDriftDirectOrder,
cancelDriftOrder,
getDriftOrders,
getDriftPositions,
getDriftBalance,
modifyDriftOrder,
setDriftLeverage,
type DriftPositionInfo,
type DriftOrderInfo,
type DriftBalanceInfo,
} from '../../../solana/drift';
import { logger } from '../../../utils/logger';
import * as bs58Module from 'bs58';
const bs58 = (bs58Module as { default?: typeof bs58Module }).default || bs58Module;
// =============================================================================
// HELPERS
// =============================================================================
function formatNumber(n: number | string, decimals = 2): string {
const num = typeof n === 'string' ? parseFloat(n) : n;
if (isNaN(num)) return '0';
if (Math.abs(num) >= 1e9) return (num / 1e9).toFixed(decimals) + 'B';
if (Math.abs(num) >= 1e6) return (num / 1e6).toFixed(decimals) + 'M';
if (Math.abs(num) >= 1e3) return (num / 1e3).toFixed(decimals) + 'K';
return num.toFixed(decimals);
}
function formatPnl(pnl: number | string): string {
const num = typeof pnl === 'string' ? parseFloat(pnl) : pnl;
if (isNaN(num)) return '$0';
const sign = num >= 0 ? '+' : '';
return `${sign}$${formatNumber(Math.abs(num))}`;
}
function getConnection(): Connection {
const rpcUrl = process.env.SOLANA_RPC_URL || 'https://api.mainnet-beta.solana.com';
return new Connection(rpcUrl, 'confirmed');
}
function getKeypair(): Keypair | null {
const privateKey = process.env.DRIFT_PRIVATE_KEY;
if (!privateKey) return null;
try {
// Try base58 first
if (!privateKey.startsWith('[')) {
const decoded = bs58.decode(privateKey);
return Keypair.fromSecretKey(decoded);
}
// Try JSON array
const array = JSON.parse(privateKey);
return Keypair.fromSecretKey(Uint8Array.from(array));
} catch {
return null;
}
}
// Market index mapping
const MARKET_INDICES: Record<string, number> = {
'BTC': 0, 'BTC-PERP': 0,
'ETH': 1, 'ETH-PERP': 1,
'SOL': 2, 'SOL-PERP': 2,
'MATIC': 3, 'MATIC-PERP': 3,
'ARB': 4, 'ARB-PERP': 4,
'DOGE': 5, 'DOGE-PERP': 5,
'BNB': 6, 'BNB-PERP': 6,
'SUI': 7, 'SUI-PERP': 7,
'PEPE': 8, 'PEPE-PERP': 8,
'OP': 9, 'OP-PERP': 9,
};
const INDEX_TO_SYMBOL: Record<number, string> = {
0: 'BTC', 1: 'ETH', 2: 'SOL', 3: 'MATIC', 4: 'ARB',
5: 'DOGE', 6: 'BNB', 7: 'SUI', 8: 'PEPE', 9: 'OP',
};
function getMarketIndex(coin: string): number | null {
const key = coin.toUpperCase();
return MARKET_INDICES[key] ?? null;
}
function getSymbol(marketIndex: number): string {
return INDEX_TO_SYMBOL[marketIndex] || `MARKET-${marketIndex}`;
}
// =============================================================================
// HANDLERS
// =============================================================================
async function handleBalance(): Promise<string> {
const connection = getConnection();
const keypair = getKeypair();
if (!keypair) {
return 'DRIFT_PRIVATE_KEY not configured. Set it in environment variables.';
}
try {
const balance: DriftBalanceInfo = await getDriftBalance(connection, keypair);
return [
'**Drift Account Balance**',
'',
`Collateral: $${formatNumber(balance.totalCollateral)}`,
`Free Collateral: $${formatNumber(balance.freeCollateral)}`,
`Maintenance Margin: $${formatNumber(balance.maintenanceMargin)}`,
`Account Equity: $${formatNumber(balance.accountEquity)}`,
`Health Factor: ${balance.healthFactor.toFixed(1)}%`,
].join('\n');
} catch (error) {
logger.error('Failed to get Drift balance', error);
return `Error: ${error instanceof Error ? error.message : 'Failed to get balance'}`;
}
}
async function handlePositions(): Promise<string> {
const connection = getConnection();
const keypair = getKeypair();
if (!keypair) {
return 'DRIFT_PRIVATE_KEY not configured. Set it in environment variables.';
}
try {
const positions: DriftPositionInfo[] = await getDriftPositions(connection, keypair);
if (positions.length === 0) {
return 'No open positions';
}
const lines = ['**Drift Positions**', ''];
for (const pos of positions) {
const baseAmount = parseFloat(pos.baseAssetAmount);
const direction = baseAmount > 0 ? 'LONG' : 'SHORT';
const size = Math.abs(baseAmount);
const symbol = getSymbol(pos.marketIndex);
lines.push(`${symbol} ${direction}`);
lines.push(` Size: ${formatNumber(size)} | Entry: $${formatNumber(pos.entryPrice)}`);
lines.push(` Quote: $${formatNumber(pos.quoteAssetAmount)}`);
lines.push('');
}
return lines.join('\n').trim();
} catch (error) {
logger.error('Failed to get Drift positions', error);
return `Error: ${error instanceof Error ? error.message : 'Failed to get positions'}`;
}
}
async function handleOrders(): Promise<string> {
const connection = getConnection();
const keypair = getKeypair();
if (!keypair) {
return 'DRIFT_PRIVATE_KEY not configured. Set it in environment variables.';
}
try {
const orders: DriftOrderInfo[] = await getDriftOrders(connection, keypair);
if (orders.length === 0) {
return 'No open orders';
}
const lines = ['**Drift Open Orders**', ''];
for (const order of orders) {
const symbol = getSymbol(order.marketIndex);
lines.push(`[${order.orderId}] ${symbol} ${order.direction.toUpperCase()} ${order.orderType}`);
lines.push(` Size: ${formatNumber(order.baseAssetAmount)} @ $${formatNumber(order.price)}`);
lines.push('');
}
return lines.join('\n').trim();
} catch (error) {
logger.error('Failed to get Drift orders', error);
return `Error: ${error instanceof Error ? error.message : 'Failed to get orders'}`;
}
}
async function handleLong(args: string): Promise<string> {
const parts = args.trim().split(/\s+/);
if (parts.length < 2) {
return 'Usage: /drift long <coin> <size> [price]\nExample: /drift long BTC 0.1';
}
const [coin, sizeStr, priceStr] = parts;
const marketIndex = getMarketIndex(coin);
if (marketIndex === null) {
return `Unknown market: ${coin}. Supported: BTC, ETH, SOL, MATIC, ARB, DOGE, BNB, SUI, PEPE, OP`;
}
const size = parseFloat(sizeStr);
if (isNaN(size) || size <= 0) {
return 'Invalid size. Must be a positive number.';
}
const parsedPrice = priceStr ? parseFloat(priceStr) : undefined;
if (parsedPrice !== undefined && (isNaN(parsedPrice) || parsedPrice <= 0)) {
return 'Invalid price. Must be a positive number.';
}
const price = parsedPrice;
const orderType = price ? 'limit' : 'market';
const connection = getConnection();
const keypair = getKeypair();
if (!keypair) {
return 'DRIFT_PRIVATE_KEY not configured. Set it in environment variables.';
}
if (process.env.DRY_RUN === 'true') {
return `[DRY RUN] Would open LONG ${size} ${coin.toUpperCase()} @ ${price ? `$${price}` : 'market'}`;
}
try {
const result = await executeDriftDirectOrder(connection, keypair, {
marketIndex,
marketType: 'perp',
side: 'buy',
baseAmount: size.toString(),
price: price?.toString(),
orderType,
});
return [
`**Order Placed**`,
`${coin.toUpperCase()} LONG ${orderType.toUpperCase()}`,
`Size: ${size}`,
price ? `Price: $${price}` : 'Price: Market',
`Order ID: ${result.orderId}`,
].join('\n');
} catch (error) {
logger.error('Failed to place Drift order', error);
return `Error: ${error instanceof Error ? error.message : 'Failed to place order'}`;
}
}
async function handleShort(args: string): Promise<string> {
const parts = args.trim().split(/\s+/);
if (parts.length < 2) {
return 'Usage: /drift short <coin> <size> [price]\nExample: /drift short ETH 1 2500';
}
const [coin, sizeStr, priceStr] = parts;
const marketIndex = getMarketIndex(coin);
if (marketIndex === null) {
return `Unknown market: ${coin}. Supported: BTC, ETH, SOL, MATIC, ARB, DOGE, BNB, SUI, PEPE, OP`;
}
const size = parseFloat(sizeStr);
if (isNaN(size) || size <= 0) {
return 'Invalid size. Must be a positive number.';
}
const parsedPrice = priceStr ? parseFloat(priceStr) : undefined;
if (parsedPrice !== undefined && (isNaN(parsedPrice) || parsedPrice <= 0)) {
return 'Invalid price. Must be a positive number.';
}
const price = parsedPrice;
const orderType = price ? 'limit' : 'market';
const connection = getConnection();
const keypair = getKeypair();
if (!keypair) {
return 'DRIFT_PRIVATE_KEY not configured. Set it in environment variables.';
}
if (process.env.DRY_RUN === 'true') {
return `[DRY RUN] Would open SHORT ${size} ${coin.toUpperCase()} @ ${price ? `$${price}` : 'market'}`;
}
try {
const result = await executeDriftDirectOrder(connection, keypair, {
marketIndex,
marketType: 'perp',
side: 'sell',
baseAmount: size.toString(),
price: price?.toString(),
orderType,
});
return [
`**Order Placed**`,
`${coin.toUpperCase()} SHORT ${orderType.toUpperCase()}`,
`Size: ${size}`,
price ? `Price: $${price}` : 'Price: Market',
`Order ID: ${result.orderId}`,
].join('\n');
} catch (error) {
logger.error('Failed to place Drift order', error);
return `Error: ${error instanceof Error ? error.message : 'Failed to place order'}`;
}
}
async function handleClose(args: string): Promise<string> {
const coin = args.trim().toUpperCase();
if (!coin) {
return 'Usage: /drift close <coin>\nExample: /drift close BTC';
}
const marketIndex = getMarketIndex(coin);
if (marketIndex === null) {
return `Unknown market: ${coin}. Supported: BTC, ETH, SOL, MATIC, ARB, DOGE, BNB, SUI, PEPE, OP`;
}
const connection = getConnection();
const keypair = getKeypair();
if (!keypair) {
return 'DRIFT_PRIVATE_KEY not configured. Set it in environment variables.';
}
try {
// Get position to determine direction and size
const positions = await getDriftPositions(connection, keypair, marketIndex);
const position = positions[0];
if (!position) {
return `No open position for ${coin}`;
}
const baseAmount = parseFloat(position.baseAssetAmount);
if (baseAmount === 0) {
return `No open position for ${coin}`;
}
const side = baseAmount > 0 ? 'sell' : 'buy';
const size = Math.abs(baseAmount);
if (process.env.DRY_RUN === 'true') {
return `[DRY RUN] Would close ${coin} position (${size} ${baseAmount > 0 ? 'LONG' : 'SHORT'})`;
}
const result = await executeDriftDirectOrder(connection, keypair, {
marketIndex,
marketType: 'perp',
side,
baseAmount: size.toString(),
orderType: 'market',
});
return [
`**Position Closed**`,
`${coin} closed at market`,
`Order ID: ${result.orderId}`,
].join('\n');
} catch (error) {
logger.error('Failed to close Drift position', error);
return `Error: ${error instanceof Error ? error.message : 'Failed to close position'}`;
}
}
async function handleCancel(args: string): Promise<string> {
const arg = args.trim();
const connection = getConnection();
const keypair = getKeypair();
if (!keypair) {
return 'DRIFT_PRIVATE_KEY not configured. Set it in environment variables.';
}
if (process.env.DRY_RUN === 'true') {
return `[DRY RUN] Would cancel order(s): ${arg || 'all'}`;
}
try {
// Check if it's a market name or order ID
const marketIndex = getMarketIndex(arg);
if (marketIndex !== null) {
// Cancel all orders for market
const result = await cancelDriftOrder(connection, keypair, {
marketIndex,
marketType: 'perp',
});
return `Cancelled ${result.cancelled.length} order(s) for ${arg.toUpperCase()}. TX: ${result.txSig}`;
} else if (arg) {
// Cancel by order ID
const orderId = parseInt(arg, 10);
if (isNaN(orderId)) {
return 'Invalid order ID. Use /drift cancel <orderId> or /drift cancel <coin>';
}
const result = await cancelDriftOrder(connection, keypair, { orderId });
return result.cancelled.length > 0
? `Order ${orderId} cancelled. TX: ${result.txSig}`
: `Failed to cancel order ${orderId}`;
} else {
return 'Usage: /drift cancel <orderId> or /drift cancel <coin>';
}
} catch (error) {
logger.error('Failed to cancel Drift order', error);
return `Error: ${error instanceof Error ? error.message : 'Failed to cancel order'}`;
}
}
async function handleCancelAll(): Promise<string> {
const connection = getConnection();
const keypair = getKeypair();
if (!keypair) {
return 'DRIFT_PRIVATE_KEY not configured. Set it in environment variables.';
}
if (process.env.DRY_RUN === 'true') {
return '[DRY RUN] Would cancel all orders';
}
try {
// Cancel orders for all markets
let totalCancelled = 0;
for (let i = 0; i <= 9; i++) {
try {
const result = await cancelDriftOrder(connection, keypair, {
marketIndex: i,
marketType: 'perp',
});
totalCancelled += result.cancelled.length;
} catch {
// Ignore errors for individual markets
}
}
return `Cancelled ${totalCancelled} order(s)`;
} catch (error) {
logger.error('Failed to cancel all Drift orders', error);
return `Error: ${error instanceof Error ? error.message : 'Failed to cancel orders'}`;
}
}
async function handleLeverage(args: string): Promise<string> {
const parts = args.trim().split(/\s+/);
if (parts.length < 2) {
return 'Usage: /drift leverage <coin> <value>\nExample: /drift leverage BTC 5';
}
const [coin, leverageStr] = parts;
const marketIndex = getMarketIndex(coin);
if (marketIndex === null) {
return `Unknown market: ${coin}. Supported: BTC, ETH, SOL, MATIC, ARB, DOGE, BNB, SUI, PEPE, OP`;
}
const leverage = parseInt(leverageStr, 10);
if (isNaN(leverage) || leverage < 1 || leverage > 20) {
return 'Invalid leverage. Must be between 1 and 20.';
}
const connection = getConnection();
const keypair = getKeypair();
if (!keypair) {
return 'DRIFT_PRIVATE_KEY not configured. Set it in environment variables.';
}
if (process.env.DRY_RUN === 'true') {
return `[DRY RUN] Would set ${coin.toUpperCase()} leverage to ${leverage}x`;
}
try {
const result = await setDriftLeverage(connection, keypair, {
marketIndex,
leverage,
});
return `Set ${coin.toUpperCase()} leverage to ${result.leverage}x. TX: ${result.txSig}`;
} catch (error) {
logger.error('Failed to set Drift leverage', error);
return `Error: ${error instanceof Error ? error.message : 'Failed to set leverage'}`;
}
}
// =============================================================================
// MAIN HANDLER
// =============================================================================
export async function handle(args: string): Promise<string> {
const parts = args.trim().split(/\s+/);
const command = parts[0]?.toLowerCase() || '';
const rest = parts.slice(1).join(' ');
switch (command) {
case '':
case 'help':
return [
'**Drift Protocol SDK Commands**',
'',
'`/drift balance` - Account balance & margin',
'`/drift positions` - Open positions',
'`/drift orders` - Open orders',
'`/drift long <coin> <size> [price]` - Open long',
'`/drift short <coin> <size> [price]` - Open short',
'`/drift close <coin>` - Close position',
'`/drift cancel <orderId|coin>` - Cancel order(s)',
'`/drift cancelall` - Cancel all orders',
'`/drift leverage <coin> <1-20>` - Set leverage',
].join('\n');
case 'balance':
case 'b':
return handleBalance();
case 'positions':
case 'pos':
case 'p':
return handlePositions();
case 'orders':
case 'o':
return handleOrders();
case 'long':
case 'l':
return handleLong(rest);
case 'short':
case 's':
return handleShort(rest);
case 'close':
return handleClose(rest);
case 'cancel':
return handleCancel(rest);
case 'cancelall':
return handleCancelAll();
case 'leverage':
case 'lev':
return handleLeverage(rest);
default:
return `Unknown command: ${command}. Use /drift help for available commands.`;
}
}
export default {
name: 'drift-sdk',
description: 'Drift Protocol SDK - Direct SDK integration for perpetual futures trading on Solana',
commands: ['/drift-sdk'],
handle,
};