@d8x/perpetuals-sdk 0.0.1

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.
Files changed (46) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +17 -0
  3. package/abi/ERC20.json +288 -0
  4. package/abi/IPerpetualManager.json +4674 -0
  5. package/abi/LimitOrderBook.json +865 -0
  6. package/abi/LimitOrderBookFactory.json +166 -0
  7. package/config/defaultConfig.json +9 -0
  8. package/config/oldConfig.json +9 -0
  9. package/dist/accountTrade.d.ts +54 -0
  10. package/dist/accountTrade.js +164 -0
  11. package/dist/brokerTool.d.ts +41 -0
  12. package/dist/brokerTool.js +129 -0
  13. package/dist/d8XMath.d.ts +71 -0
  14. package/dist/d8XMath.js +162 -0
  15. package/dist/index.d.ts +11 -0
  16. package/dist/index.js +49 -0
  17. package/dist/liquiditatorTool.d.ts +14 -0
  18. package/dist/liquiditatorTool.js +21 -0
  19. package/dist/liquidityProviderTool.d.ts +39 -0
  20. package/dist/liquidityProviderTool.js +100 -0
  21. package/dist/marketData.d.ts +39 -0
  22. package/dist/marketData.js +160 -0
  23. package/dist/nodeSDKTypes.d.ts +130 -0
  24. package/dist/nodeSDKTypes.js +52 -0
  25. package/dist/orderReferrerTool.d.ts +14 -0
  26. package/dist/orderReferrerTool.js +21 -0
  27. package/dist/perpetualDataHandler.d.ts +85 -0
  28. package/dist/perpetualDataHandler.js +474 -0
  29. package/dist/utils.d.ts +37 -0
  30. package/dist/utils.js +84 -0
  31. package/dist/writeAccessHandler.d.ts +36 -0
  32. package/dist/writeAccessHandler.js +95 -0
  33. package/module.d.ts +1 -0
  34. package/package.json +63 -0
  35. package/src/accountTrade.ts +217 -0
  36. package/src/brokerTool.ts +155 -0
  37. package/src/d8XMath.ts +176 -0
  38. package/src/index.ts +32 -0
  39. package/src/liquiditatorTool.ts +21 -0
  40. package/src/liquidityProviderTool.ts +100 -0
  41. package/src/marketData.ts +149 -0
  42. package/src/nodeSDKTypes.ts +158 -0
  43. package/src/orderReferrerTool.ts +17 -0
  44. package/src/perpetualDataHandler.ts +549 -0
  45. package/src/utils.ts +83 -0
  46. package/src/writeAccessHandler.ts +83 -0
@@ -0,0 +1,474 @@
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
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ const ethers_1 = require("ethers");
13
+ const nodeSDKTypes_1 = require("./nodeSDKTypes");
14
+ const utils_1 = require("./utils");
15
+ const d8XMath_1 = require("./d8XMath");
16
+ /**
17
+ * Parent class for AccountTrade and MarketData that handles
18
+ * common data and chain operations
19
+ */
20
+ class PerpetualDataHandler {
21
+ constructor(config) {
22
+ this.proxyContract = null;
23
+ // limit order book
24
+ this.lobFactoryContract = null;
25
+ this.provider = null;
26
+ this.signerOrProvider = null;
27
+ this.symbolToPerpStaticInfo = new Map();
28
+ this.poolStaticInfos = new Array();
29
+ this.symbolToTokenAddrMap = new Map();
30
+ this.nestedPerpetualIDs = new Array();
31
+ this.proxyAddr = config.proxyAddr;
32
+ this.lobFactoryAddr = config.limitOrderBookFactoryAddr;
33
+ this.nodeURL = config.nodeURL;
34
+ this.proxyABI = require(config.proxyABILocation);
35
+ this.lobFactoryABI = require(config.limitOrderBookFactoryABILocation);
36
+ this.lobABI = require(config.limitOrderBookABILocation);
37
+ }
38
+ initContractsAndData(signerOrProvider) {
39
+ return __awaiter(this, void 0, void 0, function* () {
40
+ this.signerOrProvider = signerOrProvider;
41
+ this.proxyContract = new ethers_1.ethers.Contract(this.proxyAddr, this.proxyABI, signerOrProvider);
42
+ this.lobFactoryContract = new ethers_1.ethers.Contract(this.lobFactoryAddr, this.lobFactoryABI, signerOrProvider);
43
+ yield this._fillSymbolMaps(this.proxyContract);
44
+ });
45
+ }
46
+ /**
47
+ * Returns the order-book contract for the symbol if found or fails
48
+ * @param symbol symbol of the form ETH-USD-MATIC
49
+ * @returns order book contract for the perpetual
50
+ */
51
+ getOrderBookContract(symbol) {
52
+ var _a;
53
+ let cleanSymbol = PerpetualDataHandler.symbolToBytes4Symbol(symbol);
54
+ let orderBookAddr = (_a = this.symbolToPerpStaticInfo.get(cleanSymbol)) === null || _a === void 0 ? void 0 : _a.limitOrderBookAddr;
55
+ if (orderBookAddr == "" || orderBookAddr == undefined || this.signerOrProvider == null) {
56
+ throw Error(`no limit order book found for ${symbol} or no signer`);
57
+ }
58
+ let lobContract = new ethers_1.ethers.Contract(orderBookAddr, this.lobABI, this.signerOrProvider);
59
+ return lobContract;
60
+ }
61
+ /**
62
+ * Called when initializing. This function fills this.symbolToTokenAddrMap,
63
+ * and this.nestedPerpetualIDs and this.symbolToPerpStaticInfo
64
+ *
65
+ */
66
+ _fillSymbolMaps(proxyContract) {
67
+ return __awaiter(this, void 0, void 0, function* () {
68
+ if (proxyContract == null || this.lobFactoryContract == null) {
69
+ throw Error("proxy or limit order book not defined");
70
+ }
71
+ this.nestedPerpetualIDs = yield PerpetualDataHandler.getNestedPerpetualIds(proxyContract);
72
+ for (let j = 0; j < this.nestedPerpetualIDs.length; j++) {
73
+ let pool = yield proxyContract.getLiquidityPool(j + 1);
74
+ let poolMarginTokenAddr = pool.marginTokenAddress;
75
+ let perpetualIDs = this.nestedPerpetualIDs[j];
76
+ let poolCCY = undefined;
77
+ let currentSymbols = [];
78
+ let currentSymbolsS3 = [];
79
+ let currentLimitOrderBookAddr = [];
80
+ let ccy = [];
81
+ let mgnRate = [];
82
+ for (let k = 0; k < perpetualIDs.length; k++) {
83
+ let perp = yield proxyContract.getPerpetual(perpetualIDs[k]);
84
+ let base = (0, utils_1.fromBytes4HexString)(perp.S2BaseCCY);
85
+ let quote = (0, utils_1.fromBytes4HexString)(perp.S2QuoteCCY);
86
+ let base3 = (0, utils_1.fromBytes4HexString)(perp.S3BaseCCY);
87
+ let quote3 = (0, utils_1.fromBytes4HexString)(perp.S3QuoteCCY);
88
+ currentSymbols.push(base + "-" + quote);
89
+ currentSymbolsS3.push(base3 + "-" + quote3);
90
+ mgnRate.push((0, d8XMath_1.ABK64x64ToFloat)(perp.fMaintenanceMarginRate));
91
+ // try to find a limit order book
92
+ let lobAddr = yield this.lobFactoryContract.getOrderBookAddress(perpetualIDs[k]);
93
+ currentLimitOrderBookAddr.push(lobAddr);
94
+ // we find out the pool currency by looking at all perpetuals
95
+ // unless for quanto perpetuals, we know the pool currency
96
+ // from the perpetual. This fails if we have a pool with only
97
+ // quanto perpetuals
98
+ if (perp.eCollateralCurrency == nodeSDKTypes_1.COLLATERAL_CURRENCY_BASE) {
99
+ poolCCY = base;
100
+ ccy.push(nodeSDKTypes_1.CollaterlCCY.BASE);
101
+ }
102
+ else if (perp.eCollateralCurrency == nodeSDKTypes_1.COLLATERAL_CURRENCY_QUOTE) {
103
+ poolCCY = quote;
104
+ ccy.push(nodeSDKTypes_1.CollaterlCCY.QUOTE);
105
+ }
106
+ else {
107
+ ccy.push(nodeSDKTypes_1.CollaterlCCY.QUANTO);
108
+ }
109
+ }
110
+ if (perpetualIDs.length == 0) {
111
+ continue;
112
+ }
113
+ if (poolCCY == undefined) {
114
+ throw Error("Pool only has quanto perps, unable to determine collateral currency");
115
+ }
116
+ let oracleFactoryAddr = yield proxyContract.getOracleFactory();
117
+ let info = {
118
+ poolId: j + 1,
119
+ poolMarginSymbol: poolCCY,
120
+ poolMarginTokenAddr: poolMarginTokenAddr,
121
+ shareTokenAddr: pool.shareTokenAddress,
122
+ oracleFactoryAddr: oracleFactoryAddr,
123
+ };
124
+ this.poolStaticInfos.push(info);
125
+ let currentSymbols3 = currentSymbols.map((x) => x + "-" + poolCCY);
126
+ // push into map
127
+ for (let k = 0; k < perpetualIDs.length; k++) {
128
+ this.symbolToPerpStaticInfo.set(currentSymbols3[k], {
129
+ id: perpetualIDs[k],
130
+ limitOrderBookAddr: currentLimitOrderBookAddr[k],
131
+ maintenanceMarginRate: mgnRate[k],
132
+ collateralCurrencyType: ccy[k],
133
+ S2Symbol: currentSymbols[k],
134
+ S3Symbol: currentSymbolsS3[k],
135
+ });
136
+ }
137
+ // push margin token address into map
138
+ this.symbolToTokenAddrMap.set(poolCCY, poolMarginTokenAddr);
139
+ }
140
+ });
141
+ }
142
+ getSymbolFromPoolId(poolId) {
143
+ return PerpetualDataHandler._getSymbolFromPoolId(poolId, this.poolStaticInfos);
144
+ }
145
+ getPoolIdFromSymbol(symbol) {
146
+ return PerpetualDataHandler._getPoolIdFromSymbol(symbol, this.poolStaticInfos);
147
+ }
148
+ static _getSymbolFromPoolId(poolId, staticInfos) {
149
+ let idx = poolId - 1;
150
+ return staticInfos[idx].poolMarginSymbol;
151
+ }
152
+ static _getPoolIdFromSymbol(symbol, staticInfos) {
153
+ let symbols = symbol.split("-");
154
+ //in case user provided ETH-USD-MATIC instead of MATIC; or similar
155
+ if (symbols.length == 3) {
156
+ symbol = symbols[2];
157
+ }
158
+ let cleanSymbol = (0, utils_1.to4Chars)(symbol);
159
+ cleanSymbol = cleanSymbol.replace(/\0/g, "");
160
+ let j = 0;
161
+ while (j < staticInfos.length && staticInfos[j].poolMarginSymbol != cleanSymbol) {
162
+ j++;
163
+ }
164
+ if (j == staticInfos.length) {
165
+ throw new Error(`no pool found for symbol ${symbol}`);
166
+ }
167
+ return j + 1;
168
+ }
169
+ static getNestedPerpetualIds(_proxyContract) {
170
+ return __awaiter(this, void 0, void 0, function* () {
171
+ let poolCount = yield _proxyContract.getPoolCount();
172
+ let poolIds = new Array(poolCount);
173
+ for (let i = 1; i < poolCount + 1; i++) {
174
+ let perpetualCount = yield _proxyContract.getPerpetualCountInPool(i);
175
+ poolIds[i - 1] = new Array(perpetualCount);
176
+ for (let j = 0; j < perpetualCount; j++) {
177
+ let id = yield _proxyContract.getPerpetualId(i, j);
178
+ poolIds[i - 1][j] = id;
179
+ }
180
+ }
181
+ return poolIds;
182
+ });
183
+ }
184
+ static getMarginAccount(traderAddr, symbol, symbolToPerpStaticInfo, _proxyContract) {
185
+ return __awaiter(this, void 0, void 0, function* () {
186
+ let cleanSymbol = PerpetualDataHandler.symbolToBytes4Symbol(symbol);
187
+ let perpId = PerpetualDataHandler.symbolToPerpetualId(cleanSymbol, symbolToPerpStaticInfo);
188
+ const idx_cash = 3;
189
+ const idx_notional = 4;
190
+ const idx_locked_in = 5;
191
+ const idx_mark_price = 8;
192
+ const idx_lvg = 7;
193
+ const idx_s3 = 9;
194
+ let traderState = yield _proxyContract.getTraderState(perpId, traderAddr);
195
+ let isEmpty = traderState[idx_notional] == 0;
196
+ let cash = (0, d8XMath_1.ABK64x64ToFloat)(traderState[idx_cash]);
197
+ let S2Liq = 0, S3Liq = 0, tau = Infinity, pnl = 0, unpaidFundingCC = 0, fLockedIn = ethers_1.BigNumber.from(0), side = nodeSDKTypes_1.CLOSED_SIDE, entryPrice = 0;
198
+ if (!isEmpty) {
199
+ [S2Liq, S3Liq, tau, pnl, unpaidFundingCC] = PerpetualDataHandler._calculateLiquidationPrice(cleanSymbol, traderState, symbolToPerpStaticInfo);
200
+ fLockedIn = traderState[idx_locked_in];
201
+ side = traderState[idx_locked_in] > 0 ? nodeSDKTypes_1.BUY_SIDE : nodeSDKTypes_1.SELL_SIDE;
202
+ entryPrice = (0, d8XMath_1.ABK64x64ToFloat)((0, d8XMath_1.div64x64)(fLockedIn, traderState[idx_notional]));
203
+ }
204
+ let mgn = {
205
+ symbol: symbol,
206
+ positionNotionalBaseCCY: isEmpty ? 0 : (0, d8XMath_1.ABK64x64ToFloat)(traderState[idx_notional]),
207
+ side: isEmpty ? nodeSDKTypes_1.CLOSED_SIDE : side,
208
+ entryPrice: isEmpty ? 0 : entryPrice,
209
+ leverage: isEmpty ? 0 : (0, d8XMath_1.ABK64x64ToFloat)(traderState[idx_lvg]),
210
+ markPrice: (0, d8XMath_1.ABK64x64ToFloat)(traderState[idx_mark_price].abs()),
211
+ unrealizedPnlQuoteCCY: isEmpty ? 0 : pnl,
212
+ unrealizedFundingCollateralCCY: isEmpty ? 0 : unpaidFundingCC,
213
+ collateralCC: cash,
214
+ liquidationLvg: isEmpty ? 0 : 1 / tau,
215
+ liquidationPrice: isEmpty ? [0, 0] : [S2Liq, S3Liq],
216
+ collToQuoteConversion: (0, d8XMath_1.ABK64x64ToFloat)(traderState[idx_s3]),
217
+ };
218
+ return mgn;
219
+ });
220
+ }
221
+ /**
222
+ * Liquidation price
223
+ * @param cleanSymbol symbol after calling symbolToBytes4Symbol
224
+ * @param traderState BigInt array according to smart contract
225
+ * @param symbolToPerpStaticInfo mapping symbol->PerpStaticInfo
226
+ * @returns liquidation mark-price, corresponding collateral/quote conversion
227
+ */
228
+ static _calculateLiquidationPrice(cleanSymbol, traderState, symbolToPerpStaticInfo) {
229
+ const idx_availableCashCC = 2;
230
+ const idx_cash = 3;
231
+ const idx_notional = 4;
232
+ const idx_locked_in = 5;
233
+ const idx_mark_price = 8;
234
+ const idx_s3 = 9;
235
+ const idx_s2 = 10;
236
+ let S2Liq;
237
+ let S3Liq = (0, d8XMath_1.ABK64x64ToFloat)(traderState[idx_s3]);
238
+ let perpInfo = symbolToPerpStaticInfo.get(cleanSymbol);
239
+ if (perpInfo == undefined) {
240
+ throw new Error(`no info for perpetual ${cleanSymbol}`);
241
+ }
242
+ let tau = perpInfo.maintenanceMarginRate;
243
+ let lockedInValueQC = (0, d8XMath_1.ABK64x64ToFloat)(traderState[idx_locked_in]);
244
+ let position = (0, d8XMath_1.ABK64x64ToFloat)(traderState[idx_notional]);
245
+ let cashCC = (0, d8XMath_1.ABK64x64ToFloat)(traderState[idx_availableCashCC]);
246
+ let Sm = (0, d8XMath_1.ABK64x64ToFloat)(traderState[idx_mark_price]);
247
+ let unpaidFundingCC = (0, d8XMath_1.ABK64x64ToFloat)(traderState[idx_availableCashCC].sub(traderState[idx_cash]));
248
+ let unpaidFunding = unpaidFundingCC;
249
+ if (perpInfo.collateralCurrencyType == nodeSDKTypes_1.CollaterlCCY.BASE) {
250
+ S2Liq = (0, d8XMath_1.calculateLiquidationPriceCollateralBase)(lockedInValueQC, position, cashCC, tau);
251
+ S3Liq = S2Liq;
252
+ unpaidFunding = unpaidFunding / (0, d8XMath_1.ABK64x64ToFloat)(traderState[idx_s2]);
253
+ }
254
+ else if (perpInfo.collateralCurrencyType == nodeSDKTypes_1.CollaterlCCY.QUANTO) {
255
+ let S3 = S3Liq;
256
+ S3Liq = S3;
257
+ S2Liq = (0, d8XMath_1.calculateLiquidationPriceCollateralQuanto)(lockedInValueQC, position, cashCC, tau, S3, Sm);
258
+ unpaidFunding = unpaidFunding / S3;
259
+ }
260
+ else {
261
+ S2Liq = (0, d8XMath_1.calculateLiquidationPriceCollateralQuote)(lockedInValueQC, position, cashCC, tau);
262
+ }
263
+ let pnl = position * Sm - lockedInValueQC - unpaidFunding;
264
+ return [S2Liq, S3Liq, tau, pnl, unpaidFundingCC];
265
+ }
266
+ /**
267
+ * Finds the perpetual id for a symbol of the form
268
+ * <base>-<quote>-<collateral>. The function first converts the
269
+ * token names into bytes4 representation
270
+ * @param symbol symbol (e.g., BTC-USD-MATIC)
271
+ * @param symbolToPerpStaticInfo map that contains the bytes4-symbol to PerpetualStaticInfo
272
+ * including id mapping
273
+ * @returns perpetual id or it fails
274
+ */
275
+ static symbolToPerpetualId(symbol, symbolToPerpStaticInfo) {
276
+ var _a;
277
+ let cleanSymbol = PerpetualDataHandler.symbolToBytes4Symbol(symbol);
278
+ let id = (_a = symbolToPerpStaticInfo.get(cleanSymbol)) === null || _a === void 0 ? void 0 : _a.id;
279
+ if (id == undefined) {
280
+ throw Error(`No perpetual found for symbol ${symbol}`);
281
+ }
282
+ return id;
283
+ }
284
+ static symbolToBytes4Symbol(symbol) {
285
+ //split by dashes BTC-USD-MATIC
286
+ let symbols = symbol.split("-");
287
+ if (symbols.length != 3) {
288
+ throw Error(`Symbol ${symbol} not valid. Expecting CCY-CCY-CCY format`);
289
+ }
290
+ //transform into bytes4 currencies (without the space): "BTC", "USD", "MATC"
291
+ symbols = symbols.map((x) => {
292
+ let v = (0, utils_1.to4Chars)(x);
293
+ v = v.replace(/\0/g, "");
294
+ return v;
295
+ });
296
+ // concatenate and find perpetual Id in map
297
+ return symbols[0] + "-" + symbols[1] + "-" + symbols[2];
298
+ }
299
+ static _getByValue(map, searchValue) {
300
+ for (let [key, value] of map.entries()) {
301
+ if (value === searchValue) {
302
+ return key;
303
+ }
304
+ }
305
+ }
306
+ static fromSmartContractOrder(order, symbolToPerpInfoMap) {
307
+ // find symbol of perpetual id
308
+ let symbol = PerpetualDataHandler._getByValue(symbolToPerpInfoMap, order.iPerpetualId);
309
+ let side = order.fAmount > 0 ? nodeSDKTypes_1.BUY_SIDE : nodeSDKTypes_1.SELL_SIDE;
310
+ let limitPrice, stopPrice;
311
+ let fLimitPrice = ethers_1.BigNumber.from(order.fLimitPrice);
312
+ if (fLimitPrice.eq(0) || fLimitPrice.eq(nodeSDKTypes_1.MAX_64x64)) {
313
+ limitPrice = undefined;
314
+ }
315
+ else {
316
+ limitPrice = (0, d8XMath_1.ABK64x64ToFloat)(fLimitPrice);
317
+ }
318
+ let fStopPrice = ethers_1.BigNumber.from(order.fTriggerPrice);
319
+ if (fStopPrice.eq(0) || fStopPrice.eq(nodeSDKTypes_1.MAX_64x64)) {
320
+ stopPrice = undefined;
321
+ }
322
+ else {
323
+ stopPrice = (0, d8XMath_1.ABK64x64ToFloat)(fStopPrice);
324
+ }
325
+ let userOrder = {
326
+ symbol: symbol,
327
+ side: side,
328
+ type: PerpetualDataHandler._flagToOrderType(order),
329
+ quantity: Math.abs((0, d8XMath_1.ABK64x64ToFloat)(ethers_1.BigNumber.from(order.fAmount))),
330
+ reduceOnly: (0, utils_1.containsFlag)(ethers_1.BigNumber.from(order.flags), nodeSDKTypes_1.MASK_CLOSE_ONLY),
331
+ limitPrice: limitPrice,
332
+ keepPositionLvg: (0, utils_1.containsFlag)(ethers_1.BigNumber.from(order.flags), nodeSDKTypes_1.MASK_KEEP_POS_LEVERAGE),
333
+ brokerFeeTbps: Number(order.brokerFeeTbps),
334
+ brokerAddr: order.brokerAddr,
335
+ brokerSignature: order.brokerSignature,
336
+ stopPrice: stopPrice,
337
+ leverage: (0, d8XMath_1.ABK64x64ToFloat)(ethers_1.BigNumber.from(order.fLeverage)),
338
+ deadline: Number(order.iDeadline),
339
+ timestamp: Number(order.createdTimestamp),
340
+ };
341
+ return userOrder;
342
+ }
343
+ /**
344
+ * Transform the convenient form of the order into a smart-contract accepted type of order
345
+ * @param order order type
346
+ * @param traderAddr address of the trader
347
+ * @param symbolToPerpetualMap mapping of symbol to perpetual Id
348
+ * @returns SmartContractOrder
349
+ */
350
+ static toSmartContractOrder(order, traderAddr, perpStaticInfo) {
351
+ let flags = PerpetualDataHandler._orderTypeToFlag(order);
352
+ let brokerSig = order.brokerSignature == undefined ? [] : order.brokerSignature;
353
+ let perpetualId = PerpetualDataHandler.symbolToPerpetualId(order.symbol, perpStaticInfo);
354
+ let fAmount;
355
+ if (order.side == nodeSDKTypes_1.BUY_SIDE) {
356
+ fAmount = (0, d8XMath_1.floatToABK64x64)(Math.abs(order.quantity));
357
+ }
358
+ else if (order.side == nodeSDKTypes_1.SELL_SIDE) {
359
+ fAmount = (0, d8XMath_1.floatToABK64x64)(-Math.abs(order.quantity));
360
+ }
361
+ else {
362
+ throw Error(`invalid side in order spec, use ${nodeSDKTypes_1.BUY_SIDE} or ${nodeSDKTypes_1.SELL_SIDE}`);
363
+ }
364
+ let fLimitPrice;
365
+ if (order.limitPrice == undefined) {
366
+ // we need to set the limit price to infinity or zero for
367
+ // the trade to go through
368
+ // Also: stop orders always have limits set, so even for this case
369
+ // we set the limit to 0 or infinity
370
+ fLimitPrice = order.side == nodeSDKTypes_1.BUY_SIDE ? nodeSDKTypes_1.MAX_64x64 : ethers_1.BigNumber.from(0);
371
+ }
372
+ else {
373
+ fLimitPrice = (0, d8XMath_1.floatToABK64x64)(order.limitPrice);
374
+ }
375
+ let iDeadline = order.deadline == undefined ? Date.now() + nodeSDKTypes_1.ORDER_MAX_DURATION_SEC : order.deadline;
376
+ let fTriggerPrice = order.stopPrice == undefined ? ethers_1.BigNumber.from(0) : (0, d8XMath_1.floatToABK64x64)(order.stopPrice);
377
+ if (order.reduceOnly != undefined && order.reduceOnly == true) {
378
+ }
379
+ let smOrder = {
380
+ flags: flags,
381
+ iPerpetualId: ethers_1.BigNumber.from(perpetualId),
382
+ brokerFeeTbps: order.brokerFeeTbps == undefined ? ethers_1.BigNumber.from(0) : ethers_1.BigNumber.from(order.brokerFeeTbps),
383
+ traderAddr: traderAddr,
384
+ brokerAddr: order.brokerAddr == undefined ? nodeSDKTypes_1.ZERO_ADDRESS : order.brokerAddr,
385
+ referrerAddr: nodeSDKTypes_1.ZERO_ADDRESS,
386
+ brokerSignature: brokerSig,
387
+ fAmount: fAmount,
388
+ fLimitPrice: fLimitPrice,
389
+ fTriggerPrice: fTriggerPrice,
390
+ fLeverage: order.leverage == undefined ? ethers_1.BigNumber.from(0) : (0, d8XMath_1.floatToABK64x64)(order.leverage),
391
+ iDeadline: ethers_1.BigNumber.from(iDeadline),
392
+ createdTimestamp: ethers_1.BigNumber.from(order.timestamp),
393
+ };
394
+ return smOrder;
395
+ }
396
+ static _flagToOrderType(order) {
397
+ let hasTrigger = ethers_1.BigNumber.from(order.fTriggerPrice).eq(0);
398
+ let hasLimit = !ethers_1.BigNumber.from(order.fTriggerPrice).eq(0) || !ethers_1.BigNumber.from(order.fTriggerPrice).eq(nodeSDKTypes_1.MAX_64x64);
399
+ if (hasTrigger && hasLimit) {
400
+ return nodeSDKTypes_1.ORDER_TYPE_STOP_LIMIT;
401
+ }
402
+ else if (hasTrigger && !hasLimit) {
403
+ return nodeSDKTypes_1.ORDER_TYPE_STOP_MARKET;
404
+ }
405
+ else if (hasLimit && (0, utils_1.containsFlag)(ethers_1.BigNumber.from(order.flags), nodeSDKTypes_1.MASK_LIMIT_ORDER)) {
406
+ return nodeSDKTypes_1.ORDER_TYPE_LIMIT;
407
+ }
408
+ else {
409
+ return nodeSDKTypes_1.ORDER_TYPE_MARKET;
410
+ }
411
+ }
412
+ /**
413
+ * Determine the correct order flags based on the order-properties.
414
+ * Checks for some misspecifications.
415
+ * @param order order type
416
+ * @returns BigNumber flags
417
+ */
418
+ static _orderTypeToFlag(order) {
419
+ let flag;
420
+ switch (order.type) {
421
+ case nodeSDKTypes_1.ORDER_TYPE_LIMIT:
422
+ flag = nodeSDKTypes_1.MASK_LIMIT_ORDER;
423
+ break;
424
+ case nodeSDKTypes_1.ORDER_TYPE_MARKET:
425
+ flag = nodeSDKTypes_1.MASK_MARKET_ORDER;
426
+ break;
427
+ case nodeSDKTypes_1.ORDER_TYPE_STOP_MARKET:
428
+ flag = nodeSDKTypes_1.MASK_STOP_ORDER;
429
+ break;
430
+ case nodeSDKTypes_1.ORDER_TYPE_STOP_LIMIT:
431
+ flag = nodeSDKTypes_1.MASK_STOP_ORDER;
432
+ break;
433
+ default: {
434
+ throw Error(`Order type ${order.type} not found.`);
435
+ }
436
+ }
437
+ if (order.keepPositionLvg != undefined && order.keepPositionLvg) {
438
+ flag = (0, utils_1.combineFlags)(flag, nodeSDKTypes_1.MASK_KEEP_POS_LEVERAGE);
439
+ }
440
+ if (order.reduceOnly != undefined && order.reduceOnly) {
441
+ flag = (0, utils_1.combineFlags)(flag, nodeSDKTypes_1.MASK_CLOSE_ONLY);
442
+ }
443
+ if ((order.type == nodeSDKTypes_1.ORDER_TYPE_LIMIT || order.type == nodeSDKTypes_1.ORDER_TYPE_STOP_LIMIT) && order.limitPrice == undefined) {
444
+ throw Error(`Order type ${order.type} requires limit price.`);
445
+ }
446
+ if ((order.type == nodeSDKTypes_1.ORDER_TYPE_STOP_MARKET || order.type == nodeSDKTypes_1.ORDER_TYPE_STOP_LIMIT) && order.stopPrice == undefined) {
447
+ throw Error(`Order type ${order.type} requires trigger price.`);
448
+ }
449
+ if ((order.type == nodeSDKTypes_1.ORDER_TYPE_MARKET || order.type == nodeSDKTypes_1.ORDER_TYPE_LIMIT) && order.stopPrice != undefined) {
450
+ throw Error(`Order type ${order.type} has no trigger price.`);
451
+ }
452
+ if (order.type != nodeSDKTypes_1.ORDER_TYPE_MARKET && order.stopPrice != undefined) {
453
+ throw Error(`Order type ${order.type} has no trigger price.`);
454
+ }
455
+ return flag;
456
+ }
457
+ /**
458
+ * Read config file into NodeSDKConfig interface
459
+ * @param fileLocation json-file with required variables for config
460
+ * @returns NodeSDKConfig
461
+ */
462
+ static readSDKConfig(fileLocation) {
463
+ if (fileLocation == nodeSDKTypes_1.DEFAULT_CONFIG_MAINNET_NAME) {
464
+ fileLocation = nodeSDKTypes_1.DEFAULT_CONFIG_MAINNET;
465
+ }
466
+ else if (fileLocation == nodeSDKTypes_1.DEFAULT_CONFIG_TESTNET_NAME) {
467
+ fileLocation = nodeSDKTypes_1.DEFAULT_CONFIG_TESTNET;
468
+ }
469
+ let configFile = require(fileLocation);
470
+ let config = configFile;
471
+ return config;
472
+ }
473
+ }
474
+ exports.default = PerpetualDataHandler;
@@ -0,0 +1,37 @@
1
+ /// <reference types="node" />
2
+ import { BigNumber } from "ethers";
3
+ /**
4
+ *
5
+ * @param s string to shorten/extend to 4 characters
6
+ * @returns string with 4 characters (or characters + null chars)
7
+ */
8
+ export declare function to4Chars(s: string): string;
9
+ /**
10
+ * Converts string into 4-character bytes4
11
+ * uses to4Chars to first convert the string into
12
+ * 4 characters.
13
+ * Resulting buffer can be used with smart contract to
14
+ * identify tokens (BTC, USDC, MATIC etc.)
15
+ * @param s string to encode into bytes4
16
+ * @returns buffer
17
+ */
18
+ export declare function toBytes4(s: string): Buffer;
19
+ /**
20
+ * Decodes a buffer encoded with toBytes4 into
21
+ * a string. The string is the result of to4Chars of the
22
+ * originally encoded string stripped from null-chars
23
+ * @param b correctly encoded bytes4 buffer using toBytes4
24
+ * @returns string decoded into to4Chars-type string without null characters
25
+ */
26
+ export declare function fromBytes4(b: Buffer): string;
27
+ /**
28
+ * Decodes the bytes4 encoded string received from the
29
+ * smart contract as a hex-number in string-format
30
+ * @param s string representing a hex-number ("0x...")
31
+ * @returns x of to4Chars(x) stripped from null-chars,
32
+ * where x was originally encoded and
33
+ * returned by the smart contract as bytes4
34
+ */
35
+ export declare function fromBytes4HexString(s: string): string;
36
+ export declare function combineFlags(f1: BigNumber, f2: BigNumber): BigNumber;
37
+ export declare function containsFlag(f1: BigNumber, f2: BigNumber): boolean;
package/dist/utils.js ADDED
@@ -0,0 +1,84 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.containsFlag = exports.combineFlags = exports.fromBytes4HexString = exports.fromBytes4 = exports.toBytes4 = exports.to4Chars = void 0;
4
+ const ethers_1 = require("ethers");
5
+ const ethers = require("ethers");
6
+ function _isVocal(char) {
7
+ char = char.toLowerCase();
8
+ return char == "a" || char == "e" || char == "i" || char == "o" || char == "u";
9
+ }
10
+ /**
11
+ *
12
+ * @param s string to shorten/extend to 4 characters
13
+ * @returns string with 4 characters (or characters + null chars)
14
+ */
15
+ function to4Chars(s) {
16
+ while (s.length < 4) {
17
+ s = s + "\0";
18
+ }
19
+ let k = s.length - 1;
20
+ while (s.length > 4 && k >= 0) {
21
+ // chop off vocals from the end of string
22
+ // e.g. MATIC -> MATC
23
+ if (_isVocal(s.charAt(k))) {
24
+ s = s.substring(0, k) + s.substring(k + 1, s.length);
25
+ }
26
+ k--;
27
+ }
28
+ s = s.substring(0, 4);
29
+ return s;
30
+ }
31
+ exports.to4Chars = to4Chars;
32
+ /**
33
+ * Converts string into 4-character bytes4
34
+ * uses to4Chars to first convert the string into
35
+ * 4 characters.
36
+ * Resulting buffer can be used with smart contract to
37
+ * identify tokens (BTC, USDC, MATIC etc.)
38
+ * @param s string to encode into bytes4
39
+ * @returns buffer
40
+ */
41
+ function toBytes4(s) {
42
+ s = to4Chars(s);
43
+ let valBuff = Buffer.from(s, "ascii");
44
+ return valBuff;
45
+ }
46
+ exports.toBytes4 = toBytes4;
47
+ /**
48
+ * Decodes a buffer encoded with toBytes4 into
49
+ * a string. The string is the result of to4Chars of the
50
+ * originally encoded string stripped from null-chars
51
+ * @param b correctly encoded bytes4 buffer using toBytes4
52
+ * @returns string decoded into to4Chars-type string without null characters
53
+ */
54
+ function fromBytes4(b) {
55
+ let val = b.toString("ascii");
56
+ val = val.replace(/\0/g, "");
57
+ return val;
58
+ }
59
+ exports.fromBytes4 = fromBytes4;
60
+ /**
61
+ * Decodes the bytes4 encoded string received from the
62
+ * smart contract as a hex-number in string-format
63
+ * @param s string representing a hex-number ("0x...")
64
+ * @returns x of to4Chars(x) stripped from null-chars,
65
+ * where x was originally encoded and
66
+ * returned by the smart contract as bytes4
67
+ */
68
+ function fromBytes4HexString(s) {
69
+ let res = "";
70
+ for (let k = 2; k < s.length; k = k + 2) {
71
+ res = res + String.fromCharCode(parseInt(s.substring(k, k + 2), 16));
72
+ }
73
+ res = res.replace(/\0/g, "");
74
+ return res;
75
+ }
76
+ exports.fromBytes4HexString = fromBytes4HexString;
77
+ function combineFlags(f1, f2) {
78
+ return ethers_1.BigNumber.from(parseInt(f1.toString()) | parseInt(f2.toString()));
79
+ }
80
+ exports.combineFlags = combineFlags;
81
+ function containsFlag(f1, f2) {
82
+ return (parseInt(f1.toString()) & parseInt(f2.toString())) > 0;
83
+ }
84
+ exports.containsFlag = containsFlag;
@@ -0,0 +1,36 @@
1
+ import { BigNumber, ethers } from "ethers";
2
+ import PerpetualDataHandler from "./perpetualDataHandler";
3
+ import { NodeSDKConfig } from "./nodeSDKTypes";
4
+ /**
5
+ * This is a parent class for the classes that require
6
+ * write access to the contracts.
7
+ * This class requires a private key and executes smart-contract interaction that
8
+ * require gas-payments.
9
+ */
10
+ export default class WriteAccessHandler extends PerpetualDataHandler {
11
+ protected privateKey: string;
12
+ protected traderAddr: string;
13
+ protected signer: ethers.Wallet | null;
14
+ protected gasLimit: number;
15
+ protected chainId: number;
16
+ /**
17
+ * Constructor
18
+ * @param config configuration
19
+ * @param privateKey private key of account that trades
20
+ */
21
+ constructor(config: NodeSDKConfig, privateKey: string);
22
+ /**
23
+ * Initialize the AccountTrade-Class with this function
24
+ * to create instance of D8X perpetual contract and gather information
25
+ * about perpetual currencies
26
+ */
27
+ createProxyInstance(): Promise<void>;
28
+ /**
29
+ * Set allowance for ar margin token (e.g., MATIC, ETH, USDC)
30
+ * @param symbol token in 'long-form' such as MATIC, symbol also fine (ETH-USD-MATIC)
31
+ * @param amount optional, amount to approve if not 'infinity'
32
+ * @returns transaction hash
33
+ */
34
+ setAllowance(symbol: string, amount?: number | undefined): Promise<string>;
35
+ protected static _setAllowance(tokenAddr: string, proxyAddr: string, signer: ethers.Wallet, amount: BigNumber): Promise<string>;
36
+ }