@drift-labs/sdk 0.2.0-master.36 → 0.2.0-master.38
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/addresses/pda.js +2 -2
- package/lib/admin.d.ts +6 -3
- package/lib/admin.js +30 -3
- package/lib/clearingHouse.d.ts +17 -6
- package/lib/clearingHouse.js +162 -45
- package/lib/clearingHouseUser.js +8 -27
- package/lib/config.js +1 -1
- package/lib/factory/bigNum.d.ts +1 -0
- package/lib/factory/bigNum.js +26 -4
- package/lib/idl/clearing_house.json +425 -285
- package/lib/math/funding.js +3 -2
- package/lib/math/market.js +4 -6
- package/lib/math/position.d.ts +7 -1
- package/lib/math/position.js +18 -2
- package/lib/math/spotBalance.js +5 -5
- package/lib/types.d.ts +18 -16
- package/package.json +1 -1
- package/src/addresses/pda.ts +2 -2
- package/src/admin.ts +73 -13
- package/src/clearingHouse.ts +214 -54
- package/src/clearingHouseUser.ts +10 -26
- package/src/config.ts +1 -1
- package/src/factory/bigNum.ts +27 -4
- package/src/idl/clearing_house.json +425 -285
- package/src/math/funding.ts +3 -5
- package/src/math/market.ts +4 -6
- package/src/math/position.ts +18 -1
- package/src/math/spotBalance.ts +9 -9
- package/src/types.ts +18 -16
- package/tests/dlob/helpers.ts +47 -43
package/src/clearingHouse.ts
CHANGED
|
@@ -86,7 +86,7 @@ type RemainingAccountParams = {
|
|
|
86
86
|
writablePerpMarketIndexes?: number[];
|
|
87
87
|
writableSpotMarketIndexes?: number[];
|
|
88
88
|
readablePerpMarketIndex?: number;
|
|
89
|
-
|
|
89
|
+
readableSpotMarketIndexes?: number[];
|
|
90
90
|
useMarketLastSlotCache?: boolean;
|
|
91
91
|
};
|
|
92
92
|
|
|
@@ -108,7 +108,8 @@ export class ClearingHouse {
|
|
|
108
108
|
eventEmitter: StrictEventEmitter<EventEmitter, ClearingHouseAccountEvents>;
|
|
109
109
|
_isSubscribed = false;
|
|
110
110
|
txSender: TxSender;
|
|
111
|
-
|
|
111
|
+
perpMarketLastSlotCache = new Map<number, number>();
|
|
112
|
+
spotMarketLastSlotCache = new Map<number, number>();
|
|
112
113
|
authority: PublicKey;
|
|
113
114
|
|
|
114
115
|
public get isSubscribed() {
|
|
@@ -664,11 +665,14 @@ export class ClearingHouse {
|
|
|
664
665
|
this.getRemainingAccountMapsForUsers(params.userAccounts);
|
|
665
666
|
|
|
666
667
|
if (params.useMarketLastSlotCache) {
|
|
667
|
-
const
|
|
668
|
-
for (const [
|
|
668
|
+
const lastUserSlot = this.getUserAccountAndSlot()?.slot;
|
|
669
|
+
for (const [
|
|
670
|
+
marketIndex,
|
|
671
|
+
slot,
|
|
672
|
+
] of this.perpMarketLastSlotCache.entries()) {
|
|
669
673
|
// if cache has more recent slot than user positions account slot, add market to remaining accounts
|
|
670
674
|
// otherwise remove from slot
|
|
671
|
-
if (slot >
|
|
675
|
+
if (slot > lastUserSlot) {
|
|
672
676
|
const marketAccount = this.getPerpMarketAccount(marketIndex);
|
|
673
677
|
perpMarketAccountMap.set(marketIndex, {
|
|
674
678
|
pubkey: marketAccount.pubkey,
|
|
@@ -681,7 +685,32 @@ export class ClearingHouse {
|
|
|
681
685
|
isWritable: false,
|
|
682
686
|
});
|
|
683
687
|
} else {
|
|
684
|
-
this.
|
|
688
|
+
this.perpMarketLastSlotCache.delete(marketIndex);
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
for (const [
|
|
693
|
+
marketIndex,
|
|
694
|
+
slot,
|
|
695
|
+
] of this.spotMarketLastSlotCache.entries()) {
|
|
696
|
+
// if cache has more recent slot than user positions account slot, add market to remaining accounts
|
|
697
|
+
// otherwise remove from slot
|
|
698
|
+
if (slot > lastUserSlot) {
|
|
699
|
+
const marketAccount = this.getSpotMarketAccount(marketIndex);
|
|
700
|
+
spotMarketAccountMap.set(marketIndex, {
|
|
701
|
+
pubkey: marketAccount.pubkey,
|
|
702
|
+
isSigner: false,
|
|
703
|
+
isWritable: false,
|
|
704
|
+
});
|
|
705
|
+
if (!marketAccount.oracle.equals(PublicKey.default)) {
|
|
706
|
+
oracleAccountMap.set(marketAccount.oracle.toString(), {
|
|
707
|
+
pubkey: marketAccount.oracle,
|
|
708
|
+
isSigner: false,
|
|
709
|
+
isWritable: false,
|
|
710
|
+
});
|
|
711
|
+
}
|
|
712
|
+
} else {
|
|
713
|
+
this.spotMarketLastSlotCache.delete(marketIndex);
|
|
685
714
|
}
|
|
686
715
|
}
|
|
687
716
|
}
|
|
@@ -720,21 +749,23 @@ export class ClearingHouse {
|
|
|
720
749
|
}
|
|
721
750
|
}
|
|
722
751
|
|
|
723
|
-
if (params.
|
|
724
|
-
const
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
isWritable: false,
|
|
731
|
-
});
|
|
732
|
-
if (spotMarketAccount.marketIndex !== 0) {
|
|
733
|
-
oracleAccountMap.set(spotMarketAccount.oracle.toString(), {
|
|
734
|
-
pubkey: spotMarketAccount.oracle,
|
|
752
|
+
if (params.readableSpotMarketIndexes !== undefined) {
|
|
753
|
+
for (const readableSpotMarketIndex of params.readableSpotMarketIndexes) {
|
|
754
|
+
const spotMarketAccount = this.getSpotMarketAccount(
|
|
755
|
+
readableSpotMarketIndex
|
|
756
|
+
);
|
|
757
|
+
spotMarketAccountMap.set(readableSpotMarketIndex, {
|
|
758
|
+
pubkey: spotMarketAccount.pubkey,
|
|
735
759
|
isSigner: false,
|
|
736
760
|
isWritable: false,
|
|
737
761
|
});
|
|
762
|
+
if (spotMarketAccount.marketIndex !== 0) {
|
|
763
|
+
oracleAccountMap.set(spotMarketAccount.oracle.toString(), {
|
|
764
|
+
pubkey: spotMarketAccount.oracle,
|
|
765
|
+
isSigner: false,
|
|
766
|
+
isWritable: false,
|
|
767
|
+
});
|
|
768
|
+
}
|
|
738
769
|
}
|
|
739
770
|
}
|
|
740
771
|
|
|
@@ -793,6 +824,17 @@ export class ClearingHouse {
|
|
|
793
824
|
isWritable: false,
|
|
794
825
|
});
|
|
795
826
|
}
|
|
827
|
+
|
|
828
|
+
if (
|
|
829
|
+
!spotPosition.openAsks.eq(ZERO) ||
|
|
830
|
+
!spotPosition.openBids.eq(ZERO)
|
|
831
|
+
) {
|
|
832
|
+
spotMarketAccountMap.set(spotPosition.marketIndex, {
|
|
833
|
+
pubkey: this.getQuoteSpotMarketAccount().pubkey,
|
|
834
|
+
isSigner: false,
|
|
835
|
+
isWritable: false,
|
|
836
|
+
});
|
|
837
|
+
}
|
|
796
838
|
}
|
|
797
839
|
}
|
|
798
840
|
for (const position of userAccount.perpPositions) {
|
|
@@ -894,11 +936,12 @@ export class ClearingHouse {
|
|
|
894
936
|
);
|
|
895
937
|
}
|
|
896
938
|
|
|
897
|
-
const { txSig } = await this.txSender.send(
|
|
939
|
+
const { txSig, slot } = await this.txSender.send(
|
|
898
940
|
tx,
|
|
899
941
|
additionalSigners,
|
|
900
942
|
this.opts
|
|
901
943
|
);
|
|
944
|
+
this.spotMarketLastSlotCache.set(marketIndex, slot);
|
|
902
945
|
return txSig;
|
|
903
946
|
}
|
|
904
947
|
|
|
@@ -1119,12 +1162,12 @@ export class ClearingHouse {
|
|
|
1119
1162
|
);
|
|
1120
1163
|
}
|
|
1121
1164
|
|
|
1122
|
-
const { txSig } = await this.txSender.send(
|
|
1165
|
+
const { txSig, slot } = await this.txSender.send(
|
|
1123
1166
|
tx,
|
|
1124
1167
|
additionalSigners,
|
|
1125
1168
|
this.opts
|
|
1126
1169
|
);
|
|
1127
|
-
|
|
1170
|
+
this.spotMarketLastSlotCache.set(marketIndex, slot);
|
|
1128
1171
|
return [txSig, userAccountPublicKey];
|
|
1129
1172
|
}
|
|
1130
1173
|
|
|
@@ -1242,11 +1285,12 @@ export class ClearingHouse {
|
|
|
1242
1285
|
);
|
|
1243
1286
|
}
|
|
1244
1287
|
|
|
1245
|
-
const { txSig } = await this.txSender.send(
|
|
1288
|
+
const { txSig, slot } = await this.txSender.send(
|
|
1246
1289
|
tx,
|
|
1247
1290
|
additionalSigners,
|
|
1248
1291
|
this.opts
|
|
1249
1292
|
);
|
|
1293
|
+
this.spotMarketLastSlotCache.set(marketIndex, slot);
|
|
1250
1294
|
return txSig;
|
|
1251
1295
|
}
|
|
1252
1296
|
|
|
@@ -1262,6 +1306,7 @@ export class ClearingHouse {
|
|
|
1262
1306
|
userAccounts: [this.getUserAccount()],
|
|
1263
1307
|
useMarketLastSlotCache: true,
|
|
1264
1308
|
writableSpotMarketIndexes: [marketIndex],
|
|
1309
|
+
readableSpotMarketIndexes: [QUOTE_SPOT_MARKET_INDEX],
|
|
1265
1310
|
});
|
|
1266
1311
|
|
|
1267
1312
|
const spotMarketAccount = this.getSpotMarketAccount(marketIndex);
|
|
@@ -1293,7 +1338,7 @@ export class ClearingHouse {
|
|
|
1293
1338
|
fromSubAccountId: number,
|
|
1294
1339
|
toSubAccountId: number
|
|
1295
1340
|
): Promise<TransactionSignature> {
|
|
1296
|
-
const { txSig } = await this.txSender.send(
|
|
1341
|
+
const { txSig, slot } = await this.txSender.send(
|
|
1297
1342
|
wrapInTx(
|
|
1298
1343
|
await this.getTransferDepositIx(
|
|
1299
1344
|
amount,
|
|
@@ -1305,6 +1350,12 @@ export class ClearingHouse {
|
|
|
1305
1350
|
[],
|
|
1306
1351
|
this.opts
|
|
1307
1352
|
);
|
|
1353
|
+
if (
|
|
1354
|
+
fromSubAccountId === this.activeSubAccountId ||
|
|
1355
|
+
toSubAccountId === this.activeSubAccountId
|
|
1356
|
+
) {
|
|
1357
|
+
this.spotMarketLastSlotCache.set(marketIndex, slot);
|
|
1358
|
+
}
|
|
1308
1359
|
return txSig;
|
|
1309
1360
|
}
|
|
1310
1361
|
|
|
@@ -1356,6 +1407,7 @@ export class ClearingHouse {
|
|
|
1356
1407
|
toUser,
|
|
1357
1408
|
userStats: this.getUserStatsAccountPublicKey(),
|
|
1358
1409
|
state: await this.getStatePublicKey(),
|
|
1410
|
+
spotMarketVault: this.getQuoteSpotMarketAccount().vault,
|
|
1359
1411
|
},
|
|
1360
1412
|
remainingAccounts,
|
|
1361
1413
|
});
|
|
@@ -1530,7 +1582,7 @@ export class ClearingHouse {
|
|
|
1530
1582
|
[],
|
|
1531
1583
|
this.opts
|
|
1532
1584
|
);
|
|
1533
|
-
this.
|
|
1585
|
+
this.perpMarketLastSlotCache.set(marketIndex, slot);
|
|
1534
1586
|
return txSig;
|
|
1535
1587
|
}
|
|
1536
1588
|
|
|
@@ -1619,7 +1671,7 @@ export class ClearingHouse {
|
|
|
1619
1671
|
true
|
|
1620
1672
|
);
|
|
1621
1673
|
|
|
1622
|
-
this.
|
|
1674
|
+
this.perpMarketLastSlotCache.set(orderParams.marketIndex, slot);
|
|
1623
1675
|
|
|
1624
1676
|
return { txSig, signedFillTx };
|
|
1625
1677
|
}
|
|
@@ -1632,7 +1684,7 @@ export class ClearingHouse {
|
|
|
1632
1684
|
[],
|
|
1633
1685
|
this.opts
|
|
1634
1686
|
);
|
|
1635
|
-
this.
|
|
1687
|
+
this.perpMarketLastSlotCache.set(orderParams.marketIndex, slot);
|
|
1636
1688
|
return txSig;
|
|
1637
1689
|
}
|
|
1638
1690
|
|
|
@@ -1993,11 +2045,13 @@ export class ClearingHouse {
|
|
|
1993
2045
|
public async placeSpotOrder(
|
|
1994
2046
|
orderParams: OptionalOrderParams
|
|
1995
2047
|
): Promise<TransactionSignature> {
|
|
1996
|
-
const { txSig } = await this.txSender.send(
|
|
2048
|
+
const { txSig, slot } = await this.txSender.send(
|
|
1997
2049
|
wrapInTx(await this.getPlaceSpotOrderIx(orderParams)),
|
|
1998
2050
|
[],
|
|
1999
2051
|
this.opts
|
|
2000
2052
|
);
|
|
2053
|
+
this.spotMarketLastSlotCache.set(orderParams.marketIndex, slot);
|
|
2054
|
+
this.spotMarketLastSlotCache.set(QUOTE_SPOT_MARKET_INDEX, slot);
|
|
2001
2055
|
return txSig;
|
|
2002
2056
|
}
|
|
2003
2057
|
|
|
@@ -2010,7 +2064,10 @@ export class ClearingHouse {
|
|
|
2010
2064
|
const remainingAccounts = this.getRemainingAccounts({
|
|
2011
2065
|
userAccounts: [this.getUserAccount()],
|
|
2012
2066
|
useMarketLastSlotCache: true,
|
|
2013
|
-
|
|
2067
|
+
readableSpotMarketIndexes: [
|
|
2068
|
+
orderParams.marketIndex,
|
|
2069
|
+
QUOTE_SPOT_MARKET_INDEX,
|
|
2070
|
+
],
|
|
2014
2071
|
});
|
|
2015
2072
|
|
|
2016
2073
|
return await this.program.instruction.placeSpotOrder(orderParams, {
|
|
@@ -2109,13 +2166,11 @@ export class ClearingHouse {
|
|
|
2109
2166
|
const orderId = order.orderId;
|
|
2110
2167
|
const makerOrderId = makerInfo ? makerInfo.order.orderId : null;
|
|
2111
2168
|
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
);
|
|
2118
|
-
}
|
|
2169
|
+
this.addSpotFulfillmentAccounts(
|
|
2170
|
+
marketIndex,
|
|
2171
|
+
remainingAccounts,
|
|
2172
|
+
fulfillmentConfig
|
|
2173
|
+
);
|
|
2119
2174
|
|
|
2120
2175
|
return await this.program.instruction.fillSpotOrder(
|
|
2121
2176
|
orderId,
|
|
@@ -2135,6 +2190,31 @@ export class ClearingHouse {
|
|
|
2135
2190
|
);
|
|
2136
2191
|
}
|
|
2137
2192
|
|
|
2193
|
+
addSpotFulfillmentAccounts(
|
|
2194
|
+
marketIndex: number,
|
|
2195
|
+
remainingAccounts: AccountMeta[],
|
|
2196
|
+
fulfillmentConfig?: SerumV3FulfillmentConfigAccount
|
|
2197
|
+
) {
|
|
2198
|
+
if (fulfillmentConfig) {
|
|
2199
|
+
this.addSerumRemainingAccounts(
|
|
2200
|
+
marketIndex,
|
|
2201
|
+
remainingAccounts,
|
|
2202
|
+
fulfillmentConfig
|
|
2203
|
+
);
|
|
2204
|
+
} else {
|
|
2205
|
+
remainingAccounts.push({
|
|
2206
|
+
pubkey: this.getSpotMarketAccount(marketIndex).vault,
|
|
2207
|
+
isWritable: false,
|
|
2208
|
+
isSigner: false,
|
|
2209
|
+
});
|
|
2210
|
+
remainingAccounts.push({
|
|
2211
|
+
pubkey: this.getQuoteSpotMarketAccount().vault,
|
|
2212
|
+
isWritable: false,
|
|
2213
|
+
isSigner: false,
|
|
2214
|
+
});
|
|
2215
|
+
}
|
|
2216
|
+
}
|
|
2217
|
+
|
|
2138
2218
|
addSerumRemainingAccounts(
|
|
2139
2219
|
marketIndex: number,
|
|
2140
2220
|
remainingAccounts: AccountMeta[],
|
|
@@ -2291,7 +2371,7 @@ export class ClearingHouse {
|
|
|
2291
2371
|
[],
|
|
2292
2372
|
this.opts
|
|
2293
2373
|
);
|
|
2294
|
-
this.
|
|
2374
|
+
this.perpMarketLastSlotCache.set(orderParams.marketIndex, slot);
|
|
2295
2375
|
return txSig;
|
|
2296
2376
|
}
|
|
2297
2377
|
|
|
@@ -2374,7 +2454,7 @@ export class ClearingHouse {
|
|
|
2374
2454
|
this.opts
|
|
2375
2455
|
);
|
|
2376
2456
|
|
|
2377
|
-
this.
|
|
2457
|
+
this.perpMarketLastSlotCache.set(orderParams.marketIndex, slot);
|
|
2378
2458
|
|
|
2379
2459
|
return txSig;
|
|
2380
2460
|
}
|
|
@@ -2431,7 +2511,7 @@ export class ClearingHouse {
|
|
|
2431
2511
|
makerInfo?: MakerInfo,
|
|
2432
2512
|
referrerInfo?: ReferrerInfo
|
|
2433
2513
|
): Promise<TransactionSignature> {
|
|
2434
|
-
const { txSig } = await this.txSender.send(
|
|
2514
|
+
const { txSig, slot } = await this.txSender.send(
|
|
2435
2515
|
wrapInTx(
|
|
2436
2516
|
await this.getPlaceAndTakeSpotOrderIx(
|
|
2437
2517
|
orderParams,
|
|
@@ -2443,6 +2523,8 @@ export class ClearingHouse {
|
|
|
2443
2523
|
[],
|
|
2444
2524
|
this.opts
|
|
2445
2525
|
);
|
|
2526
|
+
this.spotMarketLastSlotCache.set(orderParams.marketIndex, slot);
|
|
2527
|
+
this.spotMarketLastSlotCache.set(QUOTE_SPOT_MARKET_INDEX, slot);
|
|
2446
2528
|
return txSig;
|
|
2447
2529
|
}
|
|
2448
2530
|
|
|
@@ -2497,13 +2579,11 @@ export class ClearingHouse {
|
|
|
2497
2579
|
});
|
|
2498
2580
|
}
|
|
2499
2581
|
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
);
|
|
2506
|
-
}
|
|
2582
|
+
this.addSpotFulfillmentAccounts(
|
|
2583
|
+
orderParams.marketIndex,
|
|
2584
|
+
remainingAccounts,
|
|
2585
|
+
fulfillmentConfig
|
|
2586
|
+
);
|
|
2507
2587
|
|
|
2508
2588
|
return await this.program.instruction.placeAndTakeSpotOrder(
|
|
2509
2589
|
orderParams,
|
|
@@ -2524,26 +2604,30 @@ export class ClearingHouse {
|
|
|
2524
2604
|
public async placeAndMakeSpotOrder(
|
|
2525
2605
|
orderParams: OptionalOrderParams,
|
|
2526
2606
|
takerInfo: TakerInfo,
|
|
2607
|
+
fulfillmentConfig?: SerumV3FulfillmentConfigAccount,
|
|
2527
2608
|
referrerInfo?: ReferrerInfo
|
|
2528
2609
|
): Promise<TransactionSignature> {
|
|
2529
|
-
const { txSig } = await this.txSender.send(
|
|
2610
|
+
const { txSig, slot } = await this.txSender.send(
|
|
2530
2611
|
wrapInTx(
|
|
2531
2612
|
await this.getPlaceAndMakeSpotOrderIx(
|
|
2532
2613
|
orderParams,
|
|
2533
2614
|
takerInfo,
|
|
2615
|
+
fulfillmentConfig,
|
|
2534
2616
|
referrerInfo
|
|
2535
2617
|
)
|
|
2536
2618
|
),
|
|
2537
2619
|
[],
|
|
2538
2620
|
this.opts
|
|
2539
2621
|
);
|
|
2540
|
-
|
|
2622
|
+
this.spotMarketLastSlotCache.set(orderParams.marketIndex, slot);
|
|
2623
|
+
this.spotMarketLastSlotCache.set(QUOTE_SPOT_MARKET_INDEX, slot);
|
|
2541
2624
|
return txSig;
|
|
2542
2625
|
}
|
|
2543
2626
|
|
|
2544
2627
|
public async getPlaceAndMakeSpotOrderIx(
|
|
2545
2628
|
orderParams: OptionalOrderParams,
|
|
2546
2629
|
takerInfo: TakerInfo,
|
|
2630
|
+
fulfillmentConfig?: SerumV3FulfillmentConfigAccount,
|
|
2547
2631
|
referrerInfo?: ReferrerInfo
|
|
2548
2632
|
): Promise<TransactionInstruction> {
|
|
2549
2633
|
orderParams = this.getOrderParams(orderParams, MarketType.SPOT);
|
|
@@ -2572,10 +2656,17 @@ export class ClearingHouse {
|
|
|
2572
2656
|
});
|
|
2573
2657
|
}
|
|
2574
2658
|
|
|
2659
|
+
this.addSpotFulfillmentAccounts(
|
|
2660
|
+
orderParams.marketIndex,
|
|
2661
|
+
remainingAccounts,
|
|
2662
|
+
fulfillmentConfig
|
|
2663
|
+
);
|
|
2664
|
+
|
|
2575
2665
|
const takerOrderId = takerInfo.order.orderId;
|
|
2576
2666
|
return await this.program.instruction.placeAndMakeSpotOrder(
|
|
2577
2667
|
orderParams,
|
|
2578
2668
|
takerOrderId,
|
|
2669
|
+
fulfillmentConfig ? fulfillmentConfig.fulfillmentType : null,
|
|
2579
2670
|
{
|
|
2580
2671
|
accounts: {
|
|
2581
2672
|
state: await this.getStatePublicKey(),
|
|
@@ -2614,6 +2705,66 @@ export class ClearingHouse {
|
|
|
2614
2705
|
});
|
|
2615
2706
|
}
|
|
2616
2707
|
|
|
2708
|
+
/**
|
|
2709
|
+
* Modifies an open order by closing it and replacing it with a new order.
|
|
2710
|
+
* @param orderId: The open order to modify
|
|
2711
|
+
* @param newBaseAmount: The new base amount for the order. One of [newBaseAmount|newLimitPrice|newOraclePriceOffset] must be provided.
|
|
2712
|
+
* @param newLimitPice: The new limit price for the order. One of [newBaseAmount|newLimitPrice|newOraclePriceOffset] must be provided.
|
|
2713
|
+
* @param newOraclePriceOffset: The new oracle price offset for the order. One of [newBaseAmount|newLimitPrice|newOraclePriceOffset] must be provided.
|
|
2714
|
+
* @returns
|
|
2715
|
+
*/
|
|
2716
|
+
public async modifyPerpOrder(
|
|
2717
|
+
orderId: number,
|
|
2718
|
+
newBaseAmount?: BN,
|
|
2719
|
+
newLimitPrice?: BN,
|
|
2720
|
+
newOraclePriceOffset?: number
|
|
2721
|
+
): Promise<TransactionSignature> {
|
|
2722
|
+
if (!newBaseAmount && !newLimitPrice && !newOraclePriceOffset) {
|
|
2723
|
+
throw new Error(
|
|
2724
|
+
`Must provide newBaseAmount or newLimitPrice or newOraclePriceOffset to modify order`
|
|
2725
|
+
);
|
|
2726
|
+
}
|
|
2727
|
+
|
|
2728
|
+
const openOrder = this.getUser().getOrder(orderId);
|
|
2729
|
+
if (!openOrder) {
|
|
2730
|
+
throw new Error(`No open order with id ${orderId.toString()}`);
|
|
2731
|
+
}
|
|
2732
|
+
const cancelOrderIx = await this.getCancelOrderIx(orderId);
|
|
2733
|
+
|
|
2734
|
+
const newOrderParams: OptionalOrderParams = {
|
|
2735
|
+
orderType: openOrder.orderType,
|
|
2736
|
+
marketType: openOrder.marketType,
|
|
2737
|
+
direction: openOrder.direction,
|
|
2738
|
+
baseAssetAmount: newBaseAmount || openOrder.baseAssetAmount,
|
|
2739
|
+
price: newLimitPrice || openOrder.price,
|
|
2740
|
+
marketIndex: openOrder.marketIndex,
|
|
2741
|
+
reduceOnly: openOrder.reduceOnly,
|
|
2742
|
+
postOnly: openOrder.postOnly,
|
|
2743
|
+
immediateOrCancel: openOrder.immediateOrCancel,
|
|
2744
|
+
triggerPrice: openOrder.triggerPrice,
|
|
2745
|
+
triggerCondition: openOrder.triggerCondition,
|
|
2746
|
+
oraclePriceOffset: newOraclePriceOffset || openOrder.oraclePriceOffset,
|
|
2747
|
+
auctionDuration: openOrder.auctionDuration,
|
|
2748
|
+
maxTs: openOrder.maxTs,
|
|
2749
|
+
auctionStartPrice: openOrder.auctionStartPrice,
|
|
2750
|
+
auctionEndPrice: openOrder.auctionEndPrice,
|
|
2751
|
+
};
|
|
2752
|
+
const placeOrderIx = await this.getPlacePerpOrderIx(newOrderParams);
|
|
2753
|
+
|
|
2754
|
+
const tx = new Transaction();
|
|
2755
|
+
tx.add(
|
|
2756
|
+
ComputeBudgetProgram.requestUnits({
|
|
2757
|
+
units: 1_000_000,
|
|
2758
|
+
additionalFee: 0,
|
|
2759
|
+
})
|
|
2760
|
+
);
|
|
2761
|
+
tx.add(cancelOrderIx);
|
|
2762
|
+
tx.add(placeOrderIx);
|
|
2763
|
+
const { txSig, slot } = await this.txSender.send(tx, [], this.opts);
|
|
2764
|
+
this.perpMarketLastSlotCache.set(newOrderParams.marketIndex, slot);
|
|
2765
|
+
return txSig;
|
|
2766
|
+
}
|
|
2767
|
+
|
|
2617
2768
|
public async settlePNLs(
|
|
2618
2769
|
users: {
|
|
2619
2770
|
settleeUserAccountPublicKey: PublicKey;
|
|
@@ -2680,6 +2831,7 @@ export class ClearingHouse {
|
|
|
2680
2831
|
state: await this.getStatePublicKey(),
|
|
2681
2832
|
authority: this.wallet.publicKey,
|
|
2682
2833
|
user: settleeUserAccountPublicKey,
|
|
2834
|
+
spotMarketVault: this.getQuoteSpotMarketAccount().vault,
|
|
2683
2835
|
},
|
|
2684
2836
|
remainingAccounts: remainingAccounts,
|
|
2685
2837
|
});
|
|
@@ -2689,7 +2841,8 @@ export class ClearingHouse {
|
|
|
2689
2841
|
userAccountPublicKey: PublicKey,
|
|
2690
2842
|
userAccount: UserAccount,
|
|
2691
2843
|
marketIndex: number,
|
|
2692
|
-
maxBaseAssetAmount: BN
|
|
2844
|
+
maxBaseAssetAmount: BN,
|
|
2845
|
+
limitPrice?: BN
|
|
2693
2846
|
): Promise<TransactionSignature> {
|
|
2694
2847
|
const { txSig, slot } = await this.txSender.send(
|
|
2695
2848
|
wrapInTx(
|
|
@@ -2697,13 +2850,14 @@ export class ClearingHouse {
|
|
|
2697
2850
|
userAccountPublicKey,
|
|
2698
2851
|
userAccount,
|
|
2699
2852
|
marketIndex,
|
|
2700
|
-
maxBaseAssetAmount
|
|
2853
|
+
maxBaseAssetAmount,
|
|
2854
|
+
limitPrice
|
|
2701
2855
|
)
|
|
2702
2856
|
),
|
|
2703
2857
|
[],
|
|
2704
2858
|
this.opts
|
|
2705
2859
|
);
|
|
2706
|
-
this.
|
|
2860
|
+
this.perpMarketLastSlotCache.set(marketIndex, slot);
|
|
2707
2861
|
return txSig;
|
|
2708
2862
|
}
|
|
2709
2863
|
|
|
@@ -2711,7 +2865,8 @@ export class ClearingHouse {
|
|
|
2711
2865
|
userAccountPublicKey: PublicKey,
|
|
2712
2866
|
userAccount: UserAccount,
|
|
2713
2867
|
marketIndex: number,
|
|
2714
|
-
maxBaseAssetAmount: BN
|
|
2868
|
+
maxBaseAssetAmount: BN,
|
|
2869
|
+
limitPrice?: BN
|
|
2715
2870
|
): Promise<TransactionInstruction> {
|
|
2716
2871
|
const userStatsPublicKey = getUserStatsAccountPublicKey(
|
|
2717
2872
|
this.program.programId,
|
|
@@ -2730,6 +2885,7 @@ export class ClearingHouse {
|
|
|
2730
2885
|
return await this.program.instruction.liquidatePerp(
|
|
2731
2886
|
marketIndex,
|
|
2732
2887
|
maxBaseAssetAmount,
|
|
2888
|
+
limitPrice ?? null,
|
|
2733
2889
|
{
|
|
2734
2890
|
accounts: {
|
|
2735
2891
|
state: await this.getStatePublicKey(),
|
|
@@ -2751,7 +2907,7 @@ export class ClearingHouse {
|
|
|
2751
2907
|
liabilityMarketIndex: number,
|
|
2752
2908
|
maxLiabilityTransfer: BN
|
|
2753
2909
|
): Promise<TransactionSignature> {
|
|
2754
|
-
const { txSig } = await this.txSender.send(
|
|
2910
|
+
const { txSig, slot } = await this.txSender.send(
|
|
2755
2911
|
wrapInTx(
|
|
2756
2912
|
await this.getLiquidateSpotIx(
|
|
2757
2913
|
userAccountPublicKey,
|
|
@@ -2764,6 +2920,8 @@ export class ClearingHouse {
|
|
|
2764
2920
|
[],
|
|
2765
2921
|
this.opts
|
|
2766
2922
|
);
|
|
2923
|
+
this.spotMarketLastSlotCache.set(assetMarketIndex, slot);
|
|
2924
|
+
this.spotMarketLastSlotCache.set(liabilityMarketIndex, slot);
|
|
2767
2925
|
return txSig;
|
|
2768
2926
|
}
|
|
2769
2927
|
|
|
@@ -2826,7 +2984,8 @@ export class ClearingHouse {
|
|
|
2826
2984
|
[],
|
|
2827
2985
|
this.opts
|
|
2828
2986
|
);
|
|
2829
|
-
this.
|
|
2987
|
+
this.perpMarketLastSlotCache.set(perpMarketIndex, slot);
|
|
2988
|
+
this.spotMarketLastSlotCache.set(liabilityMarketIndex, slot);
|
|
2830
2989
|
return txSig;
|
|
2831
2990
|
}
|
|
2832
2991
|
|
|
@@ -2889,7 +3048,8 @@ export class ClearingHouse {
|
|
|
2889
3048
|
[],
|
|
2890
3049
|
this.opts
|
|
2891
3050
|
);
|
|
2892
|
-
this.
|
|
3051
|
+
this.perpMarketLastSlotCache.set(perpMarketIndex, slot);
|
|
3052
|
+
this.spotMarketLastSlotCache.set(assetMarketIndex, slot);
|
|
2893
3053
|
return txSig;
|
|
2894
3054
|
}
|
|
2895
3055
|
|
package/src/clearingHouseUser.ts
CHANGED
|
@@ -143,6 +143,7 @@ export class ClearingHouseUser {
|
|
|
143
143
|
marketIndex,
|
|
144
144
|
quoteAssetAmount: ZERO,
|
|
145
145
|
quoteEntryAmount: ZERO,
|
|
146
|
+
quoteBreakEvenAmount: ZERO,
|
|
146
147
|
openOrders: 0,
|
|
147
148
|
openBids: ZERO,
|
|
148
149
|
openAsks: ZERO,
|
|
@@ -213,7 +214,7 @@ export class ClearingHouseUser {
|
|
|
213
214
|
*/
|
|
214
215
|
public getLPBidAsks(marketIndex: number): [BN, BN] {
|
|
215
216
|
const position = this.getUserPosition(marketIndex);
|
|
216
|
-
if (position.lpShares.eq(ZERO)) {
|
|
217
|
+
if (position === undefined || position.lpShares.eq(ZERO)) {
|
|
217
218
|
return [ZERO, ZERO];
|
|
218
219
|
}
|
|
219
220
|
|
|
@@ -773,30 +774,12 @@ export class ClearingHouseUser {
|
|
|
773
774
|
settledPosition.baseAssetAmount.add(dustBaa);
|
|
774
775
|
perpPosition.quoteAssetAmount = settledPosition.quoteAssetAmount;
|
|
775
776
|
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
openAsks = market.amm.maxBaseAssetReserve
|
|
780
|
-
.sub(market.amm.baseAssetReserve)
|
|
781
|
-
.mul(perpPosition.lpShares)
|
|
782
|
-
.div(market.amm.sqrtK)
|
|
783
|
-
.mul(new BN(-1));
|
|
784
|
-
} else {
|
|
785
|
-
openAsks = ZERO;
|
|
786
|
-
}
|
|
787
|
-
|
|
788
|
-
let openBids;
|
|
789
|
-
if (market.amm.minBaseAssetReserve < market.amm.baseAssetReserve) {
|
|
790
|
-
openBids = market.amm.baseAssetReserve
|
|
791
|
-
.sub(market.amm.minBaseAssetReserve)
|
|
792
|
-
.mul(perpPosition.lpShares)
|
|
793
|
-
.div(market.amm.sqrtK);
|
|
794
|
-
} else {
|
|
795
|
-
openBids = ZERO;
|
|
796
|
-
}
|
|
777
|
+
const [totalOpenBids, totalOpenAsks] = this.getPerpBidAsks(
|
|
778
|
+
market.marketIndex
|
|
779
|
+
);
|
|
797
780
|
|
|
798
|
-
perpPosition.openAsks =
|
|
799
|
-
perpPosition.openBids =
|
|
781
|
+
perpPosition.openAsks = totalOpenAsks;
|
|
782
|
+
perpPosition.openBids = totalOpenBids;
|
|
800
783
|
}
|
|
801
784
|
|
|
802
785
|
let valuationPrice = this.getOracleDataForPerpMarket(
|
|
@@ -1118,6 +1101,7 @@ export class ClearingHouseUser {
|
|
|
1118
1101
|
remainderBaseAssetAmount: 0,
|
|
1119
1102
|
quoteAssetAmount: new BN(0),
|
|
1120
1103
|
lastCumulativeFundingRate: ZERO,
|
|
1104
|
+
quoteBreakEvenAmount: new BN(0),
|
|
1121
1105
|
quoteEntryAmount: new BN(0),
|
|
1122
1106
|
openOrders: 0,
|
|
1123
1107
|
openBids: new BN(0),
|
|
@@ -1487,7 +1471,7 @@ export class ClearingHouseUser {
|
|
|
1487
1471
|
|
|
1488
1472
|
const amountWithdrawable = freeCollateral
|
|
1489
1473
|
.mul(MARGIN_PRECISION)
|
|
1490
|
-
.div(spotMarket.initialAssetWeight)
|
|
1474
|
+
.div(new BN(spotMarket.initialAssetWeight))
|
|
1491
1475
|
.mul(PRICE_PRECISION)
|
|
1492
1476
|
.div(oracleData.price)
|
|
1493
1477
|
.mul(precisionIncrease);
|
|
@@ -1526,7 +1510,7 @@ export class ClearingHouseUser {
|
|
|
1526
1510
|
|
|
1527
1511
|
const maxLiabilityAllowed = freeCollatAfterWithdraw
|
|
1528
1512
|
.mul(MARGIN_PRECISION)
|
|
1529
|
-
.div(spotMarket.initialLiabilityWeight)
|
|
1513
|
+
.div(new BN(spotMarket.initialLiabilityWeight))
|
|
1530
1514
|
.mul(PRICE_PRECISION)
|
|
1531
1515
|
.div(oracleData.price)
|
|
1532
1516
|
.mul(precisionIncrease);
|
package/src/config.ts
CHANGED
|
@@ -29,7 +29,7 @@ export const configs: { [key in DriftEnv]: DriftConfig } = {
|
|
|
29
29
|
devnet: {
|
|
30
30
|
ENV: 'devnet',
|
|
31
31
|
PYTH_ORACLE_MAPPING_ADDRESS: 'BmA9Z6FjioHJPpjT39QazZyhDRUdZy2ezwx4GiDdE2u2',
|
|
32
|
-
CLEARING_HOUSE_PROGRAM_ID: '
|
|
32
|
+
CLEARING_HOUSE_PROGRAM_ID: 'jAEeKs9twxAJmXZHqS2p459xW7FMDjoyvuqthRo9qGS',
|
|
33
33
|
USDC_MINT_ADDRESS: '8zGuJQqwhZafTah7Uc7Z4tXRnguqkn5KLFAP8oV6PHe2',
|
|
34
34
|
SERUM_V3: 'DESVgJVGajEgKGXhb6XmqDHGz3VjdgP7rEVESBgxmroY',
|
|
35
35
|
V2_ALPHA_TICKET_MINT_ADDRESS:
|
package/src/factory/bigNum.ts
CHANGED
|
@@ -9,6 +9,11 @@ export class BigNum {
|
|
|
9
9
|
static delim = '.';
|
|
10
10
|
static spacer = ',';
|
|
11
11
|
|
|
12
|
+
public static setLocale(locale: string): void {
|
|
13
|
+
BigNum.delim = (1.1).toLocaleString(locale).slice(1, 2) || '.';
|
|
14
|
+
BigNum.spacer = (1000).toLocaleString(locale).slice(1, 2) || ',';
|
|
15
|
+
}
|
|
16
|
+
|
|
12
17
|
constructor(
|
|
13
18
|
val: BN | number | string,
|
|
14
19
|
precisionVal: BN | number | string = new BN(0)
|
|
@@ -566,7 +571,21 @@ export class BigNum {
|
|
|
566
571
|
* @returns
|
|
567
572
|
*/
|
|
568
573
|
public toNum() {
|
|
569
|
-
|
|
574
|
+
let printedValue = this.print();
|
|
575
|
+
|
|
576
|
+
// Must convert any non-US delimiters and spacers to US format before using parseFloat
|
|
577
|
+
if (BigNum.delim !== '.' || BigNum.spacer !== ',') {
|
|
578
|
+
printedValue = printedValue
|
|
579
|
+
.split('')
|
|
580
|
+
.map((char) => {
|
|
581
|
+
if (char === BigNum.delim) return '.';
|
|
582
|
+
if (char === BigNum.spacer) return ',';
|
|
583
|
+
return char;
|
|
584
|
+
})
|
|
585
|
+
.join('');
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
return parseFloat(printedValue);
|
|
570
589
|
}
|
|
571
590
|
|
|
572
591
|
static fromJSON(json: { val: string; precision: string }) {
|
|
@@ -599,12 +618,16 @@ export class BigNum {
|
|
|
599
618
|
static fromPrint(val: string, precisionShift?: BN): BigNum {
|
|
600
619
|
// Handle empty number edge cases
|
|
601
620
|
if (!val) return BigNum.from(ZERO, precisionShift);
|
|
602
|
-
if (!val.replace(BigNum.delim, ''))
|
|
621
|
+
if (!val.replace(BigNum.delim, '')) {
|
|
603
622
|
return BigNum.from(ZERO, precisionShift);
|
|
623
|
+
}
|
|
604
624
|
|
|
605
|
-
const
|
|
625
|
+
const sides = val.split(BigNum.delim);
|
|
626
|
+
const rightSide = sides[1];
|
|
627
|
+
const leftSide = sides[0].replace(/\D/g, '');
|
|
628
|
+
const bnInput = `${leftSide ?? ''}${rightSide ?? ''}`;
|
|
606
629
|
|
|
607
|
-
const rawBn = new BN(
|
|
630
|
+
const rawBn = new BN(bnInput);
|
|
608
631
|
|
|
609
632
|
const rightSideLength = rightSide?.length ?? 0;
|
|
610
633
|
|