@drift-labs/sdk 2.28.0-beta.4 → 2.28.0-beta.6
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/config.d.ts +1 -0
- package/lib/config.js +4 -3
- package/lib/constants/perpMarkets.js +20 -0
- package/lib/driftClient.d.ts +62 -7
- package/lib/driftClient.js +186 -66
- package/lib/driftClientConfig.d.ts +4 -3
- package/lib/idl/drift.json +856 -1
- package/lib/math/spotMarket.d.ts +1 -1
- package/lib/math/spotMarket.js +6 -1
- package/lib/math/utils.d.ts +9 -0
- package/lib/math/utils.js +39 -1
- package/lib/phoenix/phoenixSubscriber.js +1 -2
- package/lib/tx/retryTxSender.d.ts +1 -1
- package/lib/tx/retryTxSender.js +1 -2
- package/lib/tx/types.d.ts +1 -1
- package/lib/types.d.ts +0 -1
- package/lib/types.js +0 -1
- package/lib/user.d.ts +8 -0
- package/lib/user.js +18 -0
- package/package.json +1 -1
- package/src/assert/assert.js +9 -0
- package/src/config.ts +4 -2
- package/src/constants/perpMarkets.ts +20 -0
- package/src/driftClient.ts +273 -138
- package/src/driftClientConfig.ts +9 -3
- package/src/idl/drift.json +856 -1
- package/src/math/spotMarket.ts +6 -2
- package/src/math/utils.ts +46 -0
- package/src/phoenix/phoenixSubscriber.ts +4 -2
- package/src/token/index.js +38 -0
- package/src/tx/retryTxSender.ts +1 -9
- package/src/tx/types.ts +1 -2
- package/src/types.ts +0 -2
- package/src/user.ts +28 -0
- package/src/util/computeUnits.js +27 -0
- package/src/util/getTokenAddress.js +9 -0
- package/src/util/promiseTimeout.js +14 -0
- package/src/util/tps.js +27 -0
- package/tests/insurance/test.ts +40 -0
- package/dlob_read.ts +0 -155
package/src/math/spotMarket.ts
CHANGED
|
@@ -9,10 +9,14 @@ import { calculateAssetWeight, calculateLiabilityWeight } from './spotBalance';
|
|
|
9
9
|
import { MARGIN_PRECISION } from '../constants/numericConstants';
|
|
10
10
|
|
|
11
11
|
export function castNumberToSpotPrecision(
|
|
12
|
-
value: number,
|
|
12
|
+
value: number | BN,
|
|
13
13
|
spotMarket: SpotMarketAccount
|
|
14
14
|
): BN {
|
|
15
|
-
|
|
15
|
+
if (typeof value === 'number') {
|
|
16
|
+
return new BN(value * Math.pow(10, spotMarket.decimals));
|
|
17
|
+
} else {
|
|
18
|
+
return value.mul(new BN(Math.pow(10, spotMarket.decimals)));
|
|
19
|
+
}
|
|
16
20
|
}
|
|
17
21
|
|
|
18
22
|
export function calculateSpotMarketMarginRatio(
|
package/src/math/utils.ts
CHANGED
|
@@ -33,3 +33,49 @@ export const divCeil = (a: BN, b: BN): BN => {
|
|
|
33
33
|
return quotient;
|
|
34
34
|
}
|
|
35
35
|
};
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* calculates the time remaining until the next update based on a rounded, "on-the-hour" update schedule
|
|
39
|
+
* this schedule is used for Perpetual Funding Rate and Revenue -> Insurance Updates
|
|
40
|
+
* @param now: current blockchain unix timestamp
|
|
41
|
+
* @param lastUpdateTs: the unix timestamp of the last update
|
|
42
|
+
* @param updatePeriod: desired interval between updates (in seconds)
|
|
43
|
+
* @returns: timeRemainingUntilUpdate (in seconds)
|
|
44
|
+
*/
|
|
45
|
+
export function timeRemainingUntilUpdate(
|
|
46
|
+
now: BN,
|
|
47
|
+
lastUpdateTs: BN,
|
|
48
|
+
updatePeriod: BN
|
|
49
|
+
): BN {
|
|
50
|
+
const timeSinceLastUpdate = now.sub(lastUpdateTs);
|
|
51
|
+
|
|
52
|
+
// round next update time to be available on the hour
|
|
53
|
+
let nextUpdateWait = updatePeriod;
|
|
54
|
+
if (updatePeriod.gt(new BN(1))) {
|
|
55
|
+
const lastUpdateDelay = lastUpdateTs.umod(updatePeriod);
|
|
56
|
+
if (!lastUpdateDelay.isZero()) {
|
|
57
|
+
const maxDelayForNextPeriod = updatePeriod.div(new BN(3));
|
|
58
|
+
|
|
59
|
+
const twoFundingPeriods = updatePeriod.mul(new BN(2));
|
|
60
|
+
|
|
61
|
+
if (lastUpdateDelay.gt(maxDelayForNextPeriod)) {
|
|
62
|
+
// too late for on the hour next period, delay to following period
|
|
63
|
+
nextUpdateWait = twoFundingPeriods.sub(lastUpdateDelay);
|
|
64
|
+
} else {
|
|
65
|
+
// allow update on the hour
|
|
66
|
+
nextUpdateWait = updatePeriod.sub(lastUpdateDelay);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (nextUpdateWait.gt(twoFundingPeriods)) {
|
|
70
|
+
nextUpdateWait = nextUpdateWait.sub(updatePeriod);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
const timeRemainingUntilUpdate = nextUpdateWait
|
|
75
|
+
.sub(timeSinceLastUpdate)
|
|
76
|
+
.isNeg()
|
|
77
|
+
? ZERO
|
|
78
|
+
: nextUpdateWait.sub(timeSinceLastUpdate);
|
|
79
|
+
|
|
80
|
+
return timeRemainingUntilUpdate;
|
|
81
|
+
}
|
|
@@ -163,8 +163,10 @@ export class PhoenixSubscriber implements L2OrderBookGenerator {
|
|
|
163
163
|
}
|
|
164
164
|
|
|
165
165
|
*getL2Levels(side: 'bids' | 'asks'): Generator<L2Level> {
|
|
166
|
-
|
|
167
|
-
|
|
166
|
+
const basePrecision = Math.pow(
|
|
167
|
+
10,
|
|
168
|
+
this.market.data.header.baseParams.decimals
|
|
169
|
+
);
|
|
168
170
|
const pricePrecision = PRICE_PRECISION.toNumber();
|
|
169
171
|
|
|
170
172
|
const ladder = getMarketUiLadder(
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseTokenAccount = void 0;
|
|
4
|
+
const spl_token_1 = require("@solana/spl-token");
|
|
5
|
+
const web3_js_1 = require("@solana/web3.js");
|
|
6
|
+
function parseTokenAccount(data) {
|
|
7
|
+
const accountInfo = spl_token_1.AccountLayout.decode(data);
|
|
8
|
+
accountInfo.mint = new web3_js_1.PublicKey(accountInfo.mint);
|
|
9
|
+
accountInfo.owner = new web3_js_1.PublicKey(accountInfo.owner);
|
|
10
|
+
accountInfo.amount = spl_token_1.u64.fromBuffer(accountInfo.amount);
|
|
11
|
+
if (accountInfo.delegateOption === 0) {
|
|
12
|
+
accountInfo.delegate = null;
|
|
13
|
+
// eslint-disable-next-line new-cap
|
|
14
|
+
accountInfo.delegatedAmount = new spl_token_1.u64(0);
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
accountInfo.delegate = new web3_js_1.PublicKey(accountInfo.delegate);
|
|
18
|
+
accountInfo.delegatedAmount = spl_token_1.u64.fromBuffer(accountInfo.delegatedAmount);
|
|
19
|
+
}
|
|
20
|
+
accountInfo.isInitialized = accountInfo.state !== 0;
|
|
21
|
+
accountInfo.isFrozen = accountInfo.state === 2;
|
|
22
|
+
if (accountInfo.isNativeOption === 1) {
|
|
23
|
+
accountInfo.rentExemptReserve = spl_token_1.u64.fromBuffer(accountInfo.isNative);
|
|
24
|
+
accountInfo.isNative = true;
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
accountInfo.rentExemptReserve = null;
|
|
28
|
+
accountInfo.isNative = false;
|
|
29
|
+
}
|
|
30
|
+
if (accountInfo.closeAuthorityOption === 0) {
|
|
31
|
+
accountInfo.closeAuthority = null;
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
accountInfo.closeAuthority = new web3_js_1.PublicKey(accountInfo.closeAuthority);
|
|
35
|
+
}
|
|
36
|
+
return accountInfo;
|
|
37
|
+
}
|
|
38
|
+
exports.parseTokenAccount = parseTokenAccount;
|
package/src/tx/retryTxSender.ts
CHANGED
|
@@ -115,18 +115,10 @@ export class RetryTxSender implements TxSender {
|
|
|
115
115
|
}
|
|
116
116
|
|
|
117
117
|
async sendVersionedTransaction(
|
|
118
|
-
|
|
119
|
-
lookupTableAccounts: AddressLookupTableAccount[],
|
|
118
|
+
tx: VersionedTransaction,
|
|
120
119
|
additionalSigners?: Array<Signer>,
|
|
121
120
|
opts?: ConfirmOptions
|
|
122
121
|
): Promise<TxSigAndSlot> {
|
|
123
|
-
const tx = await this.getVersionedTransaction(
|
|
124
|
-
ixs,
|
|
125
|
-
lookupTableAccounts,
|
|
126
|
-
additionalSigners,
|
|
127
|
-
opts
|
|
128
|
-
);
|
|
129
|
-
|
|
130
122
|
// @ts-ignore
|
|
131
123
|
tx.sign(additionalSigners.concat(this.provider.wallet.payer));
|
|
132
124
|
|
package/src/tx/types.ts
CHANGED
|
@@ -25,8 +25,7 @@ export interface TxSender {
|
|
|
25
25
|
): Promise<TxSigAndSlot>;
|
|
26
26
|
|
|
27
27
|
sendVersionedTransaction(
|
|
28
|
-
|
|
29
|
-
lookupTableAccounts: AddressLookupTableAccount[],
|
|
28
|
+
tx: VersionedTransaction,
|
|
30
29
|
additionalSigners?: Array<Signer>,
|
|
31
30
|
opts?: ConfirmOptions
|
|
32
31
|
): Promise<TxSigAndSlot>;
|
package/src/types.ts
CHANGED
|
@@ -857,7 +857,6 @@ export type OrderParams = {
|
|
|
857
857
|
immediateOrCancel: boolean;
|
|
858
858
|
triggerPrice: BN | null;
|
|
859
859
|
triggerCondition: OrderTriggerCondition;
|
|
860
|
-
positionLimit: BN;
|
|
861
860
|
oraclePriceOffset: number | null;
|
|
862
861
|
auctionDuration: number | null;
|
|
863
862
|
maxTs: BN | null;
|
|
@@ -899,7 +898,6 @@ export const DefaultOrderParams: OrderParams = {
|
|
|
899
898
|
immediateOrCancel: false,
|
|
900
899
|
triggerPrice: null,
|
|
901
900
|
triggerCondition: OrderTriggerCondition.ABOVE,
|
|
902
|
-
positionLimit: ZERO,
|
|
903
901
|
oraclePriceOffset: null,
|
|
904
902
|
auctionDuration: null,
|
|
905
903
|
maxTs: null,
|
package/src/user.ts
CHANGED
|
@@ -162,6 +162,28 @@ export class User {
|
|
|
162
162
|
);
|
|
163
163
|
}
|
|
164
164
|
|
|
165
|
+
/**
|
|
166
|
+
* Returns the token amount for a given market. The spot market precision is based on the token mint decimals.
|
|
167
|
+
* Positive if it is a deposit, negative if it is a borrow.
|
|
168
|
+
*
|
|
169
|
+
* @param marketIndex
|
|
170
|
+
*/
|
|
171
|
+
public getTokenAmount(marketIndex: number): BN {
|
|
172
|
+
const spotPosition = this.getSpotPosition(marketIndex);
|
|
173
|
+
if (spotPosition === undefined) {
|
|
174
|
+
return ZERO;
|
|
175
|
+
}
|
|
176
|
+
const spotMarket = this.driftClient.getSpotMarketAccount(marketIndex);
|
|
177
|
+
return getSignedTokenAmount(
|
|
178
|
+
getTokenAmount(
|
|
179
|
+
spotPosition.scaledBalance,
|
|
180
|
+
spotMarket,
|
|
181
|
+
spotPosition.balanceType
|
|
182
|
+
),
|
|
183
|
+
spotPosition.balanceType
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
|
|
165
187
|
public getEmptyPosition(marketIndex: number): PerpPosition {
|
|
166
188
|
return {
|
|
167
189
|
baseAssetAmount: ZERO,
|
|
@@ -206,6 +228,12 @@ export class User {
|
|
|
206
228
|
);
|
|
207
229
|
}
|
|
208
230
|
|
|
231
|
+
public getOpenOrders(): Order[] {
|
|
232
|
+
return this.getUserAccount()?.orders.filter((order) =>
|
|
233
|
+
isVariant(order.status, 'open')
|
|
234
|
+
);
|
|
235
|
+
}
|
|
236
|
+
|
|
209
237
|
public getUserAccountPublicKey(): PublicKey {
|
|
210
238
|
return this.userAccountPublicKey;
|
|
211
239
|
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.findComputeUnitConsumption = void 0;
|
|
13
|
+
function findComputeUnitConsumption(programId, connection, txSignature, commitment = 'confirmed') {
|
|
14
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
15
|
+
const tx = yield connection.getTransaction(txSignature, { commitment });
|
|
16
|
+
const computeUnits = [];
|
|
17
|
+
const regex = new RegExp(`Program ${programId.toString()} consumed ([0-9]{0,6}) of ([0-9]{0,7}) compute units`);
|
|
18
|
+
tx.meta.logMessages.forEach((logMessage) => {
|
|
19
|
+
const match = logMessage.match(regex);
|
|
20
|
+
if (match && match[1]) {
|
|
21
|
+
computeUnits.push(match[1]);
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
return computeUnits;
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
exports.findComputeUnitConsumption = findComputeUnitConsumption;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getTokenAddress = void 0;
|
|
4
|
+
const spl_token_1 = require("@solana/spl-token");
|
|
5
|
+
const web3_js_1 = require("@solana/web3.js");
|
|
6
|
+
const getTokenAddress = (mintAddress, userPubKey) => {
|
|
7
|
+
return spl_token_1.Token.getAssociatedTokenAddress(spl_token_1.ASSOCIATED_TOKEN_PROGRAM_ID, spl_token_1.TOKEN_PROGRAM_ID, new web3_js_1.PublicKey(mintAddress), new web3_js_1.PublicKey(userPubKey));
|
|
8
|
+
};
|
|
9
|
+
exports.getTokenAddress = getTokenAddress;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.promiseTimeout = void 0;
|
|
4
|
+
function promiseTimeout(promise, timeoutMs) {
|
|
5
|
+
let timeoutId;
|
|
6
|
+
const timeoutPromise = new Promise((resolve) => {
|
|
7
|
+
timeoutId = setTimeout(() => resolve(null), timeoutMs);
|
|
8
|
+
});
|
|
9
|
+
return Promise.race([promise, timeoutPromise]).then((result) => {
|
|
10
|
+
clearTimeout(timeoutId);
|
|
11
|
+
return result;
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
exports.promiseTimeout = promiseTimeout;
|
package/src/util/tps.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.estimateTps = void 0;
|
|
13
|
+
function estimateTps(programId, connection, failed) {
|
|
14
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
15
|
+
let signatures = yield connection.getSignaturesForAddress(programId, undefined, 'finalized');
|
|
16
|
+
if (failed) {
|
|
17
|
+
signatures = signatures.filter((signature) => signature.err);
|
|
18
|
+
}
|
|
19
|
+
const numberOfSignatures = signatures.length;
|
|
20
|
+
if (numberOfSignatures === 0) {
|
|
21
|
+
return 0;
|
|
22
|
+
}
|
|
23
|
+
return (numberOfSignatures /
|
|
24
|
+
(signatures[0].blockTime - signatures[numberOfSignatures - 1].blockTime));
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
exports.estimateTps = estimateTps;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { BN, ZERO, timeRemainingUntilUpdate, ONE } from '../../src';
|
|
2
|
+
// import { mockPerpMarkets } from '../dlob/helpers';
|
|
3
|
+
|
|
4
|
+
import { assert } from '../../src/assert/assert';
|
|
5
|
+
|
|
6
|
+
describe('Insurance Tests', () => {
|
|
7
|
+
it('time remaining updates', () => {
|
|
8
|
+
const now = new BN(1683576852);
|
|
9
|
+
const lastUpdate = new BN(1683576000);
|
|
10
|
+
const period = new BN(3600); //hourly
|
|
11
|
+
|
|
12
|
+
let tr;
|
|
13
|
+
// console.log(now.sub(lastUpdate).toString());
|
|
14
|
+
|
|
15
|
+
tr = timeRemainingUntilUpdate(now, lastUpdate, period);
|
|
16
|
+
// console.log(tr.toString());
|
|
17
|
+
assert(tr.eq(new BN('2748')));
|
|
18
|
+
|
|
19
|
+
tr = timeRemainingUntilUpdate(now, lastUpdate.sub(period), period);
|
|
20
|
+
// console.log(tr.toString());
|
|
21
|
+
assert(tr.eq(ZERO));
|
|
22
|
+
|
|
23
|
+
const tooLateUpdate = lastUpdate.sub(period.div(new BN(3)).add(ONE));
|
|
24
|
+
tr = timeRemainingUntilUpdate(
|
|
25
|
+
tooLateUpdate.add(ONE),
|
|
26
|
+
tooLateUpdate,
|
|
27
|
+
period
|
|
28
|
+
);
|
|
29
|
+
// console.log(tr.toString());
|
|
30
|
+
assert(tr.eq(new BN('4800')));
|
|
31
|
+
|
|
32
|
+
tr = timeRemainingUntilUpdate(now, lastUpdate.add(ONE), period);
|
|
33
|
+
// console.log(tr.toString());
|
|
34
|
+
assert(tr.eq(new BN('2748')));
|
|
35
|
+
|
|
36
|
+
tr = timeRemainingUntilUpdate(now, lastUpdate.sub(ONE), period);
|
|
37
|
+
// console.log(tr.toString());
|
|
38
|
+
assert(tr.eq(new BN('2748')));
|
|
39
|
+
});
|
|
40
|
+
});
|
package/dlob_read.ts
DELETED
|
@@ -1,155 +0,0 @@
|
|
|
1
|
-
import { Connection, Keypair, PublicKey } from '@solana/web3.js';
|
|
2
|
-
import {
|
|
3
|
-
BASE_PRECISION,
|
|
4
|
-
BulkAccountLoader,
|
|
5
|
-
configs,
|
|
6
|
-
convertToNumber,
|
|
7
|
-
DLOBSubscriber,
|
|
8
|
-
DriftClient,
|
|
9
|
-
getMarketsAndOraclesForSubscription,
|
|
10
|
-
MarketType,
|
|
11
|
-
PRICE_PRECISION,
|
|
12
|
-
SlotSubscriber,
|
|
13
|
-
UserMap,
|
|
14
|
-
Wallet,
|
|
15
|
-
} from './src/index';
|
|
16
|
-
import {
|
|
17
|
-
DLOBApiClient,
|
|
18
|
-
} from './src/dlob/DLOBApiClient';
|
|
19
|
-
|
|
20
|
-
async function main() {
|
|
21
|
-
|
|
22
|
-
const driftConfig = configs['mainnet-beta'];
|
|
23
|
-
const connection = new Connection('https://api.mainnet-beta.solana.com');
|
|
24
|
-
|
|
25
|
-
const accountLoader = new BulkAccountLoader(
|
|
26
|
-
connection,
|
|
27
|
-
'confirmed',
|
|
28
|
-
10000
|
|
29
|
-
);
|
|
30
|
-
|
|
31
|
-
const { perpMarketIndexes, spotMarketIndexes, oracleInfos } = getMarketsAndOraclesForSubscription('mainnet-beta');
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
const driftClient = new DriftClient({
|
|
35
|
-
connection: connection,
|
|
36
|
-
wallet: new Wallet(new Keypair()),
|
|
37
|
-
programID: new PublicKey(driftConfig.DRIFT_PROGRAM_ID),
|
|
38
|
-
accountSubscription: {
|
|
39
|
-
type: 'polling',
|
|
40
|
-
accountLoader: accountLoader,
|
|
41
|
-
},
|
|
42
|
-
perpMarketIndexes,
|
|
43
|
-
spotMarketIndexes,
|
|
44
|
-
oracleInfos,
|
|
45
|
-
userStats: true,
|
|
46
|
-
env: 'mainnet-beta',
|
|
47
|
-
});
|
|
48
|
-
console.log(`driftClientSubscribed: ${await driftClient.subscribe()}`);
|
|
49
|
-
|
|
50
|
-
const slotSubscriber = new SlotSubscriber(connection);
|
|
51
|
-
await slotSubscriber.subscribe();
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
// Alternatively, you can also use the UserMap class, which loads the DLOB via RPC calls.
|
|
55
|
-
// const userMap = new UserMap(driftClient, driftClient.userAccountSubscriptionConfig, false);
|
|
56
|
-
|
|
57
|
-
// This loads the DLOB from a server hosted by Drift.
|
|
58
|
-
const dlobAPI = new DLOBApiClient({
|
|
59
|
-
url: 'https://dlob.drift.trade/orders/idlWithSlot',
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
const dlobSubscriber = new DLOBSubscriber({
|
|
63
|
-
dlobSource: dlobAPI,
|
|
64
|
-
slotSource: slotSubscriber,
|
|
65
|
-
driftClient: driftClient,
|
|
66
|
-
updateFrequency: 10000,
|
|
67
|
-
});
|
|
68
|
-
await dlobSubscriber.subscribe();
|
|
69
|
-
|
|
70
|
-
const l2 = dlobSubscriber.getL2({
|
|
71
|
-
marketIndex: 0,
|
|
72
|
-
marketType: MarketType.PERP,
|
|
73
|
-
});
|
|
74
|
-
console.log("Level 2 order book:");
|
|
75
|
-
|
|
76
|
-
console.log("Asks:");
|
|
77
|
-
const asks = l2.asks.slice().reverse();
|
|
78
|
-
for (let i = 0; i < asks.length; i++) {
|
|
79
|
-
const ask = asks[i];
|
|
80
|
-
console.log(` [${asks.length - i - 1}] ${convertToNumber(ask.size, BASE_PRECISION)} @ $${convertToNumber(ask.price, PRICE_PRECISION)}`);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
console.log("Bids:");
|
|
84
|
-
const bids = l2.bids;
|
|
85
|
-
for (let i = 0; i < bids.length; i++) {
|
|
86
|
-
const bid = bids[i];
|
|
87
|
-
console.log(` [${i}] ${convertToNumber(bid.size, BASE_PRECISION)} @ $${convertToNumber(bid.price, PRICE_PRECISION)}`);
|
|
88
|
-
}
|
|
89
|
-
console.log("");
|
|
90
|
-
console.log("");
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
Level 2 order book:
|
|
94
|
-
Asks:
|
|
95
|
-
[9] 664.8 @ $21.3248
|
|
96
|
-
[8] 3.5 @ $21.288301
|
|
97
|
-
[7] 3.5 @ $21.287237
|
|
98
|
-
[6] 3.5 @ $21.283129
|
|
99
|
-
[5] 0.1 @ $21.2825
|
|
100
|
-
[4] 1937.6 @ $21.2748
|
|
101
|
-
[3] 1 @ $21.26
|
|
102
|
-
[2] 2015 @ $21.2589
|
|
103
|
-
[1] 503.7 @ $21.2483
|
|
104
|
-
[0] 377.8 @ $21.243
|
|
105
|
-
Bids:
|
|
106
|
-
[0] 1168.2 @ $21.2464
|
|
107
|
-
[1] 136.7 @ $21.2461
|
|
108
|
-
[2] 2570.2 @ $21.2426
|
|
109
|
-
[3] 0.1 @ $21.2419
|
|
110
|
-
[4] 47 @ $21.216188
|
|
111
|
-
[5] 327.8 @ $21.211
|
|
112
|
-
[6] 437 @ $21.2057
|
|
113
|
-
[7] 47 @ $21.205592
|
|
114
|
-
[8] 1748.3 @ $21.1951
|
|
115
|
-
[9] 187 @ $21.1792
|
|
116
|
-
*/
|
|
117
|
-
|
|
118
|
-
const l3 = dlobSubscriber.getL3({
|
|
119
|
-
marketIndex: 0,
|
|
120
|
-
marketType: MarketType.PERP,
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
console.log("Level 3 order book:");
|
|
124
|
-
console.log("Asks:");
|
|
125
|
-
const l3asks = l3.asks.slice().reverse();
|
|
126
|
-
for (let i = 0; i < l3asks.length; i++) {
|
|
127
|
-
const ask = l3asks[i];
|
|
128
|
-
console.log(` [${l3asks.length - i - 1}] ${ask.maker.toBase58()} ${convertToNumber(ask.size, BASE_PRECISION)} @ $${convertToNumber(ask.price, PRICE_PRECISION)}`);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
console.log("Bids:");
|
|
132
|
-
const l3bids = l3.bids;
|
|
133
|
-
for (let i = 0; i < l3bids.length; i++) {
|
|
134
|
-
const bid = l3bids[i];
|
|
135
|
-
console.log(` [${i}] ${bid.maker.toBase58()} ${convertToNumber(bid.size, BASE_PRECISION)} @ $${convertToNumber(bid.price, PRICE_PRECISION)}`);
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
/**
|
|
139
|
-
Level 3 order book:
|
|
140
|
-
Asks:
|
|
141
|
-
...
|
|
142
|
-
[3] FrEFAwxdrzHxgc7S4cuFfsfLmcg8pfbxnkCQW83euyCS 1 @ $21.26
|
|
143
|
-
[2] C13FZykQfLXKuMAMh2iuG7JxhQqd8otujNRAgVETU6id 2015 @ $21.2589
|
|
144
|
-
[1] C13FZykQfLXKuMAMh2iuG7JxhQqd8otujNRAgVETU6id 503.7 @ $21.2483
|
|
145
|
-
[0] C13FZykQfLXKuMAMh2iuG7JxhQqd8otujNRAgVETU6id 377.8 @ $21.243
|
|
146
|
-
Bids:
|
|
147
|
-
[0] FrEFAwxdrzHxgc7S4cuFfsfLmcg8pfbxnkCQW83euyCS 1168.2 @ $21.2464
|
|
148
|
-
[1] FrEFAwxdrzHxgc7S4cuFfsfLmcg8pfbxnkCQW83euyCS 2570.2 @ $21.2464
|
|
149
|
-
[2] FrEFAwxdrzHxgc7S4cuFfsfLmcg8pfbxnkCQW83euyCS 136.7 @ $21.2461
|
|
150
|
-
[3] FrEFAwxdrzHxgc7S4cuFfsfLmcg8pfbxnkCQW83euyCS 2570.2 @ $21.2426
|
|
151
|
-
...
|
|
152
|
-
*/
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
main().catch(console.error);
|