@drift-labs/sdk 0.2.0-master.13 → 0.2.0-master.16
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/accounts/bulkUserStatsSubscription.d.ts +7 -0
- package/lib/accounts/bulkUserStatsSubscription.js +21 -0
- package/lib/accounts/bulkUserSubscription.js +0 -1
- package/lib/accounts/fetch.d.ts +2 -1
- package/lib/accounts/fetch.js +9 -1
- package/lib/accounts/pollingUserStatsAccountSubscriber.d.ts +27 -0
- package/lib/accounts/pollingUserStatsAccountSubscriber.js +113 -0
- package/lib/accounts/types.d.ts +14 -2
- package/lib/accounts/webSocketUserStatsAccountSubsriber.d.ts +20 -0
- package/lib/accounts/webSocketUserStatsAccountSubsriber.js +47 -0
- package/lib/addresses/pda.d.ts +1 -0
- package/lib/addresses/pda.js +8 -1
- package/lib/admin.d.ts +2 -0
- package/lib/admin.js +18 -0
- package/lib/clearingHouse.d.ts +17 -1
- package/lib/clearingHouse.js +195 -14
- package/lib/clearingHouseConfig.d.ts +1 -0
- package/lib/clearingHouseUser.d.ts +5 -0
- package/lib/clearingHouseUser.js +97 -3
- package/lib/clearingHouseUserStats.d.ts +17 -0
- package/lib/clearingHouseUserStats.js +36 -0
- package/lib/clearingHouseUserStatsConfig.d.ts +14 -0
- package/{src/clearingHouseConfig.js → lib/clearingHouseUserStatsConfig.js} +0 -0
- package/lib/config.js +1 -1
- package/lib/factory/bigNum.js +7 -9
- package/lib/idl/clearing_house.json +614 -64
- package/lib/math/bankBalance.d.ts +4 -0
- package/lib/math/bankBalance.js +24 -2
- package/lib/math/oracles.d.ts +3 -0
- package/lib/math/oracles.js +25 -5
- package/lib/math/position.js +2 -1
- package/lib/math/trade.js +2 -2
- package/lib/types.d.ts +59 -9
- package/lib/types.js +6 -0
- package/package.json +1 -1
- package/src/accounts/bulkUserStatsSubscription.ts +33 -0
- package/src/accounts/bulkUserSubscription.ts +0 -1
- package/src/accounts/fetch.ts +27 -2
- package/src/accounts/pollingUserStatsAccountSubscriber.ts +172 -0
- package/src/accounts/types.ts +18 -0
- package/src/accounts/webSocketUserStatsAccountSubsriber.ts +80 -0
- package/src/addresses/pda.ts +13 -0
- package/src/admin.ts +29 -1
- package/src/clearingHouse.ts +318 -15
- package/src/clearingHouseConfig.ts +1 -0
- package/src/clearingHouseUser.ts +113 -10
- package/src/clearingHouseUserStats.ts +53 -0
- package/src/clearingHouseUserStatsConfig.ts +18 -0
- package/src/config.ts +1 -1
- package/src/factory/bigNum.ts +6 -7
- package/src/idl/clearing_house.json +614 -64
- package/src/math/bankBalance.ts +50 -1
- package/src/math/oracles.ts +42 -5
- package/src/math/position.ts +2 -1
- package/src/math/trade.ts +2 -2
- package/src/types.ts +63 -9
- package/tests/bn/test.ts +8 -0
- package/src/accounts/bulkAccountLoader.js +0 -197
- package/src/accounts/bulkUserSubscription.js +0 -33
- package/src/accounts/pollingClearingHouseAccountSubscriber.js +0 -311
- package/src/accounts/pollingOracleSubscriber.js +0 -93
- package/src/accounts/pollingTokenAccountSubscriber.js +0 -90
- package/src/accounts/pollingUserAccountSubscriber.js +0 -132
- package/src/accounts/types.js +0 -10
- package/src/accounts/utils.js +0 -7
- package/src/accounts/webSocketAccountSubscriber.js +0 -93
- package/src/accounts/webSocketClearingHouseAccountSubscriber.js +0 -233
- package/src/accounts/webSocketUserAccountSubscriber.js +0 -62
- package/src/addresses/marketAddresses.js +0 -26
- package/src/assert/assert.js +0 -9
- package/src/clearingHouseUserConfig.js +0 -2
- package/src/constants/banks.js +0 -42
- package/src/constants/markets.js +0 -42
- package/src/constants/numericConstants.js +0 -41
- package/src/events/eventList.js +0 -77
- package/src/events/eventSubscriber.js +0 -139
- package/src/events/fetchLogs.js +0 -50
- package/src/events/pollingLogProvider.js +0 -64
- package/src/events/sort.js +0 -44
- package/src/events/txEventCache.js +0 -71
- package/src/events/types.js +0 -20
- package/src/events/webSocketLogProvider.js +0 -41
- package/src/examples/makeTradeExample.js +0 -80
- package/src/factory/bigNum.js +0 -390
- package/src/factory/oracleClient.js +0 -20
- package/src/index.js +0 -69
- package/src/math/amm.js +0 -369
- package/src/math/auction.js +0 -42
- package/src/math/conversion.js +0 -11
- package/src/math/funding.js +0 -248
- package/src/math/oracles.js +0 -26
- package/src/math/repeg.js +0 -128
- package/src/math/state.js +0 -15
- package/src/math/trade.js +0 -253
- package/src/math/utils.js +0 -26
- package/src/math/utils.js.map +0 -1
- package/src/mockUSDCFaucet.js +0 -280
- package/src/oracles/oracleClientCache.js +0 -19
- package/src/oracles/pythClient.js +0 -46
- package/src/oracles/quoteAssetOracleClient.js +0 -32
- package/src/oracles/switchboardClient.js +0 -69
- package/src/oracles/types.js +0 -2
- package/src/orderParams.js +0 -20
- package/src/slot/SlotSubscriber.js +0 -39
- package/src/token/index.js +0 -38
- package/src/tokenFaucet.js +0 -189
- package/src/tx/types.js +0 -2
- package/src/tx/utils.js +0 -17
- package/src/types.js +0 -125
- package/src/userName.js +0 -20
- package/src/util/computeUnits.js +0 -27
- package/src/util/getTokenAddress.js +0 -9
- package/src/util/promiseTimeout.js +0 -14
- package/src/util/tps.js +0 -27
- package/src/wallet.js +0 -35
package/lib/clearingHouse.js
CHANGED
|
@@ -45,6 +45,7 @@ const retryTxSender_1 = require("./tx/retryTxSender");
|
|
|
45
45
|
const clearingHouseUser_1 = require("./clearingHouseUser");
|
|
46
46
|
const config_1 = require("./config");
|
|
47
47
|
const banks_1 = require("./constants/banks");
|
|
48
|
+
const clearingHouseUserStats_1 = require("./clearingHouseUserStats");
|
|
48
49
|
/**
|
|
49
50
|
* # ClearingHouse
|
|
50
51
|
* This class is the main way to interact with Drift Protocol. It allows you to subscribe to the various accounts where the Market's state is stored, as well as: opening positions, liquidating, settling funding, depositing & withdrawing, and more.
|
|
@@ -72,6 +73,13 @@ class ClearingHouse {
|
|
|
72
73
|
type: 'websocket',
|
|
73
74
|
};
|
|
74
75
|
this.createUsers(userIds, this.userAccountSubscriptionConfig);
|
|
76
|
+
if (config.userStats) {
|
|
77
|
+
this.userStats = new clearingHouseUserStats_1.ClearingHouseUserStats({
|
|
78
|
+
clearingHouse: this,
|
|
79
|
+
userStatsAccountPublicKey: (0, pda_1.getUserStatsAccountPublicKey)(this.program.programId, this.wallet.publicKey),
|
|
80
|
+
accountSubscription: this.userAccountSubscriptionConfig,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
75
83
|
let marketIndexes = config.marketIndexes;
|
|
76
84
|
let bankIndexes = config.bankIndexes;
|
|
77
85
|
let oracleInfos = config.oracleInfos;
|
|
@@ -112,6 +120,9 @@ class ClearingHouse {
|
|
|
112
120
|
}
|
|
113
121
|
async subscribe() {
|
|
114
122
|
const subscribePromises = this.subscribeUsers().concat(this.accountSubscriber.subscribe());
|
|
123
|
+
if (this.userStats !== undefined) {
|
|
124
|
+
subscribePromises.concat(this.userStats.subscribe());
|
|
125
|
+
}
|
|
115
126
|
this.isSubscribed = (await Promise.all(subscribePromises)).reduce((success, prevSuccess) => success && prevSuccess);
|
|
116
127
|
return this.isSubscribed;
|
|
117
128
|
}
|
|
@@ -128,6 +139,9 @@ class ClearingHouse {
|
|
|
128
139
|
}
|
|
129
140
|
async unsubscribe() {
|
|
130
141
|
const unsubscribePromises = this.unsubscribeUsers().concat(this.accountSubscriber.unsubscribe());
|
|
142
|
+
if (this.userStats !== undefined) {
|
|
143
|
+
unsubscribePromises.concat(this.userStats.unsubscribe());
|
|
144
|
+
}
|
|
131
145
|
await Promise.all(unsubscribePromises);
|
|
132
146
|
this.isSubscribed = false;
|
|
133
147
|
}
|
|
@@ -188,6 +202,7 @@ class ClearingHouse {
|
|
|
188
202
|
await Promise.all(this.subscribeUsers());
|
|
189
203
|
}
|
|
190
204
|
this.activeUserId = activeUserId;
|
|
205
|
+
this.userStatsAccountPublicKey = undefined;
|
|
191
206
|
}
|
|
192
207
|
async switchActiveUser(userId) {
|
|
193
208
|
this.activeUserId = userId;
|
|
@@ -202,7 +217,12 @@ class ClearingHouse {
|
|
|
202
217
|
}
|
|
203
218
|
async initializeUserAccount(userId = 0, name = userName_1.DEFAULT_USER_NAME) {
|
|
204
219
|
const [userAccountPublicKey, initializeUserAccountIx] = await this.getInitializeUserInstructions(userId, name);
|
|
205
|
-
const tx = new web3_js_1.Transaction()
|
|
220
|
+
const tx = new web3_js_1.Transaction();
|
|
221
|
+
if (userId === 0) {
|
|
222
|
+
// not the safest assumption, can explicitly check if user stats account exists if it causes problems
|
|
223
|
+
tx.add(await this.getInitializeUserStatsIx());
|
|
224
|
+
}
|
|
225
|
+
tx.add(initializeUserAccountIx);
|
|
206
226
|
const { txSig } = await this.txSender.send(tx, [], this.opts);
|
|
207
227
|
return [txSig, userAccountPublicKey];
|
|
208
228
|
}
|
|
@@ -212,6 +232,7 @@ class ClearingHouse {
|
|
|
212
232
|
const initializeUserAccountIx = await this.program.instruction.initializeUser(userId, nameBuffer, {
|
|
213
233
|
accounts: {
|
|
214
234
|
user: userAccountPublicKey,
|
|
235
|
+
userStats: this.getUserStatsAccountPublicKey(),
|
|
215
236
|
authority: this.wallet.publicKey,
|
|
216
237
|
payer: this.wallet.publicKey,
|
|
217
238
|
rent: anchor.web3.SYSVAR_RENT_PUBKEY,
|
|
@@ -221,6 +242,18 @@ class ClearingHouse {
|
|
|
221
242
|
});
|
|
222
243
|
return [userAccountPublicKey, initializeUserAccountIx];
|
|
223
244
|
}
|
|
245
|
+
async getInitializeUserStatsIx() {
|
|
246
|
+
return await this.program.instruction.initializeUserStats({
|
|
247
|
+
accounts: {
|
|
248
|
+
userStats: this.getUserStatsAccountPublicKey(),
|
|
249
|
+
authority: this.wallet.publicKey,
|
|
250
|
+
payer: this.wallet.publicKey,
|
|
251
|
+
rent: anchor.web3.SYSVAR_RENT_PUBKEY,
|
|
252
|
+
systemProgram: anchor.web3.SystemProgram.programId,
|
|
253
|
+
state: await this.getStatePublicKey(),
|
|
254
|
+
},
|
|
255
|
+
});
|
|
256
|
+
}
|
|
224
257
|
getUser(userId) {
|
|
225
258
|
userId = userId !== null && userId !== void 0 ? userId : this.activeUserId;
|
|
226
259
|
if (!this.users.has(userId)) {
|
|
@@ -231,6 +264,16 @@ class ClearingHouse {
|
|
|
231
264
|
getUsers() {
|
|
232
265
|
return [...this.users.values()];
|
|
233
266
|
}
|
|
267
|
+
getUserStats() {
|
|
268
|
+
return this.userStats;
|
|
269
|
+
}
|
|
270
|
+
getUserStatsAccountPublicKey() {
|
|
271
|
+
if (this.userStatsAccountPublicKey) {
|
|
272
|
+
return this.userStatsAccountPublicKey;
|
|
273
|
+
}
|
|
274
|
+
this.userStatsAccountPublicKey = (0, pda_1.getUserStatsAccountPublicKey)(this.program.programId, this.wallet.publicKey);
|
|
275
|
+
return this.userStatsAccountPublicKey;
|
|
276
|
+
}
|
|
234
277
|
async getUserAccountPublicKey() {
|
|
235
278
|
return this.getUser().userAccountPublicKey;
|
|
236
279
|
}
|
|
@@ -511,6 +554,9 @@ class ClearingHouse {
|
|
|
511
554
|
const depositCollateralIx = fromUserId != null
|
|
512
555
|
? await this.getTransferDepositIx(amount, bankIndex, fromUserId, userId)
|
|
513
556
|
: await this.getDepositInstruction(amount, bankIndex, userTokenAccount, userId, false, false);
|
|
557
|
+
if (userId === 0) {
|
|
558
|
+
tx.add(await this.getInitializeUserStatsIx());
|
|
559
|
+
}
|
|
514
560
|
tx.add(initializeUserAccountIx).add(depositCollateralIx);
|
|
515
561
|
// Close the wrapped sol account at the end of the transaction
|
|
516
562
|
if (createWSOLTokenAccount) {
|
|
@@ -523,11 +569,11 @@ class ClearingHouse {
|
|
|
523
569
|
const [associateTokenPublicKey, createAssociatedAccountIx, mintToIx] = await tokenFaucet.createAssociatedTokenAccountAndMintToInstructions(this.wallet.publicKey, amount);
|
|
524
570
|
const [userAccountPublicKey, initializeUserAccountIx] = await this.getInitializeUserInstructions(userId, name);
|
|
525
571
|
const depositCollateralIx = await this.getDepositInstruction(amount, bankIndex, associateTokenPublicKey, userId, false, false);
|
|
526
|
-
const tx = new web3_js_1.Transaction()
|
|
527
|
-
|
|
528
|
-
.add(
|
|
529
|
-
|
|
530
|
-
|
|
572
|
+
const tx = new web3_js_1.Transaction().add(createAssociatedAccountIx).add(mintToIx);
|
|
573
|
+
if (userId === 0) {
|
|
574
|
+
tx.add(await this.getInitializeUserStatsIx());
|
|
575
|
+
}
|
|
576
|
+
tx.add(initializeUserAccountIx).add(depositCollateralIx);
|
|
531
577
|
const txSig = await this.program.provider.sendAndConfirm(tx, []);
|
|
532
578
|
return [txSig, userAccountPublicKey];
|
|
533
579
|
}
|
|
@@ -607,6 +653,82 @@ class ClearingHouse {
|
|
|
607
653
|
},
|
|
608
654
|
});
|
|
609
655
|
}
|
|
656
|
+
async settleLP(settleeUserAccountPublicKey, marketIndex) {
|
|
657
|
+
const { txSig } = await this.txSender.send((0, utils_1.wrapInTx)(await this.settleLPIx(settleeUserAccountPublicKey, marketIndex)), [], this.opts);
|
|
658
|
+
return txSig;
|
|
659
|
+
}
|
|
660
|
+
async settleLPIx(settleeUserAccountPublicKey, marketIndex) {
|
|
661
|
+
const settleeUserAccount = (await this.program.account.user.fetch(settleeUserAccountPublicKey));
|
|
662
|
+
const userPositions = settleeUserAccount.positions;
|
|
663
|
+
const remainingAccounts = [];
|
|
664
|
+
let foundMarket = false;
|
|
665
|
+
for (const position of userPositions) {
|
|
666
|
+
if (!(0, position_1.positionIsAvailable)(position)) {
|
|
667
|
+
const marketPublicKey = await (0, pda_1.getMarketPublicKey)(this.program.programId, position.marketIndex);
|
|
668
|
+
remainingAccounts.push({
|
|
669
|
+
pubkey: marketPublicKey,
|
|
670
|
+
isWritable: true,
|
|
671
|
+
isSigner: false,
|
|
672
|
+
});
|
|
673
|
+
if (marketIndex.eq(position.marketIndex)) {
|
|
674
|
+
foundMarket = true;
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
if (!foundMarket) {
|
|
679
|
+
console.log('Warning: lp is not in the market specified -- tx will likely fail');
|
|
680
|
+
}
|
|
681
|
+
return this.program.instruction.settleLp(marketIndex, {
|
|
682
|
+
accounts: {
|
|
683
|
+
state: await this.getStatePublicKey(),
|
|
684
|
+
user: settleeUserAccountPublicKey,
|
|
685
|
+
},
|
|
686
|
+
remainingAccounts: remainingAccounts,
|
|
687
|
+
});
|
|
688
|
+
}
|
|
689
|
+
async removeLiquidity(marketIndex, sharesToBurn) {
|
|
690
|
+
const { txSig } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getRemoveLiquidityIx(marketIndex, sharesToBurn)), [], this.opts);
|
|
691
|
+
return txSig;
|
|
692
|
+
}
|
|
693
|
+
async getRemoveLiquidityIx(marketIndex, sharesToBurn) {
|
|
694
|
+
const userAccountPublicKey = await this.getUserAccountPublicKey();
|
|
695
|
+
const remainingAccounts = this.getRemainingAccounts({
|
|
696
|
+
writableMarketIndex: marketIndex,
|
|
697
|
+
});
|
|
698
|
+
if (sharesToBurn == undefined) {
|
|
699
|
+
const userAccount = this.getUserAccount();
|
|
700
|
+
const marketPosition = userAccount.positions.filter((position) => position.marketIndex.eq(marketIndex))[0];
|
|
701
|
+
sharesToBurn = marketPosition.lpShares;
|
|
702
|
+
console.log('burning lp shares:', sharesToBurn.toString());
|
|
703
|
+
}
|
|
704
|
+
return this.program.instruction.removeLiquidity(sharesToBurn, marketIndex, {
|
|
705
|
+
accounts: {
|
|
706
|
+
state: await this.getStatePublicKey(),
|
|
707
|
+
user: userAccountPublicKey,
|
|
708
|
+
authority: this.wallet.publicKey,
|
|
709
|
+
},
|
|
710
|
+
remainingAccounts: remainingAccounts,
|
|
711
|
+
});
|
|
712
|
+
}
|
|
713
|
+
async addLiquidity(amount, marketIndex) {
|
|
714
|
+
const { txSig, slot } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getAddLiquidityIx(amount, marketIndex)), [], this.opts);
|
|
715
|
+
this.marketLastSlotCache.set(marketIndex.toNumber(), slot);
|
|
716
|
+
return txSig;
|
|
717
|
+
}
|
|
718
|
+
async getAddLiquidityIx(amount, marketIndex) {
|
|
719
|
+
const userAccountPublicKey = await this.getUserAccountPublicKey();
|
|
720
|
+
const remainingAccounts = this.getRemainingAccounts({
|
|
721
|
+
writableMarketIndex: marketIndex,
|
|
722
|
+
});
|
|
723
|
+
return this.program.instruction.addLiquidity(amount, marketIndex, {
|
|
724
|
+
accounts: {
|
|
725
|
+
state: await this.getStatePublicKey(),
|
|
726
|
+
user: userAccountPublicKey,
|
|
727
|
+
authority: this.wallet.publicKey,
|
|
728
|
+
},
|
|
729
|
+
remainingAccounts: remainingAccounts,
|
|
730
|
+
});
|
|
731
|
+
}
|
|
610
732
|
async openPosition(direction, amount, marketIndex, limitPrice) {
|
|
611
733
|
return await this.placeAndTake({
|
|
612
734
|
orderType: types_1.OrderType.MARKET,
|
|
@@ -634,6 +756,7 @@ class ClearingHouse {
|
|
|
634
756
|
accounts: {
|
|
635
757
|
state: await this.getStatePublicKey(),
|
|
636
758
|
user: userAccountPublicKey,
|
|
759
|
+
userStats: this.getUserStatsAccountPublicKey(),
|
|
637
760
|
authority: this.wallet.publicKey,
|
|
638
761
|
},
|
|
639
762
|
remainingAccounts,
|
|
@@ -713,7 +836,9 @@ class ClearingHouse {
|
|
|
713
836
|
return txSig;
|
|
714
837
|
}
|
|
715
838
|
async getFillOrderIx(userAccountPublicKey, userAccount, order, makerInfo) {
|
|
839
|
+
const userStatsPublicKey = (0, pda_1.getUserStatsAccountPublicKey)(this.program.programId, userAccount.authority);
|
|
716
840
|
const fillerPublicKey = await this.getUserAccountPublicKey();
|
|
841
|
+
const fillerStatsPublicKey = this.getUserStatsAccountPublicKey();
|
|
717
842
|
const marketIndex = order.marketIndex;
|
|
718
843
|
const marketAccount = this.getMarketAccount(marketIndex);
|
|
719
844
|
const oracleAccountMap = new Map();
|
|
@@ -773,6 +898,11 @@ class ClearingHouse {
|
|
|
773
898
|
isWritable: true,
|
|
774
899
|
isSigner: false,
|
|
775
900
|
});
|
|
901
|
+
remainingAccounts.push({
|
|
902
|
+
pubkey: makerInfo.makerStats,
|
|
903
|
+
isWritable: true,
|
|
904
|
+
isSigner: false,
|
|
905
|
+
});
|
|
776
906
|
}
|
|
777
907
|
const orderId = order.orderId;
|
|
778
908
|
const makerOrderId = makerInfo ? makerInfo.order.orderId : null;
|
|
@@ -780,7 +910,9 @@ class ClearingHouse {
|
|
|
780
910
|
accounts: {
|
|
781
911
|
state: await this.getStatePublicKey(),
|
|
782
912
|
filler: fillerPublicKey,
|
|
913
|
+
fillerStats: fillerStatsPublicKey,
|
|
783
914
|
user: userAccountPublicKey,
|
|
915
|
+
userStats: userStatsPublicKey,
|
|
784
916
|
authority: this.wallet.publicKey,
|
|
785
917
|
},
|
|
786
918
|
remainingAccounts,
|
|
@@ -863,6 +995,7 @@ class ClearingHouse {
|
|
|
863
995
|
}
|
|
864
996
|
async getPlaceAndTakeIx(orderParams, makerInfo) {
|
|
865
997
|
orderParams = this.getOrderParams(orderParams);
|
|
998
|
+
const userStatsPublicKey = await this.getUserStatsAccountPublicKey();
|
|
866
999
|
const userAccountPublicKey = await this.getUserAccountPublicKey();
|
|
867
1000
|
const remainingAccounts = this.getRemainingAccounts({
|
|
868
1001
|
writableMarketIndex: orderParams.marketIndex,
|
|
@@ -876,11 +1009,17 @@ class ClearingHouse {
|
|
|
876
1009
|
isSigner: false,
|
|
877
1010
|
isWritable: true,
|
|
878
1011
|
});
|
|
1012
|
+
remainingAccounts.push({
|
|
1013
|
+
pubkey: makerInfo.makerStats,
|
|
1014
|
+
isSigner: false,
|
|
1015
|
+
isWritable: true,
|
|
1016
|
+
});
|
|
879
1017
|
}
|
|
880
1018
|
return await this.program.instruction.placeAndTake(orderParams, makerOrderId, {
|
|
881
1019
|
accounts: {
|
|
882
1020
|
state: await this.getStatePublicKey(),
|
|
883
1021
|
user: userAccountPublicKey,
|
|
1022
|
+
userStats: userStatsPublicKey,
|
|
884
1023
|
authority: this.wallet.publicKey,
|
|
885
1024
|
},
|
|
886
1025
|
remainingAccounts,
|
|
@@ -893,22 +1032,19 @@ class ClearingHouse {
|
|
|
893
1032
|
}
|
|
894
1033
|
async getPlaceAndMakeIx(orderParams, takerInfo) {
|
|
895
1034
|
orderParams = this.getOrderParams(orderParams);
|
|
1035
|
+
const userStatsPublicKey = this.getUserStatsAccountPublicKey();
|
|
896
1036
|
const userAccountPublicKey = await this.getUserAccountPublicKey();
|
|
897
1037
|
const remainingAccounts = this.getRemainingAccounts({
|
|
898
1038
|
writableMarketIndex: orderParams.marketIndex,
|
|
899
|
-
writableBankIndex: numericConstants_1.QUOTE_ASSET_BANK_INDEX,
|
|
900
1039
|
});
|
|
901
1040
|
const takerOrderId = takerInfo.order.orderId;
|
|
902
|
-
remainingAccounts.push({
|
|
903
|
-
pubkey: takerInfo.taker,
|
|
904
|
-
isSigner: false,
|
|
905
|
-
isWritable: true,
|
|
906
|
-
});
|
|
907
1041
|
return await this.program.instruction.placeAndMake(orderParams, takerOrderId, {
|
|
908
1042
|
accounts: {
|
|
909
1043
|
state: await this.getStatePublicKey(),
|
|
910
1044
|
user: userAccountPublicKey,
|
|
1045
|
+
userStats: userStatsPublicKey,
|
|
911
1046
|
taker: takerInfo.taker,
|
|
1047
|
+
takerStats: takerInfo.takerStats,
|
|
912
1048
|
authority: this.wallet.publicKey,
|
|
913
1049
|
},
|
|
914
1050
|
remainingAccounts,
|
|
@@ -919,7 +1055,7 @@ class ClearingHouse {
|
|
|
919
1055
|
* @param marketIndex
|
|
920
1056
|
* @returns
|
|
921
1057
|
*/
|
|
922
|
-
async closePosition(marketIndex) {
|
|
1058
|
+
async closePosition(marketIndex, limitPrice) {
|
|
923
1059
|
const userPosition = this.getUser().getUserPosition(marketIndex);
|
|
924
1060
|
if (!userPosition) {
|
|
925
1061
|
throw Error(`No position in market ${marketIndex.toString()}`);
|
|
@@ -928,8 +1064,9 @@ class ClearingHouse {
|
|
|
928
1064
|
orderType: types_1.OrderType.MARKET,
|
|
929
1065
|
marketIndex,
|
|
930
1066
|
direction: (0, position_1.findDirectionToClose)(userPosition),
|
|
931
|
-
baseAssetAmount: userPosition.baseAssetAmount,
|
|
1067
|
+
baseAssetAmount: userPosition.baseAssetAmount.abs(),
|
|
932
1068
|
reduceOnly: true,
|
|
1069
|
+
price: limitPrice,
|
|
933
1070
|
});
|
|
934
1071
|
}
|
|
935
1072
|
async settlePNLs(users, marketIndex) {
|
|
@@ -1016,7 +1153,9 @@ class ClearingHouse {
|
|
|
1016
1153
|
return txSig;
|
|
1017
1154
|
}
|
|
1018
1155
|
async getLiquidatePerpIx(userAccountPublicKey, userAccount, marketIndex, maxBaseAssetAmount) {
|
|
1156
|
+
const userStatsPublicKey = (0, pda_1.getUserStatsAccountPublicKey)(this.program.programId, userAccount.authority);
|
|
1019
1157
|
const liquidatorPublicKey = await this.getUserAccountPublicKey();
|
|
1158
|
+
const liquidatorStatsPublicKey = this.getUserStatsAccountPublicKey();
|
|
1020
1159
|
const remainingAccounts = this.getRemainingAccountsForLiquidation({
|
|
1021
1160
|
writableMarketIndex: marketIndex,
|
|
1022
1161
|
userAccount,
|
|
@@ -1026,7 +1165,9 @@ class ClearingHouse {
|
|
|
1026
1165
|
state: await this.getStatePublicKey(),
|
|
1027
1166
|
authority: this.wallet.publicKey,
|
|
1028
1167
|
user: userAccountPublicKey,
|
|
1168
|
+
userStats: userStatsPublicKey,
|
|
1029
1169
|
liquidator: liquidatorPublicKey,
|
|
1170
|
+
liquidatorStats: liquidatorStatsPublicKey,
|
|
1030
1171
|
},
|
|
1031
1172
|
remainingAccounts: remainingAccounts,
|
|
1032
1173
|
});
|
|
@@ -1093,6 +1234,46 @@ class ClearingHouse {
|
|
|
1093
1234
|
remainingAccounts: remainingAccounts,
|
|
1094
1235
|
});
|
|
1095
1236
|
}
|
|
1237
|
+
async resolvePerpBankruptcy(userAccountPublicKey, userAccount, marketIndex) {
|
|
1238
|
+
const { txSig } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getResolvePerpBankruptcyIx(userAccountPublicKey, userAccount, marketIndex)), [], this.opts);
|
|
1239
|
+
return txSig;
|
|
1240
|
+
}
|
|
1241
|
+
async getResolvePerpBankruptcyIx(userAccountPublicKey, userAccount, marketIndex) {
|
|
1242
|
+
const liquidatorPublicKey = await this.getUserAccountPublicKey();
|
|
1243
|
+
const remainingAccounts = this.getRemainingAccountsForLiquidation({
|
|
1244
|
+
writableMarketIndex: marketIndex,
|
|
1245
|
+
userAccount,
|
|
1246
|
+
});
|
|
1247
|
+
return await this.program.instruction.resolvePerpBankruptcy(marketIndex, {
|
|
1248
|
+
accounts: {
|
|
1249
|
+
state: await this.getStatePublicKey(),
|
|
1250
|
+
authority: this.wallet.publicKey,
|
|
1251
|
+
user: userAccountPublicKey,
|
|
1252
|
+
liquidator: liquidatorPublicKey,
|
|
1253
|
+
},
|
|
1254
|
+
remainingAccounts: remainingAccounts,
|
|
1255
|
+
});
|
|
1256
|
+
}
|
|
1257
|
+
async resolveBorrowBankruptcy(userAccountPublicKey, userAccount, bankIndex) {
|
|
1258
|
+
const { txSig } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getResolveBorrowBankruptcyIx(userAccountPublicKey, userAccount, bankIndex)), [], this.opts);
|
|
1259
|
+
return txSig;
|
|
1260
|
+
}
|
|
1261
|
+
async getResolveBorrowBankruptcyIx(userAccountPublicKey, userAccount, bankIndex) {
|
|
1262
|
+
const liquidatorPublicKey = await this.getUserAccountPublicKey();
|
|
1263
|
+
const remainingAccounts = this.getRemainingAccountsForLiquidation({
|
|
1264
|
+
writableBankIndexes: [bankIndex],
|
|
1265
|
+
userAccount,
|
|
1266
|
+
});
|
|
1267
|
+
return await this.program.instruction.resolveBorrowBankruptcy(bankIndex, {
|
|
1268
|
+
accounts: {
|
|
1269
|
+
state: await this.getStatePublicKey(),
|
|
1270
|
+
authority: this.wallet.publicKey,
|
|
1271
|
+
user: userAccountPublicKey,
|
|
1272
|
+
liquidator: liquidatorPublicKey,
|
|
1273
|
+
},
|
|
1274
|
+
remainingAccounts: remainingAccounts,
|
|
1275
|
+
});
|
|
1276
|
+
}
|
|
1096
1277
|
getRemainingAccountsForLiquidation(params) {
|
|
1097
1278
|
const liquidateeUserAccount = params.userAccount;
|
|
1098
1279
|
const oracleAccountMap = new Map();
|
|
@@ -49,6 +49,11 @@ export declare class ClearingHouseUser {
|
|
|
49
49
|
getOrderByUserOrderId(userOrderId: number): Order | undefined;
|
|
50
50
|
getUserAccountPublicKey(): PublicKey;
|
|
51
51
|
exists(): Promise<boolean>;
|
|
52
|
+
/**
|
|
53
|
+
* calculates the market position if the lp position was settled
|
|
54
|
+
* @returns : userPosition
|
|
55
|
+
*/
|
|
56
|
+
getSettledLPPosition(marketIndex: BN): [UserPosition, BN];
|
|
52
57
|
/**
|
|
53
58
|
* calculates Buying Power = FC * MAX_LEVERAGE
|
|
54
59
|
* @returns : Precision QUOTE_PRECISION
|
package/lib/clearingHouseUser.js
CHANGED
|
@@ -71,6 +71,11 @@ class ClearingHouseUser {
|
|
|
71
71
|
openOrders: numericConstants_1.ZERO,
|
|
72
72
|
openBids: numericConstants_1.ZERO,
|
|
73
73
|
openAsks: numericConstants_1.ZERO,
|
|
74
|
+
realizedPnl: numericConstants_1.ZERO,
|
|
75
|
+
lpShares: numericConstants_1.ZERO,
|
|
76
|
+
lastFeePerLp: numericConstants_1.ZERO,
|
|
77
|
+
lastNetBaseAssetAmountPerLp: numericConstants_1.ZERO,
|
|
78
|
+
lastNetQuoteAssetAmountPerLp: numericConstants_1.ZERO,
|
|
74
79
|
};
|
|
75
80
|
}
|
|
76
81
|
/**
|
|
@@ -94,6 +99,89 @@ class ClearingHouseUser {
|
|
|
94
99
|
const userAccountRPCResponse = await this.clearingHouse.connection.getParsedAccountInfo(this.userAccountPublicKey);
|
|
95
100
|
return userAccountRPCResponse.value !== null;
|
|
96
101
|
}
|
|
102
|
+
/**
|
|
103
|
+
* calculates the market position if the lp position was settled
|
|
104
|
+
* @returns : userPosition
|
|
105
|
+
*/
|
|
106
|
+
getSettledLPPosition(marketIndex) {
|
|
107
|
+
const position = this.getUserPosition(marketIndex);
|
|
108
|
+
const market = this.clearingHouse.getMarketAccount(position.marketIndex);
|
|
109
|
+
const nShares = position.lpShares;
|
|
110
|
+
const deltaBaa = market.amm.marketPositionPerLp.baseAssetAmount
|
|
111
|
+
.sub(position.lastNetBaseAssetAmountPerLp)
|
|
112
|
+
.mul(nShares)
|
|
113
|
+
.div(numericConstants_1.AMM_RESERVE_PRECISION);
|
|
114
|
+
const deltaQaa = market.amm.marketPositionPerLp.quoteAssetAmount
|
|
115
|
+
.sub(position.lastNetQuoteAssetAmountPerLp)
|
|
116
|
+
.mul(nShares)
|
|
117
|
+
.div(numericConstants_1.AMM_RESERVE_PRECISION);
|
|
118
|
+
function sign(v) {
|
|
119
|
+
const sign = { true: new _1.BN(1), false: new _1.BN(-1) }[v.gte(numericConstants_1.ZERO).toString()];
|
|
120
|
+
return sign;
|
|
121
|
+
}
|
|
122
|
+
const remainder = deltaBaa
|
|
123
|
+
.abs()
|
|
124
|
+
.mod(market.amm.baseAssetAmountStepSize)
|
|
125
|
+
.mul(sign(deltaBaa));
|
|
126
|
+
const _standardizedBaa = deltaBaa.sub(remainder);
|
|
127
|
+
let remainderBaa;
|
|
128
|
+
if (_standardizedBaa.abs().gte(market.amm.baseAssetAmountStepSize)) {
|
|
129
|
+
remainderBaa = remainder;
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
remainderBaa = deltaBaa;
|
|
133
|
+
}
|
|
134
|
+
const standardizedBaa = deltaBaa.sub(remainderBaa);
|
|
135
|
+
const reaminderPerLP = remainderBaa.mul(numericConstants_1.AMM_RESERVE_PRECISION).div(nShares);
|
|
136
|
+
position.baseAssetAmount = position.baseAssetAmount.add(standardizedBaa);
|
|
137
|
+
position.quoteAssetAmount = position.quoteAssetAmount.add(deltaQaa);
|
|
138
|
+
position.lastNetBaseAssetAmountPerLp =
|
|
139
|
+
market.amm.marketPositionPerLp.baseAssetAmount.sub(reaminderPerLP);
|
|
140
|
+
let updateType;
|
|
141
|
+
if (position.baseAssetAmount.eq(numericConstants_1.ZERO)) {
|
|
142
|
+
updateType = 'open';
|
|
143
|
+
}
|
|
144
|
+
else if (sign(position.baseAssetAmount).eq(sign(deltaBaa))) {
|
|
145
|
+
updateType = 'increase';
|
|
146
|
+
}
|
|
147
|
+
else if (position.baseAssetAmount.abs().gt(deltaBaa.abs())) {
|
|
148
|
+
updateType = 'reduce';
|
|
149
|
+
}
|
|
150
|
+
else if (position.baseAssetAmount.abs().eq(deltaBaa.abs())) {
|
|
151
|
+
updateType = 'close';
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
updateType = 'flip';
|
|
155
|
+
}
|
|
156
|
+
let newQuoteEntry;
|
|
157
|
+
let pnl;
|
|
158
|
+
if (updateType == 'open' || updateType == 'increase') {
|
|
159
|
+
newQuoteEntry = position.quoteEntryAmount.add(deltaQaa);
|
|
160
|
+
pnl = 0;
|
|
161
|
+
}
|
|
162
|
+
else if (updateType == 'reduce' || updateType == 'close') {
|
|
163
|
+
newQuoteEntry = position.quoteEntryAmount.sub(position.quoteEntryAmount
|
|
164
|
+
.mul(deltaBaa.abs())
|
|
165
|
+
.div(position.baseAssetAmount.abs()));
|
|
166
|
+
pnl = position.quoteEntryAmount.sub(newQuoteEntry);
|
|
167
|
+
}
|
|
168
|
+
else {
|
|
169
|
+
newQuoteEntry = deltaQaa.sub(deltaQaa.mul(position.baseAssetAmount.abs()).div(deltaBaa.abs()));
|
|
170
|
+
pnl = position.quoteEntryAmount.add(deltaQaa.sub(newQuoteEntry));
|
|
171
|
+
}
|
|
172
|
+
position.quoteEntryAmount = newQuoteEntry;
|
|
173
|
+
if (position.baseAssetAmount.gt(numericConstants_1.ZERO)) {
|
|
174
|
+
position.lastCumulativeFundingRate = market.amm.cumulativeFundingRateLong;
|
|
175
|
+
}
|
|
176
|
+
else if (position.baseAssetAmount.lt(numericConstants_1.ZERO)) {
|
|
177
|
+
position.lastCumulativeFundingRate =
|
|
178
|
+
market.amm.cumulativeFundingRateShort;
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
position.lastCumulativeFundingRate = numericConstants_1.ZERO;
|
|
182
|
+
}
|
|
183
|
+
return [position, pnl];
|
|
184
|
+
}
|
|
97
185
|
/**
|
|
98
186
|
* calculates Buying Power = FC * MAX_LEVERAGE
|
|
99
187
|
* @returns : Precision QUOTE_PRECISION
|
|
@@ -411,12 +499,17 @@ class ClearingHouseUser {
|
|
|
411
499
|
const proposedMarketPosition = {
|
|
412
500
|
marketIndex: marketPosition.marketIndex,
|
|
413
501
|
baseAssetAmount: proposedBaseAssetAmount,
|
|
414
|
-
lastCumulativeFundingRate: currentMarketPosition.lastCumulativeFundingRate,
|
|
415
502
|
quoteAssetAmount: new _1.BN(0),
|
|
503
|
+
lastCumulativeFundingRate: numericConstants_1.ZERO,
|
|
416
504
|
quoteEntryAmount: new _1.BN(0),
|
|
417
505
|
openOrders: new _1.BN(0),
|
|
418
506
|
openBids: new _1.BN(0),
|
|
419
507
|
openAsks: new _1.BN(0),
|
|
508
|
+
realizedPnl: numericConstants_1.ZERO,
|
|
509
|
+
lpShares: numericConstants_1.ZERO,
|
|
510
|
+
lastFeePerLp: numericConstants_1.ZERO,
|
|
511
|
+
lastNetBaseAssetAmountPerLp: numericConstants_1.ZERO,
|
|
512
|
+
lastNetQuoteAssetAmountPerLp: numericConstants_1.ZERO,
|
|
420
513
|
};
|
|
421
514
|
if (proposedBaseAssetAmount.eq(numericConstants_1.ZERO))
|
|
422
515
|
return new _1.BN(-1);
|
|
@@ -428,8 +521,9 @@ class ClearingHouseUser {
|
|
|
428
521
|
if (!position.marketIndex.eq(marketPosition.marketIndex)) {
|
|
429
522
|
const market = this.clearingHouse.getMarketAccount(position.marketIndex);
|
|
430
523
|
const positionValue = (0, margin_1.calculateMarginBaseAssetValue)(market, position, this.getOracleDataForMarket(market.marketIndex));
|
|
431
|
-
const marketMarginRequirement = positionValue
|
|
432
|
-
|
|
524
|
+
const marketMarginRequirement = positionValue
|
|
525
|
+
.mul(new _1.BN((0, _1.calculateMarketMarginRatio)(market, position.baseAssetAmount.abs(), 'Maintenance')))
|
|
526
|
+
.div(numericConstants_1.MARGIN_PRECISION);
|
|
433
527
|
totalMarginRequirement = totalMarginRequirement.add(marketMarginRequirement);
|
|
434
528
|
}
|
|
435
529
|
return totalMarginRequirement;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { ClearingHouse } from './clearingHouse';
|
|
2
|
+
import { PublicKey } from '@solana/web3.js';
|
|
3
|
+
import { DataAndSlot, UserStatsAccountSubscriber } from './accounts/types';
|
|
4
|
+
import { ClearingHouseUserStatsConfig } from './clearingHouseUserStatsConfig';
|
|
5
|
+
import { UserStatsAccount } from './types';
|
|
6
|
+
export declare class ClearingHouseUserStats {
|
|
7
|
+
clearingHouse: ClearingHouse;
|
|
8
|
+
userStatsAccountPublicKey: PublicKey;
|
|
9
|
+
accountSubscriber: UserStatsAccountSubscriber;
|
|
10
|
+
isSubscribed: boolean;
|
|
11
|
+
constructor(config: ClearingHouseUserStatsConfig);
|
|
12
|
+
subscribe(): Promise<boolean>;
|
|
13
|
+
fetchAccounts(): Promise<void>;
|
|
14
|
+
unsubscribe(): Promise<void>;
|
|
15
|
+
getAccountAndSlot(): DataAndSlot<UserStatsAccount>;
|
|
16
|
+
getAccount(): UserStatsAccount;
|
|
17
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ClearingHouseUserStats = void 0;
|
|
4
|
+
const pollingUserStatsAccountSubscriber_1 = require("./accounts/pollingUserStatsAccountSubscriber");
|
|
5
|
+
const webSocketUserStatsAccountSubsriber_1 = require("./accounts/webSocketUserStatsAccountSubsriber");
|
|
6
|
+
class ClearingHouseUserStats {
|
|
7
|
+
constructor(config) {
|
|
8
|
+
var _a;
|
|
9
|
+
this.clearingHouse = config.clearingHouse;
|
|
10
|
+
this.userStatsAccountPublicKey = config.userStatsAccountPublicKey;
|
|
11
|
+
if (((_a = config.accountSubscription) === null || _a === void 0 ? void 0 : _a.type) === 'polling') {
|
|
12
|
+
this.accountSubscriber = new pollingUserStatsAccountSubscriber_1.PollingUserStatsAccountSubscriber(config.clearingHouse.program, config.userStatsAccountPublicKey, config.accountSubscription.accountLoader);
|
|
13
|
+
}
|
|
14
|
+
else {
|
|
15
|
+
this.accountSubscriber = new webSocketUserStatsAccountSubsriber_1.WebSocketUserStatsAccountSubscriber(config.clearingHouse.program, config.userStatsAccountPublicKey);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
async subscribe() {
|
|
19
|
+
this.isSubscribed = await this.accountSubscriber.subscribe();
|
|
20
|
+
return this.isSubscribed;
|
|
21
|
+
}
|
|
22
|
+
async fetchAccounts() {
|
|
23
|
+
await this.accountSubscriber.fetch();
|
|
24
|
+
}
|
|
25
|
+
async unsubscribe() {
|
|
26
|
+
await this.accountSubscriber.unsubscribe();
|
|
27
|
+
this.isSubscribed = false;
|
|
28
|
+
}
|
|
29
|
+
getAccountAndSlot() {
|
|
30
|
+
return this.accountSubscriber.getUserStatsAccountAndSlot();
|
|
31
|
+
}
|
|
32
|
+
getAccount() {
|
|
33
|
+
return this.accountSubscriber.getUserStatsAccountAndSlot().data;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
exports.ClearingHouseUserStats = ClearingHouseUserStats;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { ClearingHouse } from './clearingHouse';
|
|
2
|
+
import { PublicKey } from '@solana/web3.js';
|
|
3
|
+
import { BulkAccountLoader } from './accounts/bulkAccountLoader';
|
|
4
|
+
export declare type ClearingHouseUserStatsConfig = {
|
|
5
|
+
accountSubscription?: ClearingHouseUserStatsAccountSubscriptionConfig;
|
|
6
|
+
clearingHouse: ClearingHouse;
|
|
7
|
+
userStatsAccountPublicKey: PublicKey;
|
|
8
|
+
};
|
|
9
|
+
export declare type ClearingHouseUserStatsAccountSubscriptionConfig = {
|
|
10
|
+
type: 'websocket';
|
|
11
|
+
} | {
|
|
12
|
+
type: 'polling';
|
|
13
|
+
accountLoader: BulkAccountLoader;
|
|
14
|
+
};
|
|
File without changes
|
package/lib/config.js
CHANGED
|
@@ -7,7 +7,7 @@ exports.configs = {
|
|
|
7
7
|
devnet: {
|
|
8
8
|
ENV: 'devnet',
|
|
9
9
|
PYTH_ORACLE_MAPPING_ADDRESS: 'BmA9Z6FjioHJPpjT39QazZyhDRUdZy2ezwx4GiDdE2u2',
|
|
10
|
-
CLEARING_HOUSE_PROGRAM_ID: '
|
|
10
|
+
CLEARING_HOUSE_PROGRAM_ID: 'D9bW92Maa1yDigJqvabRgr5S5VybPNDB5xxSpQD6mkkV',
|
|
11
11
|
USDC_MINT_ADDRESS: '8zGuJQqwhZafTah7Uc7Z4tXRnguqkn5KLFAP8oV6PHe2',
|
|
12
12
|
MARKETS: markets_1.DevnetMarkets,
|
|
13
13
|
BANKS: banks_1.DevnetBanks,
|
package/lib/factory/bigNum.js
CHANGED
|
@@ -137,7 +137,8 @@ class BigNum {
|
|
|
137
137
|
*/
|
|
138
138
|
print() {
|
|
139
139
|
(0, assert_1.assert)(this.precision.gte(numericConstants_1.ZERO), 'Tried to print a BN with precision lower than zero');
|
|
140
|
-
const
|
|
140
|
+
const isNeg = this.isNeg();
|
|
141
|
+
const plainString = this.abs().toString();
|
|
141
142
|
const precisionNum = this.precision.toNumber();
|
|
142
143
|
// make a string with at least the precisionNum number of zeroes
|
|
143
144
|
let printString = [
|
|
@@ -152,14 +153,11 @@ class BigNum {
|
|
|
152
153
|
// remove leading zeroes
|
|
153
154
|
printString = printString.replace(/^0+/, '');
|
|
154
155
|
// add zero if leading delim
|
|
155
|
-
if (
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
if (printString[0] === BigNum.delim)
|
|
161
|
-
printString = `0${printString}`;
|
|
162
|
-
}
|
|
156
|
+
if (printString[0] === BigNum.delim)
|
|
157
|
+
printString = `0${printString}`;
|
|
158
|
+
// Add minus if negative
|
|
159
|
+
if (isNeg)
|
|
160
|
+
printString = `-${printString}`;
|
|
163
161
|
// remove trailing delim
|
|
164
162
|
if (printString[printString.length - 1] === BigNum.delim)
|
|
165
163
|
printString = printString.slice(0, printString.length - 1);
|