@evaafi/sdk 0.6.4 → 0.9.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 (129) hide show
  1. package/dist/api/feeds.d.ts +30 -0
  2. package/dist/api/feeds.js +73 -0
  3. package/dist/api/liquidation.js +1 -1
  4. package/dist/api/math.js +1 -1
  5. package/dist/api/parser.d.ts +4 -2
  6. package/dist/api/parser.js +39 -18
  7. package/dist/api/parsers/AbstractOracleParser.d.ts +11 -0
  8. package/dist/api/parsers/AbstractOracleParser.js +9 -0
  9. package/dist/api/parsers/ClassicOracleParser.d.ts +10 -0
  10. package/dist/api/parsers/ClassicOracleParser.js +16 -0
  11. package/dist/api/parsers/PythOracleParser.d.ts +17 -0
  12. package/dist/api/parsers/PythOracleParser.js +22 -0
  13. package/dist/api/parsers/index.d.ts +3 -0
  14. package/dist/api/parsers/index.js +19 -0
  15. package/dist/api/prices.d.ts +6 -6
  16. package/dist/api/prices.js +37 -46
  17. package/dist/api/pyth.d.ts +16 -0
  18. package/dist/api/pyth.js +35 -0
  19. package/dist/constants/assets/assetId.d.ts +22 -0
  20. package/dist/constants/assets/assetId.js +29 -0
  21. package/dist/constants/assets/index.d.ts +3 -0
  22. package/dist/constants/assets/index.js +19 -0
  23. package/dist/constants/assets/mainnet.d.ts +19 -0
  24. package/dist/constants/assets/mainnet.js +114 -0
  25. package/dist/constants/assets/testnet.d.ts +14 -0
  26. package/dist/constants/assets/testnet.js +54 -0
  27. package/dist/constants/assets.d.ts +3 -0
  28. package/dist/constants/assets.js +14 -1
  29. package/dist/constants/general/index.d.ts +65 -0
  30. package/dist/constants/general/index.js +93 -0
  31. package/dist/constants/general/mainnet.d.ts +24 -0
  32. package/dist/constants/general/mainnet.js +53 -0
  33. package/dist/constants/general/testnet.d.ts +12 -0
  34. package/dist/constants/general/testnet.js +15 -0
  35. package/dist/constants/general.d.ts +4 -4
  36. package/dist/constants/general.js +6 -6
  37. package/dist/constants/index.d.ts +3 -0
  38. package/dist/constants/index.js +19 -0
  39. package/dist/constants/pools/index.d.ts +2 -0
  40. package/dist/constants/pools/index.js +18 -0
  41. package/dist/constants/pools/mainnet.d.ts +14 -0
  42. package/dist/constants/pools/mainnet.js +145 -0
  43. package/dist/constants/pools/testnet.d.ts +9 -0
  44. package/dist/constants/pools/testnet.js +57 -0
  45. package/dist/constants/pools.js +9 -9
  46. package/dist/contracts/AbstractMaster.d.ts +185 -0
  47. package/dist/contracts/AbstractMaster.js +179 -0
  48. package/dist/contracts/ClassicMaster.d.ts +34 -0
  49. package/dist/contracts/ClassicMaster.js +87 -0
  50. package/dist/contracts/PythMaster.d.ts +61 -0
  51. package/dist/contracts/PythMaster.js +179 -0
  52. package/dist/contracts/UserContract.d.ts +1 -7
  53. package/dist/contracts/UserContract.js +1 -19
  54. package/dist/contracts/index.d.ts +5 -0
  55. package/dist/contracts/index.js +21 -0
  56. package/dist/index.d.ts +14 -14
  57. package/dist/index.js +20 -60
  58. package/dist/prices/Oracle.interface.d.ts +9 -0
  59. package/dist/prices/Oracle.interface.js +2 -0
  60. package/dist/prices/Prices.d.ts +5 -3
  61. package/dist/prices/Prices.js +13 -3
  62. package/dist/prices/PricesCollector.d.ts +17 -7
  63. package/dist/prices/PricesCollector.js +67 -51
  64. package/dist/prices/PythCollector.d.ts +22 -0
  65. package/dist/prices/PythCollector.js +217 -0
  66. package/dist/prices/Types.d.ts +17 -2
  67. package/dist/prices/Types.js +8 -1
  68. package/dist/prices/index.d.ts +4 -3
  69. package/dist/prices/index.js +4 -3
  70. package/dist/prices/sources/Backend.d.ts +5 -4
  71. package/dist/prices/sources/Backend.js +16 -13
  72. package/dist/prices/sources/Icp.d.ts +2 -1
  73. package/dist/prices/sources/Icp.js +12 -9
  74. package/dist/prices/sources/PriceSource.d.ts +7 -6
  75. package/dist/prices/utils.d.ts +10 -9
  76. package/dist/prices/utils.js +32 -46
  77. package/dist/rewards/RewardMaster.d.ts +0 -1
  78. package/dist/rewards/RewardUser.d.ts +0 -1
  79. package/dist/types/Master.d.ts +10 -31
  80. package/dist/types/Master.js +3 -0
  81. package/dist/types/MasterRewards.d.ts +0 -1
  82. package/dist/types/UserRewards.d.ts +0 -1
  83. package/dist/utils/sha256BigInt.d.ts +0 -1
  84. package/dist/utils/userJettonWallet.js +0 -8
  85. package/dist/utils/utils.d.ts +8 -1
  86. package/dist/utils/utils.js +31 -2
  87. package/package.json +4 -3
  88. package/src/api/feeds.ts +90 -0
  89. package/src/api/liquidation.ts +1 -1
  90. package/src/api/math.ts +1 -1
  91. package/src/api/parser.ts +100 -38
  92. package/src/api/parsers/AbstractOracleParser.ts +16 -0
  93. package/src/api/parsers/ClassicOracleParser.ts +20 -0
  94. package/src/api/parsers/PythOracleParser.ts +34 -0
  95. package/src/api/parsers/index.ts +3 -0
  96. package/src/api/prices.ts +32 -41
  97. package/src/constants/assets/assetId.ts +30 -0
  98. package/src/constants/assets/index.ts +3 -0
  99. package/src/constants/{assets.ts → assets/mainnet.ts} +27 -94
  100. package/src/constants/assets/testnet.ts +74 -0
  101. package/src/constants/general/index.ts +91 -0
  102. package/src/constants/{general.ts → general/mainnet.ts} +48 -72
  103. package/src/constants/general/testnet.ts +25 -0
  104. package/src/constants/index.ts +3 -0
  105. package/src/constants/pools/index.ts +2 -0
  106. package/src/constants/pools/mainnet.ts +218 -0
  107. package/src/constants/pools/testnet.ts +75 -0
  108. package/src/contracts/AbstractMaster.ts +450 -0
  109. package/src/contracts/ClassicMaster.ts +149 -0
  110. package/src/contracts/PythMaster.ts +313 -0
  111. package/src/contracts/UserContract.ts +7 -28
  112. package/src/contracts/index.ts +7 -0
  113. package/src/index.ts +18 -85
  114. package/src/prices/Oracle.interface.ts +18 -0
  115. package/src/prices/Prices.ts +17 -4
  116. package/src/prices/PricesCollector.ts +91 -68
  117. package/src/prices/PythCollector.ts +294 -0
  118. package/src/prices/Types.ts +28 -6
  119. package/src/prices/index.ts +4 -3
  120. package/src/prices/sources/Backend.ts +21 -19
  121. package/src/prices/sources/Icp.ts +13 -10
  122. package/src/prices/sources/PriceSource.ts +6 -5
  123. package/src/prices/utils.ts +65 -68
  124. package/src/types/Master.ts +29 -52
  125. package/src/types/User.ts +15 -7
  126. package/src/utils/userJettonWallet.ts +0 -8
  127. package/src/utils/utils.ts +41 -2
  128. package/src/constants/pools.ts +0 -175
  129. package/src/contracts/MasterContract.ts +0 -410
@@ -0,0 +1,217 @@
1
+ "use strict";
2
+ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
3
+ if (kind === "m") throw new TypeError("Private method is not writable");
4
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
5
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
6
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
7
+ };
8
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
9
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
10
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
11
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
12
+ };
13
+ var _PythCollector_instances, _PythCollector_oracleInfo, _PythCollector_parsedFeedsMap, _PythCollector_pythConfig, _PythCollector_poolAssetsConfig, _PythCollector_pythToEvaaDirect, _PythCollector_pythToEvaaReferred, _PythCollector_evaaToPythDirect, _PythCollector_allowedRefEvaa, _PythCollector_getPythFeedsUpdates, _PythCollector_fetchPythUpdatesWithRetry, _PythCollector_filterEmptyPrincipalsAndAssets;
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.PythCollector = void 0;
16
+ const hermes_client_1 = require("@pythnetwork/hermes-client");
17
+ const core_1 = require("@ton/core");
18
+ const math_1 = require("../api/math");
19
+ const prices_1 = require("../api/prices");
20
+ const constants_1 = require("../constants");
21
+ const Master_1 = require("../types/Master");
22
+ const utils_1 = require("../utils/utils");
23
+ const Prices_1 = require("./Prices");
24
+ const constants_2 = require("./constants");
25
+ class PythCollector {
26
+ constructor(config) {
27
+ _PythCollector_instances.add(this);
28
+ _PythCollector_oracleInfo.set(this, void 0);
29
+ _PythCollector_parsedFeedsMap.set(this, void 0);
30
+ _PythCollector_pythConfig.set(this, void 0);
31
+ _PythCollector_poolAssetsConfig.set(this, void 0);
32
+ _PythCollector_pythToEvaaDirect.set(this, new Map()); // pythId -> evaaId (native)
33
+ _PythCollector_pythToEvaaReferred.set(this, new Map()); // pythId -> Set<evaaId>,
34
+ _PythCollector_evaaToPythDirect.set(this, new Map()); // evaaId -> pythId (native)
35
+ _PythCollector_allowedRefEvaa.set(this, new Map()); // evaaId -> baseEvaaId (allowedRefTokens)
36
+ __classPrivateFieldSet(this, _PythCollector_oracleInfo, config.pythOracle, "f");
37
+ __classPrivateFieldSet(this, _PythCollector_pythConfig, config.pythConfig, "f");
38
+ __classPrivateFieldSet(this, _PythCollector_poolAssetsConfig, config.poolAssetsConfig, "f");
39
+ __classPrivateFieldSet(this, _PythCollector_parsedFeedsMap, (0, Master_1.parseFeedsMapDict)(__classPrivateFieldGet(this, _PythCollector_oracleInfo, "f").feedsMap), "f");
40
+ // 1) pythId -> evaaId, evaaId -> pythId
41
+ for (const [pythId, feedInfo] of __classPrivateFieldGet(this, _PythCollector_parsedFeedsMap, "f").entries()) {
42
+ __classPrivateFieldGet(this, _PythCollector_pythToEvaaDirect, "f").set(pythId, feedInfo.evaaId);
43
+ __classPrivateFieldGet(this, _PythCollector_evaaToPythDirect, "f").set(feedInfo.evaaId, pythId);
44
+ }
45
+ // 2) pythId (native) -> Set<evaaId>
46
+ for (const [pythId, feedInfo] of __classPrivateFieldGet(this, _PythCollector_parsedFeedsMap, "f").entries()) {
47
+ const ref = feedInfo.referredPythFeed;
48
+ if (ref && ref !== 0n) {
49
+ if (!__classPrivateFieldGet(this, _PythCollector_pythToEvaaReferred, "f").has(ref))
50
+ __classPrivateFieldGet(this, _PythCollector_pythToEvaaReferred, "f").set(ref, new Set());
51
+ __classPrivateFieldGet(this, _PythCollector_pythToEvaaReferred, "f").get(ref).add(feedInfo.evaaId);
52
+ }
53
+ }
54
+ // 3) evaaId -> baseEvaaId (allowedRefTokens)
55
+ for (const evaaId of __classPrivateFieldGet(this, _PythCollector_oracleInfo, "f").allowedRefTokens.keys()) {
56
+ const base = __classPrivateFieldGet(this, _PythCollector_oracleInfo, "f").allowedRefTokens.get(evaaId);
57
+ __classPrivateFieldGet(this, _PythCollector_allowedRefEvaa, "f").set(evaaId, base);
58
+ // If baseEvaaId have pythId. evaaId -> pyth(base)
59
+ const basePyth = __classPrivateFieldGet(this, _PythCollector_evaaToPythDirect, "f").get(base);
60
+ if (basePyth) {
61
+ if (!__classPrivateFieldGet(this, _PythCollector_pythToEvaaReferred, "f").has(basePyth))
62
+ __classPrivateFieldGet(this, _PythCollector_pythToEvaaReferred, "f").set(basePyth, new Set());
63
+ __classPrivateFieldGet(this, _PythCollector_pythToEvaaReferred, "f").get(basePyth).add(evaaId);
64
+ }
65
+ }
66
+ }
67
+ async getPricesForLiquidate(realPrincipals, fetchConfig) {
68
+ const assets = __classPrivateFieldGet(this, _PythCollector_instances, "m", _PythCollector_filterEmptyPrincipalsAndAssets).call(this, realPrincipals);
69
+ if (assets.includes(undefined)) {
70
+ throw new Error('User from another pool');
71
+ }
72
+ return await this.getPrices(assets.map((x) => x), fetchConfig);
73
+ }
74
+ async getPricesForSupplyWithdraw(realPrincipals, supplyAsset, withdrawAsset, collateralToDebt, fetchConfig) {
75
+ let assets = __classPrivateFieldGet(this, _PythCollector_instances, "m", _PythCollector_filterEmptyPrincipalsAndAssets).call(this, realPrincipals);
76
+ if ((0, math_1.checkNotInDebtAtAll)(realPrincipals) &&
77
+ withdrawAsset &&
78
+ (realPrincipals.get(withdrawAsset.assetId) ?? 0n) > 0n &&
79
+ !collateralToDebt) {
80
+ return new Prices_1.Prices(core_1.Dictionary.empty(), core_1.Cell.EMPTY, undefined, undefined);
81
+ }
82
+ if (assets.includes(undefined)) {
83
+ throw new Error('User from another pool');
84
+ }
85
+ if (withdrawAsset && !assets.find((a) => a?.assetId === withdrawAsset.assetId)) {
86
+ assets.push(withdrawAsset);
87
+ }
88
+ if (collateralToDebt && assets.length == 1) {
89
+ throw new Error('Cannot debt only one supplied asset');
90
+ }
91
+ return await this.getPrices(assets.map((x) => x), fetchConfig);
92
+ }
93
+ async getPrices(assets = __classPrivateFieldGet(this, _PythCollector_poolAssetsConfig, "f"), fetchConfig) {
94
+ // Declare variables at the beginning
95
+ let minPublishTime;
96
+ let maxPublishTime;
97
+ if (assets.length === 0) {
98
+ return new Prices_1.Prices(core_1.Dictionary.empty(), core_1.Cell.EMPTY, undefined, undefined);
99
+ }
100
+ const requiredFeeds = this.createRequiredFeedsList(assets.map((a) => a.assetId));
101
+ const pythUpdates = await __classPrivateFieldGet(this, _PythCollector_instances, "m", _PythCollector_fetchPythUpdatesWithRetry).call(this, requiredFeeds, fetchConfig);
102
+ // Calculate min and max publish times for validation
103
+ if (pythUpdates.parsed && pythUpdates.parsed.length > 0) {
104
+ const publishTimes = pythUpdates.parsed.map((u) => BigInt(u.price.publish_time));
105
+ const tmin = publishTimes.reduce((a, b) => (a < b ? a : b));
106
+ const tmax = publishTimes.reduce((a, b) => (a > b ? a : b));
107
+ if (tmax - tmin > constants_2.TTL_ORACLE_DATA_SEC) {
108
+ throw new Error(`Price feeds don't fit in a single 3-minute window. Time span: ${tmax - tmin} seconds (max allowed: ${constants_2.TTL_ORACLE_DATA_SEC})`);
109
+ }
110
+ // Set boundaries using "from oldest" approach: minPublishTime = tmin, maxPublishTime = tmin + 180
111
+ minPublishTime = tmin;
112
+ maxPublishTime = tmin + BigInt(constants_2.TTL_ORACLE_DATA_SEC);
113
+ }
114
+ const pricesDict = core_1.Dictionary.empty();
115
+ const pythPriceUpdates = pythUpdates.parsed;
116
+ if (pythPriceUpdates) {
117
+ // Only set prices for requested assets, not all possible mapped assets
118
+ const requestedAssetIds = new Set(assets.map((a) => a.assetId));
119
+ for (const u of pythPriceUpdates) {
120
+ const pythId = BigInt('0x' + u.id);
121
+ const price = (BigInt(u.price.price) * BigInt(10 ** 9)) / BigInt(10 ** (u.price.expo * -1));
122
+ // Set price for direct mapping if the evaaId is requested
123
+ const directEvaa = __classPrivateFieldGet(this, _PythCollector_pythToEvaaDirect, "f").get(pythId);
124
+ if (directEvaa && requestedAssetIds.has(directEvaa)) {
125
+ pricesDict.set(directEvaa, price);
126
+ }
127
+ // Set price for referred assets only if they are requested
128
+ const referredSet = __classPrivateFieldGet(this, _PythCollector_pythToEvaaReferred, "f").get(pythId);
129
+ if (referredSet && referredSet.size) {
130
+ for (const evaaId of referredSet) {
131
+ if (requestedAssetIds.has(evaaId)) {
132
+ pricesDict.set(evaaId, price);
133
+ }
134
+ }
135
+ }
136
+ }
137
+ // TODO: fix it
138
+ if (pricesDict.get(constants_1.TSTON_MAINNET.assetId) && pricesDict.get(constants_1.TON_MAINNET.assetId)) {
139
+ pricesDict.set(constants_1.TSTON_MAINNET.assetId, (pricesDict.get(constants_1.TSTON_MAINNET.assetId) * pricesDict.get(constants_1.TON_MAINNET.assetId)) / BigInt(10 ** 9));
140
+ }
141
+ // TODO: fix it
142
+ if (pricesDict.get(constants_1.STTON_MAINNET.assetId) && pricesDict.get(constants_1.TON_MAINNET.assetId)) {
143
+ pricesDict.set(constants_1.STTON_MAINNET.assetId, (pricesDict.get(constants_1.STTON_MAINNET.assetId) * pricesDict.get(constants_1.TON_MAINNET.assetId)) / BigInt(10 ** 9));
144
+ }
145
+ // TODO: fix it
146
+ if (pricesDict.get(constants_1.TSUSDE_MAINNET.assetId) && pricesDict.get(constants_1.USDE_MAINNET.assetId)) {
147
+ pricesDict.set(constants_1.TSUSDE_MAINNET.assetId, (pricesDict.get(constants_1.TSUSDE_MAINNET.assetId) * pricesDict.get(constants_1.USDE_MAINNET.assetId)) / BigInt(10 ** 9));
148
+ }
149
+ // Check that all requested assets have prices
150
+ const missing = assets.map((a) => a.assetId).filter((id) => pricesDict.get(id) === undefined);
151
+ if (missing.length) {
152
+ throw new Error(`Missing prices for ${missing.length} asset(s): ${missing.map((x) => x.toString()).join(', ')}`);
153
+ }
154
+ const dataCell = (0, prices_1.packPythUpdatesData)(pythUpdates.binary);
155
+ return new Prices_1.Prices(pricesDict, dataCell, minPublishTime, maxPublishTime);
156
+ }
157
+ return new Prices_1.Prices(core_1.Dictionary.empty(), core_1.Cell.EMPTY, minPublishTime, maxPublishTime);
158
+ }
159
+ async getPricesForWithdraw(realPrincipals, withdrawAsset, collateralToDebt = false, fetchConfig) {
160
+ let assets = __classPrivateFieldGet(this, _PythCollector_instances, "m", _PythCollector_filterEmptyPrincipalsAndAssets).call(this, realPrincipals);
161
+ if ((0, math_1.checkNotInDebtAtAll)(realPrincipals) &&
162
+ (realPrincipals.get(withdrawAsset.assetId) ?? 0n) > 0n &&
163
+ !collateralToDebt) {
164
+ return new Prices_1.Prices(core_1.Dictionary.empty(), core_1.Cell.EMPTY);
165
+ }
166
+ if (assets.includes(undefined)) {
167
+ throw new Error('User from another pool');
168
+ }
169
+ if (!assets.includes(withdrawAsset)) {
170
+ assets.push(withdrawAsset);
171
+ }
172
+ if (collateralToDebt && assets.length == 1) {
173
+ throw new Error('Cannot debt only one supplied asset');
174
+ }
175
+ return await this.getPrices(assets.map((x) => x), fetchConfig);
176
+ }
177
+ createRequiredFeedsList(evaaIds) {
178
+ const requiredFeeds = new Set();
179
+ for (const evaaId of evaaIds) {
180
+ let pythId = __classPrivateFieldGet(this, _PythCollector_evaaToPythDirect, "f").get(evaaId);
181
+ // If evaaId no have native feed — try by allowedRefTokens (evAA->baseEvAA->pyth)
182
+ if (!pythId) {
183
+ const baseEvaa = __classPrivateFieldGet(this, _PythCollector_allowedRefEvaa, "f").get(evaaId);
184
+ if (baseEvaa)
185
+ pythId = __classPrivateFieldGet(this, _PythCollector_evaaToPythDirect, "f").get(baseEvaa) ?? null;
186
+ }
187
+ if (pythId) {
188
+ requiredFeeds.add(pythId);
189
+ const feedInfo = __classPrivateFieldGet(this, _PythCollector_parsedFeedsMap, "f").get(pythId);
190
+ if (feedInfo?.referredPythFeed && feedInfo.referredPythFeed !== 0n) {
191
+ requiredFeeds.add(feedInfo.referredPythFeed);
192
+ }
193
+ }
194
+ }
195
+ return Array.from(requiredFeeds).map((id) => '0x' + id.toString(16));
196
+ }
197
+ }
198
+ exports.PythCollector = PythCollector;
199
+ _PythCollector_oracleInfo = new WeakMap(), _PythCollector_parsedFeedsMap = new WeakMap(), _PythCollector_pythConfig = new WeakMap(), _PythCollector_poolAssetsConfig = new WeakMap(), _PythCollector_pythToEvaaDirect = new WeakMap(), _PythCollector_pythToEvaaReferred = new WeakMap(), _PythCollector_evaaToPythDirect = new WeakMap(), _PythCollector_allowedRefEvaa = new WeakMap(), _PythCollector_instances = new WeakSet(), _PythCollector_getPythFeedsUpdates =
200
+ /**
201
+ * Updates feeds data from specified endpoint
202
+ * @param feedIds list of pyth feed ids to fetch
203
+ * @returns binary - buffer of feeds update, parsed - json feeds data
204
+ */
205
+ async function _PythCollector_getPythFeedsUpdates(feedIds) {
206
+ const latestPriceUpdates = await Promise.any(__classPrivateFieldGet(this, _PythCollector_pythConfig, "f").pythEndpoints.map((x) => new hermes_client_1.HermesClient(x).getLatestPriceUpdates(feedIds, { encoding: 'hex' })));
207
+ const parsed = latestPriceUpdates['parsed'];
208
+ const binary = Buffer.from(latestPriceUpdates.binary.data[0], 'hex');
209
+ return { binary, parsed };
210
+ }, _PythCollector_fetchPythUpdatesWithRetry = async function _PythCollector_fetchPythUpdatesWithRetry(requiredFeeds, fetchConfig) {
211
+ return (0, utils_1.proxyFetchRetries)(__classPrivateFieldGet(this, _PythCollector_instances, "m", _PythCollector_getPythFeedsUpdates).call(this, requiredFeeds), fetchConfig);
212
+ }, _PythCollector_filterEmptyPrincipalsAndAssets = function _PythCollector_filterEmptyPrincipalsAndAssets(principals) {
213
+ return principals
214
+ .keys()
215
+ .filter((x) => principals.get(x) != 0n)
216
+ .map((x) => __classPrivateFieldGet(this, _PythCollector_poolAssetsConfig, "f").find((asset) => asset.assetId == x));
217
+ };
@@ -1,6 +1,6 @@
1
1
  /// <reference types="node" />
2
- /// <reference types="node" />
3
- import { Cell, Dictionary } from '@ton/core';
2
+ import type { PriceUpdate } from '@pythnetwork/hermes-client';
3
+ import type { Cell, Dictionary } from '@ton/core';
4
4
  /**
5
5
  * Configuration for price source endpoints.
6
6
  */
@@ -10,10 +10,21 @@ export type PriceSourcesConfig = {
10
10
  /** Endpoints for ICP price data */
11
11
  icpEndpoints: string[];
12
12
  };
13
+ /**
14
+ * Configuration for pyth prices.
15
+ */
16
+ export type PythPriceSourcesConfig = {
17
+ /** Endpoints for pyth price data */
18
+ pythEndpoints: string[];
19
+ };
13
20
  /**
14
21
  * Default configuration for price source endpoints.
15
22
  */
16
23
  export declare const DefaultPriceSourcesConfig: PriceSourcesConfig;
24
+ /**
25
+ * Configuration for pyth price sources.
26
+ */
27
+ export declare const DefaultPythPriceSourcesConfig: PythPriceSourcesConfig;
17
28
  export type RawPriceData = {
18
29
  dict: Dictionary<bigint, bigint>;
19
30
  dataCell: Cell;
@@ -22,6 +33,10 @@ export type RawPriceData = {
22
33
  pubkey: Buffer;
23
34
  timestamp: number;
24
35
  };
36
+ export type PythFeedUpdateType = {
37
+ parsed: PriceUpdate['parsed'];
38
+ binary: Buffer;
39
+ };
25
40
  export type PriceData = {
26
41
  dict: Dictionary<bigint, bigint>;
27
42
  dataCell: Cell;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.DefaultPriceSourcesConfig = void 0;
3
+ exports.DefaultPythPriceSourcesConfig = exports.DefaultPriceSourcesConfig = void 0;
4
4
  /**
5
5
  * Default configuration for price source endpoints.
6
6
  */
@@ -8,3 +8,10 @@ exports.DefaultPriceSourcesConfig = {
8
8
  backendEndpoints: ['api.evaa.space', 'evaa.space'],
9
9
  icpEndpoints: ['6khmc-aiaaa-aaaap-ansfq-cai.raw.icp0.io'],
10
10
  };
11
+ /**
12
+ * Configuration for pyth price sources.
13
+ */
14
+ exports.DefaultPythPriceSourcesConfig = {
15
+ // FYI: 3RPS limit per IP, TODO: support Pythnet RPC
16
+ pythEndpoints: ['https://hermes.pyth.network'],
17
+ };
@@ -1,6 +1,7 @@
1
- export * from './sources';
2
- export * from './Types';
3
1
  export * from './constants';
4
- export * from './utils';
5
2
  export * from './Prices';
6
3
  export * from './PricesCollector';
4
+ export * from './PythCollector';
5
+ export * from './sources';
6
+ export * from './Types';
7
+ export * from './utils';
@@ -14,9 +14,10 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- __exportStar(require("./sources"), exports);
18
- __exportStar(require("./Types"), exports);
19
17
  __exportStar(require("./constants"), exports);
20
- __exportStar(require("./utils"), exports);
21
18
  __exportStar(require("./Prices"), exports);
22
19
  __exportStar(require("./PricesCollector"), exports);
20
+ __exportStar(require("./PythCollector"), exports);
21
+ __exportStar(require("./sources"), exports);
22
+ __exportStar(require("./Types"), exports);
23
+ __exportStar(require("./utils"), exports);
@@ -1,9 +1,10 @@
1
- import { RawPriceData } from "..";
2
- import { PriceSource } from "./PriceSource";
1
+ import { RawPriceData } from '..';
2
+ import { FetchConfig } from '../../utils/utils';
3
+ import { PriceSource } from './PriceSource';
3
4
  export declare class BackendPriceSource extends PriceSource {
4
5
  protected priceSourceName: string;
5
- getPrices(): Promise<RawPriceData[]>;
6
- loadOracleData(): Promise<OutputData[]>;
6
+ getPrices(fetchConfig?: FetchConfig): Promise<RawPriceData[]>;
7
+ loadOracleData(fetchConfig?: FetchConfig): Promise<OutputData[]>;
7
8
  parsePrices(outputData: OutputData): RawPriceData;
8
9
  }
9
10
  type OutputData = {
@@ -2,28 +2,31 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.BackendPriceSource = void 0;
4
4
  const core_1 = require("@ton/core");
5
+ const utils_1 = require("../../utils/utils");
5
6
  const PriceSource_1 = require("./PriceSource");
6
7
  class BackendPriceSource extends PriceSource_1.PriceSource {
7
8
  constructor() {
8
9
  super(...arguments);
9
10
  this.priceSourceName = 'BackendPriceSource';
10
11
  }
11
- async getPrices() {
12
- const data = await this.loadOracleData();
13
- return data.map(outputData => this.parsePrices(outputData));
12
+ async getPrices(fetchConfig) {
13
+ const data = await this.loadOracleData(fetchConfig);
14
+ return data.map((outputData) => this.parsePrices(outputData));
14
15
  }
15
- async loadOracleData() {
16
- let response = await fetch(`https://${this._endpoint}/api/prices`, {
16
+ async loadOracleData(fetchConfig = utils_1.DefaultFetchConfig) {
17
+ const fetchPromise = fetch(`https://${this._endpoint}/api/prices`, {
17
18
  headers: { accept: 'application/json' },
18
- signal: AbortSignal.timeout(5000)
19
+ signal: AbortSignal.timeout(fetchConfig.timeout),
20
+ }).then(async (response) => {
21
+ const resp = await response.json();
22
+ const data = resp;
23
+ let outputData = [];
24
+ for (const nft of this._nfts) {
25
+ outputData.push({ oracleId: nft.id, data: data[nft.address] });
26
+ }
27
+ return outputData;
19
28
  });
20
- const resp = (await response.json());
21
- const data = resp;
22
- let outputData = [];
23
- for (const nft of this._nfts) {
24
- outputData.push({ oracleId: nft.id, data: data[nft.address] });
25
- }
26
- return outputData;
29
+ return await (0, utils_1.proxyFetchRetries)(fetchPromise, fetchConfig);
27
30
  }
28
31
  parsePrices(outputData) {
29
32
  try {
@@ -1,7 +1,8 @@
1
1
  import { BackendPriceSource } from ".";
2
+ import { FetchConfig } from "../../utils/utils";
2
3
  export declare class IcpPriceSource extends BackendPriceSource {
3
4
  protected priceSourceName: string;
4
- loadOracleData(): Promise<OutputData[]>;
5
+ loadOracleData(fetchConfig?: FetchConfig): Promise<OutputData[]>;
5
6
  }
6
7
  type OutputData = {
7
8
  oracleId: number;
@@ -2,22 +2,25 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.IcpPriceSource = void 0;
4
4
  const _1 = require(".");
5
+ const utils_1 = require("../../utils/utils");
5
6
  class IcpPriceSource extends _1.BackendPriceSource {
6
7
  constructor() {
7
8
  super(...arguments);
8
9
  this.priceSourceName = 'IcpPriceSource';
9
10
  }
10
- async loadOracleData() {
11
- let response = await fetch(`https://${this._endpoint}/prices`, {
11
+ async loadOracleData(fetchConfig = utils_1.DefaultFetchConfig) {
12
+ const fetchPromise = fetch(`https://${this._endpoint}/prices`, {
12
13
  headers: { accept: 'application/json' },
13
- signal: AbortSignal.timeout(5000)
14
+ signal: AbortSignal.timeout(fetchConfig.timeout)
15
+ }).then(async (response) => {
16
+ const data = (await response.json());
17
+ let outputData = [];
18
+ for (const nft of this._nfts) {
19
+ outputData.push({ oracleId: nft.id, data: data[nft.address] });
20
+ }
21
+ return outputData;
14
22
  });
15
- const data = (await response.json());
16
- let outputData = [];
17
- for (const nft of this._nfts) {
18
- outputData.push({ oracleId: nft.id, data: data[nft.address] });
19
- }
20
- return outputData;
23
+ return await (0, utils_1.proxyFetchRetries)(fetchPromise, fetchConfig);
21
24
  }
22
25
  }
23
26
  exports.IcpPriceSource = IcpPriceSource;
@@ -1,14 +1,15 @@
1
1
  import { RawPriceData } from "..";
2
- import { OracleNFT } from "../../types/Master";
2
+ import { ExtendedEvaaOracle } from "../../types/Master";
3
+ import { FetchConfig } from "../../utils/utils";
3
4
  export declare abstract class PriceSource {
4
5
  protected priceSourceName: string;
5
6
  protected _endpoint: string;
6
- protected _nfts: OracleNFT[];
7
- constructor(endpoint: string, nfts: OracleNFT[]);
7
+ protected _nfts: ExtendedEvaaOracle[];
8
+ constructor(endpoint: string, nfts: ExtendedEvaaOracle[]);
8
9
  get sourceName(): string;
9
10
  get endpoint(): string;
10
- get nfts(): OracleNFT[];
11
+ get nfts(): ExtendedEvaaOracle[];
11
12
  set endpoint(endpoint: string);
12
- set nfts(nfts: OracleNFT[]);
13
- abstract getPrices(): Promise<RawPriceData[]>;
13
+ set nfts(nfts: ExtendedEvaaOracle[]);
14
+ abstract getPrices(fetchConfig?: FetchConfig): Promise<RawPriceData[]>;
14
15
  }
@@ -1,24 +1,25 @@
1
1
  /// <reference types="node" />
2
- /// <reference types="node" />
3
- import { Cell, Dictionary, Slice } from "@ton/core";
4
- import { OraclePricesData, PriceData, PriceSource, PriceSourcesConfig, RawPriceData } from "..";
5
- import { Oracle, OracleNFT, PoolConfig } from "../types/Master";
2
+ import { Cell, Dictionary, Slice } from '@ton/core';
3
+ import { EvaaOracle, ExtendedEvaaOracle } from '../types/Master';
4
+ import { FetchConfig } from '../utils/utils';
5
+ import { PriceSource } from './sources/PriceSource';
6
+ import { OraclePricesData, PriceData, PriceSourcesConfig, RawPriceData } from './Types';
6
7
  export declare function verifyPricesTimestamp(): (priceData: RawPriceData) => boolean;
7
- export declare function verifyPricesSign(nfts: OracleNFT[]): (priceData: RawPriceData) => boolean;
8
8
  export declare function getMedianPrice(pricesData: PriceData[], asset: bigint): bigint | null;
9
9
  export declare function packAssetsData(assetsData: {
10
10
  assetId: bigint;
11
11
  medianPrice: bigint;
12
12
  }[]): Cell;
13
13
  export declare function packPrices(assetsDataCell: Cell, oraclesDataCell: Cell): Cell;
14
- export declare function createOracleDataProof(oracle: Oracle, data: OraclePricesData, signature: Buffer, assets: Array<bigint>): Slice;
14
+ export declare function createOracleDataProof(oracle: EvaaOracle, data: OraclePricesData, signature: Buffer, assets: Array<bigint>): Slice;
15
15
  export declare function packOraclesData(oraclesData: {
16
- oracle: Oracle;
16
+ oracle: EvaaOracle;
17
17
  data: OraclePricesData;
18
18
  signature: Buffer;
19
19
  }[], assets: Array<bigint>): Cell;
20
20
  export declare function sumDicts(result: Dictionary<bigint, bigint>, addendum: Dictionary<bigint, bigint>): void;
21
- export declare function generatePriceSources(config?: PriceSourcesConfig, nfts?: OracleNFT[]): PriceSource[];
22
- export declare function collectAndFilterPrices(priceSource: PriceSource, poolConfig: PoolConfig): Promise<RawPriceData[]>;
21
+ export declare function generatePriceSources(config: PriceSourcesConfig, nfts: ExtendedEvaaOracle[]): PriceSource[];
22
+ export declare function collectAndFilterPrices(priceSource: PriceSource, minimalOracles: number, fetchConfig?: FetchConfig): Promise<RawPriceData[]>;
23
23
  export declare function unpackMedianPrices(pricesCell: Cell): Dictionary<bigint, bigint> | undefined;
24
+ export declare function verifyPricesSign(nfts: ExtendedEvaaOracle[]): (priceData: RawPriceData) => boolean;
24
25
  export declare function verifyRawPriceDataSign(priceData: RawPriceData): boolean;
@@ -1,43 +1,24 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.verifyRawPriceDataSign = exports.unpackMedianPrices = exports.collectAndFilterPrices = exports.generatePriceSources = exports.sumDicts = exports.packOraclesData = exports.createOracleDataProof = exports.packPrices = exports.packAssetsData = exports.getMedianPrice = exports.verifyPricesSign = exports.verifyPricesTimestamp = void 0;
3
+ exports.verifyRawPriceDataSign = exports.verifyPricesSign = exports.unpackMedianPrices = exports.collectAndFilterPrices = exports.generatePriceSources = exports.sumDicts = exports.packOraclesData = exports.createOracleDataProof = exports.packPrices = exports.packAssetsData = exports.getMedianPrice = exports.verifyPricesTimestamp = void 0;
4
4
  const core_1 = require("@ton/core");
5
5
  const crypto_1 = require("@ton/crypto");
6
- const __1 = require("..");
7
6
  const merkleProof_1 = require("../utils/merkleProof");
7
+ const constants_1 = require("./constants");
8
+ const Backend_1 = require("./sources/Backend");
9
+ const Icp_1 = require("./sources/Icp");
8
10
  function verifyPricesTimestamp() {
9
11
  return function (priceData) {
10
12
  const timestamp = Date.now() / 1000;
11
13
  const pricesTime = priceData.timestamp;
12
- //console.debug('timestamp - pricesTime, pricesTime', timestamp - pricesTime, pricesTime);
13
- return timestamp - pricesTime < __1.TTL_ORACLE_DATA_SEC;
14
+ return timestamp - pricesTime < constants_1.TTL_ORACLE_DATA_SEC;
14
15
  };
15
16
  }
16
17
  exports.verifyPricesTimestamp = verifyPricesTimestamp;
17
- function verifyPricesSign(nfts) {
18
- return function (priceData) {
19
- if (nfts.findIndex(x => x.pubkey.equals(priceData.pubkey)) == -1) {
20
- //console.debug('[verifyPricesSign] nft not found');
21
- return false;
22
- }
23
- return verifyRawPriceDataSign(priceData);
24
- };
25
- }
26
- exports.verifyPricesSign = verifyPricesSign;
27
- /* export function verifyPricesAssets(assets: PoolAssetsConfig) {
28
- return function(priceData: RawPriceData): boolean {
29
- for (const asset of assets) {
30
- if(!priceData.dict.has(asset.assetId)) {
31
- return false;
32
- }
33
- }
34
- return true;
35
- }
36
- } */
37
18
  function getMedianPrice(pricesData, asset) {
38
19
  try {
39
- const usingPrices = pricesData.filter(x => x.dict.has(asset));
40
- const sorted = usingPrices.map(x => x.dict.get(asset)).sort((a, b) => Number(a) - Number(b));
20
+ const usingPrices = pricesData.filter((x) => x.dict.has(asset));
21
+ const sorted = usingPrices.map((x) => x.dict.get(asset)).sort((a, b) => Number(a) - Number(b));
41
22
  if (sorted.length == 0) {
42
23
  return null;
43
24
  }
@@ -56,20 +37,13 @@ function getMedianPrice(pricesData, asset) {
56
37
  exports.getMedianPrice = getMedianPrice;
57
38
  function packAssetsData(assetsData) {
58
39
  if (assetsData.length == 0) {
59
- throw new Error("No assets data to pack");
40
+ throw new Error('No assets data to pack');
60
41
  }
61
- return assetsData.reduceRight((acc, { assetId, medianPrice }) => (0, core_1.beginCell)()
62
- .storeUint(assetId, 256)
63
- .storeCoins(medianPrice)
64
- .storeMaybeRef(acc)
65
- .endCell(), null);
42
+ return assetsData.reduceRight((acc, { assetId, medianPrice }) => (0, core_1.beginCell)().storeUint(assetId, 256).storeCoins(medianPrice).storeMaybeRef(acc).endCell(), null);
66
43
  }
67
44
  exports.packAssetsData = packAssetsData;
68
45
  function packPrices(assetsDataCell, oraclesDataCell) {
69
- let pricesCell = (0, core_1.beginCell)()
70
- .storeRef(assetsDataCell)
71
- .storeRef(oraclesDataCell)
72
- .endCell();
46
+ let pricesCell = (0, core_1.beginCell)().storeRef(assetsDataCell).storeRef(oraclesDataCell).endCell();
73
47
  return pricesCell;
74
48
  }
75
49
  exports.packPrices = packPrices;
@@ -83,9 +57,11 @@ function createOracleDataProof(oracle, data, signature, assets) {
83
57
  exports.createOracleDataProof = createOracleDataProof;
84
58
  function packOraclesData(oraclesData, assets) {
85
59
  if (oraclesData.length == 0) {
86
- throw new Error("no oracles data to pack");
60
+ throw new Error('no oracles data to pack');
87
61
  }
88
- let proofs = oraclesData.sort((d1, d2) => d1.oracle.id - d2.oracle.id).map(({ oracle, data, signature }) => createOracleDataProof(oracle, data, signature, assets));
62
+ let proofs = oraclesData
63
+ .sort((d1, d2) => d1.oracle.id - d2.oracle.id)
64
+ .map(({ oracle, data, signature }) => createOracleDataProof(oracle, data, signature, assets));
89
65
  return proofs.reduceRight((acc, val) => (0, core_1.beginCell)().storeSlice(val).storeMaybeRef(acc).endCell(), null);
90
66
  }
91
67
  exports.packOraclesData = packOraclesData;
@@ -101,20 +77,20 @@ function sumDicts(result, addendum) {
101
77
  }
102
78
  }
103
79
  exports.sumDicts = sumDicts;
104
- function generatePriceSources(config = __1.DefaultPriceSourcesConfig, nfts = __1.MAINNET_POOL_CONFIG.oracles) {
105
- let result = config.backendEndpoints.map(x => new __1.BackendPriceSource(x, nfts));
106
- result.push(...config.icpEndpoints.map(x => new __1.IcpPriceSource(x, nfts)));
80
+ function generatePriceSources(config, nfts) {
81
+ let result = config.backendEndpoints.map((x) => new Backend_1.BackendPriceSource(x, nfts));
82
+ result.push(...config.icpEndpoints.map((x) => new Icp_1.IcpPriceSource(x, nfts)));
107
83
  return result;
108
84
  }
109
85
  exports.generatePriceSources = generatePriceSources;
110
- async function collectAndFilterPrices(priceSource, poolConfig) {
111
- const prices = await priceSource.getPrices();
86
+ async function collectAndFilterPrices(priceSource, minimalOracles, fetchConfig) {
87
+ const prices = await priceSource.getPrices(fetchConfig);
112
88
  //console.debug('[FILTERING] before filtering prices len ', priceSource.sourceName, prices.length);
113
89
  return (async () => {
114
- const acceptedPrices = prices.filter(price => verifyPricesTimestamp()(price) && verifyPricesSign(poolConfig.oracles)(price));
90
+ const acceptedPrices = prices.filter((price) => verifyPricesTimestamp()(price) && verifyPricesSign(priceSource.nfts)(price));
115
91
  //console.debug('[FILTERING] after filtering prices len ', priceSource.sourceName, acceptedPrices.length);
116
- if (acceptedPrices.length < poolConfig.minimalOracles) {
117
- throw new Error("Prices are outdated");
92
+ if (acceptedPrices.length < minimalOracles) {
93
+ throw new Error('Prices are outdated');
118
94
  }
119
95
  return acceptedPrices;
120
96
  })();
@@ -136,6 +112,16 @@ function unpackMedianPrices(pricesCell) {
136
112
  return res;
137
113
  }
138
114
  exports.unpackMedianPrices = unpackMedianPrices;
115
+ function verifyPricesSign(nfts) {
116
+ return function (priceData) {
117
+ if (nfts.findIndex((x) => x.pubkey.equals(priceData.pubkey)) == -1) {
118
+ //console.debug('[verifyPricesSign] nft not found');
119
+ return false;
120
+ }
121
+ return verifyRawPriceDataSign(priceData);
122
+ };
123
+ }
124
+ exports.verifyPricesSign = verifyPricesSign;
139
125
  function verifyRawPriceDataSign(priceData) {
140
126
  const message = priceData.dataCell.refs[0].hash();
141
127
  const signature = priceData.signature;
@@ -1,5 +1,4 @@
1
1
  /// <reference types="node" />
2
- /// <reference types="node" />
3
2
  import { Address, Cell, Contract, ContractProvider, Sender, StateInit } from '@ton/ton';
4
3
  import { Maybe } from '@ton/ton/dist/utils/maybe';
5
4
  import { EvaaRewardsConfig } from '../types/MasterRewards';
@@ -1,5 +1,4 @@
1
1
  /// <reference types="node" />
2
- /// <reference types="node" />
3
2
  import { Address, Cell, Contract, ContractProvider, Sender, StateInit } from '@ton/ton';
4
3
  import { Maybe } from '@ton/ton/dist/utils/maybe';
5
4
  import { EvaaUserRewardsConfig } from '../types/UserRewards';