This commit is contained in:
wphan
2022-11-29 16:29:46 -08:00
commit 74554249e4
13 changed files with 5497 additions and 0 deletions

178
example/client.ts Normal file
View File

@@ -0,0 +1,178 @@
import fetch from "node-fetch";
import {
BulkAccountLoader,
calculateAskPrice,
calculateBidPrice,
convertToNumber,
DLOB,
DLOBOrders,
DLOBOrdersCoder,
DriftClient,
EventSubscriber,
getVariant,
initialize,
MarketType,
OrderActionRecord,
OrderRecord,
PRICE_PRECISION,
Wallet,
WrappedEvent,
} from "@drift-labs/sdk";
import { Connection, Keypair, PublicKey } from "@solana/web3.js";
/********** SET THESE **********/
const dlobServerURL = "http://localhost:6969/orders/idl";
// const dlobServerURL = "https://dlob.drift.trade/orders/idl";
// const rpcEndpoint = "https://solana-api.syndica.io/access-token/eqLMxrnnLgz5eSGKsPIaFK0dSvJeYCNviWhnIgaAH3YdM0K6C6tQdctk94Rb9mCX/rpc";
// const driftEnv = "mainnet-beta";
// const dlobServerURL = "https://master.dlob.drift.trade/orders/idl";
const rpcEndpoint = "https://api.devnet.solana.com";
const driftEnv = "devnet";
const initializedKey = [1, 2, 3, 4, 5]; // private key to initialize driftClient
/*******************************/
//@ts-ignore
const sdkConfig = initialize({ env: driftEnv });
const stateCommitment = 'confirmed';
const keypair = Keypair.fromSecretKey(Uint8Array.from(initializedKey));
const wallet = new Wallet(keypair);
const connection = new Connection(rpcEndpoint, stateCommitment);
const driftClientPublicKey = new PublicKey(sdkConfig.DRIFT_PROGRAM_ID);
/********** initializing driftClient as usual **********/
const bulkAccountLoader = new BulkAccountLoader(
connection,
stateCommitment,
1000
);
const driftClient = new DriftClient({
connection,
wallet,
programID: driftClientPublicKey,
accountSubscription: {
type: 'polling',
accountLoader: bulkAccountLoader,
},
env: driftEnv,
userStats: true,
});
const eventSubscriber = new EventSubscriber(connection, driftClient.program, {
maxTx: 8192,
maxEventsPerType: 8192,
orderBy: 'blockchain',
orderDir: 'desc',
commitment: stateCommitment,
logProviderConfig: {
type: 'polling',
frequency: 1000,
// type: 'websocket',
},
});
let maxDlobSlot = 0;
const dlob = new DLOB();
driftClient.subscribe().then((success) => {
if (!success) {
throw new Error("DriftClient subscription failed");
}
eventSubscriber.subscribe().then((success) => {
if (!success) {
throw new Error("EventSubscriber subscription failed");
}
/********** Example for updating dlob on events **********/
eventSubscriber.eventEmitter.on('newEvent', async (event: WrappedEvent<any>) => {
// NOTE: only apply events if they're newer than the last
// only apply new events if they're newer than the last slot we've seen
if (event.eventType === "OrderRecord") {
const record = event as OrderRecord;
if (maxDlobSlot > 0 && event.slot > maxDlobSlot) {
dlob.handleOrderRecord(record);
console.log(`Handled OrderRecord event for market ${record.order.marketIndex}`);
printDlob(record.order.marketIndex, dlob);
}
} else if (event.eventType === "OrderActionRecord") {
const record = event as OrderActionRecord;
if (maxDlobSlot > 0 && event.slot > maxDlobSlot) {
dlob.handleOrderActionRecord(record);
console.log(`Handled OrderActionRecord event for market ${record.marketIndex}, action: ${getVariant(record.action)} ${getVariant(record.actionExplanation)}`);
printDlob(record.marketIndex, dlob);
}
}
});
doDlobDemo();
});
});
/********** Example for initializing dlob **********/
function getLatestSlotFromOrders(dlobOrders: DLOBOrders): number {
return Math.max(...dlobOrders.map((dlobOrder) => dlobOrder.order.slot.toNumber()));
}
function printDlob(marketIndex: number, dlob: DLOB) {
const currSlot = bulkAccountLoader.mostRecentSlot;
const marketAccount = driftClient.getPerpMarketAccount(marketIndex);
const oracle = driftClient.getOracleDataForPerpMarket(marketIndex);
// you can also set vBid and vAsk to undefined to omit the vAMM price node from bids and asks
const vBid = calculateBidPrice(marketAccount!, oracle);
const vAsk = calculateAskPrice(marketAccount!, oracle);
const dlobBids = dlob.getBids(marketIndex, vBid, currSlot, MarketType.PERP, oracle);
const dlobAsks = dlob.getAsks(marketIndex, vAsk, currSlot, MarketType.PERP, oracle);
console.log(`DLOB for market ${marketIndex}:`);
console.log("Asks");
const dlobAsksArray = Array(...dlobAsks).reverse();
let countAsks = dlobAsksArray.length;
for (const ask of dlobAsksArray) {
const isVamm = ask.isVammNode();
console.log(` [${countAsks}] ${isVamm ? "vAMMNode" : getVariant(ask.order?.orderType)} ${convertToNumber(ask.getPrice(oracle, currSlot), PRICE_PRECISION)}`);
countAsks--;
}
console.log("Bids");
let countBids = 0;
for (const bid of dlobBids) {
const isVamm = bid.isVammNode();
console.log(` [${countBids}] ${isVamm ? "vAMMNode" : getVariant(bid.order?.orderType)} ${convertToNumber(bid.getPrice(oracle, currSlot), PRICE_PRECISION)}`);
countBids++;
}
console.log("");
}
function doDlobDemo() {
const dlobCoder = DLOBOrdersCoder.create();
fetch(dlobServerURL)
.then(
(r) => {
r.arrayBuffer().then((b) => {
const dlobOrders = dlobCoder.decode(Buffer.from(b));
// console.log(JSON.stringify(dlobOrders, null, 2));
console.log(`dlob orders count: ${dlobOrders.length}`);
dlob.initFromOrders(dlobOrders);
maxDlobSlot = getLatestSlotFromOrders(dlobOrders);
console.log(`maxSlot from DLOB init orders: ${maxDlobSlot}`);
console.log("Initialized DLOb from server");
printDlob(0, dlob);
printDlob(1, dlob);
printDlob(2, dlob);
});
});
}

203
example/clientWithSlot.ts Normal file
View File

@@ -0,0 +1,203 @@
/**
* Usage:
* ts-node clientWithSlot.ts
*/
import fetch from "node-fetch";
import {
BulkAccountLoader,
calculateAskPrice,
calculateBidPrice,
convertToNumber,
DLOB,
DLOBOrders,
DLOBOrdersCoder,
DriftClient,
DriftClientSubscriptionConfig,
EventSubscriber,
getVariant,
initialize,
LogProviderConfig,
MarketType,
OrderActionRecord,
OrderRecord,
PRICE_PRECISION,
Wallet,
WrappedEvent,
} from "@drift-labs/sdk";
import { Connection, Keypair, PublicKey } from "@solana/web3.js";
/********** SET THESE **********/
// const dlobServerURL = "http://localhost:6969/orders/idlWithSlot";
const dlobServerURL = "https://dlob.drift.trade/orders/idlWithSlot";
const rpcEndpoint = "https://api.mainnet-beta.solana.com";
const driftEnv = "mainnet-beta";
// const dlobServerURL = "https://master.dlob.drift.trade/orders/idlWithSlot";
// const rpcEndpoint = "https://api.devnet.solana.com";
// const driftEnv = "devnet";
const initializedKey = [1, 2, 3, 4, 5]; // private key to initialize driftClient
const useWebsocket = true;
const levelsToPrint = 10;
/*******************************/
//@ts-ignore
const sdkConfig = initialize({ env: driftEnv });
const stateCommitment = 'confirmed';
const keypair = Keypair.fromSecretKey(Uint8Array.from(initializedKey));
const wallet = new Wallet(keypair);
const connection = new Connection(rpcEndpoint, stateCommitment);
const driftClientPublicKey = new PublicKey(sdkConfig.DRIFT_PROGRAM_ID);
let lastSeenSlot = 0;
/********** initializing driftClient as usual **********/
var accountSubscription: DriftClientSubscriptionConfig;
var logProviderConfig: LogProviderConfig;
if (useWebsocket) {
accountSubscription = {
type: 'websocket',
};
logProviderConfig = {
type: 'websocket',
};
} else {
accountSubscription = {
type: 'polling',
accountLoader: new BulkAccountLoader(
connection,
stateCommitment,
10000
),
};
logProviderConfig = {
type: 'polling',
frequency: 10000,
};
}
const driftClient = new DriftClient({
connection,
wallet,
programID: driftClientPublicKey,
accountSubscription,
env: driftEnv,
userStats: true,
});
const eventSubscriber = new EventSubscriber(connection, driftClient.program, {
maxTx: 8192,
maxEventsPerType: 8192,
orderBy: 'blockchain',
orderDir: 'desc',
commitment: stateCommitment,
logProviderConfig,
});
const maxDlobSlot = 0;
const dlob = new DLOB();
driftClient.subscribe().then((success) => {
if (!success) {
throw new Error("DriftClient subscription failed");
}
eventSubscriber.subscribe().then((success) => {
if (!success) {
throw new Error("EventSubscriber subscription failed");
}
/********** Example for updating dlob on events **********/
eventSubscriber.eventEmitter.on('newEvent', async (event: WrappedEvent<any>) => {
// NOTE: only apply events if they're newer than the last
// only apply new events if they're newer than the last slot we've seen
lastSeenSlot = event.slot;
if (event.eventType === "OrderRecord") {
const record = event as OrderRecord;
if (maxDlobSlot > 0 && event.slot > maxDlobSlot) {
dlob.handleOrderRecord(record, event.slot);
console.log(`Handled OrderRecord event for market ${record.order.marketIndex}`);
printDlob(record.order.marketIndex, dlob);
}
} else if (event.eventType === "OrderActionRecord") {
const record = event as OrderActionRecord;
if (maxDlobSlot > 0 && event.slot > maxDlobSlot) {
dlob.handleOrderActionRecord(record, event.slot);
console.log(`Handled OrderActionRecord event for market ${record.marketIndex}, action: ${getVariant(record.action)} ${getVariant(record.actionExplanation)}`);
printDlob(record.marketIndex, dlob);
}
}
});
setInterval(doDlobDemo, 10000);
});
});
/********** Example for initializing dlob **********/
function _getLatestSlotFromOrders(dlobOrders: DLOBOrders): number {
return Math.max(...dlobOrders.map((dlobOrder) => dlobOrder.order.slot.toNumber()));
}
function printDlob(marketIndex: number, dlob: DLOB) {
const currSlot = lastSeenSlot;
if (lastSeenSlot === 0) {
console.log('waiting for first slot update...');
return;
}
const marketAccount = driftClient.getPerpMarketAccount(marketIndex);
const oracle = driftClient.getOracleDataForPerpMarket(marketIndex);
// you can also set vBid and vAsk to undefined to omit the vAMM price node from bids and asks
const vBid = calculateBidPrice(marketAccount!, oracle);
const vAsk = calculateAskPrice(marketAccount!, oracle);
const dlobBids = dlob.getBids(marketIndex, vBid, lastSeenSlot, MarketType.PERP, oracle);
const dlobAsks = dlob.getAsks(marketIndex, vAsk, lastSeenSlot, MarketType.PERP, oracle);
console.log(`DLOB for market ${marketIndex}:`);
console.log("Asks");
const dlobAsksArray = Array(...dlobAsks).reverse();
let countAsks = dlobAsksArray.length;
for (const ask of dlobAsksArray) {
const isVamm = ask.isVammNode();
if (countAsks < levelsToPrint) {
console.log(` [${countAsks - 1}] ${isVamm ? "vAMMNode" : getVariant(ask.order?.orderType)} ${convertToNumber(ask.getPrice(oracle, currSlot), PRICE_PRECISION)} (oraclePriceOffset: ${ask.order?.oraclePriceOffset || 0 * PRICE_PRECISION})`);
}
countAsks--;
}
console.log("Bids");
let countBids = 0;
for (const bid of dlobBids) {
const isVamm = bid.isVammNode();
if (countBids < levelsToPrint) {
console.log(` [${countBids}] ${isVamm ? "vAMMNode" : getVariant(bid.order?.orderType)} ${convertToNumber(bid.getPrice(oracle, currSlot), PRICE_PRECISION)} (oraclePriceOffset: ${bid.order?.oraclePriceOffset || 0 * PRICE_PRECISION})`);
}
countBids++;
}
console.log("");
}
function doDlobDemo() {
const dlobCoder = DLOBOrdersCoder.create();
fetch(dlobServerURL)
.then(
async (r) => {
console.log(`dlob server response: ${r.status} ${r.statusText}`);
const resp = await r.json();
lastSeenSlot = resp['slot'];
console.log(`Latest dlob slot: ${lastSeenSlot}`);
const dlobOrdersBuffer = Buffer.from(resp['data'], 'base64');
const dlobOrders = dlobCoder.decode(Buffer.from(dlobOrdersBuffer));
console.log(`Total Dlob orders count: ${dlobOrders.length}`);
dlob.initFromOrders(dlobOrders, lastSeenSlot);
const marketIndex = 0;
console.log("Initialized DLOb from server");
printDlob(marketIndex, dlob);
});
}