@drift-labs/sdk 0.1.36-master.5 → 0.2.0-master.0
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/bulkAccountLoader.d.ts +7 -6
- package/lib/accounts/bulkAccountLoader.js +83 -93
- package/lib/accounts/bulkUserSubscription.js +13 -57
- package/lib/accounts/fetch.d.ts +4 -0
- package/lib/accounts/fetch.js +18 -0
- package/lib/accounts/pollingClearingHouseAccountSubscriber.d.ts +34 -38
- package/lib/accounts/pollingClearingHouseAccountSubscriber.js +224 -224
- package/lib/accounts/pollingOracleSubscriber.d.ts +3 -3
- package/lib/accounts/pollingOracleSubscriber.js +37 -49
- package/lib/accounts/pollingTokenAccountSubscriber.d.ts +3 -3
- package/lib/accounts/pollingTokenAccountSubscriber.js +35 -50
- package/lib/accounts/pollingUserAccountSubscriber.d.ts +7 -13
- package/lib/accounts/pollingUserAccountSubscriber.js +71 -134
- package/lib/accounts/types.d.ts +34 -41
- package/lib/accounts/webSocketAccountSubscriber.d.ts +6 -4
- package/lib/accounts/webSocketAccountSubscriber.js +39 -35
- package/lib/accounts/webSocketClearingHouseAccountSubscriber.d.ts +33 -28
- package/lib/accounts/webSocketClearingHouseAccountSubscriber.js +153 -185
- package/lib/accounts/webSocketUserAccountSubscriber.d.ts +5 -11
- package/lib/accounts/webSocketUserAccountSubscriber.js +22 -67
- package/lib/addresses/marketAddresses.d.ts +4 -0
- package/lib/addresses/marketAddresses.js +15 -0
- package/lib/addresses/pda.d.ts +12 -0
- package/lib/addresses/pda.js +83 -0
- package/lib/admin.d.ts +8 -12
- package/lib/admin.js +366 -490
- package/lib/clearingHouse.d.ts +84 -103
- package/lib/clearingHouse.js +779 -810
- package/lib/clearingHouseConfig.d.ts +34 -0
- package/lib/clearingHouseConfig.js +2 -0
- package/lib/clearingHouseUser.d.ts +19 -18
- package/lib/clearingHouseUser.js +157 -115
- package/lib/clearingHouseUserConfig.d.ts +14 -0
- package/lib/clearingHouseUserConfig.js +2 -0
- package/lib/config.d.ts +12 -0
- package/lib/config.js +35 -4
- package/lib/constants/banks.d.ts +16 -0
- package/lib/constants/banks.js +34 -0
- package/lib/constants/markets.d.ts +8 -3
- package/lib/constants/markets.js +13 -206
- package/lib/constants/numericConstants.d.ts +16 -0
- package/lib/constants/numericConstants.js +22 -6
- package/lib/events/eventList.d.ts +22 -0
- package/lib/events/eventList.js +77 -0
- package/lib/events/eventSubscriber.d.ts +34 -0
- package/lib/events/eventSubscriber.js +126 -0
- package/lib/events/fetchLogs.d.ts +13 -0
- package/lib/events/fetchLogs.js +39 -0
- package/lib/events/pollingLogProvider.d.ts +15 -0
- package/lib/events/pollingLogProvider.js +53 -0
- package/lib/events/sort.d.ts +2 -0
- package/lib/events/sort.js +44 -0
- package/lib/events/txEventCache.d.ts +24 -0
- package/lib/events/txEventCache.js +71 -0
- package/lib/events/types.d.ts +49 -0
- package/lib/events/types.js +20 -0
- package/lib/events/webSocketLogProvider.d.ts +12 -0
- package/lib/events/webSocketLogProvider.js +30 -0
- package/lib/examples/makeTradeExample.js +26 -27
- package/lib/factory/bigNum.d.ts +112 -0
- package/lib/factory/bigNum.js +356 -0
- package/lib/factory/oracleClient.d.ts +1 -2
- package/lib/factory/oracleClient.js +6 -2
- package/lib/idl/clearing_house.json +1739 -2287
- package/lib/index.d.ts +13 -4
- package/lib/index.js +13 -4
- package/lib/math/amm.d.ts +19 -29
- package/lib/math/amm.js +129 -179
- package/lib/math/auction.d.ts +5 -0
- package/lib/math/auction.js +39 -0
- package/lib/math/bankBalance.d.ts +9 -0
- package/lib/math/bankBalance.js +75 -0
- package/lib/math/conversion.d.ts +0 -1
- package/lib/math/conversion.js +1 -5
- package/lib/math/funding.d.ts +6 -6
- package/lib/math/funding.js +158 -175
- package/lib/math/market.d.ts +6 -6
- package/lib/math/market.js +10 -9
- package/lib/math/oracles.d.ts +3 -0
- package/lib/math/oracles.js +26 -0
- package/lib/math/orders.d.ts +5 -0
- package/lib/math/orders.js +31 -1
- package/lib/math/position.d.ts +7 -4
- package/lib/math/position.js +27 -9
- package/lib/math/repeg.d.ts +22 -0
- package/lib/math/repeg.js +128 -0
- package/lib/math/trade.d.ts +13 -8
- package/lib/math/trade.js +85 -22
- package/lib/mockUSDCFaucet.js +87 -116
- package/lib/oracles/oracleClientCache.d.ts +8 -0
- package/lib/oracles/oracleClientCache.js +19 -0
- package/lib/oracles/pythClient.d.ts +3 -5
- package/lib/oracles/pythClient.js +12 -30
- package/lib/oracles/quoteAssetOracleClient.d.ts +9 -0
- package/lib/oracles/quoteAssetOracleClient.js +21 -0
- package/lib/oracles/switchboardClient.d.ts +3 -5
- package/lib/oracles/switchboardClient.js +29 -47
- package/lib/oracles/types.d.ts +7 -1
- package/lib/orders.d.ts +6 -6
- package/lib/orders.js +10 -9
- package/lib/slot/SlotSubscriber.d.ts +12 -0
- package/lib/slot/SlotSubscriber.js +23 -0
- package/lib/tx/retryTxSender.d.ts +2 -2
- package/lib/tx/retryTxSender.js +108 -123
- package/lib/tx/types.d.ts +5 -1
- package/lib/tx/utils.d.ts +1 -1
- package/lib/tx/utils.js +11 -2
- package/lib/types.d.ts +105 -98
- package/lib/types.js +13 -1
- package/lib/userName.d.ts +4 -0
- package/lib/userName.js +20 -0
- package/lib/util/computeUnits.js +10 -21
- package/lib/util/tps.js +11 -22
- package/lib/wallet.js +7 -20
- package/package.json +10 -3
- package/src/accounts/bulkAccountLoader.ts +26 -15
- package/src/accounts/bulkUserSubscription.ts +1 -45
- package/src/accounts/fetch.ts +33 -0
- package/src/accounts/pollingClearingHouseAccountSubscriber.ts +249 -214
- package/src/accounts/pollingOracleSubscriber.ts +16 -8
- package/src/accounts/pollingTokenAccountSubscriber.ts +11 -8
- package/src/accounts/pollingUserAccountSubscriber.ts +21 -86
- package/src/accounts/types.ts +41 -70
- package/src/accounts/webSocketAccountSubscriber.ts +33 -16
- package/src/accounts/webSocketClearingHouseAccountSubscriber.ts +190 -240
- package/src/accounts/webSocketUserAccountSubscriber.ts +11 -71
- package/src/addresses/marketAddresses.ts +18 -0
- package/src/addresses/pda.ts +118 -0
- package/src/admin.ts +209 -267
- package/src/clearingHouse.ts +921 -829
- package/src/clearingHouseConfig.ts +37 -0
- package/src/clearingHouseUser.ts +280 -127
- package/src/clearingHouseUserConfig.ts +18 -0
- package/src/config.ts +54 -1
- package/src/constants/banks.ts +43 -0
- package/src/constants/markets.ts +16 -207
- package/src/constants/numericConstants.ts +33 -5
- package/src/events/eventList.ts +94 -0
- package/src/events/eventSubscriber.ts +194 -0
- package/src/events/fetchLogs.ts +80 -0
- package/src/events/pollingLogProvider.ts +79 -0
- package/src/events/sort.ts +65 -0
- package/src/events/txEventCache.ts +74 -0
- package/src/events/types.ts +98 -0
- package/src/events/webSocketLogProvider.ts +38 -0
- package/src/examples/makeTradeExample.ts +20 -11
- package/src/factory/bigNum.ts +507 -0
- package/src/factory/oracleClient.ts +7 -4
- package/src/idl/clearing_house.json +1739 -2287
- package/src/index.ts +13 -4
- package/src/math/amm.ts +229 -245
- package/src/math/auction.ts +39 -0
- package/src/math/bankBalance.ts +112 -0
- package/src/math/conversion.ts +1 -11
- package/src/math/funding.ts +12 -9
- package/src/math/market.ts +37 -30
- package/src/math/oracles.ts +36 -0
- package/src/math/orders.ts +38 -0
- package/src/math/position.ts +48 -13
- package/src/math/repeg.ts +175 -0
- package/src/math/trade.ts +114 -36
- package/src/math/utils.js +27 -0
- package/src/math/utils.js.map +1 -0
- package/src/oracles/oracleClientCache.ts +20 -0
- package/src/oracles/pythClient.ts +5 -11
- package/src/oracles/quoteAssetOracleClient.ts +25 -0
- package/src/oracles/switchboardClient.ts +16 -24
- package/src/oracles/types.ts +8 -1
- package/src/orders.ts +35 -20
- package/src/slot/SlotSubscriber.ts +32 -0
- package/src/tx/retryTxSender.ts +6 -4
- package/src/tx/types.ts +6 -1
- package/src/tx/utils.ts +22 -3
- package/src/types.ts +108 -110
- package/src/userName.ts +20 -0
- package/src/util/computeUnits.js +17 -0
- package/src/util/computeUnits.js.map +1 -0
- package/tests/bn/test.ts +255 -0
- package/tsconfig.json +12 -12
- package/lib/addresses.d.ts +0 -9
- package/lib/addresses.js +0 -87
- package/lib/constants/accounts.d.ts +0 -15
- package/lib/constants/accounts.js +0 -18
- package/lib/factory/clearingHouse.d.ts +0 -35
- package/lib/factory/clearingHouse.js +0 -81
- package/lib/factory/clearingHouseUser.d.ts +0 -19
- package/lib/factory/clearingHouseUser.js +0 -34
- package/lib/math/insuranceFund.d.ts +0 -15
- package/lib/math/insuranceFund.js +0 -33
- package/lib/tx/defaultTxSender.d.ts +0 -8
- package/lib/tx/defaultTxSender.js +0 -12
- package/src/addresses.ts +0 -71
- package/src/constants/accounts.ts +0 -26
- package/src/factory/clearingHouse.ts +0 -173
- package/src/factory/clearingHouseUser.ts +0 -73
- package/src/math/insuranceFund.ts +0 -29
- package/src/tx/defaultTxSender.ts +0 -24
package/src/clearingHouseUser.ts
CHANGED
|
@@ -7,9 +7,7 @@ import {
|
|
|
7
7
|
MarginCategory,
|
|
8
8
|
Order,
|
|
9
9
|
UserAccount,
|
|
10
|
-
UserOrdersAccount,
|
|
11
10
|
UserPosition,
|
|
12
|
-
UserPositionsAccount,
|
|
13
11
|
} from './types';
|
|
14
12
|
import { calculateEntryPrice } from './math/position';
|
|
15
13
|
import {
|
|
@@ -22,30 +20,33 @@ import {
|
|
|
22
20
|
AMM_RESERVE_PRECISION,
|
|
23
21
|
PRICE_TO_QUOTE_PRECISION,
|
|
24
22
|
MARGIN_PRECISION,
|
|
23
|
+
BANK_WEIGHT_PRECISION,
|
|
25
24
|
} from './constants/numericConstants';
|
|
26
|
-
import {
|
|
25
|
+
import {
|
|
26
|
+
UserAccountSubscriber,
|
|
27
|
+
UserAccountEvents,
|
|
28
|
+
DataAndSlot,
|
|
29
|
+
} from './accounts/types';
|
|
27
30
|
import {
|
|
28
31
|
calculateMarkPrice,
|
|
29
32
|
calculateBaseAssetValue,
|
|
30
33
|
calculatePositionFundingPNL,
|
|
31
34
|
calculatePositionPNL,
|
|
32
35
|
PositionDirection,
|
|
33
|
-
getUserOrdersAccountPublicKey,
|
|
34
36
|
calculateTradeSlippage,
|
|
35
37
|
BN,
|
|
38
|
+
BankAccount,
|
|
36
39
|
} from '.';
|
|
37
|
-
import {
|
|
38
|
-
import {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
} from './
|
|
40
|
+
import { getTokenAmount } from './math/bankBalance';
|
|
41
|
+
import { OraclePriceData } from './oracles/types';
|
|
42
|
+
import { ClearingHouseUserConfig } from './clearingHouseUserConfig';
|
|
43
|
+
import { PollingUserAccountSubscriber } from './accounts/pollingUserAccountSubscriber';
|
|
44
|
+
import { WebSocketUserAccountSubscriber } from './accounts/webSocketUserAccountSubscriber';
|
|
42
45
|
|
|
43
46
|
export class ClearingHouseUser {
|
|
44
47
|
clearingHouse: ClearingHouse;
|
|
45
|
-
|
|
48
|
+
userAccountPublicKey: PublicKey;
|
|
46
49
|
accountSubscriber: UserAccountSubscriber;
|
|
47
|
-
userAccountPublicKey?: PublicKey;
|
|
48
|
-
userOrdersAccountPublicKey?: PublicKey;
|
|
49
50
|
_isSubscribed = false;
|
|
50
51
|
eventEmitter: StrictEventEmitter<EventEmitter, UserAccountEvents>;
|
|
51
52
|
|
|
@@ -57,34 +58,21 @@ export class ClearingHouseUser {
|
|
|
57
58
|
this._isSubscribed = val;
|
|
58
59
|
}
|
|
59
60
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
authority
|
|
76
|
-
);
|
|
77
|
-
return getClearingHouseUser(config);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
public constructor(
|
|
81
|
-
clearingHouse: ClearingHouse,
|
|
82
|
-
authority: PublicKey,
|
|
83
|
-
accountSubscriber: UserAccountSubscriber
|
|
84
|
-
) {
|
|
85
|
-
this.clearingHouse = clearingHouse;
|
|
86
|
-
this.authority = authority;
|
|
87
|
-
this.accountSubscriber = accountSubscriber;
|
|
61
|
+
public constructor(config: ClearingHouseUserConfig) {
|
|
62
|
+
this.clearingHouse = config.clearingHouse;
|
|
63
|
+
this.userAccountPublicKey = config.userAccountPublicKey;
|
|
64
|
+
if (config.accountSubscription?.type === 'polling') {
|
|
65
|
+
this.accountSubscriber = new PollingUserAccountSubscriber(
|
|
66
|
+
config.clearingHouse.program,
|
|
67
|
+
config.userAccountPublicKey,
|
|
68
|
+
config.accountSubscription.accountLoader
|
|
69
|
+
);
|
|
70
|
+
} else {
|
|
71
|
+
this.accountSubscriber = new WebSocketUserAccountSubscriber(
|
|
72
|
+
config.clearingHouse.program,
|
|
73
|
+
config.userAccountPublicKey
|
|
74
|
+
);
|
|
75
|
+
}
|
|
88
76
|
this.eventEmitter = this.accountSubscriber.eventEmitter;
|
|
89
77
|
}
|
|
90
78
|
|
|
@@ -93,9 +81,6 @@ export class ClearingHouseUser {
|
|
|
93
81
|
* @returns SusbcriptionSuccess result
|
|
94
82
|
*/
|
|
95
83
|
public async subscribe(): Promise<boolean> {
|
|
96
|
-
// Clearing house should already be subscribed, but await for the subscription just incase to avoid race condition
|
|
97
|
-
await this.clearingHouse.subscribe();
|
|
98
|
-
|
|
99
84
|
this.isSubscribed = await this.accountSubscriber.subscribe();
|
|
100
85
|
return this.isSubscribed;
|
|
101
86
|
}
|
|
@@ -113,15 +98,11 @@ export class ClearingHouseUser {
|
|
|
113
98
|
}
|
|
114
99
|
|
|
115
100
|
public getUserAccount(): UserAccount {
|
|
116
|
-
return this.accountSubscriber.
|
|
101
|
+
return this.accountSubscriber.getUserAccountAndSlot().data;
|
|
117
102
|
}
|
|
118
103
|
|
|
119
|
-
public
|
|
120
|
-
return this.accountSubscriber.
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
public getUserOrdersAccount(): UserOrdersAccount | undefined {
|
|
124
|
-
return this.accountSubscriber.getUserOrdersAccount();
|
|
104
|
+
public getUserAccountAndSlot(): DataAndSlot<UserAccount> | undefined {
|
|
105
|
+
return this.accountSubscriber.getUserAccountAndSlot();
|
|
125
106
|
}
|
|
126
107
|
|
|
127
108
|
/**
|
|
@@ -130,7 +111,7 @@ export class ClearingHouseUser {
|
|
|
130
111
|
* @returns userPosition
|
|
131
112
|
*/
|
|
132
113
|
public getUserPosition(marketIndex: BN): UserPosition | undefined {
|
|
133
|
-
return this.
|
|
114
|
+
return this.getUserAccount().positions.find((position) =>
|
|
134
115
|
position.marketIndex.eq(marketIndex)
|
|
135
116
|
);
|
|
136
117
|
}
|
|
@@ -141,7 +122,11 @@ export class ClearingHouseUser {
|
|
|
141
122
|
lastCumulativeFundingRate: ZERO,
|
|
142
123
|
marketIndex,
|
|
143
124
|
quoteAssetAmount: ZERO,
|
|
125
|
+
quoteEntryAmount: ZERO,
|
|
144
126
|
openOrders: ZERO,
|
|
127
|
+
unsettledPnl: ZERO,
|
|
128
|
+
openBids: ZERO,
|
|
129
|
+
openAsks: ZERO,
|
|
145
130
|
};
|
|
146
131
|
}
|
|
147
132
|
|
|
@@ -150,7 +135,7 @@ export class ClearingHouseUser {
|
|
|
150
135
|
* @returns Order
|
|
151
136
|
*/
|
|
152
137
|
public getOrder(orderId: BN): Order | undefined {
|
|
153
|
-
return this.
|
|
138
|
+
return this.getUserAccount().orders.find((order) =>
|
|
154
139
|
order.orderId.eq(orderId)
|
|
155
140
|
);
|
|
156
141
|
}
|
|
@@ -160,40 +145,19 @@ export class ClearingHouseUser {
|
|
|
160
145
|
* @returns Order
|
|
161
146
|
*/
|
|
162
147
|
public getOrderByUserOrderId(userOrderId: number): Order | undefined {
|
|
163
|
-
return this.
|
|
148
|
+
return this.getUserAccount().orders.find(
|
|
164
149
|
(order) => order.userOrderId === userOrderId
|
|
165
150
|
);
|
|
166
151
|
}
|
|
167
152
|
|
|
168
|
-
public
|
|
169
|
-
if (this.userAccountPublicKey) {
|
|
170
|
-
return this.userAccountPublicKey;
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
this.userAccountPublicKey = await getUserAccountPublicKey(
|
|
174
|
-
this.clearingHouse.program.programId,
|
|
175
|
-
this.authority
|
|
176
|
-
);
|
|
153
|
+
public getUserAccountPublicKey(): PublicKey {
|
|
177
154
|
return this.userAccountPublicKey;
|
|
178
155
|
}
|
|
179
156
|
|
|
180
|
-
public async getUserOrdersAccountPublicKey(): Promise<PublicKey> {
|
|
181
|
-
if (this.userOrdersAccountPublicKey) {
|
|
182
|
-
return this.userOrdersAccountPublicKey;
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
this.userOrdersAccountPublicKey = await getUserOrdersAccountPublicKey(
|
|
186
|
-
this.clearingHouse.program.programId,
|
|
187
|
-
await this.getUserAccountPublicKey()
|
|
188
|
-
);
|
|
189
|
-
return this.userOrdersAccountPublicKey;
|
|
190
|
-
}
|
|
191
|
-
|
|
192
157
|
public async exists(): Promise<boolean> {
|
|
193
|
-
const userAccountPublicKey = await this.getUserAccountPublicKey();
|
|
194
158
|
const userAccountRPCResponse =
|
|
195
159
|
await this.clearingHouse.connection.getParsedAccountInfo(
|
|
196
|
-
userAccountPublicKey
|
|
160
|
+
this.userAccountPublicKey
|
|
197
161
|
);
|
|
198
162
|
return userAccountRPCResponse.value !== null;
|
|
199
163
|
}
|
|
@@ -220,34 +184,44 @@ export class ClearingHouseUser {
|
|
|
220
184
|
}
|
|
221
185
|
|
|
222
186
|
public getInitialMarginRequirement(): BN {
|
|
223
|
-
return this.
|
|
224
|
-
(marginRequirement, marketPosition) => {
|
|
225
|
-
const market = this.clearingHouse.
|
|
187
|
+
return this.getUserAccount()
|
|
188
|
+
.positions.reduce((marginRequirement, marketPosition) => {
|
|
189
|
+
const market = this.clearingHouse.getMarketAccount(
|
|
190
|
+
marketPosition.marketIndex
|
|
191
|
+
);
|
|
226
192
|
return marginRequirement.add(
|
|
227
|
-
calculateBaseAssetValue(
|
|
193
|
+
calculateBaseAssetValue(
|
|
194
|
+
market,
|
|
195
|
+
marketPosition,
|
|
196
|
+
this.getOracleDataForMarket(market.marketIndex)
|
|
197
|
+
)
|
|
228
198
|
.mul(new BN(market.marginRatioInitial))
|
|
229
199
|
.div(MARGIN_PRECISION)
|
|
230
200
|
);
|
|
231
|
-
},
|
|
232
|
-
|
|
233
|
-
);
|
|
201
|
+
}, ZERO)
|
|
202
|
+
.add(this.getTotalLiability());
|
|
234
203
|
}
|
|
235
204
|
|
|
236
205
|
/**
|
|
237
206
|
* @returns The partial margin requirement in USDC. : QUOTE_PRECISION
|
|
238
207
|
*/
|
|
239
208
|
public getPartialMarginRequirement(): BN {
|
|
240
|
-
return this.
|
|
241
|
-
(marginRequirement, marketPosition) => {
|
|
242
|
-
const market = this.clearingHouse.
|
|
209
|
+
return this.getUserAccount()
|
|
210
|
+
.positions.reduce((marginRequirement, marketPosition) => {
|
|
211
|
+
const market = this.clearingHouse.getMarketAccount(
|
|
212
|
+
marketPosition.marketIndex
|
|
213
|
+
);
|
|
243
214
|
return marginRequirement.add(
|
|
244
|
-
calculateBaseAssetValue(
|
|
215
|
+
calculateBaseAssetValue(
|
|
216
|
+
market,
|
|
217
|
+
marketPosition,
|
|
218
|
+
this.getOracleDataForMarket(market.marketIndex)
|
|
219
|
+
)
|
|
245
220
|
.mul(new BN(market.marginRatioPartial))
|
|
246
221
|
.div(MARGIN_PRECISION)
|
|
247
222
|
);
|
|
248
|
-
},
|
|
249
|
-
|
|
250
|
-
);
|
|
223
|
+
}, ZERO)
|
|
224
|
+
.add(this.getTotalLiability());
|
|
251
225
|
}
|
|
252
226
|
|
|
253
227
|
/**
|
|
@@ -255,42 +229,158 @@ export class ClearingHouseUser {
|
|
|
255
229
|
* @returns : Precision QUOTE_PRECISION
|
|
256
230
|
*/
|
|
257
231
|
public getUnrealizedPNL(withFunding?: boolean, marketIndex?: BN): BN {
|
|
258
|
-
return this.
|
|
232
|
+
return this.getUserAccount()
|
|
259
233
|
.positions.filter((pos) =>
|
|
260
234
|
marketIndex ? pos.marketIndex === marketIndex : true
|
|
261
235
|
)
|
|
262
236
|
.reduce((pnl, marketPosition) => {
|
|
263
|
-
const market = this.clearingHouse.
|
|
237
|
+
const market = this.clearingHouse.getMarketAccount(
|
|
238
|
+
marketPosition.marketIndex
|
|
239
|
+
);
|
|
264
240
|
return pnl.add(
|
|
265
|
-
calculatePositionPNL(
|
|
241
|
+
calculatePositionPNL(
|
|
242
|
+
market,
|
|
243
|
+
marketPosition,
|
|
244
|
+
withFunding,
|
|
245
|
+
this.getOracleDataForMarket(market.marketIndex)
|
|
246
|
+
)
|
|
266
247
|
);
|
|
267
248
|
}, ZERO);
|
|
268
249
|
}
|
|
269
250
|
|
|
251
|
+
/**
|
|
252
|
+
* calculates unrealized position price pnl
|
|
253
|
+
* @returns : Precision QUOTE_PRECISION
|
|
254
|
+
*/
|
|
255
|
+
public getUnsettledPNL(marketIndex?: BN): BN {
|
|
256
|
+
return this.getUserAccount()
|
|
257
|
+
.positions.filter((pos) =>
|
|
258
|
+
marketIndex ? pos.marketIndex === marketIndex : true
|
|
259
|
+
)
|
|
260
|
+
.reduce((pnl, marketPosition) => {
|
|
261
|
+
return pnl.add(marketPosition.unsettledPnl);
|
|
262
|
+
}, ZERO);
|
|
263
|
+
}
|
|
264
|
+
|
|
270
265
|
/**
|
|
271
266
|
* calculates unrealized funding payment pnl
|
|
272
267
|
* @returns : Precision QUOTE_PRECISION
|
|
273
268
|
*/
|
|
274
269
|
public getUnrealizedFundingPNL(marketIndex?: BN): BN {
|
|
275
|
-
return this.
|
|
270
|
+
return this.getUserAccount()
|
|
276
271
|
.positions.filter((pos) =>
|
|
277
272
|
marketIndex ? pos.marketIndex === marketIndex : true
|
|
278
273
|
)
|
|
279
274
|
.reduce((pnl, marketPosition) => {
|
|
280
|
-
const market = this.clearingHouse.
|
|
275
|
+
const market = this.clearingHouse.getMarketAccount(
|
|
276
|
+
marketPosition.marketIndex
|
|
277
|
+
);
|
|
281
278
|
return pnl.add(calculatePositionFundingPNL(market, marketPosition));
|
|
282
279
|
}, ZERO);
|
|
283
280
|
}
|
|
284
281
|
|
|
282
|
+
public getTotalLiability(): BN {
|
|
283
|
+
return this.getUserAccount().bankBalances.reduce(
|
|
284
|
+
(totalAssetValue, bankBalance) => {
|
|
285
|
+
if (
|
|
286
|
+
bankBalance.balance.eq(ZERO) ||
|
|
287
|
+
isVariant(bankBalance.balanceType, 'deposit')
|
|
288
|
+
) {
|
|
289
|
+
return totalAssetValue;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// Todo this needs to account for whether it's based on initial or maintenance requirements
|
|
293
|
+
const bankAccount: BankAccount = this.clearingHouse.getBankAccount(
|
|
294
|
+
bankBalance.bankIndex
|
|
295
|
+
);
|
|
296
|
+
|
|
297
|
+
const tokenAmount = getTokenAmount(
|
|
298
|
+
bankBalance.balance,
|
|
299
|
+
bankAccount,
|
|
300
|
+
bankBalance.balanceType
|
|
301
|
+
);
|
|
302
|
+
return totalAssetValue.add(
|
|
303
|
+
tokenAmount
|
|
304
|
+
.mul(this.getOracleDataForBank(bankAccount.bankIndex).price)
|
|
305
|
+
.mul(bankAccount.initialLiabilityWeight)
|
|
306
|
+
.div(BANK_WEIGHT_PRECISION)
|
|
307
|
+
.div(MARK_PRICE_PRECISION)
|
|
308
|
+
);
|
|
309
|
+
},
|
|
310
|
+
ZERO
|
|
311
|
+
);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
public getCollateralValue(bankIndex?: BN): BN {
|
|
315
|
+
return this.getUserAccount().bankBalances.reduce(
|
|
316
|
+
(totalAssetValue, bankBalance) => {
|
|
317
|
+
if (
|
|
318
|
+
bankBalance.balance.eq(ZERO) ||
|
|
319
|
+
(bankIndex !== undefined && !bankBalance.bankIndex.eq(bankIndex))
|
|
320
|
+
) {
|
|
321
|
+
return totalAssetValue;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// Todo this needs to account for whether it's based on initial or maintenance requirements
|
|
325
|
+
const bankAccount: BankAccount = this.clearingHouse.getBankAccount(
|
|
326
|
+
bankBalance.bankIndex
|
|
327
|
+
);
|
|
328
|
+
|
|
329
|
+
let tokenAmount = getTokenAmount(
|
|
330
|
+
bankBalance.balance,
|
|
331
|
+
bankAccount,
|
|
332
|
+
bankBalance.balanceType
|
|
333
|
+
);
|
|
334
|
+
|
|
335
|
+
if (isVariant(bankBalance.balanceType, 'borrow')) {
|
|
336
|
+
tokenAmount = tokenAmount.mul(new BN(-1));
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
return totalAssetValue.add(
|
|
340
|
+
tokenAmount
|
|
341
|
+
.mul(this.getOracleDataForBank(bankAccount.bankIndex).price)
|
|
342
|
+
.div(MARK_PRICE_PRECISION)
|
|
343
|
+
);
|
|
344
|
+
},
|
|
345
|
+
ZERO
|
|
346
|
+
);
|
|
347
|
+
}
|
|
348
|
+
|
|
285
349
|
/**
|
|
286
350
|
* calculates TotalCollateral: collateral + unrealized pnl
|
|
351
|
+
* TODO: rename to total equity (for perpetuals swaps)
|
|
287
352
|
* @returns : Precision QUOTE_PRECISION
|
|
288
353
|
*/
|
|
289
354
|
public getTotalCollateral(): BN {
|
|
290
|
-
return (
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
355
|
+
return this.getUserAccount()
|
|
356
|
+
.bankBalances.reduce((totalAssetValue, bankBalance) => {
|
|
357
|
+
if (
|
|
358
|
+
bankBalance.balance.eq(ZERO) ||
|
|
359
|
+
isVariant(bankBalance.balanceType, 'borrow')
|
|
360
|
+
) {
|
|
361
|
+
return totalAssetValue;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
// Todo this needs to account for whether it's based on initial or maintenance requirements
|
|
365
|
+
const bankAccount: BankAccount = this.clearingHouse.getBankAccount(
|
|
366
|
+
bankBalance.bankIndex
|
|
367
|
+
);
|
|
368
|
+
|
|
369
|
+
const tokenAmount = getTokenAmount(
|
|
370
|
+
bankBalance.balance,
|
|
371
|
+
bankAccount,
|
|
372
|
+
bankBalance.balanceType
|
|
373
|
+
);
|
|
374
|
+
return totalAssetValue.add(
|
|
375
|
+
tokenAmount
|
|
376
|
+
.mul(this.getOracleDataForBank(bankAccount.bankIndex).price)
|
|
377
|
+
.mul(bankAccount.initialAssetWeight)
|
|
378
|
+
.div(BANK_WEIGHT_PRECISION)
|
|
379
|
+
.div(MARK_PRICE_PRECISION)
|
|
380
|
+
);
|
|
381
|
+
}, ZERO)
|
|
382
|
+
.add(this.getUnrealizedPNL(true))
|
|
383
|
+
.add(this.getUnsettledPNL());
|
|
294
384
|
}
|
|
295
385
|
|
|
296
386
|
/**
|
|
@@ -298,11 +388,17 @@ export class ClearingHouseUser {
|
|
|
298
388
|
* @returns : Precision QUOTE_PRECISION
|
|
299
389
|
*/
|
|
300
390
|
getTotalPositionValue(): BN {
|
|
301
|
-
return this.
|
|
391
|
+
return this.getUserAccount().positions.reduce(
|
|
302
392
|
(positionValue, marketPosition) => {
|
|
303
|
-
const market = this.clearingHouse.
|
|
393
|
+
const market = this.clearingHouse.getMarketAccount(
|
|
394
|
+
marketPosition.marketIndex
|
|
395
|
+
);
|
|
304
396
|
return positionValue.add(
|
|
305
|
-
calculateBaseAssetValue(
|
|
397
|
+
calculateBaseAssetValue(
|
|
398
|
+
market,
|
|
399
|
+
marketPosition,
|
|
400
|
+
this.getOracleDataForMarket(market.marketIndex)
|
|
401
|
+
)
|
|
306
402
|
);
|
|
307
403
|
},
|
|
308
404
|
ZERO
|
|
@@ -313,11 +409,16 @@ export class ClearingHouseUser {
|
|
|
313
409
|
* calculates position value from closing 100%
|
|
314
410
|
* @returns : Precision QUOTE_PRECISION
|
|
315
411
|
*/
|
|
316
|
-
public getPositionValue(
|
|
412
|
+
public getPositionValue(
|
|
413
|
+
marketIndex: BN,
|
|
414
|
+
oraclePriceData: OraclePriceData
|
|
415
|
+
): BN {
|
|
317
416
|
const userPosition =
|
|
318
417
|
this.getUserPosition(marketIndex) || this.getEmptyPosition(marketIndex);
|
|
319
|
-
const market = this.clearingHouse.
|
|
320
|
-
|
|
418
|
+
const market = this.clearingHouse.getMarketAccount(
|
|
419
|
+
userPosition.marketIndex
|
|
420
|
+
);
|
|
421
|
+
return calculateBaseAssetValue(market, userPosition, oraclePriceData);
|
|
321
422
|
}
|
|
322
423
|
|
|
323
424
|
public getPositionSide(
|
|
@@ -340,13 +441,15 @@ export class ClearingHouseUser {
|
|
|
340
441
|
position: UserPosition,
|
|
341
442
|
amountToClose?: BN
|
|
342
443
|
): [BN, BN] {
|
|
343
|
-
const market = this.clearingHouse.
|
|
444
|
+
const market = this.clearingHouse.getMarketAccount(position.marketIndex);
|
|
344
445
|
|
|
345
446
|
const entryPrice = calculateEntryPrice(position);
|
|
346
447
|
|
|
448
|
+
const oraclePriceData = this.getOracleDataForMarket(position.marketIndex);
|
|
449
|
+
|
|
347
450
|
if (amountToClose) {
|
|
348
451
|
if (amountToClose.eq(ZERO)) {
|
|
349
|
-
return [calculateMarkPrice(market), ZERO];
|
|
452
|
+
return [calculateMarkPrice(market, oraclePriceData), ZERO];
|
|
350
453
|
}
|
|
351
454
|
position = {
|
|
352
455
|
baseAssetAmount: amountToClose,
|
|
@@ -356,7 +459,11 @@ export class ClearingHouseUser {
|
|
|
356
459
|
} as UserPosition;
|
|
357
460
|
}
|
|
358
461
|
|
|
359
|
-
const baseAssetValue = calculateBaseAssetValue(
|
|
462
|
+
const baseAssetValue = calculateBaseAssetValue(
|
|
463
|
+
market,
|
|
464
|
+
position,
|
|
465
|
+
oraclePriceData
|
|
466
|
+
);
|
|
360
467
|
if (position.baseAssetAmount.eq(ZERO)) {
|
|
361
468
|
return [ZERO, ZERO];
|
|
362
469
|
}
|
|
@@ -397,7 +504,7 @@ export class ClearingHouseUser {
|
|
|
397
504
|
marketIndex: BN | number,
|
|
398
505
|
category: MarginCategory = 'Initial'
|
|
399
506
|
): BN {
|
|
400
|
-
const market = this.clearingHouse.
|
|
507
|
+
const market = this.clearingHouse.getMarketAccount(marketIndex);
|
|
401
508
|
let marginRatioCategory: number;
|
|
402
509
|
|
|
403
510
|
switch (category) {
|
|
@@ -447,14 +554,14 @@ export class ClearingHouseUser {
|
|
|
447
554
|
* @returns
|
|
448
555
|
*/
|
|
449
556
|
public needsToSettleFundingPayment(): boolean {
|
|
450
|
-
const
|
|
451
|
-
for (const userPosition of this.getUserPositionsAccount().positions) {
|
|
557
|
+
for (const userPosition of this.getUserAccount().positions) {
|
|
452
558
|
if (userPosition.baseAssetAmount.eq(ZERO)) {
|
|
453
559
|
continue;
|
|
454
560
|
}
|
|
455
561
|
|
|
456
|
-
const market =
|
|
457
|
-
|
|
562
|
+
const market = this.clearingHouse.getMarketAccount(
|
|
563
|
+
userPosition.marketIndex
|
|
564
|
+
);
|
|
458
565
|
if (
|
|
459
566
|
market.amm.cumulativeFundingRateLong.eq(
|
|
460
567
|
userPosition.lastCumulativeFundingRate
|
|
@@ -518,18 +625,23 @@ export class ClearingHouseUser {
|
|
|
518
625
|
lastCumulativeFundingRate:
|
|
519
626
|
currentMarketPosition.lastCumulativeFundingRate,
|
|
520
627
|
quoteAssetAmount: new BN(0),
|
|
628
|
+
quoteEntryAmount: new BN(0),
|
|
521
629
|
openOrders: new BN(0),
|
|
630
|
+
unsettledPnl: new BN(0),
|
|
631
|
+
openBids: new BN(0),
|
|
632
|
+
openAsks: new BN(0),
|
|
522
633
|
};
|
|
523
634
|
|
|
524
635
|
if (proposedBaseAssetAmount.eq(ZERO)) return new BN(-1);
|
|
525
636
|
|
|
526
|
-
const market = this.clearingHouse.
|
|
637
|
+
const market = this.clearingHouse.getMarketAccount(
|
|
527
638
|
proposedMarketPosition.marketIndex
|
|
528
639
|
);
|
|
529
640
|
|
|
530
641
|
const proposedMarketPositionValue = calculateBaseAssetValue(
|
|
531
642
|
market,
|
|
532
|
-
proposedMarketPosition
|
|
643
|
+
proposedMarketPosition,
|
|
644
|
+
this.getOracleDataForMarket(market.marketIndex)
|
|
533
645
|
);
|
|
534
646
|
|
|
535
647
|
// total position value after trade
|
|
@@ -537,11 +649,17 @@ export class ClearingHouseUser {
|
|
|
537
649
|
totalPositionValueExcludingTargetMarket.add(proposedMarketPositionValue);
|
|
538
650
|
|
|
539
651
|
const marginRequirementExcludingTargetMarket =
|
|
540
|
-
this.
|
|
652
|
+
this.getUserAccount().positions.reduce(
|
|
541
653
|
(totalMarginRequirement, position) => {
|
|
542
654
|
if (!position.marketIndex.eq(marketPosition.marketIndex)) {
|
|
543
|
-
const market = this.clearingHouse.
|
|
544
|
-
|
|
655
|
+
const market = this.clearingHouse.getMarketAccount(
|
|
656
|
+
position.marketIndex
|
|
657
|
+
);
|
|
658
|
+
const positionValue = calculateBaseAssetValue(
|
|
659
|
+
market,
|
|
660
|
+
position,
|
|
661
|
+
this.getOracleDataForMarket(market.marketIndex)
|
|
662
|
+
);
|
|
545
663
|
const marketMarginRequirement = positionValue
|
|
546
664
|
.mul(
|
|
547
665
|
partial
|
|
@@ -608,7 +726,8 @@ export class ClearingHouseUser {
|
|
|
608
726
|
let markPriceAfterTrade;
|
|
609
727
|
if (positionBaseSizeChange.eq(ZERO)) {
|
|
610
728
|
markPriceAfterTrade = calculateMarkPrice(
|
|
611
|
-
this.clearingHouse.
|
|
729
|
+
this.clearingHouse.getMarketAccount(marketPosition.marketIndex),
|
|
730
|
+
this.getOracleDataForMarket(marketPosition.marketIndex)
|
|
612
731
|
);
|
|
613
732
|
} else {
|
|
614
733
|
const direction = positionBaseSizeChange.gt(ZERO)
|
|
@@ -617,8 +736,9 @@ export class ClearingHouseUser {
|
|
|
617
736
|
markPriceAfterTrade = calculateTradeSlippage(
|
|
618
737
|
direction,
|
|
619
738
|
positionBaseSizeChange.abs(),
|
|
620
|
-
this.clearingHouse.
|
|
621
|
-
'base'
|
|
739
|
+
this.clearingHouse.getMarketAccount(marketPosition.marketIndex),
|
|
740
|
+
'base',
|
|
741
|
+
this.getOracleDataForMarket(marketPosition.marketIndex)
|
|
622
742
|
)[3]; // newPrice after swap
|
|
623
743
|
}
|
|
624
744
|
|
|
@@ -657,7 +777,8 @@ export class ClearingHouseUser {
|
|
|
657
777
|
{
|
|
658
778
|
marketIndex: positionMarketIndex,
|
|
659
779
|
},
|
|
660
|
-
closeBaseAmount
|
|
780
|
+
closeBaseAmount,
|
|
781
|
+
true
|
|
661
782
|
);
|
|
662
783
|
}
|
|
663
784
|
|
|
@@ -700,10 +821,12 @@ export class ClearingHouseUser {
|
|
|
700
821
|
? true
|
|
701
822
|
: targetSide === currentPositionSide;
|
|
702
823
|
|
|
824
|
+
const oracleData = this.getOracleDataForMarket(targetMarketIndex);
|
|
825
|
+
|
|
703
826
|
// add any position we have on the opposite side of the current trade, because we can "flip" the size of this position without taking any extra leverage.
|
|
704
827
|
const oppositeSizeValueUSDC = targetingSameSide
|
|
705
828
|
? ZERO
|
|
706
|
-
: this.getPositionValue(targetMarketIndex);
|
|
829
|
+
: this.getPositionValue(targetMarketIndex, oracleData);
|
|
707
830
|
|
|
708
831
|
let maxPositionSize = this.getBuyingPower(targetMarketIndex);
|
|
709
832
|
if (maxPositionSize.gte(ZERO)) {
|
|
@@ -720,8 +843,11 @@ export class ClearingHouseUser {
|
|
|
720
843
|
// current leverage is greater than max leverage - can only reduce position size
|
|
721
844
|
|
|
722
845
|
if (!targetingSameSide) {
|
|
723
|
-
const market = this.clearingHouse.
|
|
724
|
-
const marketPositionValue = this.getPositionValue(
|
|
846
|
+
const market = this.clearingHouse.getMarketAccount(targetMarketIndex);
|
|
847
|
+
const marketPositionValue = this.getPositionValue(
|
|
848
|
+
targetMarketIndex,
|
|
849
|
+
oracleData
|
|
850
|
+
);
|
|
725
851
|
const totalCollateral = this.getTotalCollateral();
|
|
726
852
|
const marginRequirement = this.getInitialMarginRequirement();
|
|
727
853
|
const marginFreedByClosing = marketPositionValue
|
|
@@ -770,7 +896,12 @@ export class ClearingHouseUser {
|
|
|
770
896
|
this.getUserPosition(targetMarketIndex) ||
|
|
771
897
|
this.getEmptyPosition(targetMarketIndex);
|
|
772
898
|
|
|
773
|
-
|
|
899
|
+
const oracleData = this.getOracleDataForMarket(targetMarketIndex);
|
|
900
|
+
|
|
901
|
+
let currentPositionQuoteAmount = this.getPositionValue(
|
|
902
|
+
targetMarketIndex,
|
|
903
|
+
oracleData
|
|
904
|
+
);
|
|
774
905
|
|
|
775
906
|
const currentSide =
|
|
776
907
|
currentPosition && currentPosition.baseAssetAmount.isNeg()
|
|
@@ -826,11 +957,33 @@ export class ClearingHouseUser {
|
|
|
826
957
|
this.getUserPosition(marketToIgnore) ||
|
|
827
958
|
this.getEmptyPosition(marketToIgnore);
|
|
828
959
|
|
|
960
|
+
const oracleData = this.getOracleDataForMarket(marketToIgnore);
|
|
961
|
+
|
|
829
962
|
let currentMarketPositionValueUSDC = ZERO;
|
|
830
963
|
if (currentMarketPosition) {
|
|
831
|
-
currentMarketPositionValueUSDC = this.getPositionValue(
|
|
964
|
+
currentMarketPositionValueUSDC = this.getPositionValue(
|
|
965
|
+
marketToIgnore,
|
|
966
|
+
oracleData
|
|
967
|
+
);
|
|
832
968
|
}
|
|
833
969
|
|
|
834
970
|
return this.getTotalPositionValue().sub(currentMarketPositionValueUSDC);
|
|
835
971
|
}
|
|
972
|
+
|
|
973
|
+
private getOracleDataForMarket(marketIndex: BN): OraclePriceData {
|
|
974
|
+
const oracleKey =
|
|
975
|
+
this.clearingHouse.getMarketAccount(marketIndex).amm.oracle;
|
|
976
|
+
const oracleData =
|
|
977
|
+
this.clearingHouse.getOraclePriceDataAndSlot(oracleKey).data;
|
|
978
|
+
|
|
979
|
+
return oracleData;
|
|
980
|
+
}
|
|
981
|
+
private getOracleDataForBank(bankIndex: BN): OraclePriceData {
|
|
982
|
+
const oracleKey = this.clearingHouse.getBankAccount(bankIndex).oracle;
|
|
983
|
+
|
|
984
|
+
const oracleData =
|
|
985
|
+
this.clearingHouse.getOraclePriceDataAndSlot(oracleKey).data;
|
|
986
|
+
|
|
987
|
+
return oracleData;
|
|
988
|
+
}
|
|
836
989
|
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { ClearingHouse } from './clearingHouse';
|
|
2
|
+
import { PublicKey } from '@solana/web3.js';
|
|
3
|
+
import { BulkAccountLoader } from './accounts/bulkAccountLoader';
|
|
4
|
+
|
|
5
|
+
export type ClearingHouseUserConfig = {
|
|
6
|
+
accountSubscription?: ClearingHouseUserAccountSubscriptionConfig;
|
|
7
|
+
clearingHouse: ClearingHouse;
|
|
8
|
+
userAccountPublicKey: PublicKey;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export type ClearingHouseUserAccountSubscriptionConfig =
|
|
12
|
+
| {
|
|
13
|
+
type: 'websocket';
|
|
14
|
+
}
|
|
15
|
+
| {
|
|
16
|
+
type: 'polling';
|
|
17
|
+
accountLoader: BulkAccountLoader;
|
|
18
|
+
};
|