@d8x/perpetuals-sdk 0.1.4 → 0.1.5
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/abi/central-park/IPerpetualManager.json +11 -5
- package/config/defaultConfig.json +2 -2
- package/dist/liquidatorTool.d.ts +1 -1
- package/dist/liquidatorTool.js +16 -4
- package/dist/marketData.d.ts +8 -0
- package/dist/marketData.js +22 -13
- package/dist/nodeSDKTypes.d.ts +1 -0
- package/dist/perpetualDataHandler.js +8 -1
- package/dist/priceFeeds.d.ts +13 -13
- package/dist/priceFeeds.js +25 -19
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/writeAccessHandler.d.ts +2 -2
- package/dist/writeAccessHandler.js +1 -1
- package/package.json +1 -1
- package/src/liquidatorTool.ts +25 -5
- package/src/marketData.ts +35 -31
- package/src/nodeSDKTypes.ts +3 -2
- package/src/perpetualDataHandler.ts +12 -2
- package/src/priceFeeds.ts +113 -104
- package/src/version.ts +1 -1
- package/src/writeAccessHandler.ts +2 -2
|
@@ -3012,12 +3012,12 @@
|
|
|
3012
3012
|
"type": "int128"
|
|
3013
3013
|
},
|
|
3014
3014
|
{
|
|
3015
|
-
"internalType": "
|
|
3016
|
-
"name": "
|
|
3017
|
-
"type": "
|
|
3015
|
+
"internalType": "bool",
|
|
3016
|
+
"name": "_isBuy",
|
|
3017
|
+
"type": "bool"
|
|
3018
3018
|
}
|
|
3019
3019
|
],
|
|
3020
|
-
"name": "
|
|
3020
|
+
"name": "getMaxSignedOpenTradeSizeForPos",
|
|
3021
3021
|
"outputs": [
|
|
3022
3022
|
{
|
|
3023
3023
|
"internalType": "int128",
|
|
@@ -4834,7 +4834,13 @@
|
|
|
4834
4834
|
}
|
|
4835
4835
|
],
|
|
4836
4836
|
"name": "tradeViaOrderBook",
|
|
4837
|
-
"outputs": [
|
|
4837
|
+
"outputs": [
|
|
4838
|
+
{
|
|
4839
|
+
"internalType": "bool",
|
|
4840
|
+
"name": "",
|
|
4841
|
+
"type": "bool"
|
|
4842
|
+
}
|
|
4843
|
+
],
|
|
4838
4844
|
"stateMutability": "nonpayable",
|
|
4839
4845
|
"type": "function"
|
|
4840
4846
|
},
|
|
@@ -23,12 +23,12 @@
|
|
|
23
23
|
},
|
|
24
24
|
{
|
|
25
25
|
"name": "central-park",
|
|
26
|
-
"version":
|
|
26
|
+
"version": 5.0,
|
|
27
27
|
"proxyAddr": "0x4F1C7EE9E881Cc735f39Ca36c649ba9E930B4E4e",
|
|
28
28
|
"nodeURL": "https://polygon-mumbai.blockpi.network/v1/rpc/public",
|
|
29
29
|
"priceFeedConfigNetwork": "testnet",
|
|
30
30
|
"proxyABILocation": "../abi/central-park/IPerpetualManager.json",
|
|
31
|
-
"limitOrderBookFactoryAddr": "
|
|
31
|
+
"limitOrderBookFactoryAddr": "0xdb43AdBb66925B7529b400C31879e499a72f6fad",
|
|
32
32
|
"limitOrderBookFactoryABILocation": "../abi/central-park/LimitOrderBookFactory.json",
|
|
33
33
|
"limitOrderBookABILocation": "../abi/central-park/LimitOrderBook.json",
|
|
34
34
|
"symbolListLocation": "../config/symbolList.json"
|
package/dist/liquidatorTool.d.ts
CHANGED
|
@@ -59,7 +59,7 @@ export default class LiquidatorTool extends WriteAccessHandler {
|
|
|
59
59
|
* If not, the position can be liquidated.
|
|
60
60
|
* @param {string} symbol Symbol of the form ETH-USD-MATIC.
|
|
61
61
|
* @param {string} traderAddr Address of the trader whose position you want to assess.
|
|
62
|
-
* @param {[
|
|
62
|
+
* @param {number[]} indexPrices optional, index price S2/S3 for which we test
|
|
63
63
|
* @example
|
|
64
64
|
* import { LiquidatorTool, PerpetualDataHandler } from '@d8x/perpetuals-sdk';
|
|
65
65
|
* async function main() {
|
package/dist/liquidatorTool.js
CHANGED
|
@@ -13,6 +13,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
13
13
|
};
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
15
|
const writeAccessHandler_1 = __importDefault(require("./writeAccessHandler"));
|
|
16
|
+
const d8XMath_1 = require("./d8XMath");
|
|
16
17
|
/**
|
|
17
18
|
* Functions to liquidate traders. This class requires a private key
|
|
18
19
|
* and executes smart-contract interactions that require gas-payments.
|
|
@@ -92,7 +93,7 @@ class LiquidatorTool extends writeAccessHandler_1.default {
|
|
|
92
93
|
* If not, the position can be liquidated.
|
|
93
94
|
* @param {string} symbol Symbol of the form ETH-USD-MATIC.
|
|
94
95
|
* @param {string} traderAddr Address of the trader whose position you want to assess.
|
|
95
|
-
* @param {[
|
|
96
|
+
* @param {number[]} indexPrices optional, index price S2/S3 for which we test
|
|
96
97
|
* @example
|
|
97
98
|
* import { LiquidatorTool, PerpetualDataHandler } from '@d8x/perpetuals-sdk';
|
|
98
99
|
* async function main() {
|
|
@@ -124,12 +125,23 @@ class LiquidatorTool extends writeAccessHandler_1.default {
|
|
|
124
125
|
let obj = yield this.priceFeedGetter.fetchPricesForPerpetual(symbol);
|
|
125
126
|
indexPrices = [obj.idxPrices[0], obj.idxPrices[1]];
|
|
126
127
|
}
|
|
127
|
-
let traderState = yield this.proxyContract.getTraderState(perpID, traderAddr, indexPrices);
|
|
128
|
+
let traderState = yield this.proxyContract.getTraderState(perpID, traderAddr, indexPrices.map((x) => (0, d8XMath_1.floatToABK64x64)(x)));
|
|
128
129
|
if (traderState[idx_notional] == 0) {
|
|
129
130
|
// trader does not have open position
|
|
130
|
-
return
|
|
131
|
+
return true;
|
|
131
132
|
}
|
|
132
|
-
|
|
133
|
+
// calculate margin from traderstate
|
|
134
|
+
const idx_maintenanceMgnRate = 10;
|
|
135
|
+
const idx_marginAccountPositionBC = 4;
|
|
136
|
+
const idx_collateralToQuoteConversion = 9;
|
|
137
|
+
const idx_marginBalance = 0;
|
|
138
|
+
const maintMgnRate = (0, d8XMath_1.ABK64x64ToFloat)(traderState[idx_maintenanceMgnRate]);
|
|
139
|
+
const pos = (0, d8XMath_1.ABK64x64ToFloat)(traderState[idx_marginAccountPositionBC]);
|
|
140
|
+
const marginbalance = (0, d8XMath_1.ABK64x64ToFloat)(traderState[idx_marginBalance]);
|
|
141
|
+
const coll2quote = (0, d8XMath_1.ABK64x64ToFloat)(traderState[idx_collateralToQuoteConversion]);
|
|
142
|
+
const base2collateral = indexPrices[0] / coll2quote;
|
|
143
|
+
const threshold = Math.abs(pos * base2collateral * maintMgnRate);
|
|
144
|
+
return marginbalance >= threshold;
|
|
133
145
|
});
|
|
134
146
|
}
|
|
135
147
|
/**
|
package/dist/marketData.d.ts
CHANGED
|
@@ -282,6 +282,14 @@ export default class MarketData extends PerpetualDataHandler {
|
|
|
282
282
|
* @ignore
|
|
283
283
|
*/
|
|
284
284
|
static orderIdsOfTrader(traderAddr: string, orderBookContract: ethers.Contract): Promise<string[]>;
|
|
285
|
+
/**
|
|
286
|
+
* Query the available margin conditional on the given (or current) index prices
|
|
287
|
+
* Result is in collateral currency
|
|
288
|
+
* @param traderAddr address of the trader
|
|
289
|
+
* @param symbol perpetual symbol of the form BTC-USD-MATIC
|
|
290
|
+
* @param indexPrices optional index prices, will otherwise fetch from REST API
|
|
291
|
+
* @returns available margin in collateral currency
|
|
292
|
+
*/
|
|
285
293
|
getAvailableMargin(traderAddr: string, symbol: string, indexPrices?: [number, number]): Promise<number>;
|
|
286
294
|
/**
|
|
287
295
|
* Calculate a type of exchange loyality score based on trader volume
|
package/dist/marketData.js
CHANGED
|
@@ -249,9 +249,10 @@ class MarketData extends perpetualDataHandler_1.default {
|
|
|
249
249
|
let exchangeFeeTbps = yield this.proxyContract.queryExchangeFee(poolId, traderAddr, (_b = order.brokerAddr) !== null && _b !== void 0 ? _b : nodeSDKTypes_1.ZERO_ADDRESS);
|
|
250
250
|
let exchangeFeeCC = (Math.abs(tradeAmountBC) * exchangeFeeTbps * 1e-5 * S2) / S3;
|
|
251
251
|
let brokerFeeCC = (Math.abs(tradeAmountBC) * ((_c = order.brokerFeeTbps) !== null && _c !== void 0 ? _c : 0) * 1e-5 * S2) / S3;
|
|
252
|
+
let referralFeeCC = this.symbolToPerpStaticInfo.get(account.symbol).referralRebate;
|
|
252
253
|
// Trade type:
|
|
253
254
|
let isClose = newPositionBC == 0 || newPositionBC * tradeAmountBC < 0;
|
|
254
|
-
let isOpen = newPositionBC != 0 && (currentPositionBC == 0 ||
|
|
255
|
+
let isOpen = newPositionBC != 0 && (currentPositionBC == 0 || tradeAmountBC * currentPositionBC > 0); // regular open, no flip
|
|
255
256
|
let isFlip = Math.abs(newPositionBC) > Math.abs(currentPositionBC) && !isOpen; // flip position sign, not fully closed
|
|
256
257
|
let keepPositionLvgOnClose = ((_d = order.keepPositionLvg) !== null && _d !== void 0 ? _d : false) && !isOpen;
|
|
257
258
|
// Contract: _doMarginCollateralActions
|
|
@@ -272,10 +273,10 @@ class MarketData extends perpetualDataHandler_1.default {
|
|
|
272
273
|
targetLvg = isFlip || isOpen ? (_e = order.leverage) !== null && _e !== void 0 ? _e : 1 / initialMarginRate : 0;
|
|
273
274
|
let [b0, pos0] = isOpen ? [0, 0] : [account.collateralCC, currentPositionBC];
|
|
274
275
|
traderDepositCC = (0, d8XMath_1.getDepositAmountForLvgTrade)(b0, pos0, tradeAmountBC, targetLvg, tradePrice, S3, Sm);
|
|
275
|
-
console.log("deposit for trget lvg:", traderDepositCC);
|
|
276
276
|
// fees are paid from wallet in this case
|
|
277
277
|
// referral rebate??
|
|
278
|
-
|
|
278
|
+
console.log("deposit for trget lvg:", traderDepositCC);
|
|
279
|
+
traderDepositCC += exchangeFeeCC + brokerFeeCC + referralFeeCC;
|
|
279
280
|
}
|
|
280
281
|
// Contract: _executeTrade
|
|
281
282
|
let deltaCashCC = (-tradeAmountBC * (tradePrice - S2)) / S3;
|
|
@@ -286,7 +287,7 @@ class MarketData extends perpetualDataHandler_1.default {
|
|
|
286
287
|
deltaCashCC += pnl / S3;
|
|
287
288
|
}
|
|
288
289
|
// funding and fees
|
|
289
|
-
deltaCashCC = deltaCashCC + account.unrealizedFundingCollateralCCY - exchangeFeeCC - brokerFeeCC;
|
|
290
|
+
deltaCashCC = deltaCashCC + account.unrealizedFundingCollateralCCY - exchangeFeeCC - brokerFeeCC - referralFeeCC;
|
|
290
291
|
// New cash, locked-in, entry price & leverage after trade
|
|
291
292
|
let newLockedInValueQC = currentLockedInQC + deltaLockedQC;
|
|
292
293
|
let newMarginCashCC = currentMarginCashCC + deltaCashCC + traderDepositCC;
|
|
@@ -411,6 +412,9 @@ class MarketData extends perpetualDataHandler_1.default {
|
|
|
411
412
|
else {
|
|
412
413
|
S2Liq = (0, d8XMath_1.calculateLiquidationPriceCollateralQuote)(lockedInQC, signedPositionBC, marginCashCC, tau);
|
|
413
414
|
}
|
|
415
|
+
// floor at 0
|
|
416
|
+
S2Liq = S2Liq < 0 ? 0 : S2Liq;
|
|
417
|
+
S3Liq = S3Liq && S3Liq < 0 ? 0 : S3Liq;
|
|
414
418
|
return [S2Liq, S3Liq, tau];
|
|
415
419
|
}
|
|
416
420
|
/**
|
|
@@ -595,6 +599,7 @@ class MarketData extends perpetualDataHandler_1.default {
|
|
|
595
599
|
S2Symbol: perpInfo.S2Symbol,
|
|
596
600
|
S3Symbol: perpInfo.S3Symbol,
|
|
597
601
|
lotSizeBC: perpInfo.lotSizeBC,
|
|
602
|
+
referralRebate: perpInfo.referralRebate,
|
|
598
603
|
priceIds: perpInfo.priceIds,
|
|
599
604
|
};
|
|
600
605
|
return res;
|
|
@@ -665,6 +670,14 @@ class MarketData extends perpetualDataHandler_1.default {
|
|
|
665
670
|
return digests;
|
|
666
671
|
});
|
|
667
672
|
}
|
|
673
|
+
/**
|
|
674
|
+
* Query the available margin conditional on the given (or current) index prices
|
|
675
|
+
* Result is in collateral currency
|
|
676
|
+
* @param traderAddr address of the trader
|
|
677
|
+
* @param symbol perpetual symbol of the form BTC-USD-MATIC
|
|
678
|
+
* @param indexPrices optional index prices, will otherwise fetch from REST API
|
|
679
|
+
* @returns available margin in collateral currency
|
|
680
|
+
*/
|
|
668
681
|
getAvailableMargin(traderAddr, symbol, indexPrices) {
|
|
669
682
|
return __awaiter(this, void 0, void 0, function* () {
|
|
670
683
|
if (this.proxyContract == null) {
|
|
@@ -675,15 +688,11 @@ class MarketData extends perpetualDataHandler_1.default {
|
|
|
675
688
|
let obj = yield this.priceFeedGetter.fetchPricesForPerpetual(symbol);
|
|
676
689
|
indexPrices = [obj.idxPrices[0], obj.idxPrices[1]];
|
|
677
690
|
}
|
|
678
|
-
let
|
|
679
|
-
let
|
|
680
|
-
|
|
681
|
-
let
|
|
682
|
-
|
|
683
|
-
let balanceCC = mgnAcct.collateralCC + mgnAcct.unrealizedPnlQuoteCCY / S3;
|
|
684
|
-
let initalMarginCC = Math.abs((perpInfo.initialMarginRate * mgnAcct.positionNotionalBaseCCY * mgnAcct.markPrice) /
|
|
685
|
-
mgnAcct.collToQuoteConversion);
|
|
686
|
-
return balanceCC - initalMarginCC;
|
|
691
|
+
let perpID = perpetualDataHandler_1.default.symbolToPerpetualId(symbol, this.symbolToPerpStaticInfo);
|
|
692
|
+
let traderState = yield this.proxyContract.getTraderState(perpID, traderAddr, indexPrices.map((x) => (0, d8XMath_1.floatToABK64x64)(x)));
|
|
693
|
+
const idx_availableMargin = 1;
|
|
694
|
+
let mgn = (0, d8XMath_1.ABK64x64ToFloat)(traderState[idx_availableMargin]);
|
|
695
|
+
return mgn;
|
|
687
696
|
});
|
|
688
697
|
}
|
|
689
698
|
/**
|
package/dist/nodeSDKTypes.d.ts
CHANGED
|
@@ -88,6 +88,7 @@ class PerpetualDataHandler {
|
|
|
88
88
|
let initRate = [];
|
|
89
89
|
let mgnRate = [];
|
|
90
90
|
let lotSizes = [];
|
|
91
|
+
let refRebates = [];
|
|
91
92
|
for (let k = 0; k < perpetualIDs.length; k++) {
|
|
92
93
|
let perp = yield proxyContract.getPerpetual(perpetualIDs[k]);
|
|
93
94
|
let base = (0, utils_1.contractSymbolToSymbol)(perp.S2BaseCCY, this.symbolList);
|
|
@@ -108,6 +109,7 @@ class PerpetualDataHandler {
|
|
|
108
109
|
initRate.push((0, d8XMath_1.ABK64x64ToFloat)(perp.fInitialMarginRate));
|
|
109
110
|
mgnRate.push((0, d8XMath_1.ABK64x64ToFloat)(perp.fMaintenanceMarginRate));
|
|
110
111
|
lotSizes.push((0, d8XMath_1.ABK64x64ToFloat)(perp.fLotSizeBC));
|
|
112
|
+
refRebates.push((0, d8XMath_1.ABK64x64ToFloat)(perp.fReferralRebateCC));
|
|
111
113
|
// try to find a limit order book
|
|
112
114
|
let lobAddr = yield this.lobFactoryContract.getOrderBookAddress(perpetualIDs[k]);
|
|
113
115
|
currentLimitOrderBookAddr.push(lobAddr);
|
|
@@ -146,6 +148,7 @@ class PerpetualDataHandler {
|
|
|
146
148
|
// add price IDs
|
|
147
149
|
let idsB32, isPyth;
|
|
148
150
|
[idsB32, isPyth] = yield proxyContract.getPriceInfo(perpetualIDs[k]);
|
|
151
|
+
console.log("ref reb", refRebates[k]);
|
|
149
152
|
this.symbolToPerpStaticInfo.set(currentSymbols3[k], {
|
|
150
153
|
id: perpetualIDs[k],
|
|
151
154
|
limitOrderBookAddr: currentLimitOrderBookAddr[k],
|
|
@@ -155,6 +158,7 @@ class PerpetualDataHandler {
|
|
|
155
158
|
S2Symbol: currentSymbols[k],
|
|
156
159
|
S3Symbol: currentSymbolsS3[k],
|
|
157
160
|
lotSizeBC: lotSizes[k],
|
|
161
|
+
referralRebate: refRebates[k],
|
|
158
162
|
priceIds: idsB32,
|
|
159
163
|
});
|
|
160
164
|
}
|
|
@@ -296,7 +300,7 @@ class PerpetualDataHandler {
|
|
|
296
300
|
const idx_mark_price = 8;
|
|
297
301
|
const idx_lvg = 7;
|
|
298
302
|
const idx_s3 = 9;
|
|
299
|
-
let traderState = yield _proxyContract.getTraderState(perpId, traderAddr, _pxS2S3.map(x => (0, d8XMath_1.floatToABK64x64)(x)));
|
|
303
|
+
let traderState = yield _proxyContract.getTraderState(perpId, traderAddr, _pxS2S3.map((x) => (0, d8XMath_1.floatToABK64x64)(x)));
|
|
300
304
|
let isEmpty = traderState[idx_notional] == 0;
|
|
301
305
|
let cash = (0, d8XMath_1.ABK64x64ToFloat)(traderState[idx_cash]);
|
|
302
306
|
let S2Liq = 0, S3Liq = 0, tau = Infinity, pnl = 0, unpaidFundingCC = 0, fLockedIn = ethers_1.BigNumber.from(0), side = nodeSDKTypes_1.CLOSED_SIDE, entryPrice = 0;
|
|
@@ -413,6 +417,9 @@ class PerpetualDataHandler {
|
|
|
413
417
|
else {
|
|
414
418
|
S2Liq = (0, d8XMath_1.calculateLiquidationPriceCollateralQuote)(lockedInValueQC, position, cashCC, tau);
|
|
415
419
|
}
|
|
420
|
+
// floor at 0
|
|
421
|
+
S2Liq = S2Liq < 0 ? 0 : S2Liq;
|
|
422
|
+
S3Liq = S3Liq && S3Liq < 0 ? 0 : S3Liq;
|
|
416
423
|
// account cash + pnl = avail cash + pos Sm - L = margin balance
|
|
417
424
|
let pnl = position * Sm - lockedInValueQC + unpaidFunding;
|
|
418
425
|
return [S2Liq, S3Liq, tau, pnl, unpaidFundingCC];
|
package/dist/priceFeeds.d.ts
CHANGED
|
@@ -30,16 +30,16 @@ export default class PriceFeeds {
|
|
|
30
30
|
mktClosed: [boolean, boolean];
|
|
31
31
|
}>;
|
|
32
32
|
/**
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
33
|
+
* Get all prices/isMarketClosed for the provided symbols via
|
|
34
|
+
* "latest_price_feeds" and triangulation. Triangulation must be defined in config, unless
|
|
35
|
+
* it is a direct price feed.
|
|
36
|
+
* @returns map of feed-price symbol to price/isMarketClosed
|
|
37
|
+
*/
|
|
38
38
|
fetchPrices(symbols: string[]): Promise<Map<string, [number, boolean]>>;
|
|
39
39
|
/**
|
|
40
40
|
* Get index prices and market closed information for the given perpetual
|
|
41
41
|
* @param symbol perpetual symbol such as ETH-USD-MATIC
|
|
42
|
-
* @returns
|
|
42
|
+
* @returns Index prices and market closed information
|
|
43
43
|
*/
|
|
44
44
|
fetchPricesForPerpetual(symbol: string): Promise<{
|
|
45
45
|
idxPrices: number[];
|
|
@@ -76,13 +76,13 @@ export default class PriceFeeds {
|
|
|
76
76
|
*/
|
|
77
77
|
calculateTriangulatedPricesFromFeedInfo(symbols: string[], feeds: PriceFeedSubmission): [number[], boolean[]];
|
|
78
78
|
/**
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
79
|
+
* Extract pair-prices from underlying price feeds via triangulation
|
|
80
|
+
* The function either needs a direct price feed or a defined triangulation to succesfully
|
|
81
|
+
* return a triangulated price
|
|
82
|
+
* @param symbols array of pairs for which we want prices, e.g., [BTC-USDC, ETH-USD]
|
|
83
|
+
* @param feeds data obtained via fetchLatestFeedPriceInfo or fetchLatestFeedPrices
|
|
84
|
+
* @returns array of prices with same order as symbols
|
|
85
|
+
*/
|
|
86
86
|
triangulatePricesFromFeedPrices(symbols: string[], feedPriceMap: Map<string, [number, boolean]>): [number[], boolean[]];
|
|
87
87
|
/**
|
|
88
88
|
* Queries the REST endpoint and returns parsed VAA price data
|
package/dist/priceFeeds.js
CHANGED
|
@@ -55,7 +55,7 @@ class PriceFeeds {
|
|
|
55
55
|
// fetch prices from required price-feeds (REST)
|
|
56
56
|
let submission = yield this.fetchLatestFeedPriceInfoForPerpetual(symbol);
|
|
57
57
|
// calculate index-prices from price-feeds
|
|
58
|
-
let [_idxPrices, _mktClosed] = this.calculateTriangulatedPricesFromFeedInfo(indexSymbols.filter((x) => x !=
|
|
58
|
+
let [_idxPrices, _mktClosed] = this.calculateTriangulatedPricesFromFeedInfo(indexSymbols.filter((x) => x != ""), submission);
|
|
59
59
|
let idxPrices = [_idxPrices[0], 0];
|
|
60
60
|
let mktClosed = [_mktClosed[0], false];
|
|
61
61
|
if (idxPrices.length > 1) {
|
|
@@ -66,16 +66,16 @@ class PriceFeeds {
|
|
|
66
66
|
});
|
|
67
67
|
}
|
|
68
68
|
/**
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
69
|
+
* Get all prices/isMarketClosed for the provided symbols via
|
|
70
|
+
* "latest_price_feeds" and triangulation. Triangulation must be defined in config, unless
|
|
71
|
+
* it is a direct price feed.
|
|
72
|
+
* @returns map of feed-price symbol to price/isMarketClosed
|
|
73
|
+
*/
|
|
74
74
|
fetchPrices(symbols) {
|
|
75
75
|
return __awaiter(this, void 0, void 0, function* () {
|
|
76
76
|
let feedPrices = yield this.fetchAllFeedPrices();
|
|
77
77
|
let [prices, mktClosed] = this.triangulatePricesFromFeedPrices(symbols, feedPrices);
|
|
78
|
-
let symMap = new Map;
|
|
78
|
+
let symMap = new Map();
|
|
79
79
|
for (let k = 0; k < symbols.length; k++) {
|
|
80
80
|
symMap.set(symbols[k], [prices[k], mktClosed[k]]);
|
|
81
81
|
}
|
|
@@ -85,11 +85,11 @@ class PriceFeeds {
|
|
|
85
85
|
/**
|
|
86
86
|
* Get index prices and market closed information for the given perpetual
|
|
87
87
|
* @param symbol perpetual symbol such as ETH-USD-MATIC
|
|
88
|
-
* @returns
|
|
88
|
+
* @returns Index prices and market closed information
|
|
89
89
|
*/
|
|
90
90
|
fetchPricesForPerpetual(symbol) {
|
|
91
91
|
return __awaiter(this, void 0, void 0, function* () {
|
|
92
|
-
let indexSymbols = this.dataHandler.getIndexSymbols(symbol).filter(x => x != "");
|
|
92
|
+
let indexSymbols = this.dataHandler.getIndexSymbols(symbol).filter((x) => x != "");
|
|
93
93
|
// determine relevant price feeds
|
|
94
94
|
let feedSymbols = new Array();
|
|
95
95
|
for (let sym of indexSymbols) {
|
|
@@ -229,7 +229,13 @@ class PriceFeeds {
|
|
|
229
229
|
prices.push(price);
|
|
230
230
|
timestamps.push(pxInfo.publish_time);
|
|
231
231
|
}
|
|
232
|
-
return {
|
|
232
|
+
return {
|
|
233
|
+
symbols: symbols,
|
|
234
|
+
priceFeedVaas: priceFeedUpdates,
|
|
235
|
+
prices: prices,
|
|
236
|
+
isMarketClosed: mktClosed,
|
|
237
|
+
timestamps: timestamps,
|
|
238
|
+
};
|
|
233
239
|
});
|
|
234
240
|
}
|
|
235
241
|
/**
|
|
@@ -248,13 +254,13 @@ class PriceFeeds {
|
|
|
248
254
|
return this.triangulatePricesFromFeedPrices(symbols, priceMap);
|
|
249
255
|
}
|
|
250
256
|
/**
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
257
|
+
* Extract pair-prices from underlying price feeds via triangulation
|
|
258
|
+
* The function either needs a direct price feed or a defined triangulation to succesfully
|
|
259
|
+
* return a triangulated price
|
|
260
|
+
* @param symbols array of pairs for which we want prices, e.g., [BTC-USDC, ETH-USD]
|
|
261
|
+
* @param feeds data obtained via fetchLatestFeedPriceInfo or fetchLatestFeedPrices
|
|
262
|
+
* @returns array of prices with same order as symbols
|
|
263
|
+
*/
|
|
258
264
|
triangulatePricesFromFeedPrices(symbols, feedPriceMap) {
|
|
259
265
|
let prices = new Array();
|
|
260
266
|
let mktClosed = new Array();
|
|
@@ -284,7 +290,7 @@ class PriceFeeds {
|
|
|
284
290
|
*/
|
|
285
291
|
fetchVAAQuery(query) {
|
|
286
292
|
return __awaiter(this, void 0, void 0, function* () {
|
|
287
|
-
const headers = { headers: {
|
|
293
|
+
const headers = { headers: { "Content-Type": "application/json" } };
|
|
288
294
|
let response = yield fetch(query, headers);
|
|
289
295
|
if (!response.ok) {
|
|
290
296
|
throw new Error(`Failed to fetch posts (${response.status}): ${response.statusText}`);
|
|
@@ -306,7 +312,7 @@ class PriceFeeds {
|
|
|
306
312
|
*/
|
|
307
313
|
fetchPriceQuery(query) {
|
|
308
314
|
return __awaiter(this, void 0, void 0, function* () {
|
|
309
|
-
const headers = { headers: {
|
|
315
|
+
const headers = { headers: { "Content-Type": "application/json" } };
|
|
310
316
|
let response = yield fetch(query, headers);
|
|
311
317
|
if (!response.ok) {
|
|
312
318
|
throw new Error(`Failed to fetch posts (${response.status}): ${response.statusText}`);
|
package/dist/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const D8X_SDK_VERSION = "0.1.
|
|
1
|
+
export declare const D8X_SDK_VERSION = "0.1.5";
|
package/dist/version.js
CHANGED
|
@@ -45,7 +45,7 @@ export default class WriteAccessHandler extends PerpetualDataHandler {
|
|
|
45
45
|
* into a mock token used for trading on testnet, with a rate of 1:100_000
|
|
46
46
|
* @param symbol Pool margin token e.g. MATIC
|
|
47
47
|
* @param amountToPay Amount in chain currency, e.g. "0.1" for 0.1 MATIC
|
|
48
|
-
* @returns
|
|
48
|
+
* @returns Transaction object
|
|
49
49
|
*/
|
|
50
|
-
swapForMockToken(symbol: string, amountToPay: string): Promise<
|
|
50
|
+
swapForMockToken(symbol: string, amountToPay: string): Promise<ethers.ContractTransaction>;
|
|
51
51
|
}
|
|
@@ -106,7 +106,7 @@ class WriteAccessHandler extends perpetualDataHandler_1.default {
|
|
|
106
106
|
* into a mock token used for trading on testnet, with a rate of 1:100_000
|
|
107
107
|
* @param symbol Pool margin token e.g. MATIC
|
|
108
108
|
* @param amountToPay Amount in chain currency, e.g. "0.1" for 0.1 MATIC
|
|
109
|
-
* @returns
|
|
109
|
+
* @returns Transaction object
|
|
110
110
|
*/
|
|
111
111
|
swapForMockToken(symbol, amountToPay) {
|
|
112
112
|
return __awaiter(this, void 0, void 0, function* () {
|
package/package.json
CHANGED
package/src/liquidatorTool.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import WriteAccessHandler from "./writeAccessHandler";
|
|
2
2
|
import { NodeSDKConfig, PriceFeedSubmission } from "./nodeSDKTypes";
|
|
3
3
|
import { ethers } from "ethers";
|
|
4
|
+
import { ABK64x64ToFloat, floatToABK64x64 } from "./d8XMath";
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Functions to liquidate traders. This class requires a private key
|
|
@@ -86,7 +87,7 @@ export default class LiquidatorTool extends WriteAccessHandler {
|
|
|
86
87
|
* If not, the position can be liquidated.
|
|
87
88
|
* @param {string} symbol Symbol of the form ETH-USD-MATIC.
|
|
88
89
|
* @param {string} traderAddr Address of the trader whose position you want to assess.
|
|
89
|
-
* @param {[
|
|
90
|
+
* @param {number[]} indexPrices optional, index price S2/S3 for which we test
|
|
90
91
|
* @example
|
|
91
92
|
* import { LiquidatorTool, PerpetualDataHandler } from '@d8x/perpetuals-sdk';
|
|
92
93
|
* async function main() {
|
|
@@ -106,7 +107,11 @@ export default class LiquidatorTool extends WriteAccessHandler {
|
|
|
106
107
|
* @returns {boolean} True if the trader is maintenance margin safe in the perpetual.
|
|
107
108
|
* False means that the trader's position can be liquidated.
|
|
108
109
|
*/
|
|
109
|
-
public async isMaintenanceMarginSafe(
|
|
110
|
+
public async isMaintenanceMarginSafe(
|
|
111
|
+
symbol: string,
|
|
112
|
+
traderAddr: string,
|
|
113
|
+
indexPrices?: [number, number]
|
|
114
|
+
): Promise<boolean> {
|
|
110
115
|
if (this.proxyContract == null) {
|
|
111
116
|
throw Error("no proxy contract initialized. Use createProxyInstance().");
|
|
112
117
|
}
|
|
@@ -117,12 +122,27 @@ export default class LiquidatorTool extends WriteAccessHandler {
|
|
|
117
122
|
let obj = await this.priceFeedGetter.fetchPricesForPerpetual(symbol);
|
|
118
123
|
indexPrices = [obj.idxPrices[0], obj.idxPrices[1]];
|
|
119
124
|
}
|
|
120
|
-
let traderState = await this.proxyContract.getTraderState(
|
|
125
|
+
let traderState = await this.proxyContract.getTraderState(
|
|
126
|
+
perpID,
|
|
127
|
+
traderAddr,
|
|
128
|
+
indexPrices.map((x) => floatToABK64x64(x))
|
|
129
|
+
);
|
|
121
130
|
if (traderState[idx_notional] == 0) {
|
|
122
131
|
// trader does not have open position
|
|
123
|
-
return
|
|
132
|
+
return true;
|
|
124
133
|
}
|
|
125
|
-
|
|
134
|
+
// calculate margin from traderstate
|
|
135
|
+
const idx_maintenanceMgnRate = 10;
|
|
136
|
+
const idx_marginAccountPositionBC = 4;
|
|
137
|
+
const idx_collateralToQuoteConversion = 9;
|
|
138
|
+
const idx_marginBalance = 0;
|
|
139
|
+
const maintMgnRate = ABK64x64ToFloat(traderState[idx_maintenanceMgnRate]);
|
|
140
|
+
const pos = ABK64x64ToFloat(traderState[idx_marginAccountPositionBC]);
|
|
141
|
+
const marginbalance = ABK64x64ToFloat(traderState[idx_marginBalance]);
|
|
142
|
+
const coll2quote = ABK64x64ToFloat(traderState[idx_collateralToQuoteConversion]);
|
|
143
|
+
const base2collateral = indexPrices[0] / coll2quote;
|
|
144
|
+
const threshold = Math.abs(pos * base2collateral * maintMgnRate);
|
|
145
|
+
return marginbalance >= threshold;
|
|
126
146
|
}
|
|
127
147
|
|
|
128
148
|
/**
|
package/src/marketData.ts
CHANGED
|
@@ -290,10 +290,10 @@ export default class MarketData extends PerpetualDataHandler {
|
|
|
290
290
|
);
|
|
291
291
|
let exchangeFeeCC = (Math.abs(tradeAmountBC) * exchangeFeeTbps * 1e-5 * S2) / S3;
|
|
292
292
|
let brokerFeeCC = (Math.abs(tradeAmountBC) * (order.brokerFeeTbps ?? 0) * 1e-5 * S2) / S3;
|
|
293
|
-
|
|
293
|
+
let referralFeeCC = this.symbolToPerpStaticInfo.get(account.symbol)!.referralRebate;
|
|
294
294
|
// Trade type:
|
|
295
295
|
let isClose = newPositionBC == 0 || newPositionBC * tradeAmountBC < 0;
|
|
296
|
-
let isOpen = newPositionBC != 0 && (currentPositionBC == 0 ||
|
|
296
|
+
let isOpen = newPositionBC != 0 && (currentPositionBC == 0 || tradeAmountBC * currentPositionBC > 0); // regular open, no flip
|
|
297
297
|
let isFlip = Math.abs(newPositionBC) > Math.abs(currentPositionBC) && !isOpen; // flip position sign, not fully closed
|
|
298
298
|
let keepPositionLvgOnClose = (order.keepPositionLvg ?? false) && !isOpen;
|
|
299
299
|
|
|
@@ -314,10 +314,10 @@ export default class MarketData extends PerpetualDataHandler {
|
|
|
314
314
|
targetLvg = isFlip || isOpen ? order.leverage ?? 1 / initialMarginRate : 0;
|
|
315
315
|
let [b0, pos0] = isOpen ? [0, 0] : [account.collateralCC, currentPositionBC];
|
|
316
316
|
traderDepositCC = getDepositAmountForLvgTrade(b0, pos0, tradeAmountBC, targetLvg, tradePrice, S3, Sm);
|
|
317
|
-
console.log("deposit for trget lvg:", traderDepositCC);
|
|
318
317
|
// fees are paid from wallet in this case
|
|
319
318
|
// referral rebate??
|
|
320
|
-
|
|
319
|
+
console.log("deposit for trget lvg:", traderDepositCC);
|
|
320
|
+
traderDepositCC += exchangeFeeCC + brokerFeeCC + referralFeeCC;
|
|
321
321
|
}
|
|
322
322
|
|
|
323
323
|
// Contract: _executeTrade
|
|
@@ -329,7 +329,7 @@ export default class MarketData extends PerpetualDataHandler {
|
|
|
329
329
|
deltaCashCC += pnl / S3;
|
|
330
330
|
}
|
|
331
331
|
// funding and fees
|
|
332
|
-
deltaCashCC = deltaCashCC + account.unrealizedFundingCollateralCCY - exchangeFeeCC - brokerFeeCC;
|
|
332
|
+
deltaCashCC = deltaCashCC + account.unrealizedFundingCollateralCCY - exchangeFeeCC - brokerFeeCC - referralFeeCC;
|
|
333
333
|
|
|
334
334
|
// New cash, locked-in, entry price & leverage after trade
|
|
335
335
|
let newLockedInValueQC = currentLockedInQC + deltaLockedQC;
|
|
@@ -495,6 +495,9 @@ export default class MarketData extends PerpetualDataHandler {
|
|
|
495
495
|
} else {
|
|
496
496
|
S2Liq = calculateLiquidationPriceCollateralQuote(lockedInQC, signedPositionBC, marginCashCC, tau);
|
|
497
497
|
}
|
|
498
|
+
// floor at 0
|
|
499
|
+
S2Liq = S2Liq < 0 ? 0 : S2Liq;
|
|
500
|
+
S3Liq = S3Liq && S3Liq < 0 ? 0 : S3Liq;
|
|
498
501
|
return [S2Liq, S3Liq, tau];
|
|
499
502
|
}
|
|
500
503
|
|
|
@@ -712,6 +715,7 @@ export default class MarketData extends PerpetualDataHandler {
|
|
|
712
715
|
S2Symbol: perpInfo.S2Symbol,
|
|
713
716
|
S3Symbol: perpInfo.S3Symbol,
|
|
714
717
|
lotSizeBC: perpInfo.lotSizeBC,
|
|
718
|
+
referralRebate: perpInfo.referralRebate,
|
|
715
719
|
priceIds: perpInfo.priceIds,
|
|
716
720
|
};
|
|
717
721
|
return res;
|
|
@@ -780,33 +784,33 @@ export default class MarketData extends PerpetualDataHandler {
|
|
|
780
784
|
return digests;
|
|
781
785
|
}
|
|
782
786
|
|
|
787
|
+
/**
|
|
788
|
+
* Query the available margin conditional on the given (or current) index prices
|
|
789
|
+
* Result is in collateral currency
|
|
790
|
+
* @param traderAddr address of the trader
|
|
791
|
+
* @param symbol perpetual symbol of the form BTC-USD-MATIC
|
|
792
|
+
* @param indexPrices optional index prices, will otherwise fetch from REST API
|
|
793
|
+
* @returns available margin in collateral currency
|
|
794
|
+
*/
|
|
783
795
|
public async getAvailableMargin(traderAddr: string, symbol: string, indexPrices?: [number, number]): Promise<number> {
|
|
784
796
|
if (this.proxyContract == null) {
|
|
785
797
|
throw Error("no proxy contract initialized. Use createProxyInstance().");
|
|
786
798
|
}
|
|
787
|
-
|
|
799
|
+
|
|
788
800
|
if (indexPrices == undefined) {
|
|
789
801
|
// fetch from API
|
|
790
802
|
let obj = await this.priceFeedGetter.fetchPricesForPerpetual(symbol);
|
|
791
803
|
indexPrices = [obj.idxPrices[0], obj.idxPrices[1]];
|
|
792
804
|
}
|
|
793
|
-
let
|
|
805
|
+
let perpID = PerpetualDataHandler.symbolToPerpetualId(symbol, this.symbolToPerpStaticInfo);
|
|
806
|
+
let traderState = await this.proxyContract.getTraderState(
|
|
807
|
+
perpID,
|
|
794
808
|
traderAddr,
|
|
795
|
-
|
|
796
|
-
this.symbolToPerpStaticInfo,
|
|
797
|
-
this.proxyContract,
|
|
798
|
-
[indexPrices[0], indexPrices[1]]
|
|
799
|
-
);
|
|
800
|
-
let S2 = indexPrices[0];
|
|
801
|
-
let ccyType = this.getPerpetualStaticInfo(symbol).collateralCurrencyType;
|
|
802
|
-
let S3 = ccyType == COLLATERAL_CURRENCY_QUANTO ? indexPrices[1] : ccyType == COLLATERAL_CURRENCY_QUOTE ? 1 : S2;
|
|
803
|
-
let perpInfo = this.symbolToPerpStaticInfo.get(symbol);
|
|
804
|
-
let balanceCC = mgnAcct.collateralCC + mgnAcct.unrealizedPnlQuoteCCY / S3;
|
|
805
|
-
let initalMarginCC = Math.abs(
|
|
806
|
-
(perpInfo!.initialMarginRate * mgnAcct.positionNotionalBaseCCY * mgnAcct.markPrice) /
|
|
807
|
-
mgnAcct.collToQuoteConversion
|
|
809
|
+
indexPrices.map((x) => floatToABK64x64(x))
|
|
808
810
|
);
|
|
809
|
-
|
|
811
|
+
const idx_availableMargin = 1;
|
|
812
|
+
let mgn = ABK64x64ToFloat(traderState[idx_availableMargin]);
|
|
813
|
+
return mgn;
|
|
810
814
|
}
|
|
811
815
|
|
|
812
816
|
/**
|
|
@@ -815,15 +819,15 @@ export default class MarketData extends PerpetualDataHandler {
|
|
|
815
819
|
* @param brokerAddr address of the trader's broker or undefined
|
|
816
820
|
* @returns a loyality score (4 worst, 1 best)
|
|
817
821
|
*/
|
|
818
|
-
public async getTraderLoyalityScore(traderAddr: string, brokerAddr?: string)
|
|
822
|
+
public async getTraderLoyalityScore(traderAddr: string, brokerAddr?: string): Promise<number> {
|
|
819
823
|
if (this.proxyContract == null) {
|
|
820
824
|
throw Error("no proxy contract or wallet initialized. Use createProxyInstance().");
|
|
821
825
|
}
|
|
822
826
|
// loop over all pools and query volumes
|
|
823
|
-
let brokerProm
|
|
824
|
-
let traderProm
|
|
825
|
-
for(let k=0; k<this.poolStaticInfos.length; k++) {
|
|
826
|
-
if (brokerAddr!="" && brokerAddr!=undefined) {
|
|
827
|
+
let brokerProm: Array<Promise<BigNumber>> = [];
|
|
828
|
+
let traderProm: Array<Promise<BigNumber>> = [];
|
|
829
|
+
for (let k = 0; k < this.poolStaticInfos.length; k++) {
|
|
830
|
+
if (brokerAddr != "" && brokerAddr != undefined) {
|
|
827
831
|
let brkrVol = this.proxyContract.getCurrentBrokerVolume(this.poolStaticInfos[k].poolId, brokerAddr);
|
|
828
832
|
brokerProm.push(brkrVol);
|
|
829
833
|
}
|
|
@@ -835,18 +839,18 @@ export default class MarketData extends PerpetualDataHandler {
|
|
|
835
839
|
let totalTraderVolume = 0;
|
|
836
840
|
let brkrVol = await Promise.all(brokerProm);
|
|
837
841
|
let trdrVol = await Promise.all(traderProm);
|
|
838
|
-
for(let k=0; k<this.poolStaticInfos.length; k++) {
|
|
839
|
-
if (brokerAddr!="" && brokerAddr!=undefined) {
|
|
842
|
+
for (let k = 0; k < this.poolStaticInfos.length; k++) {
|
|
843
|
+
if (brokerAddr != "" && brokerAddr != undefined) {
|
|
840
844
|
totalBrokerVolume += ABK64x64ToFloat(brkrVol[k]);
|
|
841
845
|
}
|
|
842
846
|
totalTraderVolume += ABK64x64ToFloat(trdrVol[k]);
|
|
843
847
|
}
|
|
844
848
|
const volumeCap = 500_000;
|
|
845
|
-
let score = totalBrokerVolume==0 ? totalTraderVolume/volumeCap : totalBrokerVolume;
|
|
849
|
+
let score = totalBrokerVolume == 0 ? totalTraderVolume / volumeCap : totalBrokerVolume;
|
|
846
850
|
// 5 different equally spaced categories: (4 is best, 1 worst)
|
|
847
|
-
let rank4 = 1+Math.floor(Math.min(score,1-1e-15)*4);
|
|
851
|
+
let rank4 = 1 + Math.floor(Math.min(score, 1 - 1e-15) * 4);
|
|
848
852
|
// desired ranking starts at 4 (worst) and ends at 1 (best)
|
|
849
|
-
return 5-rank4;
|
|
853
|
+
return 5 - rank4;
|
|
850
854
|
}
|
|
851
855
|
|
|
852
856
|
public static async _exchangeInfo(
|
package/src/nodeSDKTypes.ts
CHANGED
|
@@ -85,6 +85,7 @@ export interface PerpetualStaticInfo {
|
|
|
85
85
|
S2Symbol: string;
|
|
86
86
|
S3Symbol: string;
|
|
87
87
|
lotSizeBC: number;
|
|
88
|
+
referralRebate: number;
|
|
88
89
|
priceIds: string[];
|
|
89
90
|
}
|
|
90
91
|
|
|
@@ -154,7 +155,7 @@ export interface OrderStruct {
|
|
|
154
155
|
}
|
|
155
156
|
|
|
156
157
|
export interface Order {
|
|
157
|
-
symbol: string
|
|
158
|
+
symbol: string; //symbol of the form ETH-USD-MATIC
|
|
158
159
|
side: string;
|
|
159
160
|
type: string;
|
|
160
161
|
quantity: number;
|
|
@@ -219,7 +220,7 @@ export interface PriceFeedConfig {
|
|
|
219
220
|
|
|
220
221
|
export interface PriceFeedSubmission {
|
|
221
222
|
symbols: string[];
|
|
222
|
-
priceFeedVaas: string[];
|
|
223
|
+
priceFeedVaas: string[];
|
|
223
224
|
prices: number[];
|
|
224
225
|
isMarketClosed: boolean[];
|
|
225
226
|
timestamps: number[];
|
|
@@ -143,6 +143,7 @@ export default class PerpetualDataHandler {
|
|
|
143
143
|
let initRate: number[] = [];
|
|
144
144
|
let mgnRate: number[] = [];
|
|
145
145
|
let lotSizes: number[] = [];
|
|
146
|
+
let refRebates: number[] = [];
|
|
146
147
|
|
|
147
148
|
for (let k = 0; k < perpetualIDs.length; k++) {
|
|
148
149
|
let perp = await proxyContract.getPerpetual(perpetualIDs[k]);
|
|
@@ -163,6 +164,7 @@ export default class PerpetualDataHandler {
|
|
|
163
164
|
initRate.push(ABK64x64ToFloat(perp.fInitialMarginRate));
|
|
164
165
|
mgnRate.push(ABK64x64ToFloat(perp.fMaintenanceMarginRate));
|
|
165
166
|
lotSizes.push(ABK64x64ToFloat(perp.fLotSizeBC));
|
|
167
|
+
refRebates.push(ABK64x64ToFloat(perp.fReferralRebateCC));
|
|
166
168
|
// try to find a limit order book
|
|
167
169
|
let lobAddr = await this.lobFactoryContract.getOrderBookAddress(perpetualIDs[k]);
|
|
168
170
|
currentLimitOrderBookAddr.push(lobAddr);
|
|
@@ -200,7 +202,7 @@ export default class PerpetualDataHandler {
|
|
|
200
202
|
// add price IDs
|
|
201
203
|
let idsB32, isPyth;
|
|
202
204
|
[idsB32, isPyth] = await proxyContract.getPriceInfo(perpetualIDs[k]);
|
|
203
|
-
|
|
205
|
+
console.log("ref reb", refRebates[k]);
|
|
204
206
|
this.symbolToPerpStaticInfo.set(currentSymbols3[k], {
|
|
205
207
|
id: perpetualIDs[k],
|
|
206
208
|
limitOrderBookAddr: currentLimitOrderBookAddr[k],
|
|
@@ -210,6 +212,7 @@ export default class PerpetualDataHandler {
|
|
|
210
212
|
S2Symbol: currentSymbols[k],
|
|
211
213
|
S3Symbol: currentSymbolsS3[k],
|
|
212
214
|
lotSizeBC: lotSizes[k],
|
|
215
|
+
referralRebate: refRebates[k],
|
|
213
216
|
priceIds: idsB32,
|
|
214
217
|
});
|
|
215
218
|
}
|
|
@@ -364,7 +367,11 @@ export default class PerpetualDataHandler {
|
|
|
364
367
|
const idx_mark_price = 8;
|
|
365
368
|
const idx_lvg = 7;
|
|
366
369
|
const idx_s3 = 9;
|
|
367
|
-
let traderState = await _proxyContract.getTraderState(
|
|
370
|
+
let traderState = await _proxyContract.getTraderState(
|
|
371
|
+
perpId,
|
|
372
|
+
traderAddr,
|
|
373
|
+
_pxS2S3.map((x) => floatToABK64x64(x))
|
|
374
|
+
);
|
|
368
375
|
let isEmpty = traderState[idx_notional] == 0;
|
|
369
376
|
let cash = ABK64x64ToFloat(traderState[idx_cash]);
|
|
370
377
|
let S2Liq = 0,
|
|
@@ -509,6 +516,9 @@ export default class PerpetualDataHandler {
|
|
|
509
516
|
} else {
|
|
510
517
|
S2Liq = calculateLiquidationPriceCollateralQuote(lockedInValueQC, position, cashCC, tau);
|
|
511
518
|
}
|
|
519
|
+
// floor at 0
|
|
520
|
+
S2Liq = S2Liq < 0 ? 0 : S2Liq;
|
|
521
|
+
S3Liq = S3Liq && S3Liq < 0 ? 0 : S3Liq;
|
|
512
522
|
// account cash + pnl = avail cash + pos Sm - L = margin balance
|
|
513
523
|
let pnl = position * Sm - lockedInValueQC + unpaidFunding;
|
|
514
524
|
return [S2Liq, S3Liq, tau, pnl, unpaidFundingCC];
|
package/src/priceFeeds.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {BigNumber} from "ethers";
|
|
1
|
+
import { BigNumber } from "ethers";
|
|
2
2
|
import PerpetualDataHandler from "./perpetualDataHandler";
|
|
3
3
|
import Triangulator from "./triangulator";
|
|
4
|
-
import {PriceFeedConfig, PriceFeedSubmission, PriceFeedFormat} from "./nodeSDKTypes"
|
|
5
|
-
import {decNToFloat} from "./d8XMath";
|
|
4
|
+
import { PriceFeedConfig, PriceFeedSubmission, PriceFeedFormat } from "./nodeSDKTypes";
|
|
5
|
+
import { decNToFloat } from "./d8XMath";
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* This class communicates with the REST API that provides price-data that is
|
|
@@ -12,19 +12,18 @@ import {decNToFloat} from "./d8XMath";
|
|
|
12
12
|
export default class PriceFeeds {
|
|
13
13
|
private config: PriceFeedConfig;
|
|
14
14
|
private feedEndpoints: Array<string>; //feedEndpoints[endpointId] = endpointstring
|
|
15
|
-
private feedInfo: Map<string, {symbol:string
|
|
16
|
-
private dataHandler
|
|
15
|
+
private feedInfo: Map<string, { symbol: string; endpointId: number }>; // priceFeedId -> symbol, endpointId
|
|
16
|
+
private dataHandler: PerpetualDataHandler;
|
|
17
17
|
// store triangulation paths given the price feeds
|
|
18
|
-
private triangulations
|
|
18
|
+
private triangulations: Map<string, [string[], boolean[]]>;
|
|
19
19
|
private THRESHOLD_MARKET_CLOSED_SEC = 15; // smallest lag for which we consider the market as being closed
|
|
20
20
|
|
|
21
21
|
constructor(dataHandler: PerpetualDataHandler, priceFeedConfigNetwork: string) {
|
|
22
|
-
|
|
23
22
|
let configs = <PriceFeedConfig[]>require("../config/priceFeedConfig.json");
|
|
24
23
|
this.config = PriceFeeds._selectConfig(configs, priceFeedConfigNetwork);
|
|
25
24
|
[this.feedInfo, this.feedEndpoints] = PriceFeeds._constructFeedInfo(this.config);
|
|
26
25
|
this.dataHandler = dataHandler;
|
|
27
|
-
this.triangulations = new Map<string, [string[], boolean[]]>();
|
|
26
|
+
this.triangulations = new Map<string, [string[], boolean[]]>();
|
|
28
27
|
}
|
|
29
28
|
|
|
30
29
|
/**
|
|
@@ -33,10 +32,10 @@ export default class PriceFeeds {
|
|
|
33
32
|
*/
|
|
34
33
|
public initializeTriangulations(symbols: Set<string>) {
|
|
35
34
|
let feedSymbols = new Array<string>();
|
|
36
|
-
for(let [key, value] of this.feedInfo) {
|
|
35
|
+
for (let [key, value] of this.feedInfo) {
|
|
37
36
|
feedSymbols.push(value.symbol);
|
|
38
37
|
}
|
|
39
|
-
for(let symbol of symbols.values()) {
|
|
38
|
+
for (let symbol of symbols.values()) {
|
|
40
39
|
let triangulation = Triangulator.triangulate(feedSymbols, symbol);
|
|
41
40
|
this.triangulations.set(symbol, triangulation);
|
|
42
41
|
}
|
|
@@ -48,35 +47,38 @@ export default class PriceFeeds {
|
|
|
48
47
|
* @param symbol symbol of perpetual, e.g., BTC-USD-MATIC
|
|
49
48
|
* @returns PriceFeedSubmission, index prices, market closed information
|
|
50
49
|
*/
|
|
51
|
-
public async fetchFeedPriceInfoAndIndicesForPerpetual(
|
|
52
|
-
|
|
53
|
-
{
|
|
50
|
+
public async fetchFeedPriceInfoAndIndicesForPerpetual(
|
|
51
|
+
symbol: string
|
|
52
|
+
): Promise<{ submission: PriceFeedSubmission; pxS2S3: [number, number]; mktClosed: [boolean, boolean] }> {
|
|
54
53
|
let indexSymbols = this.dataHandler.getIndexSymbols(symbol);
|
|
55
54
|
// fetch prices from required price-feeds (REST)
|
|
56
|
-
let submission
|
|
55
|
+
let submission: PriceFeedSubmission = await this.fetchLatestFeedPriceInfoForPerpetual(symbol);
|
|
57
56
|
// calculate index-prices from price-feeds
|
|
58
|
-
let [_idxPrices, _mktClosed] = this.calculateTriangulatedPricesFromFeedInfo(
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
57
|
+
let [_idxPrices, _mktClosed] = this.calculateTriangulatedPricesFromFeedInfo(
|
|
58
|
+
indexSymbols.filter((x) => x != ""),
|
|
59
|
+
submission
|
|
60
|
+
);
|
|
61
|
+
let idxPrices: [number, number] = [_idxPrices[0], 0];
|
|
62
|
+
let mktClosed: [boolean, boolean] = [_mktClosed[0], false];
|
|
63
|
+
if (idxPrices.length > 1) {
|
|
62
64
|
idxPrices[1] = _idxPrices[1];
|
|
63
65
|
mktClosed[1] = _mktClosed[1];
|
|
64
66
|
}
|
|
65
|
-
return {submission
|
|
67
|
+
return { submission: submission, pxS2S3: idxPrices, mktClosed: mktClosed };
|
|
66
68
|
}
|
|
67
69
|
|
|
68
|
-
|
|
69
|
-
* Get all prices/isMarketClosed for the provided symbols via
|
|
70
|
+
/**
|
|
71
|
+
* Get all prices/isMarketClosed for the provided symbols via
|
|
70
72
|
* "latest_price_feeds" and triangulation. Triangulation must be defined in config, unless
|
|
71
73
|
* it is a direct price feed.
|
|
72
74
|
* @returns map of feed-price symbol to price/isMarketClosed
|
|
73
75
|
*/
|
|
74
|
-
public async fetchPrices(symbols: string[])
|
|
76
|
+
public async fetchPrices(symbols: string[]): Promise<Map<string, [number, boolean]>> {
|
|
75
77
|
let feedPrices = await this.fetchAllFeedPrices();
|
|
76
78
|
let [prices, mktClosed] = this.triangulatePricesFromFeedPrices(symbols, feedPrices);
|
|
77
|
-
let symMap = new Map<string, [number, boolean]
|
|
78
|
-
for(let k=0; k<symbols.length; k++) {
|
|
79
|
-
symMap.set(symbols[k], [prices[k], mktClosed[k]])
|
|
79
|
+
let symMap = new Map<string, [number, boolean]>();
|
|
80
|
+
for (let k = 0; k < symbols.length; k++) {
|
|
81
|
+
symMap.set(symbols[k], [prices[k], mktClosed[k]]);
|
|
80
82
|
}
|
|
81
83
|
return symMap;
|
|
82
84
|
}
|
|
@@ -84,34 +86,34 @@ export default class PriceFeeds {
|
|
|
84
86
|
/**
|
|
85
87
|
* Get index prices and market closed information for the given perpetual
|
|
86
88
|
* @param symbol perpetual symbol such as ETH-USD-MATIC
|
|
87
|
-
* @returns
|
|
89
|
+
* @returns Index prices and market closed information
|
|
88
90
|
*/
|
|
89
|
-
public async fetchPricesForPerpetual(symbol: string)
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
}
|
|
91
|
+
public async fetchPricesForPerpetual(symbol: string): Promise<{ idxPrices: number[]; mktClosed: boolean[] }> {
|
|
92
|
+
let indexSymbols = this.dataHandler.getIndexSymbols(symbol).filter((x) => x != "");
|
|
93
|
+
// determine relevant price feeds
|
|
94
|
+
let feedSymbols = new Array<string>();
|
|
95
|
+
for (let sym of indexSymbols) {
|
|
96
|
+
if (sym != "") {
|
|
97
|
+
let triang: [string[], boolean[]] | undefined = this.triangulations.get(sym);
|
|
98
|
+
if (triang == undefined) {
|
|
99
|
+
// no triangulation defined, so symbol must be a feed (unless misconfigured)
|
|
100
|
+
feedSymbols.push(sym);
|
|
101
|
+
} else {
|
|
102
|
+
// push all required feeds to array
|
|
103
|
+
triang[0].map((feedSym) => feedSymbols.push(feedSym));
|
|
103
104
|
}
|
|
104
105
|
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
106
|
+
}
|
|
107
|
+
// get all feed prices
|
|
108
|
+
let feedPrices = await this.fetchFeedPrices(feedSymbols);
|
|
109
|
+
// triangulate
|
|
110
|
+
let [prices, mktClosed] = this.triangulatePricesFromFeedPrices(indexSymbols, feedPrices);
|
|
111
|
+
// ensure we return an array of 2 in all cases
|
|
112
|
+
if (prices.length == 1) {
|
|
113
|
+
prices.push(0);
|
|
114
|
+
mktClosed.push(false);
|
|
115
|
+
}
|
|
116
|
+
return { idxPrices: prices, mktClosed: mktClosed };
|
|
115
117
|
}
|
|
116
118
|
|
|
117
119
|
/**
|
|
@@ -124,16 +126,16 @@ export default class PriceFeeds {
|
|
|
124
126
|
public async fetchFeedPrices(symbols?: string[]): Promise<Map<string, [number, boolean]>> {
|
|
125
127
|
let queries = new Array<string>(this.feedEndpoints.length);
|
|
126
128
|
let symbolsOfEndpoint: string[][] = [];
|
|
127
|
-
for(let j=0;j<queries.length;j++) {
|
|
129
|
+
for (let j = 0; j < queries.length; j++) {
|
|
128
130
|
symbolsOfEndpoint.push([]);
|
|
129
131
|
}
|
|
130
|
-
for(let k=0; k<this.config.ids.length; k++) {
|
|
132
|
+
for (let k = 0; k < this.config.ids.length; k++) {
|
|
131
133
|
let currFeed = this.config.ids[k];
|
|
132
|
-
if(symbols!=undefined && !symbols.includes(currFeed.symbol)) {
|
|
134
|
+
if (symbols != undefined && !symbols.includes(currFeed.symbol)) {
|
|
133
135
|
continue;
|
|
134
136
|
}
|
|
135
137
|
// feedInfo: Map<string, {symbol:string, endpointId: number}>; // priceFeedId -> symbol, endpointId
|
|
136
|
-
let endpointId = this.feedInfo.get(currFeed.id)!.endpointId;
|
|
138
|
+
let endpointId = this.feedInfo.get(currFeed.id)!.endpointId;
|
|
137
139
|
symbolsOfEndpoint[endpointId].push(currFeed.symbol);
|
|
138
140
|
if (queries[endpointId] == undefined) {
|
|
139
141
|
// each id can have a different endpoint, but we cluster
|
|
@@ -143,30 +145,29 @@ export default class PriceFeeds {
|
|
|
143
145
|
queries[endpointId] = queries[endpointId] + "ids[]=" + currFeed.id + "&";
|
|
144
146
|
}
|
|
145
147
|
let resultPrices = new Map<string, [number, boolean]>();
|
|
146
|
-
for(let k=0; k<queries.length; k++) {
|
|
147
|
-
if(queries[k]==undefined) {
|
|
148
|
+
for (let k = 0; k < queries.length; k++) {
|
|
149
|
+
if (queries[k] == undefined) {
|
|
148
150
|
continue;
|
|
149
151
|
}
|
|
150
|
-
let [id, pxInfo]
|
|
151
|
-
let tsSecNow = Math.round(Date.now()/1000);
|
|
152
|
-
for(let j=0; j<pxInfo.length; j++) {
|
|
152
|
+
let [id, pxInfo]: [string[], PriceFeedFormat[]] = await this.fetchPriceQuery(queries[k]);
|
|
153
|
+
let tsSecNow = Math.round(Date.now() / 1000);
|
|
154
|
+
for (let j = 0; j < pxInfo.length; j++) {
|
|
153
155
|
let price = decNToFloat(BigNumber.from(pxInfo[j].price), -pxInfo[j].expo);
|
|
154
156
|
let isMarketClosed = tsSecNow - pxInfo[j].publish_time > this.THRESHOLD_MARKET_CLOSED_SEC;
|
|
155
157
|
resultPrices.set(symbolsOfEndpoint[k][j], [price, isMarketClosed]);
|
|
156
158
|
}
|
|
157
159
|
}
|
|
158
160
|
return resultPrices;
|
|
159
|
-
|
|
160
161
|
}
|
|
161
162
|
|
|
162
163
|
/**
|
|
163
164
|
* Get all configured feed prices via "latest_price_feeds"
|
|
164
165
|
* @returns map of feed-price symbol to price/isMarketClosed
|
|
165
166
|
*/
|
|
166
|
-
public async fetchAllFeedPrices()
|
|
167
|
+
public async fetchAllFeedPrices(): Promise<Map<string, [number, boolean]>> {
|
|
167
168
|
return this.fetchFeedPrices();
|
|
168
169
|
}
|
|
169
|
-
|
|
170
|
+
|
|
170
171
|
/**
|
|
171
172
|
* Get the latest prices for a given perpetual from the offchain oracle
|
|
172
173
|
* networks
|
|
@@ -174,7 +175,7 @@ export default class PriceFeeds {
|
|
|
174
175
|
* @returns array of price feed updates that can be submitted to the smart contract
|
|
175
176
|
* and corresponding price information
|
|
176
177
|
*/
|
|
177
|
-
public async fetchLatestFeedPriceInfoForPerpetual(symbol: string)
|
|
178
|
+
public async fetchLatestFeedPriceInfoForPerpetual(symbol: string): Promise<PriceFeedSubmission> {
|
|
178
179
|
let feedIds = this.dataHandler.getPriceIds(symbol);
|
|
179
180
|
let queries = new Array<string>(this.feedEndpoints.length);
|
|
180
181
|
// we need to preserve the order of the price feeds
|
|
@@ -215,10 +216,10 @@ export default class PriceFeeds {
|
|
|
215
216
|
const prices = new Array<number>();
|
|
216
217
|
const mktClosed = new Array<boolean>();
|
|
217
218
|
const timestamps = new Array<number>();
|
|
218
|
-
const tsSecNow = Math.round(Date.now()/1000);
|
|
219
|
-
for(let k=0; k<orderEndpointNumber.length; k++) {
|
|
220
|
-
let endpointId = Math.floor(orderEndpointNumber[k]/100);
|
|
221
|
-
let idWithinEndpoint = orderEndpointNumber[k]-100*endpointId;
|
|
219
|
+
const tsSecNow = Math.round(Date.now() / 1000);
|
|
220
|
+
for (let k = 0; k < orderEndpointNumber.length; k++) {
|
|
221
|
+
let endpointId = Math.floor(orderEndpointNumber[k] / 100);
|
|
222
|
+
let idWithinEndpoint = orderEndpointNumber[k] - 100 * endpointId;
|
|
222
223
|
priceFeedUpdates.push(data[endpointId][0][idWithinEndpoint]);
|
|
223
224
|
let pxInfo: PriceFeedFormat = data[endpointId][1][idWithinEndpoint];
|
|
224
225
|
let price = decNToFloat(BigNumber.from(pxInfo.price), -pxInfo.expo);
|
|
@@ -227,8 +228,14 @@ export default class PriceFeeds {
|
|
|
227
228
|
prices.push(price);
|
|
228
229
|
timestamps.push(pxInfo.publish_time);
|
|
229
230
|
}
|
|
230
|
-
|
|
231
|
-
return {
|
|
231
|
+
|
|
232
|
+
return {
|
|
233
|
+
symbols: symbols,
|
|
234
|
+
priceFeedVaas: priceFeedUpdates,
|
|
235
|
+
prices: prices,
|
|
236
|
+
isMarketClosed: mktClosed,
|
|
237
|
+
timestamps: timestamps,
|
|
238
|
+
};
|
|
232
239
|
}
|
|
233
240
|
|
|
234
241
|
/**
|
|
@@ -239,14 +246,14 @@ export default class PriceFeeds {
|
|
|
239
246
|
* @param feeds data obtained via fetchLatestFeedPriceInfo or fetchLatestFeedPrices
|
|
240
247
|
* @returns array of prices with same order as symbols
|
|
241
248
|
*/
|
|
242
|
-
public calculateTriangulatedPricesFromFeedInfo(symbols: string[], feeds: PriceFeedSubmission)
|
|
243
|
-
let priceMap = new Map<string, [number,boolean]>();
|
|
244
|
-
for(let j=0; j<feeds.prices.length; j++) {
|
|
249
|
+
public calculateTriangulatedPricesFromFeedInfo(symbols: string[], feeds: PriceFeedSubmission): [number[], boolean[]] {
|
|
250
|
+
let priceMap = new Map<string, [number, boolean]>();
|
|
251
|
+
for (let j = 0; j < feeds.prices.length; j++) {
|
|
245
252
|
priceMap.set(feeds.symbols[j], [feeds.prices[j], feeds.isMarketClosed[j]]);
|
|
246
253
|
}
|
|
247
254
|
return this.triangulatePricesFromFeedPrices(symbols, priceMap);
|
|
248
255
|
}
|
|
249
|
-
|
|
256
|
+
/**
|
|
250
257
|
* Extract pair-prices from underlying price feeds via triangulation
|
|
251
258
|
* The function either needs a direct price feed or a defined triangulation to succesfully
|
|
252
259
|
* return a triangulated price
|
|
@@ -254,22 +261,25 @@ export default class PriceFeeds {
|
|
|
254
261
|
* @param feeds data obtained via fetchLatestFeedPriceInfo or fetchLatestFeedPrices
|
|
255
262
|
* @returns array of prices with same order as symbols
|
|
256
263
|
*/
|
|
257
|
-
|
|
264
|
+
public triangulatePricesFromFeedPrices(
|
|
265
|
+
symbols: string[],
|
|
266
|
+
feedPriceMap: Map<string, [number, boolean]>
|
|
267
|
+
): [number[], boolean[]] {
|
|
258
268
|
let prices = new Array<number>();
|
|
259
269
|
let mktClosed = new Array<boolean>();
|
|
260
|
-
for(let k=0; k<symbols.length; k++) {
|
|
261
|
-
let triangulation
|
|
262
|
-
if(triangulation==undefined) {
|
|
270
|
+
for (let k = 0; k < symbols.length; k++) {
|
|
271
|
+
let triangulation: [string[], boolean[]] | undefined = this.triangulations.get(symbols[k]);
|
|
272
|
+
if (triangulation == undefined) {
|
|
263
273
|
let feedPrice = feedPriceMap.get(symbols[k]);
|
|
264
|
-
if (feedPrice==undefined) {
|
|
274
|
+
if (feedPrice == undefined) {
|
|
265
275
|
throw new Error(`PriceFeeds: no triangulation defined for ${symbols[k]}`);
|
|
266
276
|
} else {
|
|
267
|
-
prices.push(feedPrice[0])
|
|
268
|
-
mktClosed.push(feedPrice[1])
|
|
277
|
+
prices.push(feedPrice[0]); //price
|
|
278
|
+
mktClosed.push(feedPrice[1]); //market closed?
|
|
269
279
|
continue;
|
|
270
280
|
}
|
|
271
281
|
}
|
|
272
|
-
let [px, isMktClosed]
|
|
282
|
+
let [px, isMktClosed]: [number, boolean] = Triangulator.calculateTriangulatedPrice(triangulation, feedPriceMap);
|
|
273
283
|
prices.push(px);
|
|
274
284
|
mktClosed.push(isMktClosed);
|
|
275
285
|
}
|
|
@@ -281,8 +291,8 @@ export default class PriceFeeds {
|
|
|
281
291
|
* @param query query price-info from endpoint
|
|
282
292
|
* @returns vaa and price info
|
|
283
293
|
*/
|
|
284
|
-
private async fetchVAAQuery(query: string)
|
|
285
|
-
const headers = {headers: {
|
|
294
|
+
private async fetchVAAQuery(query: string): Promise<[string[], PriceFeedFormat[]]> {
|
|
295
|
+
const headers = { headers: { "Content-Type": "application/json" } };
|
|
286
296
|
let response = await fetch(query, headers);
|
|
287
297
|
if (!response.ok) {
|
|
288
298
|
throw new Error(`Failed to fetch posts (${response.status}): ${response.statusText}`);
|
|
@@ -302,8 +312,8 @@ export default class PriceFeeds {
|
|
|
302
312
|
* @param query query price-info from endpoint
|
|
303
313
|
* @returns vaa and price info
|
|
304
314
|
*/
|
|
305
|
-
public async fetchPriceQuery(query: string)
|
|
306
|
-
const headers = {headers: {
|
|
315
|
+
public async fetchPriceQuery(query: string): Promise<[string[], PriceFeedFormat[]]> {
|
|
316
|
+
const headers = { headers: { "Content-Type": "application/json" } };
|
|
307
317
|
let response = await fetch(query, headers);
|
|
308
318
|
if (!response.ok) {
|
|
309
319
|
throw new Error(`Failed to fetch posts (${response.status}): ${response.statusText}`);
|
|
@@ -320,17 +330,17 @@ export default class PriceFeeds {
|
|
|
320
330
|
|
|
321
331
|
/**
|
|
322
332
|
* Searches for configuration for given network
|
|
323
|
-
* @param configs pricefeed configuration from json
|
|
333
|
+
* @param configs pricefeed configuration from json
|
|
324
334
|
* @param network e.g. testnet
|
|
325
335
|
* @returns selected configuration
|
|
326
336
|
*/
|
|
327
|
-
static _selectConfig(configs: PriceFeedConfig[], network: string)
|
|
328
|
-
let k=0;
|
|
329
|
-
while(k<configs.length) {
|
|
330
|
-
if (configs[k].network==network) {
|
|
337
|
+
static _selectConfig(configs: PriceFeedConfig[], network: string): PriceFeedConfig {
|
|
338
|
+
let k = 0;
|
|
339
|
+
while (k < configs.length) {
|
|
340
|
+
if (configs[k].network == network) {
|
|
331
341
|
return configs[k];
|
|
332
342
|
}
|
|
333
|
-
k=k+1;
|
|
343
|
+
k = k + 1;
|
|
334
344
|
}
|
|
335
345
|
throw new Error(`PriceFeeds: config not found for network ${network}`);
|
|
336
346
|
}
|
|
@@ -340,32 +350,31 @@ export default class PriceFeeds {
|
|
|
340
350
|
* @param config configuration for the selected network
|
|
341
351
|
* @returns feedInfo-map and endPoints-array
|
|
342
352
|
*/
|
|
343
|
-
static _constructFeedInfo(config: PriceFeedConfig)
|
|
344
|
-
let feed = new Map<string, {symbol:string
|
|
353
|
+
static _constructFeedInfo(config: PriceFeedConfig): [Map<string, { symbol: string; endpointId: number }>, string[]] {
|
|
354
|
+
let feed = new Map<string, { symbol: string; endpointId: number }>();
|
|
345
355
|
let endpointId = -1;
|
|
346
|
-
let type="";
|
|
356
|
+
let type = "";
|
|
347
357
|
let feedEndpoints = new Array<string>();
|
|
348
|
-
for(let k=0; k<config.endpoints.length; k++) {
|
|
358
|
+
for (let k = 0; k < config.endpoints.length; k++) {
|
|
349
359
|
feedEndpoints.push(config.endpoints[k].endpoint);
|
|
350
360
|
}
|
|
351
|
-
for(let k=0; k<config.ids.length; k++) {
|
|
352
|
-
if (type!=config.ids[k].type) {
|
|
361
|
+
for (let k = 0; k < config.ids.length; k++) {
|
|
362
|
+
if (type != config.ids[k].type) {
|
|
353
363
|
type = config.ids[k].type;
|
|
354
|
-
let j=0;
|
|
355
|
-
while(j<config.endpoints.length) {
|
|
356
|
-
if(config.endpoints[j].type == type) {
|
|
364
|
+
let j = 0;
|
|
365
|
+
while (j < config.endpoints.length) {
|
|
366
|
+
if (config.endpoints[j].type == type) {
|
|
357
367
|
endpointId = j;
|
|
358
|
-
j=config.endpoints.length;
|
|
368
|
+
j = config.endpoints.length;
|
|
359
369
|
}
|
|
360
370
|
j++;
|
|
361
371
|
}
|
|
362
|
-
if(config.endpoints[endpointId].type!=type) {
|
|
372
|
+
if (config.endpoints[endpointId].type != type) {
|
|
363
373
|
throw new Error(`priceFeeds: no enpoint found for ${type} check priceFeedConfig`);
|
|
364
374
|
}
|
|
365
375
|
}
|
|
366
|
-
feed.set(config.ids[k].id, {symbol: config.ids[k].symbol.toUpperCase(), endpointId: endpointId });
|
|
376
|
+
feed.set(config.ids[k].id, { symbol: config.ids[k].symbol.toUpperCase(), endpointId: endpointId });
|
|
367
377
|
}
|
|
368
378
|
return [feed, feedEndpoints];
|
|
369
379
|
}
|
|
370
|
-
|
|
371
380
|
}
|
package/src/version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const D8X_SDK_VERSION = "0.1.
|
|
1
|
+
export const D8X_SDK_VERSION = "0.1.5";
|
|
@@ -99,9 +99,9 @@ export default class WriteAccessHandler extends PerpetualDataHandler {
|
|
|
99
99
|
* into a mock token used for trading on testnet, with a rate of 1:100_000
|
|
100
100
|
* @param symbol Pool margin token e.g. MATIC
|
|
101
101
|
* @param amountToPay Amount in chain currency, e.g. "0.1" for 0.1 MATIC
|
|
102
|
-
* @returns
|
|
102
|
+
* @returns Transaction object
|
|
103
103
|
*/
|
|
104
|
-
public async swapForMockToken(symbol: string, amountToPay: string) {
|
|
104
|
+
public async swapForMockToken(symbol: string, amountToPay: string): Promise<ethers.ContractTransaction> {
|
|
105
105
|
if (this.signer == null) {
|
|
106
106
|
throw Error("no wallet initialized. Use createProxyInstance().");
|
|
107
107
|
}
|