@ox-fun/drift-sdk
Version:
SDK for Drift Protocol
160 lines (138 loc) • 3.66 kB
text/typescript
import {
AMM_RESERVE_PRECISION,
BN,
convertToNumber,
getLimitPrice,
isVariant,
PRICE_PRECISION,
OraclePriceData,
Order,
ZERO,
} from '..';
// import { PublicKey } from '@solana/web3.js';
import { getOrderSignature } from './NodeList';
export interface DLOBNode {
getPrice(oraclePriceData: OraclePriceData, slot: number): BN;
isVammNode(): boolean;
order: Order | undefined;
isBaseFilled(): boolean;
haveFilled: boolean;
userAccount: string | undefined;
}
export abstract class OrderNode implements DLOBNode {
order: Order;
userAccount: string;
sortValue: BN;
haveFilled = false;
haveTrigger = false;
constructor(order: Order, userAccount: string) {
// Copy the order over to the node
this.order = { ...order };
this.userAccount = userAccount;
this.sortValue = this.getSortValue(order);
}
abstract getSortValue(order: Order): BN;
public getLabel(): string {
let msg = `Order ${getOrderSignature(
this.order.orderId,
this.userAccount
)}`;
msg += ` ${isVariant(this.order.direction, 'long') ? 'LONG' : 'SHORT'} `;
msg += `${convertToNumber(
this.order.baseAssetAmount,
AMM_RESERVE_PRECISION
).toFixed(3)}`;
if (this.order.price.gt(ZERO)) {
msg += ` @ ${convertToNumber(this.order.price, PRICE_PRECISION).toFixed(
3
)}`;
}
if (this.order.triggerPrice.gt(ZERO)) {
msg += ` ${
isVariant(this.order.triggerCondition, 'below') ? 'BELOW' : 'ABOVE'
}`;
msg += ` ${convertToNumber(
this.order.triggerPrice,
PRICE_PRECISION
).toFixed(3)}`;
}
return msg;
}
getPrice(oraclePriceData: OraclePriceData, slot: number): BN {
return getLimitPrice(this.order, oraclePriceData, slot);
}
isBaseFilled(): boolean {
return this.order.baseAssetAmountFilled.eq(this.order.baseAssetAmount);
}
isVammNode(): boolean {
return false;
}
}
export class TakingLimitOrderNode extends OrderNode {
next?: TakingLimitOrderNode;
previous?: TakingLimitOrderNode;
getSortValue(order: Order): BN {
return order.slot;
}
}
export class RestingLimitOrderNode extends OrderNode {
next?: RestingLimitOrderNode;
previous?: RestingLimitOrderNode;
getSortValue(order: Order): BN {
return order.price;
}
}
export class FloatingLimitOrderNode extends OrderNode {
next?: FloatingLimitOrderNode;
previous?: FloatingLimitOrderNode;
getSortValue(order: Order): BN {
return new BN(order.oraclePriceOffset);
}
}
export class MarketOrderNode extends OrderNode {
next?: MarketOrderNode;
previous?: MarketOrderNode;
getSortValue(order: Order): BN {
return order.slot;
}
}
export class TriggerOrderNode extends OrderNode {
next?: TriggerOrderNode;
previous?: TriggerOrderNode;
getSortValue(order: Order): BN {
return order.triggerPrice;
}
}
export type DLOBNodeMap = {
restingLimit: RestingLimitOrderNode;
takingLimit: TakingLimitOrderNode;
floatingLimit: FloatingLimitOrderNode;
market: MarketOrderNode;
trigger: TriggerOrderNode;
};
export type DLOBNodeType =
| 'restingLimit'
| 'takingLimit'
| 'floatingLimit'
| 'market'
| ('trigger' & keyof DLOBNodeMap);
export function createNode<T extends DLOBNodeType>(
nodeType: T,
order: Order,
userAccount: string
): DLOBNodeMap[T] {
switch (nodeType) {
case 'floatingLimit':
return new FloatingLimitOrderNode(order, userAccount);
case 'restingLimit':
return new RestingLimitOrderNode(order, userAccount);
case 'takingLimit':
return new TakingLimitOrderNode(order, userAccount);
case 'market':
return new MarketOrderNode(order, userAccount);
case 'trigger':
return new TriggerOrderNode(order, userAccount);
default:
throw Error(`Unknown DLOBNode type ${nodeType}`);
}
}