@drift-labs/sdk 2.83.0-beta.1 → 2.83.0-beta.11
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/adminClient.d.ts +2 -2
- package/lib/adminClient.js +7 -9
- package/lib/clock/clockSubscriber.d.ts +4 -2
- package/lib/clock/clockSubscriber.js +8 -2
- package/lib/decode/phoenix.d.ts +6 -0
- package/lib/decode/phoenix.js +159 -0
- package/lib/driftClient.d.ts +5 -2
- package/lib/driftClient.js +92 -47
- package/lib/idl/drift.json +63 -0
- package/lib/index.d.ts +1 -0
- package/lib/index.js +1 -0
- package/lib/math/auction.js +2 -2
- package/lib/math/market.js +4 -1
- package/lib/math/orders.js +1 -1
- package/lib/phoenix/phoenixSubscriber.d.ts +2 -0
- package/lib/phoenix/phoenixSubscriber.js +15 -2
- package/lib/priorityFee/priorityFeeSubscriber.js +1 -1
- package/lib/tx/baseTxSender.d.ts +5 -2
- package/lib/tx/baseTxSender.js +30 -1
- package/lib/tx/fastSingleTxSender.d.ts +1 -1
- package/lib/tx/fastSingleTxSender.js +1 -0
- package/lib/tx/forwardOnlyTxSender.d.ts +1 -1
- package/lib/tx/retryTxSender.d.ts +1 -1
- package/lib/tx/retryTxSender.js +1 -0
- package/lib/tx/txHandler.d.ts +2 -0
- package/lib/tx/txHandler.js +16 -9
- package/lib/tx/types.d.ts +2 -1
- package/lib/tx/whileValidTxSender.d.ts +1 -1
- package/lib/tx/whileValidTxSender.js +1 -0
- package/lib/types.d.ts +9 -0
- package/lib/types.js +6 -1
- package/lib/util/computeUnits.d.ts +7 -1
- package/lib/util/computeUnits.js +31 -1
- package/package.json +1 -1
- package/src/adminClient.ts +12 -10
- package/src/clock/clockSubscriber.ts +12 -4
- package/src/decode/phoenix.ts +207 -0
- package/src/driftClient.ts +188 -104
- package/src/idl/drift.json +63 -0
- package/src/index.ts +1 -0
- package/src/math/auction.ts +2 -2
- package/src/math/market.ts +4 -1
- package/src/math/orders.ts +5 -2
- package/src/phoenix/phoenixSubscriber.ts +15 -3
- package/src/priorityFee/priorityFeeSubscriber.ts +1 -1
- package/src/tx/baseTxSender.ts +59 -2
- package/src/tx/fastSingleTxSender.ts +2 -1
- package/src/tx/forwardOnlyTxSender.ts +1 -1
- package/src/tx/retryTxSender.ts +4 -1
- package/src/tx/txHandler.ts +19 -7
- package/src/tx/types.ts +11 -0
- package/src/tx/whileValidTxSender.ts +4 -1
- package/src/types.ts +6 -0
- package/src/util/computeUnits.ts +43 -1
- package/tests/decode/phoenix.ts +71 -0
package/src/math/orders.ts
CHANGED
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
Order,
|
|
8
8
|
PositionDirection,
|
|
9
9
|
} from '../types';
|
|
10
|
-
import { ZERO, TWO } from '../constants/numericConstants';
|
|
10
|
+
import { ZERO, TWO, ONE } from '../constants/numericConstants';
|
|
11
11
|
import { BN } from '@coral-xyz/anchor';
|
|
12
12
|
import { OraclePriceData } from '../oracles/types';
|
|
13
13
|
import {
|
|
@@ -160,7 +160,10 @@ export function getLimitPrice(
|
|
|
160
160
|
if (hasAuctionPrice(order, slot)) {
|
|
161
161
|
limitPrice = getAuctionPrice(order, slot, oraclePriceData.price);
|
|
162
162
|
} else if (order.oraclePriceOffset !== 0) {
|
|
163
|
-
limitPrice =
|
|
163
|
+
limitPrice = BN.max(
|
|
164
|
+
oraclePriceData.price.add(new BN(order.oraclePriceOffset)),
|
|
165
|
+
ONE
|
|
166
|
+
);
|
|
164
167
|
} else if (order.price.eq(ZERO)) {
|
|
165
168
|
limitPrice = fallbackPrice;
|
|
166
169
|
} else {
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
import { PRICE_PRECISION } from '../constants/numericConstants';
|
|
11
11
|
import { BN } from '@coral-xyz/anchor';
|
|
12
12
|
import { L2Level, L2OrderBookGenerator } from '../dlob/orderBookLevels';
|
|
13
|
+
import { fastDecode } from '../decode/phoenix';
|
|
13
14
|
|
|
14
15
|
export type PhoenixMarketSubscriberConfig = {
|
|
15
16
|
connection: Connection;
|
|
@@ -24,6 +25,7 @@ export type PhoenixMarketSubscriberConfig = {
|
|
|
24
25
|
| {
|
|
25
26
|
type: 'websocket';
|
|
26
27
|
};
|
|
28
|
+
fastDecode?: boolean;
|
|
27
29
|
};
|
|
28
30
|
|
|
29
31
|
export class PhoenixSubscriber implements L2OrderBookGenerator {
|
|
@@ -36,7 +38,8 @@ export class PhoenixSubscriber implements L2OrderBookGenerator {
|
|
|
36
38
|
market: Market;
|
|
37
39
|
marketCallbackId: string | number;
|
|
38
40
|
clockCallbackId: string | number;
|
|
39
|
-
|
|
41
|
+
// fastDecode omits trader data from the markets for faster decoding process
|
|
42
|
+
fastDecode: boolean;
|
|
40
43
|
subscribed: boolean;
|
|
41
44
|
lastSlot: number;
|
|
42
45
|
lastUnixTimestamp: number;
|
|
@@ -53,6 +56,7 @@ export class PhoenixSubscriber implements L2OrderBookGenerator {
|
|
|
53
56
|
}
|
|
54
57
|
this.lastSlot = 0;
|
|
55
58
|
this.lastUnixTimestamp = 0;
|
|
59
|
+
this.fastDecode = config.fastDecode ?? true;
|
|
56
60
|
}
|
|
57
61
|
|
|
58
62
|
public async subscribe(): Promise<void> {
|
|
@@ -76,7 +80,11 @@ export class PhoenixSubscriber implements L2OrderBookGenerator {
|
|
|
76
80
|
this.marketAddress,
|
|
77
81
|
(accountInfo, _ctx) => {
|
|
78
82
|
try {
|
|
79
|
-
|
|
83
|
+
if (this.fastDecode) {
|
|
84
|
+
this.market.data = fastDecode(accountInfo.data);
|
|
85
|
+
} else {
|
|
86
|
+
this.market = this.market.reload(accountInfo.data);
|
|
87
|
+
}
|
|
80
88
|
} catch {
|
|
81
89
|
console.error('Failed to reload Phoenix market data');
|
|
82
90
|
}
|
|
@@ -101,7 +109,11 @@ export class PhoenixSubscriber implements L2OrderBookGenerator {
|
|
|
101
109
|
try {
|
|
102
110
|
this.lastSlot = slot;
|
|
103
111
|
if (buffer) {
|
|
104
|
-
|
|
112
|
+
if (this.fastDecode) {
|
|
113
|
+
this.market.data = fastDecode(buffer);
|
|
114
|
+
} else {
|
|
115
|
+
this.market = this.market.reload(buffer);
|
|
116
|
+
}
|
|
105
117
|
}
|
|
106
118
|
} catch {
|
|
107
119
|
console.error('Failed to reload Phoenix market data');
|
|
@@ -96,8 +96,8 @@ export class PriorityFeeSubscriber {
|
|
|
96
96
|
return;
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
+
this.intervalId = setInterval(this.load.bind(this), this.frequencyMs); // we set the intervalId first, preventing a side effect of unsubscribing failing during the race condition where unsubscribes happens before subscribe is finished
|
|
99
100
|
await this.load();
|
|
100
|
-
this.intervalId = setInterval(this.load.bind(this), this.frequencyMs);
|
|
101
101
|
}
|
|
102
102
|
|
|
103
103
|
private async loadForSolana(): Promise<void> {
|
package/src/tx/baseTxSender.ts
CHANGED
|
@@ -15,6 +15,10 @@ import {
|
|
|
15
15
|
TransactionSignature,
|
|
16
16
|
Connection,
|
|
17
17
|
VersionedTransaction,
|
|
18
|
+
SendTransactionError,
|
|
19
|
+
TransactionInstruction,
|
|
20
|
+
AddressLookupTableAccount,
|
|
21
|
+
BlockhashWithExpiryBlockHeight,
|
|
18
22
|
} from '@solana/web3.js';
|
|
19
23
|
import { AnchorProvider } from '@coral-xyz/anchor';
|
|
20
24
|
import assert from 'assert';
|
|
@@ -53,7 +57,7 @@ export abstract class BaseTxSender implements TxSender {
|
|
|
53
57
|
additionalConnections?;
|
|
54
58
|
confirmationStrategy?: ConfirmationStrategy;
|
|
55
59
|
additionalTxSenderCallbacks?: ((base58EncodedTx: string) => void)[];
|
|
56
|
-
txHandler
|
|
60
|
+
txHandler?: TxHandler;
|
|
57
61
|
}) {
|
|
58
62
|
this.connection = connection;
|
|
59
63
|
this.wallet = wallet;
|
|
@@ -62,7 +66,13 @@ export abstract class BaseTxSender implements TxSender {
|
|
|
62
66
|
this.additionalConnections = additionalConnections;
|
|
63
67
|
this.confirmationStrategy = confirmationStrategy;
|
|
64
68
|
this.additionalTxSenderCallbacks = additionalTxSenderCallbacks;
|
|
65
|
-
this.txHandler =
|
|
69
|
+
this.txHandler =
|
|
70
|
+
txHandler ??
|
|
71
|
+
new TxHandler({
|
|
72
|
+
connection: this.connection,
|
|
73
|
+
wallet: this.wallet,
|
|
74
|
+
confirmationOptions: this.opts,
|
|
75
|
+
});
|
|
66
76
|
}
|
|
67
77
|
|
|
68
78
|
async send(
|
|
@@ -103,6 +113,21 @@ export abstract class BaseTxSender implements TxSender {
|
|
|
103
113
|
);
|
|
104
114
|
}
|
|
105
115
|
|
|
116
|
+
async getVersionedTransaction(
|
|
117
|
+
ixs: TransactionInstruction[],
|
|
118
|
+
lookupTableAccounts: AddressLookupTableAccount[],
|
|
119
|
+
_additionalSigners?: Array<Signer>,
|
|
120
|
+
opts?: ConfirmOptions,
|
|
121
|
+
blockhash?: BlockhashWithExpiryBlockHeight
|
|
122
|
+
): Promise<VersionedTransaction> {
|
|
123
|
+
return this.txHandler.generateVersionedTransaction(
|
|
124
|
+
blockhash,
|
|
125
|
+
ixs,
|
|
126
|
+
lookupTableAccounts,
|
|
127
|
+
this.wallet
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
|
|
106
131
|
async sendVersionedTransaction(
|
|
107
132
|
tx: VersionedTransaction,
|
|
108
133
|
additionalSigners?: Array<Signer>,
|
|
@@ -342,4 +367,36 @@ export abstract class BaseTxSender implements TxSender {
|
|
|
342
367
|
public getTimeoutCount(): number {
|
|
343
368
|
return this.timeoutCount;
|
|
344
369
|
}
|
|
370
|
+
|
|
371
|
+
public async checkConfirmationResultForError(
|
|
372
|
+
txSig: string,
|
|
373
|
+
result: RpcResponseAndContext<SignatureResult>
|
|
374
|
+
) {
|
|
375
|
+
if (result.value.err) {
|
|
376
|
+
await this.reportTransactionError(txSig);
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
public async reportTransactionError(txSig: string) {
|
|
383
|
+
const transactionResult = await this.connection.getTransaction(txSig, {
|
|
384
|
+
maxSupportedTransactionVersion: 0,
|
|
385
|
+
});
|
|
386
|
+
|
|
387
|
+
if (!transactionResult?.meta?.err) {
|
|
388
|
+
return undefined;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
const logs = transactionResult.meta.logMessages;
|
|
392
|
+
|
|
393
|
+
const lastLog = logs[logs.length - 1];
|
|
394
|
+
|
|
395
|
+
const friendlyMessage = lastLog?.match(/(failed:) (.+)/)?.[2];
|
|
396
|
+
|
|
397
|
+
throw new SendTransactionError(
|
|
398
|
+
`Transaction Failed${friendlyMessage ? `: ${friendlyMessage}` : ''}`,
|
|
399
|
+
transactionResult.meta.logMessages
|
|
400
|
+
);
|
|
401
|
+
}
|
|
345
402
|
}
|
|
@@ -48,7 +48,7 @@ export class FastSingleTxSender extends BaseTxSender {
|
|
|
48
48
|
skipConfirmation?: boolean;
|
|
49
49
|
blockhashCommitment?: Commitment;
|
|
50
50
|
confirmationStrategy?: ConfirmationStrategy;
|
|
51
|
-
txHandler
|
|
51
|
+
txHandler?: TxHandler;
|
|
52
52
|
}) {
|
|
53
53
|
super({
|
|
54
54
|
connection,
|
|
@@ -101,6 +101,7 @@ export class FastSingleTxSender extends BaseTxSender {
|
|
|
101
101
|
if (!this.skipConfirmation) {
|
|
102
102
|
try {
|
|
103
103
|
const result = await this.confirmTransaction(txid, opts.commitment);
|
|
104
|
+
await this.checkConfirmationResultForError(txid, result);
|
|
104
105
|
slot = result.context.slot;
|
|
105
106
|
} catch (e) {
|
|
106
107
|
console.error(e);
|
|
@@ -43,7 +43,7 @@ export class ForwardOnlyTxSender extends BaseTxSender {
|
|
|
43
43
|
retrySleep?: number;
|
|
44
44
|
confirmationStrategy?: ConfirmationStrategy;
|
|
45
45
|
additionalTxSenderCallbacks?: ((base58EncodedTx: string) => void)[];
|
|
46
|
-
txHandler
|
|
46
|
+
txHandler?: TxHandler;
|
|
47
47
|
}) {
|
|
48
48
|
super({
|
|
49
49
|
connection,
|
package/src/tx/retryTxSender.ts
CHANGED
|
@@ -40,7 +40,7 @@ export class RetryTxSender extends BaseTxSender {
|
|
|
40
40
|
additionalConnections?;
|
|
41
41
|
confirmationStrategy?: ConfirmationStrategy;
|
|
42
42
|
additionalTxSenderCallbacks?: ((base58EncodedTx: string) => void)[];
|
|
43
|
-
txHandler
|
|
43
|
+
txHandler?: TxHandler;
|
|
44
44
|
}) {
|
|
45
45
|
super({
|
|
46
46
|
connection,
|
|
@@ -105,6 +105,9 @@ export class RetryTxSender extends BaseTxSender {
|
|
|
105
105
|
let slot: number;
|
|
106
106
|
try {
|
|
107
107
|
const result = await this.confirmTransaction(txid, opts.commitment);
|
|
108
|
+
|
|
109
|
+
await this.checkConfirmationResultForError(txid, result);
|
|
110
|
+
|
|
108
111
|
slot = result.context.slot;
|
|
109
112
|
// eslint-disable-next-line no-useless-catch
|
|
110
113
|
} catch (e) {
|
package/src/tx/txHandler.ts
CHANGED
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
SignedTxData,
|
|
24
24
|
TxParams,
|
|
25
25
|
} from '../types';
|
|
26
|
+
import { containsComputeUnitIxs } from '../util/computeUnits';
|
|
26
27
|
|
|
27
28
|
export const COMPUTE_UNITS_DEFAULT = 200_000;
|
|
28
29
|
|
|
@@ -50,6 +51,7 @@ export class TxHandler {
|
|
|
50
51
|
private wallet: IWallet;
|
|
51
52
|
private confirmationOptions: ConfirmOptions;
|
|
52
53
|
|
|
54
|
+
private preSignedCb?: () => void;
|
|
53
55
|
private onSignedCb?: (txSigs: DriftClientMetricsEvents['txSigned']) => void;
|
|
54
56
|
|
|
55
57
|
constructor(props: {
|
|
@@ -59,6 +61,7 @@ export class TxHandler {
|
|
|
59
61
|
opts?: {
|
|
60
62
|
returnBlockHeightsWithSignedTxCallbackData?: boolean;
|
|
61
63
|
onSignedCb?: (txSigs: DriftClientMetricsEvents['txSigned']) => void;
|
|
64
|
+
preSignedCb?: () => void;
|
|
62
65
|
};
|
|
63
66
|
}) {
|
|
64
67
|
this.connection = props.connection;
|
|
@@ -69,6 +72,7 @@ export class TxHandler {
|
|
|
69
72
|
this.returnBlockHeightsWithSignedTxCallbackData =
|
|
70
73
|
props.opts?.returnBlockHeightsWithSignedTxCallbackData ?? false;
|
|
71
74
|
this.onSignedCb = props.opts?.onSignedCb;
|
|
75
|
+
this.preSignedCb = props.opts?.preSignedCb;
|
|
72
76
|
}
|
|
73
77
|
|
|
74
78
|
private addHashAndExpiryToLookup(
|
|
@@ -177,6 +181,8 @@ export class TxHandler {
|
|
|
177
181
|
tx.partialSign(kp);
|
|
178
182
|
});
|
|
179
183
|
|
|
184
|
+
this.preSignedCb?.();
|
|
185
|
+
|
|
180
186
|
const signedTx = await wallet.signTransaction(tx);
|
|
181
187
|
|
|
182
188
|
// Turn txSig Buffer into base58 string
|
|
@@ -213,6 +219,8 @@ export class TxHandler {
|
|
|
213
219
|
tx.sign([kp]);
|
|
214
220
|
});
|
|
215
221
|
|
|
222
|
+
this.preSignedCb?.();
|
|
223
|
+
|
|
216
224
|
//@ts-ignore
|
|
217
225
|
const signedTx = (await wallet.signTransaction(tx)) as VersionedTransaction;
|
|
218
226
|
|
|
@@ -406,10 +414,16 @@ export class TxHandler {
|
|
|
406
414
|
};
|
|
407
415
|
}
|
|
408
416
|
|
|
417
|
+
const instructionsArray = Array.isArray(instructions)
|
|
418
|
+
? instructions
|
|
419
|
+
: [instructions];
|
|
420
|
+
const { hasSetComputeUnitLimitIx, hasSetComputeUnitPriceIx } =
|
|
421
|
+
containsComputeUnitIxs(instructionsArray);
|
|
422
|
+
|
|
409
423
|
// # Create Tx Instructions
|
|
410
424
|
const allIx = [];
|
|
411
425
|
const computeUnits = baseTxParams?.computeUnits;
|
|
412
|
-
if (computeUnits
|
|
426
|
+
if (computeUnits > 0 && !hasSetComputeUnitLimitIx) {
|
|
413
427
|
allIx.push(
|
|
414
428
|
ComputeBudgetProgram.setComputeUnitLimit({
|
|
415
429
|
units: computeUnits,
|
|
@@ -419,7 +433,7 @@ export class TxHandler {
|
|
|
419
433
|
|
|
420
434
|
const computeUnitsPrice = baseTxParams?.computeUnitsPrice;
|
|
421
435
|
|
|
422
|
-
if (computeUnitsPrice
|
|
436
|
+
if (computeUnitsPrice > 0 && !hasSetComputeUnitPriceIx) {
|
|
423
437
|
allIx.push(
|
|
424
438
|
ComputeBudgetProgram.setComputeUnitPrice({
|
|
425
439
|
microLamports: computeUnitsPrice,
|
|
@@ -427,11 +441,7 @@ export class TxHandler {
|
|
|
427
441
|
);
|
|
428
442
|
}
|
|
429
443
|
|
|
430
|
-
|
|
431
|
-
allIx.push(...instructions);
|
|
432
|
-
} else {
|
|
433
|
-
allIx.push(instructions);
|
|
434
|
-
}
|
|
444
|
+
allIx.push(...instructionsArray);
|
|
435
445
|
|
|
436
446
|
const recentBlockHash =
|
|
437
447
|
props?.recentBlockHash ?? (await this.getLatestBlockhashForTransaction());
|
|
@@ -572,6 +582,8 @@ export class TxHandler {
|
|
|
572
582
|
}
|
|
573
583
|
});
|
|
574
584
|
|
|
585
|
+
this.preSignedCb?.();
|
|
586
|
+
|
|
575
587
|
const signedTxs = await wallet.signAllTransactions(
|
|
576
588
|
txsToSign
|
|
577
589
|
.map((tx) => {
|
package/src/tx/types.ts
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
|
+
AddressLookupTableAccount,
|
|
3
|
+
BlockhashWithExpiryBlockHeight,
|
|
2
4
|
ConfirmOptions,
|
|
3
5
|
Signer,
|
|
4
6
|
Transaction,
|
|
7
|
+
TransactionInstruction,
|
|
5
8
|
TransactionSignature,
|
|
6
9
|
VersionedTransaction,
|
|
7
10
|
} from '@solana/web3.js';
|
|
@@ -35,6 +38,14 @@ export interface TxSender {
|
|
|
35
38
|
preSigned?: boolean
|
|
36
39
|
): Promise<TxSigAndSlot>;
|
|
37
40
|
|
|
41
|
+
getVersionedTransaction(
|
|
42
|
+
ixs: TransactionInstruction[],
|
|
43
|
+
lookupTableAccounts: AddressLookupTableAccount[],
|
|
44
|
+
additionalSigners?: Array<Signer>,
|
|
45
|
+
opts?: ConfirmOptions,
|
|
46
|
+
blockhash?: BlockhashWithExpiryBlockHeight
|
|
47
|
+
): Promise<VersionedTransaction>;
|
|
48
|
+
|
|
38
49
|
sendRawTransaction(
|
|
39
50
|
rawTransaction: Buffer | Uint8Array,
|
|
40
51
|
opts: ConfirmOptions
|
|
@@ -50,7 +50,7 @@ export class WhileValidTxSender extends BaseTxSender {
|
|
|
50
50
|
additionalConnections?;
|
|
51
51
|
additionalTxSenderCallbacks?: ((base58EncodedTx: string) => void)[];
|
|
52
52
|
blockhashCommitment?: Commitment;
|
|
53
|
-
txHandler
|
|
53
|
+
txHandler?: TxHandler;
|
|
54
54
|
}) {
|
|
55
55
|
super({
|
|
56
56
|
connection,
|
|
@@ -190,6 +190,9 @@ export class WhileValidTxSender extends BaseTxSender {
|
|
|
190
190
|
},
|
|
191
191
|
opts.commitment
|
|
192
192
|
);
|
|
193
|
+
|
|
194
|
+
await this.checkConfirmationResultForError(txid, result);
|
|
195
|
+
|
|
193
196
|
slot = result.context.slot;
|
|
194
197
|
// eslint-disable-next-line no-useless-catch
|
|
195
198
|
} catch (e) {
|
package/src/types.ts
CHANGED
|
@@ -234,6 +234,11 @@ export class StakeAction {
|
|
|
234
234
|
static readonly STAKE_TRANSFER = { stakeTransfer: {} };
|
|
235
235
|
}
|
|
236
236
|
|
|
237
|
+
export class SettlePnlMode {
|
|
238
|
+
static readonly TRY_SETTLE = { trySettle: {} };
|
|
239
|
+
static readonly MUST_SETTLE = { mustSettle: {} };
|
|
240
|
+
}
|
|
241
|
+
|
|
237
242
|
export function isVariant(object: unknown, type: string) {
|
|
238
243
|
return object.hasOwnProperty(type);
|
|
239
244
|
}
|
|
@@ -1187,6 +1192,7 @@ export type HealthComponent = {
|
|
|
1187
1192
|
|
|
1188
1193
|
export interface DriftClientMetricsEvents {
|
|
1189
1194
|
txSigned: SignedTxData[];
|
|
1195
|
+
preTxSigned: void;
|
|
1190
1196
|
}
|
|
1191
1197
|
|
|
1192
1198
|
export type SignedTxData = {
|
package/src/util/computeUnits.ts
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
ComputeBudgetProgram,
|
|
3
|
+
Connection,
|
|
4
|
+
Finality,
|
|
5
|
+
PublicKey,
|
|
6
|
+
TransactionInstruction,
|
|
7
|
+
} from '@solana/web3.js';
|
|
2
8
|
|
|
3
9
|
export async function findComputeUnitConsumption(
|
|
4
10
|
programId: PublicKey,
|
|
@@ -19,3 +25,39 @@ export async function findComputeUnitConsumption(
|
|
|
19
25
|
});
|
|
20
26
|
return computeUnits;
|
|
21
27
|
}
|
|
28
|
+
|
|
29
|
+
export function isSetComputeUnitsIx(ix: TransactionInstruction): boolean {
|
|
30
|
+
// Compute budget program discriminator is first byte
|
|
31
|
+
// 2: set compute unit limit
|
|
32
|
+
// 3: set compute unit price
|
|
33
|
+
if (
|
|
34
|
+
ix.programId.equals(ComputeBudgetProgram.programId) &&
|
|
35
|
+
ix.data.at(0) === 2
|
|
36
|
+
) {
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function isSetComputeUnitPriceIx(ix: TransactionInstruction): boolean {
|
|
43
|
+
// Compute budget program discriminator is first byte
|
|
44
|
+
// 2: set compute unit limit
|
|
45
|
+
// 3: set compute unit price
|
|
46
|
+
if (
|
|
47
|
+
ix.programId.equals(ComputeBudgetProgram.programId) &&
|
|
48
|
+
ix.data.at(0) === 3
|
|
49
|
+
) {
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function containsComputeUnitIxs(ixs: TransactionInstruction[]): {
|
|
56
|
+
hasSetComputeUnitLimitIx: boolean;
|
|
57
|
+
hasSetComputeUnitPriceIx: boolean;
|
|
58
|
+
} {
|
|
59
|
+
return {
|
|
60
|
+
hasSetComputeUnitLimitIx: ixs.some(isSetComputeUnitsIx),
|
|
61
|
+
hasSetComputeUnitPriceIx: ixs.some(isSetComputeUnitPriceIx),
|
|
62
|
+
};
|
|
63
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { MarketData, deserializeMarketData } from '@ellipsis-labs/phoenix-sdk';
|
|
2
|
+
import { fastDecode } from '../../src/decode/phoenix';
|
|
3
|
+
import { Connection, PublicKey } from '@solana/web3.js';
|
|
4
|
+
import assert from 'assert';
|
|
5
|
+
|
|
6
|
+
describe('custom phoenix decode', function () {
|
|
7
|
+
this.timeout(100_000);
|
|
8
|
+
|
|
9
|
+
it('decodes quickly', async function () {
|
|
10
|
+
const connection = new Connection('https://api.mainnet-beta.solana.com');
|
|
11
|
+
|
|
12
|
+
const val = await connection.getAccountInfo(
|
|
13
|
+
new PublicKey('4DoNfFBfF7UokCC2FQzriy7yHK6DY6NVdYpuekQ5pRgg')
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
const numIterations = 100;
|
|
17
|
+
|
|
18
|
+
let regularDecoded: MarketData;
|
|
19
|
+
const regularStart = performance.now();
|
|
20
|
+
for (let i = 0; i < numIterations; i++) {
|
|
21
|
+
regularDecoded = deserializeMarketData(val!.data);
|
|
22
|
+
}
|
|
23
|
+
const regularEnd = performance.now();
|
|
24
|
+
|
|
25
|
+
let fastDecoded: MarketData;
|
|
26
|
+
const fastStart = performance.now();
|
|
27
|
+
for (let i = 0; i < numIterations; i++) {
|
|
28
|
+
fastDecoded = fastDecode(val!.data);
|
|
29
|
+
}
|
|
30
|
+
const fastEnd = performance.now();
|
|
31
|
+
|
|
32
|
+
console.log(`Regular: ${regularEnd - regularStart} ms`);
|
|
33
|
+
console.log(
|
|
34
|
+
`Regular avg: ${(regularEnd - regularStart) / numIterations} ms`
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
console.log(`Fast: ${fastEnd - fastStart} ms`);
|
|
38
|
+
console.log(`Fast avg: ${(fastEnd - fastStart) / numIterations} ms`);
|
|
39
|
+
|
|
40
|
+
// @ts-ignore
|
|
41
|
+
assert(deepEqual(fastDecoded.bids, regularDecoded.bids));
|
|
42
|
+
// @ts-ignore
|
|
43
|
+
assert(deepEqual(regularDecoded.asks, fastDecoded.asks));
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
function deepEqual(obj1: any, obj2: any) {
|
|
48
|
+
if (obj1 === obj2) return true;
|
|
49
|
+
|
|
50
|
+
if (
|
|
51
|
+
obj1 == null ||
|
|
52
|
+
obj2 == null ||
|
|
53
|
+
typeof obj1 !== 'object' ||
|
|
54
|
+
typeof obj2 !== 'object'
|
|
55
|
+
) {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const keys1 = Object.keys(obj1);
|
|
60
|
+
const keys2 = Object.keys(obj2);
|
|
61
|
+
|
|
62
|
+
if (keys1.length !== keys2.length) return false;
|
|
63
|
+
|
|
64
|
+
for (const key of keys1) {
|
|
65
|
+
if (!keys2.includes(key) || !deepEqual(obj1[key], obj2[key])) {
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return true;
|
|
71
|
+
}
|