@drift-labs/sdk 2.26.0-beta.3 → 2.27.0-beta.0
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/constants/perpMarkets.js +20 -0
- package/lib/dlob/orderBookLevels.d.ts +1 -1
- package/lib/driftClient.d.ts +2 -3
- package/lib/driftClient.js +27 -26
- package/lib/driftClientConfig.d.ts +1 -1
- package/lib/idl/drift.json +1 -1
- package/lib/phoenix/phoenixSubscriber.d.ts +5 -1
- package/lib/phoenix/phoenixSubscriber.js +23 -0
- package/lib/wallet.d.ts +1 -0
- package/lib/wallet.js +24 -1
- package/package.json +1 -1
- package/src/constants/perpMarkets.ts +20 -0
- package/src/dlob/orderBookLevels.ts +1 -1
- package/src/driftClient.ts +49 -34
- package/src/driftClientConfig.ts +1 -1
- package/src/idl/drift.json +1 -1
- package/src/phoenix/phoenixSubscriber.ts +35 -1
- package/src/wallet.ts +22 -0
|
@@ -94,6 +94,16 @@ exports.DevnetPerpMarkets = [
|
|
|
94
94
|
launchTs: 1680808053000,
|
|
95
95
|
oracleSource: __1.OracleSource.PYTH,
|
|
96
96
|
},
|
|
97
|
+
{
|
|
98
|
+
fullName: 'Sui',
|
|
99
|
+
category: ['L1'],
|
|
100
|
+
symbol: 'SUI-PERP',
|
|
101
|
+
baseAssetSymbol: 'SUI',
|
|
102
|
+
marketIndex: 9,
|
|
103
|
+
oracle: new web3_js_1.PublicKey('6SK9vS8eMSSj3LUX2dPku93CrNv8xLCp9ng39F39h7A5'),
|
|
104
|
+
launchTs: 1683125906000,
|
|
105
|
+
oracleSource: __1.OracleSource.PYTH,
|
|
106
|
+
},
|
|
97
107
|
];
|
|
98
108
|
exports.MainnetPerpMarkets = [
|
|
99
109
|
{
|
|
@@ -186,6 +196,16 @@ exports.MainnetPerpMarkets = [
|
|
|
186
196
|
launchTs: 1680808053000,
|
|
187
197
|
oracleSource: __1.OracleSource.PYTH,
|
|
188
198
|
},
|
|
199
|
+
{
|
|
200
|
+
fullName: 'Sui',
|
|
201
|
+
category: ['L1'],
|
|
202
|
+
symbol: 'SUI-PERP',
|
|
203
|
+
baseAssetSymbol: 'SUI',
|
|
204
|
+
marketIndex: 9,
|
|
205
|
+
oracle: new web3_js_1.PublicKey('3Qub3HaAJaa2xNY7SUqPKd3vVwTqDfDDkEUMPjXD2c1q'),
|
|
206
|
+
launchTs: 1683125906000,
|
|
207
|
+
oracleSource: __1.OracleSource.PYTH,
|
|
208
|
+
},
|
|
189
209
|
];
|
|
190
210
|
exports.PerpMarkets = {
|
|
191
211
|
devnet: exports.DevnetPerpMarkets,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { BN, DLOBNode, OraclePriceData, PerpMarketAccount } from '..';
|
|
2
2
|
import { PublicKey } from '@solana/web3.js';
|
|
3
|
-
type liquiditySource = 'serum' | 'vamm' | 'dlob';
|
|
3
|
+
type liquiditySource = 'serum' | 'vamm' | 'dlob' | 'phoenix';
|
|
4
4
|
export type L2Level = {
|
|
5
5
|
price: BN;
|
|
6
6
|
size: BN;
|
package/lib/driftClient.d.ts
CHANGED
|
@@ -34,7 +34,6 @@ export declare class DriftClient {
|
|
|
34
34
|
users: Map<string, User>;
|
|
35
35
|
userStats?: UserStats;
|
|
36
36
|
activeSubAccountId: number;
|
|
37
|
-
activeAuthority: PublicKey;
|
|
38
37
|
userAccountSubscriptionConfig: UserSubscriptionConfig;
|
|
39
38
|
accountSubscriber: DriftClientAccountSubscriber;
|
|
40
39
|
eventEmitter: StrictEventEmitter<EventEmitter, DriftClientAccountEvents>;
|
|
@@ -46,7 +45,7 @@ export declare class DriftClient {
|
|
|
46
45
|
marketLookupTable: PublicKey;
|
|
47
46
|
lookupTableAccount: AddressLookupTableAccount;
|
|
48
47
|
includeDelegates?: boolean;
|
|
49
|
-
|
|
48
|
+
authoritySubAccountMap?: Map<string, number[]>;
|
|
50
49
|
skipLoadUsers?: boolean;
|
|
51
50
|
get isSubscribed(): boolean;
|
|
52
51
|
set isSubscribed(val: boolean);
|
|
@@ -98,7 +97,7 @@ export declare class DriftClient {
|
|
|
98
97
|
*/
|
|
99
98
|
updateWallet(newWallet: IWallet, subAccountIds?: number[], activeSubAccountId?: number, includeDelegates?: boolean, authoritySubaccountMap?: Map<string, number[]>): Promise<boolean>;
|
|
100
99
|
switchActiveUser(subAccountId: number, authority?: PublicKey): void;
|
|
101
|
-
addUser(subAccountId: number, authority?: PublicKey): Promise<boolean>;
|
|
100
|
+
addUser(subAccountId: number, authority?: PublicKey, userAccount?: UserAccount): Promise<boolean>;
|
|
102
101
|
/**
|
|
103
102
|
* Adds and subscribes to users based on params set by the constructor or by updateWallet.
|
|
104
103
|
*/
|
package/lib/driftClient.js
CHANGED
|
@@ -77,19 +77,18 @@ class DriftClient {
|
|
|
77
77
|
if (config.includeDelegates && config.subAccountIds) {
|
|
78
78
|
throw new Error('Can only pass one of includeDelegates or subAccountIds. If you want to specify subaccount ids for multiple authorities, pass authoritySubaccountMap instead');
|
|
79
79
|
}
|
|
80
|
-
if (config.
|
|
80
|
+
if (config.authoritySubAccountMap && config.subAccountIds) {
|
|
81
81
|
throw new Error('Can only pass one of authoritySubaccountMap or subAccountIds');
|
|
82
82
|
}
|
|
83
|
-
if (config.
|
|
83
|
+
if (config.authoritySubAccountMap && config.includeDelegates) {
|
|
84
84
|
throw new Error('Can only pass one of authoritySubaccountMap or includeDelegates');
|
|
85
85
|
}
|
|
86
|
-
this.
|
|
87
|
-
? config.
|
|
86
|
+
this.authoritySubAccountMap = config.authoritySubAccountMap
|
|
87
|
+
? config.authoritySubAccountMap
|
|
88
88
|
: config.subAccountIds
|
|
89
89
|
? new Map([[this.authority.toString(), config.subAccountIds]])
|
|
90
90
|
: new Map();
|
|
91
91
|
this.includeDelegates = (_d = config.includeDelegates) !== null && _d !== void 0 ? _d : false;
|
|
92
|
-
this.activeAuthority = this.authority;
|
|
93
92
|
this.userAccountSubscriptionConfig =
|
|
94
93
|
((_e = config.accountSubscription) === null || _e === void 0 ? void 0 : _e.type) === 'polling'
|
|
95
94
|
? {
|
|
@@ -298,7 +297,7 @@ class DriftClient {
|
|
|
298
297
|
if (authoritySubaccountMap && includeDelegates) {
|
|
299
298
|
throw new Error('Can only pass one of authoritySubaccountMap or includeDelegates');
|
|
300
299
|
}
|
|
301
|
-
this.
|
|
300
|
+
this.authoritySubAccountMap = authoritySubaccountMap
|
|
302
301
|
? authoritySubaccountMap
|
|
303
302
|
: subAccountIds
|
|
304
303
|
? new Map([[this.authority.toString(), subAccountIds]])
|
|
@@ -322,16 +321,17 @@ class DriftClient {
|
|
|
322
321
|
}
|
|
323
322
|
switchActiveUser(subAccountId, authority) {
|
|
324
323
|
this.activeSubAccountId = subAccountId;
|
|
325
|
-
this.
|
|
324
|
+
this.authority = authority !== null && authority !== void 0 ? authority : this.authority;
|
|
325
|
+
this.userStatsAccountPublicKey = (0, pda_1.getUserStatsAccountPublicKey)(this.program.programId, this.authority);
|
|
326
326
|
}
|
|
327
|
-
async addUser(subAccountId, authority) {
|
|
327
|
+
async addUser(subAccountId, authority, userAccount) {
|
|
328
328
|
authority = authority !== null && authority !== void 0 ? authority : this.authority;
|
|
329
329
|
const userKey = this.getUserMapKey(subAccountId, authority);
|
|
330
330
|
if (this.users.has(userKey) && this.users.get(userKey).isSubscribed) {
|
|
331
331
|
return true;
|
|
332
332
|
}
|
|
333
333
|
const user = this.createUser(subAccountId, this.userAccountSubscriptionConfig, authority);
|
|
334
|
-
const result = await user.subscribe();
|
|
334
|
+
const result = await user.subscribe(userAccount);
|
|
335
335
|
if (result) {
|
|
336
336
|
this.users.set(userKey, user);
|
|
337
337
|
return true;
|
|
@@ -349,28 +349,28 @@ class DriftClient {
|
|
|
349
349
|
if (this.skipLoadUsers)
|
|
350
350
|
return true;
|
|
351
351
|
let result = true;
|
|
352
|
-
if (this.
|
|
353
|
-
this.
|
|
352
|
+
if (this.authoritySubAccountMap && this.authoritySubAccountMap.size > 0) {
|
|
353
|
+
this.authoritySubAccountMap.forEach(async (value, key) => {
|
|
354
354
|
for (const subAccountId of value) {
|
|
355
355
|
result =
|
|
356
356
|
result && (await this.addUser(subAccountId, new web3_js_1.PublicKey(key)));
|
|
357
357
|
}
|
|
358
358
|
});
|
|
359
359
|
if (this.activeSubAccountId == undefined) {
|
|
360
|
-
this.switchActiveUser((_a = [...this.
|
|
360
|
+
this.switchActiveUser((_a = [...this.authoritySubAccountMap.values()][0][0]) !== null && _a !== void 0 ? _a : 0, new web3_js_1.PublicKey((_b = [...this.authoritySubAccountMap.keys()][0]) !== null && _b !== void 0 ? _b : this.authority.toString()));
|
|
361
361
|
}
|
|
362
362
|
}
|
|
363
363
|
else {
|
|
364
|
-
const userAccounts = (_c = (await this.getUserAccountsForAuthority(this.
|
|
364
|
+
const userAccounts = (_c = (await this.getUserAccountsForAuthority(this.wallet.publicKey))) !== null && _c !== void 0 ? _c : [];
|
|
365
365
|
let delegatedAccounts = [];
|
|
366
366
|
if (this.includeDelegates) {
|
|
367
367
|
delegatedAccounts =
|
|
368
|
-
(_d = (await this.getUserAccountsForDelegate(this.
|
|
368
|
+
(_d = (await this.getUserAccountsForDelegate(this.wallet.publicKey))) !== null && _d !== void 0 ? _d : [];
|
|
369
369
|
}
|
|
370
370
|
for (const account of userAccounts.concat(delegatedAccounts)) {
|
|
371
371
|
result =
|
|
372
372
|
result &&
|
|
373
|
-
(await this.addUser(account.subAccountId, account.authority));
|
|
373
|
+
(await this.addUser(account.subAccountId, account.authority, account));
|
|
374
374
|
}
|
|
375
375
|
if (this.activeSubAccountId == undefined) {
|
|
376
376
|
this.switchActiveUser((_f = (_e = userAccounts.concat(delegatedAccounts)[0]) === null || _e === void 0 ? void 0 : _e.subAccountId) !== null && _f !== void 0 ? _f : 0, (_h = (_g = userAccounts.concat(delegatedAccounts)[0]) === null || _g === void 0 ? void 0 : _g.authority) !== null && _h !== void 0 ? _h : this.authority);
|
|
@@ -388,6 +388,7 @@ class DriftClient {
|
|
|
388
388
|
}
|
|
389
389
|
tx.add(initializeUserAccountIx);
|
|
390
390
|
const { txSig } = await this.sendTransaction(tx, [], this.opts);
|
|
391
|
+
await this.addUser(subAccountId);
|
|
391
392
|
return [txSig, userAccountPublicKey];
|
|
392
393
|
}
|
|
393
394
|
async getInitializeUserInstructions(subAccountId = 0, name = userName_1.DEFAULT_USER_NAME, referrerInfo) {
|
|
@@ -604,18 +605,18 @@ class DriftClient {
|
|
|
604
605
|
}
|
|
605
606
|
getUser(subAccountId, authority) {
|
|
606
607
|
subAccountId = subAccountId !== null && subAccountId !== void 0 ? subAccountId : this.activeSubAccountId;
|
|
607
|
-
authority = authority !== null && authority !== void 0 ? authority : this.
|
|
608
|
+
authority = authority !== null && authority !== void 0 ? authority : this.authority;
|
|
608
609
|
const userMapKey = this.getUserMapKey(subAccountId, authority);
|
|
609
610
|
if (!this.users.has(userMapKey)) {
|
|
610
|
-
throw new Error(`Clearing House has no user for user id ${
|
|
611
|
+
throw new Error(`Clearing House has no user for user id ${userMapKey}`);
|
|
611
612
|
}
|
|
612
613
|
return this.users.get(userMapKey);
|
|
613
614
|
}
|
|
614
615
|
getUsers() {
|
|
615
616
|
// delegate users get added to the end
|
|
616
617
|
return [...this.users.values()]
|
|
617
|
-
.filter((acct) => acct.getUserAccount().authority.equals(this.
|
|
618
|
-
.concat([...this.users.values()].filter((acct) => !acct.getUserAccount().authority.equals(this.
|
|
618
|
+
.filter((acct) => acct.getUserAccount().authority.equals(this.wallet.publicKey))
|
|
619
|
+
.concat([...this.users.values()].filter((acct) => !acct.getUserAccount().authority.equals(this.wallet.publicKey)));
|
|
619
620
|
}
|
|
620
621
|
getUserStats() {
|
|
621
622
|
return this.userStats;
|
|
@@ -629,7 +630,7 @@ class DriftClient {
|
|
|
629
630
|
if (this.userStatsAccountPublicKey) {
|
|
630
631
|
return this.userStatsAccountPublicKey;
|
|
631
632
|
}
|
|
632
|
-
this.userStatsAccountPublicKey = (0, pda_1.getUserStatsAccountPublicKey)(this.program.programId, this.
|
|
633
|
+
this.userStatsAccountPublicKey = (0, pda_1.getUserStatsAccountPublicKey)(this.program.programId, this.authority);
|
|
633
634
|
return this.userStatsAccountPublicKey;
|
|
634
635
|
}
|
|
635
636
|
async getUserAccountPublicKey(subAccountId, authority) {
|
|
@@ -909,8 +910,8 @@ class DriftClient {
|
|
|
909
910
|
const additionalSigners = [];
|
|
910
911
|
const spotMarketAccount = this.getSpotMarketAccount(marketIndex);
|
|
911
912
|
const isSolMarket = spotMarketAccount.mint.equals(spotMarkets_1.WRAPPED_SOL_MINT);
|
|
912
|
-
const
|
|
913
|
-
const createWSOLTokenAccount = isSolMarket && collateralAccountPublicKey.equals(
|
|
913
|
+
const signerAuthority = this.wallet.publicKey;
|
|
914
|
+
const createWSOLTokenAccount = isSolMarket && collateralAccountPublicKey.equals(signerAuthority);
|
|
914
915
|
if (createWSOLTokenAccount) {
|
|
915
916
|
const { ixs, signers, pubkey } = await this.getWrappedSolAccountCreationIxs(amount, true);
|
|
916
917
|
collateralAccountPublicKey = pubkey;
|
|
@@ -923,16 +924,14 @@ class DriftClient {
|
|
|
923
924
|
tx.add(depositCollateralIx);
|
|
924
925
|
// Close the wrapped sol account at the end of the transaction
|
|
925
926
|
if (createWSOLTokenAccount) {
|
|
926
|
-
tx.add(spl_token_1.Token.createCloseAccountInstruction(spl_token_1.TOKEN_PROGRAM_ID, collateralAccountPublicKey,
|
|
927
|
+
tx.add(spl_token_1.Token.createCloseAccountInstruction(spl_token_1.TOKEN_PROGRAM_ID, collateralAccountPublicKey, signerAuthority, signerAuthority, []));
|
|
927
928
|
}
|
|
928
929
|
const { txSig, slot } = await this.sendTransaction(tx, additionalSigners, this.opts);
|
|
929
930
|
this.spotMarketLastSlotCache.set(marketIndex, slot);
|
|
930
931
|
return txSig;
|
|
931
932
|
}
|
|
932
933
|
async getDepositInstruction(amount, marketIndex, userTokenAccount, subAccountId, reduceOnly = false, userInitialized = true) {
|
|
933
|
-
const userAccountPublicKey = subAccountId
|
|
934
|
-
? await (0, pda_1.getUserAccountPublicKey)(this.program.programId, this.authority, subAccountId)
|
|
935
|
-
: await this.getUserAccountPublicKey();
|
|
934
|
+
const userAccountPublicKey = await (0, pda_1.getUserAccountPublicKey)(this.program.programId, this.authority, subAccountId !== null && subAccountId !== void 0 ? subAccountId : this.activeSubAccountId);
|
|
936
935
|
let remainingAccounts = [];
|
|
937
936
|
if (userInitialized) {
|
|
938
937
|
remainingAccounts = this.getRemainingAccounts({
|
|
@@ -1049,6 +1048,7 @@ class DriftClient {
|
|
|
1049
1048
|
}
|
|
1050
1049
|
const { txSig, slot } = await this.sendTransaction(tx, additionalSigners, this.opts);
|
|
1051
1050
|
this.spotMarketLastSlotCache.set(marketIndex, slot);
|
|
1051
|
+
await this.addUser(subAccountId);
|
|
1052
1052
|
return [txSig, userAccountPublicKey];
|
|
1053
1053
|
}
|
|
1054
1054
|
async initializeUserAccountForDevnet(subAccountId = 0, name = userName_1.DEFAULT_USER_NAME, marketIndex, tokenFaucet, amount, referrerInfo) {
|
|
@@ -1063,6 +1063,7 @@ class DriftClient {
|
|
|
1063
1063
|
}
|
|
1064
1064
|
tx.add(initializeUserAccountIx).add(depositCollateralIx);
|
|
1065
1065
|
const txSig = await this.program.provider.sendAndConfirm(tx, []);
|
|
1066
|
+
await this.addUser(subAccountId);
|
|
1066
1067
|
return [txSig, userAccountPublicKey];
|
|
1067
1068
|
}
|
|
1068
1069
|
async withdraw(amount, marketIndex, userTokenAccount, reduceOnly = false) {
|
|
@@ -20,7 +20,7 @@ export type DriftClientConfig = {
|
|
|
20
20
|
userStats?: boolean;
|
|
21
21
|
authority?: PublicKey;
|
|
22
22
|
includeDelegates?: boolean;
|
|
23
|
-
|
|
23
|
+
authoritySubAccountMap?: Map<string, number[]>;
|
|
24
24
|
skipLoadUsers?: boolean;
|
|
25
25
|
};
|
|
26
26
|
export type DriftClientSubscriptionConfig = {
|
package/lib/idl/drift.json
CHANGED
|
@@ -2,6 +2,7 @@ import { Connection, PublicKey } from '@solana/web3.js';
|
|
|
2
2
|
import { BulkAccountLoader } from '../accounts/bulkAccountLoader';
|
|
3
3
|
import { MarketData, Client } from '@ellipsis-labs/phoenix-sdk';
|
|
4
4
|
import { BN } from '@coral-xyz/anchor';
|
|
5
|
+
import { L2Level, L2OrderBookGenerator } from '../dlob/orderBookLevels';
|
|
5
6
|
export type PhoenixMarketSubscriberConfig = {
|
|
6
7
|
connection: Connection;
|
|
7
8
|
programId: PublicKey;
|
|
@@ -13,7 +14,7 @@ export type PhoenixMarketSubscriberConfig = {
|
|
|
13
14
|
type: 'websocket';
|
|
14
15
|
};
|
|
15
16
|
};
|
|
16
|
-
export declare class PhoenixSubscriber {
|
|
17
|
+
export declare class PhoenixSubscriber implements L2OrderBookGenerator {
|
|
17
18
|
connection: Connection;
|
|
18
19
|
client: Client;
|
|
19
20
|
programId: PublicKey;
|
|
@@ -30,5 +31,8 @@ export declare class PhoenixSubscriber {
|
|
|
30
31
|
subscribe(): Promise<void>;
|
|
31
32
|
getBestBid(): BN;
|
|
32
33
|
getBestAsk(): BN;
|
|
34
|
+
getL2Bids(): Generator<L2Level>;
|
|
35
|
+
getL2Asks(): Generator<L2Level>;
|
|
36
|
+
getL2Levels(side: 'bids' | 'asks'): Generator<L2Level>;
|
|
33
37
|
unsubscribe(): Promise<void>;
|
|
34
38
|
}
|
|
@@ -60,6 +60,29 @@ class PhoenixSubscriber {
|
|
|
60
60
|
const ladder = (0, phoenix_sdk_1.getMarketUiLadder)(this.market, this.lastSlot, this.lastUnixTimestamp, 1);
|
|
61
61
|
return new anchor_1.BN(Math.floor(ladder.asks[0][0] * numericConstants_1.PRICE_PRECISION.toNumber()));
|
|
62
62
|
}
|
|
63
|
+
getL2Bids() {
|
|
64
|
+
return this.getL2Levels('bids');
|
|
65
|
+
}
|
|
66
|
+
getL2Asks() {
|
|
67
|
+
return this.getL2Levels('asks');
|
|
68
|
+
}
|
|
69
|
+
*getL2Levels(side) {
|
|
70
|
+
// @ts-ignore
|
|
71
|
+
const basePrecision = Math.pow(10, this.market.header.baseParams.decimals);
|
|
72
|
+
const pricePrecision = numericConstants_1.PRICE_PRECISION.toNumber();
|
|
73
|
+
const ladder = (0, phoenix_sdk_1.getMarketUiLadder)(this.market, this.lastSlot, this.lastUnixTimestamp, 20);
|
|
74
|
+
for (let i = 0; i < ladder[side].length; i++) {
|
|
75
|
+
const [priceNum, sizeNum] = ladder[side][i];
|
|
76
|
+
const size = new anchor_1.BN(Math.floor(sizeNum * basePrecision));
|
|
77
|
+
yield {
|
|
78
|
+
price: new anchor_1.BN(Math.floor(priceNum * pricePrecision)),
|
|
79
|
+
size,
|
|
80
|
+
sources: {
|
|
81
|
+
phoenix: size,
|
|
82
|
+
},
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
}
|
|
63
86
|
async unsubscribe() {
|
|
64
87
|
if (!this.subscribed) {
|
|
65
88
|
return;
|
package/lib/wallet.d.ts
CHANGED
package/lib/wallet.js
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.Wallet = void 0;
|
|
6
|
+
exports.loadKeypair = exports.Wallet = void 0;
|
|
7
|
+
const web3_js_1 = require("@solana/web3.js");
|
|
8
|
+
const fs_1 = __importDefault(require("fs"));
|
|
9
|
+
const bs58_1 = __importDefault(require("bs58"));
|
|
4
10
|
class Wallet {
|
|
5
11
|
constructor(payer) {
|
|
6
12
|
this.payer = payer;
|
|
@@ -20,3 +26,20 @@ class Wallet {
|
|
|
20
26
|
}
|
|
21
27
|
}
|
|
22
28
|
exports.Wallet = Wallet;
|
|
29
|
+
function loadKeypair(privateKey) {
|
|
30
|
+
// try to load privateKey as a filepath
|
|
31
|
+
let loadedKey;
|
|
32
|
+
if (fs_1.default.existsSync(privateKey)) {
|
|
33
|
+
loadedKey = new Uint8Array(JSON.parse(fs_1.default.readFileSync(privateKey).toString()));
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
if (privateKey.includes(',')) {
|
|
37
|
+
loadedKey = Uint8Array.from(privateKey.split(',').map((val) => Number(val)));
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
loadedKey = new Uint8Array(bs58_1.default.decode(privateKey));
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return web3_js_1.Keypair.fromSecretKey(Uint8Array.from(loadedKey));
|
|
44
|
+
}
|
|
45
|
+
exports.loadKeypair = loadKeypair;
|
package/package.json
CHANGED
|
@@ -104,6 +104,16 @@ export const DevnetPerpMarkets: PerpMarketConfig[] = [
|
|
|
104
104
|
launchTs: 1680808053000,
|
|
105
105
|
oracleSource: OracleSource.PYTH,
|
|
106
106
|
},
|
|
107
|
+
{
|
|
108
|
+
fullName: 'Sui',
|
|
109
|
+
category: ['L1'],
|
|
110
|
+
symbol: 'SUI-PERP',
|
|
111
|
+
baseAssetSymbol: 'SUI',
|
|
112
|
+
marketIndex: 9,
|
|
113
|
+
oracle: new PublicKey('6SK9vS8eMSSj3LUX2dPku93CrNv8xLCp9ng39F39h7A5'),
|
|
114
|
+
launchTs: 1683125906000,
|
|
115
|
+
oracleSource: OracleSource.PYTH,
|
|
116
|
+
},
|
|
107
117
|
];
|
|
108
118
|
|
|
109
119
|
export const MainnetPerpMarkets: PerpMarketConfig[] = [
|
|
@@ -197,6 +207,16 @@ export const MainnetPerpMarkets: PerpMarketConfig[] = [
|
|
|
197
207
|
launchTs: 1680808053000,
|
|
198
208
|
oracleSource: OracleSource.PYTH,
|
|
199
209
|
},
|
|
210
|
+
{
|
|
211
|
+
fullName: 'Sui',
|
|
212
|
+
category: ['L1'],
|
|
213
|
+
symbol: 'SUI-PERP',
|
|
214
|
+
baseAssetSymbol: 'SUI',
|
|
215
|
+
marketIndex: 9,
|
|
216
|
+
oracle: new PublicKey('3Qub3HaAJaa2xNY7SUqPKd3vVwTqDfDDkEUMPjXD2c1q'),
|
|
217
|
+
launchTs: 1683125906000,
|
|
218
|
+
oracleSource: OracleSource.PYTH,
|
|
219
|
+
},
|
|
200
220
|
];
|
|
201
221
|
|
|
202
222
|
export const PerpMarkets: { [key in DriftEnv]: PerpMarketConfig[] } = {
|
package/src/driftClient.ts
CHANGED
|
@@ -121,7 +121,6 @@ export class DriftClient {
|
|
|
121
121
|
users = new Map<string, User>();
|
|
122
122
|
userStats?: UserStats;
|
|
123
123
|
activeSubAccountId: number;
|
|
124
|
-
activeAuthority: PublicKey;
|
|
125
124
|
userAccountSubscriptionConfig: UserSubscriptionConfig;
|
|
126
125
|
accountSubscriber: DriftClientAccountSubscriber;
|
|
127
126
|
eventEmitter: StrictEventEmitter<EventEmitter, DriftClientAccountEvents>;
|
|
@@ -133,7 +132,7 @@ export class DriftClient {
|
|
|
133
132
|
marketLookupTable: PublicKey;
|
|
134
133
|
lookupTableAccount: AddressLookupTableAccount;
|
|
135
134
|
includeDelegates?: boolean;
|
|
136
|
-
|
|
135
|
+
authoritySubAccountMap?: Map<string, number[]>;
|
|
137
136
|
skipLoadUsers?: boolean;
|
|
138
137
|
|
|
139
138
|
public get isSubscribed() {
|
|
@@ -169,26 +168,25 @@ export class DriftClient {
|
|
|
169
168
|
);
|
|
170
169
|
}
|
|
171
170
|
|
|
172
|
-
if (config.
|
|
171
|
+
if (config.authoritySubAccountMap && config.subAccountIds) {
|
|
173
172
|
throw new Error(
|
|
174
173
|
'Can only pass one of authoritySubaccountMap or subAccountIds'
|
|
175
174
|
);
|
|
176
175
|
}
|
|
177
176
|
|
|
178
|
-
if (config.
|
|
177
|
+
if (config.authoritySubAccountMap && config.includeDelegates) {
|
|
179
178
|
throw new Error(
|
|
180
179
|
'Can only pass one of authoritySubaccountMap or includeDelegates'
|
|
181
180
|
);
|
|
182
181
|
}
|
|
183
182
|
|
|
184
|
-
this.
|
|
185
|
-
? config.
|
|
183
|
+
this.authoritySubAccountMap = config.authoritySubAccountMap
|
|
184
|
+
? config.authoritySubAccountMap
|
|
186
185
|
: config.subAccountIds
|
|
187
186
|
? new Map([[this.authority.toString(), config.subAccountIds]])
|
|
188
187
|
: new Map<string, number[]>();
|
|
189
188
|
|
|
190
189
|
this.includeDelegates = config.includeDelegates ?? false;
|
|
191
|
-
this.activeAuthority = this.authority;
|
|
192
190
|
this.userAccountSubscriptionConfig =
|
|
193
191
|
config.accountSubscription?.type === 'polling'
|
|
194
192
|
? {
|
|
@@ -525,7 +523,7 @@ export class DriftClient {
|
|
|
525
523
|
);
|
|
526
524
|
}
|
|
527
525
|
|
|
528
|
-
this.
|
|
526
|
+
this.authoritySubAccountMap = authoritySubaccountMap
|
|
529
527
|
? authoritySubaccountMap
|
|
530
528
|
: subAccountIds
|
|
531
529
|
? new Map([[this.authority.toString(), subAccountIds]])
|
|
@@ -557,12 +555,17 @@ export class DriftClient {
|
|
|
557
555
|
|
|
558
556
|
public switchActiveUser(subAccountId: number, authority?: PublicKey) {
|
|
559
557
|
this.activeSubAccountId = subAccountId;
|
|
560
|
-
this.
|
|
558
|
+
this.authority = authority ?? this.authority;
|
|
559
|
+
this.userStatsAccountPublicKey = getUserStatsAccountPublicKey(
|
|
560
|
+
this.program.programId,
|
|
561
|
+
this.authority
|
|
562
|
+
);
|
|
561
563
|
}
|
|
562
564
|
|
|
563
565
|
public async addUser(
|
|
564
566
|
subAccountId: number,
|
|
565
|
-
authority?: PublicKey
|
|
567
|
+
authority?: PublicKey,
|
|
568
|
+
userAccount?: UserAccount
|
|
566
569
|
): Promise<boolean> {
|
|
567
570
|
authority = authority ?? this.authority;
|
|
568
571
|
const userKey = this.getUserMapKey(subAccountId, authority);
|
|
@@ -577,7 +580,7 @@ export class DriftClient {
|
|
|
577
580
|
authority
|
|
578
581
|
);
|
|
579
582
|
|
|
580
|
-
const result = await user.subscribe();
|
|
583
|
+
const result = await user.subscribe(userAccount);
|
|
581
584
|
|
|
582
585
|
if (result) {
|
|
583
586
|
this.users.set(userKey, user);
|
|
@@ -596,8 +599,8 @@ export class DriftClient {
|
|
|
596
599
|
|
|
597
600
|
let result = true;
|
|
598
601
|
|
|
599
|
-
if (this.
|
|
600
|
-
this.
|
|
602
|
+
if (this.authoritySubAccountMap && this.authoritySubAccountMap.size > 0) {
|
|
603
|
+
this.authoritySubAccountMap.forEach(async (value, key) => {
|
|
601
604
|
for (const subAccountId of value) {
|
|
602
605
|
result =
|
|
603
606
|
result && (await this.addUser(subAccountId, new PublicKey(key)));
|
|
@@ -606,27 +609,31 @@ export class DriftClient {
|
|
|
606
609
|
|
|
607
610
|
if (this.activeSubAccountId == undefined) {
|
|
608
611
|
this.switchActiveUser(
|
|
609
|
-
[...this.
|
|
612
|
+
[...this.authoritySubAccountMap.values()][0][0] ?? 0,
|
|
610
613
|
new PublicKey(
|
|
611
|
-
[...this.
|
|
614
|
+
[...this.authoritySubAccountMap.keys()][0] ??
|
|
612
615
|
this.authority.toString()
|
|
613
616
|
)
|
|
614
617
|
);
|
|
615
618
|
}
|
|
616
619
|
} else {
|
|
617
620
|
const userAccounts =
|
|
618
|
-
(await this.getUserAccountsForAuthority(this.
|
|
621
|
+
(await this.getUserAccountsForAuthority(this.wallet.publicKey)) ?? [];
|
|
619
622
|
let delegatedAccounts = [];
|
|
620
623
|
|
|
621
624
|
if (this.includeDelegates) {
|
|
622
625
|
delegatedAccounts =
|
|
623
|
-
(await this.getUserAccountsForDelegate(this.
|
|
626
|
+
(await this.getUserAccountsForDelegate(this.wallet.publicKey)) ?? [];
|
|
624
627
|
}
|
|
625
628
|
|
|
626
629
|
for (const account of userAccounts.concat(delegatedAccounts)) {
|
|
627
630
|
result =
|
|
628
631
|
result &&
|
|
629
|
-
(await this.addUser(
|
|
632
|
+
(await this.addUser(
|
|
633
|
+
account.subAccountId,
|
|
634
|
+
account.authority,
|
|
635
|
+
account
|
|
636
|
+
));
|
|
630
637
|
}
|
|
631
638
|
|
|
632
639
|
if (this.activeSubAccountId == undefined) {
|
|
@@ -662,6 +669,9 @@ export class DriftClient {
|
|
|
662
669
|
}
|
|
663
670
|
tx.add(initializeUserAccountIx);
|
|
664
671
|
const { txSig } = await this.sendTransaction(tx, [], this.opts);
|
|
672
|
+
|
|
673
|
+
await this.addUser(subAccountId);
|
|
674
|
+
|
|
665
675
|
return [txSig, userAccountPublicKey];
|
|
666
676
|
}
|
|
667
677
|
|
|
@@ -1006,11 +1016,11 @@ export class DriftClient {
|
|
|
1006
1016
|
|
|
1007
1017
|
public getUser(subAccountId?: number, authority?: PublicKey): User {
|
|
1008
1018
|
subAccountId = subAccountId ?? this.activeSubAccountId;
|
|
1009
|
-
authority = authority ?? this.
|
|
1019
|
+
authority = authority ?? this.authority;
|
|
1010
1020
|
const userMapKey = this.getUserMapKey(subAccountId, authority);
|
|
1011
1021
|
|
|
1012
1022
|
if (!this.users.has(userMapKey)) {
|
|
1013
|
-
throw new Error(`Clearing House has no user for user id ${
|
|
1023
|
+
throw new Error(`Clearing House has no user for user id ${userMapKey}`);
|
|
1014
1024
|
}
|
|
1015
1025
|
return this.users.get(userMapKey);
|
|
1016
1026
|
}
|
|
@@ -1018,10 +1028,13 @@ export class DriftClient {
|
|
|
1018
1028
|
public getUsers(): User[] {
|
|
1019
1029
|
// delegate users get added to the end
|
|
1020
1030
|
return [...this.users.values()]
|
|
1021
|
-
.filter((acct) =>
|
|
1031
|
+
.filter((acct) =>
|
|
1032
|
+
acct.getUserAccount().authority.equals(this.wallet.publicKey)
|
|
1033
|
+
)
|
|
1022
1034
|
.concat(
|
|
1023
1035
|
[...this.users.values()].filter(
|
|
1024
|
-
(acct) =>
|
|
1036
|
+
(acct) =>
|
|
1037
|
+
!acct.getUserAccount().authority.equals(this.wallet.publicKey)
|
|
1025
1038
|
)
|
|
1026
1039
|
);
|
|
1027
1040
|
}
|
|
@@ -1051,7 +1064,7 @@ export class DriftClient {
|
|
|
1051
1064
|
|
|
1052
1065
|
this.userStatsAccountPublicKey = getUserStatsAccountPublicKey(
|
|
1053
1066
|
this.program.programId,
|
|
1054
|
-
this.
|
|
1067
|
+
this.authority
|
|
1055
1068
|
);
|
|
1056
1069
|
return this.userStatsAccountPublicKey;
|
|
1057
1070
|
}
|
|
@@ -1419,10 +1432,10 @@ export class DriftClient {
|
|
|
1419
1432
|
|
|
1420
1433
|
const isSolMarket = spotMarketAccount.mint.equals(WRAPPED_SOL_MINT);
|
|
1421
1434
|
|
|
1422
|
-
const
|
|
1435
|
+
const signerAuthority = this.wallet.publicKey;
|
|
1423
1436
|
|
|
1424
1437
|
const createWSOLTokenAccount =
|
|
1425
|
-
isSolMarket && collateralAccountPublicKey.equals(
|
|
1438
|
+
isSolMarket && collateralAccountPublicKey.equals(signerAuthority);
|
|
1426
1439
|
|
|
1427
1440
|
if (createWSOLTokenAccount) {
|
|
1428
1441
|
const { ixs, signers, pubkey } =
|
|
@@ -1454,8 +1467,8 @@ export class DriftClient {
|
|
|
1454
1467
|
Token.createCloseAccountInstruction(
|
|
1455
1468
|
TOKEN_PROGRAM_ID,
|
|
1456
1469
|
collateralAccountPublicKey,
|
|
1457
|
-
|
|
1458
|
-
|
|
1470
|
+
signerAuthority,
|
|
1471
|
+
signerAuthority,
|
|
1459
1472
|
[]
|
|
1460
1473
|
)
|
|
1461
1474
|
);
|
|
@@ -1478,13 +1491,11 @@ export class DriftClient {
|
|
|
1478
1491
|
reduceOnly = false,
|
|
1479
1492
|
userInitialized = true
|
|
1480
1493
|
): Promise<TransactionInstruction> {
|
|
1481
|
-
const userAccountPublicKey =
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
)
|
|
1487
|
-
: await this.getUserAccountPublicKey();
|
|
1494
|
+
const userAccountPublicKey = await getUserAccountPublicKey(
|
|
1495
|
+
this.program.programId,
|
|
1496
|
+
this.authority,
|
|
1497
|
+
subAccountId ?? this.activeSubAccountId
|
|
1498
|
+
);
|
|
1488
1499
|
|
|
1489
1500
|
let remainingAccounts = [];
|
|
1490
1501
|
if (userInitialized) {
|
|
@@ -1713,6 +1724,8 @@ export class DriftClient {
|
|
|
1713
1724
|
);
|
|
1714
1725
|
this.spotMarketLastSlotCache.set(marketIndex, slot);
|
|
1715
1726
|
|
|
1727
|
+
await this.addUser(subAccountId);
|
|
1728
|
+
|
|
1716
1729
|
return [txSig, userAccountPublicKey];
|
|
1717
1730
|
}
|
|
1718
1731
|
|
|
@@ -1759,6 +1772,8 @@ export class DriftClient {
|
|
|
1759
1772
|
|
|
1760
1773
|
const txSig = await this.program.provider.sendAndConfirm(tx, []);
|
|
1761
1774
|
|
|
1775
|
+
await this.addUser(subAccountId);
|
|
1776
|
+
|
|
1762
1777
|
return [txSig, userAccountPublicKey];
|
|
1763
1778
|
}
|
|
1764
1779
|
|
package/src/driftClientConfig.ts
CHANGED
|
@@ -21,7 +21,7 @@ export type DriftClientConfig = {
|
|
|
21
21
|
userStats?: boolean;
|
|
22
22
|
authority?: PublicKey; // explicitly pass an authority if signer is delegate
|
|
23
23
|
includeDelegates?: boolean; // flag for whether to load delegate accounts as well
|
|
24
|
-
|
|
24
|
+
authoritySubAccountMap?: Map<string, number[]>; // if passed this will override subAccountIds and includeDelegates
|
|
25
25
|
skipLoadUsers?: boolean; // if passed to constructor, no user accounts will be loaded. they will load if updateWallet is called afterwards.
|
|
26
26
|
};
|
|
27
27
|
|
package/src/idl/drift.json
CHANGED
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
} from '@ellipsis-labs/phoenix-sdk';
|
|
11
11
|
import { PRICE_PRECISION } from '../constants/numericConstants';
|
|
12
12
|
import { BN } from '@coral-xyz/anchor';
|
|
13
|
+
import { L2Level, L2OrderBookGenerator } from '../dlob/orderBookLevels';
|
|
13
14
|
|
|
14
15
|
export type PhoenixMarketSubscriberConfig = {
|
|
15
16
|
connection: Connection;
|
|
@@ -26,7 +27,7 @@ export type PhoenixMarketSubscriberConfig = {
|
|
|
26
27
|
};
|
|
27
28
|
};
|
|
28
29
|
|
|
29
|
-
export class PhoenixSubscriber {
|
|
30
|
+
export class PhoenixSubscriber implements L2OrderBookGenerator {
|
|
30
31
|
connection: Connection;
|
|
31
32
|
client: Client;
|
|
32
33
|
programId: PublicKey;
|
|
@@ -127,6 +128,39 @@ export class PhoenixSubscriber {
|
|
|
127
128
|
return new BN(Math.floor(ladder.asks[0][0] * PRICE_PRECISION.toNumber()));
|
|
128
129
|
}
|
|
129
130
|
|
|
131
|
+
public getL2Bids(): Generator<L2Level> {
|
|
132
|
+
return this.getL2Levels('bids');
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
public getL2Asks(): Generator<L2Level> {
|
|
136
|
+
return this.getL2Levels('asks');
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
*getL2Levels(side: 'bids' | 'asks'): Generator<L2Level> {
|
|
140
|
+
// @ts-ignore
|
|
141
|
+
const basePrecision = Math.pow(10, this.market.header.baseParams.decimals);
|
|
142
|
+
const pricePrecision = PRICE_PRECISION.toNumber();
|
|
143
|
+
|
|
144
|
+
const ladder = getMarketUiLadder(
|
|
145
|
+
this.market,
|
|
146
|
+
this.lastSlot,
|
|
147
|
+
this.lastUnixTimestamp,
|
|
148
|
+
20
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
for (let i = 0; i < ladder[side].length; i++) {
|
|
152
|
+
const [priceNum, sizeNum] = ladder[side][i];
|
|
153
|
+
const size = new BN(Math.floor(sizeNum * basePrecision));
|
|
154
|
+
yield {
|
|
155
|
+
price: new BN(Math.floor(priceNum * pricePrecision)),
|
|
156
|
+
size,
|
|
157
|
+
sources: {
|
|
158
|
+
phoenix: size,
|
|
159
|
+
},
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
130
164
|
public async unsubscribe(): Promise<void> {
|
|
131
165
|
if (!this.subscribed) {
|
|
132
166
|
return;
|
package/src/wallet.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { Keypair, PublicKey, Transaction } from '@solana/web3.js';
|
|
2
2
|
import { IWallet } from './types';
|
|
3
|
+
import fs from 'fs';
|
|
4
|
+
import bs58 from 'bs58';
|
|
3
5
|
|
|
4
6
|
export class Wallet implements IWallet {
|
|
5
7
|
constructor(readonly payer: Keypair) {}
|
|
@@ -20,3 +22,23 @@ export class Wallet implements IWallet {
|
|
|
20
22
|
return this.payer.publicKey;
|
|
21
23
|
}
|
|
22
24
|
}
|
|
25
|
+
|
|
26
|
+
export function loadKeypair(privateKey: string): Keypair {
|
|
27
|
+
// try to load privateKey as a filepath
|
|
28
|
+
let loadedKey: Uint8Array;
|
|
29
|
+
if (fs.existsSync(privateKey)) {
|
|
30
|
+
loadedKey = new Uint8Array(
|
|
31
|
+
JSON.parse(fs.readFileSync(privateKey).toString())
|
|
32
|
+
);
|
|
33
|
+
} else {
|
|
34
|
+
if (privateKey.includes(',')) {
|
|
35
|
+
loadedKey = Uint8Array.from(
|
|
36
|
+
privateKey.split(',').map((val) => Number(val))
|
|
37
|
+
);
|
|
38
|
+
} else {
|
|
39
|
+
loadedKey = new Uint8Array(bs58.decode(privateKey));
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return Keypair.fromSecretKey(Uint8Array.from(loadedKey));
|
|
44
|
+
}
|