@d8x/perpetuals-sdk 0.1.12 → 0.2.0

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 (165) hide show
  1. package/dist/cjs/abi/testnet/IPerpetualManager.json +5215 -0
  2. package/dist/cjs/abi/testnet/LimitOrderBook.json +1075 -0
  3. package/dist/cjs/abi/zkevmTestnet/IPerpetualManager.json +5215 -0
  4. package/dist/cjs/abi/zkevmTestnet/LimitOrderBook.json +1075 -0
  5. package/dist/cjs/abi/zkevmTestnet/LimitOrderBookFactory.json +135 -0
  6. package/dist/cjs/accountTrade.js +441 -0
  7. package/dist/cjs/accountTrade.js.map +1 -0
  8. package/dist/{src → cjs}/brokerTool.js +31 -84
  9. package/dist/cjs/brokerTool.js.map +1 -0
  10. package/dist/cjs/config/defaultConfig.json +47 -0
  11. package/dist/cjs/config/mockSwap.json +4 -0
  12. package/dist/cjs/config/priceFeedConfig.json +104 -0
  13. package/dist/cjs/config/symbolList.json +13 -0
  14. package/dist/cjs/d8XMath.js.map +1 -0
  15. package/dist/cjs/index.js +29 -0
  16. package/dist/cjs/index.js.map +1 -0
  17. package/dist/cjs/liquidatorTool.js +287 -0
  18. package/dist/cjs/liquidatorTool.js.map +1 -0
  19. package/dist/{src → cjs}/liquidityProviderTool.js +12 -65
  20. package/dist/cjs/liquidityProviderTool.js.map +1 -0
  21. package/dist/{src → cjs}/marketData.js +52 -134
  22. package/dist/cjs/marketData.js.map +1 -0
  23. package/dist/{src → cjs}/nodeSDKTypes.d.ts +5 -5
  24. package/dist/cjs/nodeSDKTypes.js +64 -0
  25. package/dist/cjs/nodeSDKTypes.js.map +1 -0
  26. package/dist/{src → cjs}/orderReferrerTool.d.ts +12 -5
  27. package/dist/{src → cjs}/orderReferrerTool.js +114 -112
  28. package/dist/cjs/orderReferrerTool.js.map +1 -0
  29. package/dist/{src → cjs}/perpetualDataHandler.d.ts +1 -1
  30. package/dist/{src → cjs}/perpetualDataHandler.js +47 -109
  31. package/dist/cjs/perpetualDataHandler.js.map +1 -0
  32. package/dist/{src → cjs}/perpetualEventHandler.d.ts +3 -3
  33. package/dist/{src → cjs}/perpetualEventHandler.js +12 -74
  34. package/dist/cjs/perpetualEventHandler.js.map +1 -0
  35. package/dist/cjs/priceFeeds.js +466 -0
  36. package/dist/cjs/priceFeeds.js.map +1 -0
  37. package/dist/{src → cjs}/traderDigests.js +7 -43
  38. package/dist/cjs/traderDigests.js.map +1 -0
  39. package/dist/{src → cjs}/traderInterface.js +13 -66
  40. package/dist/cjs/traderInterface.js.map +1 -0
  41. package/dist/{src → cjs}/triangulator.js +2 -17
  42. package/dist/cjs/triangulator.js.map +1 -0
  43. package/dist/{src → cjs}/utils.js +3 -29
  44. package/dist/cjs/utils.js.map +1 -0
  45. package/dist/cjs/version.d.ts +1 -0
  46. package/dist/{src → cjs}/version.js +1 -1
  47. package/dist/cjs/version.js.map +1 -0
  48. package/dist/{src → cjs}/writeAccessHandler.js +12 -65
  49. package/dist/cjs/writeAccessHandler.js.map +1 -0
  50. package/dist/esm/abi/ERC20.json +288 -0
  51. package/dist/esm/abi/MockTokenSwap.json +186 -0
  52. package/dist/{abi/testnet → esm/abi/central-park}/IPerpetualManager.json +404 -214
  53. package/dist/{abi/testnet → esm/abi/central-park}/LimitOrderBook.json +197 -15
  54. package/dist/esm/abi/central-park/LimitOrderBookFactory.json +135 -0
  55. package/dist/esm/abi/testnet/IPerpetualManager.json +5215 -0
  56. package/dist/esm/abi/testnet/LimitOrderBook.json +1075 -0
  57. package/dist/esm/abi/testnet/LimitOrderBookFactory.json +135 -0
  58. package/dist/esm/abi/zkevmTestnet/IPerpetualManager.json +5215 -0
  59. package/dist/esm/abi/zkevmTestnet/LimitOrderBook.json +1075 -0
  60. package/dist/esm/abi/zkevmTestnet/LimitOrderBookFactory.json +135 -0
  61. package/dist/esm/accountTrade.d.ts +221 -0
  62. package/dist/{src → esm}/accountTrade.js +22 -93
  63. package/dist/esm/accountTrade.js.map +1 -0
  64. package/dist/esm/brokerTool.d.ts +318 -0
  65. package/dist/esm/brokerTool.js +572 -0
  66. package/dist/esm/brokerTool.js.map +1 -0
  67. package/dist/esm/config/defaultConfig.json +47 -0
  68. package/dist/esm/config/mockSwap.json +4 -0
  69. package/dist/esm/config/priceFeedConfig.json +104 -0
  70. package/dist/esm/config/symbolList.json +13 -0
  71. package/dist/esm/d8XMath.d.ts +122 -0
  72. package/dist/esm/d8XMath.js +247 -0
  73. package/dist/esm/d8XMath.js.map +1 -0
  74. package/{src/index.ts → dist/esm/index.d.ts} +1 -15
  75. package/dist/esm/index.js +16 -0
  76. package/dist/esm/index.js.map +1 -0
  77. package/dist/esm/liquidatorTool.d.ts +158 -0
  78. package/dist/{src → esm}/liquidatorTool.js +10 -65
  79. package/dist/esm/liquidatorTool.js.map +1 -0
  80. package/dist/esm/liquidityProviderTool.d.ts +126 -0
  81. package/dist/esm/liquidityProviderTool.js +218 -0
  82. package/dist/esm/liquidityProviderTool.js.map +1 -0
  83. package/dist/esm/marketData.d.ts +309 -0
  84. package/dist/esm/marketData.js +1007 -0
  85. package/dist/esm/marketData.js.map +1 -0
  86. package/dist/esm/nodeSDKTypes.d.ts +266 -0
  87. package/dist/esm/nodeSDKTypes.js +60 -0
  88. package/dist/esm/nodeSDKTypes.js.map +1 -0
  89. package/dist/esm/orderReferrerTool.d.ts +196 -0
  90. package/dist/esm/orderReferrerTool.js +491 -0
  91. package/dist/esm/orderReferrerTool.js.map +1 -0
  92. package/dist/esm/perpetualDataHandler.d.ts +220 -0
  93. package/dist/esm/perpetualDataHandler.js +1060 -0
  94. package/dist/esm/perpetualDataHandler.js.map +1 -0
  95. package/dist/esm/perpetualEventHandler.d.ts +179 -0
  96. package/dist/esm/perpetualEventHandler.js +435 -0
  97. package/dist/esm/perpetualEventHandler.js.map +1 -0
  98. package/dist/esm/priceFeeds.d.ts +115 -0
  99. package/dist/{src → esm}/priceFeeds.js +16 -83
  100. package/dist/esm/priceFeeds.js.map +1 -0
  101. package/dist/esm/traderDigests.d.ts +21 -0
  102. package/dist/esm/traderDigests.js +80 -0
  103. package/dist/esm/traderDigests.js.map +1 -0
  104. package/dist/esm/traderInterface.d.ts +79 -0
  105. package/dist/esm/traderInterface.js +196 -0
  106. package/dist/esm/traderInterface.js.map +1 -0
  107. package/dist/esm/triangulator.d.ts +27 -0
  108. package/dist/esm/triangulator.js +110 -0
  109. package/dist/esm/triangulator.js.map +1 -0
  110. package/dist/esm/utils.d.ts +59 -0
  111. package/dist/esm/utils.js +138 -0
  112. package/dist/esm/utils.js.map +1 -0
  113. package/dist/esm/version.d.ts +1 -0
  114. package/dist/esm/version.js +2 -0
  115. package/dist/esm/version.js.map +1 -0
  116. package/dist/esm/writeAccessHandler.d.ts +50 -0
  117. package/dist/esm/writeAccessHandler.js +157 -0
  118. package/dist/esm/writeAccessHandler.js.map +1 -0
  119. package/package.json +16 -26
  120. package/dist/bundle.js +0 -36793
  121. package/dist/config/defaultConfig.json +0 -47
  122. package/dist/config/mockSwap.json +0 -4
  123. package/dist/config/priceFeedConfig.json +0 -104
  124. package/dist/config/symbolList.json +0 -13
  125. package/dist/src/index.js +0 -45
  126. package/dist/src/nodeSDKTypes.js +0 -115
  127. package/dist/src/version.d.ts +0 -1
  128. package/module.d.ts +0 -1
  129. package/src/accountTrade.ts +0 -392
  130. package/src/brokerTool.ts +0 -507
  131. package/src/d8XMath.ts +0 -319
  132. package/src/liquidatorTool.ts +0 -258
  133. package/src/liquidityProviderTool.ts +0 -186
  134. package/src/marketData.ts +0 -946
  135. package/src/nodeSDKTypes.ts +0 -293
  136. package/src/orderReferrerTool.ts +0 -389
  137. package/src/perpetualDataHandler.ts +0 -1061
  138. package/src/perpetualEventHandler.ts +0 -455
  139. package/src/priceFeeds.ts +0 -381
  140. package/src/traderDigests.ts +0 -91
  141. package/src/traderInterface.ts +0 -159
  142. package/src/triangulator.ts +0 -105
  143. package/src/utils.ts +0 -134
  144. package/src/version.ts +0 -1
  145. package/src/writeAccessHandler.ts +0 -127
  146. /package/dist/{abi → cjs/abi}/ERC20.json +0 -0
  147. /package/dist/{abi → cjs/abi}/MockTokenSwap.json +0 -0
  148. /package/dist/{abi → cjs/abi}/central-park/IPerpetualManager.json +0 -0
  149. /package/dist/{abi → cjs/abi}/central-park/LimitOrderBook.json +0 -0
  150. /package/dist/{abi → cjs/abi}/central-park/LimitOrderBookFactory.json +0 -0
  151. /package/dist/{abi → cjs/abi}/testnet/LimitOrderBookFactory.json +0 -0
  152. /package/dist/{src → cjs}/accountTrade.d.ts +0 -0
  153. /package/dist/{src → cjs}/brokerTool.d.ts +0 -0
  154. /package/dist/{src → cjs}/d8XMath.d.ts +0 -0
  155. /package/dist/{src → cjs}/d8XMath.js +0 -0
  156. /package/dist/{src → cjs}/index.d.ts +0 -0
  157. /package/dist/{src → cjs}/liquidatorTool.d.ts +0 -0
  158. /package/dist/{src → cjs}/liquidityProviderTool.d.ts +0 -0
  159. /package/dist/{src → cjs}/marketData.d.ts +0 -0
  160. /package/dist/{src → cjs}/priceFeeds.d.ts +0 -0
  161. /package/dist/{src → cjs}/traderDigests.d.ts +0 -0
  162. /package/dist/{src → cjs}/traderInterface.d.ts +0 -0
  163. /package/dist/{src → cjs}/triangulator.d.ts +0 -0
  164. /package/dist/{src → cjs}/utils.d.ts +0 -0
  165. /package/dist/{src → cjs}/writeAccessHandler.d.ts +0 -0
package/src/priceFeeds.ts DELETED
@@ -1,381 +0,0 @@
1
- import { BigNumber } from "ethers";
2
- import PerpetualDataHandler from "./perpetualDataHandler";
3
- import Triangulator from "./triangulator";
4
- import { PriceFeedConfig, PriceFeedSubmission, PriceFeedFormat } from "./nodeSDKTypes";
5
- import { decNToFloat } from "./d8XMath";
6
- import { Buffer } from "buffer";
7
-
8
- /**
9
- * This class communicates with the REST API that provides price-data that is
10
- * to be submitted to the smart contracts for certain functions such as
11
- * trader liquidations, trade executions, change of trader margin amount.
12
- */
13
- export default class PriceFeeds {
14
- private config: PriceFeedConfig;
15
- private feedEndpoints: Array<string>; //feedEndpoints[endpointId] = endpointstring
16
- private feedInfo: Map<string, { symbol: string; endpointId: number }>; // priceFeedId -> symbol, endpointId
17
- private dataHandler: PerpetualDataHandler;
18
- // store triangulation paths given the price feeds
19
- private triangulations: Map<string, [string[], boolean[]]>;
20
- private THRESHOLD_MARKET_CLOSED_SEC = 15; // smallest lag for which we consider the market as being closed
21
-
22
- constructor(dataHandler: PerpetualDataHandler, priceFeedConfigNetwork: string) {
23
- let configs = <PriceFeedConfig[]>require("../config/priceFeedConfig.json");
24
- this.config = PriceFeeds._selectConfig(configs, priceFeedConfigNetwork);
25
- [this.feedInfo, this.feedEndpoints] = PriceFeeds._constructFeedInfo(this.config);
26
- this.dataHandler = dataHandler;
27
- this.triangulations = new Map<string, [string[], boolean[]]>();
28
- }
29
-
30
- /**
31
- * Pre-processing of triangulations for symbols, given the price feeds
32
- * @param symbols set of symbols we want to triangulate from price feeds
33
- */
34
- public initializeTriangulations(symbols: Set<string>) {
35
- let feedSymbols = new Array<string>();
36
- for (let [key, value] of this.feedInfo) {
37
- feedSymbols.push(value.symbol);
38
- }
39
- for (let symbol of symbols.values()) {
40
- let triangulation = Triangulator.triangulate(feedSymbols, symbol);
41
- this.triangulations.set(symbol, triangulation);
42
- }
43
- }
44
-
45
- /**
46
- * Get required information to be able to submit a blockchain transaction with price-update
47
- * such as trade execution, liquidation
48
- * @param symbol symbol of perpetual, e.g., BTC-USD-MATIC
49
- * @returns PriceFeedSubmission, index prices, market closed information
50
- */
51
- public async fetchFeedPriceInfoAndIndicesForPerpetual(
52
- symbol: string
53
- ): Promise<{ submission: PriceFeedSubmission; pxS2S3: [number, number]; mktClosed: [boolean, boolean] }> {
54
- let indexSymbols = this.dataHandler.getIndexSymbols(symbol);
55
- // fetch prices from required price-feeds (REST)
56
- let submission: PriceFeedSubmission = await this.fetchLatestFeedPriceInfoForPerpetual(symbol);
57
- // calculate index-prices from price-feeds
58
- let [_idxPrices, _mktClosed] = this.calculateTriangulatedPricesFromFeedInfo(
59
- indexSymbols.filter((x) => x != ""),
60
- submission
61
- );
62
- let idxPrices: [number, number] = [_idxPrices[0], 0];
63
- let mktClosed: [boolean, boolean] = [_mktClosed[0], false];
64
- if (idxPrices.length > 1) {
65
- idxPrices[1] = _idxPrices[1];
66
- mktClosed[1] = _mktClosed[1];
67
- }
68
- return { submission: submission, pxS2S3: idxPrices, mktClosed: mktClosed };
69
- }
70
-
71
- /**
72
- * Get all prices/isMarketClosed for the provided symbols via
73
- * "latest_price_feeds" and triangulation. Triangulation must be defined in config, unless
74
- * it is a direct price feed.
75
- * @returns map of feed-price symbol to price/isMarketClosed
76
- */
77
- public async fetchPrices(symbols: string[]): Promise<Map<string, [number, boolean]>> {
78
- let feedPrices = await this.fetchAllFeedPrices();
79
- let [prices, mktClosed] = this.triangulatePricesFromFeedPrices(symbols, feedPrices);
80
- let symMap = new Map<string, [number, boolean]>();
81
- for (let k = 0; k < symbols.length; k++) {
82
- symMap.set(symbols[k], [prices[k], mktClosed[k]]);
83
- }
84
- return symMap;
85
- }
86
-
87
- /**
88
- * Get index prices and market closed information for the given perpetual
89
- * @param symbol perpetual symbol such as ETH-USD-MATIC
90
- * @returns Index prices and market closed information
91
- */
92
- public async fetchPricesForPerpetual(symbol: string): Promise<{ idxPrices: number[]; mktClosed: boolean[] }> {
93
- let indexSymbols = this.dataHandler.getIndexSymbols(symbol).filter((x) => x != "");
94
- // determine relevant price feeds
95
- let feedSymbols = new Array<string>();
96
- for (let sym of indexSymbols) {
97
- if (sym != "") {
98
- let triang: [string[], boolean[]] | undefined = this.triangulations.get(sym);
99
- if (triang == undefined) {
100
- // no triangulation defined, so symbol must be a feed (unless misconfigured)
101
- feedSymbols.push(sym);
102
- } else {
103
- // push all required feeds to array
104
- triang[0].map((feedSym) => feedSymbols.push(feedSym));
105
- }
106
- }
107
- }
108
- // get all feed prices
109
- let feedPrices = await this.fetchFeedPrices(feedSymbols);
110
- // triangulate
111
- let [prices, mktClosed] = this.triangulatePricesFromFeedPrices(indexSymbols, feedPrices);
112
- // ensure we return an array of 2 in all cases
113
- if (prices.length == 1) {
114
- prices.push(0);
115
- mktClosed.push(false);
116
- }
117
- return { idxPrices: prices, mktClosed: mktClosed };
118
- }
119
-
120
- /**
121
- * Fetch the provided feed prices and bool whether market is closed or open
122
- * - requires the feeds to be defined in priceFeedConfig.json
123
- * - if undefined, all feeds are queried
124
- * @param symbols array of feed-price symbols (e.g., [btc-usd, eth-usd]) or undefined
125
- * @returns mapping symbol-> [price, isMarketClosed]
126
- */
127
- public async fetchFeedPrices(symbols?: string[]): Promise<Map<string, [number, boolean]>> {
128
- let queries = new Array<string>(this.feedEndpoints.length);
129
- let symbolsOfEndpoint: string[][] = [];
130
- for (let j = 0; j < queries.length; j++) {
131
- symbolsOfEndpoint.push([]);
132
- }
133
- for (let k = 0; k < this.config.ids.length; k++) {
134
- let currFeed = this.config.ids[k];
135
- if (symbols != undefined && !symbols.includes(currFeed.symbol)) {
136
- continue;
137
- }
138
- // feedInfo: Map<string, {symbol:string, endpointId: number}>; // priceFeedId -> symbol, endpointId
139
- let endpointId = this.feedInfo.get(currFeed.id)!.endpointId;
140
- symbolsOfEndpoint[endpointId].push(currFeed.symbol);
141
- if (queries[endpointId] == undefined) {
142
- // each id can have a different endpoint, but we cluster
143
- // the queries into one per endpoint
144
- queries[endpointId] = this.feedEndpoints[endpointId] + "/latest_price_feeds?";
145
- }
146
- queries[endpointId] = queries[endpointId] + "ids[]=" + currFeed.id + "&";
147
- }
148
- let resultPrices = new Map<string, [number, boolean]>();
149
- for (let k = 0; k < queries.length; k++) {
150
- if (queries[k] == undefined) {
151
- continue;
152
- }
153
- let [id, pxInfo]: [string[], PriceFeedFormat[]] = await this.fetchPriceQuery(queries[k]);
154
- let tsSecNow = Math.round(Date.now() / 1000);
155
- for (let j = 0; j < pxInfo.length; j++) {
156
- let price = decNToFloat(BigNumber.from(pxInfo[j].price), -pxInfo[j].expo);
157
- let isMarketClosed = tsSecNow - pxInfo[j].publish_time > this.THRESHOLD_MARKET_CLOSED_SEC;
158
- resultPrices.set(symbolsOfEndpoint[k][j], [price, isMarketClosed]);
159
- }
160
- }
161
- return resultPrices;
162
- }
163
-
164
- /**
165
- * Get all configured feed prices via "latest_price_feeds"
166
- * @returns map of feed-price symbol to price/isMarketClosed
167
- */
168
- public async fetchAllFeedPrices(): Promise<Map<string, [number, boolean]>> {
169
- return this.fetchFeedPrices();
170
- }
171
-
172
- /**
173
- * Get the latest prices for a given perpetual from the offchain oracle
174
- * networks
175
- * @param symbol perpetual symbol of the form BTC-USD-MATIC
176
- * @returns array of price feed updates that can be submitted to the smart contract
177
- * and corresponding price information
178
- */
179
- public async fetchLatestFeedPriceInfoForPerpetual(symbol: string): Promise<PriceFeedSubmission> {
180
- let feedIds = this.dataHandler.getPriceIds(symbol);
181
- let queries = new Array<string>(this.feedEndpoints.length);
182
- // we need to preserve the order of the price feeds
183
- let orderEndpointNumber = new Array<number>();
184
- // count how many prices per endpoint
185
- let idCountPriceFeeds = new Array<number>(this.feedEndpoints.length);
186
- let symbols = new Array<string>();
187
- for (let k = 0; k < feedIds.length; k++) {
188
- let info = this.feedInfo.get(feedIds[k]);
189
- if (info == undefined) {
190
- throw new Error(`priceFeeds: config for symbol ${symbol} insufficient`);
191
- }
192
- let id = info.endpointId;
193
- symbols.push(info.symbol);
194
- if (queries[id] == undefined) {
195
- // each id can have a different endpoint, but we cluster
196
- // the queries into one per endpoint
197
- queries[id] = this.feedEndpoints[id] + "/latest_vaas_px?";
198
- idCountPriceFeeds[id] = 0;
199
- }
200
- queries[id] = queries[id] + "ids[]=" + feedIds[k] + "&";
201
- orderEndpointNumber.push(id * 100 + idCountPriceFeeds[id]);
202
- idCountPriceFeeds[id] = idCountPriceFeeds[id] + 1;
203
- }
204
-
205
- let data = await Promise.all(
206
- queries.map(async (q) => {
207
- if (q != undefined) {
208
- return this.fetchVAAQuery(q);
209
- } else {
210
- return [[], []];
211
- }
212
- })
213
- );
214
-
215
- // re-order arrays so we preserve the order of the feeds
216
- const priceFeedUpdates = new Array<string>();
217
- const prices = new Array<number>();
218
- const mktClosed = new Array<boolean>();
219
- const timestamps = new Array<number>();
220
- const tsSecNow = Math.round(Date.now() / 1000);
221
- for (let k = 0; k < orderEndpointNumber.length; k++) {
222
- let endpointId = Math.floor(orderEndpointNumber[k] / 100);
223
- let idWithinEndpoint = orderEndpointNumber[k] - 100 * endpointId;
224
- priceFeedUpdates.push(data[endpointId][0][idWithinEndpoint]);
225
- let pxInfo: PriceFeedFormat = data[endpointId][1][idWithinEndpoint];
226
- let price = decNToFloat(BigNumber.from(pxInfo.price), -pxInfo.expo);
227
- let isMarketClosed = tsSecNow - pxInfo.publish_time > this.THRESHOLD_MARKET_CLOSED_SEC;
228
- mktClosed.push(isMarketClosed);
229
- prices.push(price);
230
- timestamps.push(pxInfo.publish_time);
231
- }
232
-
233
- return {
234
- symbols: symbols,
235
- priceFeedVaas: priceFeedUpdates,
236
- prices: prices,
237
- isMarketClosed: mktClosed,
238
- timestamps: timestamps,
239
- };
240
- }
241
-
242
- /**
243
- * Extract pair-prices from underlying price feeds via triangulation
244
- * The function either needs a direct price feed or a defined triangulation to succesfully
245
- * return a triangulated price
246
- * @param symbols array of pairs for which we want prices, e.g., [BTC-USDC, ETH-USD]
247
- * @param feeds data obtained via fetchLatestFeedPriceInfo or fetchLatestFeedPrices
248
- * @returns array of prices with same order as symbols
249
- */
250
- public calculateTriangulatedPricesFromFeedInfo(symbols: string[], feeds: PriceFeedSubmission): [number[], boolean[]] {
251
- let priceMap = new Map<string, [number, boolean]>();
252
- for (let j = 0; j < feeds.prices.length; j++) {
253
- priceMap.set(feeds.symbols[j], [feeds.prices[j], feeds.isMarketClosed[j]]);
254
- }
255
- return this.triangulatePricesFromFeedPrices(symbols, priceMap);
256
- }
257
- /**
258
- * Extract pair-prices from underlying price feeds via triangulation
259
- * The function either needs a direct price feed or a defined triangulation to succesfully
260
- * return a triangulated price
261
- * @param symbols array of pairs for which we want prices, e.g., [BTC-USDC, ETH-USD]
262
- * @param feeds data obtained via fetchLatestFeedPriceInfo or fetchLatestFeedPrices
263
- * @returns array of prices with same order as symbols
264
- */
265
- public triangulatePricesFromFeedPrices(
266
- symbols: string[],
267
- feedPriceMap: Map<string, [number, boolean]>
268
- ): [number[], boolean[]] {
269
- let prices = new Array<number>();
270
- let mktClosed = new Array<boolean>();
271
- for (let k = 0; k < symbols.length; k++) {
272
- let triangulation: [string[], boolean[]] | undefined = this.triangulations.get(symbols[k]);
273
- if (triangulation == undefined) {
274
- let feedPrice = feedPriceMap.get(symbols[k]);
275
- if (feedPrice == undefined) {
276
- throw new Error(`PriceFeeds: no triangulation defined for ${symbols[k]}`);
277
- } else {
278
- prices.push(feedPrice[0]); //price
279
- mktClosed.push(feedPrice[1]); //market closed?
280
- continue;
281
- }
282
- }
283
- let [px, isMktClosed]: [number, boolean] = Triangulator.calculateTriangulatedPrice(triangulation, feedPriceMap);
284
- prices.push(px);
285
- mktClosed.push(isMktClosed);
286
- }
287
- return [prices, mktClosed];
288
- }
289
-
290
- /**
291
- * Queries the REST endpoint and returns parsed VAA price data
292
- * @param query query price-info from endpoint
293
- * @returns vaa and price info
294
- */
295
- private async fetchVAAQuery(query: string): Promise<[string[], PriceFeedFormat[]]> {
296
- const headers = { headers: { "Content-Type": "application/json" } };
297
- let response = await fetch(query, headers);
298
- if (!response.ok) {
299
- throw new Error(`Failed to fetch posts (${response.status}): ${response.statusText}`);
300
- }
301
- let values = (await response.json()) as Array<[string, PriceFeedFormat]>;
302
- const priceFeedUpdates = new Array<string>();
303
- const px = new Array<PriceFeedFormat>();
304
- for (let k = 0; k < values.length; k++) {
305
- priceFeedUpdates.push("0x" + Buffer.from(values[k][0], "base64").toString("hex"));
306
- px.push(values[k][1]);
307
- }
308
- return [priceFeedUpdates, px];
309
- }
310
-
311
- /**
312
- * Queries the REST endpoint and returns parsed price data
313
- * @param query query price-info from endpoint
314
- * @returns vaa and price info
315
- */
316
- public async fetchPriceQuery(query: string): Promise<[string[], PriceFeedFormat[]]> {
317
- const headers = { headers: { "Content-Type": "application/json" } };
318
- let response = await fetch(query, headers);
319
- if (!response.ok) {
320
- throw new Error(`Failed to fetch posts (${response.status}): ${response.statusText}`);
321
- }
322
- let values = await response.json();
323
- const priceFeedUpdates = new Array<string>();
324
- const px = new Array<PriceFeedFormat>();
325
- for (let k = 0; k < values.length; k++) {
326
- priceFeedUpdates.push("0x" + Buffer.from(values[k].id, "base64").toString("hex"));
327
- px.push(values[k].price as PriceFeedFormat);
328
- }
329
- return [priceFeedUpdates, px];
330
- }
331
-
332
- /**
333
- * Searches for configuration for given network
334
- * @param configs pricefeed configuration from json
335
- * @param network e.g. testnet
336
- * @returns selected configuration
337
- */
338
- static _selectConfig(configs: PriceFeedConfig[], network: string): PriceFeedConfig {
339
- let k = 0;
340
- while (k < configs.length) {
341
- if (configs[k].network == network) {
342
- return configs[k];
343
- }
344
- k = k + 1;
345
- }
346
- throw new Error(`PriceFeeds: config not found for network ${network}`);
347
- }
348
-
349
- /**
350
- * Wraps configuration into convenient data-structure
351
- * @param config configuration for the selected network
352
- * @returns feedInfo-map and endPoints-array
353
- */
354
- static _constructFeedInfo(config: PriceFeedConfig): [Map<string, { symbol: string; endpointId: number }>, string[]] {
355
- let feed = new Map<string, { symbol: string; endpointId: number }>();
356
- let endpointId = -1;
357
- let type = "";
358
- let feedEndpoints = new Array<string>();
359
- for (let k = 0; k < config.endpoints.length; k++) {
360
- feedEndpoints.push(config.endpoints[k].endpoint);
361
- }
362
- for (let k = 0; k < config.ids.length; k++) {
363
- if (type != config.ids[k].type) {
364
- type = config.ids[k].type;
365
- let j = 0;
366
- while (j < config.endpoints.length) {
367
- if (config.endpoints[j].type == type) {
368
- endpointId = j;
369
- j = config.endpoints.length;
370
- }
371
- j++;
372
- }
373
- if (config.endpoints[endpointId].type != type) {
374
- throw new Error(`priceFeeds: no enpoint found for ${type} check priceFeedConfig`);
375
- }
376
- }
377
- feed.set(config.ids[k].id, { symbol: config.ids[k].symbol.toUpperCase(), endpointId: endpointId });
378
- }
379
- return [feed, feedEndpoints];
380
- }
381
- }
@@ -1,91 +0,0 @@
1
- import { toUtf8Bytes } from "@ethersproject/strings";
2
- import { concat } from "@ethersproject/bytes";
3
- import { ethers } from "ethers";
4
- import { SmartContractOrder } from "./nodeSDKTypes";
5
- import { Buffer } from "buffer";
6
-
7
- export default class TraderDigests {
8
- /**
9
- * Creates an order-id from the digest. Order-id is the 'digest' used in the smart contract.
10
- * @param digest created with _createDigest
11
- * @returns orderId string
12
- * @ignore
13
- */
14
- public async createOrderId(digest: string) {
15
- let digestBuffer = Buffer.from(digest.substring(2, digest.length), "hex");
16
- const messagePrefix = "\x19Ethereum Signed Message:\n";
17
- let tmp = concat([toUtf8Bytes(messagePrefix), toUtf8Bytes(String(digestBuffer.length)), digestBuffer]);
18
- // see: https://github.com/ethers-io/ethers.js/blob/c80fcddf50a9023486e9f9acb1848aba4c19f7b6/packages/hash/src.ts/message.ts#L7
19
- return ethers.utils.keccak256(tmp);
20
- }
21
-
22
- /**
23
- * Creates a digest (order-id)
24
- * @param order smart-contract-type order
25
- * @param chainId chainId of network
26
- * @param isNewOrder true unless we cancel
27
- * @param signer ethereum-type wallet
28
- * @param proxyAddress address of the contract
29
- * @returns digest
30
- * @ignore
31
- */
32
- public async createDigest(
33
- order: SmartContractOrder,
34
- chainId: number,
35
- isNewOrder: boolean,
36
- proxyAddress: string
37
- ): Promise<string> {
38
- const NAME = "Perpetual Trade Manager";
39
- const DOMAIN_TYPEHASH = ethers.utils.keccak256(
40
- Buffer.from("EIP712Domain(string name,uint256 chainId,address verifyingContract)")
41
- );
42
- let abiCoder = ethers.utils.defaultAbiCoder;
43
- let domainSeparator = ethers.utils.keccak256(
44
- abiCoder.encode(
45
- ["bytes32", "bytes32", "uint256", "address"],
46
- [DOMAIN_TYPEHASH, ethers.utils.keccak256(Buffer.from(NAME)), chainId, proxyAddress]
47
- )
48
- );
49
- const TRADE_ORDER_TYPEHASH = ethers.utils.keccak256(
50
- Buffer.from(
51
- "Order(uint24 iPerpetualId,uint16 brokerFeeTbps,address traderAddr,address brokerAddr,int128 fAmount,int128 fLimitPrice,int128 fTriggerPrice,uint64 iDeadline,uint32 flags,int128 fLeverage,uint64 createdTimestamp)"
52
- )
53
- );
54
- let structHash = ethers.utils.keccak256(
55
- abiCoder.encode(
56
- [
57
- "bytes32",
58
- "uint24",
59
- "uint16",
60
- "address",
61
- "address",
62
- "int128",
63
- "int128",
64
- "int128",
65
- "uint64",
66
- "uint32",
67
- "int128",
68
- "uint64",
69
- ],
70
- [
71
- TRADE_ORDER_TYPEHASH,
72
- order.iPerpetualId,
73
- order.brokerFeeTbps,
74
- order.traderAddr,
75
- order.brokerAddr,
76
- order.fAmount,
77
- order.fLimitPrice,
78
- order.fTriggerPrice,
79
- order.iDeadline,
80
- order.flags,
81
- order.fLeverage,
82
- order.createdTimestamp,
83
- ]
84
- )
85
- );
86
- let digest = ethers.utils.keccak256(
87
- abiCoder.encode(["bytes32", "bytes32", "bool"], [domainSeparator, structHash, isNewOrder])
88
- );
89
- return digest;
90
- }
91
- }
@@ -1,159 +0,0 @@
1
- import { ethers } from "ethers";
2
- import MarketData from "./marketData";
3
- import PerpetualDataHandler from "./perpetualDataHandler";
4
- import { NodeSDKConfig, SmartContractOrder, Order, ClientOrder, ZERO_ORDER_ID } from "./nodeSDKTypes";
5
- import TraderDigests from "./traderDigests";
6
- import { ABK64x64ToFloat } from "./d8XMath";
7
- /**
8
- * Interface that can be used by front-end that wraps all private functions
9
- * so that signatures can be handled in frontend via wallet
10
- * @extends MarketData
11
- */
12
- export default class TraderInterface extends MarketData {
13
- public digestTool: TraderDigests;
14
-
15
- // accTrade.order(order)
16
- // cancelOrder(symbol: string, orderId: string)
17
- // accTrade.setAllowance
18
- // accTrade.getOrderIds("MATIC-USD-MATIC")
19
-
20
- /**
21
- * Constructor
22
- * @param {NodeSDKConfig} config Configuration object, see
23
- * PerpetualDataHandler.readSDKConfig.
24
- */
25
- constructor(config: NodeSDKConfig) {
26
- super(config);
27
- this.digestTool = new TraderDigests();
28
- }
29
-
30
- /**
31
- * Get the fee that is charged to the trader for a given broker (can be ZERO-address),
32
- * without broker fee
33
- * @param poolSymbolName pool currency (e.g. MATIC)
34
- * @param traderAddr address of trader
35
- * @param brokerAddr address of broker
36
- * @returns fee (in decimals) that is charged by exchange (without broker)
37
- */
38
- public async queryExchangeFee(poolSymbolName: string, traderAddr: string, brokerAddr: string): Promise<number> {
39
- if (this.proxyContract == null) {
40
- throw Error("no proxy contract or wallet initialized. Use createProxyInstance().");
41
- }
42
- let poolId = PerpetualDataHandler._getPoolIdFromSymbol(poolSymbolName, this.poolStaticInfos);
43
- let feeTbps = await this.proxyContract.queryExchangeFee(poolId, traderAddr, brokerAddr);
44
- return feeTbps / 100_000;
45
- }
46
-
47
- /**
48
- *
49
- * @param poolSymbolName pool symbol, e.g. MATIC
50
- * @param traderAddr address of the trader
51
- * @returns volume in USD
52
- */
53
- public async getCurrentTraderVolume(poolSymbolName: string, traderAddr: string): Promise<number> {
54
- if (this.proxyContract == null) {
55
- throw Error("no proxy contract or wallet initialized. Use createProxyInstance().");
56
- }
57
- let poolId = PerpetualDataHandler._getPoolIdFromSymbol(poolSymbolName, this.poolStaticInfos);
58
- let volume = await this.proxyContract.getCurrentTraderVolume(poolId, traderAddr);
59
- return ABK64x64ToFloat(volume);
60
- }
61
-
62
- /**
63
- * Get digest to cancel an order. Digest needs to be signed and submitted via
64
- * orderBookContract.cancelOrder(orderId, signature);
65
- * @param symbol
66
- * @param orderId
67
- * @returns tuple of digest which the trader needs to sign and address of order book contract
68
- */
69
- public async cancelOrderDigest(symbol: string, orderId: string): Promise<{ digest: string; OBContractAddr: string }> {
70
- if (this.proxyContract == null) {
71
- throw Error("no proxy contract initialized. Use createProxyInstance().");
72
- }
73
- let orderBookContract = this.getOrderBookContract(symbol);
74
- let scOrder: SmartContractOrder = await orderBookContract.orderOfDigest(orderId);
75
- let digest = await this.digestTool.createDigest(scOrder, this.chainId, false, this.proxyAddr);
76
- return { digest: digest, OBContractAddr: orderBookContract.address };
77
- }
78
-
79
- /**
80
- * Get the order book address for a perpetual
81
- * @param symbol symbol (e.g. MATIC-USD-MATIC)
82
- * @returns order book address for the perpetual
83
- */
84
- public getOrderBookAddress(symbol: string): string {
85
- let orderBookContract: ethers.Contract = this.getOrderBookContract(symbol);
86
- return orderBookContract.address;
87
- }
88
-
89
- /**
90
- * createSmartContractOrder from user-friendly order
91
- * @param order order struct
92
- * @param traderAddr address of trader
93
- * @returns Smart contract type order struct
94
- */
95
- public createSmartContractOrder(order: Order, traderAddr: string): SmartContractOrder {
96
- let scOrder = TraderInterface.toSmartContractOrder(order, traderAddr, this.symbolToPerpStaticInfo);
97
- return scOrder;
98
- }
99
-
100
- /**
101
- * Create smart contract order and digest that the trader signs.
102
- * await orderBookContract.postOrder(scOrder, signature, { gasLimit: gasLimit });
103
- * Order must contain broker fee and broker address if there is supposed to be a broker.
104
- * @param scOrder smart contract order struct (get from order via createSCOrder)
105
- * @returns digest that the trader has to sign
106
- */
107
- public async orderDigest(scOrder: SmartContractOrder): Promise<string> {
108
- if (this.proxyContract == null) {
109
- throw Error("no proxy contract or wallet initialized. Use createProxyInstance().");
110
- }
111
- let digest = await this.digestTool.createDigest(scOrder, this.chainId, true, this.proxyContract.address);
112
- return digest;
113
- }
114
-
115
- /**
116
- * Get the ABI of a method in the proxy contract
117
- * @param method Name of the method
118
- * @returns ABI as a single string
119
- */
120
- public getProxyABI(method: string): string {
121
- if (this.proxyContract == null) {
122
- throw Error("no proxy contract or wallet initialized. Use createProxyInstance().");
123
- }
124
- return PerpetualDataHandler._getABIFromContract(this.proxyContract, method);
125
- }
126
-
127
- /**
128
- * Get the ABI of a method in the Limit Order Book contract corresponding to a given symbol.
129
- * @param symbol Symbol of the form MATIC-USD-MATIC
130
- * @param method Name of the method
131
- * @returns ABI as a single string
132
- */
133
- public getOrderBookABI(symbol: string, method: string): string {
134
- if (this.proxyContract == null) {
135
- throw Error("no proxy contract or wallet initialized. Use createProxyInstance().");
136
- }
137
- let orderBookContract: ethers.Contract = this.getOrderBookContract(symbol);
138
- return PerpetualDataHandler._getABIFromContract(orderBookContract, method);
139
- }
140
-
141
- public static chainOrders(orders: SmartContractOrder[], ids: string[]): ClientOrder[] {
142
- // add dependency
143
- let obOrders: ClientOrder[] = new Array<ClientOrder>(orders.length);
144
- if (orders.length == 1 || orders.length > 3) {
145
- // nothing to add
146
- obOrders = orders.map((o) => PerpetualDataHandler.fromSmartContratOrderToClientOrder(o));
147
- } else if (orders.length == 2) {
148
- // first order is parent, second a child
149
- obOrders[0] = PerpetualDataHandler.fromSmartContratOrderToClientOrder(orders[0], [ids[1], ZERO_ORDER_ID]);
150
- obOrders[1] = PerpetualDataHandler.fromSmartContratOrderToClientOrder(orders[1], [ZERO_ORDER_ID, ids[0]]);
151
- } else {
152
- // first order is parent, other two its children
153
- obOrders[0] = PerpetualDataHandler.fromSmartContratOrderToClientOrder(orders[0], [ids[1], ids[2]]);
154
- obOrders[1] = PerpetualDataHandler.fromSmartContratOrderToClientOrder(orders[1], [ZERO_ORDER_ID, ids[0]]);
155
- obOrders[2] = PerpetualDataHandler.fromSmartContratOrderToClientOrder(orders[2], [ZERO_ORDER_ID, ids[0]]);
156
- }
157
- return obOrders;
158
- }
159
- }