@drift-labs/sdk 2.52.0-beta.0 → 2.52.0-beta.2
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/VERSION +1 -1
- package/lib/accounts/basicUserAccountSubscriber.d.ts +4 -0
- package/lib/accounts/basicUserAccountSubscriber.js +4 -0
- package/lib/accounts/bulkAccountLoader.js +7 -1
- package/lib/accounts/oneShotUserAccountSubscriber.d.ts +17 -0
- package/lib/accounts/oneShotUserAccountSubscriber.js +48 -0
- package/lib/accounts/pollingInsuranceFundStakeAccountSubscriber.js +1 -0
- package/lib/accounts/webSocketAccountSubscriber.d.ts +1 -1
- package/lib/accounts/webSocketAccountSubscriber.js +7 -4
- package/lib/accounts/webSocketProgramAccountSubscriber.d.ts +1 -1
- package/lib/accounts/webSocketProgramAccountSubscriber.js +7 -4
- package/lib/adminClient.d.ts +1 -0
- package/lib/adminClient.js +9 -0
- package/lib/constants/numericConstants.d.ts +3 -0
- package/lib/constants/numericConstants.js +4 -1
- package/lib/dlob/orderBookLevels.d.ts +22 -0
- package/lib/dlob/orderBookLevels.js +115 -1
- package/lib/driftClient.d.ts +1 -0
- package/lib/driftClient.js +14 -5
- package/lib/events/webSocketLogProvider.js +3 -3
- package/lib/factory/bigNum.d.ts +1 -1
- package/lib/factory/bigNum.js +5 -2
- package/lib/idl/drift.json +13 -1
- package/lib/index.d.ts +1 -0
- package/lib/index.js +1 -0
- package/lib/math/amm.d.ts +5 -1
- package/lib/math/amm.js +62 -13
- package/lib/phoenix/phoenixSubscriber.js +2 -2
- package/lib/slot/SlotSubscriber.d.ts +11 -3
- package/lib/slot/SlotSubscriber.js +40 -4
- package/lib/types.d.ts +1 -1
- package/lib/userMap/userMap.d.ts +3 -0
- package/lib/userMap/userMap.js +10 -1
- package/lib/userStats.d.ts +1 -0
- package/lib/userStats.js +3 -0
- package/package.json +1 -1
- package/src/accounts/basicUserAccountSubscriber.ts +4 -0
- package/src/accounts/bulkAccountLoader.ts +10 -3
- package/src/accounts/oneShotUserAccountSubscriber.ts +64 -0
- package/src/accounts/pollingInsuranceFundStakeAccountSubscriber.ts +1 -0
- package/src/accounts/webSocketAccountSubscriber.ts +7 -4
- package/src/accounts/webSocketProgramAccountSubscriber.ts +7 -4
- package/src/adminClient.ts +13 -0
- package/src/constants/numericConstants.ts +4 -0
- package/src/dlob/orderBookLevels.ts +136 -0
- package/src/driftClient.ts +21 -10
- package/src/events/webSocketLogProvider.ts +3 -3
- package/src/factory/bigNum.ts +11 -2
- package/src/idl/drift.json +13 -1
- package/src/index.ts +1 -0
- package/src/math/amm.ts +159 -25
- package/src/phoenix/phoenixSubscriber.ts +2 -2
- package/src/slot/SlotSubscriber.ts +52 -5
- package/src/types.ts +1 -1
- package/src/userMap/userMap.ts +17 -3
- package/src/userStats.ts +8 -0
- package/tests/amm/test.ts +219 -11
- package/tests/bn/test.ts +27 -0
- package/tests/dlob/helpers.ts +1 -1
- package/tests/dlob/test.ts +372 -2
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
2.52.0-beta.
|
|
1
|
+
2.52.0-beta.2
|
|
@@ -4,6 +4,10 @@ import { PublicKey } from '@solana/web3.js';
|
|
|
4
4
|
import StrictEventEmitter from 'strict-event-emitter-types';
|
|
5
5
|
import { EventEmitter } from 'events';
|
|
6
6
|
import { UserAccount } from '../types';
|
|
7
|
+
/**
|
|
8
|
+
* Basic implementation of UserAccountSubscriber. It will only take in UserAccount
|
|
9
|
+
* data during initialization and will not fetch or subscribe to updates.
|
|
10
|
+
*/
|
|
7
11
|
export declare class BasicUserAccountSubscriber implements UserAccountSubscriber {
|
|
8
12
|
isSubscribed: boolean;
|
|
9
13
|
eventEmitter: StrictEventEmitter<EventEmitter, UserAccountEvents>;
|
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.BasicUserAccountSubscriber = void 0;
|
|
4
4
|
const events_1 = require("events");
|
|
5
|
+
/**
|
|
6
|
+
* Basic implementation of UserAccountSubscriber. It will only take in UserAccount
|
|
7
|
+
* data during initialization and will not fetch or subscribe to updates.
|
|
8
|
+
*/
|
|
5
9
|
class BasicUserAccountSubscriber {
|
|
6
10
|
constructor(userAccountPublicKey, data, slot) {
|
|
7
11
|
this.isSubscribed = true;
|
|
@@ -47,6 +47,7 @@ class BulkAccountLoader {
|
|
|
47
47
|
if (existingAccountToLoad) {
|
|
48
48
|
existingAccountToLoad.callbacks.delete(callbackId);
|
|
49
49
|
if (existingAccountToLoad.callbacks.size === 0) {
|
|
50
|
+
this.bufferAndSlotMap.delete(publicKey.toString());
|
|
50
51
|
this.accountsToLoad.delete(existingAccountToLoad.publicKey.toString());
|
|
51
52
|
}
|
|
52
53
|
}
|
|
@@ -107,7 +108,9 @@ class BulkAccountLoader {
|
|
|
107
108
|
const requests = new Array();
|
|
108
109
|
for (const accountsToLoadChunk of accountsToLoadChunks) {
|
|
109
110
|
const args = [
|
|
110
|
-
accountsToLoadChunk
|
|
111
|
+
accountsToLoadChunk
|
|
112
|
+
.filter((accountToLoad) => accountToLoad.callbacks.size > 0)
|
|
113
|
+
.map((accountToLoad) => {
|
|
111
114
|
return accountToLoad.publicKey.toBase58();
|
|
112
115
|
}),
|
|
113
116
|
{ commitment: this.commitment },
|
|
@@ -137,6 +140,9 @@ class BulkAccountLoader {
|
|
|
137
140
|
}
|
|
138
141
|
const accountsToLoad = accountsToLoadChunks[i];
|
|
139
142
|
accountsToLoad.forEach((accountToLoad, j) => {
|
|
143
|
+
if (accountToLoad.callbacks.size === 0) {
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
140
146
|
const key = accountToLoad.publicKey.toBase58();
|
|
141
147
|
const oldRPCResponse = this.bufferAndSlotMap.get(key);
|
|
142
148
|
if (oldRPCResponse && newSlot < oldRPCResponse.slot) {
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Commitment, PublicKey } from '@solana/web3.js';
|
|
2
|
+
import { UserAccount } from '../types';
|
|
3
|
+
import { BasicUserAccountSubscriber } from './basicUserAccountSubscriber';
|
|
4
|
+
import { Program } from '@coral-xyz/anchor';
|
|
5
|
+
/**
|
|
6
|
+
* Simple implementation of UserAccountSubscriber. It will fetch the UserAccount
|
|
7
|
+
* date on subscribe (or call to fetch) if no account data is provided on init.
|
|
8
|
+
* Expect to use only 1 RPC call unless you call fetch repeatedly.
|
|
9
|
+
*/
|
|
10
|
+
export declare class OneShotUserAccountSubscriber extends BasicUserAccountSubscriber {
|
|
11
|
+
program: Program;
|
|
12
|
+
commitment: Commitment;
|
|
13
|
+
constructor(program: Program, userAccountPublicKey: PublicKey, data?: UserAccount, slot?: number, commitment?: Commitment);
|
|
14
|
+
subscribe(userAccount?: UserAccount): Promise<boolean>;
|
|
15
|
+
fetchIfUnloaded(): Promise<void>;
|
|
16
|
+
fetch(): Promise<void>;
|
|
17
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.OneShotUserAccountSubscriber = void 0;
|
|
4
|
+
const basicUserAccountSubscriber_1 = require("./basicUserAccountSubscriber");
|
|
5
|
+
/**
|
|
6
|
+
* Simple implementation of UserAccountSubscriber. It will fetch the UserAccount
|
|
7
|
+
* date on subscribe (or call to fetch) if no account data is provided on init.
|
|
8
|
+
* Expect to use only 1 RPC call unless you call fetch repeatedly.
|
|
9
|
+
*/
|
|
10
|
+
class OneShotUserAccountSubscriber extends basicUserAccountSubscriber_1.BasicUserAccountSubscriber {
|
|
11
|
+
constructor(program, userAccountPublicKey, data, slot, commitment) {
|
|
12
|
+
super(userAccountPublicKey, data, slot);
|
|
13
|
+
this.program = program;
|
|
14
|
+
this.commitment = commitment !== null && commitment !== void 0 ? commitment : 'confirmed';
|
|
15
|
+
}
|
|
16
|
+
async subscribe(userAccount) {
|
|
17
|
+
if (userAccount) {
|
|
18
|
+
this.user = { data: userAccount, slot: this.user.slot };
|
|
19
|
+
return true;
|
|
20
|
+
}
|
|
21
|
+
await this.fetchIfUnloaded();
|
|
22
|
+
if (this.doesAccountExist()) {
|
|
23
|
+
this.eventEmitter.emit('update');
|
|
24
|
+
}
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
async fetchIfUnloaded() {
|
|
28
|
+
if (this.user.data === undefined) {
|
|
29
|
+
await this.fetch();
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
async fetch() {
|
|
33
|
+
var _a, _b;
|
|
34
|
+
try {
|
|
35
|
+
const dataAndContext = await this.program.account.user.fetchAndContext(this.userAccountPublicKey, this.commitment);
|
|
36
|
+
if (dataAndContext.context.slot > ((_b = (_a = this.user) === null || _a === void 0 ? void 0 : _a.slot) !== null && _b !== void 0 ? _b : 0)) {
|
|
37
|
+
this.user = {
|
|
38
|
+
data: dataAndContext.data,
|
|
39
|
+
slot: dataAndContext.context.slot,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
catch (e) {
|
|
44
|
+
console.error(`OneShotUserAccountSubscriber.fetch() UserAccount does not exist: ${e.message}`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
exports.OneShotUserAccountSubscriber = OneShotUserAccountSubscriber;
|
|
@@ -24,5 +24,5 @@ export declare class WebSocketAccountSubscriber<T> implements AccountSubscriber<
|
|
|
24
24
|
fetch(): Promise<void>;
|
|
25
25
|
handleRpcResponse(context: Context, accountInfo?: AccountInfo<Buffer>): void;
|
|
26
26
|
decodeBuffer(buffer: Buffer): T;
|
|
27
|
-
unsubscribe(): Promise<void>;
|
|
27
|
+
unsubscribe(onResub?: boolean): Promise<void>;
|
|
28
28
|
}
|
|
@@ -15,7 +15,7 @@ class WebSocketAccountSubscriber {
|
|
|
15
15
|
commitment !== null && commitment !== void 0 ? commitment : this.program.provider.opts.commitment;
|
|
16
16
|
}
|
|
17
17
|
async subscribe(onChange) {
|
|
18
|
-
if (this.listenerId || this.isUnsubscribing) {
|
|
18
|
+
if (this.listenerId != null || this.isUnsubscribing) {
|
|
19
19
|
return;
|
|
20
20
|
}
|
|
21
21
|
this.onChange = onChange;
|
|
@@ -58,7 +58,7 @@ class WebSocketAccountSubscriber {
|
|
|
58
58
|
}
|
|
59
59
|
if (this.receivingData) {
|
|
60
60
|
console.log(`No ws data from ${this.accountName} in ${this.resubTimeoutMs}ms, resubscribing`);
|
|
61
|
-
await this.unsubscribe();
|
|
61
|
+
await this.unsubscribe(true);
|
|
62
62
|
this.receivingData = false;
|
|
63
63
|
await this.subscribe(this.onChange);
|
|
64
64
|
}
|
|
@@ -114,11 +114,14 @@ class WebSocketAccountSubscriber {
|
|
|
114
114
|
return this.program.account[this.accountName].coder.accounts.decode((0, utils_1.capitalize)(this.accountName), buffer);
|
|
115
115
|
}
|
|
116
116
|
}
|
|
117
|
-
unsubscribe() {
|
|
117
|
+
unsubscribe(onResub = false) {
|
|
118
|
+
if (!onResub) {
|
|
119
|
+
this.resubTimeoutMs = undefined;
|
|
120
|
+
}
|
|
118
121
|
this.isUnsubscribing = true;
|
|
119
122
|
clearTimeout(this.timeoutId);
|
|
120
123
|
this.timeoutId = undefined;
|
|
121
|
-
if (this.listenerId) {
|
|
124
|
+
if (this.listenerId != null) {
|
|
122
125
|
const promise = this.program.provider.connection
|
|
123
126
|
.removeAccountChangeListener(this.listenerId)
|
|
124
127
|
.then(() => {
|
|
@@ -29,5 +29,5 @@ export declare class WebSocketProgramAccountSubscriber<T> implements ProgramAcco
|
|
|
29
29
|
subscribe(onChange: (accountId: PublicKey, data: T, context: Context) => void): Promise<void>;
|
|
30
30
|
private setTimeout;
|
|
31
31
|
handleRpcResponse(context: Context, keyedAccountInfo: KeyedAccountInfo): void;
|
|
32
|
-
unsubscribe(): Promise<void>;
|
|
32
|
+
unsubscribe(onResub?: boolean): Promise<void>;
|
|
33
33
|
}
|
|
@@ -17,7 +17,7 @@ class WebSocketProgramAccountSubscriber {
|
|
|
17
17
|
}
|
|
18
18
|
async subscribe(onChange) {
|
|
19
19
|
var _a;
|
|
20
|
-
if (this.listenerId || this.isUnsubscribing) {
|
|
20
|
+
if (this.listenerId != null || this.isUnsubscribing) {
|
|
21
21
|
return;
|
|
22
22
|
}
|
|
23
23
|
this.onChange = onChange;
|
|
@@ -47,7 +47,7 @@ class WebSocketProgramAccountSubscriber {
|
|
|
47
47
|
}
|
|
48
48
|
if (this.receivingData) {
|
|
49
49
|
console.log(`No ws data from ${this.subscriptionName} in ${this.resubTimeoutMs}ms, resubscribing`);
|
|
50
|
-
await this.unsubscribe();
|
|
50
|
+
await this.unsubscribe(true);
|
|
51
51
|
this.receivingData = false;
|
|
52
52
|
await this.subscribe(this.onChange);
|
|
53
53
|
}
|
|
@@ -93,11 +93,14 @@ class WebSocketProgramAccountSubscriber {
|
|
|
93
93
|
this.onChange(keyedAccountInfo.accountId, account, context);
|
|
94
94
|
}
|
|
95
95
|
}
|
|
96
|
-
unsubscribe() {
|
|
96
|
+
unsubscribe(onResub = false) {
|
|
97
|
+
if (!onResub) {
|
|
98
|
+
this.resubTimeoutMs = undefined;
|
|
99
|
+
}
|
|
97
100
|
this.isUnsubscribing = true;
|
|
98
101
|
clearTimeout(this.timeoutId);
|
|
99
102
|
this.timeoutId = undefined;
|
|
100
|
-
if (this.listenerId) {
|
|
103
|
+
if (this.listenerId != null) {
|
|
101
104
|
const promise = this.program.provider.connection
|
|
102
105
|
.removeAccountChangeListener(this.listenerId)
|
|
103
106
|
.then(() => {
|
package/lib/adminClient.d.ts
CHANGED
|
@@ -54,6 +54,7 @@ export declare class AdminClient extends DriftClient {
|
|
|
54
54
|
updateSpotMarketOracle(spotMarketIndex: number, oracle: PublicKey, oracleSource: OracleSource): Promise<TransactionSignature>;
|
|
55
55
|
updateSpotMarketOrdersEnabled(spotMarketIndex: number, ordersEnabled: boolean): Promise<TransactionSignature>;
|
|
56
56
|
updateSerumFulfillmentConfigStatus(serumFulfillmentConfig: PublicKey, status: SpotFulfillmentConfigStatus): Promise<TransactionSignature>;
|
|
57
|
+
updatePhoenixFulfillmentConfigStatus(phoenixFulfillmentConfig: PublicKey, status: SpotFulfillmentConfigStatus): Promise<TransactionSignature>;
|
|
57
58
|
updateSpotMarketExpiry(spotMarketIndex: number, expiryTs: BN): Promise<TransactionSignature>;
|
|
58
59
|
updateWhitelistMint(whitelistMint?: PublicKey): Promise<TransactionSignature>;
|
|
59
60
|
updateDiscountMint(discountMint: PublicKey): Promise<TransactionSignature>;
|
package/lib/adminClient.js
CHANGED
|
@@ -626,6 +626,15 @@ class AdminClient extends driftClient_1.DriftClient {
|
|
|
626
626
|
},
|
|
627
627
|
});
|
|
628
628
|
}
|
|
629
|
+
async updatePhoenixFulfillmentConfigStatus(phoenixFulfillmentConfig, status) {
|
|
630
|
+
return await this.program.rpc.phoenixFulfillmentConfigStatus(status, {
|
|
631
|
+
accounts: {
|
|
632
|
+
admin: this.wallet.publicKey,
|
|
633
|
+
state: await this.getStatePublicKey(),
|
|
634
|
+
phoenixFulfillmentConfig,
|
|
635
|
+
},
|
|
636
|
+
});
|
|
637
|
+
}
|
|
629
638
|
async updateSpotMarketExpiry(spotMarketIndex, expiryTs) {
|
|
630
639
|
return await this.program.rpc.updateSpotMarketExpiry(expiryTs, {
|
|
631
640
|
accounts: {
|
|
@@ -61,3 +61,6 @@ export declare const LAMPORTS_PRECISION: BN;
|
|
|
61
61
|
export declare const LAMPORTS_EXP: BN;
|
|
62
62
|
export declare const OPEN_ORDER_MARGIN_REQUIREMENT: BN;
|
|
63
63
|
export declare const DEFAULT_REVENUE_SINCE_LAST_FUNDING_SPREAD_RETREAT: BN;
|
|
64
|
+
export declare const ACCOUNT_AGE_DELETION_CUTOFF_SECONDS: number;
|
|
65
|
+
export declare const IDLE_TIME_SLOTS = 9000;
|
|
66
|
+
export declare const SLOT_TIME_ESTIMATE_MS = 400;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.MARGIN_PRECISION = exports.AMM_TIMES_PEG_TO_QUOTE_PRECISION_RATIO = exports.PRICE_TO_QUOTE_PRECISION = exports.PRICE_DIV_PEG = exports.AMM_TO_QUOTE_PRECISION_RATIO = exports.BASE_PRECISION_EXP = exports.BASE_PRECISION = exports.AMM_RESERVE_PRECISION = exports.PEG_PRECISION = exports.FUNDING_RATE_BUFFER_PRECISION = exports.FUNDING_RATE_PRECISION = exports.PRICE_PRECISION = exports.QUOTE_PRECISION = exports.LIQUIDATION_FEE_PRECISION = exports.SPOT_MARKET_IMF_PRECISION = exports.SPOT_MARKET_IMF_PRECISION_EXP = exports.SPOT_MARKET_BALANCE_PRECISION = exports.SPOT_MARKET_BALANCE_PRECISION_EXP = exports.SPOT_MARKET_WEIGHT_PRECISION = exports.SPOT_MARKET_UTILIZATION_PRECISION = exports.SPOT_MARKET_UTILIZATION_PRECISION_EXP = exports.SPOT_MARKET_CUMULATIVE_INTEREST_PRECISION = exports.SPOT_MARKET_CUMULATIVE_INTEREST_PRECISION_EXP = exports.SPOT_MARKET_RATE_PRECISION = exports.SPOT_MARKET_RATE_PRECISION_EXP = exports.AMM_RESERVE_PRECISION_EXP = exports.PEG_PRECISION_EXP = exports.FUNDING_RATE_PRECISION_EXP = exports.PRICE_PRECISION_EXP = exports.FUNDING_RATE_BUFFER_PRECISION_EXP = exports.QUOTE_PRECISION_EXP = exports.CONCENTRATION_PRECISION = exports.PERCENTAGE_PRECISION = exports.PERCENTAGE_PRECISION_EXP = exports.MAX_LEVERAGE_ORDER_SIZE = exports.MAX_LEVERAGE = exports.TEN_MILLION = exports.BN_MAX = exports.TEN_THOUSAND = exports.TEN = exports.NINE = exports.EIGHT = exports.SEVEN = exports.SIX = exports.FIVE = exports.FOUR = exports.THREE = exports.TWO = exports.ONE = exports.ZERO = void 0;
|
|
4
|
-
exports.DEFAULT_REVENUE_SINCE_LAST_FUNDING_SPREAD_RETREAT = exports.OPEN_ORDER_MARGIN_REQUIREMENT = exports.LAMPORTS_EXP = exports.LAMPORTS_PRECISION = exports.QUOTE_SPOT_MARKET_INDEX = exports.ONE_YEAR = exports.ONE_HOUR = exports.FIVE_MINUTE = exports.FUNDING_RATE_OFFSET_DENOMINATOR = exports.LIQUIDATION_PCT_PRECISION = exports.BID_ASK_SPREAD_PRECISION = void 0;
|
|
4
|
+
exports.SLOT_TIME_ESTIMATE_MS = exports.IDLE_TIME_SLOTS = exports.ACCOUNT_AGE_DELETION_CUTOFF_SECONDS = exports.DEFAULT_REVENUE_SINCE_LAST_FUNDING_SPREAD_RETREAT = exports.OPEN_ORDER_MARGIN_REQUIREMENT = exports.LAMPORTS_EXP = exports.LAMPORTS_PRECISION = exports.QUOTE_SPOT_MARKET_INDEX = exports.ONE_YEAR = exports.ONE_HOUR = exports.FIVE_MINUTE = exports.FUNDING_RATE_OFFSET_DENOMINATOR = exports.LIQUIDATION_PCT_PRECISION = exports.BID_ASK_SPREAD_PRECISION = void 0;
|
|
5
5
|
const web3_js_1 = require("@solana/web3.js");
|
|
6
6
|
const __1 = require("../");
|
|
7
7
|
exports.ZERO = new __1.BN(0);
|
|
@@ -65,3 +65,6 @@ exports.LAMPORTS_PRECISION = new __1.BN(web3_js_1.LAMPORTS_PER_SOL);
|
|
|
65
65
|
exports.LAMPORTS_EXP = new __1.BN(Math.log10(web3_js_1.LAMPORTS_PER_SOL));
|
|
66
66
|
exports.OPEN_ORDER_MARGIN_REQUIREMENT = exports.QUOTE_PRECISION.div(new __1.BN(100));
|
|
67
67
|
exports.DEFAULT_REVENUE_SINCE_LAST_FUNDING_SPREAD_RETREAT = new __1.BN(-25).mul(exports.QUOTE_PRECISION);
|
|
68
|
+
exports.ACCOUNT_AGE_DELETION_CUTOFF_SECONDS = 60 * 60 * 24 * 13; // 13 days
|
|
69
|
+
exports.IDLE_TIME_SLOTS = 9000;
|
|
70
|
+
exports.SLOT_TIME_ESTIMATE_MS = 400;
|
|
@@ -47,4 +47,26 @@ export declare function getVammL2Generator({ marketAccount, oraclePriceData, num
|
|
|
47
47
|
topOfBookQuoteAmounts?: BN[];
|
|
48
48
|
}): L2OrderBookGenerator;
|
|
49
49
|
export declare function groupL2(l2: L2OrderBook, grouping: BN, depth: number): L2OrderBook;
|
|
50
|
+
/**
|
|
51
|
+
* The purpose of this function is uncross the L2 orderbook by modifying the bid/ask price at the top of the book
|
|
52
|
+
* This will make the liquidity look worse but more intuitive (users familiar with clob get confused w temporarily
|
|
53
|
+
* crossing book)
|
|
54
|
+
*
|
|
55
|
+
* Things to note about how it works:
|
|
56
|
+
* - it will not uncross the user's liquidity
|
|
57
|
+
* - it does the uncrossing by "shifting" the crossing liquidity to the nearest uncrossed levels. Thus the output liquidity maintains the same total size.
|
|
58
|
+
*
|
|
59
|
+
* @param bids
|
|
60
|
+
* @param asks
|
|
61
|
+
* @param oraclePrice
|
|
62
|
+
* @param oracleTwap5Min
|
|
63
|
+
* @param markTwap5Min
|
|
64
|
+
* @param grouping
|
|
65
|
+
* @param userBids
|
|
66
|
+
* @param userAsks
|
|
67
|
+
*/
|
|
68
|
+
export declare function uncrossL2(bids: L2Level[], asks: L2Level[], oraclePrice: BN, oracleTwap5Min: BN, markTwap5Min: BN, grouping: BN, userBids: Set<string>, userAsks: Set<string>): {
|
|
69
|
+
bids: L2Level[];
|
|
70
|
+
asks: L2Level[];
|
|
71
|
+
};
|
|
50
72
|
export {};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.groupL2 = exports.getVammL2Generator = exports.createL2Levels = exports.mergeL2LevelGenerators = exports.getL2GeneratorFromDLOBNodes = exports.DEFAULT_TOP_OF_BOOK_QUOTE_AMOUNTS = void 0;
|
|
3
|
+
exports.uncrossL2 = exports.groupL2 = exports.getVammL2Generator = exports.createL2Levels = exports.mergeL2LevelGenerators = exports.getL2GeneratorFromDLOBNodes = exports.DEFAULT_TOP_OF_BOOK_QUOTE_AMOUNTS = void 0;
|
|
4
4
|
const __1 = require("..");
|
|
5
5
|
const assert_1 = require("../assert/assert");
|
|
6
6
|
exports.DEFAULT_TOP_OF_BOOK_QUOTE_AMOUNTS = [
|
|
@@ -245,3 +245,117 @@ function groupL2Levels(levels, grouping, direction, depth) {
|
|
|
245
245
|
}
|
|
246
246
|
return groupedLevels;
|
|
247
247
|
}
|
|
248
|
+
/**
|
|
249
|
+
* The purpose of this function is uncross the L2 orderbook by modifying the bid/ask price at the top of the book
|
|
250
|
+
* This will make the liquidity look worse but more intuitive (users familiar with clob get confused w temporarily
|
|
251
|
+
* crossing book)
|
|
252
|
+
*
|
|
253
|
+
* Things to note about how it works:
|
|
254
|
+
* - it will not uncross the user's liquidity
|
|
255
|
+
* - it does the uncrossing by "shifting" the crossing liquidity to the nearest uncrossed levels. Thus the output liquidity maintains the same total size.
|
|
256
|
+
*
|
|
257
|
+
* @param bids
|
|
258
|
+
* @param asks
|
|
259
|
+
* @param oraclePrice
|
|
260
|
+
* @param oracleTwap5Min
|
|
261
|
+
* @param markTwap5Min
|
|
262
|
+
* @param grouping
|
|
263
|
+
* @param userBids
|
|
264
|
+
* @param userAsks
|
|
265
|
+
*/
|
|
266
|
+
function uncrossL2(bids, asks, oraclePrice, oracleTwap5Min, markTwap5Min, grouping, userBids, userAsks) {
|
|
267
|
+
// If there are no bids or asks, there is nothing to center
|
|
268
|
+
if (bids.length === 0 || asks.length === 0) {
|
|
269
|
+
return { bids, asks };
|
|
270
|
+
}
|
|
271
|
+
// If the top of the book is already centered, there is nothing to do
|
|
272
|
+
if (bids[0].price.lt(asks[0].price)) {
|
|
273
|
+
return { bids, asks };
|
|
274
|
+
}
|
|
275
|
+
const newBids = [];
|
|
276
|
+
const newAsks = [];
|
|
277
|
+
const updateLevels = (newPrice, oldLevel, levels) => {
|
|
278
|
+
if (levels.length > 0 && levels[levels.length - 1].price.eq(newPrice)) {
|
|
279
|
+
levels[levels.length - 1].size = levels[levels.length - 1].size.add(oldLevel.size);
|
|
280
|
+
for (const [source, size] of Object.entries(oldLevel.sources)) {
|
|
281
|
+
if (levels[levels.length - 1].sources[source]) {
|
|
282
|
+
levels[levels.length - 1].sources = {
|
|
283
|
+
...levels[levels.length - 1].sources,
|
|
284
|
+
[source]: levels[levels.length - 1].sources[source].add(size),
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
else {
|
|
288
|
+
levels[levels.length - 1].sources[source] = size;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
else {
|
|
293
|
+
levels.push({
|
|
294
|
+
price: newPrice,
|
|
295
|
+
size: oldLevel.size,
|
|
296
|
+
sources: oldLevel.sources,
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
};
|
|
300
|
+
// This is the best estimate of the premium in the market vs oracle to filter crossing around
|
|
301
|
+
const referencePrice = oraclePrice.add(markTwap5Min.sub(oracleTwap5Min));
|
|
302
|
+
let bidIndex = 0;
|
|
303
|
+
let askIndex = 0;
|
|
304
|
+
while (bidIndex < bids.length || askIndex < asks.length) {
|
|
305
|
+
const nextBid = bids[bidIndex];
|
|
306
|
+
const nextAsk = asks[askIndex];
|
|
307
|
+
if (!nextBid) {
|
|
308
|
+
newAsks.push(nextAsk);
|
|
309
|
+
askIndex++;
|
|
310
|
+
continue;
|
|
311
|
+
}
|
|
312
|
+
if (!nextAsk) {
|
|
313
|
+
newBids.push(nextBid);
|
|
314
|
+
bidIndex++;
|
|
315
|
+
continue;
|
|
316
|
+
}
|
|
317
|
+
if (nextBid.price.gt(nextAsk.price)) {
|
|
318
|
+
if (userBids.has(nextBid.price.toString())) {
|
|
319
|
+
newBids.push(nextBid);
|
|
320
|
+
bidIndex++;
|
|
321
|
+
continue;
|
|
322
|
+
}
|
|
323
|
+
if (userAsks.has(nextAsk.price.toString())) {
|
|
324
|
+
newAsks.push(nextAsk);
|
|
325
|
+
askIndex++;
|
|
326
|
+
continue;
|
|
327
|
+
}
|
|
328
|
+
if (nextBid.price.gt(referencePrice) &&
|
|
329
|
+
nextAsk.price.gt(referencePrice)) {
|
|
330
|
+
const newBidPrice = nextAsk.price.sub(grouping);
|
|
331
|
+
updateLevels(newBidPrice, nextBid, newBids);
|
|
332
|
+
bidIndex++;
|
|
333
|
+
}
|
|
334
|
+
else if (nextAsk.price.lt(referencePrice) &&
|
|
335
|
+
nextBid.price.lt(referencePrice)) {
|
|
336
|
+
const newAskPrice = nextBid.price.add(grouping);
|
|
337
|
+
updateLevels(newAskPrice, nextAsk, newAsks);
|
|
338
|
+
askIndex++;
|
|
339
|
+
}
|
|
340
|
+
else {
|
|
341
|
+
const newBidPrice = referencePrice.sub(grouping);
|
|
342
|
+
const newAskPrice = referencePrice.add(grouping);
|
|
343
|
+
updateLevels(newBidPrice, nextBid, newBids);
|
|
344
|
+
updateLevels(newAskPrice, nextAsk, newAsks);
|
|
345
|
+
bidIndex++;
|
|
346
|
+
askIndex++;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
else {
|
|
350
|
+
newAsks.push(nextAsk);
|
|
351
|
+
askIndex++;
|
|
352
|
+
newBids.push(nextBid);
|
|
353
|
+
bidIndex++;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
return {
|
|
357
|
+
bids: newBids,
|
|
358
|
+
asks: newAsks,
|
|
359
|
+
};
|
|
360
|
+
}
|
|
361
|
+
exports.uncrossL2 = uncrossL2;
|
package/lib/driftClient.d.ts
CHANGED
|
@@ -133,6 +133,7 @@ export declare class DriftClient {
|
|
|
133
133
|
getUserAccountsForAuthority(authority: PublicKey): Promise<UserAccount[]>;
|
|
134
134
|
getReferredUserStatsAccountsByReferrer(referrer: PublicKey): Promise<UserStatsAccount[]>;
|
|
135
135
|
getReferrerNameAccountsForAuthority(authority: PublicKey): Promise<ReferrerNameAccount[]>;
|
|
136
|
+
getUserDeletionIx(userAccountPublicKey: PublicKey): Promise<anchor.web3.TransactionInstruction>;
|
|
136
137
|
deleteUser(subAccountId?: number, txParams?: TxParams): Promise<TransactionSignature>;
|
|
137
138
|
getUser(subAccountId?: number, authority?: PublicKey): User;
|
|
138
139
|
hasUser(subAccountId?: number, authority?: PublicKey): boolean;
|
package/lib/driftClient.js
CHANGED
|
@@ -665,9 +665,7 @@ class DriftClient {
|
|
|
665
665
|
]);
|
|
666
666
|
return programAccounts.map((programAccount) => programAccount.account);
|
|
667
667
|
}
|
|
668
|
-
async
|
|
669
|
-
var _a;
|
|
670
|
-
const userAccountPublicKey = (0, pda_1.getUserAccountPublicKeySync)(this.program.programId, this.wallet.publicKey, subAccountId);
|
|
668
|
+
async getUserDeletionIx(userAccountPublicKey) {
|
|
671
669
|
const ix = await this.program.instruction.deleteUser({
|
|
672
670
|
accounts: {
|
|
673
671
|
user: userAccountPublicKey,
|
|
@@ -676,6 +674,12 @@ class DriftClient {
|
|
|
676
674
|
state: await this.getStatePublicKey(),
|
|
677
675
|
},
|
|
678
676
|
});
|
|
677
|
+
return ix;
|
|
678
|
+
}
|
|
679
|
+
async deleteUser(subAccountId = 0, txParams) {
|
|
680
|
+
var _a;
|
|
681
|
+
const userAccountPublicKey = (0, pda_1.getUserAccountPublicKeySync)(this.program.programId, this.wallet.publicKey, subAccountId);
|
|
682
|
+
const ix = await this.getUserDeletionIx(userAccountPublicKey);
|
|
679
683
|
const { txSig } = await this.sendTransaction(await this.buildTransaction(ix, txParams), [], this.opts);
|
|
680
684
|
const userMapKey = this.getUserMapKey(subAccountId, this.wallet.publicKey);
|
|
681
685
|
await ((_a = this.users.get(userMapKey)) === null || _a === void 0 ? void 0 : _a.unsubscribe());
|
|
@@ -2212,8 +2216,13 @@ class DriftClient {
|
|
|
2212
2216
|
async getSwapIx({ outMarketIndex, inMarketIndex, amountIn, inTokenAccount, outTokenAccount, limitPrice, reduceOnly, userAccountPublicKey, }) {
|
|
2213
2217
|
const userAccountPublicKeyToUse = userAccountPublicKey || (await this.getUserAccountPublicKey());
|
|
2214
2218
|
const userAccounts = [];
|
|
2215
|
-
|
|
2216
|
-
|
|
2219
|
+
try {
|
|
2220
|
+
if (this.hasUser() && this.getUser().getUserAccountAndSlot()) {
|
|
2221
|
+
userAccounts.push(this.getUser().getUserAccountAndSlot().data);
|
|
2222
|
+
}
|
|
2223
|
+
}
|
|
2224
|
+
catch (err) {
|
|
2225
|
+
// ignore
|
|
2217
2226
|
}
|
|
2218
2227
|
const remainingAccounts = this.getRemainingAccounts({
|
|
2219
2228
|
userAccounts,
|
|
@@ -17,7 +17,7 @@ class WebSocketLogProvider {
|
|
|
17
17
|
}
|
|
18
18
|
}
|
|
19
19
|
async subscribe(callback) {
|
|
20
|
-
if (this.subscriptionId) {
|
|
20
|
+
if (this.subscriptionId != null) {
|
|
21
21
|
return true;
|
|
22
22
|
}
|
|
23
23
|
this.callback = callback;
|
|
@@ -48,14 +48,14 @@ class WebSocketLogProvider {
|
|
|
48
48
|
}, this.commitment);
|
|
49
49
|
}
|
|
50
50
|
isSubscribed() {
|
|
51
|
-
return this.subscriptionId
|
|
51
|
+
return this.subscriptionId != null;
|
|
52
52
|
}
|
|
53
53
|
async unsubscribe(external = false) {
|
|
54
54
|
this.isUnsubscribing = true;
|
|
55
55
|
this.externalUnsubscribe = external;
|
|
56
56
|
clearTimeout(this.timeoutId);
|
|
57
57
|
this.timeoutId = undefined;
|
|
58
|
-
if (this.subscriptionId
|
|
58
|
+
if (this.subscriptionId != null) {
|
|
59
59
|
try {
|
|
60
60
|
await this.connection.removeOnLogsListener(this.subscriptionId);
|
|
61
61
|
this.subscriptionId = undefined;
|
package/lib/factory/bigNum.d.ts
CHANGED
|
@@ -86,7 +86,7 @@ export declare class BigNum {
|
|
|
86
86
|
* @returns
|
|
87
87
|
*/
|
|
88
88
|
toNotional(useTradePrecision?: boolean, precisionOverride?: number): string;
|
|
89
|
-
toMillified(precision?: number, rounded?: boolean): string;
|
|
89
|
+
toMillified(precision?: number, rounded?: boolean, type?: 'financial' | 'scientific'): string;
|
|
90
90
|
toJSON(): {
|
|
91
91
|
val: string;
|
|
92
92
|
precision: string;
|
package/lib/factory/bigNum.js
CHANGED
|
@@ -330,7 +330,7 @@ class BigNum {
|
|
|
330
330
|
}
|
|
331
331
|
return `${prefix}${val.replace('-', '')}`;
|
|
332
332
|
}
|
|
333
|
-
toMillified(precision = 3, rounded = false) {
|
|
333
|
+
toMillified(precision = 3, rounded = false, type = 'financial') {
|
|
334
334
|
if (rounded) {
|
|
335
335
|
return this.toRounded(precision).toMillified(precision);
|
|
336
336
|
}
|
|
@@ -346,7 +346,10 @@ class BigNum {
|
|
|
346
346
|
if (leftSide.length <= 3) {
|
|
347
347
|
return this.shift(new anchor_1.BN(precision)).toPrecision(precision, true);
|
|
348
348
|
}
|
|
349
|
-
const unitTicks =
|
|
349
|
+
const unitTicks = type === 'financial'
|
|
350
|
+
? ['', 'K', 'M', 'B', 'T', 'Q']
|
|
351
|
+
: ['', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y'];
|
|
352
|
+
// TODO -- handle nubers which are larger than the max unit tick
|
|
350
353
|
const unitNumber = Math.floor((leftSide.length - 1) / 3);
|
|
351
354
|
const unit = unitTicks[unitNumber];
|
|
352
355
|
let leadDigits = leftSide.slice(0, precision);
|
package/lib/idl/drift.json
CHANGED
|
@@ -7343,12 +7343,24 @@
|
|
|
7343
7343
|
"name": "totalFeeEarnedPerLp",
|
|
7344
7344
|
"type": "u64"
|
|
7345
7345
|
},
|
|
7346
|
+
{
|
|
7347
|
+
"name": "netUnsettledFundingPnl",
|
|
7348
|
+
"type": "i64"
|
|
7349
|
+
},
|
|
7350
|
+
{
|
|
7351
|
+
"name": "quoteAssetAmountWithUnsettledLp",
|
|
7352
|
+
"type": "i64"
|
|
7353
|
+
},
|
|
7354
|
+
{
|
|
7355
|
+
"name": "referencePriceOffset",
|
|
7356
|
+
"type": "i32"
|
|
7357
|
+
},
|
|
7346
7358
|
{
|
|
7347
7359
|
"name": "padding",
|
|
7348
7360
|
"type": {
|
|
7349
7361
|
"array": [
|
|
7350
7362
|
"u8",
|
|
7351
|
-
|
|
7363
|
+
12
|
|
7352
7364
|
]
|
|
7353
7365
|
}
|
|
7354
7366
|
}
|
package/lib/index.d.ts
CHANGED
|
@@ -20,6 +20,7 @@ export * from './accounts/pollingUserAccountSubscriber';
|
|
|
20
20
|
export * from './accounts/pollingUserStatsAccountSubscriber';
|
|
21
21
|
export * from './accounts/pollingInsuranceFundStakeAccountSubscriber';
|
|
22
22
|
export * from './accounts/basicUserAccountSubscriber';
|
|
23
|
+
export * from './accounts/oneShotUserAccountSubscriber';
|
|
23
24
|
export * from './accounts/types';
|
|
24
25
|
export * from './addresses/pda';
|
|
25
26
|
export * from './adminClient';
|
package/lib/index.js
CHANGED
|
@@ -43,6 +43,7 @@ __exportStar(require("./accounts/pollingUserAccountSubscriber"), exports);
|
|
|
43
43
|
__exportStar(require("./accounts/pollingUserStatsAccountSubscriber"), exports);
|
|
44
44
|
__exportStar(require("./accounts/pollingInsuranceFundStakeAccountSubscriber"), exports);
|
|
45
45
|
__exportStar(require("./accounts/basicUserAccountSubscriber"), exports);
|
|
46
|
+
__exportStar(require("./accounts/oneShotUserAccountSubscriber"), exports);
|
|
46
47
|
__exportStar(require("./accounts/types"), exports);
|
|
47
48
|
__exportStar(require("./addresses/pda"), exports);
|
|
48
49
|
__exportStar(require("./adminClient"), exports);
|
package/lib/math/amm.d.ts
CHANGED
|
@@ -34,7 +34,9 @@ export type AssetType = 'quote' | 'base';
|
|
|
34
34
|
*/
|
|
35
35
|
export declare function calculateAmmReservesAfterSwap(amm: Pick<AMM, 'pegMultiplier' | 'quoteAssetReserve' | 'sqrtK' | 'baseAssetReserve'>, inputAssetType: AssetType, swapAmount: BN, swapDirection: SwapDirection): [BN, BN];
|
|
36
36
|
export declare function calculateMarketOpenBidAsk(baseAssetReserve: BN, minBaseAssetReserve: BN, maxBaseAssetReserve: BN, stepSize?: BN): [BN, BN];
|
|
37
|
+
export declare function calculateInventoryLiquidityRatio(baseAssetAmountWithAmm: BN, baseAssetReserve: BN, minBaseAssetReserve: BN, maxBaseAssetReserve: BN): BN;
|
|
37
38
|
export declare function calculateInventoryScale(baseAssetAmountWithAmm: BN, baseAssetReserve: BN, minBaseAssetReserve: BN, maxBaseAssetReserve: BN, directionalSpread: number, maxSpread: number): number;
|
|
39
|
+
export declare function calculateReferencePriceOffset(reservePrice: BN, last24hAvgFundingRate: BN, liquidityFraction: BN, oracleTwapFast: BN, markTwapFast: BN, oracleTwapSlow: BN, markTwapSlow: BN, maxOffsetPct: number): BN;
|
|
38
40
|
export declare function calculateEffectiveLeverage(baseSpread: number, quoteAssetReserve: BN, terminalQuoteAssetReserve: BN, pegMultiplier: BN, netBaseAssetAmount: BN, reservePrice: BN, totalFeeMinusDistributions: BN): number;
|
|
39
41
|
export declare function calculateMaxSpread(marginRatioInitial: number): number;
|
|
40
42
|
export declare function calculateVolSpreadBN(lastOracleConfPct: BN, reservePrice: BN, markStd: BN, oracleStd: BN, longIntensity: BN, shortIntensity: BN, volume24H: BN): [BN, BN];
|
|
@@ -55,11 +57,13 @@ export declare function calculateSpreadBN(baseSpread: number, lastOracleReserveP
|
|
|
55
57
|
halfRevenueRetreatAmount: number;
|
|
56
58
|
longSpreadwRevRetreat: number;
|
|
57
59
|
shortSpreadwRevRetreat: number;
|
|
60
|
+
longSpreadwOffsetShrink: number;
|
|
61
|
+
shortSpreadwOffsetShrink: number;
|
|
58
62
|
totalSpread: number;
|
|
59
63
|
longSpread: number;
|
|
60
64
|
shortSpread: number;
|
|
61
65
|
};
|
|
62
|
-
export declare function calculateSpread(amm: AMM, oraclePriceData: OraclePriceData, now?: BN): [number, number];
|
|
66
|
+
export declare function calculateSpread(amm: AMM, oraclePriceData: OraclePriceData, now?: BN, reservePrice?: BN): [number, number];
|
|
63
67
|
export declare function calculateSpreadReserves(amm: AMM, oraclePriceData: OraclePriceData, now?: BN): {
|
|
64
68
|
baseAssetReserve: any;
|
|
65
69
|
quoteAssetReserve: any;
|