@d8x/perpetuals-sdk 0.0.44 → 0.0.46
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/README.md +12 -0
- package/abi/MockTokenSwap.json +186 -0
- package/config/defaultConfig.json +36 -10
- package/config/mockSwap.json +4 -0
- package/config/oldConfig.json +2 -1
- package/config/priceFeedConfig.json +18 -0
- package/dist/accountTrade.d.ts +1 -0
- package/dist/accountTrade.js +31 -7
- package/dist/d8XMath.d.ts +6 -0
- package/dist/d8XMath.js +19 -1
- package/dist/liquidatorTool.d.ts +6 -4
- package/dist/liquidatorTool.js +13 -7
- package/dist/marketData.d.ts +6 -11
- package/dist/marketData.js +59 -41
- package/dist/nodeSDKTypes.d.ts +33 -2
- package/dist/nodeSDKTypes.js +3 -18
- package/dist/orderReferrerTool.d.ts +17 -7
- package/dist/orderReferrerTool.js +43 -13
- package/dist/perpetualDataHandler.d.ts +46 -6
- package/dist/perpetualDataHandler.js +143 -16
- package/dist/perpetualEventHandler.d.ts +0 -3
- package/dist/perpetualEventHandler.js +0 -3
- package/dist/priceFeeds.d.ts +115 -0
- package/dist/priceFeeds.js +373 -0
- package/dist/triangulator.d.ts +27 -0
- package/dist/triangulator.js +107 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +3 -2
- package/src/accountTrade.ts +31 -8
- package/src/d8XMath.ts +47 -22
- package/src/index.ts +2 -0
- package/src/liquidatorTool.ts +28 -8
- package/src/marketData.ts +99 -61
- package/src/nodeSDKTypes.ts +30 -3
- package/src/orderReferrerTool.ts +56 -13
- package/src/perpetualDataHandler.ts +149 -21
- package/src/perpetualEventHandler.ts +0 -3
- package/src/priceFeeds.ts +371 -0
- package/src/triangulator.ts +105 -0
- package/src/version.ts +1 -1
package/src/orderReferrerTool.ts
CHANGED
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
SELL_SIDE,
|
|
8
8
|
ZERO_ADDRESS,
|
|
9
9
|
ZERO_ORDER_ID,
|
|
10
|
+
PriceFeedSubmission,
|
|
10
11
|
} from "./nodeSDKTypes";
|
|
11
12
|
import PerpetualDataHandler from "./perpetualDataHandler";
|
|
12
13
|
import WriteAccessHandler from "./writeAccessHandler";
|
|
@@ -46,8 +47,9 @@ export default class OrderReferrerTool extends WriteAccessHandler {
|
|
|
46
47
|
* Executes an order by symbol and ID. This action interacts with the blockchain and incurs gas costs.
|
|
47
48
|
* @param {string} symbol Symbol of the form ETH-USD-MATIC.
|
|
48
49
|
* @param {string} orderId ID of the order to be executed.
|
|
49
|
-
* @param {string=} referrerAddr
|
|
50
|
-
*
|
|
50
|
+
* @param {string=} referrerAddr optional address of the wallet to be credited for executing the order, if different from the one submitting this transaction.
|
|
51
|
+
* @param {number=} nonce optional nonce
|
|
52
|
+
* @param {PriceFeedSubmission=} submission optional signed prices obtained via PriceFeeds::fetchLatestFeedPriceInfoForPerpetual
|
|
51
53
|
* @example
|
|
52
54
|
* import { OrderReferrerTool, PerpetualDataHandler, Order } from "@d8x/perpetuals-sdk";
|
|
53
55
|
* async function main() {
|
|
@@ -79,7 +81,8 @@ export default class OrderReferrerTool extends WriteAccessHandler {
|
|
|
79
81
|
symbol: string,
|
|
80
82
|
orderId: string,
|
|
81
83
|
referrerAddr?: string,
|
|
82
|
-
nonce?: number
|
|
84
|
+
nonce?: number,
|
|
85
|
+
submission?: PriceFeedSubmission
|
|
83
86
|
): Promise<ethers.ContractTransaction> {
|
|
84
87
|
if (this.proxyContract == null || this.signer == null) {
|
|
85
88
|
throw Error("no proxy contract or wallet initialized. Use createProxyInstance().");
|
|
@@ -88,8 +91,22 @@ export default class OrderReferrerTool extends WriteAccessHandler {
|
|
|
88
91
|
if (typeof referrerAddr == "undefined") {
|
|
89
92
|
referrerAddr = this.traderAddr;
|
|
90
93
|
}
|
|
91
|
-
|
|
92
|
-
|
|
94
|
+
if (submission == undefined) {
|
|
95
|
+
submission = await this.priceFeedGetter.fetchLatestFeedPriceInfoForPerpetual(symbol);
|
|
96
|
+
}
|
|
97
|
+
const options = {
|
|
98
|
+
gasLimit: this.gasLimit,
|
|
99
|
+
nonce: nonce,
|
|
100
|
+
value: this.PRICE_UPDATE_FEE_GWEI * submission?.priceFeedVaas.length,
|
|
101
|
+
};
|
|
102
|
+
console.log(submission);
|
|
103
|
+
return await orderBookSC.executeOrder(
|
|
104
|
+
orderId,
|
|
105
|
+
referrerAddr,
|
|
106
|
+
submission?.priceFeedVaas,
|
|
107
|
+
submission?.timestamps,
|
|
108
|
+
options
|
|
109
|
+
);
|
|
93
110
|
}
|
|
94
111
|
|
|
95
112
|
/**
|
|
@@ -224,6 +241,8 @@ export default class OrderReferrerTool extends WriteAccessHandler {
|
|
|
224
241
|
/**
|
|
225
242
|
* Check if a conditional order can be executed
|
|
226
243
|
* @param order order structure
|
|
244
|
+
* @param indexPrices pair of index prices S2 and S3. S3 set to zero if not required. If undefined
|
|
245
|
+
* the function will fetch the latest prices from the REST API
|
|
227
246
|
* @example
|
|
228
247
|
* import { OrderReferrerTool, PerpetualDataHandler } from '@d8x/perpetuals-sdk';
|
|
229
248
|
* async function main() {
|
|
@@ -241,26 +260,39 @@ export default class OrderReferrerTool extends WriteAccessHandler {
|
|
|
241
260
|
* main();
|
|
242
261
|
* @returns true if order can be executed for the current state of the perpetuals
|
|
243
262
|
*/
|
|
244
|
-
public async isTradeable(order: Order): Promise<boolean> {
|
|
263
|
+
public async isTradeable(order: Order, indexPrices?: [number, number]): Promise<boolean> {
|
|
245
264
|
if (this.proxyContract == null) {
|
|
246
265
|
throw Error("no proxy contract initialized. Use createProxyInstance().");
|
|
247
266
|
}
|
|
267
|
+
if (indexPrices == undefined) {
|
|
268
|
+
let obj = await this.priceFeedGetter.fetchPricesForPerpetual(order.symbol);
|
|
269
|
+
indexPrices = [obj.idxPrices[0], obj.idxPrices[1]];
|
|
270
|
+
}
|
|
248
271
|
let orderPrice = await PerpetualDataHandler._queryPerpetualPrice(
|
|
249
272
|
order.symbol,
|
|
250
273
|
order.quantity,
|
|
251
274
|
this.symbolToPerpStaticInfo,
|
|
252
|
-
this.proxyContract
|
|
275
|
+
this.proxyContract,
|
|
276
|
+
indexPrices
|
|
253
277
|
);
|
|
254
278
|
let markPrice = await PerpetualDataHandler._queryPerpetualMarkPrice(
|
|
255
279
|
order.symbol,
|
|
256
280
|
this.symbolToPerpStaticInfo,
|
|
257
|
-
this.proxyContract
|
|
281
|
+
this.proxyContract,
|
|
282
|
+
indexPrices
|
|
258
283
|
);
|
|
259
284
|
let block = await this.provider!.getBlockNumber();
|
|
260
285
|
return OrderReferrerTool._isTradeable(order, orderPrice, markPrice, block, this.symbolToPerpStaticInfo);
|
|
261
286
|
}
|
|
262
287
|
|
|
263
|
-
|
|
288
|
+
/**
|
|
289
|
+
* Check for a batch of orders on the same perpetual whether they can be traded
|
|
290
|
+
* @param orders orders belonging to 1 perpetual
|
|
291
|
+
* @param indexPrice S2,S3-index prices for the given perpetual. Will fetch prices from REST API
|
|
292
|
+
* if not defined.
|
|
293
|
+
* @returns array of tradeable boolean
|
|
294
|
+
*/
|
|
295
|
+
public async isTradeableBatch(orders: Order[], indexPrices?: [number, number, boolean, boolean]): Promise<boolean[]> {
|
|
264
296
|
if (orders.length == 0) {
|
|
265
297
|
return [];
|
|
266
298
|
}
|
|
@@ -270,20 +302,31 @@ export default class OrderReferrerTool extends WriteAccessHandler {
|
|
|
270
302
|
if (orders.filter((o) => o.symbol == orders[0].symbol).length < orders.length) {
|
|
271
303
|
throw Error("all orders in a batch must have the same symbol");
|
|
272
304
|
}
|
|
305
|
+
if (indexPrices == undefined) {
|
|
306
|
+
let obj = await this.priceFeedGetter.fetchPricesForPerpetual(orders[0].symbol);
|
|
307
|
+
indexPrices = [obj.idxPrices[0], obj.idxPrices[1], obj.mktClosed[0], obj.mktClosed[1]];
|
|
308
|
+
}
|
|
309
|
+
if (indexPrices[2] || indexPrices[3]) {
|
|
310
|
+
// market closed
|
|
311
|
+
return orders.map((o) => false);
|
|
312
|
+
}
|
|
313
|
+
|
|
273
314
|
let orderPrice = await Promise.all(
|
|
274
315
|
orders.map((o) =>
|
|
275
316
|
PerpetualDataHandler._queryPerpetualPrice(
|
|
276
317
|
o.symbol,
|
|
277
318
|
o.quantity,
|
|
278
319
|
this.symbolToPerpStaticInfo,
|
|
279
|
-
this.proxyContract
|
|
320
|
+
this.proxyContract!,
|
|
321
|
+
[indexPrices![0], indexPrices![1]]
|
|
280
322
|
)
|
|
281
323
|
)
|
|
282
324
|
);
|
|
283
325
|
let markPrice = await PerpetualDataHandler._queryPerpetualMarkPrice(
|
|
284
326
|
orders[0].symbol,
|
|
285
327
|
this.symbolToPerpStaticInfo,
|
|
286
|
-
this.proxyContract
|
|
328
|
+
this.proxyContract,
|
|
329
|
+
[indexPrices![0], indexPrices![1]]
|
|
287
330
|
);
|
|
288
331
|
let block = await this.provider!.getBlockNumber();
|
|
289
332
|
return orders.map((o, idx) =>
|
|
@@ -293,7 +336,7 @@ export default class OrderReferrerTool extends WriteAccessHandler {
|
|
|
293
336
|
|
|
294
337
|
public static _isTradeable(
|
|
295
338
|
order: Order,
|
|
296
|
-
|
|
339
|
+
tradePrice: number,
|
|
297
340
|
markPrice: number,
|
|
298
341
|
block: number,
|
|
299
342
|
symbolToPerpInfoMap: Map<string, PerpetualStaticInfo>
|
|
@@ -316,7 +359,7 @@ export default class OrderReferrerTool extends WriteAccessHandler {
|
|
|
316
359
|
return false;
|
|
317
360
|
}
|
|
318
361
|
let limitPrice = order.limitPrice!;
|
|
319
|
-
if ((order.side == BUY_SIDE &&
|
|
362
|
+
if ((order.side == BUY_SIDE && tradePrice > limitPrice) || (order.side == SELL_SIDE && tradePrice < limitPrice)) {
|
|
320
363
|
return false;
|
|
321
364
|
}
|
|
322
365
|
// do we need to check trigger/stop?
|
|
@@ -24,13 +24,12 @@ import {
|
|
|
24
24
|
MASK_STOP_ORDER,
|
|
25
25
|
MarginAccount,
|
|
26
26
|
PoolStaticInfo,
|
|
27
|
-
DEFAULT_CONFIG_MAINNET_NAME,
|
|
28
|
-
DEFAULT_CONFIG_MAINNET,
|
|
29
|
-
DEFAULT_CONFIG_TESTNET_NAME,
|
|
30
|
-
DEFAULT_CONFIG_TESTNET,
|
|
31
27
|
ONE_64x64,
|
|
32
28
|
PERP_STATE_STR,
|
|
33
29
|
PerpetualState,
|
|
30
|
+
DEFAULT_CONFIG,
|
|
31
|
+
DEFAULT_CONFIG_MAINNET_NAME,
|
|
32
|
+
PriceFeedSubmission,
|
|
34
33
|
} from "./nodeSDKTypes";
|
|
35
34
|
import {
|
|
36
35
|
fromBytes4HexString,
|
|
@@ -48,12 +47,14 @@ import {
|
|
|
48
47
|
calculateLiquidationPriceCollateralBase,
|
|
49
48
|
calculateLiquidationPriceCollateralQuote,
|
|
50
49
|
} from "./d8XMath";
|
|
50
|
+
import PriceFeeds from "./priceFeeds";
|
|
51
51
|
|
|
52
52
|
/**
|
|
53
53
|
* Parent class for MarketData and WriteAccessHandler that handles
|
|
54
54
|
* common data and chain operations.
|
|
55
55
|
*/
|
|
56
56
|
export default class PerpetualDataHandler {
|
|
57
|
+
PRICE_UPDATE_FEE_GWEI = 1;
|
|
57
58
|
//map symbol of the form ETH-USD-MATIC into perpetual ID and other static info
|
|
58
59
|
//this is initialized in the createProxyInstance function
|
|
59
60
|
protected symbolToPerpStaticInfo: Map<string, PerpetualStaticInfo>;
|
|
@@ -76,6 +77,7 @@ export default class PerpetualDataHandler {
|
|
|
76
77
|
protected provider: ethers.providers.JsonRpcProvider | null = null;
|
|
77
78
|
|
|
78
79
|
private signerOrProvider: ethers.Signer | ethers.providers.Provider | null = null;
|
|
80
|
+
protected priceFeedGetter : PriceFeeds;
|
|
79
81
|
|
|
80
82
|
// pools are numbered consecutively starting at 1
|
|
81
83
|
// nestedPerpetualIDs contains an array for each pool
|
|
@@ -94,6 +96,7 @@ export default class PerpetualDataHandler {
|
|
|
94
96
|
this.lobFactoryABI = require(config.limitOrderBookFactoryABILocation);
|
|
95
97
|
this.lobABI = require(config.limitOrderBookABILocation);
|
|
96
98
|
this.symbolList = new Map<string, string>(Object.entries(require(config.symbolListLocation)));
|
|
99
|
+
this.priceFeedGetter = new PriceFeeds(this, config.priceFeedConfigNetwork);
|
|
97
100
|
}
|
|
98
101
|
|
|
99
102
|
protected async initContractsAndData(signerOrProvider: ethers.Signer | ethers.providers.Provider) {
|
|
@@ -127,6 +130,7 @@ export default class PerpetualDataHandler {
|
|
|
127
130
|
throw Error("proxy or limit order book not defined");
|
|
128
131
|
}
|
|
129
132
|
this.nestedPerpetualIDs = await PerpetualDataHandler.getNestedPerpetualIds(proxyContract);
|
|
133
|
+
let requiredPairs = new Set<string>();
|
|
130
134
|
for (let j = 0; j < this.nestedPerpetualIDs.length; j++) {
|
|
131
135
|
let pool = await proxyContract.getLiquidityPool(j + 1);
|
|
132
136
|
let poolMarginTokenAddr = pool.marginTokenAddress;
|
|
@@ -146,8 +150,16 @@ export default class PerpetualDataHandler {
|
|
|
146
150
|
let quote = contractSymbolToSymbol(perp.S2QuoteCCY, this.symbolList);
|
|
147
151
|
let base3 = contractSymbolToSymbol(perp.S3BaseCCY, this.symbolList);
|
|
148
152
|
let quote3 = contractSymbolToSymbol(perp.S3QuoteCCY, this.symbolList);
|
|
149
|
-
|
|
150
|
-
|
|
153
|
+
let sym = base + "-" + quote;
|
|
154
|
+
let sym3 = base3 + "-" + quote3;
|
|
155
|
+
requiredPairs.add(sym);
|
|
156
|
+
if (sym3!="-") {
|
|
157
|
+
requiredPairs.add(sym3);
|
|
158
|
+
} else {
|
|
159
|
+
sym3 = "";
|
|
160
|
+
}
|
|
161
|
+
currentSymbols.push(sym);
|
|
162
|
+
currentSymbolsS3.push(sym3);
|
|
151
163
|
initRate.push(ABK64x64ToFloat(perp.fInitialMarginRate));
|
|
152
164
|
mgnRate.push(ABK64x64ToFloat(perp.fMaintenanceMarginRate));
|
|
153
165
|
lotSizes.push(ABK64x64ToFloat(perp.fLotSizeBC));
|
|
@@ -186,6 +198,10 @@ export default class PerpetualDataHandler {
|
|
|
186
198
|
let currentSymbols3 = currentSymbols.map((x) => x + "-" + poolCCY);
|
|
187
199
|
// push into map
|
|
188
200
|
for (let k = 0; k < perpetualIDs.length; k++) {
|
|
201
|
+
// add price IDs
|
|
202
|
+
let idsB32, isPyth;
|
|
203
|
+
[idsB32, isPyth] = await proxyContract.getPriceInfo(perpetualIDs[k]);
|
|
204
|
+
|
|
189
205
|
this.symbolToPerpStaticInfo.set(currentSymbols3[k], {
|
|
190
206
|
id: perpetualIDs[k],
|
|
191
207
|
limitOrderBookAddr: currentLimitOrderBookAddr[k],
|
|
@@ -195,11 +211,16 @@ export default class PerpetualDataHandler {
|
|
|
195
211
|
S2Symbol: currentSymbols[k],
|
|
196
212
|
S3Symbol: currentSymbolsS3[k],
|
|
197
213
|
lotSizeBC: lotSizes[k],
|
|
214
|
+
priceIds: idsB32,
|
|
198
215
|
});
|
|
199
216
|
}
|
|
200
217
|
// push margin token address into map
|
|
201
218
|
this.symbolToTokenAddrMap.set(poolCCY!, poolMarginTokenAddr);
|
|
202
219
|
}
|
|
220
|
+
// pre-calculate all triangulation paths so we can easily get from
|
|
221
|
+
// the prices of price-feeds to the index price required, e.g.
|
|
222
|
+
// BTC-USDC : BTC-USD / USDC-USD
|
|
223
|
+
this.priceFeedGetter.initializeTriangulations(requiredPairs);
|
|
203
224
|
}
|
|
204
225
|
|
|
205
226
|
/**
|
|
@@ -241,6 +262,55 @@ export default class PerpetualDataHandler {
|
|
|
241
262
|
return symbol4BToLongSymbol(sym, this.symbolList);
|
|
242
263
|
}
|
|
243
264
|
|
|
265
|
+
/**
|
|
266
|
+
* Get PriceFeedSubmission data required for blockchain queries that involve price data, and the corresponding
|
|
267
|
+
* triangulated prices for the indices S2 and S3
|
|
268
|
+
* @param symbol pool symbol of the form "ETH-USD-MATIC"
|
|
269
|
+
* @returns PriceFeedSubmission and prices for S2 and S3. [S2price, 0] if S3 not defined.
|
|
270
|
+
*/
|
|
271
|
+
public async fetchPriceSubmissionInfoForPerpetual(symbol: string) : Promise<{submission : PriceFeedSubmission, pxS2S3 : [number,number]}> {
|
|
272
|
+
// fetch prices from required price-feeds (REST)
|
|
273
|
+
return await this.priceFeedGetter.fetchFeedPriceInfoAndIndicesForPerpetual(symbol);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Get the symbols required as indices for the given perpetual
|
|
278
|
+
* @param symbol of the form ETH-USD-MATIC, specifying the perpetual
|
|
279
|
+
* @returns name of underlying index prices, e.g. ["MATIC-USD", ""]
|
|
280
|
+
*/
|
|
281
|
+
public getIndexSymbols(symbol: string) : [string, string] {
|
|
282
|
+
// get index
|
|
283
|
+
let staticInfo = this.symbolToPerpStaticInfo.get(symbol);
|
|
284
|
+
if (staticInfo==undefined) {
|
|
285
|
+
throw new Error(`No static info for perpetual with symbol ${symbol}`);
|
|
286
|
+
}
|
|
287
|
+
return [staticInfo.S2Symbol,staticInfo.S3Symbol];
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Get the latest prices for a given perpetual from the offchain oracle
|
|
292
|
+
* networks
|
|
293
|
+
* @param symbol perpetual symbol of the form BTC-USD-MATIC
|
|
294
|
+
* @returns array of price feed updates that can be submitted to the smart contract
|
|
295
|
+
* and corresponding price information
|
|
296
|
+
*/
|
|
297
|
+
public async fetchLatestFeedPriceInfo(symbol: string) : Promise<PriceFeedSubmission> {
|
|
298
|
+
return await this.priceFeedGetter.fetchLatestFeedPriceInfoForPerpetual(symbol);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Get list of required pyth price source IDs for given perpetual
|
|
303
|
+
* @param symbol perpetual symbol, e.g., BTC-USD-MATIC
|
|
304
|
+
* @returns list of required pyth price sources for this perpetual
|
|
305
|
+
*/
|
|
306
|
+
public getPriceIds(symbol: string): string[] {
|
|
307
|
+
let perpInfo = this.symbolToPerpStaticInfo.get(symbol);
|
|
308
|
+
if (perpInfo == undefined) {
|
|
309
|
+
throw Error(`Perpetual with symbol ${symbol} not found. Check symbol or use createProxyInstance().`);
|
|
310
|
+
}
|
|
311
|
+
return perpInfo.priceIds;
|
|
312
|
+
}
|
|
313
|
+
|
|
244
314
|
protected static _getSymbolFromPoolId(poolId: number, staticInfos: PoolStaticInfo[]): string {
|
|
245
315
|
let idx = poolId - 1;
|
|
246
316
|
return staticInfos[idx].poolMarginSymbol;
|
|
@@ -334,31 +404,37 @@ export default class PerpetualDataHandler {
|
|
|
334
404
|
symbol: string,
|
|
335
405
|
tradeAmount: number,
|
|
336
406
|
symbolToPerpStaticInfo: Map<string, PerpetualStaticInfo>,
|
|
337
|
-
_proxyContract: ethers.Contract
|
|
407
|
+
_proxyContract: ethers.Contract,
|
|
408
|
+
indexPrices: [number, number]
|
|
338
409
|
): Promise<number> {
|
|
339
410
|
let perpId = PerpetualDataHandler.symbolToPerpetualId(symbol, symbolToPerpStaticInfo);
|
|
340
|
-
let
|
|
411
|
+
let fIndexPrices = indexPrices.map(x=>floatToABK64x64(x));
|
|
412
|
+
let fPrice = await _proxyContract.queryPerpetualPrice(perpId, floatToABK64x64(tradeAmount), fIndexPrices);
|
|
341
413
|
return ABK64x64ToFloat(fPrice);
|
|
342
414
|
}
|
|
343
415
|
|
|
344
416
|
protected static async _queryPerpetualMarkPrice(
|
|
345
417
|
symbol: string,
|
|
346
418
|
symbolToPerpStaticInfo: Map<string, PerpetualStaticInfo>,
|
|
347
|
-
_proxyContract: ethers.Contract
|
|
419
|
+
_proxyContract: ethers.Contract,
|
|
420
|
+
indexPrices: [number, number]
|
|
348
421
|
): Promise<number> {
|
|
349
422
|
let perpId = PerpetualDataHandler.symbolToPerpetualId(symbol, symbolToPerpStaticInfo);
|
|
350
|
-
let
|
|
423
|
+
let [S2, S3] = indexPrices.map(x=>floatToABK64x64(x));
|
|
424
|
+
let ammState = await _proxyContract.getAMMState(perpId, [S2, S3]);
|
|
351
425
|
return ABK64x64ToFloat(ammState[6].mul(ONE_64x64.add(ammState[8])).div(ONE_64x64));
|
|
352
426
|
}
|
|
353
427
|
|
|
354
428
|
protected static async _queryPerpetualState(
|
|
355
429
|
symbol: string,
|
|
356
430
|
symbolToPerpStaticInfo: Map<string, PerpetualStaticInfo>,
|
|
357
|
-
_proxyContract: ethers.Contract
|
|
431
|
+
_proxyContract: ethers.Contract,
|
|
432
|
+
indexPrices: [number, number, boolean, boolean]
|
|
358
433
|
): Promise<PerpetualState> {
|
|
359
434
|
let perpId = PerpetualDataHandler.symbolToPerpetualId(symbol, symbolToPerpStaticInfo);
|
|
360
435
|
let ccy = symbol.split("-");
|
|
361
|
-
let
|
|
436
|
+
let [S2, S3] = [indexPrices[0], indexPrices[1]];
|
|
437
|
+
let ammState = await _proxyContract.getAMMState(perpId, [S2, S3].map(x=>floatToABK64x64(x)));
|
|
362
438
|
let markPrice = ABK64x64ToFloat(ammState[6].mul(ONE_64x64.add(ammState[8])).div(ONE_64x64));
|
|
363
439
|
let state = {
|
|
364
440
|
id: perpId,
|
|
@@ -372,6 +448,7 @@ export default class PerpetualDataHandler {
|
|
|
372
448
|
currentFundingRateBps: ABK64x64ToFloat(ammState[14]) * 1e4,
|
|
373
449
|
openInterestBC: ABK64x64ToFloat(ammState[11]),
|
|
374
450
|
maxPositionBC: ABK64x64ToFloat(ammState[12]),
|
|
451
|
+
isMarketClosed: indexPrices[2] || indexPrices[3]
|
|
375
452
|
};
|
|
376
453
|
if (symbolToPerpStaticInfo.get(symbol)?.collateralCurrencyType == CollaterlCCY.BASE) {
|
|
377
454
|
state.collToQuoteIndexPrice = state.indexPrice;
|
|
@@ -677,17 +754,35 @@ export default class PerpetualDataHandler {
|
|
|
677
754
|
|
|
678
755
|
/**
|
|
679
756
|
* Read config file into NodeSDKConfig interface
|
|
680
|
-
* @param
|
|
757
|
+
* @param configNameOrfileLocation json-file with required variables for config, or name of a default known config
|
|
681
758
|
* @returns NodeSDKConfig
|
|
682
759
|
*/
|
|
683
|
-
public static readSDKConfig(
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
760
|
+
public static readSDKConfig(configNameOrFileLocation: string, version?: string): NodeSDKConfig {
|
|
761
|
+
let config;
|
|
762
|
+
if (/\.json$/.test(configNameOrFileLocation)) {
|
|
763
|
+
// file path
|
|
764
|
+
let configFile = require(configNameOrFileLocation);
|
|
765
|
+
config = <NodeSDKConfig>configFile;
|
|
766
|
+
} else {
|
|
767
|
+
// name
|
|
768
|
+
let configFile = require(DEFAULT_CONFIG);
|
|
769
|
+
configFile = configFile.filter((c: any) => c.name == configNameOrFileLocation);
|
|
770
|
+
if (configFile.length == 0) {
|
|
771
|
+
throw Error(`Config name ${configNameOrFileLocation} not found.`);
|
|
772
|
+
} else if (configFile.length > 1) {
|
|
773
|
+
// TODO: pick one with highest version, unless version is given
|
|
774
|
+
throw Error(`Config name ${configNameOrFileLocation} not unique.`);
|
|
775
|
+
}
|
|
776
|
+
for (let configItem of configFile) {
|
|
777
|
+
if (configItem.name == configNameOrFileLocation) {
|
|
778
|
+
config = <NodeSDKConfig>configItem;
|
|
779
|
+
break;
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
if (config == undefined) {
|
|
784
|
+
throw Error(`Config file ${configNameOrFileLocation} not found.`);
|
|
785
|
+
}
|
|
691
786
|
return config;
|
|
692
787
|
}
|
|
693
788
|
|
|
@@ -701,4 +796,37 @@ export default class PerpetualDataHandler {
|
|
|
701
796
|
const FormatTypes = ethers.utils.FormatTypes;
|
|
702
797
|
return contract.interface.getFunction(functionName).format(FormatTypes.full);
|
|
703
798
|
}
|
|
799
|
+
|
|
800
|
+
/**
|
|
801
|
+
* Gets the pool index (in exchangeInfo) corresponding to a given symbol.
|
|
802
|
+
* @param symbol Symbol of the form ETH-USD-MATIC
|
|
803
|
+
* @returns Pool index
|
|
804
|
+
*/
|
|
805
|
+
public getPoolIndexFromSymbol(symbol: string): number {
|
|
806
|
+
let pools = this.poolStaticInfos!;
|
|
807
|
+
let poolId = PerpetualDataHandler._getPoolIdFromSymbol(symbol, this.poolStaticInfos);
|
|
808
|
+
let k = 0;
|
|
809
|
+
while (k < pools.length) {
|
|
810
|
+
if (pools[k].poolId == poolId) {
|
|
811
|
+
// pool found
|
|
812
|
+
return k;
|
|
813
|
+
}
|
|
814
|
+
k++;
|
|
815
|
+
}
|
|
816
|
+
return -1;
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
public getMarginTokenFromSymbol(symbol: string): string | undefined {
|
|
820
|
+
let pools = this.poolStaticInfos!;
|
|
821
|
+
let poolId = PerpetualDataHandler._getPoolIdFromSymbol(symbol, this.poolStaticInfos);
|
|
822
|
+
let k = 0;
|
|
823
|
+
while (k < pools.length) {
|
|
824
|
+
if (pools[k].poolId == poolId) {
|
|
825
|
+
// pool found
|
|
826
|
+
return pools[k].poolMarginTokenAddr;
|
|
827
|
+
}
|
|
828
|
+
k++;
|
|
829
|
+
}
|
|
830
|
+
return undefined;
|
|
831
|
+
}
|
|
704
832
|
}
|
|
@@ -20,9 +20,6 @@ import {
|
|
|
20
20
|
* ordersInPerpetual: Map<number, OrderStruct> all open orders for the given trader
|
|
21
21
|
* positionInPerpetual: Map<number, MarginAccount> all open positions for the given trader
|
|
22
22
|
*
|
|
23
|
-
* TODO:
|
|
24
|
-
* - update functions for midprice & index & collateral prices without event
|
|
25
|
-
* - testing
|
|
26
23
|
*
|
|
27
24
|
* Get data:
|
|
28
25
|
* - getPerpetualData(perp id (string) or symbol) : PerpetualState. This is a reference!
|