@drift-labs/sdk 2.31.0-beta.1 → 2.31.0-beta.4
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/bulkAccountLoader.js +5 -0
- package/lib/auctionSubscriber/auctionSubscriber.d.ts +13 -0
- package/lib/auctionSubscriber/auctionSubscriber.js +22 -0
- package/lib/auctionSubscriber/index.d.ts +2 -0
- package/lib/auctionSubscriber/index.js +18 -0
- package/lib/auctionSubscriber/types.d.ts +10 -0
- package/lib/auctionSubscriber/types.js +2 -0
- package/lib/driftClient.d.ts +2 -0
- package/lib/driftClient.js +22 -9
- package/lib/events/eventSubscriber.d.ts +1 -0
- package/lib/events/eventSubscriber.js +5 -3
- package/lib/events/fetchLogs.d.ts +1 -1
- package/lib/events/fetchLogs.js +2 -2
- package/lib/events/pollingLogProvider.d.ts +2 -2
- package/lib/events/pollingLogProvider.js +3 -3
- package/lib/events/types.d.ts +2 -1
- package/lib/events/webSocketLogProvider.d.ts +2 -2
- package/lib/events/webSocketLogProvider.js +3 -3
- package/lib/idl/drift.json +61 -2
- package/lib/index.d.ts +1 -0
- package/lib/index.js +1 -0
- package/lib/math/spotBalance.js +1 -1
- package/lib/memcmp.d.ts +5 -0
- package/lib/memcmp.js +44 -0
- package/lib/orderSubscriber/OrderSubscriber.d.ts +24 -0
- package/lib/orderSubscriber/OrderSubscriber.js +100 -0
- package/lib/orderSubscriber/PollingSubscription.d.ts +13 -0
- package/lib/orderSubscriber/PollingSubscription.js +23 -0
- package/lib/orderSubscriber/WebsocketSubscription.d.ts +12 -0
- package/lib/orderSubscriber/WebsocketSubscription.js +30 -0
- package/lib/orderSubscriber/index.d.ts +2 -0
- package/lib/orderSubscriber/index.js +18 -0
- package/lib/orderSubscriber/types.d.ts +11 -0
- package/lib/orderSubscriber/types.js +2 -0
- package/lib/tx/retryTxSender.js +5 -2
- package/lib/types.d.ts +5 -1
- package/lib/types.js +1 -1
- package/lib/userMap/userMap.js +4 -19
- package/package.json +1 -1
- package/src/accounts/bulkAccountLoader.ts +5 -0
- package/src/auctionSubscriber/auctionSubscriber.ts +50 -0
- package/src/auctionSubscriber/index.ts +2 -0
- package/src/auctionSubscriber/types.ts +16 -0
- package/src/driftClient.ts +41 -10
- package/src/events/eventSubscriber.ts +6 -4
- package/src/events/fetchLogs.ts +2 -2
- package/src/events/pollingLogProvider.ts +2 -2
- package/src/events/types.ts +2 -1
- package/src/events/webSocketLogProvider.ts +2 -2
- package/src/idl/drift.json +61 -2
- package/src/index.ts +1 -0
- package/src/math/spotBalance.ts +1 -3
- package/src/memcmp.ts +39 -0
- package/src/orderSubscriber/OrderSubscriber.ts +132 -0
- package/src/orderSubscriber/PollingSubscription.ts +39 -0
- package/src/orderSubscriber/WebsocketSubscription.ts +54 -0
- package/src/orderSubscriber/index.ts +2 -0
- package/src/orderSubscriber/types.ts +14 -0
- package/src/tx/retryTxSender.ts +8 -2
- package/src/types.ts +5 -1
- package/src/userMap/userMap.ts +4 -16
|
@@ -124,6 +124,11 @@ class BulkAccountLoader {
|
|
|
124
124
|
}
|
|
125
125
|
for (const i in rpcResponses) {
|
|
126
126
|
const rpcResponse = rpcResponses[i];
|
|
127
|
+
if (!rpcResponse.result) {
|
|
128
|
+
console.error('rpc response missing result:');
|
|
129
|
+
console.log(JSON.stringify(rpcResponse));
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
127
132
|
const newSlot = rpcResponse.result.context.slot;
|
|
128
133
|
if (newSlot > this.mostRecentSlot) {
|
|
129
134
|
this.mostRecentSlot = newSlot;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import { AuctionSubscriberConfig, AuctionSubscriberEvents } from './types';
|
|
3
|
+
import StrictEventEmitter from 'strict-event-emitter-types';
|
|
4
|
+
import { EventEmitter } from 'events';
|
|
5
|
+
export declare class AuctionSubscriber {
|
|
6
|
+
private driftClient;
|
|
7
|
+
private opts;
|
|
8
|
+
eventEmitter: StrictEventEmitter<EventEmitter, AuctionSubscriberEvents>;
|
|
9
|
+
private websocketId;
|
|
10
|
+
constructor({ driftClient, opts }: AuctionSubscriberConfig);
|
|
11
|
+
subscribe(): Promise<void>;
|
|
12
|
+
unsubscribe(): Promise<void>;
|
|
13
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AuctionSubscriber = void 0;
|
|
4
|
+
const memcmp_1 = require("../memcmp");
|
|
5
|
+
class AuctionSubscriber {
|
|
6
|
+
constructor({ driftClient, opts }) {
|
|
7
|
+
this.driftClient = driftClient;
|
|
8
|
+
this.opts = opts || this.driftClient.opts;
|
|
9
|
+
}
|
|
10
|
+
async subscribe() {
|
|
11
|
+
this.websocketId = this.driftClient.connection.onProgramAccountChange(this.driftClient.program.programId, (keyAccountInfo, context) => {
|
|
12
|
+
const userAccount = this.driftClient.program.account.user.coder.accounts.decode('User', keyAccountInfo.accountInfo.data);
|
|
13
|
+
this.eventEmitter.emit('onAccountUpdate', userAccount, keyAccountInfo.accountId, context.slot);
|
|
14
|
+
}, this.driftClient.opts.commitment, [(0, memcmp_1.getUserFilter)(), (0, memcmp_1.getUserWithAuctionFilter)()]);
|
|
15
|
+
}
|
|
16
|
+
async unsubscribe() {
|
|
17
|
+
if (this.websocketId) {
|
|
18
|
+
await this.driftClient.connection.removeProgramAccountChangeListener(this.websocketId);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
exports.AuctionSubscriber = AuctionSubscriber;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./types"), exports);
|
|
18
|
+
__exportStar(require("./auctionSubscriber"), exports);
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { DriftClient } from '../driftClient';
|
|
2
|
+
import { UserAccount } from '../types';
|
|
3
|
+
import { ConfirmOptions, PublicKey } from '@solana/web3.js';
|
|
4
|
+
export type AuctionSubscriberConfig = {
|
|
5
|
+
driftClient: DriftClient;
|
|
6
|
+
opts?: ConfirmOptions;
|
|
7
|
+
};
|
|
8
|
+
export interface AuctionSubscriberEvents {
|
|
9
|
+
onAccountUpdate: (account: UserAccount, pubkey: PublicKey, slot: number) => void;
|
|
10
|
+
}
|
package/lib/driftClient.d.ts
CHANGED
|
@@ -329,6 +329,8 @@ export declare class DriftClient {
|
|
|
329
329
|
getForceCancelOrdersIx(userAccountPublicKey: PublicKey, userAccount: UserAccount): Promise<TransactionInstruction>;
|
|
330
330
|
updateUserIdle(userAccountPublicKey: PublicKey, user: UserAccount, txParams?: TxParams): Promise<TransactionSignature>;
|
|
331
331
|
getUpdateUserIdleIx(userAccountPublicKey: PublicKey, userAccount: UserAccount): Promise<TransactionInstruction>;
|
|
332
|
+
updateUserOpenOrdersCount(userAccountPublicKey: PublicKey, user: UserAccount, txParams?: TxParams): Promise<TransactionSignature>;
|
|
333
|
+
getUpdateUserOpenOrdersCountIx(userAccountPublicKey: PublicKey, userAccount: UserAccount): Promise<TransactionInstruction>;
|
|
332
334
|
placeAndTakePerpOrder(orderParams: OptionalOrderParams, makerInfo?: MakerInfo | MakerInfo[], referrerInfo?: ReferrerInfo, txParams?: TxParams): Promise<TransactionSignature>;
|
|
333
335
|
getPlaceAndTakePerpOrderIx(orderParams: OptionalOrderParams, makerInfo?: MakerInfo | MakerInfo[], referrerInfo?: ReferrerInfo): Promise<TransactionInstruction>;
|
|
334
336
|
placeAndMakePerpOrder(orderParams: OptionalOrderParams, takerInfo: TakerInfo, referrerInfo?: ReferrerInfo, txParams?: TxParams): Promise<TransactionSignature>;
|
package/lib/driftClient.js
CHANGED
|
@@ -51,6 +51,7 @@ const spotPosition_1 = require("./math/spotPosition");
|
|
|
51
51
|
const market_1 = require("./math/market");
|
|
52
52
|
const fetch_1 = require("./accounts/fetch");
|
|
53
53
|
const spotMarket_1 = require("./math/spotMarket");
|
|
54
|
+
const memcmp_1 = require("./memcmp");
|
|
54
55
|
/**
|
|
55
56
|
* # DriftClient
|
|
56
57
|
* This class is the main way to interact with Drift Protocol. It allows you to subscribe to the various accounts where the Market's state is stored, as well as: opening positions, liquidating, settling funding, depositing & withdrawing, and more.
|
|
@@ -515,14 +516,7 @@ class DriftClient {
|
|
|
515
516
|
async fetchAllUserAccounts(includeIdle = true) {
|
|
516
517
|
let filters = undefined;
|
|
517
518
|
if (!includeIdle) {
|
|
518
|
-
filters = [
|
|
519
|
-
{
|
|
520
|
-
memcmp: {
|
|
521
|
-
offset: 4350,
|
|
522
|
-
bytes: bs58_1.default.encode(Uint8Array.from([0])),
|
|
523
|
-
},
|
|
524
|
-
},
|
|
525
|
-
];
|
|
519
|
+
filters = [(0, memcmp_1.getNonIdleUserFilter)()];
|
|
526
520
|
}
|
|
527
521
|
return (await this.program.account.user.all(filters));
|
|
528
522
|
}
|
|
@@ -2024,7 +2018,7 @@ class DriftClient {
|
|
|
2024
2018
|
...jupiterInstructions,
|
|
2025
2019
|
endSwapIx,
|
|
2026
2020
|
];
|
|
2027
|
-
const tx = await this.buildTransaction(instructions, txParams, 0, lookupTables);
|
|
2021
|
+
const tx = (await this.buildTransaction(instructions, txParams, 0, lookupTables));
|
|
2028
2022
|
const { txSig, slot } = await this.sendTransaction(tx);
|
|
2029
2023
|
this.spotMarketLastSlotCache.set(outMarketIndex, slot);
|
|
2030
2024
|
this.spotMarketLastSlotCache.set(inMarketIndex, slot);
|
|
@@ -2152,6 +2146,25 @@ class DriftClient {
|
|
|
2152
2146
|
remainingAccounts,
|
|
2153
2147
|
});
|
|
2154
2148
|
}
|
|
2149
|
+
async updateUserOpenOrdersCount(userAccountPublicKey, user, txParams) {
|
|
2150
|
+
const { txSig } = await this.sendTransaction(await this.buildTransaction(await this.getUpdateUserOpenOrdersCountIx(userAccountPublicKey, user), txParams), [], this.opts);
|
|
2151
|
+
return txSig;
|
|
2152
|
+
}
|
|
2153
|
+
async getUpdateUserOpenOrdersCountIx(userAccountPublicKey, userAccount) {
|
|
2154
|
+
const fillerPublicKey = await this.getUserAccountPublicKey();
|
|
2155
|
+
const remainingAccounts = this.getRemainingAccounts({
|
|
2156
|
+
userAccounts: [userAccount],
|
|
2157
|
+
});
|
|
2158
|
+
return await this.program.instruction.updateUserOpenOrdersCount({
|
|
2159
|
+
accounts: {
|
|
2160
|
+
state: await this.getStatePublicKey(),
|
|
2161
|
+
filler: fillerPublicKey,
|
|
2162
|
+
user: userAccountPublicKey,
|
|
2163
|
+
authority: this.wallet.publicKey,
|
|
2164
|
+
},
|
|
2165
|
+
remainingAccounts,
|
|
2166
|
+
});
|
|
2167
|
+
}
|
|
2155
2168
|
async placeAndTakePerpOrder(orderParams, makerInfo, referrerInfo, txParams) {
|
|
2156
2169
|
const { txSig, slot } = await this.sendTransaction(await this.buildTransaction(await this.getPlaceAndTakePerpOrderIx(orderParams, makerInfo, referrerInfo), txParams), [], this.opts);
|
|
2157
2170
|
this.perpMarketLastSlotCache.set(orderParams.marketIndex, slot);
|
|
@@ -11,12 +11,14 @@ const events_1 = require("events");
|
|
|
11
11
|
const sort_1 = require("./sort");
|
|
12
12
|
class EventSubscriber {
|
|
13
13
|
constructor(connection, program, options = types_1.DefaultEventSubscriptionOptions) {
|
|
14
|
+
var _a;
|
|
14
15
|
this.connection = connection;
|
|
15
16
|
this.program = program;
|
|
16
17
|
this.options = options;
|
|
17
18
|
this.awaitTxPromises = new Map();
|
|
18
19
|
this.awaitTxResolver = new Map();
|
|
19
20
|
this.options = Object.assign({}, types_1.DefaultEventSubscriptionOptions, options);
|
|
21
|
+
this.address = (_a = this.options.address) !== null && _a !== void 0 ? _a : program.programId;
|
|
20
22
|
this.txEventCache = new txEventCache_1.TxEventCache(this.options.maxTx);
|
|
21
23
|
this.eventListMap = new Map();
|
|
22
24
|
for (const eventType of this.options.eventTypes) {
|
|
@@ -24,10 +26,10 @@ class EventSubscriber {
|
|
|
24
26
|
}
|
|
25
27
|
this.eventEmitter = new events_1.EventEmitter();
|
|
26
28
|
if (this.options.logProviderConfig.type === 'websocket') {
|
|
27
|
-
this.logProvider = new webSocketLogProvider_1.WebSocketLogProvider(this.connection, this.
|
|
29
|
+
this.logProvider = new webSocketLogProvider_1.WebSocketLogProvider(this.connection, this.address, this.options.commitment);
|
|
28
30
|
}
|
|
29
31
|
else {
|
|
30
|
-
this.logProvider = new pollingLogProvider_1.PollingLogProvider(this.connection, this.
|
|
32
|
+
this.logProvider = new pollingLogProvider_1.PollingLogProvider(this.connection, this.address, options.commitment, this.options.logProviderConfig.frequency);
|
|
31
33
|
}
|
|
32
34
|
}
|
|
33
35
|
async subscribe() {
|
|
@@ -80,7 +82,7 @@ class EventSubscriber {
|
|
|
80
82
|
let beforeTx = undefined;
|
|
81
83
|
const untilTx = this.options.untilTx;
|
|
82
84
|
while (txFetched < this.options.maxTx) {
|
|
83
|
-
const response = await (0, fetchLogs_1.fetchLogs)(this.connection, this.
|
|
85
|
+
const response = await (0, fetchLogs_1.fetchLogs)(this.connection, this.address, this.options.commitment === 'finalized' ? 'finalized' : 'confirmed', beforeTx, untilTx);
|
|
84
86
|
if (response === undefined) {
|
|
85
87
|
break;
|
|
86
88
|
}
|
|
@@ -14,7 +14,7 @@ type FetchLogsResponse = {
|
|
|
14
14
|
transactionLogs: Log[];
|
|
15
15
|
mostRecentBlockTime: number | undefined;
|
|
16
16
|
};
|
|
17
|
-
export declare function fetchLogs(connection: Connection,
|
|
17
|
+
export declare function fetchLogs(connection: Connection, address: PublicKey, finality: Finality, beforeTx?: TransactionSignature, untilTx?: TransactionSignature, limit?: number): Promise<FetchLogsResponse>;
|
|
18
18
|
export declare class LogParser {
|
|
19
19
|
private program;
|
|
20
20
|
constructor(program: Program);
|
package/lib/events/fetchLogs.js
CHANGED
|
@@ -8,8 +8,8 @@ function mapTransactionResponseToLog(transaction) {
|
|
|
8
8
|
logs: transaction.meta.logMessages,
|
|
9
9
|
};
|
|
10
10
|
}
|
|
11
|
-
async function fetchLogs(connection,
|
|
12
|
-
const signatures = await connection.getSignaturesForAddress(
|
|
11
|
+
async function fetchLogs(connection, address, finality, beforeTx, untilTx, limit) {
|
|
12
|
+
const signatures = await connection.getSignaturesForAddress(address, {
|
|
13
13
|
before: beforeTx,
|
|
14
14
|
until: untilTx,
|
|
15
15
|
limit,
|
|
@@ -2,14 +2,14 @@ import { LogProvider, logProviderCallback } from './types';
|
|
|
2
2
|
import { Commitment, Connection, PublicKey } from '@solana/web3.js';
|
|
3
3
|
export declare class PollingLogProvider implements LogProvider {
|
|
4
4
|
private connection;
|
|
5
|
-
private
|
|
5
|
+
private address;
|
|
6
6
|
private frequency;
|
|
7
7
|
private finality;
|
|
8
8
|
private intervalId;
|
|
9
9
|
private mostRecentSeenTx?;
|
|
10
10
|
private mutex;
|
|
11
11
|
private firstFetch;
|
|
12
|
-
constructor(connection: Connection,
|
|
12
|
+
constructor(connection: Connection, address: PublicKey, commitment: Commitment, frequency?: number);
|
|
13
13
|
subscribe(callback: logProviderCallback, skipHistory?: boolean): boolean;
|
|
14
14
|
isSubscribed(): boolean;
|
|
15
15
|
unsubscribe(): Promise<boolean>;
|
|
@@ -3,9 +3,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.PollingLogProvider = void 0;
|
|
4
4
|
const fetchLogs_1 = require("./fetchLogs");
|
|
5
5
|
class PollingLogProvider {
|
|
6
|
-
constructor(connection,
|
|
6
|
+
constructor(connection, address, commitment, frequency = 15 * 1000) {
|
|
7
7
|
this.connection = connection;
|
|
8
|
-
this.
|
|
8
|
+
this.address = address;
|
|
9
9
|
this.frequency = frequency;
|
|
10
10
|
this.firstFetch = true;
|
|
11
11
|
this.finality = commitment === 'finalized' ? 'finalized' : 'confirmed';
|
|
@@ -20,7 +20,7 @@ class PollingLogProvider {
|
|
|
20
20
|
}
|
|
21
21
|
this.mutex = 1;
|
|
22
22
|
try {
|
|
23
|
-
const response = await (0, fetchLogs_1.fetchLogs)(this.connection, this.
|
|
23
|
+
const response = await (0, fetchLogs_1.fetchLogs)(this.connection, this.address, this.finality, undefined, this.mostRecentSeenTx,
|
|
24
24
|
// If skipping history, only fetch one log back, not the maximum amount available
|
|
25
25
|
skipHistory && this.firstFetch ? 1 : undefined);
|
|
26
26
|
if (response === undefined) {
|
package/lib/events/types.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { Commitment, TransactionSignature } from '@solana/web3.js';
|
|
1
|
+
import { Commitment, PublicKey, TransactionSignature } from '@solana/web3.js';
|
|
2
2
|
import { DepositRecord, FundingPaymentRecord, FundingRateRecord, LiquidationRecord, NewUserRecord, OrderActionRecord, OrderRecord, SettlePnlRecord, LPRecord, InsuranceFundRecord, SpotInterestRecord, InsuranceFundStakeRecord, CurveRecord, SwapRecord } from '../index';
|
|
3
3
|
export type EventSubscriptionOptions = {
|
|
4
|
+
address?: PublicKey;
|
|
4
5
|
eventTypes?: EventType[];
|
|
5
6
|
maxEventsPerType?: number;
|
|
6
7
|
orderBy?: EventSubscriptionOrderBy;
|
|
@@ -2,10 +2,10 @@ import { LogProvider, logProviderCallback } from './types';
|
|
|
2
2
|
import { Commitment, Connection, PublicKey } from '@solana/web3.js';
|
|
3
3
|
export declare class WebSocketLogProvider implements LogProvider {
|
|
4
4
|
private connection;
|
|
5
|
-
private
|
|
5
|
+
private address;
|
|
6
6
|
private commitment;
|
|
7
7
|
private subscriptionId;
|
|
8
|
-
constructor(connection: Connection,
|
|
8
|
+
constructor(connection: Connection, address: PublicKey, commitment: Commitment);
|
|
9
9
|
subscribe(callback: logProviderCallback): boolean;
|
|
10
10
|
isSubscribed(): boolean;
|
|
11
11
|
unsubscribe(): Promise<boolean>;
|
|
@@ -2,16 +2,16 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.WebSocketLogProvider = void 0;
|
|
4
4
|
class WebSocketLogProvider {
|
|
5
|
-
constructor(connection,
|
|
5
|
+
constructor(connection, address, commitment) {
|
|
6
6
|
this.connection = connection;
|
|
7
|
-
this.
|
|
7
|
+
this.address = address;
|
|
8
8
|
this.commitment = commitment;
|
|
9
9
|
}
|
|
10
10
|
subscribe(callback) {
|
|
11
11
|
if (this.subscriptionId) {
|
|
12
12
|
return true;
|
|
13
13
|
}
|
|
14
|
-
this.subscriptionId = this.connection.onLogs(this.
|
|
14
|
+
this.subscriptionId = this.connection.onLogs(this.address, (logs, ctx) => {
|
|
15
15
|
callback(logs.signature, ctx.slot, logs.logs, undefined);
|
|
16
16
|
}, this.commitment);
|
|
17
17
|
return true;
|
package/lib/idl/drift.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "2.31.0-beta.
|
|
2
|
+
"version": "2.31.0-beta.4",
|
|
3
3
|
"name": "drift",
|
|
4
4
|
"instructions": [
|
|
5
5
|
{
|
|
@@ -1305,6 +1305,32 @@
|
|
|
1305
1305
|
],
|
|
1306
1306
|
"args": []
|
|
1307
1307
|
},
|
|
1308
|
+
{
|
|
1309
|
+
"name": "updateUserOpenOrdersCount",
|
|
1310
|
+
"accounts": [
|
|
1311
|
+
{
|
|
1312
|
+
"name": "state",
|
|
1313
|
+
"isMut": false,
|
|
1314
|
+
"isSigner": false
|
|
1315
|
+
},
|
|
1316
|
+
{
|
|
1317
|
+
"name": "authority",
|
|
1318
|
+
"isMut": false,
|
|
1319
|
+
"isSigner": true
|
|
1320
|
+
},
|
|
1321
|
+
{
|
|
1322
|
+
"name": "filler",
|
|
1323
|
+
"isMut": true,
|
|
1324
|
+
"isSigner": false
|
|
1325
|
+
},
|
|
1326
|
+
{
|
|
1327
|
+
"name": "user",
|
|
1328
|
+
"isMut": true,
|
|
1329
|
+
"isSigner": false
|
|
1330
|
+
}
|
|
1331
|
+
],
|
|
1332
|
+
"args": []
|
|
1333
|
+
},
|
|
1308
1334
|
{
|
|
1309
1335
|
"name": "settlePnl",
|
|
1310
1336
|
"accounts": [
|
|
@@ -5438,12 +5464,40 @@
|
|
|
5438
5464
|
],
|
|
5439
5465
|
"type": "bool"
|
|
5440
5466
|
},
|
|
5467
|
+
{
|
|
5468
|
+
"name": "openOrders",
|
|
5469
|
+
"docs": [
|
|
5470
|
+
"number of open orders"
|
|
5471
|
+
],
|
|
5472
|
+
"type": "u8"
|
|
5473
|
+
},
|
|
5474
|
+
{
|
|
5475
|
+
"name": "hasOpenOrder",
|
|
5476
|
+
"docs": [
|
|
5477
|
+
"Whether or not user has open order"
|
|
5478
|
+
],
|
|
5479
|
+
"type": "bool"
|
|
5480
|
+
},
|
|
5481
|
+
{
|
|
5482
|
+
"name": "openAuctions",
|
|
5483
|
+
"docs": [
|
|
5484
|
+
"number of open orders with auction"
|
|
5485
|
+
],
|
|
5486
|
+
"type": "u8"
|
|
5487
|
+
},
|
|
5488
|
+
{
|
|
5489
|
+
"name": "hasOpenAuction",
|
|
5490
|
+
"docs": [
|
|
5491
|
+
"Whether or not user has open order with auction"
|
|
5492
|
+
],
|
|
5493
|
+
"type": "bool"
|
|
5494
|
+
},
|
|
5441
5495
|
{
|
|
5442
5496
|
"name": "padding",
|
|
5443
5497
|
"type": {
|
|
5444
5498
|
"array": [
|
|
5445
5499
|
"u8",
|
|
5446
|
-
|
|
5500
|
+
21
|
|
5447
5501
|
]
|
|
5448
5502
|
}
|
|
5449
5503
|
}
|
|
@@ -10433,6 +10487,11 @@
|
|
|
10433
10487
|
"code": 6250,
|
|
10434
10488
|
"name": "SpotMarketReduceOnly",
|
|
10435
10489
|
"msg": "SpotMarketReduceOnly"
|
|
10490
|
+
},
|
|
10491
|
+
{
|
|
10492
|
+
"code": 6251,
|
|
10493
|
+
"name": "FundingWasNotUpdated",
|
|
10494
|
+
"msg": "FundingWasNotUpdated"
|
|
10436
10495
|
}
|
|
10437
10496
|
]
|
|
10438
10497
|
}
|
package/lib/index.d.ts
CHANGED
package/lib/index.js
CHANGED
|
@@ -98,3 +98,4 @@ __exportStar(require("./dlob/orderBookLevels"), exports);
|
|
|
98
98
|
__exportStar(require("./userMap/userMap"), exports);
|
|
99
99
|
__exportStar(require("./userMap/userStatsMap"), exports);
|
|
100
100
|
__exportStar(require("./math/bankruptcy"), exports);
|
|
101
|
+
__exportStar(require("./orderSubscriber"), exports);
|
package/lib/math/spotBalance.js
CHANGED
|
@@ -189,7 +189,7 @@ function calculateInterestRate(bank) {
|
|
|
189
189
|
else {
|
|
190
190
|
const borrowRateSlope = new anchor_1.BN(bank.optimalBorrowRate)
|
|
191
191
|
.mul(numericConstants_1.SPOT_MARKET_UTILIZATION_PRECISION)
|
|
192
|
-
.div(
|
|
192
|
+
.div(new anchor_1.BN(bank.optimalUtilization));
|
|
193
193
|
interestRate = utilization
|
|
194
194
|
.mul(borrowRateSlope)
|
|
195
195
|
.div(numericConstants_1.SPOT_MARKET_UTILIZATION_PRECISION);
|
package/lib/memcmp.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { MemcmpFilter } from '@solana/web3.js';
|
|
2
|
+
export declare function getUserFilter(): MemcmpFilter;
|
|
3
|
+
export declare function getNonIdleUserFilter(): MemcmpFilter;
|
|
4
|
+
export declare function getUserWithOrderFilter(): MemcmpFilter;
|
|
5
|
+
export declare function getUserWithAuctionFilter(): MemcmpFilter;
|
package/lib/memcmp.js
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.getUserWithAuctionFilter = exports.getUserWithOrderFilter = exports.getNonIdleUserFilter = exports.getUserFilter = void 0;
|
|
7
|
+
const bs58_1 = __importDefault(require("bs58"));
|
|
8
|
+
const anchor_1 = require("@coral-xyz/anchor");
|
|
9
|
+
function getUserFilter() {
|
|
10
|
+
return {
|
|
11
|
+
memcmp: {
|
|
12
|
+
offset: 0,
|
|
13
|
+
bytes: bs58_1.default.encode(anchor_1.BorshAccountsCoder.accountDiscriminator('User')),
|
|
14
|
+
},
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
exports.getUserFilter = getUserFilter;
|
|
18
|
+
function getNonIdleUserFilter() {
|
|
19
|
+
return {
|
|
20
|
+
memcmp: {
|
|
21
|
+
offset: 4350,
|
|
22
|
+
bytes: bs58_1.default.encode(Uint8Array.from([0])),
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
exports.getNonIdleUserFilter = getNonIdleUserFilter;
|
|
27
|
+
function getUserWithOrderFilter() {
|
|
28
|
+
return {
|
|
29
|
+
memcmp: {
|
|
30
|
+
offset: 4352,
|
|
31
|
+
bytes: bs58_1.default.encode(Uint8Array.from([1])),
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
exports.getUserWithOrderFilter = getUserWithOrderFilter;
|
|
36
|
+
function getUserWithAuctionFilter() {
|
|
37
|
+
return {
|
|
38
|
+
memcmp: {
|
|
39
|
+
offset: 4354,
|
|
40
|
+
bytes: bs58_1.default.encode(Uint8Array.from([1])),
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
exports.getUserWithAuctionFilter = getUserWithAuctionFilter;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import { DriftClient } from '../driftClient';
|
|
3
|
+
import { UserAccount } from '../types';
|
|
4
|
+
import { Buffer } from 'buffer';
|
|
5
|
+
import { DLOB } from '../dlob/DLOB';
|
|
6
|
+
import { OrderSubscriberConfig } from './types';
|
|
7
|
+
import { PollingSubscription } from './PollingSubscription';
|
|
8
|
+
import { WebsocketSubscription } from './WebsocketSubscription';
|
|
9
|
+
export declare class OrderSubscriber {
|
|
10
|
+
driftClient: DriftClient;
|
|
11
|
+
usersAccounts: Map<string, {
|
|
12
|
+
slot: number;
|
|
13
|
+
userAccount: UserAccount;
|
|
14
|
+
}>;
|
|
15
|
+
subscription: PollingSubscription | WebsocketSubscription;
|
|
16
|
+
fetchPromise?: Promise<void>;
|
|
17
|
+
fetchPromiseResolver: () => void;
|
|
18
|
+
constructor(config: OrderSubscriberConfig);
|
|
19
|
+
subscribe(): Promise<void>;
|
|
20
|
+
fetch(): Promise<void>;
|
|
21
|
+
tryUpdateUserAccount(key: string, buffer: Buffer, slot: number): void;
|
|
22
|
+
getDLOB(slot: number): Promise<DLOB>;
|
|
23
|
+
unsubscribe(): Promise<void>;
|
|
24
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.OrderSubscriber = void 0;
|
|
4
|
+
const memcmp_1 = require("../memcmp");
|
|
5
|
+
const web3_js_1 = require("@solana/web3.js");
|
|
6
|
+
const buffer_1 = require("buffer");
|
|
7
|
+
const DLOB_1 = require("../dlob/DLOB");
|
|
8
|
+
const PollingSubscription_1 = require("./PollingSubscription");
|
|
9
|
+
const WebsocketSubscription_1 = require("./WebsocketSubscription");
|
|
10
|
+
class OrderSubscriber {
|
|
11
|
+
constructor(config) {
|
|
12
|
+
this.usersAccounts = new Map();
|
|
13
|
+
this.driftClient = config.driftClient;
|
|
14
|
+
if (config.subscriptionConfig.type === 'polling') {
|
|
15
|
+
this.subscription = new PollingSubscription_1.PollingSubscription({
|
|
16
|
+
orderSubscriber: this,
|
|
17
|
+
frequency: config.subscriptionConfig.frequency,
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
this.subscription = new WebsocketSubscription_1.WebsocketSubscription({
|
|
22
|
+
orderSubscriber: this,
|
|
23
|
+
skipInitialLoad: config.subscriptionConfig.skipInitialLoad,
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
async subscribe() {
|
|
28
|
+
await this.subscription.subscribe();
|
|
29
|
+
}
|
|
30
|
+
async fetch() {
|
|
31
|
+
if (this.fetchPromise) {
|
|
32
|
+
return this.fetchPromise;
|
|
33
|
+
}
|
|
34
|
+
this.fetchPromise = new Promise((resolver) => {
|
|
35
|
+
this.fetchPromiseResolver = resolver;
|
|
36
|
+
});
|
|
37
|
+
try {
|
|
38
|
+
const rpcRequestArgs = [
|
|
39
|
+
this.driftClient.program.programId.toBase58(),
|
|
40
|
+
{
|
|
41
|
+
commitment: this.driftClient.opts.commitment,
|
|
42
|
+
filters: [(0, memcmp_1.getUserFilter)(), (0, memcmp_1.getUserWithOrderFilter)()],
|
|
43
|
+
encoding: 'base64',
|
|
44
|
+
withContext: true,
|
|
45
|
+
},
|
|
46
|
+
];
|
|
47
|
+
const rpcJSONResponse =
|
|
48
|
+
// @ts-ignore
|
|
49
|
+
await this.driftClient.connection._rpcRequest('getProgramAccounts', rpcRequestArgs);
|
|
50
|
+
const rpcResponseAndContext = rpcJSONResponse.result;
|
|
51
|
+
const slot = rpcResponseAndContext.context.slot;
|
|
52
|
+
const programAccountSet = new Set();
|
|
53
|
+
for (const programAccount of rpcResponseAndContext.value) {
|
|
54
|
+
const key = programAccount.pubkey.toString();
|
|
55
|
+
// @ts-ignore
|
|
56
|
+
const buffer = buffer_1.Buffer.from(programAccount.account.data[0], programAccount.account.data[1]);
|
|
57
|
+
programAccountSet.add(key);
|
|
58
|
+
this.tryUpdateUserAccount(key, buffer, slot);
|
|
59
|
+
}
|
|
60
|
+
for (const key of this.usersAccounts.keys()) {
|
|
61
|
+
if (!programAccountSet.has(key)) {
|
|
62
|
+
this.usersAccounts.delete(key);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
catch (e) {
|
|
67
|
+
console.error(e);
|
|
68
|
+
}
|
|
69
|
+
finally {
|
|
70
|
+
this.fetchPromiseResolver();
|
|
71
|
+
this.fetchPromise = undefined;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
tryUpdateUserAccount(key, buffer, slot) {
|
|
75
|
+
const slotAndUserAccount = this.usersAccounts.get(key);
|
|
76
|
+
if (!slotAndUserAccount || slotAndUserAccount.slot < slot) {
|
|
77
|
+
const userAccount = this.driftClient.program.account.user.coder.accounts.decode('User', buffer);
|
|
78
|
+
if (userAccount.hasOpenOrder) {
|
|
79
|
+
this.usersAccounts.set(key, { slot, userAccount });
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
this.usersAccounts.delete(key);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
async getDLOB(slot) {
|
|
87
|
+
const dlob = new DLOB_1.DLOB();
|
|
88
|
+
for (const [key, { userAccount }] of this.usersAccounts.entries()) {
|
|
89
|
+
const userAccountPubkey = new web3_js_1.PublicKey(key);
|
|
90
|
+
for (const order of userAccount.orders) {
|
|
91
|
+
dlob.insertOrder(order, userAccountPubkey, slot);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return dlob;
|
|
95
|
+
}
|
|
96
|
+
async unsubscribe() {
|
|
97
|
+
await this.subscription.unsubscribe();
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
exports.OrderSubscriber = OrderSubscriber;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import { OrderSubscriber } from './OrderSubscriber';
|
|
3
|
+
export declare class PollingSubscription {
|
|
4
|
+
private orderSubscriber;
|
|
5
|
+
private frequency;
|
|
6
|
+
intervalId?: NodeJS.Timer;
|
|
7
|
+
constructor({ orderSubscriber, frequency, }: {
|
|
8
|
+
orderSubscriber: OrderSubscriber;
|
|
9
|
+
frequency: number;
|
|
10
|
+
});
|
|
11
|
+
subscribe(): Promise<void>;
|
|
12
|
+
unsubscribe(): Promise<void>;
|
|
13
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PollingSubscription = void 0;
|
|
4
|
+
class PollingSubscription {
|
|
5
|
+
constructor({ orderSubscriber, frequency, }) {
|
|
6
|
+
this.orderSubscriber = orderSubscriber;
|
|
7
|
+
this.frequency = frequency;
|
|
8
|
+
}
|
|
9
|
+
async subscribe() {
|
|
10
|
+
if (this.intervalId) {
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
this.intervalId = setInterval(this.orderSubscriber.fetch.bind(this.orderSubscriber), this.frequency);
|
|
14
|
+
await this.orderSubscriber.fetch();
|
|
15
|
+
}
|
|
16
|
+
async unsubscribe() {
|
|
17
|
+
if (this.intervalId) {
|
|
18
|
+
clearInterval(this.intervalId);
|
|
19
|
+
this.intervalId = undefined;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
exports.PollingSubscription = PollingSubscription;
|