@drift-labs/sdk 0.2.0-temp.0 → 0.2.0-temp.1
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/admin.d.ts +7 -5
- package/lib/admin.js +34 -11
- package/lib/clearingHouse.d.ts +23 -9
- package/lib/clearingHouse.js +335 -95
- package/lib/clearingHouseUser.d.ts +2 -2
- package/lib/clearingHouseUser.js +8 -17
- package/lib/config.js +1 -1
- package/lib/constants/banks.js +9 -2
- package/lib/constants/numericConstants.d.ts +1 -0
- package/lib/constants/numericConstants.js +2 -1
- package/lib/idl/clearing_house.json +689 -153
- package/lib/idl/{mock_usdc_faucet.json → token_faucet.json} +46 -23
- package/lib/index.d.ts +3 -2
- package/lib/index.js +7 -2
- package/lib/math/amm.js +7 -35
- package/lib/math/auction.js +4 -1
- package/lib/math/orders.d.ts +2 -2
- package/lib/math/orders.js +19 -2
- package/lib/math/position.js +3 -1
- package/lib/math/trade.d.ts +1 -1
- package/lib/math/trade.js +7 -10
- package/lib/orderParams.d.ts +14 -5
- package/lib/orderParams.js +8 -96
- package/lib/orders.js +1 -1
- package/lib/slot/SlotSubscriber.d.ts +7 -0
- package/lib/slot/SlotSubscriber.js +3 -0
- package/lib/{mockUSDCFaucet.d.ts → tokenFaucet.d.ts} +7 -5
- package/lib/{mockUSDCFaucet.js → tokenFaucet.js} +41 -40
- package/lib/tx/utils.js +1 -1
- package/lib/types.d.ts +132 -14
- package/lib/types.js +52 -1
- package/lib/util/computeUnits.js +1 -1
- package/package.json +3 -3
- package/src/accounts/bulkAccountLoader.js +197 -0
- package/src/accounts/bulkUserSubscription.js +33 -0
- package/src/accounts/pollingClearingHouseAccountSubscriber.js +311 -0
- package/src/accounts/pollingOracleSubscriber.js +93 -0
- package/src/accounts/pollingTokenAccountSubscriber.js +90 -0
- package/src/accounts/pollingUserAccountSubscriber.js +132 -0
- package/src/accounts/types.js +10 -0
- package/src/accounts/utils.js +7 -0
- package/src/accounts/webSocketAccountSubscriber.js +93 -0
- package/src/accounts/webSocketClearingHouseAccountSubscriber.js +233 -0
- package/src/accounts/webSocketUserAccountSubscriber.js +62 -0
- package/src/addresses/marketAddresses.js +26 -0
- package/src/admin.js +517 -0
- package/src/admin.ts +53 -14
- package/src/assert/assert.js +9 -0
- package/src/clearingHouse.ts +510 -131
- package/src/clearingHouseConfig.js +2 -0
- package/src/clearingHouseUser.ts +12 -23
- package/src/clearingHouseUserConfig.js +2 -0
- package/src/config.js +67 -0
- package/src/config.ts +1 -1
- package/src/constants/banks.js +42 -0
- package/src/constants/banks.ts +9 -2
- package/src/constants/markets.js +42 -0
- package/src/constants/numericConstants.js +41 -0
- package/src/constants/numericConstants.ts +1 -0
- package/src/events/eventList.js +77 -0
- package/src/events/eventSubscriber.js +139 -0
- package/src/events/fetchLogs.js +50 -0
- package/src/events/pollingLogProvider.js +64 -0
- package/src/events/sort.js +44 -0
- package/src/events/txEventCache.js +71 -0
- package/src/events/types.js +20 -0
- package/src/events/webSocketLogProvider.js +41 -0
- package/src/examples/makeTradeExample.js +80 -0
- package/src/factory/bigNum.js +390 -0
- package/src/factory/oracleClient.js +20 -0
- package/src/idl/clearing_house.json +689 -153
- package/src/idl/{mock_usdc_faucet.json → token_faucet.json} +46 -23
- package/src/index.js +69 -0
- package/src/index.ts +3 -2
- package/src/math/amm.js +369 -0
- package/src/math/amm.ts +19 -49
- package/src/math/auction.js +42 -0
- package/src/math/auction.ts +5 -1
- package/src/math/conversion.js +11 -0
- package/src/math/funding.js +248 -0
- package/src/math/oracles.js +26 -0
- package/src/math/orders.ts +17 -3
- package/src/math/position.ts +5 -1
- package/src/math/repeg.js +128 -0
- package/src/math/state.js +15 -0
- package/src/math/trade.js +253 -0
- package/src/math/trade.ts +23 -25
- package/src/math/utils.js +0 -1
- package/src/mockUSDCFaucet.js +280 -0
- package/src/oracles/oracleClientCache.js +19 -0
- package/src/oracles/pythClient.js +46 -0
- package/src/oracles/quoteAssetOracleClient.js +32 -0
- package/src/oracles/switchboardClient.js +69 -0
- package/src/oracles/types.js +2 -0
- package/src/orderParams.js +20 -0
- package/src/orderParams.ts +20 -141
- package/src/orders.ts +2 -1
- package/src/slot/SlotSubscriber.js +39 -0
- package/src/slot/SlotSubscriber.ts +11 -1
- package/src/token/index.js +38 -0
- package/src/tokenFaucet.js +189 -0
- package/src/{mockUSDCFaucet.ts → tokenFaucet.ts} +48 -59
- package/src/tx/types.js +2 -0
- package/src/tx/utils.js +17 -0
- package/src/tx/utils.ts +1 -1
- package/src/types.js +125 -0
- package/src/types.ts +128 -15
- package/src/userName.js +20 -0
- package/src/util/computeUnits.js +21 -11
- package/src/util/computeUnits.ts +1 -1
- package/src/util/getTokenAddress.js +9 -0
- package/src/util/promiseTimeout.js +14 -0
- package/src/util/tps.js +27 -0
- package/src/wallet.js +35 -0
- package/src/util/computeUnits.js.map +0 -1
package/lib/clearingHouse.js
CHANGED
|
@@ -29,6 +29,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
29
29
|
exports.ClearingHouse = void 0;
|
|
30
30
|
const anchor_1 = require("@project-serum/anchor");
|
|
31
31
|
const spl_token_1 = require("@solana/spl-token");
|
|
32
|
+
const types_1 = require("./types");
|
|
32
33
|
const anchor = __importStar(require("@project-serum/anchor"));
|
|
33
34
|
const clearing_house_json_1 = __importDefault(require("./idl/clearing_house.json"));
|
|
34
35
|
const web3_js_1 = require("@solana/web3.js");
|
|
@@ -42,7 +43,6 @@ const pollingClearingHouseAccountSubscriber_1 = require("./accounts/pollingClear
|
|
|
42
43
|
const webSocketClearingHouseAccountSubscriber_1 = require("./accounts/webSocketClearingHouseAccountSubscriber");
|
|
43
44
|
const retryTxSender_1 = require("./tx/retryTxSender");
|
|
44
45
|
const clearingHouseUser_1 = require("./clearingHouseUser");
|
|
45
|
-
const orderParams_1 = require("./orderParams");
|
|
46
46
|
const config_1 = require("./config");
|
|
47
47
|
/**
|
|
48
48
|
* # ClearingHouse
|
|
@@ -371,13 +371,19 @@ class ClearingHouse {
|
|
|
371
371
|
});
|
|
372
372
|
}
|
|
373
373
|
else {
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
374
|
+
const bankAccount = this.getBankAccount(bankIndex);
|
|
375
|
+
if (!bankAccount.oracle.equals(web3_js_1.PublicKey.default)) {
|
|
376
|
+
remainingAccounts.push({
|
|
377
|
+
pubkey: bankAccount.oracle,
|
|
377
378
|
isSigner: false,
|
|
378
|
-
isWritable:
|
|
379
|
-
}
|
|
380
|
-
|
|
379
|
+
isWritable: false,
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
remainingAccounts.push({
|
|
383
|
+
pubkey: bankAccount.pubkey,
|
|
384
|
+
isSigner: false,
|
|
385
|
+
isWritable: true,
|
|
386
|
+
});
|
|
381
387
|
}
|
|
382
388
|
const bank = this.getBankAccount(bankIndex);
|
|
383
389
|
return await this.program.instruction.deposit(bankIndex, amount, reduceOnly, {
|
|
@@ -413,10 +419,10 @@ class ClearingHouse {
|
|
|
413
419
|
const { txSig } = await this.txSender.send(tx, []);
|
|
414
420
|
return [txSig, userAccountPublicKey];
|
|
415
421
|
}
|
|
416
|
-
async initializeUserAccountForDevnet(userId = 0, name = userName_1.DEFAULT_USER_NAME,
|
|
417
|
-
const [associateTokenPublicKey, createAssociatedAccountIx, mintToIx] = await
|
|
422
|
+
async initializeUserAccountForDevnet(userId = 0, name = userName_1.DEFAULT_USER_NAME, bankIndex, tokenFaucet, amount) {
|
|
423
|
+
const [associateTokenPublicKey, createAssociatedAccountIx, mintToIx] = await tokenFaucet.createAssociatedTokenAccountAndMintToInstructions(this.wallet.publicKey, amount);
|
|
418
424
|
const [userAccountPublicKey, initializeUserAccountIx] = await this.getInitializeUserInstructions(userId, name);
|
|
419
|
-
const depositCollateralIx = await this.getDepositInstruction(amount,
|
|
425
|
+
const depositCollateralIx = await this.getDepositInstruction(amount, bankIndex, associateTokenPublicKey, userId, false, false);
|
|
420
426
|
const tx = new web3_js_1.Transaction()
|
|
421
427
|
.add(createAssociatedAccountIx)
|
|
422
428
|
.add(mintToIx)
|
|
@@ -482,14 +488,24 @@ class ClearingHouse {
|
|
|
482
488
|
});
|
|
483
489
|
}
|
|
484
490
|
async openPosition(direction, amount, marketIndex, limitPrice) {
|
|
485
|
-
return await this.placeAndTake(
|
|
491
|
+
return await this.placeAndTake({
|
|
492
|
+
orderType: types_1.OrderType.MARKET,
|
|
493
|
+
marketIndex,
|
|
494
|
+
direction,
|
|
495
|
+
baseAssetAmount: amount,
|
|
496
|
+
price: limitPrice,
|
|
497
|
+
});
|
|
486
498
|
}
|
|
487
499
|
async placeOrder(orderParams) {
|
|
488
500
|
const { txSig, slot } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getPlaceOrderIx(orderParams)), [], this.opts);
|
|
489
501
|
this.marketLastSlotCache.set(orderParams.marketIndex.toNumber(), slot);
|
|
490
502
|
return txSig;
|
|
491
503
|
}
|
|
504
|
+
getOrderParams(optionalOrderParams) {
|
|
505
|
+
return Object.assign({}, types_1.DefaultOrderParams, optionalOrderParams);
|
|
506
|
+
}
|
|
492
507
|
async getPlaceOrderIx(orderParams) {
|
|
508
|
+
orderParams = this.getOrderParams(orderParams);
|
|
493
509
|
const userAccountPublicKey = await this.getUserAccountPublicKey();
|
|
494
510
|
const remainingAccounts = this.getRemainingAccounts({
|
|
495
511
|
writableMarketIndex: orderParams.marketIndex,
|
|
@@ -580,44 +596,57 @@ class ClearingHouse {
|
|
|
580
596
|
const fillerPublicKey = await this.getUserAccountPublicKey();
|
|
581
597
|
const marketIndex = order.marketIndex;
|
|
582
598
|
const marketAccount = this.getMarketAccount(marketIndex);
|
|
583
|
-
const
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
599
|
+
const oracleAccountMap = new Map();
|
|
600
|
+
const bankAccountMap = new Map();
|
|
601
|
+
const marketAccountMap = new Map();
|
|
602
|
+
marketAccountMap.set(marketIndex.toNumber(), {
|
|
603
|
+
pubkey: marketAccount.pubkey,
|
|
604
|
+
isWritable: true,
|
|
605
|
+
isSigner: false,
|
|
606
|
+
});
|
|
607
|
+
oracleAccountMap.set(marketAccount.amm.oracle.toString(), {
|
|
608
|
+
pubkey: marketAccount.amm.oracle,
|
|
609
|
+
isWritable: false,
|
|
610
|
+
isSigner: false,
|
|
611
|
+
});
|
|
612
|
+
for (const bankBalance of userAccount.bankBalances) {
|
|
613
|
+
if (!bankBalance.balance.eq(numericConstants_1.ZERO)) {
|
|
614
|
+
const bankAccount = this.getBankAccount(bankBalance.bankIndex);
|
|
615
|
+
bankAccountMap.set(bankBalance.bankIndex.toNumber(), {
|
|
616
|
+
pubkey: bankAccount.pubkey,
|
|
617
|
+
isSigner: false,
|
|
618
|
+
isWritable: true,
|
|
619
|
+
});
|
|
620
|
+
if (!bankAccount.oracle.equals(web3_js_1.PublicKey.default)) {
|
|
621
|
+
oracleAccountMap.set(bankAccount.oracle.toString(), {
|
|
622
|
+
pubkey: bankAccount.oracle,
|
|
623
|
+
isSigner: false,
|
|
624
|
+
isWritable: false,
|
|
625
|
+
});
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
}
|
|
604
629
|
for (const position of userAccount.positions) {
|
|
605
630
|
if (!(0, position_1.positionIsAvailable)(position) &&
|
|
606
631
|
!position.marketIndex.eq(order.marketIndex)) {
|
|
607
632
|
const market = this.getMarketAccount(position.marketIndex);
|
|
608
|
-
|
|
633
|
+
marketAccountMap.set(position.marketIndex.toNumber(), {
|
|
609
634
|
pubkey: market.pubkey,
|
|
610
635
|
isWritable: true,
|
|
611
636
|
isSigner: false,
|
|
612
637
|
});
|
|
613
|
-
|
|
638
|
+
oracleAccountMap.set(market.amm.oracle.toString(), {
|
|
614
639
|
pubkey: market.amm.oracle,
|
|
615
640
|
isWritable: false,
|
|
616
641
|
isSigner: false,
|
|
617
642
|
});
|
|
618
643
|
}
|
|
619
644
|
}
|
|
620
|
-
const remainingAccounts =
|
|
645
|
+
const remainingAccounts = [
|
|
646
|
+
...oracleAccountMap.values(),
|
|
647
|
+
...bankAccountMap.values(),
|
|
648
|
+
...marketAccountMap.values(),
|
|
649
|
+
];
|
|
621
650
|
if (makerInfo) {
|
|
622
651
|
remainingAccounts.push({
|
|
623
652
|
pubkey: makerInfo.maker,
|
|
@@ -645,44 +674,57 @@ class ClearingHouse {
|
|
|
645
674
|
const fillerPublicKey = await this.getUserAccountPublicKey();
|
|
646
675
|
const marketIndex = order.marketIndex;
|
|
647
676
|
const marketAccount = this.getMarketAccount(marketIndex);
|
|
648
|
-
const
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
677
|
+
const oracleAccountMap = new Map();
|
|
678
|
+
const bankAccountMap = new Map();
|
|
679
|
+
const marketAccountMap = new Map();
|
|
680
|
+
marketAccountMap.set(marketIndex.toNumber(), {
|
|
681
|
+
pubkey: marketAccount.pubkey,
|
|
682
|
+
isWritable: true,
|
|
683
|
+
isSigner: false,
|
|
684
|
+
});
|
|
685
|
+
oracleAccountMap.set(marketAccount.amm.oracle.toString(), {
|
|
686
|
+
pubkey: marketAccount.amm.oracle,
|
|
687
|
+
isWritable: false,
|
|
688
|
+
isSigner: false,
|
|
689
|
+
});
|
|
690
|
+
for (const bankBalance of userAccount.bankBalances) {
|
|
691
|
+
if (!bankBalance.balance.eq(numericConstants_1.ZERO)) {
|
|
692
|
+
const bankAccount = this.getBankAccount(bankBalance.bankIndex);
|
|
693
|
+
bankAccountMap.set(bankBalance.bankIndex.toNumber(), {
|
|
694
|
+
pubkey: bankAccount.pubkey,
|
|
695
|
+
isSigner: false,
|
|
696
|
+
isWritable: true,
|
|
697
|
+
});
|
|
698
|
+
if (!bankAccount.oracle.equals(web3_js_1.PublicKey.default)) {
|
|
699
|
+
oracleAccountMap.set(bankAccount.oracle.toString(), {
|
|
700
|
+
pubkey: bankAccount.oracle,
|
|
701
|
+
isSigner: false,
|
|
702
|
+
isWritable: false,
|
|
703
|
+
});
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
}
|
|
669
707
|
for (const position of userAccount.positions) {
|
|
670
708
|
if (!(0, position_1.positionIsAvailable)(position) &&
|
|
671
709
|
!position.marketIndex.eq(order.marketIndex)) {
|
|
672
710
|
const market = this.getMarketAccount(position.marketIndex);
|
|
673
|
-
|
|
711
|
+
marketAccountMap.set(position.marketIndex.toNumber(), {
|
|
674
712
|
pubkey: market.pubkey,
|
|
675
|
-
isWritable:
|
|
713
|
+
isWritable: true,
|
|
676
714
|
isSigner: false,
|
|
677
715
|
});
|
|
678
|
-
|
|
716
|
+
oracleAccountMap.set(market.amm.oracle.toString(), {
|
|
679
717
|
pubkey: market.amm.oracle,
|
|
680
718
|
isWritable: false,
|
|
681
719
|
isSigner: false,
|
|
682
720
|
});
|
|
683
721
|
}
|
|
684
722
|
}
|
|
685
|
-
const remainingAccounts =
|
|
723
|
+
const remainingAccounts = [
|
|
724
|
+
...oracleAccountMap.values(),
|
|
725
|
+
...bankAccountMap.values(),
|
|
726
|
+
...marketAccountMap.values(),
|
|
727
|
+
];
|
|
686
728
|
const orderId = order.orderId;
|
|
687
729
|
return await this.program.instruction.triggerOrder(orderId, {
|
|
688
730
|
accounts: {
|
|
@@ -700,6 +742,7 @@ class ClearingHouse {
|
|
|
700
742
|
return txSig;
|
|
701
743
|
}
|
|
702
744
|
async getPlaceAndTakeIx(orderParams, makerInfo) {
|
|
745
|
+
orderParams = this.getOrderParams(orderParams);
|
|
703
746
|
const userAccountPublicKey = await this.getUserAccountPublicKey();
|
|
704
747
|
const remainingAccounts = this.getRemainingAccounts({
|
|
705
748
|
writableMarketIndex: orderParams.marketIndex,
|
|
@@ -723,6 +766,34 @@ class ClearingHouse {
|
|
|
723
766
|
remainingAccounts,
|
|
724
767
|
});
|
|
725
768
|
}
|
|
769
|
+
async placeAndMake(orderParams, takerInfo) {
|
|
770
|
+
const { txSig, slot } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getPlaceAndMakeIx(orderParams, takerInfo)), [], this.opts);
|
|
771
|
+
this.marketLastSlotCache.set(orderParams.marketIndex.toNumber(), slot);
|
|
772
|
+
return txSig;
|
|
773
|
+
}
|
|
774
|
+
async getPlaceAndMakeIx(orderParams, takerInfo) {
|
|
775
|
+
orderParams = this.getOrderParams(orderParams);
|
|
776
|
+
const userAccountPublicKey = await this.getUserAccountPublicKey();
|
|
777
|
+
const remainingAccounts = this.getRemainingAccounts({
|
|
778
|
+
writableMarketIndex: orderParams.marketIndex,
|
|
779
|
+
writableBankIndex: numericConstants_1.QUOTE_ASSET_BANK_INDEX,
|
|
780
|
+
});
|
|
781
|
+
const takerOrderId = takerInfo.order.orderId;
|
|
782
|
+
remainingAccounts.push({
|
|
783
|
+
pubkey: takerInfo.taker,
|
|
784
|
+
isSigner: false,
|
|
785
|
+
isWritable: true,
|
|
786
|
+
});
|
|
787
|
+
return await this.program.instruction.placeAndMake(orderParams, takerOrderId, {
|
|
788
|
+
accounts: {
|
|
789
|
+
state: await this.getStatePublicKey(),
|
|
790
|
+
user: userAccountPublicKey,
|
|
791
|
+
taker: takerInfo.taker,
|
|
792
|
+
authority: this.wallet.publicKey,
|
|
793
|
+
},
|
|
794
|
+
remainingAccounts,
|
|
795
|
+
});
|
|
796
|
+
}
|
|
726
797
|
/**
|
|
727
798
|
* Close an entire position. If you want to reduce a position, use the {@link openPosition} method in the opposite direction of the current position.
|
|
728
799
|
* @param marketIndex
|
|
@@ -733,7 +804,13 @@ class ClearingHouse {
|
|
|
733
804
|
if (!userPosition) {
|
|
734
805
|
throw Error(`No position in market ${marketIndex.toString()}`);
|
|
735
806
|
}
|
|
736
|
-
return await this.placeAndTake(
|
|
807
|
+
return await this.placeAndTake({
|
|
808
|
+
orderType: types_1.OrderType.MARKET,
|
|
809
|
+
marketIndex,
|
|
810
|
+
direction: (0, position_1.findDirectionToClose)(userPosition),
|
|
811
|
+
baseAssetAmount: userPosition.baseAssetAmount,
|
|
812
|
+
reduceOnly: true,
|
|
813
|
+
});
|
|
737
814
|
}
|
|
738
815
|
async settlePNLs(users, marketIndex) {
|
|
739
816
|
const ixs = [];
|
|
@@ -814,54 +891,217 @@ class ClearingHouse {
|
|
|
814
891
|
remainingAccounts: remainingAccounts,
|
|
815
892
|
});
|
|
816
893
|
}
|
|
817
|
-
async
|
|
818
|
-
const { txSig } = await this.txSender.send((0, utils_1.wrapInTx)(await this.
|
|
894
|
+
async liquidatePerp(userAccountPublicKey, userAccount, marketIndex, maxBaseAssetAmount) {
|
|
895
|
+
const { txSig } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getLiquidatePerpIx(userAccountPublicKey, userAccount, marketIndex, maxBaseAssetAmount)), [], this.opts);
|
|
819
896
|
return txSig;
|
|
820
897
|
}
|
|
821
|
-
async
|
|
822
|
-
const
|
|
823
|
-
const
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
898
|
+
async getLiquidatePerpIx(userAccountPublicKey, userAccount, marketIndex, maxBaseAssetAmount) {
|
|
899
|
+
const liquidatorPublicKey = await this.getUserAccountPublicKey();
|
|
900
|
+
const remainingAccounts = this.getRemainingAccountsForLiquidation({
|
|
901
|
+
writableMarketIndex: marketIndex,
|
|
902
|
+
userAccount,
|
|
903
|
+
});
|
|
904
|
+
return await this.program.instruction.liquidatePerp(marketIndex, maxBaseAssetAmount, {
|
|
905
|
+
accounts: {
|
|
906
|
+
state: await this.getStatePublicKey(),
|
|
907
|
+
authority: this.wallet.publicKey,
|
|
908
|
+
user: userAccountPublicKey,
|
|
909
|
+
liquidator: liquidatorPublicKey,
|
|
829
910
|
},
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
911
|
+
remainingAccounts: remainingAccounts,
|
|
912
|
+
});
|
|
913
|
+
}
|
|
914
|
+
async liquidateBorrow(userAccountPublicKey, userAccount, assetBankIndex, liabilityBankIndex, maxLiabilityTransfer) {
|
|
915
|
+
const { txSig } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getLiquidateBorrowIx(userAccountPublicKey, userAccount, assetBankIndex, liabilityBankIndex, maxLiabilityTransfer)), [], this.opts);
|
|
916
|
+
return txSig;
|
|
917
|
+
}
|
|
918
|
+
async getLiquidateBorrowIx(userAccountPublicKey, userAccount, assetBankIndex, liabilityBankIndex, maxLiabilityTransfer) {
|
|
919
|
+
const liquidatorPublicKey = await this.getUserAccountPublicKey();
|
|
920
|
+
const remainingAccounts = this.getRemainingAccountsForLiquidation({
|
|
921
|
+
userAccount,
|
|
922
|
+
writableBankIndexes: [liabilityBankIndex, assetBankIndex],
|
|
923
|
+
});
|
|
924
|
+
return await this.program.instruction.liquidateBorrow(assetBankIndex, liabilityBankIndex, maxLiabilityTransfer, {
|
|
925
|
+
accounts: {
|
|
926
|
+
state: await this.getStatePublicKey(),
|
|
927
|
+
authority: this.wallet.publicKey,
|
|
928
|
+
user: userAccountPublicKey,
|
|
929
|
+
liquidator: liquidatorPublicKey,
|
|
930
|
+
},
|
|
931
|
+
remainingAccounts: remainingAccounts,
|
|
932
|
+
});
|
|
933
|
+
}
|
|
934
|
+
async liquidateBorrowForPerpPnl(userAccountPublicKey, userAccount, perpMarketIndex, liabilityBankIndex, maxLiabilityTransfer) {
|
|
935
|
+
const { txSig } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getLiquidateBorrowForPerpPnlIx(userAccountPublicKey, userAccount, perpMarketIndex, liabilityBankIndex, maxLiabilityTransfer)), [], this.opts);
|
|
936
|
+
return txSig;
|
|
937
|
+
}
|
|
938
|
+
async getLiquidateBorrowForPerpPnlIx(userAccountPublicKey, userAccount, perpMarketIndex, liabilityBankIndex, maxLiabilityTransfer) {
|
|
939
|
+
const liquidatorPublicKey = await this.getUserAccountPublicKey();
|
|
940
|
+
const remainingAccounts = this.getRemainingAccountsForLiquidation({
|
|
941
|
+
userAccount,
|
|
942
|
+
writableMarketIndex: perpMarketIndex,
|
|
943
|
+
writableBankIndexes: [liabilityBankIndex],
|
|
944
|
+
});
|
|
945
|
+
return await this.program.instruction.liquidateBorrowForPerpPnl(perpMarketIndex, liabilityBankIndex, maxLiabilityTransfer, {
|
|
946
|
+
accounts: {
|
|
947
|
+
state: await this.getStatePublicKey(),
|
|
948
|
+
authority: this.wallet.publicKey,
|
|
949
|
+
user: userAccountPublicKey,
|
|
950
|
+
liquidator: liquidatorPublicKey,
|
|
951
|
+
},
|
|
952
|
+
remainingAccounts: remainingAccounts,
|
|
953
|
+
});
|
|
954
|
+
}
|
|
955
|
+
async liquidatePerpPnlForDeposit(userAccountPublicKey, userAccount, perpMarketIndex, assetBankIndex, maxPnlTransfer) {
|
|
956
|
+
const { txSig } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getLiquidatePerpPnlForDepositIx(userAccountPublicKey, userAccount, perpMarketIndex, assetBankIndex, maxPnlTransfer)), [], this.opts);
|
|
957
|
+
return txSig;
|
|
958
|
+
}
|
|
959
|
+
async getLiquidatePerpPnlForDepositIx(userAccountPublicKey, userAccount, perpMarketIndex, assetBankIndex, maxPnlTransfer) {
|
|
960
|
+
const liquidatorPublicKey = await this.getUserAccountPublicKey();
|
|
961
|
+
const remainingAccounts = this.getRemainingAccountsForLiquidation({
|
|
962
|
+
userAccount,
|
|
963
|
+
writableMarketIndex: perpMarketIndex,
|
|
964
|
+
writableBankIndexes: [assetBankIndex],
|
|
965
|
+
});
|
|
966
|
+
return await this.program.instruction.liquidatePerpPnlForDeposit(perpMarketIndex, assetBankIndex, maxPnlTransfer, {
|
|
967
|
+
accounts: {
|
|
968
|
+
state: await this.getStatePublicKey(),
|
|
969
|
+
authority: this.wallet.publicKey,
|
|
970
|
+
user: userAccountPublicKey,
|
|
971
|
+
liquidator: liquidatorPublicKey,
|
|
972
|
+
},
|
|
973
|
+
remainingAccounts: remainingAccounts,
|
|
974
|
+
});
|
|
975
|
+
}
|
|
976
|
+
getRemainingAccountsForLiquidation(params) {
|
|
977
|
+
const liquidateeUserAccount = params.userAccount;
|
|
978
|
+
const oracleAccountMap = new Map();
|
|
979
|
+
const bankAccountMap = new Map();
|
|
980
|
+
const marketAccountMap = new Map();
|
|
981
|
+
for (const bankBalance of liquidateeUserAccount.bankBalances) {
|
|
982
|
+
if (!bankBalance.balance.eq(numericConstants_1.ZERO)) {
|
|
983
|
+
const bankAccount = this.getBankAccount(bankBalance.bankIndex);
|
|
984
|
+
bankAccountMap.set(bankBalance.bankIndex.toNumber(), {
|
|
985
|
+
pubkey: bankAccount.pubkey,
|
|
986
|
+
isSigner: false,
|
|
987
|
+
isWritable: false,
|
|
988
|
+
});
|
|
989
|
+
if (!bankAccount.oracle.equals(web3_js_1.PublicKey.default)) {
|
|
990
|
+
oracleAccountMap.set(bankAccount.oracle.toString(), {
|
|
991
|
+
pubkey: bankAccount.oracle,
|
|
992
|
+
isSigner: false,
|
|
993
|
+
isWritable: false,
|
|
994
|
+
});
|
|
995
|
+
}
|
|
996
|
+
}
|
|
997
|
+
}
|
|
833
998
|
for (const position of liquidateeUserAccount.positions) {
|
|
834
999
|
if (!(0, position_1.positionIsAvailable)(position)) {
|
|
835
1000
|
const market = this.getMarketAccount(position.marketIndex);
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
isWritable: true,
|
|
1001
|
+
marketAccountMap.set(position.marketIndex.toNumber(), {
|
|
1002
|
+
pubkey: market.pubkey,
|
|
1003
|
+
isWritable: false,
|
|
840
1004
|
isSigner: false,
|
|
841
1005
|
});
|
|
842
|
-
|
|
1006
|
+
oracleAccountMap.set(market.amm.oracle.toString(), {
|
|
843
1007
|
pubkey: market.amm.oracle,
|
|
844
1008
|
isWritable: false,
|
|
845
1009
|
isSigner: false,
|
|
846
1010
|
});
|
|
847
1011
|
}
|
|
848
1012
|
}
|
|
849
|
-
const
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
1013
|
+
const userAccountAndSlot = this.getUserAccountAndSlot();
|
|
1014
|
+
if (!userAccountAndSlot) {
|
|
1015
|
+
throw Error('No user account found. Most likely user account does not exist or failed to fetch account');
|
|
1016
|
+
}
|
|
1017
|
+
const { data: userAccount, slot: lastUserPositionsSlot } = userAccountAndSlot;
|
|
1018
|
+
for (const [marketIndexNum, slot] of this.marketLastSlotCache.entries()) {
|
|
1019
|
+
// if cache has more recent slot than user positions account slot, add market to remaining accounts
|
|
1020
|
+
// otherwise remove from slot
|
|
1021
|
+
if (slot > lastUserPositionsSlot) {
|
|
1022
|
+
const marketAccount = this.getMarketAccount(marketIndexNum);
|
|
1023
|
+
marketAccountMap.set(marketIndexNum, {
|
|
1024
|
+
pubkey: marketAccount.pubkey,
|
|
1025
|
+
isSigner: false,
|
|
1026
|
+
isWritable: false,
|
|
1027
|
+
});
|
|
1028
|
+
oracleAccountMap.set(marketAccount.amm.oracle.toString(), {
|
|
1029
|
+
pubkey: marketAccount.amm.oracle,
|
|
1030
|
+
isSigner: false,
|
|
1031
|
+
isWritable: false,
|
|
1032
|
+
});
|
|
1033
|
+
}
|
|
1034
|
+
else {
|
|
1035
|
+
this.marketLastSlotCache.delete(marketIndexNum);
|
|
1036
|
+
}
|
|
1037
|
+
}
|
|
1038
|
+
for (const bankBalance of userAccount.bankBalances) {
|
|
1039
|
+
if (!bankBalance.balance.eq(numericConstants_1.ZERO)) {
|
|
1040
|
+
const bankAccount = this.getBankAccount(bankBalance.bankIndex);
|
|
1041
|
+
bankAccountMap.set(bankBalance.bankIndex.toNumber(), {
|
|
1042
|
+
pubkey: bankAccount.pubkey,
|
|
1043
|
+
isSigner: false,
|
|
1044
|
+
isWritable: false,
|
|
1045
|
+
});
|
|
1046
|
+
if (!bankAccount.oracle.equals(web3_js_1.PublicKey.default)) {
|
|
1047
|
+
oracleAccountMap.set(bankAccount.oracle.toString(), {
|
|
1048
|
+
pubkey: bankAccount.oracle,
|
|
1049
|
+
isSigner: false,
|
|
1050
|
+
isWritable: false,
|
|
1051
|
+
});
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
1055
|
+
for (const position of userAccount.positions) {
|
|
1056
|
+
if (!(0, position_1.positionIsAvailable)(position)) {
|
|
1057
|
+
const market = this.getMarketAccount(position.marketIndex);
|
|
1058
|
+
marketAccountMap.set(position.marketIndex.toNumber(), {
|
|
1059
|
+
pubkey: market.pubkey,
|
|
1060
|
+
isWritable: false,
|
|
1061
|
+
isSigner: false,
|
|
1062
|
+
});
|
|
1063
|
+
oracleAccountMap.set(market.amm.oracle.toString(), {
|
|
1064
|
+
pubkey: market.amm.oracle,
|
|
1065
|
+
isWritable: false,
|
|
1066
|
+
isSigner: false,
|
|
1067
|
+
});
|
|
1068
|
+
}
|
|
1069
|
+
}
|
|
1070
|
+
if (params.writableMarketIndex) {
|
|
1071
|
+
const market = this.getMarketAccount(params.writableMarketIndex);
|
|
1072
|
+
marketAccountMap.set(market.marketIndex.toNumber(), {
|
|
1073
|
+
pubkey: market.pubkey,
|
|
1074
|
+
isSigner: false,
|
|
1075
|
+
isWritable: true,
|
|
1076
|
+
});
|
|
1077
|
+
oracleAccountMap.set(market.amm.oracle.toString(), {
|
|
1078
|
+
pubkey: market.amm.oracle,
|
|
1079
|
+
isSigner: false,
|
|
1080
|
+
isWritable: false,
|
|
1081
|
+
});
|
|
1082
|
+
}
|
|
1083
|
+
if (params.writableBankIndexes) {
|
|
1084
|
+
for (const writableBankIndex of params.writableBankIndexes) {
|
|
1085
|
+
const bank = this.getBankAccount(writableBankIndex);
|
|
1086
|
+
bankAccountMap.set(bank.bankIndex.toNumber(), {
|
|
1087
|
+
pubkey: bank.pubkey,
|
|
1088
|
+
isSigner: false,
|
|
1089
|
+
isWritable: true,
|
|
1090
|
+
});
|
|
1091
|
+
if (!bank.oracle.equals(web3_js_1.PublicKey.default)) {
|
|
1092
|
+
oracleAccountMap.set(bank.oracle.toString(), {
|
|
1093
|
+
pubkey: bank.oracle,
|
|
1094
|
+
isSigner: false,
|
|
1095
|
+
isWritable: false,
|
|
1096
|
+
});
|
|
1097
|
+
}
|
|
1098
|
+
}
|
|
1099
|
+
}
|
|
1100
|
+
return [
|
|
1101
|
+
...oracleAccountMap.values(),
|
|
1102
|
+
...bankAccountMap.values(),
|
|
1103
|
+
...marketAccountMap.values(),
|
|
1104
|
+
];
|
|
865
1105
|
}
|
|
866
1106
|
async updateFundingRate(oracle, marketIndex) {
|
|
867
1107
|
const { txSig } = await this.txSender.send((0, utils_1.wrapInTx)(await this.getUpdateFundingRateIx(oracle, marketIndex)), [], this.opts);
|
|
@@ -63,7 +63,7 @@ export declare class ClearingHouseUser {
|
|
|
63
63
|
/**
|
|
64
64
|
* @returns The partial margin requirement in USDC. : QUOTE_PRECISION
|
|
65
65
|
*/
|
|
66
|
-
|
|
66
|
+
getMaintenanceMarginRequirement(): BN;
|
|
67
67
|
/**
|
|
68
68
|
* calculates unrealized position price pnl
|
|
69
69
|
* @returns : Precision QUOTE_PRECISION
|
|
@@ -132,7 +132,7 @@ export declare class ClearingHouseUser {
|
|
|
132
132
|
* @param partial
|
|
133
133
|
* @returns Precision : MARK_PRICE_PRECISION
|
|
134
134
|
*/
|
|
135
|
-
liquidationPrice(marketPosition: Pick<UserPosition, 'marketIndex'>, positionBaseSizeChange?: BN
|
|
135
|
+
liquidationPrice(marketPosition: Pick<UserPosition, 'marketIndex'>, positionBaseSizeChange?: BN): BN;
|
|
136
136
|
/**
|
|
137
137
|
* Calculates the estimated liquidation price for a position after closing a quote amount of the position.
|
|
138
138
|
* @param positionMarketIndex
|
package/lib/clearingHouseUser.js
CHANGED
|
@@ -126,12 +126,12 @@ class ClearingHouseUser {
|
|
|
126
126
|
/**
|
|
127
127
|
* @returns The partial margin requirement in USDC. : QUOTE_PRECISION
|
|
128
128
|
*/
|
|
129
|
-
|
|
129
|
+
getMaintenanceMarginRequirement() {
|
|
130
130
|
return this.getUserAccount()
|
|
131
131
|
.positions.reduce((marginRequirement, marketPosition) => {
|
|
132
132
|
const market = this.clearingHouse.getMarketAccount(marketPosition.marketIndex);
|
|
133
133
|
return marginRequirement.add((0, _1.calculateBaseAssetValue)(market, marketPosition, this.getOracleDataForMarket(market.marketIndex))
|
|
134
|
-
.mul(new _1.BN(market.
|
|
134
|
+
.mul(new _1.BN(market.marginRatioMaintenance))
|
|
135
135
|
.div(numericConstants_1.MARGIN_PRECISION));
|
|
136
136
|
}, numericConstants_1.ZERO)
|
|
137
137
|
.add(this.getTotalLiability());
|
|
@@ -319,9 +319,6 @@ class ClearingHouseUser {
|
|
|
319
319
|
case 'Maintenance':
|
|
320
320
|
marginRatioCategory = market.marginRatioMaintenance;
|
|
321
321
|
break;
|
|
322
|
-
case 'Partial':
|
|
323
|
-
marginRatioCategory = market.marginRatioPartial;
|
|
324
|
-
break;
|
|
325
322
|
default:
|
|
326
323
|
marginRatioCategory = market.marginRatioInitial;
|
|
327
324
|
break;
|
|
@@ -342,7 +339,7 @@ class ClearingHouseUser {
|
|
|
342
339
|
}
|
|
343
340
|
canBeLiquidated() {
|
|
344
341
|
const totalCollateral = this.getTotalCollateral();
|
|
345
|
-
const partialMaintenanceRequirement = this.
|
|
342
|
+
const partialMaintenanceRequirement = this.getMaintenanceMarginRequirement();
|
|
346
343
|
const marginRatio = this.getMarginRatio();
|
|
347
344
|
const canLiquidate = totalCollateral.lt(partialMaintenanceRequirement);
|
|
348
345
|
return [canLiquidate, marginRatio];
|
|
@@ -372,7 +369,7 @@ class ClearingHouseUser {
|
|
|
372
369
|
* @param partial
|
|
373
370
|
* @returns Precision : MARK_PRICE_PRECISION
|
|
374
371
|
*/
|
|
375
|
-
liquidationPrice(marketPosition, positionBaseSizeChange = numericConstants_1.ZERO
|
|
372
|
+
liquidationPrice(marketPosition, positionBaseSizeChange = numericConstants_1.ZERO) {
|
|
376
373
|
// solves formula for example canBeLiquidated below
|
|
377
374
|
/* example: assume BTC price is $40k (examine 10% up/down)
|
|
378
375
|
|
|
@@ -413,9 +410,7 @@ class ClearingHouseUser {
|
|
|
413
410
|
const market = this.clearingHouse.getMarketAccount(position.marketIndex);
|
|
414
411
|
const positionValue = (0, _1.calculateBaseAssetValue)(market, position, this.getOracleDataForMarket(market.marketIndex));
|
|
415
412
|
const marketMarginRequirement = positionValue
|
|
416
|
-
.mul(
|
|
417
|
-
? new _1.BN(market.marginRatioPartial)
|
|
418
|
-
: new _1.BN(market.marginRatioMaintenance))
|
|
413
|
+
.mul(new _1.BN(market.marginRatioMaintenance))
|
|
419
414
|
.div(numericConstants_1.MARGIN_PRECISION);
|
|
420
415
|
totalMarginRequirement = totalMarginRequirement.add(marketMarginRequirement);
|
|
421
416
|
}
|
|
@@ -428,14 +423,10 @@ class ClearingHouseUser {
|
|
|
428
423
|
return new _1.BN(-1);
|
|
429
424
|
}
|
|
430
425
|
const marginRequirementAfterTrade = marginRequirementExcludingTargetMarket.add(proposedMarketPositionValue
|
|
431
|
-
.mul(
|
|
432
|
-
? new _1.BN(market.marginRatioPartial)
|
|
433
|
-
: new _1.BN(market.marginRatioMaintenance))
|
|
426
|
+
.mul(new _1.BN(market.marginRatioMaintenance))
|
|
434
427
|
.div(numericConstants_1.MARGIN_PRECISION));
|
|
435
428
|
const freeCollateralAfterTrade = totalCollateral.sub(marginRequirementAfterTrade);
|
|
436
|
-
const marketMaxLeverage =
|
|
437
|
-
? this.getMaxLeverage(proposedMarketPosition.marketIndex, 'Partial')
|
|
438
|
-
: this.getMaxLeverage(proposedMarketPosition.marketIndex, 'Maintenance');
|
|
429
|
+
const marketMaxLeverage = this.getMaxLeverage(proposedMarketPosition.marketIndex, 'Maintenance');
|
|
439
430
|
let priceDelta;
|
|
440
431
|
if (proposedBaseAssetAmount.lt(numericConstants_1.ZERO)) {
|
|
441
432
|
priceDelta = freeCollateralAfterTrade
|
|
@@ -486,7 +477,7 @@ class ClearingHouseUser {
|
|
|
486
477
|
.neg();
|
|
487
478
|
return this.liquidationPrice({
|
|
488
479
|
marketIndex: positionMarketIndex,
|
|
489
|
-
}, closeBaseAmount
|
|
480
|
+
}, closeBaseAmount);
|
|
490
481
|
}
|
|
491
482
|
/**
|
|
492
483
|
* Get the maximum trade size for a given market, taking into account the user's current leverage, positions, collateral, etc.
|
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: '4oyTJnAQ9FqJj1y9mPytbWsLeeHmBzGYfuFqypwyQvuh',
|
|
11
11
|
USDC_MINT_ADDRESS: '8zGuJQqwhZafTah7Uc7Z4tXRnguqkn5KLFAP8oV6PHe2',
|
|
12
12
|
MARKETS: markets_1.DevnetMarkets,
|
|
13
13
|
BANKS: banks_1.DevnetBanks,
|