@drift-labs/sdk 0.2.0-master.24 → 0.2.0-master.26
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/pollingClearingHouseAccountSubscriber.d.ts +13 -13
- package/lib/accounts/pollingClearingHouseAccountSubscriber.js +27 -27
- package/lib/accounts/types.d.ts +8 -9
- package/lib/accounts/webSocketClearingHouseAccountSubscriber.d.ts +14 -14
- package/lib/accounts/webSocketClearingHouseAccountSubscriber.js +35 -34
- package/lib/addresses/pda.d.ts +8 -6
- package/lib/addresses/pda.js +35 -27
- package/lib/admin.d.ts +9 -6
- package/lib/admin.js +90 -54
- package/lib/clearingHouse.d.ts +71 -42
- package/lib/clearingHouse.js +765 -282
- package/lib/clearingHouseConfig.d.ts +2 -2
- package/lib/clearingHouseUser.d.ts +19 -17
- package/lib/clearingHouseUser.js +145 -123
- package/lib/config.d.ts +7 -7
- package/lib/config.js +21 -21
- package/lib/constants/numericConstants.d.ts +12 -12
- package/lib/constants/numericConstants.js +13 -13
- package/lib/constants/{markets.d.ts → perpMarkets.d.ts} +5 -5
- package/{src/constants/markets.js → lib/constants/perpMarkets.js} +4 -4
- package/lib/constants/{banks.d.ts → spotMarkets.d.ts} +6 -6
- package/lib/constants/{banks.js → spotMarkets.js} +16 -16
- package/lib/events/eventSubscriber.d.ts +4 -2
- package/lib/events/eventSubscriber.js +16 -9
- package/lib/events/fetchLogs.d.ts +10 -1
- package/lib/events/fetchLogs.js +27 -7
- package/lib/events/pollingLogProvider.d.ts +2 -1
- package/lib/events/pollingLogProvider.js +6 -2
- package/lib/events/types.d.ts +4 -2
- package/lib/events/types.js +2 -0
- package/lib/examples/makeTradeExample.js +18 -6
- package/lib/idl/clearing_house.json +1128 -347
- package/lib/index.d.ts +6 -3
- package/lib/index.js +6 -3
- package/lib/math/amm.d.ts +5 -3
- package/lib/math/amm.js +42 -4
- package/lib/math/funding.d.ts +6 -6
- package/lib/math/funding.js +2 -1
- package/lib/math/margin.d.ts +4 -4
- package/lib/math/margin.js +18 -11
- package/lib/math/market.d.ts +10 -9
- package/lib/math/market.js +29 -6
- package/lib/math/oracles.d.ts +2 -1
- package/lib/math/oracles.js +11 -1
- package/lib/math/orders.d.ts +5 -5
- package/lib/math/position.d.ts +13 -13
- package/lib/math/position.js +19 -19
- package/lib/math/spotBalance.d.ts +19 -0
- package/lib/math/spotBalance.js +176 -0
- package/lib/math/spotMarket.d.ts +4 -0
- package/lib/math/spotMarket.js +8 -0
- package/lib/math/spotPosition.d.ts +2 -0
- package/lib/math/spotPosition.js +8 -0
- package/lib/math/state.js +2 -2
- package/lib/math/trade.d.ts +4 -4
- package/lib/orderParams.d.ts +4 -4
- package/lib/orderParams.js +12 -4
- package/lib/serum/serumSubscriber.d.ts +23 -0
- package/lib/serum/serumSubscriber.js +41 -0
- package/lib/serum/types.d.ts +11 -0
- package/lib/serum/types.js +2 -0
- package/lib/tx/retryTxSender.d.ts +1 -1
- package/lib/tx/retryTxSender.js +4 -2
- package/lib/tx/types.d.ts +1 -1
- package/lib/types.d.ts +148 -39
- package/lib/types.js +37 -9
- package/my-script/.env +7 -0
- package/my-script/getUserStats.ts +106 -0
- package/my-script/multiConnections.ts +119 -0
- package/my-script/test-regex.ts +11 -0
- package/my-script/utils.ts +52 -0
- package/package.json +1 -1
- package/src/accounts/bulkAccountLoader.js +249 -0
- package/src/accounts/bulkUserStatsSubscription.js +75 -0
- package/src/accounts/bulkUserSubscription.js +75 -0
- package/src/accounts/fetch.js +92 -0
- package/src/accounts/pollingClearingHouseAccountSubscriber.js +465 -0
- package/src/accounts/pollingClearingHouseAccountSubscriber.ts +38 -38
- package/src/accounts/pollingOracleSubscriber.js +156 -0
- package/src/accounts/pollingTokenAccountSubscriber.js +141 -0
- package/src/accounts/pollingUserAccountSubscriber.js +208 -0
- package/src/accounts/pollingUserStatsAccountSubscriber.js +208 -0
- package/src/accounts/types.js +28 -0
- package/src/accounts/types.ts +11 -9
- package/src/accounts/utils.js +7 -0
- package/src/accounts/webSocketAccountSubscriber.js +138 -0
- package/src/accounts/webSocketClearingHouseAccountSubscriber.js +433 -0
- package/src/accounts/webSocketClearingHouseAccountSubscriber.ts +59 -52
- package/src/accounts/webSocketUserAccountSubscriber.js +113 -0
- package/src/accounts/webSocketUserStatsAccountSubsriber.js +113 -0
- package/src/addresses/pda.js +186 -0
- package/src/addresses/pda.ts +56 -42
- package/src/admin.js +1284 -0
- package/src/admin.ts +149 -75
- package/src/assert/assert.js +1 -1
- package/src/clearingHouse.js +3433 -0
- package/src/clearingHouse.ts +1097 -380
- package/src/clearingHouseConfig.js +2 -0
- package/src/clearingHouseConfig.ts +2 -2
- package/src/clearingHouseUser.js +874 -0
- package/src/clearingHouseUser.ts +237 -172
- package/src/clearingHouseUserConfig.js +2 -0
- package/src/clearingHouseUserStats.js +115 -0
- package/src/clearingHouseUserStatsConfig.js +2 -0
- package/src/config.js +80 -0
- package/src/config.ts +30 -30
- package/src/constants/numericConstants.js +18 -11
- package/src/constants/numericConstants.ts +17 -15
- package/{lib/constants/markets.js → src/constants/perpMarkets.js} +11 -11
- package/src/constants/{markets.ts → perpMarkets.ts} +5 -5
- package/src/constants/spotMarkets.js +51 -0
- package/src/constants/{banks.ts → spotMarkets.ts} +19 -19
- package/src/events/eventList.js +66 -23
- package/src/events/eventSubscriber.js +202 -0
- package/src/events/eventSubscriber.ts +20 -12
- package/src/events/fetchLogs.js +117 -0
- package/src/events/fetchLogs.ts +35 -8
- package/src/events/pollingLogProvider.js +113 -0
- package/src/events/pollingLogProvider.ts +10 -2
- package/src/events/sort.js +41 -0
- package/src/events/txEventCache.js +22 -19
- package/src/events/types.js +25 -0
- package/src/events/types.ts +7 -1
- package/src/events/webSocketLogProvider.js +76 -0
- package/src/examples/makeTradeExample.ts +27 -6
- package/src/factory/bigNum.js +183 -180
- package/src/factory/oracleClient.js +9 -9
- package/src/idl/clearing_house.json +1128 -347
- package/src/index.js +75 -0
- package/src/index.ts +6 -3
- package/src/math/amm.js +422 -0
- package/src/math/amm.ts +73 -5
- package/src/math/auction.js +10 -10
- package/src/math/conversion.js +4 -3
- package/src/math/funding.js +223 -175
- package/src/math/funding.ts +7 -7
- package/src/math/insurance.js +27 -0
- package/src/math/margin.js +77 -0
- package/src/math/margin.ts +34 -23
- package/src/math/market.js +105 -0
- package/src/math/market.ts +71 -19
- package/src/math/oracles.js +40 -10
- package/src/math/oracles.ts +18 -1
- package/src/math/orders.js +153 -0
- package/src/math/orders.ts +5 -5
- package/src/math/position.js +172 -0
- package/src/math/position.ts +31 -31
- package/src/math/repeg.js +40 -40
- package/src/math/spotBalance.js +176 -0
- package/src/math/spotBalance.ts +290 -0
- package/src/math/spotMarket.js +8 -0
- package/src/math/spotMarket.ts +9 -0
- package/src/math/spotPosition.js +8 -0
- package/src/math/spotPosition.ts +6 -0
- package/src/math/state.ts +2 -2
- package/src/math/trade.js +81 -74
- package/src/math/trade.ts +4 -4
- package/src/math/utils.js +8 -7
- package/src/oracles/oracleClientCache.js +10 -9
- package/src/oracles/pythClient.js +52 -17
- package/src/oracles/quoteAssetOracleClient.js +44 -13
- package/src/oracles/switchboardClient.js +69 -37
- package/src/oracles/types.js +1 -1
- package/src/orderParams.js +14 -6
- package/src/orderParams.ts +16 -8
- package/src/serum/serumSubscriber.js +102 -0
- package/src/serum/serumSubscriber.ts +80 -0
- package/src/serum/types.js +2 -0
- package/src/serum/types.ts +13 -0
- package/src/slot/SlotSubscriber.js +67 -20
- package/src/token/index.js +4 -4
- package/src/tokenFaucet.js +288 -154
- package/src/tx/retryTxSender.js +280 -0
- package/src/tx/retryTxSender.ts +5 -2
- package/src/tx/types.js +1 -1
- package/src/tx/types.ts +2 -1
- package/src/tx/utils.js +7 -6
- package/src/types.js +216 -0
- package/src/types.ts +131 -39
- package/src/userName.js +5 -5
- package/src/util/computeUnits.js +46 -11
- package/src/util/promiseTimeout.js +5 -5
- package/src/util/tps.js +46 -12
- package/src/wallet.js +55 -18
- package/lib/math/bankBalance.d.ts +0 -15
- package/lib/math/bankBalance.js +0 -150
- package/src/addresses/marketAddresses.js +0 -26
- package/src/constants/banks.js +0 -42
- package/src/examples/makeTradeExample.js +0 -80
- package/src/math/bankBalance.ts +0 -258
- package/src/math/state.js +0 -15
- package/src/math/utils.js.map +0 -1
- package/src/util/getTokenAddress.js +0 -9
|
@@ -0,0 +1,874 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
12
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
13
|
+
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
14
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
15
|
+
function step(op) {
|
|
16
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
17
|
+
while (_) try {
|
|
18
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
19
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
20
|
+
switch (op[0]) {
|
|
21
|
+
case 0: case 1: t = op; break;
|
|
22
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
23
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
24
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
25
|
+
default:
|
|
26
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
27
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
28
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
29
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
30
|
+
if (t[2]) _.ops.pop();
|
|
31
|
+
_.trys.pop(); continue;
|
|
32
|
+
}
|
|
33
|
+
op = body.call(thisArg, _);
|
|
34
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
35
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
exports.__esModule = true;
|
|
39
|
+
exports.ClearingHouseUser = void 0;
|
|
40
|
+
var types_1 = require("./types");
|
|
41
|
+
var position_1 = require("./math/position");
|
|
42
|
+
var numericConstants_1 = require("./constants/numericConstants");
|
|
43
|
+
var _1 = require(".");
|
|
44
|
+
var spotBalance_1 = require("./math/spotBalance");
|
|
45
|
+
var margin_1 = require("./math/margin");
|
|
46
|
+
var pollingUserAccountSubscriber_1 = require("./accounts/pollingUserAccountSubscriber");
|
|
47
|
+
var webSocketUserAccountSubscriber_1 = require("./accounts/webSocketUserAccountSubscriber");
|
|
48
|
+
var ClearingHouseUser = /** @class */ (function () {
|
|
49
|
+
function ClearingHouseUser(config) {
|
|
50
|
+
var _a;
|
|
51
|
+
this._isSubscribed = false;
|
|
52
|
+
this.clearingHouse = config.clearingHouse;
|
|
53
|
+
this.userAccountPublicKey = config.userAccountPublicKey;
|
|
54
|
+
if (((_a = config.accountSubscription) === null || _a === void 0 ? void 0 : _a.type) === 'polling') {
|
|
55
|
+
this.accountSubscriber = new pollingUserAccountSubscriber_1.PollingUserAccountSubscriber(config.clearingHouse.program, config.userAccountPublicKey, config.accountSubscription.accountLoader);
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
this.accountSubscriber = new webSocketUserAccountSubscriber_1.WebSocketUserAccountSubscriber(config.clearingHouse.program, config.userAccountPublicKey);
|
|
59
|
+
}
|
|
60
|
+
this.eventEmitter = this.accountSubscriber.eventEmitter;
|
|
61
|
+
}
|
|
62
|
+
Object.defineProperty(ClearingHouseUser.prototype, "isSubscribed", {
|
|
63
|
+
get: function () {
|
|
64
|
+
return this._isSubscribed && this.accountSubscriber.isSubscribed;
|
|
65
|
+
},
|
|
66
|
+
set: function (val) {
|
|
67
|
+
this._isSubscribed = val;
|
|
68
|
+
},
|
|
69
|
+
enumerable: false,
|
|
70
|
+
configurable: true
|
|
71
|
+
});
|
|
72
|
+
/**
|
|
73
|
+
* Subscribe to ClearingHouseUser state accounts
|
|
74
|
+
* @returns SusbcriptionSuccess result
|
|
75
|
+
*/
|
|
76
|
+
ClearingHouseUser.prototype.subscribe = function () {
|
|
77
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
78
|
+
var _a;
|
|
79
|
+
return __generator(this, function (_b) {
|
|
80
|
+
switch (_b.label) {
|
|
81
|
+
case 0:
|
|
82
|
+
_a = this;
|
|
83
|
+
return [4 /*yield*/, this.accountSubscriber.subscribe()];
|
|
84
|
+
case 1:
|
|
85
|
+
_a.isSubscribed = _b.sent();
|
|
86
|
+
return [2 /*return*/, this.isSubscribed];
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
};
|
|
91
|
+
/**
|
|
92
|
+
* Forces the accountSubscriber to fetch account updates from rpc
|
|
93
|
+
*/
|
|
94
|
+
ClearingHouseUser.prototype.fetchAccounts = function () {
|
|
95
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
96
|
+
return __generator(this, function (_a) {
|
|
97
|
+
switch (_a.label) {
|
|
98
|
+
case 0: return [4 /*yield*/, this.accountSubscriber.fetch()];
|
|
99
|
+
case 1:
|
|
100
|
+
_a.sent();
|
|
101
|
+
return [2 /*return*/];
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
};
|
|
106
|
+
ClearingHouseUser.prototype.unsubscribe = function () {
|
|
107
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
108
|
+
return __generator(this, function (_a) {
|
|
109
|
+
switch (_a.label) {
|
|
110
|
+
case 0: return [4 /*yield*/, this.accountSubscriber.unsubscribe()];
|
|
111
|
+
case 1:
|
|
112
|
+
_a.sent();
|
|
113
|
+
this.isSubscribed = false;
|
|
114
|
+
return [2 /*return*/];
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
};
|
|
119
|
+
ClearingHouseUser.prototype.getUserAccount = function () {
|
|
120
|
+
return this.accountSubscriber.getUserAccountAndSlot().data;
|
|
121
|
+
};
|
|
122
|
+
ClearingHouseUser.prototype.getUserAccountAndSlot = function () {
|
|
123
|
+
return this.accountSubscriber.getUserAccountAndSlot();
|
|
124
|
+
};
|
|
125
|
+
/**
|
|
126
|
+
* Gets the user's current position for a given market. If the user has no position returns undefined
|
|
127
|
+
* @param marketIndex
|
|
128
|
+
* @returns userPosition
|
|
129
|
+
*/
|
|
130
|
+
ClearingHouseUser.prototype.getUserPosition = function (marketIndex) {
|
|
131
|
+
return this.getUserAccount().perpPositions.find(function (position) {
|
|
132
|
+
return position.marketIndex.eq(marketIndex);
|
|
133
|
+
});
|
|
134
|
+
};
|
|
135
|
+
ClearingHouseUser.prototype.getEmptyPosition = function (marketIndex) {
|
|
136
|
+
return {
|
|
137
|
+
baseAssetAmount: numericConstants_1.ZERO,
|
|
138
|
+
remainderBaseAssetAmount: numericConstants_1.ZERO,
|
|
139
|
+
lastCumulativeFundingRate: numericConstants_1.ZERO,
|
|
140
|
+
marketIndex: marketIndex,
|
|
141
|
+
quoteAssetAmount: numericConstants_1.ZERO,
|
|
142
|
+
quoteEntryAmount: numericConstants_1.ZERO,
|
|
143
|
+
openOrders: numericConstants_1.ZERO,
|
|
144
|
+
openBids: numericConstants_1.ZERO,
|
|
145
|
+
openAsks: numericConstants_1.ZERO,
|
|
146
|
+
realizedPnl: numericConstants_1.ZERO,
|
|
147
|
+
lpShares: numericConstants_1.ZERO,
|
|
148
|
+
lastFeePerLp: numericConstants_1.ZERO,
|
|
149
|
+
lastNetBaseAssetAmountPerLp: numericConstants_1.ZERO,
|
|
150
|
+
lastNetQuoteAssetAmountPerLp: numericConstants_1.ZERO
|
|
151
|
+
};
|
|
152
|
+
};
|
|
153
|
+
ClearingHouseUser.prototype.getClonedPosition = function (position) {
|
|
154
|
+
var clonedPosition = Object.assign({}, position);
|
|
155
|
+
return clonedPosition;
|
|
156
|
+
};
|
|
157
|
+
/**
|
|
158
|
+
* @param orderId
|
|
159
|
+
* @returns Order
|
|
160
|
+
*/
|
|
161
|
+
ClearingHouseUser.prototype.getOrder = function (orderId) {
|
|
162
|
+
return this.getUserAccount().orders.find(function (order) {
|
|
163
|
+
return order.orderId.eq(orderId);
|
|
164
|
+
});
|
|
165
|
+
};
|
|
166
|
+
/**
|
|
167
|
+
* @param userOrderId
|
|
168
|
+
* @returns Order
|
|
169
|
+
*/
|
|
170
|
+
ClearingHouseUser.prototype.getOrderByUserOrderId = function (userOrderId) {
|
|
171
|
+
return this.getUserAccount().orders.find(function (order) { return order.userOrderId === userOrderId; });
|
|
172
|
+
};
|
|
173
|
+
ClearingHouseUser.prototype.getUserAccountPublicKey = function () {
|
|
174
|
+
return this.userAccountPublicKey;
|
|
175
|
+
};
|
|
176
|
+
ClearingHouseUser.prototype.exists = function () {
|
|
177
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
178
|
+
var userAccountRPCResponse;
|
|
179
|
+
return __generator(this, function (_a) {
|
|
180
|
+
switch (_a.label) {
|
|
181
|
+
case 0: return [4 /*yield*/, this.clearingHouse.connection.getParsedAccountInfo(this.userAccountPublicKey)];
|
|
182
|
+
case 1:
|
|
183
|
+
userAccountRPCResponse = _a.sent();
|
|
184
|
+
return [2 /*return*/, userAccountRPCResponse.value !== null];
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
};
|
|
189
|
+
/**
|
|
190
|
+
* calculates the market position if the lp position was settled
|
|
191
|
+
* @returns : the settled userPosition
|
|
192
|
+
* @returns : the dust base asset amount (ie, < stepsize)
|
|
193
|
+
* @returns : pnl from settle
|
|
194
|
+
*/
|
|
195
|
+
ClearingHouseUser.prototype.getSettledLPPosition = function (marketIndex) {
|
|
196
|
+
var _position = this.getUserPosition(marketIndex);
|
|
197
|
+
var position = this.getClonedPosition(_position);
|
|
198
|
+
var market = this.clearingHouse.getPerpMarketAccount(position.marketIndex);
|
|
199
|
+
var nShares = position.lpShares;
|
|
200
|
+
var deltaBaa = market.amm.marketPositionPerLp.baseAssetAmount
|
|
201
|
+
.sub(position.lastNetBaseAssetAmountPerLp)
|
|
202
|
+
.mul(nShares)
|
|
203
|
+
.div(numericConstants_1.AMM_RESERVE_PRECISION);
|
|
204
|
+
var deltaQaa = market.amm.marketPositionPerLp.quoteAssetAmount
|
|
205
|
+
.sub(position.lastNetQuoteAssetAmountPerLp)
|
|
206
|
+
.mul(nShares)
|
|
207
|
+
.div(numericConstants_1.AMM_RESERVE_PRECISION);
|
|
208
|
+
function sign(v) {
|
|
209
|
+
var sign = { "true": new _1.BN(1), "false": new _1.BN(-1) }[v.gte(numericConstants_1.ZERO).toString()];
|
|
210
|
+
return sign;
|
|
211
|
+
}
|
|
212
|
+
function standardize(amount, stepsize) {
|
|
213
|
+
var remainder = amount.abs().mod(stepsize).mul(sign(amount));
|
|
214
|
+
var standardizedAmount = amount.sub(remainder);
|
|
215
|
+
return [standardizedAmount, remainder];
|
|
216
|
+
}
|
|
217
|
+
var _a = standardize(deltaBaa, market.amm.baseAssetAmountStepSize), standardizedBaa = _a[0], remainderBaa = _a[1];
|
|
218
|
+
position.remainderBaseAssetAmount =
|
|
219
|
+
position.remainderBaseAssetAmount.add(remainderBaa);
|
|
220
|
+
if (position.remainderBaseAssetAmount
|
|
221
|
+
.abs()
|
|
222
|
+
.gte(market.amm.baseAssetAmountStepSize)) {
|
|
223
|
+
var _b = standardize(position.remainderBaseAssetAmount, market.amm.baseAssetAmountStepSize), newStandardizedBaa = _b[0], newRemainderBaa = _b[1];
|
|
224
|
+
position.baseAssetAmount =
|
|
225
|
+
position.baseAssetAmount.add(newStandardizedBaa);
|
|
226
|
+
position.remainderBaseAssetAmount = newRemainderBaa;
|
|
227
|
+
}
|
|
228
|
+
var updateType;
|
|
229
|
+
if (position.baseAssetAmount.eq(numericConstants_1.ZERO)) {
|
|
230
|
+
updateType = 'open';
|
|
231
|
+
}
|
|
232
|
+
else if (sign(position.baseAssetAmount).eq(sign(deltaBaa))) {
|
|
233
|
+
updateType = 'increase';
|
|
234
|
+
}
|
|
235
|
+
else if (position.baseAssetAmount.abs().gt(deltaBaa.abs())) {
|
|
236
|
+
updateType = 'reduce';
|
|
237
|
+
}
|
|
238
|
+
else if (position.baseAssetAmount.abs().eq(deltaBaa.abs())) {
|
|
239
|
+
updateType = 'close';
|
|
240
|
+
}
|
|
241
|
+
else {
|
|
242
|
+
updateType = 'flip';
|
|
243
|
+
}
|
|
244
|
+
var newQuoteEntry;
|
|
245
|
+
var pnl;
|
|
246
|
+
if (updateType == 'open' || updateType == 'increase') {
|
|
247
|
+
newQuoteEntry = position.quoteEntryAmount.add(deltaQaa);
|
|
248
|
+
pnl = 0;
|
|
249
|
+
}
|
|
250
|
+
else if (updateType == 'reduce' || updateType == 'close') {
|
|
251
|
+
newQuoteEntry = position.quoteEntryAmount.sub(position.quoteEntryAmount
|
|
252
|
+
.mul(deltaBaa.abs())
|
|
253
|
+
.div(position.baseAssetAmount.abs()));
|
|
254
|
+
pnl = position.quoteEntryAmount.sub(newQuoteEntry).add(deltaQaa);
|
|
255
|
+
}
|
|
256
|
+
else {
|
|
257
|
+
newQuoteEntry = deltaQaa.sub(deltaQaa.mul(position.baseAssetAmount.abs()).div(deltaBaa.abs()));
|
|
258
|
+
pnl = position.quoteEntryAmount.add(deltaQaa.sub(newQuoteEntry));
|
|
259
|
+
}
|
|
260
|
+
position.quoteEntryAmount = newQuoteEntry;
|
|
261
|
+
position.baseAssetAmount = position.baseAssetAmount.add(standardizedBaa);
|
|
262
|
+
position.quoteAssetAmount = position.quoteAssetAmount.add(deltaQaa);
|
|
263
|
+
if (position.baseAssetAmount.gt(numericConstants_1.ZERO)) {
|
|
264
|
+
position.lastCumulativeFundingRate = market.amm.cumulativeFundingRateLong;
|
|
265
|
+
}
|
|
266
|
+
else if (position.baseAssetAmount.lt(numericConstants_1.ZERO)) {
|
|
267
|
+
position.lastCumulativeFundingRate =
|
|
268
|
+
market.amm.cumulativeFundingRateShort;
|
|
269
|
+
}
|
|
270
|
+
else {
|
|
271
|
+
position.lastCumulativeFundingRate = numericConstants_1.ZERO;
|
|
272
|
+
}
|
|
273
|
+
return [position, remainderBaa, pnl];
|
|
274
|
+
};
|
|
275
|
+
/**
|
|
276
|
+
* calculates Buying Power = FC * MAX_LEVERAGE
|
|
277
|
+
* @returns : Precision QUOTE_PRECISION
|
|
278
|
+
*/
|
|
279
|
+
ClearingHouseUser.prototype.getBuyingPower = function (marketIndex) {
|
|
280
|
+
return this.getFreeCollateral()
|
|
281
|
+
.mul(this.getMaxLeverage(marketIndex, 'Initial'))
|
|
282
|
+
.div(numericConstants_1.TEN_THOUSAND);
|
|
283
|
+
};
|
|
284
|
+
/**
|
|
285
|
+
* calculates Free Collateral = Total collateral - initial margin requirement
|
|
286
|
+
* @returns : Precision QUOTE_PRECISION
|
|
287
|
+
*/
|
|
288
|
+
ClearingHouseUser.prototype.getFreeCollateral = function () {
|
|
289
|
+
var totalCollateral = this.getTotalCollateral();
|
|
290
|
+
var initialMarginRequirement = this.getInitialMarginRequirement();
|
|
291
|
+
var freeCollateral = totalCollateral.sub(initialMarginRequirement);
|
|
292
|
+
return freeCollateral.gte(numericConstants_1.ZERO) ? freeCollateral : numericConstants_1.ZERO;
|
|
293
|
+
};
|
|
294
|
+
/**
|
|
295
|
+
* @returns The margin requirement of a certain type (Initial or Maintenance) in USDC. : QUOTE_PRECISION
|
|
296
|
+
*/
|
|
297
|
+
ClearingHouseUser.prototype.getMarginRequirement = function (type) {
|
|
298
|
+
var _this = this;
|
|
299
|
+
return this.getUserAccount()
|
|
300
|
+
.perpPositions.reduce(function (marginRequirement, perpPosition) {
|
|
301
|
+
var market = _this.clearingHouse.getPerpMarketAccount(perpPosition.marketIndex);
|
|
302
|
+
if (perpPosition.lpShares.gt(numericConstants_1.ZERO)) {
|
|
303
|
+
// is an lp
|
|
304
|
+
// clone so we dont mutate the position
|
|
305
|
+
perpPosition = _this.getClonedPosition(perpPosition);
|
|
306
|
+
// settle position
|
|
307
|
+
var _a = _this.getSettledLPPosition(market.marketIndex), settledPosition = _a[0], dustBaa = _a[1], _2 = _a[2];
|
|
308
|
+
perpPosition.baseAssetAmount =
|
|
309
|
+
settledPosition.baseAssetAmount.add(dustBaa);
|
|
310
|
+
perpPosition.quoteAssetAmount = settledPosition.quoteAssetAmount;
|
|
311
|
+
// open orders
|
|
312
|
+
var openAsks = void 0;
|
|
313
|
+
if (market.amm.maxBaseAssetReserve > market.amm.baseAssetReserve) {
|
|
314
|
+
openAsks = market.amm.maxBaseAssetReserve
|
|
315
|
+
.sub(market.amm.baseAssetReserve)
|
|
316
|
+
.mul(perpPosition.lpShares)
|
|
317
|
+
.div(market.amm.sqrtK)
|
|
318
|
+
.mul(new _1.BN(-1));
|
|
319
|
+
}
|
|
320
|
+
else {
|
|
321
|
+
openAsks = numericConstants_1.ZERO;
|
|
322
|
+
}
|
|
323
|
+
var openBids = void 0;
|
|
324
|
+
if (market.amm.minBaseAssetReserve < market.amm.baseAssetReserve) {
|
|
325
|
+
openBids = market.amm.baseAssetReserve
|
|
326
|
+
.sub(market.amm.minBaseAssetReserve)
|
|
327
|
+
.mul(perpPosition.lpShares)
|
|
328
|
+
.div(market.amm.sqrtK);
|
|
329
|
+
}
|
|
330
|
+
else {
|
|
331
|
+
openBids = numericConstants_1.ZERO;
|
|
332
|
+
}
|
|
333
|
+
perpPosition.openAsks = perpPosition.openAsks.add(openAsks);
|
|
334
|
+
perpPosition.openBids = perpPosition.openBids.add(openBids);
|
|
335
|
+
}
|
|
336
|
+
var valuationPrice = _this.getOracleDataForMarket(market.marketIndex).price;
|
|
337
|
+
if ((0, types_1.isVariant)(market.status, 'settlement')) {
|
|
338
|
+
valuationPrice = market.settlementPrice;
|
|
339
|
+
}
|
|
340
|
+
var worstCaseBaseAssetAmount = (0, margin_1.calculateWorstCaseBaseAssetAmount)(perpPosition);
|
|
341
|
+
var worstCaseAssetValue = worstCaseBaseAssetAmount
|
|
342
|
+
.abs()
|
|
343
|
+
.mul(valuationPrice)
|
|
344
|
+
.div(numericConstants_1.AMM_TO_QUOTE_PRECISION_RATIO.mul(numericConstants_1.MARK_PRICE_PRECISION));
|
|
345
|
+
return marginRequirement.add(worstCaseAssetValue
|
|
346
|
+
.mul(new _1.BN((0, _1.calculateMarketMarginRatio)(market, worstCaseBaseAssetAmount.abs(), type)))
|
|
347
|
+
.div(numericConstants_1.MARGIN_PRECISION));
|
|
348
|
+
}, numericConstants_1.ZERO)
|
|
349
|
+
.add(this.getSpotMarketLiabilityValue(undefined, type));
|
|
350
|
+
};
|
|
351
|
+
/**
|
|
352
|
+
* @returns The initial margin requirement in USDC. : QUOTE_PRECISION
|
|
353
|
+
*/
|
|
354
|
+
ClearingHouseUser.prototype.getInitialMarginRequirement = function () {
|
|
355
|
+
return this.getMarginRequirement('Initial');
|
|
356
|
+
};
|
|
357
|
+
/**
|
|
358
|
+
* @returns The maintenance margin requirement in USDC. : QUOTE_PRECISION
|
|
359
|
+
*/
|
|
360
|
+
ClearingHouseUser.prototype.getMaintenanceMarginRequirement = function () {
|
|
361
|
+
return this.getMarginRequirement('Maintenance');
|
|
362
|
+
};
|
|
363
|
+
/**
|
|
364
|
+
* calculates unrealized position price pnl
|
|
365
|
+
* @returns : Precision QUOTE_PRECISION
|
|
366
|
+
*/
|
|
367
|
+
ClearingHouseUser.prototype.getUnrealizedPNL = function (withFunding, marketIndex, withWeightMarginCategory) {
|
|
368
|
+
var _this = this;
|
|
369
|
+
return this.getUserAccount()
|
|
370
|
+
.perpPositions.filter(function (pos) {
|
|
371
|
+
return marketIndex ? pos.marketIndex === marketIndex : true;
|
|
372
|
+
})
|
|
373
|
+
.reduce(function (unrealizedPnl, perpPosition) {
|
|
374
|
+
var market = _this.clearingHouse.getPerpMarketAccount(perpPosition.marketIndex);
|
|
375
|
+
var positionUnrealizedPnl = (0, _1.calculatePositionPNL)(market, perpPosition, withFunding, _this.getOracleDataForMarket(market.marketIndex));
|
|
376
|
+
if (withWeightMarginCategory !== undefined) {
|
|
377
|
+
if (positionUnrealizedPnl.gt(numericConstants_1.ZERO)) {
|
|
378
|
+
positionUnrealizedPnl = positionUnrealizedPnl
|
|
379
|
+
.mul((0, _1.calculateUnrealizedAssetWeight)(market, positionUnrealizedPnl, withWeightMarginCategory))
|
|
380
|
+
.div(new _1.BN(numericConstants_1.SPOT_MARKET_WEIGHT_PRECISION));
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
return unrealizedPnl.add(positionUnrealizedPnl);
|
|
384
|
+
}, numericConstants_1.ZERO);
|
|
385
|
+
};
|
|
386
|
+
/**
|
|
387
|
+
* calculates unrealized funding payment pnl
|
|
388
|
+
* @returns : Precision QUOTE_PRECISION
|
|
389
|
+
*/
|
|
390
|
+
ClearingHouseUser.prototype.getUnrealizedFundingPNL = function (marketIndex) {
|
|
391
|
+
var _this = this;
|
|
392
|
+
return this.getUserAccount()
|
|
393
|
+
.perpPositions.filter(function (pos) {
|
|
394
|
+
return marketIndex ? pos.marketIndex === marketIndex : true;
|
|
395
|
+
})
|
|
396
|
+
.reduce(function (pnl, perpPosition) {
|
|
397
|
+
var market = _this.clearingHouse.getPerpMarketAccount(perpPosition.marketIndex);
|
|
398
|
+
return pnl.add((0, _1.calculatePositionFundingPNL)(market, perpPosition));
|
|
399
|
+
}, numericConstants_1.ZERO);
|
|
400
|
+
};
|
|
401
|
+
ClearingHouseUser.prototype.getSpotMarketLiabilityValue = function (marketIndex, withWeightMarginCategory) {
|
|
402
|
+
var _this = this;
|
|
403
|
+
return this.getUserAccount().spotPositions.reduce(function (totalLiabilityValue, spotPosition) {
|
|
404
|
+
if (spotPosition.balance.eq(numericConstants_1.ZERO) ||
|
|
405
|
+
(0, types_1.isVariant)(spotPosition.balanceType, 'deposit') ||
|
|
406
|
+
(marketIndex !== undefined &&
|
|
407
|
+
!spotPosition.marketIndex.eq(marketIndex))) {
|
|
408
|
+
return totalLiabilityValue;
|
|
409
|
+
}
|
|
410
|
+
// Todo this needs to account for whether it's based on initial or maintenance requirements
|
|
411
|
+
var spotMarketAccount = _this.clearingHouse.getSpotMarketAccount(spotPosition.marketIndex);
|
|
412
|
+
var tokenAmount = (0, spotBalance_1.getTokenAmount)(spotPosition.balance, spotMarketAccount, spotPosition.balanceType);
|
|
413
|
+
var liabilityValue = tokenAmount
|
|
414
|
+
.mul(_this.getOracleDataForSpotMarket(spotMarketAccount.marketIndex).price)
|
|
415
|
+
.div(numericConstants_1.MARK_PRICE_PRECISION)
|
|
416
|
+
.div(new _1.BN(10).pow(new _1.BN(spotMarketAccount.decimals).sub(numericConstants_1.SPOT_MARKET_BALANCE_PRECISION_EXP)));
|
|
417
|
+
if (withWeightMarginCategory !== undefined) {
|
|
418
|
+
var weight = (0, spotBalance_1.calculateLiabilityWeight)(tokenAmount, spotMarketAccount, withWeightMarginCategory);
|
|
419
|
+
liabilityValue = liabilityValue
|
|
420
|
+
.mul(weight)
|
|
421
|
+
.div(numericConstants_1.SPOT_MARKET_WEIGHT_PRECISION);
|
|
422
|
+
}
|
|
423
|
+
return totalLiabilityValue.add(liabilityValue);
|
|
424
|
+
}, numericConstants_1.ZERO);
|
|
425
|
+
};
|
|
426
|
+
ClearingHouseUser.prototype.getSpotMarketAssetValue = function (marketIndex, withWeightMarginCategory) {
|
|
427
|
+
var _this = this;
|
|
428
|
+
return this.getUserAccount().spotPositions.reduce(function (totalAssetValue, spotPosition) {
|
|
429
|
+
if (spotPosition.balance.eq(numericConstants_1.ZERO) ||
|
|
430
|
+
(0, types_1.isVariant)(spotPosition.balanceType, 'borrow') ||
|
|
431
|
+
(marketIndex !== undefined &&
|
|
432
|
+
!spotPosition.marketIndex.eq(marketIndex))) {
|
|
433
|
+
return totalAssetValue;
|
|
434
|
+
}
|
|
435
|
+
// Todo this needs to account for whether it's based on initial or maintenance requirements
|
|
436
|
+
var spotMarketAccount = _this.clearingHouse.getSpotMarketAccount(spotPosition.marketIndex);
|
|
437
|
+
var tokenAmount = (0, spotBalance_1.getTokenAmount)(spotPosition.balance, spotMarketAccount, spotPosition.balanceType);
|
|
438
|
+
var assetValue = tokenAmount
|
|
439
|
+
.mul(_this.getOracleDataForSpotMarket(spotMarketAccount.marketIndex).price)
|
|
440
|
+
.div(numericConstants_1.MARK_PRICE_PRECISION)
|
|
441
|
+
.div(new _1.BN(10).pow(new _1.BN(spotMarketAccount.decimals).sub(numericConstants_1.SPOT_MARKET_BALANCE_PRECISION_EXP)));
|
|
442
|
+
if (withWeightMarginCategory !== undefined) {
|
|
443
|
+
var weight = (0, spotBalance_1.calculateAssetWeight)(tokenAmount, spotMarketAccount, withWeightMarginCategory);
|
|
444
|
+
assetValue = assetValue.mul(weight).div(numericConstants_1.SPOT_MARKET_WEIGHT_PRECISION);
|
|
445
|
+
}
|
|
446
|
+
return totalAssetValue.add(assetValue);
|
|
447
|
+
}, numericConstants_1.ZERO);
|
|
448
|
+
};
|
|
449
|
+
ClearingHouseUser.prototype.getNetSpotMarketValue = function (withWeightMarginCategory) {
|
|
450
|
+
return this.getSpotMarketAssetValue(undefined, withWeightMarginCategory).sub(this.getSpotMarketLiabilityValue(undefined, withWeightMarginCategory));
|
|
451
|
+
};
|
|
452
|
+
/**
|
|
453
|
+
* calculates TotalCollateral: collateral + unrealized pnl
|
|
454
|
+
* @returns : Precision QUOTE_PRECISION
|
|
455
|
+
*/
|
|
456
|
+
ClearingHouseUser.prototype.getTotalCollateral = function (marginCategory) {
|
|
457
|
+
if (marginCategory === void 0) { marginCategory = 'Initial'; }
|
|
458
|
+
return this.getSpotMarketAssetValue(undefined, marginCategory).add(this.getUnrealizedPNL(true, undefined, marginCategory));
|
|
459
|
+
};
|
|
460
|
+
/**
|
|
461
|
+
* calculates sum of position value across all positions in margin system
|
|
462
|
+
* @returns : Precision QUOTE_PRECISION
|
|
463
|
+
*/
|
|
464
|
+
ClearingHouseUser.prototype.getTotalPositionValue = function () {
|
|
465
|
+
var _this = this;
|
|
466
|
+
return this.getUserAccount().perpPositions.reduce(function (positionValue, perpPosition) {
|
|
467
|
+
var market = _this.clearingHouse.getPerpMarketAccount(perpPosition.marketIndex);
|
|
468
|
+
var posVal = (0, margin_1.calculateBaseAssetValueWithOracle)(market, perpPosition, _this.getOracleDataForMarket(market.marketIndex));
|
|
469
|
+
return positionValue.add(posVal);
|
|
470
|
+
}, numericConstants_1.ZERO);
|
|
471
|
+
};
|
|
472
|
+
/**
|
|
473
|
+
* calculates position value in margin system
|
|
474
|
+
* @returns : Precision QUOTE_PRECISION
|
|
475
|
+
*/
|
|
476
|
+
ClearingHouseUser.prototype.getPositionValue = function (marketIndex, oraclePriceData) {
|
|
477
|
+
var userPosition = this.getUserPosition(marketIndex) || this.getEmptyPosition(marketIndex);
|
|
478
|
+
var market = this.clearingHouse.getPerpMarketAccount(userPosition.marketIndex);
|
|
479
|
+
return (0, margin_1.calculateBaseAssetValueWithOracle)(market, userPosition, oraclePriceData);
|
|
480
|
+
};
|
|
481
|
+
ClearingHouseUser.prototype.getPositionSide = function (currentPosition) {
|
|
482
|
+
if (currentPosition.baseAssetAmount.gt(numericConstants_1.ZERO)) {
|
|
483
|
+
return _1.PositionDirection.LONG;
|
|
484
|
+
}
|
|
485
|
+
else if (currentPosition.baseAssetAmount.lt(numericConstants_1.ZERO)) {
|
|
486
|
+
return _1.PositionDirection.SHORT;
|
|
487
|
+
}
|
|
488
|
+
else {
|
|
489
|
+
return undefined;
|
|
490
|
+
}
|
|
491
|
+
};
|
|
492
|
+
/**
|
|
493
|
+
* calculates average exit price (optionally for closing up to 100% of position)
|
|
494
|
+
* @returns : Precision MARK_PRICE_PRECISION
|
|
495
|
+
*/
|
|
496
|
+
ClearingHouseUser.prototype.getPositionEstimatedExitPriceAndPnl = function (position, amountToClose, useAMMClose) {
|
|
497
|
+
if (useAMMClose === void 0) { useAMMClose = false; }
|
|
498
|
+
var market = this.clearingHouse.getPerpMarketAccount(position.marketIndex);
|
|
499
|
+
var entryPrice = (0, position_1.calculateEntryPrice)(position);
|
|
500
|
+
var oraclePriceData = this.getOracleDataForMarket(position.marketIndex);
|
|
501
|
+
if (amountToClose) {
|
|
502
|
+
if (amountToClose.eq(numericConstants_1.ZERO)) {
|
|
503
|
+
return [(0, _1.calculateMarkPrice)(market, oraclePriceData), numericConstants_1.ZERO];
|
|
504
|
+
}
|
|
505
|
+
position = {
|
|
506
|
+
baseAssetAmount: amountToClose,
|
|
507
|
+
lastCumulativeFundingRate: position.lastCumulativeFundingRate,
|
|
508
|
+
marketIndex: position.marketIndex,
|
|
509
|
+
quoteAssetAmount: position.quoteAssetAmount
|
|
510
|
+
};
|
|
511
|
+
}
|
|
512
|
+
var baseAssetValue;
|
|
513
|
+
if (useAMMClose) {
|
|
514
|
+
baseAssetValue = (0, _1.calculateBaseAssetValue)(market, position, oraclePriceData);
|
|
515
|
+
}
|
|
516
|
+
else {
|
|
517
|
+
baseAssetValue = (0, margin_1.calculateBaseAssetValueWithOracle)(market, position, oraclePriceData);
|
|
518
|
+
}
|
|
519
|
+
if (position.baseAssetAmount.eq(numericConstants_1.ZERO)) {
|
|
520
|
+
return [numericConstants_1.ZERO, numericConstants_1.ZERO];
|
|
521
|
+
}
|
|
522
|
+
var exitPrice = baseAssetValue
|
|
523
|
+
.mul(numericConstants_1.AMM_TO_QUOTE_PRECISION_RATIO)
|
|
524
|
+
.mul(numericConstants_1.MARK_PRICE_PRECISION)
|
|
525
|
+
.div(position.baseAssetAmount.abs());
|
|
526
|
+
var pnlPerBase = exitPrice.sub(entryPrice);
|
|
527
|
+
var pnl = pnlPerBase
|
|
528
|
+
.mul(position.baseAssetAmount)
|
|
529
|
+
.div(numericConstants_1.MARK_PRICE_PRECISION)
|
|
530
|
+
.div(numericConstants_1.AMM_TO_QUOTE_PRECISION_RATIO);
|
|
531
|
+
return [exitPrice, pnl];
|
|
532
|
+
};
|
|
533
|
+
/**
|
|
534
|
+
* calculates current user leverage across all positions
|
|
535
|
+
* @returns : Precision TEN_THOUSAND
|
|
536
|
+
*/
|
|
537
|
+
ClearingHouseUser.prototype.getLeverage = function () {
|
|
538
|
+
var totalCollateral = this.getTotalCollateral();
|
|
539
|
+
var totalPositionValue = this.getTotalPositionValue();
|
|
540
|
+
if (totalPositionValue.eq(numericConstants_1.ZERO) && totalCollateral.eq(numericConstants_1.ZERO)) {
|
|
541
|
+
return numericConstants_1.ZERO;
|
|
542
|
+
}
|
|
543
|
+
return totalPositionValue.mul(numericConstants_1.TEN_THOUSAND).div(totalCollateral);
|
|
544
|
+
};
|
|
545
|
+
/**
|
|
546
|
+
* calculates max allowable leverage exceeding hitting requirement category
|
|
547
|
+
* @params category {Initial, Partial, Maintenance}
|
|
548
|
+
* @returns : Precision TEN_THOUSAND
|
|
549
|
+
*/
|
|
550
|
+
ClearingHouseUser.prototype.getMaxLeverage = function (marketIndex, category) {
|
|
551
|
+
if (category === void 0) { category = 'Initial'; }
|
|
552
|
+
var market = this.clearingHouse.getPerpMarketAccount(marketIndex);
|
|
553
|
+
var marginRatioCategory = (0, _1.calculateMarketMarginRatio)(market,
|
|
554
|
+
// worstCaseBaseAssetAmount.abs(),
|
|
555
|
+
numericConstants_1.ZERO, // todo
|
|
556
|
+
category);
|
|
557
|
+
var maxLeverage = numericConstants_1.TEN_THOUSAND.mul(numericConstants_1.TEN_THOUSAND).div(new _1.BN(marginRatioCategory));
|
|
558
|
+
return maxLeverage;
|
|
559
|
+
};
|
|
560
|
+
/**
|
|
561
|
+
* calculates margin ratio: total collateral / |total position value|
|
|
562
|
+
* @returns : Precision TEN_THOUSAND
|
|
563
|
+
*/
|
|
564
|
+
ClearingHouseUser.prototype.getMarginRatio = function () {
|
|
565
|
+
var totalPositionValue = this.getTotalPositionValue();
|
|
566
|
+
if (totalPositionValue.eq(numericConstants_1.ZERO)) {
|
|
567
|
+
return numericConstants_1.BN_MAX;
|
|
568
|
+
}
|
|
569
|
+
return this.getTotalCollateral().mul(numericConstants_1.TEN_THOUSAND).div(totalPositionValue);
|
|
570
|
+
};
|
|
571
|
+
ClearingHouseUser.prototype.canBeLiquidated = function () {
|
|
572
|
+
var totalCollateral = this.getTotalCollateral();
|
|
573
|
+
var partialMaintenanceRequirement = this.getMaintenanceMarginRequirement();
|
|
574
|
+
var marginRatio = this.getMarginRatio();
|
|
575
|
+
var canLiquidate = totalCollateral.lt(partialMaintenanceRequirement);
|
|
576
|
+
return [canLiquidate, marginRatio];
|
|
577
|
+
};
|
|
578
|
+
/**
|
|
579
|
+
* Checks if any user position cumulative funding differs from respective market cumulative funding
|
|
580
|
+
* @returns
|
|
581
|
+
*/
|
|
582
|
+
ClearingHouseUser.prototype.needsToSettleFundingPayment = function () {
|
|
583
|
+
for (var _i = 0, _a = this.getUserAccount().perpPositions; _i < _a.length; _i++) {
|
|
584
|
+
var userPosition = _a[_i];
|
|
585
|
+
if (userPosition.baseAssetAmount.eq(numericConstants_1.ZERO)) {
|
|
586
|
+
continue;
|
|
587
|
+
}
|
|
588
|
+
var market = this.clearingHouse.getPerpMarketAccount(userPosition.marketIndex);
|
|
589
|
+
if (market.amm.cumulativeFundingRateLong.eq(userPosition.lastCumulativeFundingRate) ||
|
|
590
|
+
market.amm.cumulativeFundingRateShort.eq(userPosition.lastCumulativeFundingRate)) {
|
|
591
|
+
continue;
|
|
592
|
+
}
|
|
593
|
+
return true;
|
|
594
|
+
}
|
|
595
|
+
return false;
|
|
596
|
+
};
|
|
597
|
+
/**
|
|
598
|
+
* Calculate the liquidation price of a position, with optional parameter to calculate the liquidation price after a trade
|
|
599
|
+
* @param PerpPosition
|
|
600
|
+
* @param positionBaseSizeChange // change in position size to calculate liquidation price for : Precision 10^13
|
|
601
|
+
* @param partial
|
|
602
|
+
* @returns Precision : MARK_PRICE_PRECISION
|
|
603
|
+
*/
|
|
604
|
+
ClearingHouseUser.prototype.liquidationPrice = function (perpPosition, positionBaseSizeChange) {
|
|
605
|
+
// solves formula for example canBeLiquidated below
|
|
606
|
+
var _this = this;
|
|
607
|
+
if (positionBaseSizeChange === void 0) { positionBaseSizeChange = numericConstants_1.ZERO; }
|
|
608
|
+
/* example: assume BTC price is $40k (examine 10% up/down)
|
|
609
|
+
|
|
610
|
+
if 10k deposit and levered 10x short BTC => BTC up $400 means:
|
|
611
|
+
1. higher base_asset_value (+$4k)
|
|
612
|
+
2. lower collateral (-$4k)
|
|
613
|
+
3. (10k - 4k)/(100k + 4k) => 6k/104k => .0576
|
|
614
|
+
|
|
615
|
+
for 10x long, BTC down $400:
|
|
616
|
+
3. (10k - 4k) / (100k - 4k) = 6k/96k => .0625 */
|
|
617
|
+
var totalCollateral = this.getTotalCollateral();
|
|
618
|
+
// calculate the total position value ignoring any value from the target market of the trade
|
|
619
|
+
var totalPositionValueExcludingTargetMarket = this.getTotalPositionValueExcludingMarket(perpPosition.marketIndex);
|
|
620
|
+
var currentPerpPosition = this.getUserPosition(perpPosition.marketIndex) ||
|
|
621
|
+
this.getEmptyPosition(perpPosition.marketIndex);
|
|
622
|
+
var currentPerpPositionBaseSize = currentPerpPosition.baseAssetAmount;
|
|
623
|
+
var proposedBaseAssetAmount = currentPerpPositionBaseSize.add(positionBaseSizeChange);
|
|
624
|
+
// calculate position for current market after trade
|
|
625
|
+
var proposedPerpPosition = {
|
|
626
|
+
marketIndex: perpPosition.marketIndex,
|
|
627
|
+
baseAssetAmount: proposedBaseAssetAmount,
|
|
628
|
+
remainderBaseAssetAmount: numericConstants_1.ZERO,
|
|
629
|
+
quoteAssetAmount: new _1.BN(0),
|
|
630
|
+
lastCumulativeFundingRate: numericConstants_1.ZERO,
|
|
631
|
+
quoteEntryAmount: new _1.BN(0),
|
|
632
|
+
openOrders: new _1.BN(0),
|
|
633
|
+
openBids: new _1.BN(0),
|
|
634
|
+
openAsks: new _1.BN(0),
|
|
635
|
+
realizedPnl: numericConstants_1.ZERO,
|
|
636
|
+
lpShares: numericConstants_1.ZERO,
|
|
637
|
+
lastFeePerLp: numericConstants_1.ZERO,
|
|
638
|
+
lastNetBaseAssetAmountPerLp: numericConstants_1.ZERO,
|
|
639
|
+
lastNetQuoteAssetAmountPerLp: numericConstants_1.ZERO
|
|
640
|
+
};
|
|
641
|
+
if (proposedBaseAssetAmount.eq(numericConstants_1.ZERO))
|
|
642
|
+
return new _1.BN(-1);
|
|
643
|
+
var market = this.clearingHouse.getPerpMarketAccount(proposedPerpPosition.marketIndex);
|
|
644
|
+
var proposedPerpPositionValue = (0, margin_1.calculateBaseAssetValueWithOracle)(market, proposedPerpPosition, this.getOracleDataForMarket(market.marketIndex));
|
|
645
|
+
// total position value after trade
|
|
646
|
+
var totalPositionValueAfterTrade = totalPositionValueExcludingTargetMarket.add(proposedPerpPositionValue);
|
|
647
|
+
var marginRequirementExcludingTargetMarket = this.getUserAccount().perpPositions.reduce(function (totalMarginRequirement, position) {
|
|
648
|
+
if (!position.marketIndex.eq(perpPosition.marketIndex)) {
|
|
649
|
+
var market_1 = _this.clearingHouse.getPerpMarketAccount(position.marketIndex);
|
|
650
|
+
var positionValue = (0, margin_1.calculateBaseAssetValueWithOracle)(market_1, position, _this.getOracleDataForMarket(market_1.marketIndex));
|
|
651
|
+
var marketMarginRequirement = positionValue
|
|
652
|
+
.mul(new _1.BN((0, _1.calculateMarketMarginRatio)(market_1, position.baseAssetAmount.abs(), 'Maintenance')))
|
|
653
|
+
.div(numericConstants_1.MARGIN_PRECISION);
|
|
654
|
+
totalMarginRequirement = totalMarginRequirement.add(marketMarginRequirement);
|
|
655
|
+
}
|
|
656
|
+
return totalMarginRequirement;
|
|
657
|
+
}, numericConstants_1.ZERO);
|
|
658
|
+
var freeCollateralExcludingTargetMarket = totalCollateral.sub(marginRequirementExcludingTargetMarket);
|
|
659
|
+
// if the position value after the trade is less than free collateral, there is no liq price
|
|
660
|
+
if (totalPositionValueAfterTrade.lte(freeCollateralExcludingTargetMarket) &&
|
|
661
|
+
proposedPerpPosition.baseAssetAmount.abs().gt(numericConstants_1.ZERO)) {
|
|
662
|
+
return new _1.BN(-1);
|
|
663
|
+
}
|
|
664
|
+
var marginRequirementAfterTrade = marginRequirementExcludingTargetMarket.add(proposedPerpPositionValue
|
|
665
|
+
.mul(new _1.BN((0, _1.calculateMarketMarginRatio)(market, proposedPerpPosition.baseAssetAmount.abs(), 'Maintenance')))
|
|
666
|
+
.div(numericConstants_1.MARGIN_PRECISION));
|
|
667
|
+
var freeCollateralAfterTrade = totalCollateral.sub(marginRequirementAfterTrade);
|
|
668
|
+
var marketMaxLeverage = this.getMaxLeverage(proposedPerpPosition.marketIndex, 'Maintenance');
|
|
669
|
+
var priceDelta;
|
|
670
|
+
if (proposedBaseAssetAmount.lt(numericConstants_1.ZERO)) {
|
|
671
|
+
priceDelta = freeCollateralAfterTrade
|
|
672
|
+
.mul(marketMaxLeverage) // precision is TEN_THOUSAND
|
|
673
|
+
.div(marketMaxLeverage.add(numericConstants_1.TEN_THOUSAND))
|
|
674
|
+
.mul(numericConstants_1.PRICE_TO_QUOTE_PRECISION)
|
|
675
|
+
.mul(numericConstants_1.AMM_RESERVE_PRECISION)
|
|
676
|
+
.div(proposedBaseAssetAmount);
|
|
677
|
+
}
|
|
678
|
+
else {
|
|
679
|
+
priceDelta = freeCollateralAfterTrade
|
|
680
|
+
.mul(marketMaxLeverage) // precision is TEN_THOUSAND
|
|
681
|
+
.div(marketMaxLeverage.sub(numericConstants_1.TEN_THOUSAND))
|
|
682
|
+
.mul(numericConstants_1.PRICE_TO_QUOTE_PRECISION)
|
|
683
|
+
.mul(numericConstants_1.AMM_RESERVE_PRECISION)
|
|
684
|
+
.div(proposedBaseAssetAmount);
|
|
685
|
+
}
|
|
686
|
+
var markPriceAfterTrade;
|
|
687
|
+
if (positionBaseSizeChange.eq(numericConstants_1.ZERO)) {
|
|
688
|
+
markPriceAfterTrade = (0, _1.calculateMarkPrice)(this.clearingHouse.getPerpMarketAccount(perpPosition.marketIndex), this.getOracleDataForMarket(perpPosition.marketIndex));
|
|
689
|
+
}
|
|
690
|
+
else {
|
|
691
|
+
var direction = positionBaseSizeChange.gt(numericConstants_1.ZERO)
|
|
692
|
+
? _1.PositionDirection.LONG
|
|
693
|
+
: _1.PositionDirection.SHORT;
|
|
694
|
+
markPriceAfterTrade = (0, _1.calculateTradeSlippage)(direction, positionBaseSizeChange.abs(), this.clearingHouse.getPerpMarketAccount(perpPosition.marketIndex), 'base', this.getOracleDataForMarket(perpPosition.marketIndex))[3]; // newPrice after swap
|
|
695
|
+
}
|
|
696
|
+
if (priceDelta.gt(markPriceAfterTrade)) {
|
|
697
|
+
return new _1.BN(-1);
|
|
698
|
+
}
|
|
699
|
+
return markPriceAfterTrade.sub(priceDelta);
|
|
700
|
+
};
|
|
701
|
+
/**
|
|
702
|
+
* Calculates the estimated liquidation price for a position after closing a quote amount of the position.
|
|
703
|
+
* @param positionMarketIndex
|
|
704
|
+
* @param closeQuoteAmount
|
|
705
|
+
* @returns : Precision MARK_PRICE_PRECISION
|
|
706
|
+
*/
|
|
707
|
+
ClearingHouseUser.prototype.liquidationPriceAfterClose = function (positionMarketIndex, closeQuoteAmount) {
|
|
708
|
+
var currentPosition = this.getUserPosition(positionMarketIndex) ||
|
|
709
|
+
this.getEmptyPosition(positionMarketIndex);
|
|
710
|
+
var closeBaseAmount = currentPosition.baseAssetAmount
|
|
711
|
+
.mul(closeQuoteAmount)
|
|
712
|
+
.div(currentPosition.quoteAssetAmount.abs())
|
|
713
|
+
.add(currentPosition.baseAssetAmount
|
|
714
|
+
.mul(closeQuoteAmount)
|
|
715
|
+
.mod(currentPosition.quoteAssetAmount.abs()))
|
|
716
|
+
.neg();
|
|
717
|
+
return this.liquidationPrice({
|
|
718
|
+
marketIndex: positionMarketIndex
|
|
719
|
+
}, closeBaseAmount);
|
|
720
|
+
};
|
|
721
|
+
/**
|
|
722
|
+
* Get the maximum trade size for a given market, taking into account the user's current leverage, positions, collateral, etc.
|
|
723
|
+
*
|
|
724
|
+
* To Calculate Max Quote Available:
|
|
725
|
+
*
|
|
726
|
+
* Case 1: SameSide
|
|
727
|
+
* => Remaining quote to get to maxLeverage
|
|
728
|
+
*
|
|
729
|
+
* Case 2: NOT SameSide && currentLeverage <= maxLeverage
|
|
730
|
+
* => Current opposite position x2 + remaining to get to maxLeverage
|
|
731
|
+
*
|
|
732
|
+
* Case 3: NOT SameSide && currentLeverage > maxLeverage && otherPositions - currentPosition > maxLeverage
|
|
733
|
+
* => strictly reduce current position size
|
|
734
|
+
*
|
|
735
|
+
* Case 4: NOT SameSide && currentLeverage > maxLeverage && otherPositions - currentPosition < maxLeverage
|
|
736
|
+
* => current position + remaining to get to maxLeverage
|
|
737
|
+
*
|
|
738
|
+
* @param targetMarketIndex
|
|
739
|
+
* @param tradeSide
|
|
740
|
+
* @returns tradeSizeAllowed : Precision QUOTE_PRECISION
|
|
741
|
+
*/
|
|
742
|
+
ClearingHouseUser.prototype.getMaxTradeSizeUSDC = function (targetMarketIndex, tradeSide) {
|
|
743
|
+
var currentPosition = this.getUserPosition(targetMarketIndex) ||
|
|
744
|
+
this.getEmptyPosition(targetMarketIndex);
|
|
745
|
+
var targetSide = (0, types_1.isVariant)(tradeSide, 'short') ? 'short' : 'long';
|
|
746
|
+
var currentPositionSide = (currentPosition === null || currentPosition === void 0 ? void 0 : currentPosition.baseAssetAmount.isNeg())
|
|
747
|
+
? 'short'
|
|
748
|
+
: 'long';
|
|
749
|
+
var targetingSameSide = !currentPosition
|
|
750
|
+
? true
|
|
751
|
+
: targetSide === currentPositionSide;
|
|
752
|
+
var oracleData = this.getOracleDataForMarket(targetMarketIndex);
|
|
753
|
+
// 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.
|
|
754
|
+
var oppositeSizeValueUSDC = targetingSameSide
|
|
755
|
+
? numericConstants_1.ZERO
|
|
756
|
+
: this.getPositionValue(targetMarketIndex, oracleData);
|
|
757
|
+
var maxPositionSize = this.getBuyingPower(targetMarketIndex);
|
|
758
|
+
if (maxPositionSize.gte(numericConstants_1.ZERO)) {
|
|
759
|
+
if (oppositeSizeValueUSDC.eq(numericConstants_1.ZERO)) {
|
|
760
|
+
// case 1 : Regular trade where current total position less than max, and no opposite position to account for
|
|
761
|
+
// do nothing
|
|
762
|
+
}
|
|
763
|
+
else {
|
|
764
|
+
// case 2 : trade where current total position less than max, but need to account for flipping the current position over to the other side
|
|
765
|
+
maxPositionSize = maxPositionSize.add(oppositeSizeValueUSDC.mul(new _1.BN(2)));
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
else {
|
|
769
|
+
// current leverage is greater than max leverage - can only reduce position size
|
|
770
|
+
if (!targetingSameSide) {
|
|
771
|
+
var market = this.clearingHouse.getPerpMarketAccount(targetMarketIndex);
|
|
772
|
+
var perpPositionValue = this.getPositionValue(targetMarketIndex, oracleData);
|
|
773
|
+
var totalCollateral = this.getTotalCollateral();
|
|
774
|
+
var marginRequirement = this.getInitialMarginRequirement();
|
|
775
|
+
var marginFreedByClosing = perpPositionValue
|
|
776
|
+
.mul(new _1.BN(market.marginRatioInitial))
|
|
777
|
+
.div(numericConstants_1.MARGIN_PRECISION);
|
|
778
|
+
var marginRequirementAfterClosing = marginRequirement.sub(marginFreedByClosing);
|
|
779
|
+
if (marginRequirementAfterClosing.gt(totalCollateral)) {
|
|
780
|
+
maxPositionSize = perpPositionValue;
|
|
781
|
+
}
|
|
782
|
+
else {
|
|
783
|
+
var freeCollateralAfterClose = totalCollateral.sub(marginRequirementAfterClosing);
|
|
784
|
+
var buyingPowerAfterClose = freeCollateralAfterClose
|
|
785
|
+
.mul(this.getMaxLeverage(targetMarketIndex))
|
|
786
|
+
.div(numericConstants_1.TEN_THOUSAND);
|
|
787
|
+
maxPositionSize = perpPositionValue.add(buyingPowerAfterClose);
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
else {
|
|
791
|
+
// do nothing if targetting same side
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
// subtract oneMillionth of maxPositionSize
|
|
795
|
+
// => to avoid rounding errors when taking max leverage
|
|
796
|
+
var oneMilli = maxPositionSize.div(numericConstants_1.QUOTE_PRECISION);
|
|
797
|
+
return maxPositionSize.sub(oneMilli);
|
|
798
|
+
};
|
|
799
|
+
// TODO - should this take the price impact of the trade into account for strict accuracy?
|
|
800
|
+
/**
|
|
801
|
+
* Returns the leverage ratio for the account after adding (or subtracting) the given quote size to the given position
|
|
802
|
+
* @param targetMarketIndex
|
|
803
|
+
* @param positionMarketIndex
|
|
804
|
+
* @param tradeQuoteAmount
|
|
805
|
+
* @returns leverageRatio : Precision TEN_THOUSAND
|
|
806
|
+
*/
|
|
807
|
+
ClearingHouseUser.prototype.accountLeverageRatioAfterTrade = function (targetMarketIndex, tradeQuoteAmount, tradeSide) {
|
|
808
|
+
var currentPosition = this.getUserPosition(targetMarketIndex) ||
|
|
809
|
+
this.getEmptyPosition(targetMarketIndex);
|
|
810
|
+
var oracleData = this.getOracleDataForMarket(targetMarketIndex);
|
|
811
|
+
var currentPositionQuoteAmount = this.getPositionValue(targetMarketIndex, oracleData);
|
|
812
|
+
var currentSide = currentPosition && currentPosition.baseAssetAmount.isNeg()
|
|
813
|
+
? _1.PositionDirection.SHORT
|
|
814
|
+
: _1.PositionDirection.LONG;
|
|
815
|
+
if (currentSide === _1.PositionDirection.SHORT)
|
|
816
|
+
currentPositionQuoteAmount = currentPositionQuoteAmount.neg();
|
|
817
|
+
if (tradeSide === _1.PositionDirection.SHORT)
|
|
818
|
+
tradeQuoteAmount = tradeQuoteAmount.neg();
|
|
819
|
+
var currentPerpPositionAfterTrade = currentPositionQuoteAmount
|
|
820
|
+
.add(tradeQuoteAmount)
|
|
821
|
+
.abs();
|
|
822
|
+
var totalPositionAfterTradeExcludingTargetMarket = this.getTotalPositionValueExcludingMarket(targetMarketIndex);
|
|
823
|
+
var totalCollateral = this.getTotalCollateral();
|
|
824
|
+
if (totalCollateral.gt(numericConstants_1.ZERO)) {
|
|
825
|
+
var newLeverage = currentPerpPositionAfterTrade
|
|
826
|
+
.add(totalPositionAfterTradeExcludingTargetMarket)
|
|
827
|
+
.abs()
|
|
828
|
+
.mul(numericConstants_1.TEN_THOUSAND)
|
|
829
|
+
.div(totalCollateral);
|
|
830
|
+
return newLeverage;
|
|
831
|
+
}
|
|
832
|
+
else {
|
|
833
|
+
return new _1.BN(0);
|
|
834
|
+
}
|
|
835
|
+
};
|
|
836
|
+
/**
|
|
837
|
+
* Calculates how much fee will be taken for a given sized trade
|
|
838
|
+
* @param quoteAmount
|
|
839
|
+
* @returns feeForQuote : Precision QUOTE_PRECISION
|
|
840
|
+
*/
|
|
841
|
+
ClearingHouseUser.prototype.calculateFeeForQuoteAmount = function (quoteAmount) {
|
|
842
|
+
var feeStructure = this.clearingHouse.getStateAccount().perpFeeStructure;
|
|
843
|
+
return quoteAmount
|
|
844
|
+
.mul(feeStructure.feeNumerator)
|
|
845
|
+
.div(feeStructure.feeDenominator);
|
|
846
|
+
};
|
|
847
|
+
/**
|
|
848
|
+
* Get the total position value, excluding any position coming from the given target market
|
|
849
|
+
* @param marketToIgnore
|
|
850
|
+
* @returns positionValue : Precision QUOTE_PRECISION
|
|
851
|
+
*/
|
|
852
|
+
ClearingHouseUser.prototype.getTotalPositionValueExcludingMarket = function (marketToIgnore) {
|
|
853
|
+
var currentPerpPosition = this.getUserPosition(marketToIgnore) ||
|
|
854
|
+
this.getEmptyPosition(marketToIgnore);
|
|
855
|
+
var oracleData = this.getOracleDataForMarket(marketToIgnore);
|
|
856
|
+
var currentPerpPositionValueUSDC = numericConstants_1.ZERO;
|
|
857
|
+
if (currentPerpPosition) {
|
|
858
|
+
currentPerpPositionValueUSDC = this.getPositionValue(marketToIgnore, oracleData);
|
|
859
|
+
}
|
|
860
|
+
return this.getTotalPositionValue().sub(currentPerpPositionValueUSDC);
|
|
861
|
+
};
|
|
862
|
+
ClearingHouseUser.prototype.getOracleDataForMarket = function (marketIndex) {
|
|
863
|
+
var oracleKey = this.clearingHouse.getPerpMarketAccount(marketIndex).amm.oracle;
|
|
864
|
+
var oracleData = this.clearingHouse.getOraclePriceDataAndSlot(oracleKey).data;
|
|
865
|
+
return oracleData;
|
|
866
|
+
};
|
|
867
|
+
ClearingHouseUser.prototype.getOracleDataForSpotMarket = function (marketIndex) {
|
|
868
|
+
var oracleKey = this.clearingHouse.getSpotMarketAccount(marketIndex).oracle;
|
|
869
|
+
var oracleData = this.clearingHouse.getOraclePriceDataAndSlot(oracleKey).data;
|
|
870
|
+
return oracleData;
|
|
871
|
+
};
|
|
872
|
+
return ClearingHouseUser;
|
|
873
|
+
}());
|
|
874
|
+
exports.ClearingHouseUser = ClearingHouseUser;
|