@drift-labs/sdk 2.82.0-beta.0 → 2.82.0-beta.10
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/README.md +65 -47
- package/VERSION +1 -1
- package/lib/accounts/types.d.ts +4 -0
- package/lib/accounts/webSocketAccountSubscriber.d.ts +3 -3
- package/lib/accounts/webSocketAccountSubscriber.js +15 -8
- package/lib/accounts/webSocketDriftClientAccountSubscriber.d.ts +3 -3
- package/lib/accounts/webSocketDriftClientAccountSubscriber.js +5 -5
- package/lib/accounts/webSocketInsuranceFundStakeAccountSubscriber.d.ts +2 -2
- package/lib/accounts/webSocketInsuranceFundStakeAccountSubscriber.js +5 -3
- package/lib/accounts/webSocketProgramAccountSubscriber.d.ts +3 -3
- package/lib/accounts/webSocketProgramAccountSubscriber.js +15 -9
- package/lib/accounts/webSocketUserAccountSubscriber.d.ts +3 -3
- package/lib/accounts/webSocketUserAccountSubscriber.js +3 -3
- package/lib/accounts/webSocketUserStatsAccountSubsriber.d.ts +3 -3
- package/lib/accounts/webSocketUserStatsAccountSubsriber.js +3 -3
- package/lib/auctionSubscriber/auctionSubscriber.d.ts +2 -2
- package/lib/auctionSubscriber/auctionSubscriber.js +3 -3
- package/lib/auctionSubscriber/types.d.ts +1 -0
- package/lib/constants/perpMarkets.js +2 -2
- package/lib/driftClient.d.ts +12 -1
- package/lib/driftClient.js +59 -16
- package/lib/driftClientConfig.d.ts +1 -0
- package/lib/orderSubscriber/OrderSubscriber.js +6 -3
- package/lib/orderSubscriber/WebsocketSubscription.d.ts +4 -3
- package/lib/orderSubscriber/WebsocketSubscription.js +3 -3
- package/lib/orderSubscriber/types.d.ts +1 -0
- package/lib/priorityFee/driftPriorityFeeMethod.d.ts +13 -3
- package/lib/priorityFee/driftPriorityFeeMethod.js +2 -2
- package/lib/priorityFee/index.d.ts +2 -0
- package/lib/priorityFee/index.js +2 -0
- package/lib/priorityFee/priorityFeeSubscriber.d.ts +1 -4
- package/lib/priorityFee/priorityFeeSubscriber.js +5 -4
- package/lib/priorityFee/priorityFeeSubscriberMap.d.ts +48 -0
- package/lib/priorityFee/priorityFeeSubscriberMap.js +88 -0
- package/lib/priorityFee/types.d.ts +8 -3
- package/lib/priorityFee/types.js +2 -1
- package/lib/tx/baseTxSender.js +3 -2
- package/lib/tx/fastSingleTxSender.d.ts +2 -0
- package/lib/tx/fastSingleTxSender.js +10 -8
- package/lib/tx/types.d.ts +5 -0
- package/lib/tx/types.js +12 -1
- package/lib/tx/utils.js +5 -1
- package/lib/user.d.ts +0 -10
- package/lib/user.js +6 -29
- package/lib/userConfig.d.ts +1 -0
- package/lib/userMap/WebsocketSubscription.d.ts +4 -3
- package/lib/userMap/WebsocketSubscription.js +3 -3
- package/lib/userMap/userMap.js +4 -1
- package/lib/userMap/userMapConfig.d.ts +1 -0
- package/lib/userStats.js +6 -3
- package/lib/userStatsConfig.d.ts +1 -0
- package/package.json +3 -3
- package/src/accounts/types.ts +5 -0
- package/src/accounts/webSocketAccountSubscriber.ts +34 -22
- package/src/accounts/webSocketDriftClientAccountSubscriber.ts +7 -6
- package/src/accounts/webSocketInsuranceFundStakeAccountSubscriber.ts +6 -4
- package/src/accounts/webSocketProgramAccountSubscriber.ts +32 -22
- package/src/accounts/webSocketUserAccountSubscriber.ts +5 -4
- package/src/accounts/webSocketUserStatsAccountSubsriber.ts +5 -4
- package/src/auctionSubscriber/auctionSubscriber.ts +10 -4
- package/src/auctionSubscriber/types.ts +1 -0
- package/src/blockhashSubscriber/types.ts +4 -0
- package/src/constants/perpMarkets.ts +2 -2
- package/src/driftClient.ts +70 -12
- package/src/driftClientConfig.ts +1 -0
- package/src/orderSubscriber/OrderSubscriber.ts +4 -1
- package/src/orderSubscriber/WebsocketSubscription.ts +6 -5
- package/src/orderSubscriber/types.ts +1 -0
- package/src/priorityFee/driftPriorityFeeMethod.ts +16 -4
- package/src/priorityFee/index.ts +2 -0
- package/src/priorityFee/priorityFeeSubscriber.ts +7 -7
- package/src/priorityFee/priorityFeeSubscriberMap.ts +112 -0
- package/src/priorityFee/types.ts +16 -3
- package/src/tx/baseTxSender.ts +8 -4
- package/src/tx/fastSingleTxSender.ts +12 -9
- package/src/tx/types.ts +12 -0
- package/src/tx/utils.ts +5 -1
- package/src/user.ts +7 -32
- package/src/userConfig.ts +1 -0
- package/src/userMap/WebsocketSubscription.ts +6 -5
- package/src/userMap/userMap.ts +4 -1
- package/src/userMap/userMapConfig.ts +1 -0
- package/src/userStats.ts +4 -1
- package/src/userStatsConfig.ts +1 -0
- package/tests/dlob/helpers.ts +4 -0
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
NotSubscribedError,
|
|
5
5
|
UserStatsAccountSubscriber,
|
|
6
6
|
UserStatsAccountEvents,
|
|
7
|
+
ResubOpts,
|
|
7
8
|
} from './types';
|
|
8
9
|
import { Program } from '@coral-xyz/anchor';
|
|
9
10
|
import StrictEventEmitter from 'strict-event-emitter-types';
|
|
@@ -16,7 +17,7 @@ export class WebSocketUserStatsAccountSubscriber
|
|
|
16
17
|
implements UserStatsAccountSubscriber
|
|
17
18
|
{
|
|
18
19
|
isSubscribed: boolean;
|
|
19
|
-
|
|
20
|
+
resubOpts?: ResubOpts;
|
|
20
21
|
commitment?: Commitment;
|
|
21
22
|
program: Program;
|
|
22
23
|
eventEmitter: StrictEventEmitter<EventEmitter, UserStatsAccountEvents>;
|
|
@@ -27,14 +28,14 @@ export class WebSocketUserStatsAccountSubscriber
|
|
|
27
28
|
public constructor(
|
|
28
29
|
program: Program,
|
|
29
30
|
userStatsAccountPublicKey: PublicKey,
|
|
30
|
-
|
|
31
|
+
resubOpts?: ResubOpts,
|
|
31
32
|
commitment?: Commitment
|
|
32
33
|
) {
|
|
33
34
|
this.isSubscribed = false;
|
|
34
35
|
this.program = program;
|
|
35
36
|
this.userStatsAccountPublicKey = userStatsAccountPublicKey;
|
|
36
37
|
this.eventEmitter = new EventEmitter();
|
|
37
|
-
this.
|
|
38
|
+
this.resubOpts = resubOpts;
|
|
38
39
|
this.commitment = commitment;
|
|
39
40
|
}
|
|
40
41
|
|
|
@@ -48,7 +49,7 @@ export class WebSocketUserStatsAccountSubscriber
|
|
|
48
49
|
this.program,
|
|
49
50
|
this.userStatsAccountPublicKey,
|
|
50
51
|
undefined,
|
|
51
|
-
this.
|
|
52
|
+
this.resubOpts,
|
|
52
53
|
this.commitment
|
|
53
54
|
);
|
|
54
55
|
|
|
@@ -6,20 +6,26 @@ import { EventEmitter } from 'events';
|
|
|
6
6
|
import { UserAccount } from '../types';
|
|
7
7
|
import { ConfirmOptions, Context, PublicKey } from '@solana/web3.js';
|
|
8
8
|
import { WebSocketProgramAccountSubscriber } from '../accounts/webSocketProgramAccountSubscriber';
|
|
9
|
+
import { ResubOpts } from '../accounts/types';
|
|
9
10
|
|
|
10
11
|
export class AuctionSubscriber {
|
|
11
12
|
private driftClient: DriftClient;
|
|
12
13
|
private opts: ConfirmOptions;
|
|
13
|
-
private
|
|
14
|
+
private resubOpts?: ResubOpts;
|
|
14
15
|
|
|
15
16
|
eventEmitter: StrictEventEmitter<EventEmitter, AuctionSubscriberEvents>;
|
|
16
17
|
private subscriber: WebSocketProgramAccountSubscriber<UserAccount>;
|
|
17
18
|
|
|
18
|
-
constructor({
|
|
19
|
+
constructor({
|
|
20
|
+
driftClient,
|
|
21
|
+
opts,
|
|
22
|
+
resubTimeoutMs,
|
|
23
|
+
logResubMessages,
|
|
24
|
+
}: AuctionSubscriberConfig) {
|
|
19
25
|
this.driftClient = driftClient;
|
|
20
26
|
this.opts = opts || this.driftClient.opts;
|
|
21
27
|
this.eventEmitter = new EventEmitter();
|
|
22
|
-
this.
|
|
28
|
+
this.resubOpts = { resubTimeoutMs, logResubMessages };
|
|
23
29
|
}
|
|
24
30
|
|
|
25
31
|
public async subscribe() {
|
|
@@ -35,7 +41,7 @@ export class AuctionSubscriber {
|
|
|
35
41
|
filters: [getUserFilter(), getUserWithAuctionFilter()],
|
|
36
42
|
commitment: this.opts.commitment,
|
|
37
43
|
},
|
|
38
|
-
this.
|
|
44
|
+
this.resubOpts
|
|
39
45
|
);
|
|
40
46
|
}
|
|
41
47
|
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
import { Commitment, Connection } from '@solana/web3.js';
|
|
2
2
|
|
|
3
3
|
export type BlockhashSubscriberConfig = {
|
|
4
|
+
/// rpcUrl to poll block hashes from, one of rpcUrl or Connection must provided
|
|
4
5
|
rpcUrl?: string;
|
|
6
|
+
/// connection to poll block hashes from, one of rpcUrl or Connection must provided
|
|
5
7
|
connection?: Connection;
|
|
8
|
+
/// commitment to poll block hashes with, default is 'confirmed'
|
|
6
9
|
commitment?: Commitment;
|
|
10
|
+
/// interval to poll block hashes, default is 1000 ms
|
|
7
11
|
updateIntervalMs?: number;
|
|
8
12
|
};
|
|
@@ -553,9 +553,9 @@ export const MainnetPerpMarkets: PerpMarketConfig[] = [
|
|
|
553
553
|
symbol: 'KMNO-PERP',
|
|
554
554
|
baseAssetSymbol: 'KMNO',
|
|
555
555
|
marketIndex: 28,
|
|
556
|
-
oracle: new PublicKey('
|
|
556
|
+
oracle: new PublicKey('6ynsvjkE2UoiRScbDx7ZxbBsyn7wyvg5P1vENvhtkG1C'),
|
|
557
557
|
launchTs: 1712240681000,
|
|
558
|
-
oracleSource: OracleSource.
|
|
558
|
+
oracleSource: OracleSource.SWITCHBOARD,
|
|
559
559
|
},
|
|
560
560
|
{
|
|
561
561
|
fullName: 'Tensor',
|
package/src/driftClient.ts
CHANGED
|
@@ -251,11 +251,13 @@ export class DriftClient {
|
|
|
251
251
|
this.userAccountSubscriptionConfig = {
|
|
252
252
|
type: 'websocket',
|
|
253
253
|
resubTimeoutMs: config.accountSubscription?.resubTimeoutMs,
|
|
254
|
+
logResubMessages: config.accountSubscription?.logResubMessages,
|
|
254
255
|
commitment: config.accountSubscription?.commitment,
|
|
255
256
|
};
|
|
256
257
|
this.userStatsAccountSubscriptionConfig = {
|
|
257
258
|
type: 'websocket',
|
|
258
259
|
resubTimeoutMs: config.accountSubscription?.resubTimeoutMs,
|
|
260
|
+
logResubMessages: config.accountSubscription?.logResubMessages,
|
|
259
261
|
commitment: config.accountSubscription?.commitment,
|
|
260
262
|
};
|
|
261
263
|
}
|
|
@@ -298,7 +300,10 @@ export class DriftClient {
|
|
|
298
300
|
config.spotMarketIndexes ?? [],
|
|
299
301
|
config.oracleInfos ?? [],
|
|
300
302
|
noMarketsAndOraclesSpecified,
|
|
301
|
-
|
|
303
|
+
{
|
|
304
|
+
resubTimeoutMs: config.accountSubscription?.resubTimeoutMs,
|
|
305
|
+
logResubMessages: config.accountSubscription?.logResubMessages,
|
|
306
|
+
},
|
|
302
307
|
config.accountSubscription?.commitment
|
|
303
308
|
);
|
|
304
309
|
}
|
|
@@ -6488,18 +6493,33 @@ export class DriftClient {
|
|
|
6488
6493
|
}
|
|
6489
6494
|
|
|
6490
6495
|
public async settleRevenueToInsuranceFund(
|
|
6491
|
-
|
|
6496
|
+
spotMarketIndex: number,
|
|
6497
|
+
subAccountId?: number,
|
|
6498
|
+
txParams?: TxParams
|
|
6492
6499
|
): Promise<TransactionSignature> {
|
|
6493
|
-
const
|
|
6500
|
+
const tx = await this.buildTransaction(
|
|
6501
|
+
await this.getSettleRevenueToInsuranceFundIx(
|
|
6502
|
+
spotMarketIndex,
|
|
6503
|
+
subAccountId
|
|
6504
|
+
),
|
|
6505
|
+
txParams
|
|
6506
|
+
);
|
|
6507
|
+
const { txSig } = await this.sendTransaction(tx, [], this.opts);
|
|
6508
|
+
return txSig;
|
|
6509
|
+
}
|
|
6494
6510
|
|
|
6511
|
+
public async getSettleRevenueToInsuranceFundIx(
|
|
6512
|
+
spotMarketIndex: number,
|
|
6513
|
+
subAccountId?: number
|
|
6514
|
+
): Promise<TransactionInstruction> {
|
|
6515
|
+
const spotMarketAccount = this.getSpotMarketAccount(spotMarketIndex);
|
|
6495
6516
|
const remainingAccounts = this.getRemainingAccounts({
|
|
6496
|
-
userAccounts: [this.getUserAccount()],
|
|
6517
|
+
userAccounts: [this.getUserAccount(subAccountId)],
|
|
6497
6518
|
useMarketLastSlotCache: true,
|
|
6498
|
-
writableSpotMarketIndexes: [
|
|
6519
|
+
writableSpotMarketIndexes: [spotMarketIndex],
|
|
6499
6520
|
});
|
|
6500
|
-
|
|
6501
6521
|
const ix = await this.program.instruction.settleRevenueToInsuranceFund(
|
|
6502
|
-
|
|
6522
|
+
spotMarketIndex,
|
|
6503
6523
|
{
|
|
6504
6524
|
accounts: {
|
|
6505
6525
|
state: await this.getStatePublicKey(),
|
|
@@ -6512,11 +6532,7 @@ export class DriftClient {
|
|
|
6512
6532
|
remainingAccounts,
|
|
6513
6533
|
}
|
|
6514
6534
|
);
|
|
6515
|
-
|
|
6516
|
-
const tx = await this.buildTransaction(ix);
|
|
6517
|
-
|
|
6518
|
-
const { txSig } = await this.sendTransaction(tx, [], this.opts);
|
|
6519
|
-
return txSig;
|
|
6535
|
+
return ix;
|
|
6520
6536
|
}
|
|
6521
6537
|
|
|
6522
6538
|
public async resolvePerpPnlDeficit(
|
|
@@ -6629,6 +6645,48 @@ export class DriftClient {
|
|
|
6629
6645
|
return extendedInfo;
|
|
6630
6646
|
}
|
|
6631
6647
|
|
|
6648
|
+
/**
|
|
6649
|
+
* Calculates taker / maker fee (as a percentage, e.g. .001 = 10 basis points) for particular marketType
|
|
6650
|
+
* @param marketType
|
|
6651
|
+
* @param positionMarketIndex
|
|
6652
|
+
* @returns : {takerFee: number, makerFee: number} Precision None
|
|
6653
|
+
*/
|
|
6654
|
+
public getMarketFees(
|
|
6655
|
+
marketType: MarketType,
|
|
6656
|
+
marketIndex?: number,
|
|
6657
|
+
user?: User
|
|
6658
|
+
) {
|
|
6659
|
+
let feeTier;
|
|
6660
|
+
if (user) {
|
|
6661
|
+
feeTier = user.getUserFeeTier(marketType);
|
|
6662
|
+
} else {
|
|
6663
|
+
const state = this.getStateAccount();
|
|
6664
|
+
feeTier = isVariant(marketType, 'perp')
|
|
6665
|
+
? state.perpFeeStructure.feeTiers[0]
|
|
6666
|
+
: state.spotFeeStructure.feeTiers[0];
|
|
6667
|
+
}
|
|
6668
|
+
|
|
6669
|
+
let takerFee = feeTier.feeNumerator / feeTier.feeDenominator;
|
|
6670
|
+
let makerFee =
|
|
6671
|
+
feeTier.makerRebateNumerator / feeTier.makerRebateDenominator;
|
|
6672
|
+
|
|
6673
|
+
if (marketIndex !== undefined) {
|
|
6674
|
+
let marketAccount = null;
|
|
6675
|
+
if (isVariant(marketType, 'perp')) {
|
|
6676
|
+
marketAccount = this.getPerpMarketAccount(marketIndex);
|
|
6677
|
+
} else {
|
|
6678
|
+
marketAccount = this.getSpotMarketAccount(marketIndex);
|
|
6679
|
+
}
|
|
6680
|
+
takerFee += (takerFee * marketAccount.feeAdjustment) / 100;
|
|
6681
|
+
makerFee += (makerFee * marketAccount.feeAdjustment) / 100;
|
|
6682
|
+
}
|
|
6683
|
+
|
|
6684
|
+
return {
|
|
6685
|
+
takerFee,
|
|
6686
|
+
makerFee,
|
|
6687
|
+
};
|
|
6688
|
+
}
|
|
6689
|
+
|
|
6632
6690
|
/**
|
|
6633
6691
|
* Returns the market index and type for a given market name
|
|
6634
6692
|
* E.g. "SOL-PERP" -> { marketIndex: 0, marketType: MarketType.PERP }
|
package/src/driftClientConfig.ts
CHANGED
|
@@ -39,7 +39,10 @@ export class OrderSubscriber {
|
|
|
39
39
|
orderSubscriber: this,
|
|
40
40
|
commitment: this.commitment,
|
|
41
41
|
skipInitialLoad: config.subscriptionConfig.skipInitialLoad,
|
|
42
|
-
|
|
42
|
+
resubOpts: {
|
|
43
|
+
resubTimeoutMs: config.subscriptionConfig?.resubTimeoutMs,
|
|
44
|
+
logResubMessages: config.subscriptionConfig?.logResubMessages,
|
|
45
|
+
},
|
|
43
46
|
resyncIntervalMs: config.subscriptionConfig.resyncIntervalMs,
|
|
44
47
|
decoded: config.decodeData,
|
|
45
48
|
});
|
|
@@ -3,12 +3,13 @@ import { getNonIdleUserFilter, getUserFilter } from '../memcmp';
|
|
|
3
3
|
import { WebSocketProgramAccountSubscriber } from '../accounts/webSocketProgramAccountSubscriber';
|
|
4
4
|
import { UserAccount } from '../types';
|
|
5
5
|
import { Commitment, Context, PublicKey } from '@solana/web3.js';
|
|
6
|
+
import { ResubOpts } from '../accounts/types';
|
|
6
7
|
|
|
7
8
|
export class WebsocketSubscription {
|
|
8
9
|
private orderSubscriber: OrderSubscriber;
|
|
9
10
|
private commitment: Commitment;
|
|
10
11
|
private skipInitialLoad: boolean;
|
|
11
|
-
private
|
|
12
|
+
private resubOpts?: ResubOpts;
|
|
12
13
|
private resyncIntervalMs?: number;
|
|
13
14
|
|
|
14
15
|
private subscriber?: WebSocketProgramAccountSubscriber<UserAccount>;
|
|
@@ -20,21 +21,21 @@ export class WebsocketSubscription {
|
|
|
20
21
|
orderSubscriber,
|
|
21
22
|
commitment,
|
|
22
23
|
skipInitialLoad = false,
|
|
23
|
-
|
|
24
|
+
resubOpts,
|
|
24
25
|
resyncIntervalMs,
|
|
25
26
|
decoded = true,
|
|
26
27
|
}: {
|
|
27
28
|
orderSubscriber: OrderSubscriber;
|
|
28
29
|
commitment: Commitment;
|
|
29
30
|
skipInitialLoad?: boolean;
|
|
30
|
-
|
|
31
|
+
resubOpts?: ResubOpts;
|
|
31
32
|
resyncIntervalMs?: number;
|
|
32
33
|
decoded?: boolean;
|
|
33
34
|
}) {
|
|
34
35
|
this.orderSubscriber = orderSubscriber;
|
|
35
36
|
this.commitment = commitment;
|
|
36
37
|
this.skipInitialLoad = skipInitialLoad;
|
|
37
|
-
this.
|
|
38
|
+
this.resubOpts = resubOpts;
|
|
38
39
|
this.resyncIntervalMs = resyncIntervalMs;
|
|
39
40
|
this.decoded = decoded;
|
|
40
41
|
}
|
|
@@ -53,7 +54,7 @@ export class WebsocketSubscription {
|
|
|
53
54
|
filters: [getUserFilter(), getNonIdleUserFilter()],
|
|
54
55
|
commitment: this.commitment,
|
|
55
56
|
},
|
|
56
|
-
this.
|
|
57
|
+
this.resubOpts
|
|
57
58
|
);
|
|
58
59
|
|
|
59
60
|
await this.subscriber.subscribe(
|
|
@@ -1,18 +1,30 @@
|
|
|
1
1
|
import fetch from 'node-fetch';
|
|
2
|
-
import {
|
|
2
|
+
import { HeliusPriorityLevel } from './heliusPriorityFeeMethod';
|
|
3
3
|
|
|
4
|
-
export type
|
|
4
|
+
export type DriftMarketInfo = {
|
|
5
|
+
marketType: string;
|
|
6
|
+
marketIndex: number;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export type DriftPriorityFeeLevels = {
|
|
10
|
+
[key in HeliusPriorityLevel]: number;
|
|
11
|
+
} & {
|
|
12
|
+
marketType: 'perp' | 'spot';
|
|
13
|
+
marketIndex: number;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export type DriftPriorityFeeResponse = DriftPriorityFeeLevels[];
|
|
5
17
|
|
|
6
18
|
export async function fetchDriftPriorityFee(
|
|
7
19
|
url: string,
|
|
8
20
|
marketTypes: string[],
|
|
9
|
-
|
|
21
|
+
marketIndexes: number[]
|
|
10
22
|
): Promise<DriftPriorityFeeResponse> {
|
|
11
23
|
try {
|
|
12
24
|
const response = await fetch(
|
|
13
25
|
`${url}/batchPriorityFees?marketType=${marketTypes.join(
|
|
14
26
|
','
|
|
15
|
-
)}&marketIndex=${
|
|
27
|
+
)}&marketIndex=${marketIndexes.join(',')}`
|
|
16
28
|
);
|
|
17
29
|
if (!response.ok) {
|
|
18
30
|
throw new Error(`HTTP error! status: ${response.status}`);
|
package/src/priorityFee/index.ts
CHANGED
|
@@ -4,6 +4,8 @@ export * from './ewmaStrategy';
|
|
|
4
4
|
export * from './maxOverSlotsStrategy';
|
|
5
5
|
export * from './maxStrategy';
|
|
6
6
|
export * from './priorityFeeSubscriber';
|
|
7
|
+
export * from './priorityFeeSubscriberMap';
|
|
7
8
|
export * from './solanaPriorityFeeMethod';
|
|
8
9
|
export * from './heliusPriorityFeeMethod';
|
|
10
|
+
export * from './driftPriorityFeeMethod';
|
|
9
11
|
export * from './types';
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Connection, PublicKey } from '@solana/web3.js';
|
|
2
2
|
import {
|
|
3
|
+
DEFAULT_PRIORITY_FEE_MAP_FREQUENCY_MS,
|
|
3
4
|
PriorityFeeMethod,
|
|
4
5
|
PriorityFeeStrategy,
|
|
5
6
|
PriorityFeeSubscriberConfig,
|
|
@@ -12,12 +13,10 @@ import {
|
|
|
12
13
|
HeliusPriorityLevel,
|
|
13
14
|
fetchHeliusPriorityFee,
|
|
14
15
|
} from './heliusPriorityFeeMethod';
|
|
15
|
-
import {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
marketIndex: number;
|
|
20
|
-
};
|
|
16
|
+
import {
|
|
17
|
+
fetchDriftPriorityFee,
|
|
18
|
+
DriftMarketInfo,
|
|
19
|
+
} from './driftPriorityFeeMethod';
|
|
21
20
|
|
|
22
21
|
export class PriorityFeeSubscriber {
|
|
23
22
|
connection: Connection;
|
|
@@ -46,7 +45,8 @@ export class PriorityFeeSubscriber {
|
|
|
46
45
|
|
|
47
46
|
public constructor(config: PriorityFeeSubscriberConfig) {
|
|
48
47
|
this.connection = config.connection;
|
|
49
|
-
this.frequencyMs =
|
|
48
|
+
this.frequencyMs =
|
|
49
|
+
config.frequencyMs ?? DEFAULT_PRIORITY_FEE_MAP_FREQUENCY_MS;
|
|
50
50
|
this.addresses = config.addresses
|
|
51
51
|
? config.addresses.map((address) => address.toBase58())
|
|
52
52
|
: [];
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DriftMarketInfo,
|
|
3
|
+
DriftPriorityFeeLevels,
|
|
4
|
+
DriftPriorityFeeResponse,
|
|
5
|
+
fetchDriftPriorityFee,
|
|
6
|
+
} from './driftPriorityFeeMethod';
|
|
7
|
+
import {
|
|
8
|
+
DEFAULT_PRIORITY_FEE_MAP_FREQUENCY_MS,
|
|
9
|
+
PriorityFeeSubscriberMapConfig,
|
|
10
|
+
} from './types';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* takes advantage of /batchPriorityFees endpoint from drift hosted priority fee service
|
|
14
|
+
*/
|
|
15
|
+
export class PriorityFeeSubscriberMap {
|
|
16
|
+
frequencyMs: number;
|
|
17
|
+
intervalId?: ReturnType<typeof setTimeout>;
|
|
18
|
+
|
|
19
|
+
driftMarkets?: DriftMarketInfo[];
|
|
20
|
+
driftPriorityFeeEndpoint?: string;
|
|
21
|
+
feesMap: Map<string, Map<number, DriftPriorityFeeLevels>>; // marketType -> marketIndex -> priority fee
|
|
22
|
+
|
|
23
|
+
public constructor(config: PriorityFeeSubscriberMapConfig) {
|
|
24
|
+
this.frequencyMs = config.frequencyMs;
|
|
25
|
+
this.frequencyMs =
|
|
26
|
+
config.frequencyMs ?? DEFAULT_PRIORITY_FEE_MAP_FREQUENCY_MS;
|
|
27
|
+
this.driftPriorityFeeEndpoint = config.driftPriorityFeeEndpoint;
|
|
28
|
+
this.driftMarkets = config.driftMarkets;
|
|
29
|
+
this.feesMap = new Map<string, Map<number, DriftPriorityFeeLevels>>();
|
|
30
|
+
this.feesMap.set('perp', new Map<number, DriftPriorityFeeLevels>());
|
|
31
|
+
this.feesMap.set('spot', new Map<number, DriftPriorityFeeLevels>());
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
private updateFeesMap(driftPriorityFeeResponse: DriftPriorityFeeResponse) {
|
|
35
|
+
driftPriorityFeeResponse.forEach((fee: DriftPriorityFeeLevels) => {
|
|
36
|
+
this.feesMap.get(fee.marketType)!.set(fee.marketIndex, fee);
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
public async subscribe(): Promise<void> {
|
|
41
|
+
if (this.intervalId) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
await this.load();
|
|
46
|
+
this.intervalId = setInterval(this.load.bind(this), this.frequencyMs);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
public async unsubscribe(): Promise<void> {
|
|
50
|
+
if (this.intervalId) {
|
|
51
|
+
clearInterval(this.intervalId);
|
|
52
|
+
this.intervalId = undefined;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
public async load(): Promise<void> {
|
|
57
|
+
try {
|
|
58
|
+
if (!this.driftMarkets) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
const fees = await fetchDriftPriorityFee(
|
|
62
|
+
this.driftPriorityFeeEndpoint!,
|
|
63
|
+
this.driftMarkets.map((m) => m.marketType),
|
|
64
|
+
this.driftMarkets.map((m) => m.marketIndex)
|
|
65
|
+
);
|
|
66
|
+
this.updateFeesMap(fees);
|
|
67
|
+
} catch (e) {
|
|
68
|
+
console.error('Error fetching drift priority fees', e);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
public updateMarketTypeAndIndex(driftMarkets: DriftMarketInfo[]) {
|
|
73
|
+
this.driftMarkets = driftMarkets;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
public getPriorityFees(
|
|
77
|
+
marketType: string,
|
|
78
|
+
marketIndex: number
|
|
79
|
+
): DriftPriorityFeeLevels | undefined {
|
|
80
|
+
return this.feesMap.get(marketType)?.get(marketIndex);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** Example usage:
|
|
85
|
+
async function main() {
|
|
86
|
+
const driftMarkets: DriftMarketInfo[] = [
|
|
87
|
+
{ marketType: 'perp', marketIndex: 0 },
|
|
88
|
+
{ marketType: 'perp', marketIndex: 1 },
|
|
89
|
+
{ marketType: 'spot', marketIndex: 2 }
|
|
90
|
+
];
|
|
91
|
+
|
|
92
|
+
const subscriber = new PriorityFeeSubscriberMap({
|
|
93
|
+
driftPriorityFeeEndpoint: 'https://dlob.drift.trade',
|
|
94
|
+
frequencyMs: 5000,
|
|
95
|
+
driftMarkets
|
|
96
|
+
});
|
|
97
|
+
await subscriber.subscribe();
|
|
98
|
+
|
|
99
|
+
for (let i = 0; i < 20; i++) {
|
|
100
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
101
|
+
driftMarkets.forEach(market => {
|
|
102
|
+
const fees = subscriber.getPriorityFees(market.marketType, market.marketIndex);
|
|
103
|
+
console.log(`Priority fees for ${market.marketType} market ${market.marketIndex}:`, fees);
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
await subscriber.unsubscribe();
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
main().catch(console.error);
|
|
112
|
+
*/
|
package/src/priorityFee/types.ts
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
import { Connection, PublicKey } from '@solana/web3.js';
|
|
2
2
|
import { SolanaPriorityFeeResponse } from './solanaPriorityFeeMethod';
|
|
3
3
|
import { HeliusPriorityFeeResponse } from './heliusPriorityFeeMethod';
|
|
4
|
-
import {
|
|
5
|
-
|
|
4
|
+
import {
|
|
5
|
+
DriftMarketInfo,
|
|
6
|
+
DriftPriorityFeeResponse,
|
|
7
|
+
} from './driftPriorityFeeMethod';
|
|
8
|
+
|
|
9
|
+
export const DEFAULT_PRIORITY_FEE_MAP_FREQUENCY_MS = 10_000;
|
|
6
10
|
|
|
7
11
|
export interface PriorityFeeStrategy {
|
|
8
12
|
// calculate the priority fee for a given set of samples.
|
|
@@ -25,7 +29,7 @@ export type PriorityFeeSubscriberConfig = {
|
|
|
25
29
|
/// rpc connection, optional if using priorityFeeMethod.HELIUS
|
|
26
30
|
connection?: Connection;
|
|
27
31
|
/// frequency to make RPC calls to update priority fee samples, in milliseconds
|
|
28
|
-
frequencyMs
|
|
32
|
+
frequencyMs?: number;
|
|
29
33
|
/// addresses you plan to write lock, used to determine priority fees
|
|
30
34
|
addresses?: PublicKey[];
|
|
31
35
|
/// drift market type and index, optionally provide at initialization time if using priorityFeeMethod.DRIFT
|
|
@@ -45,3 +49,12 @@ export type PriorityFeeSubscriberConfig = {
|
|
|
45
49
|
/// multiplier applied to priority fee before maxFeeMicroLamports, defaults to 1.0
|
|
46
50
|
priorityFeeMultiplier?: number;
|
|
47
51
|
};
|
|
52
|
+
|
|
53
|
+
export type PriorityFeeSubscriberMapConfig = {
|
|
54
|
+
/// frequency to make RPC calls to update priority fee samples, in milliseconds
|
|
55
|
+
frequencyMs?: number;
|
|
56
|
+
/// drift market type and associated market index to query
|
|
57
|
+
driftMarkets?: DriftMarketInfo[];
|
|
58
|
+
/// url for drift cached priority fee endpoint
|
|
59
|
+
driftPriorityFeeEndpoint: string;
|
|
60
|
+
};
|
package/src/tx/baseTxSender.ts
CHANGED
|
@@ -2,6 +2,7 @@ import {
|
|
|
2
2
|
ConfirmationStrategy,
|
|
3
3
|
ExtraConfirmationOptions,
|
|
4
4
|
TxSender,
|
|
5
|
+
TxSendError,
|
|
5
6
|
TxSigAndSlot,
|
|
6
7
|
} from './types';
|
|
7
8
|
import {
|
|
@@ -25,6 +26,7 @@ import bs58 from 'bs58';
|
|
|
25
26
|
import { IWallet } from '../types';
|
|
26
27
|
|
|
27
28
|
const DEFAULT_TIMEOUT = 35000;
|
|
29
|
+
const NOT_CONFIRMED_ERROR_CODE = -1001;
|
|
28
30
|
|
|
29
31
|
export abstract class BaseTxSender implements TxSender {
|
|
30
32
|
connection: Connection;
|
|
@@ -282,10 +284,11 @@ export abstract class BaseTxSender implements TxSender {
|
|
|
282
284
|
}
|
|
283
285
|
this.timeoutCount += 1;
|
|
284
286
|
const duration = (Date.now() - start) / 1000;
|
|
285
|
-
throw new
|
|
287
|
+
throw new TxSendError(
|
|
286
288
|
`Transaction was not confirmed in ${duration.toFixed(
|
|
287
289
|
2
|
|
288
|
-
)} seconds. It is unknown if it succeeded or failed. Check signature ${signature} using the Solana Explorer or CLI tools
|
|
290
|
+
)} seconds. It is unknown if it succeeded or failed. Check signature ${signature} using the Solana Explorer or CLI tools.`,
|
|
291
|
+
NOT_CONFIRMED_ERROR_CODE
|
|
289
292
|
);
|
|
290
293
|
}
|
|
291
294
|
|
|
@@ -317,10 +320,11 @@ export abstract class BaseTxSender implements TxSender {
|
|
|
317
320
|
// Transaction not confirmed within 30 seconds
|
|
318
321
|
this.timeoutCount += 1;
|
|
319
322
|
const duration = (Date.now() - start) / 1000;
|
|
320
|
-
throw new
|
|
323
|
+
throw new TxSendError(
|
|
321
324
|
`Transaction was not confirmed in ${duration.toFixed(
|
|
322
325
|
2
|
|
323
|
-
)} seconds. It is unknown if it succeeded or failed. Check signature ${signature} using the Solana Explorer or CLI tools
|
|
326
|
+
)} seconds. It is unknown if it succeeded or failed. Check signature ${signature} using the Solana Explorer or CLI tools.`,
|
|
327
|
+
NOT_CONFIRMED_ERROR_CODE
|
|
324
328
|
);
|
|
325
329
|
}
|
|
326
330
|
|
|
@@ -29,6 +29,7 @@ export class FastSingleTxSender extends BaseTxSender {
|
|
|
29
29
|
recentBlockhash: string;
|
|
30
30
|
skipConfirmation: boolean;
|
|
31
31
|
blockhashCommitment: Commitment;
|
|
32
|
+
blockhashIntervalId: NodeJS.Timer;
|
|
32
33
|
|
|
33
34
|
public constructor({
|
|
34
35
|
connection,
|
|
@@ -71,15 +72,17 @@ export class FastSingleTxSender extends BaseTxSender {
|
|
|
71
72
|
}
|
|
72
73
|
|
|
73
74
|
startBlockhashRefreshLoop(): void {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
75
|
+
if (this.blockhashRefreshInterval > 0) {
|
|
76
|
+
this.blockhashIntervalId = setInterval(async () => {
|
|
77
|
+
try {
|
|
78
|
+
this.recentBlockhash = (
|
|
79
|
+
await this.connection.getLatestBlockhash(this.blockhashCommitment)
|
|
80
|
+
).blockhash;
|
|
81
|
+
} catch (e) {
|
|
82
|
+
console.error('Error in startBlockhashRefreshLoop: ', e);
|
|
83
|
+
}
|
|
84
|
+
}, this.blockhashRefreshInterval);
|
|
85
|
+
}
|
|
83
86
|
}
|
|
84
87
|
|
|
85
88
|
async prepareTx(
|
package/src/tx/types.ts
CHANGED
|
@@ -60,3 +60,15 @@ export interface TxSender {
|
|
|
60
60
|
|
|
61
61
|
getTimeoutCount(): number;
|
|
62
62
|
}
|
|
63
|
+
|
|
64
|
+
export class TxSendError extends Error {
|
|
65
|
+
constructor(
|
|
66
|
+
public message: string,
|
|
67
|
+
public code: number
|
|
68
|
+
) {
|
|
69
|
+
super(message);
|
|
70
|
+
if (Error.captureStackTrace) {
|
|
71
|
+
Error.captureStackTrace(this, TxSendError);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
package/src/tx/utils.ts
CHANGED
|
@@ -53,7 +53,11 @@ export async function getSignedTransactionMap(
|
|
|
53
53
|
});
|
|
54
54
|
|
|
55
55
|
const signedTxs = await wallet.signAllTransactions(
|
|
56
|
-
txsToSign
|
|
56
|
+
txsToSign
|
|
57
|
+
.map((tx) => {
|
|
58
|
+
return tx as Transaction;
|
|
59
|
+
})
|
|
60
|
+
.filter((tx) => tx !== undefined)
|
|
57
61
|
);
|
|
58
62
|
|
|
59
63
|
signedTxs.forEach((signedTx, index) => {
|