@d8x/perpetuals-sdk 0.0.21 → 0.0.23

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.
@@ -1258,6 +1258,12 @@
1258
1258
  "name": "perpetualId",
1259
1259
  "type": "uint24"
1260
1260
  },
1261
+ {
1262
+ "indexed": false,
1263
+ "internalType": "int128",
1264
+ "name": "fMidPricePremium",
1265
+ "type": "int128"
1266
+ },
1261
1267
  {
1262
1268
  "indexed": false,
1263
1269
  "internalType": "int128",
@@ -2394,9 +2400,9 @@
2394
2400
  "name": "getAMMState",
2395
2401
  "outputs": [
2396
2402
  {
2397
- "internalType": "int128[13]",
2403
+ "internalType": "int128[15]",
2398
2404
  "name": "",
2399
- "type": "int128[13]"
2405
+ "type": "int128[15]"
2400
2406
  }
2401
2407
  ],
2402
2408
  "stateMutability": "view",
@@ -3694,6 +3700,30 @@
3694
3700
  "stateMutability": "view",
3695
3701
  "type": "function"
3696
3702
  },
3703
+ {
3704
+ "inputs": [
3705
+ {
3706
+ "internalType": "bytes4",
3707
+ "name": "_baseCurrency",
3708
+ "type": "bytes4"
3709
+ },
3710
+ {
3711
+ "internalType": "bytes4",
3712
+ "name": "_quoteCurrency",
3713
+ "type": "bytes4"
3714
+ }
3715
+ ],
3716
+ "name": "isMarketClosed",
3717
+ "outputs": [
3718
+ {
3719
+ "internalType": "bool",
3720
+ "name": "",
3721
+ "type": "bool"
3722
+ }
3723
+ ],
3724
+ "stateMutability": "view",
3725
+ "type": "function"
3726
+ },
3697
3727
  {
3698
3728
  "inputs": [
3699
3729
  {
@@ -3732,6 +3762,25 @@
3732
3762
  "stateMutability": "view",
3733
3763
  "type": "function"
3734
3764
  },
3765
+ {
3766
+ "inputs": [
3767
+ {
3768
+ "internalType": "uint24",
3769
+ "name": "_perpetualId",
3770
+ "type": "uint24"
3771
+ }
3772
+ ],
3773
+ "name": "isPerpMarketClosed",
3774
+ "outputs": [
3775
+ {
3776
+ "internalType": "bool",
3777
+ "name": "isClosed",
3778
+ "type": "bool"
3779
+ }
3780
+ ],
3781
+ "stateMutability": "view",
3782
+ "type": "function"
3783
+ },
3735
3784
  {
3736
3785
  "inputs": [
3737
3786
  {
@@ -65,12 +65,6 @@
65
65
  "name": "perpetualId",
66
66
  "type": "uint24"
67
67
  },
68
- {
69
- "indexed": false,
70
- "internalType": "uint16",
71
- "name": "brokerFeeTbps",
72
- "type": "uint16"
73
- },
74
68
  {
75
69
  "indexed": true,
76
70
  "internalType": "address",
@@ -90,46 +84,82 @@
90
84
  "type": "address"
91
85
  },
92
86
  {
87
+ "components": [
88
+ {
89
+ "internalType": "uint32",
90
+ "name": "flags",
91
+ "type": "uint32"
92
+ },
93
+ {
94
+ "internalType": "uint24",
95
+ "name": "iPerpetualId",
96
+ "type": "uint24"
97
+ },
98
+ {
99
+ "internalType": "uint16",
100
+ "name": "brokerFeeTbps",
101
+ "type": "uint16"
102
+ },
103
+ {
104
+ "internalType": "address",
105
+ "name": "traderAddr",
106
+ "type": "address"
107
+ },
108
+ {
109
+ "internalType": "address",
110
+ "name": "brokerAddr",
111
+ "type": "address"
112
+ },
113
+ {
114
+ "internalType": "address",
115
+ "name": "referrerAddr",
116
+ "type": "address"
117
+ },
118
+ {
119
+ "internalType": "bytes",
120
+ "name": "brokerSignature",
121
+ "type": "bytes"
122
+ },
123
+ {
124
+ "internalType": "int128",
125
+ "name": "fAmount",
126
+ "type": "int128"
127
+ },
128
+ {
129
+ "internalType": "int128",
130
+ "name": "fLimitPrice",
131
+ "type": "int128"
132
+ },
133
+ {
134
+ "internalType": "int128",
135
+ "name": "fTriggerPrice",
136
+ "type": "int128"
137
+ },
138
+ {
139
+ "internalType": "int128",
140
+ "name": "fLeverage",
141
+ "type": "int128"
142
+ },
143
+ {
144
+ "internalType": "uint64",
145
+ "name": "iDeadline",
146
+ "type": "uint64"
147
+ },
148
+ {
149
+ "internalType": "uint64",
150
+ "name": "createdTimestamp",
151
+ "type": "uint64"
152
+ },
153
+ {
154
+ "internalType": "uint64",
155
+ "name": "submittedBlock",
156
+ "type": "uint64"
157
+ }
158
+ ],
93
159
  "indexed": false,
94
- "internalType": "int128",
95
- "name": "tradeAmount",
96
- "type": "int128"
97
- },
98
- {
99
- "indexed": false,
100
- "internalType": "int128",
101
- "name": "limitPrice",
102
- "type": "int128"
103
- },
104
- {
105
- "indexed": false,
106
- "internalType": "int128",
107
- "name": "triggerPrice",
108
- "type": "int128"
109
- },
110
- {
111
- "indexed": false,
112
- "internalType": "uint64",
113
- "name": "deadline",
114
- "type": "uint64"
115
- },
116
- {
117
- "indexed": false,
118
- "internalType": "uint32",
119
- "name": "flags",
120
- "type": "uint32"
121
- },
122
- {
123
- "indexed": false,
124
- "internalType": "int128",
125
- "name": "leverage",
126
- "type": "int128"
127
- },
128
- {
129
- "indexed": false,
130
- "internalType": "uint64",
131
- "name": "createdTimestamp",
132
- "type": "uint64"
160
+ "internalType": "struct IPerpetualOrder.Order",
161
+ "name": "order",
162
+ "type": "tuple"
133
163
  },
134
164
  {
135
165
  "indexed": false,
@@ -1,9 +1,10 @@
1
1
  {
2
- "name": "v1.4",
3
- "proxyAddr": "0x7fe419fDE6c47F57B49Ef4D5D1ACD332307a734d",
2
+ "name": "v1.5",
3
+ "proxyAddr": "0xaB6AD25eE5CA28E7d7b16A33A33897aE34BF9e67",
4
4
  "nodeURL": "https://rpc-mumbai.maticvigil.com/",
5
5
  "proxyABILocation": "../abi/IPerpetualManager.json",
6
- "limitOrderBookFactoryAddr": "0x40aA68C1C33626ecD048a8A38aBF3947813cAF92",
6
+ "limitOrderBookFactoryAddr": "0xe95422bf27C62F3b9ae19d6032aC58c1bd13C71E",
7
7
  "limitOrderBookFactoryABILocation": "../abi/LimitOrderBookFactory.json",
8
- "limitOrderBookABILocation": "../abi/LimitOrderBook.json"
8
+ "limitOrderBookABILocation": "../abi/LimitOrderBook.json",
9
+ "symbolListLocation": "../config/symbolList.json"
9
10
  }
@@ -1,9 +1,10 @@
1
1
  {
2
- "name": "v1.3",
3
- "proxyAddr": "0x44Ae67695781209ace41c422dCfD29d3C678AF68",
2
+ "name": "v1.4",
3
+ "proxyAddr": "0x7fe419fDE6c47F57B49Ef4D5D1ACD332307a734d",
4
4
  "nodeURL": "https://rpc-mumbai.maticvigil.com/",
5
5
  "proxyABILocation": "../abi/IPerpetualManager.json",
6
- "limitOrderBookFactoryAddr": "0x5D9Af75B450be534d57106c817145f4E373069cb",
6
+ "limitOrderBookFactoryAddr": "0x40aA68C1C33626ecD048a8A38aBF3947813cAF92",
7
7
  "limitOrderBookFactoryABILocation": "../abi/LimitOrderBookFactory.json",
8
- "limitOrderBookABILocation": "../abi/LimitOrderBook.json"
8
+ "limitOrderBookABILocation": "../abi/LimitOrderBook.json",
9
+ "symbolListLocation": "../config/symbolList.json"
9
10
  }
@@ -0,0 +1,9 @@
1
+ [
2
+ { "symbol": "USD", "cleanSymbol": "USD" },
3
+ { "symbol": "BTC", "cleanSymbol": "BTC" },
4
+ { "symbol": "ETH", "cleanSymbol": "ETH" },
5
+ { "symbol": "MATIC", "cleanSymbol": "MATC" },
6
+ { "symbol": "CHF", "cleanSymbol": "CHF" },
7
+ { "symbol": "GBP", "cleanSymbol": "GBP" },
8
+ { "symbol": "XAU", "cleanSymbol": "XAU" }
9
+ ]
@@ -186,13 +186,13 @@ class AccountTrade extends writeAccessHandler_1.default {
186
186
  */
187
187
  queryExchangeFee(poolSymbolName, brokerAddr) {
188
188
  return __awaiter(this, void 0, void 0, function* () {
189
- if (this.proxyContract == null || this.signer == null) {
189
+ if (this.proxyContract == null) {
190
190
  throw Error("no proxy contract or wallet initialized. Use createProxyInstance().");
191
191
  }
192
192
  if (typeof brokerAddr == "undefined") {
193
193
  brokerAddr = nodeSDKTypes_1.ZERO_ADDRESS;
194
194
  }
195
- let poolId = writeAccessHandler_1.default._getPoolIdFromSymbol(poolSymbolName, this.poolStaticInfos);
195
+ let poolId = perpetualDataHandler_1.default._getPoolIdFromSymbol(poolSymbolName, this.poolStaticInfos);
196
196
  let feeTbps = yield this.proxyContract.queryExchangeFee(poolId, this.traderAddr, brokerAddr);
197
197
  return feeTbps / 100000;
198
198
  });
package/dist/d8XMath.d.ts CHANGED
@@ -72,3 +72,19 @@ export declare function calculateLiquidationPriceCollateralQuanto(LockedInValueQ
72
72
  * @returns {number} Amount to be deposited to have the given leverage when trading into position pos
73
73
  */
74
74
  export declare function calculateLiquidationPriceCollateralQuote(LockedInValueQC: number, position: number, cash_cc: number, maintenance_margin_rate: number): number;
75
+ /**
76
+ *
77
+ * @param targetLeverage Leverage of the resulting position. It must be positive unless the resulting position is closed.
78
+ * @param currentPosition Current position size, in base currency, signed.
79
+ * @param currentLockedInValue Current locked in value, average entry price times position size, in quote currency.
80
+ * @param tradeAmount Trade amount, in base currency, signed.
81
+ * @param markPrice Mark price, positive.
82
+ * @param indexPriceS2 Index price, positive.
83
+ * @param indexPriceS3 Collateral index price, positive.
84
+ * @param tradePrice Expected price to trade tradeAmount.
85
+ * @param feeRate
86
+ * @returns
87
+ */
88
+ export declare function getMarginRequiredForLeveragedTrade(targetLeverage: number | undefined, currentPosition: number, currentLockedInValue: number, tradeAmount: number, markPrice: number, indexPriceS2: number, indexPriceS3: number, tradePrice: number, feeRate: number): number;
89
+ export declare function getMaxSignedPositionSize(marginCollateral: number, currentPosition: number, currentLockedInValue: number, direction: number, limitPrice: number, initialMarginRate: number, feeRate: number, markPrice: number, indexPriceS2: number, indexPriceS3: number): number;
90
+ export declare function getNewPositionLeverage(tradeAmount: number, marginCollateral: number, currentPosition: number, currentLockedInValue: number, indexPriceS2: number, indexPriceS3: number, markPrice: number, limitPrice: number, feeRate: number): number;
package/dist/d8XMath.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.calculateLiquidationPriceCollateralQuote = exports.calculateLiquidationPriceCollateralQuanto = exports.calculateLiquidationPriceCollateralBase = exports.div64x64 = exports.mul64x64 = exports.floatToDec18 = exports.floatToABK64x64 = exports.dec18ToFloat = exports.ABK64x64ToFloat = void 0;
3
+ exports.getNewPositionLeverage = exports.getMaxSignedPositionSize = exports.getMarginRequiredForLeveragedTrade = exports.calculateLiquidationPriceCollateralQuote = exports.calculateLiquidationPriceCollateralQuanto = exports.calculateLiquidationPriceCollateralBase = exports.div64x64 = exports.mul64x64 = exports.floatToDec18 = exports.floatToABK64x64 = exports.dec18ToFloat = exports.ABK64x64ToFloat = void 0;
4
4
  const ethers_1 = require("ethers");
5
5
  const nodeSDKTypes_1 = require("./nodeSDKTypes");
6
6
  /**
@@ -162,3 +162,50 @@ function calculateLiquidationPriceCollateralQuote(LockedInValueQC, position, cas
162
162
  return numerator / denominator;
163
163
  }
164
164
  exports.calculateLiquidationPriceCollateralQuote = calculateLiquidationPriceCollateralQuote;
165
+ /**
166
+ *
167
+ * @param targetLeverage Leverage of the resulting position. It must be positive unless the resulting position is closed.
168
+ * @param currentPosition Current position size, in base currency, signed.
169
+ * @param currentLockedInValue Current locked in value, average entry price times position size, in quote currency.
170
+ * @param tradeAmount Trade amount, in base currency, signed.
171
+ * @param markPrice Mark price, positive.
172
+ * @param indexPriceS2 Index price, positive.
173
+ * @param indexPriceS3 Collateral index price, positive.
174
+ * @param tradePrice Expected price to trade tradeAmount.
175
+ * @param feeRate
176
+ * @returns
177
+ */
178
+ function getMarginRequiredForLeveragedTrade(targetLeverage, currentPosition, currentLockedInValue, tradeAmount, markPrice, indexPriceS2, indexPriceS3, tradePrice, feeRate) {
179
+ // we solve for margin in:
180
+ // |new position| * Sm / leverage + fee rate * |trade amount| * S2 = margin * S3 + current position * Sm - L + trade amount * (Sm - trade price)
181
+ // --> M S3 = |P'|Sm/L + FeeQC - PnL + (P'-P)(Price - Sm) = pos value / leverage + fees + price impact - pnl
182
+ let isClosing = currentPosition != 0 && currentPosition * tradeAmount < 0 && currentPosition * (currentPosition + tradeAmount) >= 0;
183
+ let feesCC = (feeRate * Math.abs(tradeAmount) * indexPriceS2) / indexPriceS3;
184
+ let collRequired = feesCC;
185
+ if (!isClosing) {
186
+ if (targetLeverage == undefined || targetLeverage <= 0) {
187
+ throw Error("opening trades must have positive leverage");
188
+ }
189
+ // unrealized pnl (could be + or -) - price impact premium (+)
190
+ let pnlQC = currentPosition * markPrice - currentLockedInValue - tradeAmount * (tradePrice - markPrice);
191
+ collRequired +=
192
+ Math.max(0, (Math.abs(currentPosition + tradeAmount) * markPrice) / targetLeverage - pnlQC) / indexPriceS3;
193
+ }
194
+ return collRequired;
195
+ }
196
+ exports.getMarginRequiredForLeveragedTrade = getMarginRequiredForLeveragedTrade;
197
+ function getMaxSignedPositionSize(marginCollateral, currentPosition, currentLockedInValue, direction, limitPrice, initialMarginRate, feeRate, markPrice, indexPriceS2, indexPriceS3) {
198
+ // we solve for new position in:
199
+ // |new position| * Sm / leverage + fee rate * |trade amount| * S2 = margin * S3 + current position * Sm - L + trade amount * (Sm - entry price)
200
+ // |trade amount| = (new position - current position) * direction
201
+ let availableCash = marginCollateral * indexPriceS3 + currentPosition * markPrice - currentLockedInValue;
202
+ let effectiveMarginRate = markPrice * initialMarginRate + feeRate * indexPriceS2 + direction * (limitPrice - markPrice);
203
+ return availableCash / effectiveMarginRate;
204
+ }
205
+ exports.getMaxSignedPositionSize = getMaxSignedPositionSize;
206
+ function getNewPositionLeverage(tradeAmount, marginCollateral, currentPosition, currentLockedInValue, indexPriceS2, indexPriceS3, markPrice, limitPrice, feeRate) {
207
+ let newPosition = tradeAmount + currentPosition;
208
+ let pnlQC = currentPosition * markPrice - currentLockedInValue + tradeAmount * (markPrice - limitPrice);
209
+ return ((Math.abs(newPosition) * indexPriceS2) / (marginCollateral * indexPriceS3 + pnlQC - feeRate * Math.abs(tradeAmount)));
210
+ }
211
+ exports.getNewPositionLeverage = getNewPositionLeverage;
@@ -1,7 +1,7 @@
1
- import { ExchangeInfo, NodeSDKConfig, MarginAccount } from "./nodeSDKTypes";
1
+ import { ExchangeInfo, NodeSDKConfig, MarginAccount, PerpetualState, PoolStaticInfo } from "./nodeSDKTypes";
2
2
  import { ethers } from "ethers";
3
3
  import PerpetualDataHandler from "./perpetualDataHandler";
4
- import { Order } from "./nodeSDKTypes";
4
+ import { SmartContractOrder, Order } from "./nodeSDKTypes";
5
5
  import "./nodeSDKTypes";
6
6
  /**
7
7
  * Functions to access market data (e.g., information on open orders, information on products that can be traded).
@@ -36,6 +36,12 @@ export default class MarketData extends PerpetualDataHandler {
36
36
  * @param provider optional provider
37
37
  */
38
38
  createProxyInstance(provider?: ethers.providers.JsonRpcProvider): Promise<void>;
39
+ /**
40
+ * Convert the smart contract output of an order into a convenient format of type "Order"
41
+ * @param smOrder SmartContractOrder, as obtained e.g., by PerpetualLimitOrderCreated event
42
+ * @returns more convenient format of order, type "Order"
43
+ */
44
+ smartContractOrderToOrder(smOrder: SmartContractOrder): Order;
39
45
  /**
40
46
  * Get contract instance. Useful for event listening.
41
47
  * @example
@@ -100,9 +106,9 @@ export default class MarketData extends PerpetualDataHandler {
100
106
  orderIds: string[];
101
107
  }>;
102
108
  /**
103
- * Information about the positions open by a given trader in a given perpetual contract.
109
+ * Information about the position open by a given trader in a given perpetual contract.
104
110
  * @param {string} traderAddr Address of the trader for which we get the position risk.
105
- * @param {string} symbol Symbol of the form ETH-USD-MATIC.
111
+ * @param {string} symbol Symbol of the form ETH-USD-MATIC. Can also be the perpetual id as string
106
112
  * @example
107
113
  * import { MarketData, PerpetualDataHandler } from '@d8x/perpetuals-sdk';
108
114
  * async function main() {
@@ -121,6 +127,8 @@ export default class MarketData extends PerpetualDataHandler {
121
127
  * @returns {MarginAccount}
122
128
  */
123
129
  positionRisk(traderAddr: string, symbol: string): Promise<MarginAccount>;
130
+ positionRiskOnTrade(traderAddr: string, order: Order, perpetualState: PerpetualState, currentPositionRisk?: MarginAccount): Promise<MarginAccount>;
131
+ maxOrderSizeForTrader(side: string, positionRisk: MarginAccount, perpetualState: PerpetualState): number;
124
132
  /**
125
133
  * Uses the Oracle(s) in the exchange to get the latest price of a given index in a given currency, if a route exists.
126
134
  * @param {string} base Index name, e.g. ETH.
@@ -183,6 +191,32 @@ export default class MarketData extends PerpetualDataHandler {
183
191
  * @returns price (number)
184
192
  */
185
193
  getPerpetualPrice(symbol: string, quantity: number): Promise<number>;
194
+ /**
195
+ * Query recent perpetual state from blockchain
196
+ * @param symbol symbol of the form ETH-USD-MATIC
197
+ * @returns PerpetualState reference
198
+ */
199
+ getPerpetualState(symbol: string): Promise<PerpetualState>;
200
+ /**
201
+ * get the current mid-price for a perpetual
202
+ * @param symbol symbol of the form ETH-USD-MATIC
203
+ * @example
204
+ * import { MarketData, PerpetualDataHandler } from '@d8x/perpetuals-sdk';
205
+ * async function main() {
206
+ * console.log(MarketData);
207
+ * // setup
208
+ * const config = PerpetualDataHandler.readSDKConfig("testnet");
209
+ * let mktData = new MarketData(config);
210
+ * await mktData.createProxyInstance();
211
+ * // get perpetual mid price
212
+ * let midPrice = await mktData.getPerpetualMidPrice("ETH-USD-MATIC");
213
+ * console.log(midPrice);
214
+ * }
215
+ * main();
216
+ *
217
+ * @returns {number} price
218
+ */
219
+ getPerpetualMidPrice(symbol: string): Promise<number>;
186
220
  /**
187
221
  * Query smart contract to get user orders and convert to user friendly order format.
188
222
  * @param {string} traderAddr Address of trader.
@@ -199,5 +233,7 @@ export default class MarketData extends PerpetualDataHandler {
199
233
  * @ignore
200
234
  */
201
235
  static orderIdsOfTrader(traderAddr: string, orderBookContract: ethers.Contract): Promise<string[]>;
202
- static _exchangeInfo(_proxyContract: ethers.Contract): Promise<ExchangeInfo>;
236
+ static _exchangeInfo(_proxyContract: ethers.Contract, _poolStaticInfos: Array<PoolStaticInfo>, _symbolList: Array<{
237
+ [key: string]: string;
238
+ }>): Promise<ExchangeInfo>;
203
239
  }
@@ -63,6 +63,14 @@ class MarketData extends perpetualDataHandler_1.default {
63
63
  yield this.initContractsAndData(this.provider);
64
64
  });
65
65
  }
66
+ /**
67
+ * Convert the smart contract output of an order into a convenient format of type "Order"
68
+ * @param smOrder SmartContractOrder, as obtained e.g., by PerpetualLimitOrderCreated event
69
+ * @returns more convenient format of order, type "Order"
70
+ */
71
+ smartContractOrderToOrder(smOrder) {
72
+ return perpetualDataHandler_1.default.fromSmartContractOrder(smOrder, this.symbolToPerpStaticInfo);
73
+ }
66
74
  /**
67
75
  * Get contract instance. Useful for event listening.
68
76
  * @example
@@ -110,7 +118,7 @@ class MarketData extends perpetualDataHandler_1.default {
110
118
  if (this.proxyContract == null) {
111
119
  throw Error("no proxy contract initialized. Use createProxyInstance().");
112
120
  }
113
- return yield MarketData._exchangeInfo(this.proxyContract);
121
+ return yield MarketData._exchangeInfo(this.proxyContract, this.poolStaticInfos, this.symbolList);
114
122
  });
115
123
  }
116
124
  /**
@@ -146,9 +154,9 @@ class MarketData extends perpetualDataHandler_1.default {
146
154
  });
147
155
  }
148
156
  /**
149
- * Information about the positions open by a given trader in a given perpetual contract.
157
+ * Information about the position open by a given trader in a given perpetual contract.
150
158
  * @param {string} traderAddr Address of the trader for which we get the position risk.
151
- * @param {string} symbol Symbol of the form ETH-USD-MATIC.
159
+ * @param {string} symbol Symbol of the form ETH-USD-MATIC. Can also be the perpetual id as string
152
160
  * @example
153
161
  * import { MarketData, PerpetualDataHandler } from '@d8x/perpetuals-sdk';
154
162
  * async function main() {
@@ -175,6 +183,87 @@ class MarketData extends perpetualDataHandler_1.default {
175
183
  return mgnAcct;
176
184
  });
177
185
  }
186
+ positionRiskOnTrade(traderAddr, order, perpetualState, currentPositionRisk) {
187
+ var _a, _b, _c;
188
+ return __awaiter(this, void 0, void 0, function* () {
189
+ if (this.proxyContract == null) {
190
+ throw Error("no proxy contract initialized. Use createProxyInstance().");
191
+ }
192
+ if (currentPositionRisk == undefined) {
193
+ currentPositionRisk = yield this.positionRisk(traderAddr, order.symbol);
194
+ }
195
+ let tradeAmount = order.quantity * (order.side == nodeSDKTypes_1.BUY_SIDE ? 1 : -1);
196
+ let currentPosition = currentPositionRisk.positionNotionalBaseCCY;
197
+ let newPosition = currentPositionRisk.positionNotionalBaseCCY + tradeAmount;
198
+ let side = newPosition > 0 ? nodeSDKTypes_1.BUY_SIDE : newPosition < 0 ? nodeSDKTypes_1.SELL_SIDE : nodeSDKTypes_1.CLOSED_SIDE;
199
+ let lockedInValue = currentPositionRisk.entryPrice * currentPosition;
200
+ let poolId = perpetualDataHandler_1.default._getPoolIdFromSymbol(order.symbol, this.poolStaticInfos);
201
+ // total fee rate = exchange fee + broker fee
202
+ let feeRate = (yield this.proxyContract.queryExchangeFee(poolId, traderAddr, (_a = order.brokerAddr) !== null && _a !== void 0 ? _a : nodeSDKTypes_1.ZERO_ADDRESS)) +
203
+ ((_b = order.brokerFeeTbps) !== null && _b !== void 0 ? _b : 0) / 100000;
204
+ // price for this order = limit price (conservative) if given, else the current perp price
205
+ let tradePrice = (_c = order.limitPrice) !== null && _c !== void 0 ? _c : (yield this.getPerpetualPrice(order.symbol, tradeAmount));
206
+ // need these for leverage/margin calculations
207
+ let [markPrice, indexPriceS2, indexPriceS3] = [
208
+ perpetualState.markPrice,
209
+ perpetualState.indexPrice,
210
+ perpetualState.collToQuoteIndexPrice,
211
+ ];
212
+ let newCollateral;
213
+ let newLeverage;
214
+ if (order.keepPositionLvg) {
215
+ // we have a target leverage for the resulting position
216
+ // this gives us the total margin needed in the account so that it satisfies the leverage condition
217
+ newCollateral = (0, d8XMath_1.getMarginRequiredForLeveragedTrade)(currentPositionRisk.leverage, currentPosition, lockedInValue, tradeAmount, markPrice, indexPriceS2, indexPriceS3, tradePrice, feeRate);
218
+ // the new leverage follows from the updated margin and position
219
+ newLeverage = (0, d8XMath_1.getNewPositionLeverage)(tradeAmount, newCollateral, currentPosition, lockedInValue, indexPriceS2, indexPriceS3, markPrice, tradePrice, feeRate);
220
+ }
221
+ else {
222
+ // the order has its own leverage and margin requirements
223
+ let tradeCollateral = (0, d8XMath_1.getMarginRequiredForLeveragedTrade)(order.leverage, 0, 0, tradeAmount, markPrice, indexPriceS2, indexPriceS3, tradePrice, feeRate);
224
+ newCollateral = currentPositionRisk.collateralCC + tradeCollateral;
225
+ // the new leverage corresponds to increasing the position and collateral according to the order
226
+ newLeverage = (0, d8XMath_1.getNewPositionLeverage)(tradeAmount, newCollateral, currentPosition, lockedInValue, indexPriceS2, indexPriceS3, markPrice, tradePrice, feeRate);
227
+ }
228
+ let newLockedInValue = lockedInValue + tradeAmount * tradePrice;
229
+ // liquidation vars
230
+ let S2Liq, S3Liq;
231
+ let tau = this.symbolToPerpStaticInfo.get(order.symbol).maintenanceMarginRate;
232
+ let ccyType = this.symbolToPerpStaticInfo.get(order.symbol).collateralCurrencyType;
233
+ if (ccyType == nodeSDKTypes_1.CollaterlCCY.BASE) {
234
+ S2Liq = (0, d8XMath_1.calculateLiquidationPriceCollateralBase)(newLockedInValue, newPosition, newCollateral, tau);
235
+ S3Liq = S2Liq;
236
+ }
237
+ else if (ccyType == nodeSDKTypes_1.CollaterlCCY.QUANTO) {
238
+ S3Liq = indexPriceS3;
239
+ S2Liq = (0, d8XMath_1.calculateLiquidationPriceCollateralQuanto)(newLockedInValue, newPosition, newCollateral, tau, indexPriceS3, markPrice);
240
+ }
241
+ else {
242
+ S2Liq = (0, d8XMath_1.calculateLiquidationPriceCollateralQuote)(newLockedInValue, newPosition, newCollateral, tau);
243
+ }
244
+ let newPositionRisk = {
245
+ symbol: currentPositionRisk.symbol,
246
+ positionNotionalBaseCCY: newPosition,
247
+ side: side,
248
+ entryPrice: Math.abs(newLockedInValue / newPosition),
249
+ leverage: newLeverage,
250
+ markPrice: markPrice,
251
+ unrealizedPnlQuoteCCY: tradeAmount * (markPrice - tradePrice),
252
+ unrealizedFundingCollateralCCY: currentPositionRisk.unrealizedFundingCollateralCCY,
253
+ collateralCC: newCollateral,
254
+ collToQuoteConversion: indexPriceS3,
255
+ liquidationPrice: [S2Liq, S3Liq],
256
+ liquidationLvg: 1 / tau,
257
+ };
258
+ return newPositionRisk;
259
+ });
260
+ }
261
+ maxOrderSizeForTrader(side, positionRisk, perpetualState) {
262
+ let initialMarginRate = this.symbolToPerpStaticInfo.get(positionRisk.symbol).initialMarginRate;
263
+ // fees not considered here
264
+ let maxPosition = (0, d8XMath_1.getMaxSignedPositionSize)(positionRisk.collateralCC, positionRisk.positionNotionalBaseCCY, positionRisk.entryPrice * positionRisk.positionNotionalBaseCCY, side == nodeSDKTypes_1.BUY_SIDE ? 1 : -1, perpetualState.markPrice, initialMarginRate, 0, perpetualState.markPrice, perpetualState.indexPrice, perpetualState.collToQuoteIndexPrice);
265
+ return maxPosition - positionRisk.positionNotionalBaseCCY;
266
+ }
178
267
  /**
179
268
  * Uses the Oracle(s) in the exchange to get the latest price of a given index in a given currency, if a route exists.
180
269
  * @param {string} base Index name, e.g. ETH.
@@ -259,6 +348,47 @@ class MarketData extends perpetualDataHandler_1.default {
259
348
  return yield perpetualDataHandler_1.default._queryPerpetualPrice(symbol, quantity, this.symbolToPerpStaticInfo, this.proxyContract);
260
349
  });
261
350
  }
351
+ /**
352
+ * Query recent perpetual state from blockchain
353
+ * @param symbol symbol of the form ETH-USD-MATIC
354
+ * @returns PerpetualState reference
355
+ */
356
+ getPerpetualState(symbol) {
357
+ return __awaiter(this, void 0, void 0, function* () {
358
+ if (this.proxyContract == null) {
359
+ throw Error("no proxy contract initialized. Use createProxyInstance().");
360
+ }
361
+ let state = yield perpetualDataHandler_1.default._queryPerpetualState(symbol, this.symbolToPerpStaticInfo, this.proxyContract);
362
+ return state;
363
+ });
364
+ }
365
+ /**
366
+ * get the current mid-price for a perpetual
367
+ * @param symbol symbol of the form ETH-USD-MATIC
368
+ * @example
369
+ * import { MarketData, PerpetualDataHandler } from '@d8x/perpetuals-sdk';
370
+ * async function main() {
371
+ * console.log(MarketData);
372
+ * // setup
373
+ * const config = PerpetualDataHandler.readSDKConfig("testnet");
374
+ * let mktData = new MarketData(config);
375
+ * await mktData.createProxyInstance();
376
+ * // get perpetual mid price
377
+ * let midPrice = await mktData.getPerpetualMidPrice("ETH-USD-MATIC");
378
+ * console.log(midPrice);
379
+ * }
380
+ * main();
381
+ *
382
+ * @returns {number} price
383
+ */
384
+ getPerpetualMidPrice(symbol) {
385
+ return __awaiter(this, void 0, void 0, function* () {
386
+ if (this.proxyContract == null) {
387
+ throw Error("no proxy contract initialized. Use createProxyInstance().");
388
+ }
389
+ return yield this.getPerpetualPrice(symbol, 0);
390
+ });
391
+ }
262
392
  /**
263
393
  * Query smart contract to get user orders and convert to user friendly order format.
264
394
  * @param {string} traderAddr Address of trader.
@@ -298,7 +428,7 @@ class MarketData extends perpetualDataHandler_1.default {
298
428
  return digests;
299
429
  });
300
430
  }
301
- static _exchangeInfo(_proxyContract) {
431
+ static _exchangeInfo(_proxyContract, _poolStaticInfos, _symbolList) {
302
432
  return __awaiter(this, void 0, void 0, function* () {
303
433
  let nestedPerpetualIDs = yield perpetualDataHandler_1.default.getNestedPerpetualIds(_proxyContract);
304
434
  let factory = yield _proxyContract.getOracleFactory();
@@ -309,6 +439,7 @@ class MarketData extends perpetualDataHandler_1.default {
309
439
  let pool = yield _proxyContract.getLiquidityPool(j + 1);
310
440
  let PoolState = {
311
441
  isRunning: pool.isRunning,
442
+ poolSymbol: _poolStaticInfos[j].poolMarginSymbol,
312
443
  marginTokenAddr: pool.marginTokenAddress,
313
444
  poolShareTokenAddr: pool.shareTokenAddress,
314
445
  defaultFundCashCC: (0, d8XMath_1.ABK64x64ToFloat)(pool.fDefaultFundCashCC),
@@ -321,6 +452,7 @@ class MarketData extends perpetualDataHandler_1.default {
321
452
  for (var k = 0; k < perpetualIDs.length; k++) {
322
453
  let perp = yield _proxyContract.getPerpetual(perpetualIDs[k]);
323
454
  let fIndexS2 = yield _proxyContract.getOraclePrice([perp.S2BaseCCY, perp.S2QuoteCCY]);
455
+ let fMidPrice = yield _proxyContract.queryPerpetualPrice(perpetualIDs[k], ethers_1.BigNumber.from(0));
324
456
  let indexS2 = (0, d8XMath_1.ABK64x64ToFloat)(fIndexS2);
325
457
  let indexS3 = 1;
326
458
  if (perp.eCollateralCurrency == nodeSDKTypes_1.COLLATERAL_CURRENCY_BASE) {
@@ -335,11 +467,12 @@ class MarketData extends perpetualDataHandler_1.default {
335
467
  let PerpetualState = {
336
468
  id: perp.id,
337
469
  state: state,
338
- baseCurrency: (0, utils_1.fromBytes4HexString)(perp.S2BaseCCY),
339
- quoteCurrency: (0, utils_1.fromBytes4HexString)(perp.S2QuoteCCY),
470
+ baseCurrency: (0, utils_1.contractSymbolToSymbol)(perp.S2BaseCCY, _symbolList),
471
+ quoteCurrency: (0, utils_1.contractSymbolToSymbol)(perp.S2QuoteCCY, _symbolList),
340
472
  indexPrice: indexS2,
341
473
  collToQuoteIndexPrice: indexS3,
342
474
  markPrice: indexS2 * (1 + markPremiumRate),
475
+ midPrice: (0, d8XMath_1.ABK64x64ToFloat)(fMidPrice),
343
476
  currentFundingRateBps: currentFundingRateBps,
344
477
  openInterestBC: (0, d8XMath_1.ABK64x64ToFloat)(perp.fOpenInterest),
345
478
  maxPositionBC: (0, d8XMath_1.ABK64x64ToFloat)(perp.fMaxPositionBC),