@drift-labs/sdk 2.31.0-beta.0 → 2.31.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/accounts/pollingDriftClientAccountSubscriber.d.ts +2 -1
- package/lib/accounts/pollingDriftClientAccountSubscriber.js +9 -1
- package/lib/accounts/webSocketDriftClientAccountSubscriber.d.ts +2 -1
- package/lib/accounts/webSocketDriftClientAccountSubscriber.js +9 -1
- package/lib/config.d.ts +6 -0
- package/lib/config.js +30 -1
- package/lib/dlob/orderBookLevels.d.ts +1 -0
- package/lib/dlob/orderBookLevels.js +38 -2
- package/lib/driftClient.js +7 -17
- package/lib/idl/drift.json +1 -1
- package/lib/math/orders.d.ts +2 -1
- package/lib/math/orders.js +18 -1
- package/lib/userMap/userMap.d.ts +6 -0
- package/lib/userMap/userMap.js +7 -1
- package/package.json +1 -1
- package/src/accounts/pollingDriftClientAccountSubscriber.ts +14 -1
- package/src/accounts/webSocketDriftClientAccountSubscriber.ts +14 -1
- package/src/config.ts +38 -0
- package/src/dlob/orderBookLevels.ts +44 -1
- package/src/driftClient.ts +13 -29
- package/src/idl/drift.json +1 -1
- package/src/math/orders.ts +22 -0
- package/src/userMap/userMap.ts +7 -1
|
@@ -15,6 +15,7 @@ export declare class PollingDriftClientAccountSubscriber implements DriftClientA
|
|
|
15
15
|
spotMarketIndexes: number[];
|
|
16
16
|
oracleInfos: OracleInfo[];
|
|
17
17
|
oracleClientCache: OracleClientCache;
|
|
18
|
+
shouldFindAllMarketsAndOracles: boolean;
|
|
18
19
|
eventEmitter: StrictEventEmitter<EventEmitter, DriftClientAccountEvents>;
|
|
19
20
|
accountLoader: BulkAccountLoader;
|
|
20
21
|
accountsToPoll: Map<string, AccountToPoll>;
|
|
@@ -28,7 +29,7 @@ export declare class PollingDriftClientAccountSubscriber implements DriftClientA
|
|
|
28
29
|
private isSubscribing;
|
|
29
30
|
private subscriptionPromise;
|
|
30
31
|
private subscriptionPromiseResolver;
|
|
31
|
-
constructor(program: Program, accountLoader: BulkAccountLoader, perpMarketIndexes: number[], spotMarketIndexes: number[], oracleInfos: OracleInfo[]);
|
|
32
|
+
constructor(program: Program, accountLoader: BulkAccountLoader, perpMarketIndexes: number[], spotMarketIndexes: number[], oracleInfos: OracleInfo[], shouldFindAllMarketsAndOracles: boolean);
|
|
32
33
|
subscribe(): Promise<boolean>;
|
|
33
34
|
updateAccountsToPoll(): Promise<void>;
|
|
34
35
|
updatePerpMarketAccountsToPoll(): Promise<boolean>;
|
|
@@ -8,8 +8,9 @@ const utils_1 = require("./utils");
|
|
|
8
8
|
const web3_js_1 = require("@solana/web3.js");
|
|
9
9
|
const oracleClientCache_1 = require("../oracles/oracleClientCache");
|
|
10
10
|
const quoteAssetOracleClient_1 = require("../oracles/quoteAssetOracleClient");
|
|
11
|
+
const config_1 = require("../config");
|
|
11
12
|
class PollingDriftClientAccountSubscriber {
|
|
12
|
-
constructor(program, accountLoader, perpMarketIndexes, spotMarketIndexes, oracleInfos) {
|
|
13
|
+
constructor(program, accountLoader, perpMarketIndexes, spotMarketIndexes, oracleInfos, shouldFindAllMarketsAndOracles) {
|
|
13
14
|
this.oracleClientCache = new oracleClientCache_1.OracleClientCache();
|
|
14
15
|
this.accountsToPoll = new Map();
|
|
15
16
|
this.oraclesToPoll = new Map();
|
|
@@ -24,6 +25,7 @@ class PollingDriftClientAccountSubscriber {
|
|
|
24
25
|
this.perpMarketIndexes = perpMarketIndexes;
|
|
25
26
|
this.spotMarketIndexes = spotMarketIndexes;
|
|
26
27
|
this.oracleInfos = oracleInfos;
|
|
28
|
+
this.shouldFindAllMarketsAndOracles = shouldFindAllMarketsAndOracles;
|
|
27
29
|
}
|
|
28
30
|
async subscribe() {
|
|
29
31
|
if (this.isSubscribed) {
|
|
@@ -36,6 +38,12 @@ class PollingDriftClientAccountSubscriber {
|
|
|
36
38
|
this.subscriptionPromise = new Promise((res) => {
|
|
37
39
|
this.subscriptionPromiseResolver = res;
|
|
38
40
|
});
|
|
41
|
+
if (this.shouldFindAllMarketsAndOracles) {
|
|
42
|
+
const { perpMarketIndexes, spotMarketIndexes, oracleInfos } = await (0, config_1.findAllMarketAndOracles)(this.program);
|
|
43
|
+
this.perpMarketIndexes = perpMarketIndexes;
|
|
44
|
+
this.spotMarketIndexes = spotMarketIndexes;
|
|
45
|
+
this.oracleInfos = oracleInfos;
|
|
46
|
+
}
|
|
39
47
|
await this.updateAccountsToPoll();
|
|
40
48
|
await this.updateOraclesToPoll();
|
|
41
49
|
await this.addToAccountLoader();
|
|
@@ -15,6 +15,7 @@ export declare class WebSocketDriftClientAccountSubscriber implements DriftClien
|
|
|
15
15
|
spotMarketIndexes: number[];
|
|
16
16
|
oracleInfos: OracleInfo[];
|
|
17
17
|
oracleClientCache: OracleClientCache;
|
|
18
|
+
shouldFindAllMarketsAndOracles: boolean;
|
|
18
19
|
eventEmitter: StrictEventEmitter<EventEmitter, DriftClientAccountEvents>;
|
|
19
20
|
stateAccountSubscriber?: AccountSubscriber<StateAccount>;
|
|
20
21
|
perpMarketAccountSubscribers: Map<number, AccountSubscriber<PerpMarketAccount>>;
|
|
@@ -23,7 +24,7 @@ export declare class WebSocketDriftClientAccountSubscriber implements DriftClien
|
|
|
23
24
|
private isSubscribing;
|
|
24
25
|
private subscriptionPromise;
|
|
25
26
|
private subscriptionPromiseResolver;
|
|
26
|
-
constructor(program: Program, perpMarketIndexes: number[], spotMarketIndexes: number[], oracleInfos: OracleInfo[]);
|
|
27
|
+
constructor(program: Program, perpMarketIndexes: number[], spotMarketIndexes: number[], oracleInfos: OracleInfo[], shouldFindAllMarketsAndOracles: boolean);
|
|
27
28
|
subscribe(): Promise<boolean>;
|
|
28
29
|
subscribeToPerpMarketAccounts(): Promise<boolean>;
|
|
29
30
|
subscribeToPerpMarketAccount(marketIndex: number): Promise<boolean>;
|
|
@@ -8,8 +8,9 @@ const webSocketAccountSubscriber_1 = require("./webSocketAccountSubscriber");
|
|
|
8
8
|
const web3_js_1 = require("@solana/web3.js");
|
|
9
9
|
const oracleClientCache_1 = require("../oracles/oracleClientCache");
|
|
10
10
|
const quoteAssetOracleClient_1 = require("../oracles/quoteAssetOracleClient");
|
|
11
|
+
const config_1 = require("../config");
|
|
11
12
|
class WebSocketDriftClientAccountSubscriber {
|
|
12
|
-
constructor(program, perpMarketIndexes, spotMarketIndexes, oracleInfos) {
|
|
13
|
+
constructor(program, perpMarketIndexes, spotMarketIndexes, oracleInfos, shouldFindAllMarketsAndOracles) {
|
|
13
14
|
this.oracleClientCache = new oracleClientCache_1.OracleClientCache();
|
|
14
15
|
this.perpMarketAccountSubscribers = new Map();
|
|
15
16
|
this.spotMarketAccountSubscribers = new Map();
|
|
@@ -21,6 +22,7 @@ class WebSocketDriftClientAccountSubscriber {
|
|
|
21
22
|
this.perpMarketIndexes = perpMarketIndexes;
|
|
22
23
|
this.spotMarketIndexes = spotMarketIndexes;
|
|
23
24
|
this.oracleInfos = oracleInfos;
|
|
25
|
+
this.shouldFindAllMarketsAndOracles = shouldFindAllMarketsAndOracles;
|
|
24
26
|
}
|
|
25
27
|
async subscribe() {
|
|
26
28
|
if (this.isSubscribed) {
|
|
@@ -33,6 +35,12 @@ class WebSocketDriftClientAccountSubscriber {
|
|
|
33
35
|
this.subscriptionPromise = new Promise((res) => {
|
|
34
36
|
this.subscriptionPromiseResolver = res;
|
|
35
37
|
});
|
|
38
|
+
if (this.shouldFindAllMarketsAndOracles) {
|
|
39
|
+
const { perpMarketIndexes, spotMarketIndexes, oracleInfos } = await (0, config_1.findAllMarketAndOracles)(this.program);
|
|
40
|
+
this.perpMarketIndexes = perpMarketIndexes;
|
|
41
|
+
this.spotMarketIndexes = spotMarketIndexes;
|
|
42
|
+
this.oracleInfos = oracleInfos;
|
|
43
|
+
}
|
|
36
44
|
const statePublicKey = await (0, pda_1.getDriftStateAccountPublicKey)(this.program.programId);
|
|
37
45
|
// create and activate main state account subscription
|
|
38
46
|
this.stateAccountSubscriber = new webSocketAccountSubscriber_1.WebSocketAccountSubscriber('state', this.program, statePublicKey);
|
package/lib/config.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { PerpMarketConfig } from './constants/perpMarkets';
|
|
2
2
|
import { SpotMarketConfig } from './constants/spotMarkets';
|
|
3
3
|
import { OracleInfo } from './oracles/types';
|
|
4
|
+
import { Program } from '@coral-xyz/anchor';
|
|
4
5
|
type DriftConfig = {
|
|
5
6
|
ENV: DriftEnv;
|
|
6
7
|
PYTH_ORACLE_MAPPING_ADDRESS: string;
|
|
@@ -35,4 +36,9 @@ export declare function getMarketsAndOraclesForSubscription(env: DriftEnv): {
|
|
|
35
36
|
spotMarketIndexes: number[];
|
|
36
37
|
oracleInfos: OracleInfo[];
|
|
37
38
|
};
|
|
39
|
+
export declare function findAllMarketAndOracles(program: Program): Promise<{
|
|
40
|
+
perpMarketIndexes: number[];
|
|
41
|
+
spotMarketIndexes: number[];
|
|
42
|
+
oracleInfos: OracleInfo[];
|
|
43
|
+
}>;
|
|
38
44
|
export {};
|
package/lib/config.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getMarketsAndOraclesForSubscription = exports.initialize = exports.getConfig = exports.configs = exports.DRIFT_PROGRAM_ID = void 0;
|
|
3
|
+
exports.findAllMarketAndOracles = exports.getMarketsAndOraclesForSubscription = exports.initialize = exports.getConfig = exports.configs = exports.DRIFT_PROGRAM_ID = void 0;
|
|
4
4
|
const perpMarkets_1 = require("./constants/perpMarkets");
|
|
5
5
|
const spotMarkets_1 = require("./constants/spotMarkets");
|
|
6
6
|
exports.DRIFT_PROGRAM_ID = 'dRiftyHA39MWEi3m9aunc5MzRF1JYuBsbn6VPcn33UH';
|
|
@@ -74,3 +74,32 @@ function getMarketsAndOraclesForSubscription(env) {
|
|
|
74
74
|
};
|
|
75
75
|
}
|
|
76
76
|
exports.getMarketsAndOraclesForSubscription = getMarketsAndOraclesForSubscription;
|
|
77
|
+
async function findAllMarketAndOracles(program) {
|
|
78
|
+
const perpMarketIndexes = [];
|
|
79
|
+
const spotMarketIndexes = [];
|
|
80
|
+
const oracleInfos = new Map();
|
|
81
|
+
const perpMarketProgramAccounts = await program.account.perpMarket.all();
|
|
82
|
+
const spotMarketProgramAccounts = await program.account.spotMarket.all();
|
|
83
|
+
for (const perpMarketProgramAccount of perpMarketProgramAccounts) {
|
|
84
|
+
const perpMarket = perpMarketProgramAccount.account;
|
|
85
|
+
perpMarketIndexes.push(perpMarket.marketIndex);
|
|
86
|
+
oracleInfos.set(perpMarket.amm.oracle.toString(), {
|
|
87
|
+
publicKey: perpMarket.amm.oracle,
|
|
88
|
+
source: perpMarket.amm.oracleSource,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
for (const spotMarketProgramAccount of spotMarketProgramAccounts) {
|
|
92
|
+
const spotMarket = spotMarketProgramAccount.account;
|
|
93
|
+
spotMarketIndexes.push(spotMarket.marketIndex);
|
|
94
|
+
oracleInfos.set(spotMarket.oracle.toString(), {
|
|
95
|
+
publicKey: spotMarket.oracle,
|
|
96
|
+
source: spotMarket.oracleSource,
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
return {
|
|
100
|
+
perpMarketIndexes,
|
|
101
|
+
spotMarketIndexes,
|
|
102
|
+
oracleInfos: Array.from(oracleInfos.values()),
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
exports.findAllMarketAndOracles = findAllMarketAndOracles;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getVammL2Generator = exports.createL2Levels = exports.mergeL2LevelGenerators = exports.getL2GeneratorFromDLOBNodes = void 0;
|
|
3
|
+
exports.groupL2 = exports.getVammL2Generator = exports.createL2Levels = exports.mergeL2LevelGenerators = exports.getL2GeneratorFromDLOBNodes = void 0;
|
|
4
4
|
const __1 = require("..");
|
|
5
5
|
/**
|
|
6
6
|
* Get an {@link Generator<L2Level>} generator from a {@link Generator<DLOBNode>}
|
|
@@ -58,7 +58,7 @@ function createL2Levels(generator, depth) {
|
|
|
58
58
|
const size = level.size;
|
|
59
59
|
if (levels.length > 0 && levels[levels.length - 1].price.eq(price)) {
|
|
60
60
|
const currentLevel = levels[levels.length - 1];
|
|
61
|
-
currentLevel.size.add(size);
|
|
61
|
+
currentLevel.size = currentLevel.size.add(size);
|
|
62
62
|
for (const [source, size] of Object.entries(level.sources)) {
|
|
63
63
|
if (currentLevel.sources[source]) {
|
|
64
64
|
currentLevel.sources[source] = currentLevel.sources[source].add(size);
|
|
@@ -135,3 +135,39 @@ function getVammL2Generator({ marketAccount, oraclePriceData, numOrders, now, })
|
|
|
135
135
|
};
|
|
136
136
|
}
|
|
137
137
|
exports.getVammL2Generator = getVammL2Generator;
|
|
138
|
+
function groupL2(l2, grouping) {
|
|
139
|
+
return {
|
|
140
|
+
bids: groupL2Levels(l2.bids, grouping, __1.PositionDirection.LONG),
|
|
141
|
+
asks: groupL2Levels(l2.asks, grouping, __1.PositionDirection.SHORT),
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
exports.groupL2 = groupL2;
|
|
145
|
+
function groupL2Levels(levels, grouping, direction) {
|
|
146
|
+
const groupedLevels = [];
|
|
147
|
+
for (const level of levels) {
|
|
148
|
+
const price = (0, __1.standardizePrice)(level.price, grouping, direction);
|
|
149
|
+
const size = level.size;
|
|
150
|
+
if (groupedLevels.length > 0 &&
|
|
151
|
+
groupedLevels[groupedLevels.length - 1].price.eq(price)) {
|
|
152
|
+
const currentLevel = groupedLevels[groupedLevels.length - 1];
|
|
153
|
+
currentLevel.size = currentLevel.size.add(size);
|
|
154
|
+
for (const [source, size] of Object.entries(level.sources)) {
|
|
155
|
+
if (currentLevel.sources[source]) {
|
|
156
|
+
currentLevel.sources[source] = currentLevel.sources[source].add(size);
|
|
157
|
+
}
|
|
158
|
+
else {
|
|
159
|
+
currentLevel.sources[source] = size;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
const groupedLevel = {
|
|
165
|
+
price: price,
|
|
166
|
+
size,
|
|
167
|
+
sources: level.sources,
|
|
168
|
+
};
|
|
169
|
+
groupedLevels.push(groupedLevel);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
return groupedLevels;
|
|
173
|
+
}
|
package/lib/driftClient.js
CHANGED
|
@@ -63,7 +63,7 @@ class DriftClient {
|
|
|
63
63
|
this._isSubscribed = val;
|
|
64
64
|
}
|
|
65
65
|
constructor(config) {
|
|
66
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
|
|
66
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s;
|
|
67
67
|
this.users = new Map();
|
|
68
68
|
this._isSubscribed = false;
|
|
69
69
|
this.perpMarketLastSlotCache = new Map();
|
|
@@ -108,31 +108,21 @@ class DriftClient {
|
|
|
108
108
|
accountSubscription: this.userAccountSubscriptionConfig,
|
|
109
109
|
});
|
|
110
110
|
}
|
|
111
|
-
let perpMarketIndexes = config.perpMarketIndexes;
|
|
112
|
-
let spotMarketIndexes = config.spotMarketIndexes;
|
|
113
|
-
let oracleInfos = config.oracleInfos;
|
|
114
|
-
if (config.env) {
|
|
115
|
-
const { perpMarketIndexes: envPerpMarketIndexes, spotMarketIndexes: envSpotMarketIndexes, oracleInfos: envOracleInfos, } = (0, config_1.getMarketsAndOraclesForSubscription)(config.env);
|
|
116
|
-
perpMarketIndexes = perpMarketIndexes
|
|
117
|
-
? perpMarketIndexes
|
|
118
|
-
: envPerpMarketIndexes;
|
|
119
|
-
spotMarketIndexes = spotMarketIndexes
|
|
120
|
-
? spotMarketIndexes
|
|
121
|
-
: envSpotMarketIndexes;
|
|
122
|
-
oracleInfos = oracleInfos ? oracleInfos : envOracleInfos;
|
|
123
|
-
}
|
|
124
111
|
this.marketLookupTable = config.marketLookupTable;
|
|
125
112
|
if (config.env && !this.marketLookupTable) {
|
|
126
113
|
this.marketLookupTable = new web3_js_1.PublicKey(config_1.configs[config.env].MARKET_LOOKUP_TABLE);
|
|
127
114
|
}
|
|
115
|
+
const noMarketsAndOraclesSpecified = config.perpMarketIndexes === undefined &&
|
|
116
|
+
config.spotMarketIndexes === undefined &&
|
|
117
|
+
config.oracleInfos === undefined;
|
|
128
118
|
if (((_h = config.accountSubscription) === null || _h === void 0 ? void 0 : _h.type) === 'polling') {
|
|
129
|
-
this.accountSubscriber = new pollingDriftClientAccountSubscriber_1.PollingDriftClientAccountSubscriber(this.program, config.accountSubscription.accountLoader, perpMarketIndexes !== null &&
|
|
119
|
+
this.accountSubscriber = new pollingDriftClientAccountSubscriber_1.PollingDriftClientAccountSubscriber(this.program, config.accountSubscription.accountLoader, (_j = config.perpMarketIndexes) !== null && _j !== void 0 ? _j : [], (_k = config.spotMarketIndexes) !== null && _k !== void 0 ? _k : [], (_l = config.oracleInfos) !== null && _l !== void 0 ? _l : [], noMarketsAndOraclesSpecified);
|
|
130
120
|
}
|
|
131
121
|
else {
|
|
132
|
-
this.accountSubscriber = new webSocketDriftClientAccountSubscriber_1.WebSocketDriftClientAccountSubscriber(this.program, perpMarketIndexes !== null &&
|
|
122
|
+
this.accountSubscriber = new webSocketDriftClientAccountSubscriber_1.WebSocketDriftClientAccountSubscriber(this.program, (_m = config.perpMarketIndexes) !== null && _m !== void 0 ? _m : [], (_o = config.spotMarketIndexes) !== null && _o !== void 0 ? _o : [], (_p = config.oracleInfos) !== null && _p !== void 0 ? _p : [], noMarketsAndOraclesSpecified);
|
|
133
123
|
}
|
|
134
124
|
this.eventEmitter = this.accountSubscriber.eventEmitter;
|
|
135
|
-
this.txSender = new retryTxSender_1.RetryTxSender(this.provider, (
|
|
125
|
+
this.txSender = new retryTxSender_1.RetryTxSender(this.provider, (_q = config.txSenderConfig) === null || _q === void 0 ? void 0 : _q.timeout, (_r = config.txSenderConfig) === null || _r === void 0 ? void 0 : _r.retrySleep, (_s = config.txSenderConfig) === null || _s === void 0 ? void 0 : _s.additionalConnections);
|
|
136
126
|
}
|
|
137
127
|
getUserMapKey(subAccountId, authority) {
|
|
138
128
|
return `${subAccountId}_${authority.toString()}`;
|
package/lib/idl/drift.json
CHANGED
package/lib/math/orders.d.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { User } from '../user';
|
|
2
|
-
import { PerpMarketAccount, AMM, Order } from '../types';
|
|
2
|
+
import { PerpMarketAccount, AMM, Order, PositionDirection } from '../types';
|
|
3
3
|
import { BN } from '@coral-xyz/anchor';
|
|
4
4
|
import { OraclePriceData } from '../oracles/types';
|
|
5
5
|
export declare function isOrderRiskIncreasing(user: User, order: Order): boolean;
|
|
6
6
|
export declare function isOrderRiskIncreasingInSameDirection(user: User, order: Order): boolean;
|
|
7
7
|
export declare function isOrderReduceOnly(user: User, order: Order): boolean;
|
|
8
8
|
export declare function standardizeBaseAssetAmount(baseAssetAmount: BN, stepSize: BN): BN;
|
|
9
|
+
export declare function standardizePrice(price: BN, tickSize: BN, direction: PositionDirection): BN;
|
|
9
10
|
export declare function getLimitPrice(order: Order, oraclePriceData: OraclePriceData, slot: number, fallbackPrice?: BN): BN | undefined;
|
|
10
11
|
export declare function hasLimitPrice(order: Order, slot: number): boolean;
|
|
11
12
|
export declare function hasAuctionPrice(order: Order, slot: number): boolean;
|
package/lib/math/orders.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.isTakingOrder = exports.isRestingLimitOrder = exports.isTriggered = exports.mustBeTriggered = exports.isLimitOrder = exports.isMarketOrder = exports.isOrderExpired = exports.calculateBaseAssetAmountToFillUpToLimitPrice = exports.calculateBaseAssetAmountForAmmToFulfill = exports.isFillableByVAMM = exports.hasAuctionPrice = exports.hasLimitPrice = exports.getLimitPrice = exports.standardizeBaseAssetAmount = exports.isOrderReduceOnly = exports.isOrderRiskIncreasingInSameDirection = exports.isOrderRiskIncreasing = void 0;
|
|
3
|
+
exports.isTakingOrder = exports.isRestingLimitOrder = exports.isTriggered = exports.mustBeTriggered = exports.isLimitOrder = exports.isMarketOrder = exports.isOrderExpired = exports.calculateBaseAssetAmountToFillUpToLimitPrice = exports.calculateBaseAssetAmountForAmmToFulfill = exports.isFillableByVAMM = exports.hasAuctionPrice = exports.hasLimitPrice = exports.getLimitPrice = exports.standardizePrice = exports.standardizeBaseAssetAmount = exports.isOrderReduceOnly = exports.isOrderRiskIncreasingInSameDirection = exports.isOrderRiskIncreasing = void 0;
|
|
4
4
|
const types_1 = require("../types");
|
|
5
5
|
const numericConstants_1 = require("../constants/numericConstants");
|
|
6
6
|
const anchor_1 = require("@coral-xyz/anchor");
|
|
@@ -79,6 +79,23 @@ function standardizeBaseAssetAmount(baseAssetAmount, stepSize) {
|
|
|
79
79
|
return baseAssetAmount.sub(remainder);
|
|
80
80
|
}
|
|
81
81
|
exports.standardizeBaseAssetAmount = standardizeBaseAssetAmount;
|
|
82
|
+
function standardizePrice(price, tickSize, direction) {
|
|
83
|
+
if (price.eq(numericConstants_1.ZERO)) {
|
|
84
|
+
console.log('price is zero');
|
|
85
|
+
return price;
|
|
86
|
+
}
|
|
87
|
+
const remainder = price.mod(tickSize);
|
|
88
|
+
if (remainder.eq(numericConstants_1.ZERO)) {
|
|
89
|
+
return price;
|
|
90
|
+
}
|
|
91
|
+
if ((0, types_1.isVariant)(direction, 'long')) {
|
|
92
|
+
return price.sub(remainder);
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
return price.add(tickSize).sub(remainder);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
exports.standardizePrice = standardizePrice;
|
|
82
99
|
function getLimitPrice(order, oraclePriceData, slot, fallbackPrice) {
|
|
83
100
|
let limitPrice;
|
|
84
101
|
if (hasAuctionPrice(order, slot)) {
|
package/lib/userMap/userMap.d.ts
CHANGED
|
@@ -18,6 +18,12 @@ export declare class UserMap implements UserMapInterface {
|
|
|
18
18
|
private includeIdle;
|
|
19
19
|
private lastNumberOfSubAccounts;
|
|
20
20
|
private syncCallback;
|
|
21
|
+
/**
|
|
22
|
+
*
|
|
23
|
+
* @param driftClient
|
|
24
|
+
* @param accountSubscription
|
|
25
|
+
* @param includeIdle whether idle users are subscribed to. defaults to false to decrease # of user subscriptions
|
|
26
|
+
*/
|
|
21
27
|
constructor(driftClient: DriftClient, accountSubscription: UserSubscriptionConfig, includeIdle?: boolean);
|
|
22
28
|
subscribe(): Promise<void>;
|
|
23
29
|
addPubkey(userAccountPublicKey: PublicKey, userAccount?: UserAccount): Promise<void>;
|
package/lib/userMap/userMap.js
CHANGED
|
@@ -9,7 +9,13 @@ const web3_js_1 = require("@solana/web3.js");
|
|
|
9
9
|
const buffer_1 = require("buffer");
|
|
10
10
|
const bs58_1 = __importDefault(require("bs58"));
|
|
11
11
|
class UserMap {
|
|
12
|
-
|
|
12
|
+
/**
|
|
13
|
+
*
|
|
14
|
+
* @param driftClient
|
|
15
|
+
* @param accountSubscription
|
|
16
|
+
* @param includeIdle whether idle users are subscribed to. defaults to false to decrease # of user subscriptions
|
|
17
|
+
*/
|
|
18
|
+
constructor(driftClient, accountSubscription, includeIdle = false) {
|
|
13
19
|
this.userMap = new Map();
|
|
14
20
|
this.syncCallback = async (state) => {
|
|
15
21
|
if (state.numberOfSubAccounts !== this.lastNumberOfSubAccounts) {
|
package/package.json
CHANGED
|
@@ -26,6 +26,7 @@ import { PublicKey } from '@solana/web3.js';
|
|
|
26
26
|
import { OracleInfo, OraclePriceData } from '../oracles/types';
|
|
27
27
|
import { OracleClientCache } from '../oracles/oracleClientCache';
|
|
28
28
|
import { QUOTE_ORACLE_PRICE_DATA } from '../oracles/quoteAssetOracleClient';
|
|
29
|
+
import { findAllMarketAndOracles } from '../config';
|
|
29
30
|
|
|
30
31
|
export class PollingDriftClientAccountSubscriber
|
|
31
32
|
implements DriftClientAccountSubscriber
|
|
@@ -37,6 +38,8 @@ export class PollingDriftClientAccountSubscriber
|
|
|
37
38
|
oracleInfos: OracleInfo[];
|
|
38
39
|
oracleClientCache = new OracleClientCache();
|
|
39
40
|
|
|
41
|
+
shouldFindAllMarketsAndOracles: boolean;
|
|
42
|
+
|
|
40
43
|
eventEmitter: StrictEventEmitter<EventEmitter, DriftClientAccountEvents>;
|
|
41
44
|
|
|
42
45
|
accountLoader: BulkAccountLoader;
|
|
@@ -59,7 +62,8 @@ export class PollingDriftClientAccountSubscriber
|
|
|
59
62
|
accountLoader: BulkAccountLoader,
|
|
60
63
|
perpMarketIndexes: number[],
|
|
61
64
|
spotMarketIndexes: number[],
|
|
62
|
-
oracleInfos: OracleInfo[]
|
|
65
|
+
oracleInfos: OracleInfo[],
|
|
66
|
+
shouldFindAllMarketsAndOracles: boolean
|
|
63
67
|
) {
|
|
64
68
|
this.isSubscribed = false;
|
|
65
69
|
this.program = program;
|
|
@@ -68,6 +72,7 @@ export class PollingDriftClientAccountSubscriber
|
|
|
68
72
|
this.perpMarketIndexes = perpMarketIndexes;
|
|
69
73
|
this.spotMarketIndexes = spotMarketIndexes;
|
|
70
74
|
this.oracleInfos = oracleInfos;
|
|
75
|
+
this.shouldFindAllMarketsAndOracles = shouldFindAllMarketsAndOracles;
|
|
71
76
|
}
|
|
72
77
|
|
|
73
78
|
public async subscribe(): Promise<boolean> {
|
|
@@ -85,6 +90,14 @@ export class PollingDriftClientAccountSubscriber
|
|
|
85
90
|
this.subscriptionPromiseResolver = res;
|
|
86
91
|
});
|
|
87
92
|
|
|
93
|
+
if (this.shouldFindAllMarketsAndOracles) {
|
|
94
|
+
const { perpMarketIndexes, spotMarketIndexes, oracleInfos } =
|
|
95
|
+
await findAllMarketAndOracles(this.program);
|
|
96
|
+
this.perpMarketIndexes = perpMarketIndexes;
|
|
97
|
+
this.spotMarketIndexes = spotMarketIndexes;
|
|
98
|
+
this.oracleInfos = oracleInfos;
|
|
99
|
+
}
|
|
100
|
+
|
|
88
101
|
await this.updateAccountsToPoll();
|
|
89
102
|
await this.updateOraclesToPoll();
|
|
90
103
|
await this.addToAccountLoader();
|
|
@@ -19,6 +19,7 @@ import { OracleInfo, OraclePriceData } from '../oracles/types';
|
|
|
19
19
|
import { OracleClientCache } from '../oracles/oracleClientCache';
|
|
20
20
|
import * as Buffer from 'buffer';
|
|
21
21
|
import { QUOTE_ORACLE_PRICE_DATA } from '../oracles/quoteAssetOracleClient';
|
|
22
|
+
import { findAllMarketAndOracles } from '../config';
|
|
22
23
|
|
|
23
24
|
export class WebSocketDriftClientAccountSubscriber
|
|
24
25
|
implements DriftClientAccountSubscriber
|
|
@@ -30,6 +31,8 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
30
31
|
oracleInfos: OracleInfo[];
|
|
31
32
|
oracleClientCache = new OracleClientCache();
|
|
32
33
|
|
|
34
|
+
shouldFindAllMarketsAndOracles: boolean;
|
|
35
|
+
|
|
33
36
|
eventEmitter: StrictEventEmitter<EventEmitter, DriftClientAccountEvents>;
|
|
34
37
|
stateAccountSubscriber?: AccountSubscriber<StateAccount>;
|
|
35
38
|
perpMarketAccountSubscribers = new Map<
|
|
@@ -50,7 +53,8 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
50
53
|
program: Program,
|
|
51
54
|
perpMarketIndexes: number[],
|
|
52
55
|
spotMarketIndexes: number[],
|
|
53
|
-
oracleInfos: OracleInfo[]
|
|
56
|
+
oracleInfos: OracleInfo[],
|
|
57
|
+
shouldFindAllMarketsAndOracles: boolean
|
|
54
58
|
) {
|
|
55
59
|
this.isSubscribed = false;
|
|
56
60
|
this.program = program;
|
|
@@ -58,6 +62,7 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
58
62
|
this.perpMarketIndexes = perpMarketIndexes;
|
|
59
63
|
this.spotMarketIndexes = spotMarketIndexes;
|
|
60
64
|
this.oracleInfos = oracleInfos;
|
|
65
|
+
this.shouldFindAllMarketsAndOracles = shouldFindAllMarketsAndOracles;
|
|
61
66
|
}
|
|
62
67
|
|
|
63
68
|
public async subscribe(): Promise<boolean> {
|
|
@@ -75,6 +80,14 @@ export class WebSocketDriftClientAccountSubscriber
|
|
|
75
80
|
this.subscriptionPromiseResolver = res;
|
|
76
81
|
});
|
|
77
82
|
|
|
83
|
+
if (this.shouldFindAllMarketsAndOracles) {
|
|
84
|
+
const { perpMarketIndexes, spotMarketIndexes, oracleInfos } =
|
|
85
|
+
await findAllMarketAndOracles(this.program);
|
|
86
|
+
this.perpMarketIndexes = perpMarketIndexes;
|
|
87
|
+
this.spotMarketIndexes = spotMarketIndexes;
|
|
88
|
+
this.oracleInfos = oracleInfos;
|
|
89
|
+
}
|
|
90
|
+
|
|
78
91
|
const statePublicKey = await getDriftStateAccountPublicKey(
|
|
79
92
|
this.program.programId
|
|
80
93
|
);
|
package/src/config.ts
CHANGED
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
MainnetSpotMarkets,
|
|
12
12
|
} from './constants/spotMarkets';
|
|
13
13
|
import { OracleInfo } from './oracles/types';
|
|
14
|
+
import { Program } from '@coral-xyz/anchor';
|
|
14
15
|
|
|
15
16
|
type DriftConfig = {
|
|
16
17
|
ENV: DriftEnv;
|
|
@@ -113,3 +114,40 @@ export function getMarketsAndOraclesForSubscription(env: DriftEnv): {
|
|
|
113
114
|
oracleInfos: Array.from(oracleInfos.values()),
|
|
114
115
|
};
|
|
115
116
|
}
|
|
117
|
+
|
|
118
|
+
export async function findAllMarketAndOracles(program: Program): Promise<{
|
|
119
|
+
perpMarketIndexes: number[];
|
|
120
|
+
spotMarketIndexes: number[];
|
|
121
|
+
oracleInfos: OracleInfo[];
|
|
122
|
+
}> {
|
|
123
|
+
const perpMarketIndexes = [];
|
|
124
|
+
const spotMarketIndexes = [];
|
|
125
|
+
const oracleInfos = new Map<string, OracleInfo>();
|
|
126
|
+
|
|
127
|
+
const perpMarketProgramAccounts = await program.account.perpMarket.all();
|
|
128
|
+
const spotMarketProgramAccounts = await program.account.spotMarket.all();
|
|
129
|
+
|
|
130
|
+
for (const perpMarketProgramAccount of perpMarketProgramAccounts) {
|
|
131
|
+
const perpMarket = perpMarketProgramAccount.account;
|
|
132
|
+
perpMarketIndexes.push(perpMarket.marketIndex);
|
|
133
|
+
oracleInfos.set(perpMarket.amm.oracle.toString(), {
|
|
134
|
+
publicKey: perpMarket.amm.oracle,
|
|
135
|
+
source: perpMarket.amm.oracleSource,
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
for (const spotMarketProgramAccount of spotMarketProgramAccounts) {
|
|
140
|
+
const spotMarket = spotMarketProgramAccount.account;
|
|
141
|
+
spotMarketIndexes.push(spotMarket.marketIndex);
|
|
142
|
+
oracleInfos.set(spotMarket.oracle.toString(), {
|
|
143
|
+
publicKey: spotMarket.oracle,
|
|
144
|
+
source: spotMarket.oracleSource,
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return {
|
|
149
|
+
perpMarketIndexes,
|
|
150
|
+
spotMarketIndexes,
|
|
151
|
+
oracleInfos: Array.from(oracleInfos.values()),
|
|
152
|
+
};
|
|
153
|
+
}
|
|
@@ -9,6 +9,8 @@ import {
|
|
|
9
9
|
DLOBNode,
|
|
10
10
|
OraclePriceData,
|
|
11
11
|
PerpMarketAccount,
|
|
12
|
+
PositionDirection,
|
|
13
|
+
standardizePrice,
|
|
12
14
|
SwapDirection,
|
|
13
15
|
} from '..';
|
|
14
16
|
import { PublicKey } from '@solana/web3.js';
|
|
@@ -114,7 +116,7 @@ export function createL2Levels(
|
|
|
114
116
|
const size = level.size;
|
|
115
117
|
if (levels.length > 0 && levels[levels.length - 1].price.eq(price)) {
|
|
116
118
|
const currentLevel = levels[levels.length - 1];
|
|
117
|
-
currentLevel.size.add(size);
|
|
119
|
+
currentLevel.size = currentLevel.size.add(size);
|
|
118
120
|
for (const [source, size] of Object.entries(level.sources)) {
|
|
119
121
|
if (currentLevel.sources[source]) {
|
|
120
122
|
currentLevel.sources[source] = currentLevel.sources[source].add(size);
|
|
@@ -241,3 +243,44 @@ export function getVammL2Generator({
|
|
|
241
243
|
getL2Asks,
|
|
242
244
|
};
|
|
243
245
|
}
|
|
246
|
+
|
|
247
|
+
export function groupL2(l2: L2OrderBook, grouping: BN): L2OrderBook {
|
|
248
|
+
return {
|
|
249
|
+
bids: groupL2Levels(l2.bids, grouping, PositionDirection.LONG),
|
|
250
|
+
asks: groupL2Levels(l2.asks, grouping, PositionDirection.SHORT),
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
function groupL2Levels(
|
|
255
|
+
levels: L2Level[],
|
|
256
|
+
grouping: BN,
|
|
257
|
+
direction: PositionDirection
|
|
258
|
+
): L2Level[] {
|
|
259
|
+
const groupedLevels = [];
|
|
260
|
+
for (const level of levels) {
|
|
261
|
+
const price = standardizePrice(level.price, grouping, direction);
|
|
262
|
+
const size = level.size;
|
|
263
|
+
if (
|
|
264
|
+
groupedLevels.length > 0 &&
|
|
265
|
+
groupedLevels[groupedLevels.length - 1].price.eq(price)
|
|
266
|
+
) {
|
|
267
|
+
const currentLevel = groupedLevels[groupedLevels.length - 1];
|
|
268
|
+
currentLevel.size = currentLevel.size.add(size);
|
|
269
|
+
for (const [source, size] of Object.entries(level.sources)) {
|
|
270
|
+
if (currentLevel.sources[source]) {
|
|
271
|
+
currentLevel.sources[source] = currentLevel.sources[source].add(size);
|
|
272
|
+
} else {
|
|
273
|
+
currentLevel.sources[source] = size;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
} else {
|
|
277
|
+
const groupedLevel = {
|
|
278
|
+
price: price,
|
|
279
|
+
size,
|
|
280
|
+
sources: level.sources,
|
|
281
|
+
};
|
|
282
|
+
groupedLevels.push(groupedLevel);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
return groupedLevels;
|
|
286
|
+
}
|
package/src/driftClient.ts
CHANGED
|
@@ -106,11 +106,7 @@ import { WebSocketDriftClientAccountSubscriber } from './accounts/webSocketDrift
|
|
|
106
106
|
import { RetryTxSender } from './tx/retryTxSender';
|
|
107
107
|
import { User } from './user';
|
|
108
108
|
import { UserSubscriptionConfig } from './userConfig';
|
|
109
|
-
import {
|
|
110
|
-
configs,
|
|
111
|
-
DRIFT_PROGRAM_ID,
|
|
112
|
-
getMarketsAndOraclesForSubscription,
|
|
113
|
-
} from './config';
|
|
109
|
+
import { configs, DRIFT_PROGRAM_ID } from './config';
|
|
114
110
|
import { WRAPPED_SOL_MINT } from './constants/spotMarkets';
|
|
115
111
|
import { UserStats } from './userStats';
|
|
116
112
|
import { isSpotPositionAvailable } from './math/spotPosition';
|
|
@@ -230,24 +226,6 @@ export class DriftClient {
|
|
|
230
226
|
});
|
|
231
227
|
}
|
|
232
228
|
|
|
233
|
-
let perpMarketIndexes = config.perpMarketIndexes;
|
|
234
|
-
let spotMarketIndexes = config.spotMarketIndexes;
|
|
235
|
-
let oracleInfos = config.oracleInfos;
|
|
236
|
-
if (config.env) {
|
|
237
|
-
const {
|
|
238
|
-
perpMarketIndexes: envPerpMarketIndexes,
|
|
239
|
-
spotMarketIndexes: envSpotMarketIndexes,
|
|
240
|
-
oracleInfos: envOracleInfos,
|
|
241
|
-
} = getMarketsAndOraclesForSubscription(config.env);
|
|
242
|
-
perpMarketIndexes = perpMarketIndexes
|
|
243
|
-
? perpMarketIndexes
|
|
244
|
-
: envPerpMarketIndexes;
|
|
245
|
-
spotMarketIndexes = spotMarketIndexes
|
|
246
|
-
? spotMarketIndexes
|
|
247
|
-
: envSpotMarketIndexes;
|
|
248
|
-
oracleInfos = oracleInfos ? oracleInfos : envOracleInfos;
|
|
249
|
-
}
|
|
250
|
-
|
|
251
229
|
this.marketLookupTable = config.marketLookupTable;
|
|
252
230
|
if (config.env && !this.marketLookupTable) {
|
|
253
231
|
this.marketLookupTable = new PublicKey(
|
|
@@ -255,20 +233,26 @@ export class DriftClient {
|
|
|
255
233
|
);
|
|
256
234
|
}
|
|
257
235
|
|
|
236
|
+
const noMarketsAndOraclesSpecified =
|
|
237
|
+
config.perpMarketIndexes === undefined &&
|
|
238
|
+
config.spotMarketIndexes === undefined &&
|
|
239
|
+
config.oracleInfos === undefined;
|
|
258
240
|
if (config.accountSubscription?.type === 'polling') {
|
|
259
241
|
this.accountSubscriber = new PollingDriftClientAccountSubscriber(
|
|
260
242
|
this.program,
|
|
261
243
|
config.accountSubscription.accountLoader,
|
|
262
|
-
perpMarketIndexes ?? [],
|
|
263
|
-
spotMarketIndexes ?? [],
|
|
264
|
-
oracleInfos ?? []
|
|
244
|
+
config.perpMarketIndexes ?? [],
|
|
245
|
+
config.spotMarketIndexes ?? [],
|
|
246
|
+
config.oracleInfos ?? [],
|
|
247
|
+
noMarketsAndOraclesSpecified
|
|
265
248
|
);
|
|
266
249
|
} else {
|
|
267
250
|
this.accountSubscriber = new WebSocketDriftClientAccountSubscriber(
|
|
268
251
|
this.program,
|
|
269
|
-
perpMarketIndexes ?? [],
|
|
270
|
-
spotMarketIndexes ?? [],
|
|
271
|
-
oracleInfos ?? []
|
|
252
|
+
config.perpMarketIndexes ?? [],
|
|
253
|
+
config.spotMarketIndexes ?? [],
|
|
254
|
+
config.oracleInfos ?? [],
|
|
255
|
+
noMarketsAndOraclesSpecified
|
|
272
256
|
);
|
|
273
257
|
}
|
|
274
258
|
this.eventEmitter = this.accountSubscriber.eventEmitter;
|
package/src/idl/drift.json
CHANGED
package/src/math/orders.ts
CHANGED
|
@@ -124,6 +124,28 @@ export function standardizeBaseAssetAmount(
|
|
|
124
124
|
return baseAssetAmount.sub(remainder);
|
|
125
125
|
}
|
|
126
126
|
|
|
127
|
+
export function standardizePrice(
|
|
128
|
+
price: BN,
|
|
129
|
+
tickSize: BN,
|
|
130
|
+
direction: PositionDirection
|
|
131
|
+
): BN {
|
|
132
|
+
if (price.eq(ZERO)) {
|
|
133
|
+
console.log('price is zero');
|
|
134
|
+
return price;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const remainder = price.mod(tickSize);
|
|
138
|
+
if (remainder.eq(ZERO)) {
|
|
139
|
+
return price;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
if (isVariant(direction, 'long')) {
|
|
143
|
+
return price.sub(remainder);
|
|
144
|
+
} else {
|
|
145
|
+
return price.add(tickSize).sub(remainder);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
127
149
|
export function getLimitPrice(
|
|
128
150
|
order: Order,
|
|
129
151
|
oraclePriceData: OraclePriceData,
|
package/src/userMap/userMap.ts
CHANGED
|
@@ -45,10 +45,16 @@ export class UserMap implements UserMapInterface {
|
|
|
45
45
|
}
|
|
46
46
|
};
|
|
47
47
|
|
|
48
|
+
/**
|
|
49
|
+
*
|
|
50
|
+
* @param driftClient
|
|
51
|
+
* @param accountSubscription
|
|
52
|
+
* @param includeIdle whether idle users are subscribed to. defaults to false to decrease # of user subscriptions
|
|
53
|
+
*/
|
|
48
54
|
constructor(
|
|
49
55
|
driftClient: DriftClient,
|
|
50
56
|
accountSubscription: UserSubscriptionConfig,
|
|
51
|
-
includeIdle =
|
|
57
|
+
includeIdle = false
|
|
52
58
|
) {
|
|
53
59
|
this.driftClient = driftClient;
|
|
54
60
|
this.accountSubscription = accountSubscription;
|