This guide covers advanced features of the Drift SDK including custom transaction handling, event processing, high-leverage mode, and advanced order types.
Custom Transaction Handling
Custom Transaction Sender
Implement custom transaction submission logic:
import { TxSender , TxSigAndSlot } from '@drift-labs/sdk' ;
import { Transaction , VersionedTransaction , TransactionSignature } from '@solana/web3.js' ;
class CustomTxSender implements TxSender {
async send (
tx : Transaction | VersionedTransaction ,
additionalSigners ?: Signer [],
opts ?: any
) : Promise < TxSigAndSlot > {
// Custom transaction logic
console . log ( 'Sending custom transaction...' );
// Add your custom preflight checks
// Add custom signing logic
// Add custom retry logic
const signature = await this . connection . sendTransaction ( tx , opts );
const slot = await this . connection . getSlot ();
return { txSig: signature , slot };
}
async sendVersionedTransaction (
tx : VersionedTransaction ,
opts ?: any
) : Promise < TxSigAndSlot > {
// Custom versioned transaction logic
const signature = await this . connection . sendTransaction ( tx , opts );
const slot = await this . connection . getSlot ();
return { txSig: signature , slot };
}
}
// Use custom sender
const customSender = new CustomTxSender ();
const driftClient = new DriftClient ({
// ... other config
txSender: customSender ,
});
Priority Fees
Add compute budget and priority fees to transactions:
import {
ComputeBudgetProgram ,
TransactionInstruction ,
} from '@solana/web3.js' ;
// Add compute budget instructions
const computeUnitLimit = ComputeBudgetProgram . setComputeUnitLimit ({
units: 400_000 ,
});
const computeUnitPrice = ComputeBudgetProgram . setComputeUnitPrice ({
microLamports: 100_000 , // 0.0001 SOL per CU
});
// Add to transaction
const tx = await driftClient . buildTransaction (
// your instruction
);
tx . add ( computeUnitLimit );
tx . add ( computeUnitPrice );
await driftClient . sendTransaction ( tx );
Dynamic Priority Fees
import { PriorityFeeSubscriber } from '@drift-labs/sdk' ;
// Subscribe to recommended priority fees
const priorityFeeSubscriber = new PriorityFeeSubscriber ({
connection: driftClient . connection ,
frequencyMs: 10_000 , // Update every 10 seconds
});
await priorityFeeSubscriber . subscribe ();
// Get recommended fee for transaction
const recommendedFee = priorityFeeSubscriber . getCustomStrategyResult (
'drift_trades' // strategy name
);
console . log ( 'Recommended priority fee:' , recommendedFee );
Event Processing
Transaction Event Parsing
import { EventSubscriber , WrappedEvent } from '@drift-labs/sdk' ;
// Subscribe to Drift program events
const eventSubscriber = new EventSubscriber ({
connection: driftClient . connection ,
programId: driftClient . program . programId ,
});
await eventSubscriber . subscribe ();
// Listen for specific events
eventSubscriber . eventEmitter . on ( 'newEvent' , ( event : WrappedEvent ) => {
if ( event . eventType === 'OrderRecord' ) {
const orderRecord = event . data as OrderRecord ;
console . log ( 'Order placed:' );
console . log ( ' User:' , orderRecord . user . toBase58 ());
console . log ( ' Order ID:' , orderRecord . orderId );
console . log ( ' Direction:' , orderRecord . direction );
console . log ( ' Base amount:' , orderRecord . baseAssetAmount . toString ());
}
if ( event . eventType === 'OrderActionRecord' ) {
const actionRecord = event . data as OrderActionRecord ;
console . log ( 'Order action:' );
console . log ( ' Action:' , actionRecord . action );
console . log ( ' Fill amount:' , actionRecord . baseAssetAmountFilled ?. toString ());
console . log ( ' Fill price:' , actionRecord . quoteAssetAmountFilled ?. toString ());
}
});
Parse Transaction Logs
import { parseLogsForFailedExplicitCancel } from '@drift-labs/sdk' ;
// Parse transaction logs for specific events
const txSig = await driftClient . placePerpOrder ( orderParams );
const tx = await driftClient . connection . getTransaction ( txSig , {
commitment: 'confirmed' ,
});
if ( tx ?. meta ?. logMessages ) {
const failedCancel = parseLogsForFailedExplicitCancel ( tx . meta . logMessages );
if ( failedCancel ) {
console . log ( 'Order cancel failed for:' , failedCancel );
}
}
High Leverage Mode
High Leverage Mode allows increased position leverage with specific margin requirements:
import { HighLeverageModeConfig } from '@drift-labs/sdk' ;
// Get high leverage mode config
const hlmConfig = await driftClient . getHighLeverageModeConfig ( perpMarketIndex );
if ( hlmConfig ) {
console . log ( 'Max leverage:' , hlmConfig . maxLeverage );
console . log ( 'IMF factor:' , hlmConfig . imfFactor );
console . log ( 'Reduce only:' , hlmConfig . reduceOnly );
}
// Enable high leverage mode for user
await driftClient . updateUserHighLeverageMode (
perpMarketIndex ,
true // enable
);
// Check if user has HLM enabled
const userAccount = user . getUserAccount ();
const hasHLM = userAccount . perpPositions [ perpMarketIndex ]?. highLeverageMode === true ;
console . log ( 'High leverage mode enabled:' , hasHLM );
High Leverage Mode has higher margin requirements and liquidation risk. Only use if you understand the risks.
Advanced Order Features
Place and Take
Place an order and immediately attempt to fill it against the book:
import { PlaceAndTakeOrderSuccessCondition } from '@drift-labs/sdk' ;
const orderParams = getLimitOrderParams ({
marketIndex: 0 ,
direction: PositionDirection . LONG ,
baseAssetAmount: new BN ( 1 ). mul ( BASE_PRECISION ),
price: new BN ( 145 ). mul ( PRICE_PRECISION ),
});
// Place and immediately attempt to fill
await driftClient . placeAndTakePerpOrder (
orderParams ,
undefined , // fulfillment config
PlaceAndTakeOrderSuccessCondition . PARTIAL_FILL // Success condition
);
Protected Maker Mode
Protected Maker Mode prevents your maker orders from being filled by your own taker orders:
// Enable protected maker mode
await driftClient . updateUserProtectedMakerMode ( true );
// Check if enabled
const userAccount = user . getUserAccount ();
console . log ( 'Protected maker:' , userAccount . isProtectedMaker );
Maker Order Referrals
Set maker referral for order rebates:
import { getReferrerInfo } from '@drift-labs/sdk' ;
// Get referrer public key
const referrerInfo = await getReferrerInfo ( referrerName , driftClient );
const orderParams = getLimitOrderParams ({
// ... order params
makerOrderId: 42 , // optional custom ID
});
// Place order with referral
await driftClient . placePerpOrder ( orderParams , {
referrerInfo ,
});
Bulk Operations
Cancel Multiple Orders
// Cancel specific orders
const orderIds = [ 1 , 2 , 3 , 4 , 5 ];
await driftClient . cancelOrders (
MarketType . PERP ,
undefined , // market index (undefined = all markets)
PositionDirection . LONG , // direction (undefined = both)
orderIds
);
// Cancel all orders for a market
await driftClient . cancelOrdersByMarketType ( MarketType . PERP );
// Cancel all orders for a user
await driftClient . cancelAllOrders ();
Batch Place Orders
import { OrderParams } from '@drift-labs/sdk' ;
// Create multiple orders
const orders : OrderParams [] = [
getLimitOrderParams ({
marketIndex: 0 ,
direction: PositionDirection . LONG ,
baseAssetAmount: new BN ( 1 ). mul ( BASE_PRECISION ),
price: new BN ( 140 ). mul ( PRICE_PRECISION ),
}),
getLimitOrderParams ({
marketIndex: 0 ,
direction: PositionDirection . LONG ,
baseAssetAmount: new BN ( 1 ). mul ( BASE_PRECISION ),
price: new BN ( 142 ). mul ( PRICE_PRECISION ),
}),
getLimitOrderParams ({
marketIndex: 0 ,
direction: PositionDirection . LONG ,
baseAssetAmount: new BN ( 1 ). mul ( BASE_PRECISION ),
price: new BN ( 144 ). mul ( PRICE_PRECISION ),
}),
];
// Place all orders in one transaction
await driftClient . placeOrders ( orders );
Spot Swaps
Swap between spot assets:
import { SwapDirection } from '@drift-labs/sdk' ;
// Swap USDC for SOL
await driftClient . swap (
new BN ( 100 ). mul ( QUOTE_PRECISION ), // 100 USDC
0 , // USDC market
1 , // SOL market
SwapDirection . ADD // ADD = buy SOL, REMOVE = sell SOL
);
With Slippage Protection
// Swap with maximum slippage
const amountIn = new BN ( 100 ). mul ( QUOTE_PRECISION );
const expectedOut = new BN ( 0.5 ). mul ( BASE_PRECISION ); // Expect ~0.5 SOL
const maxSlippage = new BN ( 50 ); // 0.5% = 50 / 10000
const minOut = expectedOut
. mul ( new BN ( 10000 ). sub ( maxSlippage ))
. div ( new BN ( 10000 ));
await driftClient . swap (
amountIn ,
0 , // USDC
1 , // SOL
SwapDirection . ADD ,
minOut // Minimum output amount
);
Address Lookup Tables
Use address lookup tables to reduce transaction size:
import { AddressLookupTableAccount } from '@solana/web3.js' ;
// Load lookup table
const lookupTableAddress = new PublicKey ( '...' );
const lookupTableAccount = await connection
. getAddressLookupTable ( lookupTableAddress )
. then ( res => res . value );
if ( lookupTableAccount ) {
// Use in transactions
const tx = await driftClient . buildTransaction (
instruction ,
[ lookupTableAccount ] // address lookup tables
);
await driftClient . sendTransaction ( tx );
}
Custom Confirmations
import { ConfirmOptions } from '@solana/web3.js' ;
const customOpts : ConfirmOptions = {
commitment: 'processed' , // processed | confirmed | finalized
preflightCommitment: 'processed' ,
skipPreflight: false ,
maxRetries: 3 ,
};
const driftClient = new DriftClient ({
// ... other config
opts: customOpts ,
});
// Or override per transaction
await driftClient . placePerpOrder ( orderParams , undefined , customOpts );
Rate Limiting
import pLimit from 'p-limit' ;
// Limit concurrent operations
const limit = pLimit ( 5 ); // Max 5 concurrent operations
const operations = markets . map ( marketIndex =>
limit ( async () => {
const market = driftClient . getPerpMarketAccount ( marketIndex );
const oracleData = driftClient . getOracleDataForPerpMarket ( marketIndex );
return {
marketIndex ,
price: oracleData . price ,
};
})
);
const results = await Promise . all ( operations );
Best Practices
Use retry logic for transactions
async function sendWithRetry ( fn : () => Promise < string >, maxRetries = 3 ) {
for ( let i = 0 ; i < maxRetries ; i ++ ) {
try {
return await fn ();
} catch ( error ) {
if ( i === maxRetries - 1 ) throw error ;
console . log ( `Retry ${ i + 1 } / ${ maxRetries } ` );
await new Promise ( r => setTimeout ( r , 1000 * ( i + 1 )));
}
}
}
const txSig = await sendWithRetry (() =>
driftClient . placePerpOrder ( orderParams )
);
Handle compute budget appropriately
Different operations require different compute budgets. Monitor your transactions and adjust accordingly.
Always listen to event logs to confirm your operations executed as expected.
Batch operations when possible
Use batch operations like placeOrders to save on transaction fees and reduce latency.
Next Steps
Examples Real-world implementation examples
API Reference Complete API documentation
Trading API Advanced trading features
Event Listening Process transaction events