@drift-labs/sdk 0.2.0-master.27 → 0.2.0-master.29
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 +3 -3
- package/lib/admin.js +5 -5
- package/lib/clearingHouse.d.ts +6 -0
- package/lib/clearingHouse.js +51 -13
- package/lib/clearingHouseConfig.d.ts +1 -0
- package/lib/clearingHouseUser.js +5 -5
- package/lib/config.js +1 -1
- package/lib/idl/clearing_house.json +123 -95
- package/lib/math/insurance.js +1 -1
- package/lib/math/market.d.ts +2 -1
- package/lib/math/market.js +16 -11
- package/lib/math/position.d.ts +3 -3
- package/lib/math/position.js +23 -16
- package/lib/math/repeg.js +8 -0
- package/lib/types.d.ts +22 -39
- package/package.json +1 -1
- package/src/admin.ts +14 -20
- package/src/clearingHouse.ts +81 -8
- package/src/clearingHouseConfig.ts +1 -0
- package/src/clearingHouseUser.ts +6 -6
- package/src/config.ts +1 -1
- package/src/idl/clearing_house.json +123 -95
- package/src/math/insurance.ts +2 -2
- package/src/math/market.ts +21 -12
- package/src/math/position.ts +36 -22
- package/src/math/repeg.ts +9 -0
- package/src/types.ts +24 -40
- package/tests/dlob/helpers.ts +1 -1
- package/lib/math/state.d.ts +0 -8
- package/lib/math/state.js +0 -15
- package/src/math/state.ts +0 -14
package/lib/math/market.d.ts
CHANGED
|
@@ -29,4 +29,5 @@ export declare function calculateOracleSpread(price: BN, oraclePriceData: Oracle
|
|
|
29
29
|
export declare function calculateMarketMarginRatio(market: PerpMarketAccount, size: BN, marginCategory: MarginCategory): number;
|
|
30
30
|
export declare function calculateUnrealizedAssetWeight(market: PerpMarketAccount, quoteSpotMarket: SpotMarketAccount, unrealizedPnl: BN, marginCategory: MarginCategory, oraclePriceData: OraclePriceData): BN;
|
|
31
31
|
export declare function calculateMarketAvailablePNL(perpMarket: PerpMarketAccount, spotMarket: SpotMarketAccount): BN;
|
|
32
|
-
export declare function
|
|
32
|
+
export declare function calculateNetUserPnl(perpMarket: PerpMarketAccount, oraclePriceData: OraclePriceData): BN;
|
|
33
|
+
export declare function calculateNetUserPnlImbalance(perpMarket: PerpMarketAccount, spotMarket: SpotMarketAccount, oraclePriceData: OraclePriceData): BN;
|
package/lib/math/market.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.calculateNetUserPnlImbalance = exports.calculateNetUserPnl = exports.calculateMarketAvailablePNL = exports.calculateUnrealizedAssetWeight = exports.calculateMarketMarginRatio = exports.calculateOracleSpread = exports.calculateMarkOracleSpread = exports.calculateNewMarketAfterTrade = exports.calculateAskPrice = exports.calculateBidPrice = exports.calculateMarkPrice = void 0;
|
|
4
4
|
const anchor_1 = require("@project-serum/anchor");
|
|
5
5
|
const types_1 = require("../types");
|
|
6
6
|
const amm_1 = require("./amm");
|
|
@@ -78,7 +78,7 @@ function calculateUnrealizedAssetWeight(market, quoteSpotMarket, unrealizedPnl,
|
|
|
78
78
|
case 'Initial':
|
|
79
79
|
assetWeight = new anchor_1.BN(market.unrealizedInitialAssetWeight);
|
|
80
80
|
if (market.unrealizedMaxImbalance.gt(numericConstants_1.ZERO)) {
|
|
81
|
-
const netUnsettledPnl =
|
|
81
|
+
const netUnsettledPnl = calculateNetUserPnlImbalance(market, quoteSpotMarket, oraclePriceData);
|
|
82
82
|
if (netUnsettledPnl.gt(market.unrealizedMaxImbalance)) {
|
|
83
83
|
assetWeight = assetWeight
|
|
84
84
|
.mul(market.unrealizedMaxImbalance)
|
|
@@ -98,17 +98,22 @@ function calculateMarketAvailablePNL(perpMarket, spotMarket) {
|
|
|
98
98
|
return (0, spotBalance_1.getTokenAmount)(perpMarket.pnlPool.balance, spotMarket, types_1.SpotBalanceType.DEPOSIT);
|
|
99
99
|
}
|
|
100
100
|
exports.calculateMarketAvailablePNL = calculateMarketAvailablePNL;
|
|
101
|
-
function
|
|
102
|
-
const netUserPositionValue =
|
|
101
|
+
function calculateNetUserPnl(perpMarket, oraclePriceData) {
|
|
102
|
+
const netUserPositionValue = perpMarket.amm.netBaseAssetAmount
|
|
103
103
|
.mul(oraclePriceData.price)
|
|
104
104
|
.div(numericConstants_1.BASE_PRECISION)
|
|
105
105
|
.div(numericConstants_1.PRICE_TO_QUOTE_PRECISION);
|
|
106
|
-
const netUserCostBasis =
|
|
107
|
-
.add(
|
|
108
|
-
.sub(
|
|
109
|
-
const
|
|
110
|
-
|
|
111
|
-
|
|
106
|
+
const netUserCostBasis = perpMarket.amm.quoteAssetAmountLong
|
|
107
|
+
.add(perpMarket.amm.quoteAssetAmountShort)
|
|
108
|
+
.sub(perpMarket.amm.cumulativeSocialLoss);
|
|
109
|
+
const netUserPnl = netUserPositionValue.add(netUserCostBasis);
|
|
110
|
+
return netUserPnl;
|
|
111
|
+
}
|
|
112
|
+
exports.calculateNetUserPnl = calculateNetUserPnl;
|
|
113
|
+
function calculateNetUserPnlImbalance(perpMarket, spotMarket, oraclePriceData) {
|
|
114
|
+
const netUserPnl = calculateNetUserPnl(perpMarket, oraclePriceData);
|
|
115
|
+
const pnlPool = (0, spotBalance_1.getTokenAmount)(perpMarket.pnlPool.balance, spotMarket, types_1.SpotBalanceType.DEPOSIT);
|
|
116
|
+
const imbalance = netUserPnl.sub(pnlPool);
|
|
112
117
|
return imbalance;
|
|
113
118
|
}
|
|
114
|
-
exports.
|
|
119
|
+
exports.calculateNetUserPnlImbalance = calculateNetUserPnlImbalance;
|
package/lib/math/position.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/// <reference types="bn.js" />
|
|
2
|
-
import { BN } from '../';
|
|
2
|
+
import { BN, SpotMarketAccount } from '../';
|
|
3
3
|
import { OraclePriceData } from '../oracles/types';
|
|
4
4
|
import { PerpMarketAccount, PositionDirection, PerpPosition } from '../types';
|
|
5
5
|
/**
|
|
@@ -10,7 +10,7 @@ import { PerpMarketAccount, PositionDirection, PerpPosition } from '../types';
|
|
|
10
10
|
* @param oraclePriceData
|
|
11
11
|
* @returns Base Asset Value. : Precision QUOTE_PRECISION
|
|
12
12
|
*/
|
|
13
|
-
export declare function calculateBaseAssetValue(market: PerpMarketAccount, userPosition: PerpPosition, oraclePriceData: OraclePriceData): BN;
|
|
13
|
+
export declare function calculateBaseAssetValue(market: PerpMarketAccount, userPosition: PerpPosition, oraclePriceData: OraclePriceData, useSpread?: boolean, skipUpdate?: boolean): BN;
|
|
14
14
|
/**
|
|
15
15
|
* calculatePositionPNL
|
|
16
16
|
* = BaseAssetAmount * (Avg Exit Price - Avg Entry Price)
|
|
@@ -21,7 +21,7 @@ export declare function calculateBaseAssetValue(market: PerpMarketAccount, userP
|
|
|
21
21
|
* @returns BaseAssetAmount : Precision QUOTE_PRECISION
|
|
22
22
|
*/
|
|
23
23
|
export declare function calculatePositionPNL(market: PerpMarketAccount, perpPosition: PerpPosition, withFunding: boolean, oraclePriceData: OraclePriceData): BN;
|
|
24
|
-
export declare function
|
|
24
|
+
export declare function calculateClaimablePnl(market: PerpMarketAccount, spotMarket: SpotMarketAccount, perpPosition: PerpPosition, oraclePriceData: OraclePriceData): BN;
|
|
25
25
|
/**
|
|
26
26
|
*
|
|
27
27
|
* @param market
|
package/lib/math/position.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.isEmptyPosition = exports.positionCurrentDirection = exports.findDirectionToClose = exports.calculateCostBasis = exports.calculateEntryPrice = exports.positionIsAvailable = exports.calculatePositionFundingPNL = exports.
|
|
3
|
+
exports.isEmptyPosition = exports.positionCurrentDirection = exports.findDirectionToClose = exports.calculateCostBasis = exports.calculateEntryPrice = exports.positionIsAvailable = exports.calculatePositionFundingPNL = exports.calculateClaimablePnl = exports.calculatePositionPNL = exports.calculateBaseAssetValue = void 0;
|
|
4
4
|
const __1 = require("../");
|
|
5
5
|
const numericConstants_1 = require("../constants/numericConstants");
|
|
6
6
|
const types_1 = require("../types");
|
|
7
7
|
const amm_1 = require("./amm");
|
|
8
8
|
const margin_1 = require("./margin");
|
|
9
|
+
const market_1 = require("./market");
|
|
9
10
|
/**
|
|
10
11
|
* calculateBaseAssetValue
|
|
11
12
|
* = market value of closing entire position
|
|
@@ -14,23 +15,28 @@ const margin_1 = require("./margin");
|
|
|
14
15
|
* @param oraclePriceData
|
|
15
16
|
* @returns Base Asset Value. : Precision QUOTE_PRECISION
|
|
16
17
|
*/
|
|
17
|
-
function calculateBaseAssetValue(market, userPosition, oraclePriceData) {
|
|
18
|
+
function calculateBaseAssetValue(market, userPosition, oraclePriceData, useSpread = true, skipUpdate = false) {
|
|
18
19
|
if (userPosition.baseAssetAmount.eq(numericConstants_1.ZERO)) {
|
|
19
20
|
return numericConstants_1.ZERO;
|
|
20
21
|
}
|
|
21
22
|
const directionToClose = findDirectionToClose(userPosition);
|
|
22
23
|
let prepegAmm;
|
|
23
|
-
if (
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
24
|
+
if (!skipUpdate) {
|
|
25
|
+
if (market.amm.baseSpread > 0 && useSpread) {
|
|
26
|
+
const { baseAssetReserve, quoteAssetReserve, sqrtK, newPeg } = (0, amm_1.calculateUpdatedAMMSpreadReserves)(market.amm, directionToClose, oraclePriceData);
|
|
27
|
+
prepegAmm = {
|
|
28
|
+
baseAssetReserve,
|
|
29
|
+
quoteAssetReserve,
|
|
30
|
+
sqrtK: sqrtK,
|
|
31
|
+
pegMultiplier: newPeg,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
prepegAmm = (0, amm_1.calculateUpdatedAMM)(market.amm, oraclePriceData);
|
|
36
|
+
}
|
|
31
37
|
}
|
|
32
38
|
else {
|
|
33
|
-
prepegAmm =
|
|
39
|
+
prepegAmm = market.amm;
|
|
34
40
|
}
|
|
35
41
|
const [newQuoteAssetReserve, _] = (0, amm_1.calculateAmmReservesAfterSwap)(prepegAmm, 'base', userPosition.baseAssetAmount.abs(), (0, amm_1.getSwapDirection)('base', directionToClose));
|
|
36
42
|
switch (directionToClose) {
|
|
@@ -75,19 +81,20 @@ function calculatePositionPNL(market, perpPosition, withFunding = false, oracleP
|
|
|
75
81
|
return pnl;
|
|
76
82
|
}
|
|
77
83
|
exports.calculatePositionPNL = calculatePositionPNL;
|
|
78
|
-
function
|
|
84
|
+
function calculateClaimablePnl(market, spotMarket, perpPosition, oraclePriceData) {
|
|
79
85
|
const unrealizedPnl = calculatePositionPNL(market, perpPosition, true, oraclePriceData);
|
|
80
|
-
|
|
86
|
+
const fundingPnL = calculatePositionFundingPNL(market, perpPosition).div(numericConstants_1.PRICE_TO_QUOTE_PRECISION);
|
|
87
|
+
let unsettledPnl = unrealizedPnl.add(fundingPnL);
|
|
81
88
|
if (unrealizedPnl.gt(numericConstants_1.ZERO)) {
|
|
82
|
-
const
|
|
89
|
+
const excessPnlPool = __1.BN.max(numericConstants_1.ZERO, (0, market_1.calculateNetUserPnlImbalance)(market, spotMarket, oraclePriceData).mul(new __1.BN(-1)));
|
|
83
90
|
const maxPositivePnl = __1.BN.max(perpPosition.quoteAssetAmount
|
|
84
91
|
.sub(perpPosition.quoteEntryAmount)
|
|
85
|
-
.add(
|
|
92
|
+
.add(excessPnlPool), numericConstants_1.ZERO);
|
|
86
93
|
unsettledPnl = __1.BN.min(maxPositivePnl, unrealizedPnl);
|
|
87
94
|
}
|
|
88
95
|
return unsettledPnl;
|
|
89
96
|
}
|
|
90
|
-
exports.
|
|
97
|
+
exports.calculateClaimablePnl = calculateClaimablePnl;
|
|
91
98
|
/**
|
|
92
99
|
*
|
|
93
100
|
* @param market
|
package/lib/math/repeg.js
CHANGED
|
@@ -71,6 +71,14 @@ function calculateBudgetedKBN(x, y, budget, Q, d) {
|
|
|
71
71
|
.div(numericConstants_1.AMM_RESERVE_PRECISION)
|
|
72
72
|
.div(numericConstants_1.QUOTE_PRECISION);
|
|
73
73
|
const denom2 = pegged_y_d_d;
|
|
74
|
+
// protocol is spending to increase k
|
|
75
|
+
if (C.lt(numericConstants_1.ZERO)) {
|
|
76
|
+
// thus denom1 is negative and solution is unstable
|
|
77
|
+
if (denom1.lt(pegged_y_d_d.abs())) {
|
|
78
|
+
console.log('budget cost exceeds stable K solution');
|
|
79
|
+
return [new anchor_1.BN(10000), new anchor_1.BN(1)];
|
|
80
|
+
}
|
|
81
|
+
}
|
|
74
82
|
const numerator = numer1.sub(numer2).div(numericConstants_1.AMM_TO_QUOTE_PRECISION_RATIO);
|
|
75
83
|
const denominator = denom1.add(denom2).div(numericConstants_1.AMM_TO_QUOTE_PRECISION_RATIO);
|
|
76
84
|
return [numerator, denominator];
|
package/lib/types.d.ts
CHANGED
|
@@ -419,8 +419,6 @@ export declare type StateAccount = {
|
|
|
419
419
|
exchangePaused: boolean;
|
|
420
420
|
adminControlsPrices: boolean;
|
|
421
421
|
insuranceVault: PublicKey;
|
|
422
|
-
perpFeeStructure: FeeStructure;
|
|
423
|
-
spotFeeStructure: FeeStructure;
|
|
424
422
|
totalFee: BN;
|
|
425
423
|
totalFeeWithdrawn: BN;
|
|
426
424
|
whitelistMint: PublicKey;
|
|
@@ -436,6 +434,8 @@ export declare type StateAccount = {
|
|
|
436
434
|
minPerpAuctionDuration: number;
|
|
437
435
|
defaultSpotAuctionDuration: number;
|
|
438
436
|
liquidationMarginBufferRatio: number;
|
|
437
|
+
perpFeeStructure: FeeStructure;
|
|
438
|
+
spotFeeStructure: FeeStructure;
|
|
439
439
|
};
|
|
440
440
|
export declare type PerpMarketAccount = {
|
|
441
441
|
status: MarketStatus;
|
|
@@ -581,7 +581,7 @@ export declare type PerpPosition = {
|
|
|
581
581
|
openOrders: BN;
|
|
582
582
|
openBids: BN;
|
|
583
583
|
openAsks: BN;
|
|
584
|
-
|
|
584
|
+
settledPnl: BN;
|
|
585
585
|
lpShares: BN;
|
|
586
586
|
lastFeePerLp: BN;
|
|
587
587
|
lastNetBaseAssetAmountPerLp: BN;
|
|
@@ -605,10 +605,11 @@ export declare type UserStatsAccount = {
|
|
|
605
605
|
isReferrer: boolean;
|
|
606
606
|
totalReferrerReward: BN;
|
|
607
607
|
authority: PublicKey;
|
|
608
|
-
|
|
608
|
+
stakedQuoteAssetAmount: BN;
|
|
609
609
|
};
|
|
610
610
|
export declare type UserAccount = {
|
|
611
611
|
authority: PublicKey;
|
|
612
|
+
delegate: PublicKey;
|
|
612
613
|
name: number[];
|
|
613
614
|
userId: number;
|
|
614
615
|
spotPositions: SpotPosition[];
|
|
@@ -733,40 +734,27 @@ export interface IWallet {
|
|
|
733
734
|
publicKey: PublicKey;
|
|
734
735
|
}
|
|
735
736
|
export declare type FeeStructure = {
|
|
736
|
-
|
|
737
|
-
feeDenominator: BN;
|
|
738
|
-
discountTokenTiers: {
|
|
739
|
-
firstTier: {
|
|
740
|
-
minimumBalance: BN;
|
|
741
|
-
discountNumerator: BN;
|
|
742
|
-
discountDenominator: BN;
|
|
743
|
-
};
|
|
744
|
-
secondTier: {
|
|
745
|
-
minimumBalance: BN;
|
|
746
|
-
discountNumerator: BN;
|
|
747
|
-
discountDenominator: BN;
|
|
748
|
-
};
|
|
749
|
-
thirdTier: {
|
|
750
|
-
minimumBalance: BN;
|
|
751
|
-
discountNumerator: BN;
|
|
752
|
-
discountDenominator: BN;
|
|
753
|
-
};
|
|
754
|
-
fourthTier: {
|
|
755
|
-
minimumBalance: BN;
|
|
756
|
-
discountNumerator: BN;
|
|
757
|
-
discountDenominator: BN;
|
|
758
|
-
};
|
|
759
|
-
};
|
|
760
|
-
referralDiscount: {
|
|
761
|
-
referrerRewardNumerator: BN;
|
|
762
|
-
referrerRewardDenominator: BN;
|
|
763
|
-
refereeDiscountNumerator: BN;
|
|
764
|
-
refereeDiscountDenominator: BN;
|
|
765
|
-
};
|
|
737
|
+
feeTiers: FeeTier[];
|
|
766
738
|
makerRebateNumerator: BN;
|
|
767
739
|
makerRebateDenominator: BN;
|
|
768
740
|
fillerRewardStructure: OrderFillerRewardStructure;
|
|
769
741
|
flatFillerFee: BN;
|
|
742
|
+
referrerRewardEpochUpperBound: BN;
|
|
743
|
+
};
|
|
744
|
+
export declare type FeeTier = {
|
|
745
|
+
feeNumerator: number;
|
|
746
|
+
feeDenominator: number;
|
|
747
|
+
makerRebateNumerator: number;
|
|
748
|
+
makerRebateDenominator: number;
|
|
749
|
+
referrerRewardNumerator: number;
|
|
750
|
+
referrerRewardDenominator: number;
|
|
751
|
+
refereeFeeNumerator: number;
|
|
752
|
+
refereeFeeDenominator: number;
|
|
753
|
+
};
|
|
754
|
+
export declare type OrderFillerRewardStructure = {
|
|
755
|
+
rewardNumerator: BN;
|
|
756
|
+
rewardDenominator: BN;
|
|
757
|
+
timeBasedRewardLowerBound: BN;
|
|
770
758
|
};
|
|
771
759
|
export declare type OracleGuardRails = {
|
|
772
760
|
priceDivergence: {
|
|
@@ -780,11 +768,6 @@ export declare type OracleGuardRails = {
|
|
|
780
768
|
};
|
|
781
769
|
useForLiquidations: boolean;
|
|
782
770
|
};
|
|
783
|
-
export declare type OrderFillerRewardStructure = {
|
|
784
|
-
rewardNumerator: BN;
|
|
785
|
-
rewardDenominator: BN;
|
|
786
|
-
timeBasedRewardLowerBound: BN;
|
|
787
|
-
};
|
|
788
771
|
export declare type MarginCategory = 'Initial' | 'Maintenance';
|
|
789
772
|
export declare type InsuranceFundStake = {
|
|
790
773
|
marketIndex: BN;
|
package/package.json
CHANGED
package/src/admin.ts
CHANGED
|
@@ -3,12 +3,7 @@ import {
|
|
|
3
3
|
SYSVAR_RENT_PUBKEY,
|
|
4
4
|
TransactionSignature,
|
|
5
5
|
} from '@solana/web3.js';
|
|
6
|
-
import {
|
|
7
|
-
FeeStructure,
|
|
8
|
-
OracleGuardRails,
|
|
9
|
-
OracleSource,
|
|
10
|
-
OrderFillerRewardStructure,
|
|
11
|
-
} from './types';
|
|
6
|
+
import { FeeStructure, OracleGuardRails, OracleSource } from './types';
|
|
12
7
|
import { BN } from '@project-serum/anchor';
|
|
13
8
|
import * as anchor from '@project-serum/anchor';
|
|
14
9
|
import {
|
|
@@ -278,7 +273,7 @@ export class Admin extends ClearingHouse {
|
|
|
278
273
|
marketIndex: BN,
|
|
279
274
|
concentrationScale: BN
|
|
280
275
|
): Promise<TransactionSignature> {
|
|
281
|
-
return await this.program.rpc.
|
|
276
|
+
return await this.program.rpc.updateConcentrationCoef(concentrationScale, {
|
|
282
277
|
accounts: {
|
|
283
278
|
state: await this.getStatePublicKey(),
|
|
284
279
|
admin: this.wallet.publicKey,
|
|
@@ -611,22 +606,21 @@ export class Admin extends ClearingHouse {
|
|
|
611
606
|
);
|
|
612
607
|
}
|
|
613
608
|
|
|
614
|
-
public async
|
|
615
|
-
|
|
609
|
+
public async updatePerpFeeStructure(
|
|
610
|
+
feeStructure: FeeStructure
|
|
616
611
|
): Promise<TransactionSignature> {
|
|
617
|
-
return await this.program.rpc.
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
},
|
|
624
|
-
}
|
|
625
|
-
);
|
|
612
|
+
return await this.program.rpc.updatePerpFeeStructure(feeStructure, {
|
|
613
|
+
accounts: {
|
|
614
|
+
admin: this.wallet.publicKey,
|
|
615
|
+
state: await this.getStatePublicKey(),
|
|
616
|
+
},
|
|
617
|
+
});
|
|
626
618
|
}
|
|
627
619
|
|
|
628
|
-
public async
|
|
629
|
-
|
|
620
|
+
public async updateSpotFeeStructure(
|
|
621
|
+
feeStructure: FeeStructure
|
|
622
|
+
): Promise<TransactionSignature> {
|
|
623
|
+
return await this.program.rpc.updateSpotFeeStructure(feeStructure, {
|
|
630
624
|
accounts: {
|
|
631
625
|
admin: this.wallet.publicKey,
|
|
632
626
|
state: await this.getStatePublicKey(),
|
package/src/clearingHouse.ts
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { AnchorProvider, BN, Idl, Program } from '@project-serum/anchor';
|
|
2
|
-
import
|
|
2
|
+
import bs58 from 'bs58';
|
|
3
|
+
import {
|
|
4
|
+
ASSOCIATED_TOKEN_PROGRAM_ID,
|
|
5
|
+
Token,
|
|
6
|
+
TOKEN_PROGRAM_ID,
|
|
7
|
+
} from '@solana/spl-token';
|
|
3
8
|
import {
|
|
4
9
|
StateAccount,
|
|
5
10
|
IWallet,
|
|
@@ -97,6 +102,7 @@ export class ClearingHouse {
|
|
|
97
102
|
_isSubscribed = false;
|
|
98
103
|
txSender: TxSender;
|
|
99
104
|
marketLastSlotCache = new Map<number, number>();
|
|
105
|
+
authority: PublicKey;
|
|
100
106
|
|
|
101
107
|
public get isSubscribed() {
|
|
102
108
|
return this._isSubscribed && this.accountSubscriber.isSubscribed;
|
|
@@ -121,6 +127,7 @@ export class ClearingHouse {
|
|
|
121
127
|
this.provider
|
|
122
128
|
);
|
|
123
129
|
|
|
130
|
+
this.authority = config.authority ?? this.wallet.publicKey;
|
|
124
131
|
const userIds = config.userIds ?? [0];
|
|
125
132
|
this.activeUserId = config.activeUserId ?? userIds[0];
|
|
126
133
|
this.userAccountSubscriptionConfig =
|
|
@@ -138,7 +145,7 @@ export class ClearingHouse {
|
|
|
138
145
|
clearingHouse: this,
|
|
139
146
|
userStatsAccountPublicKey: getUserStatsAccountPublicKey(
|
|
140
147
|
this.program.programId,
|
|
141
|
-
this.
|
|
148
|
+
this.authority
|
|
142
149
|
),
|
|
143
150
|
accountSubscription: this.userAccountSubscriptionConfig,
|
|
144
151
|
});
|
|
@@ -203,7 +210,7 @@ export class ClearingHouse {
|
|
|
203
210
|
): ClearingHouseUser {
|
|
204
211
|
const userAccountPublicKey = getUserAccountPublicKeySync(
|
|
205
212
|
this.program.programId,
|
|
206
|
-
this.
|
|
213
|
+
this.authority,
|
|
207
214
|
userId
|
|
208
215
|
);
|
|
209
216
|
|
|
@@ -494,6 +501,36 @@ export class ClearingHouse {
|
|
|
494
501
|
);
|
|
495
502
|
}
|
|
496
503
|
|
|
504
|
+
public async updateUserDelegate(
|
|
505
|
+
delegate: PublicKey,
|
|
506
|
+
userId = 0
|
|
507
|
+
): Promise<TransactionSignature> {
|
|
508
|
+
return await this.program.rpc.updateUserDelegate(userId, delegate, {
|
|
509
|
+
accounts: {
|
|
510
|
+
user: await this.getUserAccountPublicKey(),
|
|
511
|
+
authority: this.wallet.publicKey,
|
|
512
|
+
},
|
|
513
|
+
});
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
public async getUserAccountsForDelegate(
|
|
517
|
+
delegate: PublicKey
|
|
518
|
+
): Promise<UserAccount[]> {
|
|
519
|
+
const programAccounts = await this.program.account.user.all([
|
|
520
|
+
{
|
|
521
|
+
memcmp: {
|
|
522
|
+
offset: 40,
|
|
523
|
+
/** data to match, as base-58 encoded string and limited to less than 129 bytes */
|
|
524
|
+
bytes: bs58.encode(delegate.toBuffer()),
|
|
525
|
+
},
|
|
526
|
+
},
|
|
527
|
+
]);
|
|
528
|
+
|
|
529
|
+
return programAccounts.map(
|
|
530
|
+
(programAccount) => programAccount.account as UserAccount
|
|
531
|
+
);
|
|
532
|
+
}
|
|
533
|
+
|
|
497
534
|
public getUser(userId?: number): ClearingHouseUser {
|
|
498
535
|
userId = userId ?? this.activeUserId;
|
|
499
536
|
if (!this.users.has(userId)) {
|
|
@@ -518,7 +555,7 @@ export class ClearingHouse {
|
|
|
518
555
|
|
|
519
556
|
this.userStatsAccountPublicKey = getUserStatsAccountPublicKey(
|
|
520
557
|
this.program.programId,
|
|
521
|
-
this.
|
|
558
|
+
this.authority
|
|
522
559
|
);
|
|
523
560
|
return this.userStatsAccountPublicKey;
|
|
524
561
|
}
|
|
@@ -732,7 +769,7 @@ export class ClearingHouse {
|
|
|
732
769
|
|
|
733
770
|
const isSolMarket = spotMarketAccount.mint.equals(WRAPPED_SOL_MINT);
|
|
734
771
|
|
|
735
|
-
const authority = this.
|
|
772
|
+
const authority = this.authority;
|
|
736
773
|
|
|
737
774
|
const createWSOLTokenAccount =
|
|
738
775
|
isSolMarket && collateralAccountPublicKey.equals(authority);
|
|
@@ -793,7 +830,7 @@ export class ClearingHouse {
|
|
|
793
830
|
const userAccountPublicKey = userId
|
|
794
831
|
? await getUserAccountPublicKey(
|
|
795
832
|
this.program.programId,
|
|
796
|
-
this.
|
|
833
|
+
this.authority,
|
|
797
834
|
userId
|
|
798
835
|
)
|
|
799
836
|
: await this.getUserAccountPublicKey();
|
|
@@ -841,10 +878,10 @@ export class ClearingHouse {
|
|
|
841
878
|
);
|
|
842
879
|
}
|
|
843
880
|
|
|
844
|
-
private async checkIfAccountExists(account: PublicKey) {
|
|
881
|
+
private async checkIfAccountExists(account: PublicKey): Promise<boolean> {
|
|
845
882
|
try {
|
|
846
883
|
const accountInfo = await this.connection.getAccountInfo(account);
|
|
847
|
-
return accountInfo
|
|
884
|
+
return accountInfo != null;
|
|
848
885
|
} catch (e) {
|
|
849
886
|
// Doesn't already exist
|
|
850
887
|
return false;
|
|
@@ -947,6 +984,23 @@ export class ClearingHouse {
|
|
|
947
984
|
return result;
|
|
948
985
|
}
|
|
949
986
|
|
|
987
|
+
public getAssociatedTokenAccountCreationIx(
|
|
988
|
+
tokenMintAddress: PublicKey,
|
|
989
|
+
associatedTokenAddress: PublicKey
|
|
990
|
+
): anchor.web3.TransactionInstruction {
|
|
991
|
+
const createAssociatedAccountIx =
|
|
992
|
+
Token.createAssociatedTokenAccountInstruction(
|
|
993
|
+
ASSOCIATED_TOKEN_PROGRAM_ID,
|
|
994
|
+
TOKEN_PROGRAM_ID,
|
|
995
|
+
tokenMintAddress,
|
|
996
|
+
associatedTokenAddress,
|
|
997
|
+
this.wallet.publicKey,
|
|
998
|
+
this.wallet.publicKey
|
|
999
|
+
);
|
|
1000
|
+
|
|
1001
|
+
return createAssociatedAccountIx;
|
|
1002
|
+
}
|
|
1003
|
+
|
|
950
1004
|
/**
|
|
951
1005
|
* Creates the Clearing House User account for a user, and deposits some initial collateral
|
|
952
1006
|
* @param amount
|
|
@@ -1109,6 +1163,18 @@ export class ClearingHouse {
|
|
|
1109
1163
|
});
|
|
1110
1164
|
|
|
1111
1165
|
signers.forEach((signer) => additionalSigners.push(signer));
|
|
1166
|
+
} else {
|
|
1167
|
+
const accountExists = await this.checkIfAccountExists(userTokenAccount);
|
|
1168
|
+
|
|
1169
|
+
if (!accountExists) {
|
|
1170
|
+
const createAssociatedTokenAccountIx =
|
|
1171
|
+
this.getAssociatedTokenAccountCreationIx(
|
|
1172
|
+
spotMarketAccount.mint,
|
|
1173
|
+
userTokenAccount
|
|
1174
|
+
);
|
|
1175
|
+
|
|
1176
|
+
tx.add(createAssociatedTokenAccountIx);
|
|
1177
|
+
}
|
|
1112
1178
|
}
|
|
1113
1179
|
|
|
1114
1180
|
const withdrawCollateral = await this.getWithdrawIx(
|
|
@@ -3199,6 +3265,13 @@ export class ClearingHouse {
|
|
|
3199
3265
|
return oracleData;
|
|
3200
3266
|
}
|
|
3201
3267
|
|
|
3268
|
+
public getOracleDataForSpotMarket(marketIndex: BN): OraclePriceData {
|
|
3269
|
+
const oracleKey = this.getSpotMarketAccount(marketIndex).oracle;
|
|
3270
|
+
const oracleData = this.getOraclePriceDataAndSlot(oracleKey).data;
|
|
3271
|
+
|
|
3272
|
+
return oracleData;
|
|
3273
|
+
}
|
|
3274
|
+
|
|
3202
3275
|
public async initializeInsuranceFundStake(
|
|
3203
3276
|
marketIndex: BN
|
|
3204
3277
|
): Promise<TransactionSignature> {
|
package/src/clearingHouseUser.ts
CHANGED
|
@@ -142,7 +142,7 @@ export class ClearingHouseUser {
|
|
|
142
142
|
openOrders: ZERO,
|
|
143
143
|
openBids: ZERO,
|
|
144
144
|
openAsks: ZERO,
|
|
145
|
-
|
|
145
|
+
settledPnl: ZERO,
|
|
146
146
|
lpShares: ZERO,
|
|
147
147
|
lastFeePerLp: ZERO,
|
|
148
148
|
lastNetBaseAssetAmountPerLp: ZERO,
|
|
@@ -1071,7 +1071,7 @@ export class ClearingHouseUser {
|
|
|
1071
1071
|
openOrders: new BN(0),
|
|
1072
1072
|
openBids: new BN(0),
|
|
1073
1073
|
openAsks: new BN(0),
|
|
1074
|
-
|
|
1074
|
+
settledPnl: ZERO,
|
|
1075
1075
|
lpShares: ZERO,
|
|
1076
1076
|
lastFeePerLp: ZERO,
|
|
1077
1077
|
lastNetBaseAssetAmountPerLp: ZERO,
|
|
@@ -1395,11 +1395,11 @@ export class ClearingHouseUser {
|
|
|
1395
1395
|
* @returns feeForQuote : Precision QUOTE_PRECISION
|
|
1396
1396
|
*/
|
|
1397
1397
|
public calculateFeeForQuoteAmount(quoteAmount: BN): BN {
|
|
1398
|
-
const
|
|
1399
|
-
|
|
1398
|
+
const feeTier =
|
|
1399
|
+
this.clearingHouse.getStateAccount().perpFeeStructure.feeTiers[0];
|
|
1400
1400
|
return quoteAmount
|
|
1401
|
-
.mul(
|
|
1402
|
-
.div(
|
|
1401
|
+
.mul(new BN(feeTier.feeNumerator))
|
|
1402
|
+
.div(new BN(feeTier.feeDenominator));
|
|
1403
1403
|
}
|
|
1404
1404
|
|
|
1405
1405
|
/**
|
package/src/config.ts
CHANGED
|
@@ -28,7 +28,7 @@ export const configs: { [key in DriftEnv]: DriftConfig } = {
|
|
|
28
28
|
devnet: {
|
|
29
29
|
ENV: 'devnet',
|
|
30
30
|
PYTH_ORACLE_MAPPING_ADDRESS: 'BmA9Z6FjioHJPpjT39QazZyhDRUdZy2ezwx4GiDdE2u2',
|
|
31
|
-
CLEARING_HOUSE_PROGRAM_ID: '
|
|
31
|
+
CLEARING_HOUSE_PROGRAM_ID: '6MVFno8SFkVffGuCCQzg2wi8FvF8sPRFDNHa13ZPP9cK',
|
|
32
32
|
USDC_MINT_ADDRESS: '8zGuJQqwhZafTah7Uc7Z4tXRnguqkn5KLFAP8oV6PHe2',
|
|
33
33
|
PERP_MARKETS: DevnetPerpMarkets,
|
|
34
34
|
SPOT_MARKETS: DevnetSpotMarkets,
|