@drift-labs/sdk 2.54.0-beta.1 → 2.54.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/VERSION +1 -1
- package/lib/accounts/pollingInsuranceFundStakeAccountSubscriber.js +0 -1
- package/lib/constants/perpMarkets.js +20 -0
- package/lib/driftClient.d.ts +8 -2
- package/lib/driftClient.js +95 -20
- package/lib/events/webSocketLogProvider.js +3 -0
- package/lib/idl/drift.json +7 -1
- package/lib/jupiter/jupiterClient.d.ts +6 -0
- package/lib/jupiter/jupiterClient.js +2 -2
- package/lib/math/funding.js +24 -1
- package/lib/math/oracles.js +2 -2
- package/lib/math/superStake.d.ts +51 -0
- package/lib/math/superStake.js +10 -2
- package/lib/priorityFee/averageOverSlotsStrategy.d.ts +0 -5
- package/lib/priorityFee/averageOverSlotsStrategy.js +1 -13
- package/lib/priorityFee/maxOverSlotsStrategy.d.ts +0 -5
- package/lib/priorityFee/maxOverSlotsStrategy.js +1 -13
- package/lib/priorityFee/priorityFeeSubscriber.d.ts +5 -4
- package/lib/priorityFee/priorityFeeSubscriber.js +15 -21
- package/lib/tx/baseTxSender.js +2 -2
- package/lib/tx/retryTxSender.js +4 -21
- package/lib/tx/utils.d.ts +5 -1
- package/lib/tx/utils.js +20 -1
- package/lib/userMap/userMap.js +4 -0
- package/package.json +1 -1
- package/src/accounts/pollingInsuranceFundStakeAccountSubscriber.ts +0 -1
- package/src/constants/perpMarkets.ts +20 -0
- package/src/driftClient.ts +197 -39
- package/src/events/webSocketLogProvider.ts +11 -2
- package/src/idl/drift.json +7 -1
- package/src/jupiter/jupiterClient.ts +8 -2
- package/src/math/funding.ts +28 -1
- package/src/math/oracles.ts +2 -2
- package/src/math/superStake.ts +60 -1
- package/src/priorityFee/averageOverSlotsStrategy.ts +1 -16
- package/src/priorityFee/maxOverSlotsStrategy.ts +1 -16
- package/src/priorityFee/priorityFeeSubscriber.ts +22 -26
- package/src/tx/baseTxSender.ts +3 -2
- package/src/tx/retryTxSender.ts +5 -23
- package/src/tx/utils.ts +32 -0
- package/src/userMap/userMap.ts +3 -0
- package/tests/amm/test.ts +275 -2
- package/tests/dlob/test.ts +2 -2
- package/tests/tx/priorityFeeStrategy.ts +2 -2
package/lib/tx/baseTxSender.js
CHANGED
|
@@ -158,14 +158,14 @@ class BaseTxSender {
|
|
|
158
158
|
async confirmTransactionPolling(signature, commitment = 'finalized') {
|
|
159
159
|
var _a;
|
|
160
160
|
let totalTime = 0;
|
|
161
|
-
let backoffTime =
|
|
161
|
+
let backoffTime = 400; // approx block time
|
|
162
162
|
while (totalTime < this.timeout) {
|
|
163
|
+
await new Promise((resolve) => setTimeout(resolve, backoffTime));
|
|
163
164
|
const response = await this.connection.getSignatureStatus(signature);
|
|
164
165
|
const result = response && ((_a = response.value) === null || _a === void 0 ? void 0 : _a[0]);
|
|
165
166
|
if (result && result.confirmationStatus === commitment) {
|
|
166
167
|
return { context: result.context, value: { err: null } };
|
|
167
168
|
}
|
|
168
|
-
await new Promise((resolve) => setTimeout(resolve, backoffTime));
|
|
169
169
|
totalTime += backoffTime;
|
|
170
170
|
backoffTime = Math.min(backoffTime * 2, 5000);
|
|
171
171
|
}
|
package/lib/tx/retryTxSender.js
CHANGED
|
@@ -32,15 +32,8 @@ class RetryTxSender extends baseTxSender_1.BaseTxSender {
|
|
|
32
32
|
}
|
|
33
33
|
async sendRawTransaction(rawTransaction, opts) {
|
|
34
34
|
const startTime = this.getTimestamp();
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
txid = await this.connection.sendRawTransaction(rawTransaction, opts);
|
|
38
|
-
this.sendToAdditionalConnections(rawTransaction, opts);
|
|
39
|
-
}
|
|
40
|
-
catch (e) {
|
|
41
|
-
console.error(e);
|
|
42
|
-
throw e;
|
|
43
|
-
}
|
|
35
|
+
const txid = await this.connection.sendRawTransaction(rawTransaction, opts);
|
|
36
|
+
this.sendToAdditionalConnections(rawTransaction, opts);
|
|
44
37
|
let done = false;
|
|
45
38
|
const resolveReference = {
|
|
46
39
|
resolve: undefined,
|
|
@@ -65,18 +58,8 @@ class RetryTxSender extends baseTxSender_1.BaseTxSender {
|
|
|
65
58
|
}
|
|
66
59
|
}
|
|
67
60
|
})();
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
const result = await this.confirmTransaction(txid, opts.commitment);
|
|
71
|
-
slot = result.context.slot;
|
|
72
|
-
}
|
|
73
|
-
catch (e) {
|
|
74
|
-
console.error(e);
|
|
75
|
-
throw e;
|
|
76
|
-
}
|
|
77
|
-
finally {
|
|
78
|
-
stopWaiting();
|
|
79
|
-
}
|
|
61
|
+
const result = await this.confirmTransaction(txid, opts.commitment);
|
|
62
|
+
const slot = result.context.slot;
|
|
80
63
|
return { txSig: txid, slot };
|
|
81
64
|
}
|
|
82
65
|
}
|
package/lib/tx/utils.d.ts
CHANGED
|
@@ -1,2 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Wallet } from '@coral-xyz/anchor';
|
|
2
|
+
import { Transaction, TransactionInstruction, VersionedTransaction } from '@solana/web3.js';
|
|
2
3
|
export declare function wrapInTx(instruction: TransactionInstruction, computeUnits?: number, computeUnitsPrice?: number): Transaction;
|
|
4
|
+
export declare function getSignedTransactionMap(wallet: Wallet, txsToSign: (Transaction | VersionedTransaction | undefined)[], keys: string[]): Promise<{
|
|
5
|
+
[key: string]: Transaction | VersionedTransaction | undefined;
|
|
6
|
+
}>;
|
package/lib/tx/utils.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.wrapInTx = void 0;
|
|
3
|
+
exports.getSignedTransactionMap = exports.wrapInTx = void 0;
|
|
4
4
|
const web3_js_1 = require("@solana/web3.js");
|
|
5
5
|
const COMPUTE_UNITS_DEFAULT = 200000;
|
|
6
6
|
function wrapInTx(instruction, computeUnits = 600000, computeUnitsPrice = 0) {
|
|
@@ -18,3 +18,22 @@ function wrapInTx(instruction, computeUnits = 600000, computeUnitsPrice = 0) {
|
|
|
18
18
|
return tx.add(instruction);
|
|
19
19
|
}
|
|
20
20
|
exports.wrapInTx = wrapInTx;
|
|
21
|
+
/* Helper function for signing multiple transactions where some may be undefined and mapping the output */
|
|
22
|
+
async function getSignedTransactionMap(wallet, txsToSign, keys) {
|
|
23
|
+
const signedTxMap = {};
|
|
24
|
+
const keysWithTx = [];
|
|
25
|
+
txsToSign.forEach((tx, index) => {
|
|
26
|
+
if (tx == undefined) {
|
|
27
|
+
signedTxMap[keys[index]] = undefined;
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
keysWithTx.push(keys[index]);
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
const signedTxs = await wallet.signAllTransactions(txsToSign.filter((tx) => tx !== undefined));
|
|
34
|
+
signedTxs.forEach((signedTx, index) => {
|
|
35
|
+
signedTxMap[keysWithTx[index]] = signedTx;
|
|
36
|
+
});
|
|
37
|
+
return signedTxMap;
|
|
38
|
+
}
|
|
39
|
+
exports.getSignedTransactionMap = getSignedTransactionMap;
|
package/lib/userMap/userMap.js
CHANGED
|
@@ -236,6 +236,10 @@ class UserMap {
|
|
|
236
236
|
await this.addPubkey(new web3_js_1.PublicKey(key), userAccount);
|
|
237
237
|
this.userMap.get(key).accountSubscriber.updateData(userAccount, slot);
|
|
238
238
|
}
|
|
239
|
+
else {
|
|
240
|
+
const userAccount = this.decode('User', buffer);
|
|
241
|
+
this.userMap.get(key).accountSubscriber.updateData(userAccount, slot);
|
|
242
|
+
}
|
|
239
243
|
// give event loop a chance to breathe
|
|
240
244
|
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
241
245
|
}
|
package/package.json
CHANGED
|
@@ -234,6 +234,16 @@ export const DevnetPerpMarkets: PerpMarketConfig[] = [
|
|
|
234
234
|
launchTs: 1703173331000,
|
|
235
235
|
oracleSource: OracleSource.PYTH,
|
|
236
236
|
},
|
|
237
|
+
{
|
|
238
|
+
fullName: 'AVAX',
|
|
239
|
+
category: ['Rollup', 'Infra'],
|
|
240
|
+
symbol: 'AVAX-PERP',
|
|
241
|
+
baseAssetSymbol: 'AVAX',
|
|
242
|
+
marketIndex: 22,
|
|
243
|
+
oracle: new PublicKey('FVb5h1VmHPfVb1RfqZckchq18GxRv4iKt8T4eVTQAqdz'),
|
|
244
|
+
launchTs: 1704209558000,
|
|
245
|
+
oracleSource: OracleSource.PYTH,
|
|
246
|
+
},
|
|
237
247
|
];
|
|
238
248
|
|
|
239
249
|
export const MainnetPerpMarkets: PerpMarketConfig[] = [
|
|
@@ -457,6 +467,16 @@ export const MainnetPerpMarkets: PerpMarketConfig[] = [
|
|
|
457
467
|
launchTs: 1703173331000,
|
|
458
468
|
oracleSource: OracleSource.PYTH,
|
|
459
469
|
},
|
|
470
|
+
{
|
|
471
|
+
fullName: 'AVAX',
|
|
472
|
+
category: ['Rollup', 'Infra'],
|
|
473
|
+
symbol: 'AVAX-PERP',
|
|
474
|
+
baseAssetSymbol: 'AVAX',
|
|
475
|
+
marketIndex: 22,
|
|
476
|
+
oracle: new PublicKey('Ax9ujW5B9oqcv59N8m6f1BpTBq2rGeGaBcpKjC5UYsXU'),
|
|
477
|
+
launchTs: 1704209558000,
|
|
478
|
+
oracleSource: OracleSource.PYTH,
|
|
479
|
+
},
|
|
460
480
|
];
|
|
461
481
|
|
|
462
482
|
export const PerpMarkets: { [key in DriftEnv]: PerpMarketConfig[] } = {
|
package/src/driftClient.ts
CHANGED
|
@@ -88,7 +88,7 @@ import {
|
|
|
88
88
|
DataAndSlot,
|
|
89
89
|
} from './accounts/types';
|
|
90
90
|
import { TxSender, TxSigAndSlot } from './tx/types';
|
|
91
|
-
import { wrapInTx } from './tx/utils';
|
|
91
|
+
import { getSignedTransactionMap, wrapInTx } from './tx/utils';
|
|
92
92
|
import {
|
|
93
93
|
BASE_PRECISION,
|
|
94
94
|
PRICE_PRECISION,
|
|
@@ -2565,33 +2565,26 @@ export class DriftClient {
|
|
|
2565
2565
|
txParams?: TxParams,
|
|
2566
2566
|
bracketOrdersParams = new Array<OptionalOrderParams>(),
|
|
2567
2567
|
referrerInfo?: ReferrerInfo,
|
|
2568
|
-
cancelExistingOrders?: boolean
|
|
2568
|
+
cancelExistingOrders?: boolean,
|
|
2569
|
+
settlePnl?: boolean
|
|
2569
2570
|
): Promise<{
|
|
2570
2571
|
txSig: TransactionSignature;
|
|
2571
2572
|
signedFillTx?: Transaction;
|
|
2572
2573
|
signedCancelExistingOrdersTx?: Transaction;
|
|
2574
|
+
signedSettlePnlTx?: Transaction;
|
|
2573
2575
|
}> {
|
|
2574
2576
|
const marketIndex = orderParams.marketIndex;
|
|
2575
2577
|
const orderId = userAccount.nextOrderId;
|
|
2576
|
-
const bracketOrderIxs = [];
|
|
2577
2578
|
|
|
2578
|
-
const
|
|
2579
|
-
orderParams,
|
|
2579
|
+
const ordersIx = await this.getPlaceOrdersIx(
|
|
2580
|
+
[orderParams, ...bracketOrdersParams],
|
|
2580
2581
|
userAccount.subAccountId
|
|
2581
2582
|
);
|
|
2582
2583
|
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
bracketOrderParams,
|
|
2586
|
-
userAccount.subAccountId
|
|
2587
|
-
);
|
|
2588
|
-
bracketOrderIxs.push(placeBracketOrderIx);
|
|
2589
|
-
}
|
|
2590
|
-
|
|
2591
|
-
let cancelOrdersIx: TransactionInstruction;
|
|
2592
|
-
let cancelExistingOrdersTx: Transaction;
|
|
2584
|
+
/* Cancel open orders in market if requested */
|
|
2585
|
+
let cancelExistingOrdersTx;
|
|
2593
2586
|
if (cancelExistingOrders && isVariant(orderParams.marketType, 'perp')) {
|
|
2594
|
-
cancelOrdersIx = await this.getCancelOrdersIx(
|
|
2587
|
+
const cancelOrdersIx = await this.getCancelOrdersIx(
|
|
2595
2588
|
orderParams.marketType,
|
|
2596
2589
|
orderParams.marketIndex,
|
|
2597
2590
|
null,
|
|
@@ -2606,10 +2599,27 @@ export class DriftClient {
|
|
|
2606
2599
|
);
|
|
2607
2600
|
}
|
|
2608
2601
|
|
|
2602
|
+
/* Settle PnL after fill if requested */
|
|
2603
|
+
let settlePnlTx;
|
|
2604
|
+
if (settlePnl && isVariant(orderParams.marketType, 'perp')) {
|
|
2605
|
+
const settlePnlIx = await this.settlePNLIx(
|
|
2606
|
+
userAccountPublicKey,
|
|
2607
|
+
userAccount,
|
|
2608
|
+
marketIndex
|
|
2609
|
+
);
|
|
2610
|
+
|
|
2611
|
+
//@ts-ignore
|
|
2612
|
+
settlePnlTx = await this.buildTransaction(
|
|
2613
|
+
[settlePnlIx],
|
|
2614
|
+
txParams,
|
|
2615
|
+
this.txVersion
|
|
2616
|
+
);
|
|
2617
|
+
}
|
|
2618
|
+
|
|
2609
2619
|
// use versioned transactions if there is a lookup table account and wallet is compatible
|
|
2610
2620
|
if (this.txVersion === 0) {
|
|
2611
2621
|
const versionedMarketOrderTx = await this.buildTransaction(
|
|
2612
|
-
|
|
2622
|
+
ordersIx,
|
|
2613
2623
|
txParams,
|
|
2614
2624
|
0
|
|
2615
2625
|
);
|
|
@@ -2632,17 +2642,31 @@ export class DriftClient {
|
|
|
2632
2642
|
0
|
|
2633
2643
|
);
|
|
2634
2644
|
|
|
2635
|
-
const [
|
|
2645
|
+
const allPossibleTxs = [
|
|
2646
|
+
versionedMarketOrderTx,
|
|
2647
|
+
versionedFillTx,
|
|
2648
|
+
cancelExistingOrdersTx,
|
|
2649
|
+
settlePnlTx,
|
|
2650
|
+
];
|
|
2651
|
+
const txKeys = [
|
|
2652
|
+
'signedVersionedMarketOrderTx',
|
|
2653
|
+
'signedVersionedFillTx',
|
|
2654
|
+
'signedCancelExistingOrdersTx',
|
|
2655
|
+
'signedSettlePnlTx',
|
|
2656
|
+
];
|
|
2657
|
+
|
|
2658
|
+
const {
|
|
2636
2659
|
signedVersionedMarketOrderTx,
|
|
2637
2660
|
signedVersionedFillTx,
|
|
2638
2661
|
signedCancelExistingOrdersTx,
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
2662
|
+
signedSettlePnlTx,
|
|
2663
|
+
} = await getSignedTransactionMap(
|
|
2664
|
+
//@ts-ignore
|
|
2665
|
+
this.provider.wallet,
|
|
2666
|
+
allPossibleTxs,
|
|
2667
|
+
txKeys
|
|
2645
2668
|
);
|
|
2669
|
+
|
|
2646
2670
|
const { txSig, slot } = await this.txSender.sendRawTransaction(
|
|
2647
2671
|
signedVersionedMarketOrderTx.serialize(),
|
|
2648
2672
|
this.opts
|
|
@@ -2655,18 +2679,16 @@ export class DriftClient {
|
|
|
2655
2679
|
signedFillTx: signedVersionedFillTx,
|
|
2656
2680
|
// @ts-ignore
|
|
2657
2681
|
signedCancelExistingOrdersTx,
|
|
2682
|
+
// @ts-ignore
|
|
2683
|
+
signedSettlePnlTx,
|
|
2658
2684
|
};
|
|
2659
2685
|
} else {
|
|
2660
2686
|
const marketOrderTx = wrapInTx(
|
|
2661
|
-
|
|
2687
|
+
ordersIx,
|
|
2662
2688
|
txParams?.computeUnits,
|
|
2663
2689
|
txParams?.computeUnitsPrice
|
|
2664
2690
|
);
|
|
2665
2691
|
|
|
2666
|
-
if (bracketOrderIxs.length > 0) {
|
|
2667
|
-
marketOrderTx.add(...bracketOrderIxs);
|
|
2668
|
-
}
|
|
2669
|
-
|
|
2670
2692
|
// Apply the latest blockhash to the txs so that we can sign before sending them
|
|
2671
2693
|
const currentBlockHash = (
|
|
2672
2694
|
await this.connection.getLatestBlockhash('finalized')
|
|
@@ -2680,12 +2702,33 @@ export class DriftClient {
|
|
|
2680
2702
|
cancelExistingOrdersTx.feePayer = userAccount.authority;
|
|
2681
2703
|
}
|
|
2682
2704
|
|
|
2683
|
-
|
|
2684
|
-
|
|
2685
|
-
|
|
2686
|
-
|
|
2687
|
-
|
|
2688
|
-
|
|
2705
|
+
if (settlePnlTx) {
|
|
2706
|
+
settlePnlTx.recentBlockhash = currentBlockHash;
|
|
2707
|
+
settlePnlTx.feePayer = userAccount.authority;
|
|
2708
|
+
}
|
|
2709
|
+
|
|
2710
|
+
const allPossibleTxs = [
|
|
2711
|
+
marketOrderTx,
|
|
2712
|
+
cancelExistingOrdersTx,
|
|
2713
|
+
settlePnlTx,
|
|
2714
|
+
];
|
|
2715
|
+
const txKeys = [
|
|
2716
|
+
'signedMarketOrderTx',
|
|
2717
|
+
'signedCancelExistingOrdersTx',
|
|
2718
|
+
'signedSettlePnlTx',
|
|
2719
|
+
];
|
|
2720
|
+
|
|
2721
|
+
const {
|
|
2722
|
+
signedMarketOrderTx,
|
|
2723
|
+
signedCancelExistingOrdersTx,
|
|
2724
|
+
signedSettlePnlTx,
|
|
2725
|
+
} = await getSignedTransactionMap(
|
|
2726
|
+
//@ts-ignore
|
|
2727
|
+
this.provider.wallet,
|
|
2728
|
+
allPossibleTxs,
|
|
2729
|
+
txKeys
|
|
2730
|
+
);
|
|
2731
|
+
|
|
2689
2732
|
const { txSig, slot } = await this.sendTransaction(
|
|
2690
2733
|
signedMarketOrderTx,
|
|
2691
2734
|
[],
|
|
@@ -2694,7 +2737,14 @@ export class DriftClient {
|
|
|
2694
2737
|
);
|
|
2695
2738
|
this.perpMarketLastSlotCache.set(orderParams.marketIndex, slot);
|
|
2696
2739
|
|
|
2697
|
-
return {
|
|
2740
|
+
return {
|
|
2741
|
+
txSig,
|
|
2742
|
+
signedFillTx: undefined,
|
|
2743
|
+
//@ts-ignore
|
|
2744
|
+
signedCancelExistingOrdersTx,
|
|
2745
|
+
//@ts-ignore
|
|
2746
|
+
signedSettlePnlTx,
|
|
2747
|
+
};
|
|
2698
2748
|
}
|
|
2699
2749
|
}
|
|
2700
2750
|
|
|
@@ -3093,7 +3143,7 @@ export class DriftClient {
|
|
|
3093
3143
|
}
|
|
3094
3144
|
|
|
3095
3145
|
public async getPlaceOrdersIx(
|
|
3096
|
-
params:
|
|
3146
|
+
params: OptionalOrderParams[],
|
|
3097
3147
|
subAccountId?: number
|
|
3098
3148
|
): Promise<TransactionInstruction> {
|
|
3099
3149
|
const user = await this.getUserAccountPublicKey(subAccountId);
|
|
@@ -3118,7 +3168,9 @@ export class DriftClient {
|
|
|
3118
3168
|
useMarketLastSlotCache: true,
|
|
3119
3169
|
});
|
|
3120
3170
|
|
|
3121
|
-
|
|
3171
|
+
const formattedParams = params.map((item) => getOrderParams(item));
|
|
3172
|
+
|
|
3173
|
+
return await this.program.instruction.placeOrders(formattedParams, {
|
|
3122
3174
|
accounts: {
|
|
3123
3175
|
state: await this.getStatePublicKey(),
|
|
3124
3176
|
user,
|
|
@@ -3868,7 +3920,6 @@ export class DriftClient {
|
|
|
3868
3920
|
slippageBps,
|
|
3869
3921
|
swapMode,
|
|
3870
3922
|
onlyDirectRoutes,
|
|
3871
|
-
excludeDexes: ['Raydium CLMM'], // temp exclude to workaround bug with raydium clmm
|
|
3872
3923
|
});
|
|
3873
3924
|
|
|
3874
3925
|
quote = fetchedQuote;
|
|
@@ -4335,6 +4386,113 @@ export class DriftClient {
|
|
|
4335
4386
|
return txSig;
|
|
4336
4387
|
}
|
|
4337
4388
|
|
|
4389
|
+
public async placeAndTakePerpWithAdditionalOrders(
|
|
4390
|
+
orderParams: OptionalOrderParams,
|
|
4391
|
+
makerInfo?: MakerInfo | MakerInfo[],
|
|
4392
|
+
referrerInfo?: ReferrerInfo,
|
|
4393
|
+
bracketOrdersParams = new Array<OptionalOrderParams>(),
|
|
4394
|
+
txParams?: TxParams,
|
|
4395
|
+
subAccountId?: number,
|
|
4396
|
+
cancelExistingOrders?: boolean,
|
|
4397
|
+
settlePnl?: boolean
|
|
4398
|
+
): Promise<{
|
|
4399
|
+
txSig: TransactionSignature;
|
|
4400
|
+
signedCancelExistingOrdersTx?: Transaction;
|
|
4401
|
+
signedSettlePnlTx?: Transaction;
|
|
4402
|
+
}> {
|
|
4403
|
+
let cancelExistingOrdersTx: Transaction;
|
|
4404
|
+
if (cancelExistingOrders && isVariant(orderParams.marketType, 'perp')) {
|
|
4405
|
+
const cancelOrdersIx = await this.getCancelOrdersIx(
|
|
4406
|
+
orderParams.marketType,
|
|
4407
|
+
orderParams.marketIndex,
|
|
4408
|
+
null,
|
|
4409
|
+
subAccountId
|
|
4410
|
+
);
|
|
4411
|
+
|
|
4412
|
+
//@ts-ignore
|
|
4413
|
+
cancelExistingOrdersTx = await this.buildTransaction(
|
|
4414
|
+
[cancelOrdersIx],
|
|
4415
|
+
txParams,
|
|
4416
|
+
this.txVersion
|
|
4417
|
+
);
|
|
4418
|
+
}
|
|
4419
|
+
|
|
4420
|
+
/* Settle PnL after fill if requested */
|
|
4421
|
+
let settlePnlTx: Transaction;
|
|
4422
|
+
if (settlePnl && isVariant(orderParams.marketType, 'perp')) {
|
|
4423
|
+
const userAccountPublicKey = await this.getUserAccountPublicKey(
|
|
4424
|
+
subAccountId
|
|
4425
|
+
);
|
|
4426
|
+
|
|
4427
|
+
const settlePnlIx = await this.settlePNLIx(
|
|
4428
|
+
userAccountPublicKey,
|
|
4429
|
+
this.getUserAccount(subAccountId),
|
|
4430
|
+
orderParams.marketIndex
|
|
4431
|
+
);
|
|
4432
|
+
|
|
4433
|
+
//@ts-ignore
|
|
4434
|
+
settlePnlTx = await this.buildTransaction(
|
|
4435
|
+
[settlePnlIx],
|
|
4436
|
+
txParams,
|
|
4437
|
+
this.txVersion
|
|
4438
|
+
);
|
|
4439
|
+
}
|
|
4440
|
+
|
|
4441
|
+
const ixs = [];
|
|
4442
|
+
|
|
4443
|
+
const placeAndTakeIx = await this.getPlaceAndTakePerpOrderIx(
|
|
4444
|
+
orderParams,
|
|
4445
|
+
makerInfo,
|
|
4446
|
+
referrerInfo,
|
|
4447
|
+
subAccountId
|
|
4448
|
+
);
|
|
4449
|
+
|
|
4450
|
+
ixs.push(placeAndTakeIx);
|
|
4451
|
+
|
|
4452
|
+
if (bracketOrdersParams.length > 0) {
|
|
4453
|
+
const bracketOrdersIx = await this.getPlaceOrdersIx(
|
|
4454
|
+
bracketOrdersParams,
|
|
4455
|
+
subAccountId
|
|
4456
|
+
);
|
|
4457
|
+
ixs.push(bracketOrdersIx);
|
|
4458
|
+
}
|
|
4459
|
+
|
|
4460
|
+
const placeAndTakeTx = await this.buildTransaction(ixs, txParams);
|
|
4461
|
+
|
|
4462
|
+
const allPossibleTxs = [
|
|
4463
|
+
placeAndTakeTx,
|
|
4464
|
+
cancelExistingOrdersTx,
|
|
4465
|
+
settlePnlTx,
|
|
4466
|
+
];
|
|
4467
|
+
const txKeys = [
|
|
4468
|
+
'signedPlaceAndTakeTx',
|
|
4469
|
+
'signedCancelExistingOrdersTx',
|
|
4470
|
+
'signedSettlePnlTx',
|
|
4471
|
+
];
|
|
4472
|
+
|
|
4473
|
+
const {
|
|
4474
|
+
signedPlaceAndTakeTx,
|
|
4475
|
+
signedCancelExistingOrdersTx,
|
|
4476
|
+
signedSettlePnlTx,
|
|
4477
|
+
} = await getSignedTransactionMap(
|
|
4478
|
+
//@ts-ignore
|
|
4479
|
+
this.provider.wallet,
|
|
4480
|
+
allPossibleTxs,
|
|
4481
|
+
txKeys
|
|
4482
|
+
);
|
|
4483
|
+
|
|
4484
|
+
const { txSig, slot } = await this.sendTransaction(
|
|
4485
|
+
signedPlaceAndTakeTx,
|
|
4486
|
+
[],
|
|
4487
|
+
this.opts,
|
|
4488
|
+
true
|
|
4489
|
+
);
|
|
4490
|
+
this.perpMarketLastSlotCache.set(orderParams.marketIndex, slot);
|
|
4491
|
+
|
|
4492
|
+
//@ts-ignore
|
|
4493
|
+
return { txSig, signedCancelExistingOrdersTx, signedSettlePnlTx };
|
|
4494
|
+
}
|
|
4495
|
+
|
|
4338
4496
|
public async getPlaceAndTakePerpOrderIx(
|
|
4339
4497
|
orderParams: OptionalOrderParams,
|
|
4340
4498
|
makerInfo?: MakerInfo | MakerInfo[],
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import { LogProvider, logProviderCallback } from './types';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
Commitment,
|
|
4
|
+
Connection,
|
|
5
|
+
Context,
|
|
6
|
+
Logs,
|
|
7
|
+
PublicKey,
|
|
8
|
+
} from '@solana/web3.js';
|
|
3
9
|
import { EventEmitter } from 'events';
|
|
4
10
|
|
|
5
11
|
export class WebSocketLogProvider implements LogProvider {
|
|
@@ -45,7 +51,7 @@ export class WebSocketLogProvider implements LogProvider {
|
|
|
45
51
|
public setSubscription(callback: logProviderCallback): void {
|
|
46
52
|
this.subscriptionId = this.connection.onLogs(
|
|
47
53
|
this.address,
|
|
48
|
-
(logs, ctx) => {
|
|
54
|
+
(logs: Logs, ctx: Context) => {
|
|
49
55
|
if (this.resubTimeoutMs && !this.isUnsubscribing) {
|
|
50
56
|
this.receivingData = true;
|
|
51
57
|
clearTimeout(this.timeoutId);
|
|
@@ -55,6 +61,9 @@ export class WebSocketLogProvider implements LogProvider {
|
|
|
55
61
|
}
|
|
56
62
|
this.reconnectAttempts = 0;
|
|
57
63
|
}
|
|
64
|
+
if (logs.err !== null) {
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
58
67
|
callback(logs.signature, ctx.slot, logs.logs, undefined);
|
|
59
68
|
},
|
|
60
69
|
this.commitment
|
package/src/idl/drift.json
CHANGED
|
@@ -8524,7 +8524,13 @@
|
|
|
8524
8524
|
"kind": "enum",
|
|
8525
8525
|
"variants": [
|
|
8526
8526
|
{
|
|
8527
|
-
"name": "Standard"
|
|
8527
|
+
"name": "Standard",
|
|
8528
|
+
"fields": [
|
|
8529
|
+
{
|
|
8530
|
+
"name": "track_open_orders_fraction",
|
|
8531
|
+
"type": "bool"
|
|
8532
|
+
}
|
|
8533
|
+
]
|
|
8528
8534
|
},
|
|
8529
8535
|
{
|
|
8530
8536
|
"name": "Liquidation",
|
|
@@ -210,6 +210,12 @@ export interface QuoteResponse {
|
|
|
210
210
|
* @memberof QuoteResponse
|
|
211
211
|
*/
|
|
212
212
|
timeTaken?: number;
|
|
213
|
+
/**
|
|
214
|
+
*
|
|
215
|
+
* @type {string}
|
|
216
|
+
* @memberof QuoteResponse
|
|
217
|
+
*/
|
|
218
|
+
error?: string;
|
|
213
219
|
}
|
|
214
220
|
|
|
215
221
|
export class JupiterClient {
|
|
@@ -279,7 +285,7 @@ export class JupiterClient {
|
|
|
279
285
|
slippageBps = 50,
|
|
280
286
|
swapMode = 'ExactIn',
|
|
281
287
|
onlyDirectRoutes = false,
|
|
282
|
-
excludeDexes
|
|
288
|
+
excludeDexes,
|
|
283
289
|
}: {
|
|
284
290
|
inputMint: PublicKey;
|
|
285
291
|
outputMint: PublicKey;
|
|
@@ -298,7 +304,7 @@ export class JupiterClient {
|
|
|
298
304
|
swapMode,
|
|
299
305
|
onlyDirectRoutes: onlyDirectRoutes.toString(),
|
|
300
306
|
maxAccounts: maxAccounts.toString(),
|
|
301
|
-
excludeDexes: excludeDexes.join(','),
|
|
307
|
+
...(excludeDexes && { excludeDexes: excludeDexes.join(',') }),
|
|
302
308
|
}).toString();
|
|
303
309
|
const quote = await (await fetch(`${this.url}/v6/quote?${params}`)).json();
|
|
304
310
|
return quote;
|
package/src/math/funding.ts
CHANGED
|
@@ -11,6 +11,7 @@ import { PerpMarketAccount, isVariant } from '../types';
|
|
|
11
11
|
import { OraclePriceData } from '../oracles/types';
|
|
12
12
|
import { calculateBidAskPrice } from './amm';
|
|
13
13
|
import { calculateLiveOracleTwap } from './oracles';
|
|
14
|
+
import { clampBN } from './utils';
|
|
14
15
|
|
|
15
16
|
function calculateLiveMarkTwap(
|
|
16
17
|
market: PerpMarketAccount,
|
|
@@ -160,8 +161,15 @@ export async function calculateAllEstimatedFundingRate(
|
|
|
160
161
|
const twapSpreadWithOffset = twapSpread.add(
|
|
161
162
|
oracleTwap.abs().div(FUNDING_RATE_OFFSET_DENOMINATOR)
|
|
162
163
|
);
|
|
164
|
+
const maxSpread = getMaxPriceDivergenceForFundingRate(market, oracleTwap);
|
|
163
165
|
|
|
164
|
-
const
|
|
166
|
+
const clampedSpreadWithOffset = clampBN(
|
|
167
|
+
twapSpreadWithOffset,
|
|
168
|
+
maxSpread.mul(new BN(-1)),
|
|
169
|
+
maxSpread
|
|
170
|
+
);
|
|
171
|
+
|
|
172
|
+
const twapSpreadPct = clampedSpreadWithOffset
|
|
165
173
|
.mul(PRICE_PRECISION)
|
|
166
174
|
.mul(new BN(100))
|
|
167
175
|
.div(oracleTwap);
|
|
@@ -234,6 +242,25 @@ export async function calculateAllEstimatedFundingRate(
|
|
|
234
242
|
return [markTwap, oracleTwap, lowerboundEst, cappedAltEst, interpEst];
|
|
235
243
|
}
|
|
236
244
|
|
|
245
|
+
function getMaxPriceDivergenceForFundingRate(
|
|
246
|
+
market: PerpMarketAccount,
|
|
247
|
+
oracleTwap: BN
|
|
248
|
+
) {
|
|
249
|
+
if (isVariant(market.contractTier, 'a')) {
|
|
250
|
+
return oracleTwap.divn(33);
|
|
251
|
+
} else if (isVariant(market.contractTier, 'b')) {
|
|
252
|
+
return oracleTwap.divn(33);
|
|
253
|
+
} else if (isVariant(market.contractTier, 'c')) {
|
|
254
|
+
return oracleTwap.divn(20);
|
|
255
|
+
} else if (isVariant(market.contractTier, 'speculative')) {
|
|
256
|
+
return oracleTwap.divn(10);
|
|
257
|
+
} else if (isVariant(market.contractTier, 'isolated')) {
|
|
258
|
+
return oracleTwap.divn(10);
|
|
259
|
+
} else {
|
|
260
|
+
return oracleTwap.divn(10);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
237
264
|
/**
|
|
238
265
|
*
|
|
239
266
|
* @param market
|
package/src/math/oracles.ts
CHANGED
|
@@ -47,8 +47,8 @@ export function isOracleValid(
|
|
|
47
47
|
.div(oraclePriceData.price)
|
|
48
48
|
.gt(oracleGuardRails.validity.confidenceIntervalMaxSize);
|
|
49
49
|
|
|
50
|
-
const oracleIsStale =
|
|
51
|
-
.sub(
|
|
50
|
+
const oracleIsStale = new BN(slot)
|
|
51
|
+
.sub(oraclePriceData.slot)
|
|
52
52
|
.gt(oracleGuardRails.validity.slotsBeforeStaleForAmm);
|
|
53
53
|
|
|
54
54
|
return !(
|