impermax-sdk 2.1.330 → 2.1.331

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.
@@ -8,3 +8,4 @@ import { Address, NetworkVaultTypeIndex, NetworkFactoryIndex, NetworkIndex } fro
8
8
  export declare const IMPERMAX_POOLS_API: NetworkFactoryIndex<string>;
9
9
  export declare const IMPERMAX_VAULT_API: NetworkVaultTypeIndex<string>;
10
10
  export declare const NFTLP_UNIV3_API: NetworkIndex<Address | null>;
11
+ export declare const PRICE_AGGREGATOR_API_URL = "https://price-aggregator-production.up.railway.app/api/tokens";
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.NFTLP_UNIV3_API = exports.IMPERMAX_VAULT_API = exports.IMPERMAX_POOLS_API = void 0;
3
+ exports.PRICE_AGGREGATOR_API_URL = exports.NFTLP_UNIV3_API = exports.IMPERMAX_VAULT_API = exports.IMPERMAX_POOLS_API = void 0;
4
4
  const types_1 = require("./types");
5
5
  /**
6
6
  * Private API Endpoints which we might need to use in future for non-core
@@ -92,4 +92,5 @@ exports.NFTLP_UNIV3_API = {
92
92
  [types_1.Networks.Sonic]: null,
93
93
  [types_1.Networks.Linea]: null,
94
94
  };
95
- // Add more here
95
+ // Single endpoint for all factory subgraph token prices
96
+ exports.PRICE_AGGREGATOR_API_URL = "https://price-aggregator-production.up.railway.app/api/tokens";
@@ -263,22 +263,16 @@ class OffchainBorrowable extends offchainPoolToken_1.default {
263
263
  const poolTokenDataPast = await this.getPoolTokenDataPast7d();
264
264
  return this.getAverageSupplyAPR(poolTokenDataPast, this.getAverage24hSupplyAPR());
265
265
  }
266
+ // TODO: Both using the same price function, re-write properly, same as `offchainVault.ts`
266
267
  // Token price getters
267
268
  async getTokenPriceFast(fallback = true) {
268
- let tokenAddress = await this.getUnderlyingAddress();
269
- let tokenPrices = await this.getOffchain()
270
- .getPriceHelper()
271
- .getSubgraphTokensPrice(this.getOffchain().network);
272
- let tokenPrice = tokenPrices[tokenAddress];
273
- if (tokenPrice !== undefined && tokenPrice > 0)
274
- return tokenPrice;
275
- return super.getTokenPriceFast(fallback);
269
+ return this.getTokenPriceAccurate();
276
270
  }
277
271
  async getTokenPriceAccurate() {
278
272
  let tokenAddress = await this.getUnderlyingAddress();
279
273
  return this.getOffchain()
280
274
  .getPriceHelper()
281
- .getDebankTokenPrice(this.getOffchain().network, tokenAddress);
275
+ .getTokenPrice(this.getOffchain().network, tokenAddress);
282
276
  }
283
277
  async getAccrueFactor() {
284
278
  const now = Date.now() / 1000;
@@ -61,7 +61,7 @@ class OffchainLendingPoolV2 extends offchainLendingPool_1.default {
61
61
  rewardRate = rewardRate * 0.45;
62
62
  const rewardPrice = await this.offchain
63
63
  .getPriceHelper()
64
- .getDebankTokenPrice(this.offchain.network, reward.rewardsToken.id);
64
+ .getTokenPrice(this.offchain.network, reward.rewardsToken.id);
65
65
  rewards.push({
66
66
  APR: (0, utils_1.toAPR)(((rewardPrice * rewardRate) /
67
67
  (stakedTotalSupply * underlyingLPPrice)) *
@@ -58,7 +58,7 @@ export default class Offchain {
58
58
  getAccount(accountAddress: Address): OffchainAccount;
59
59
  getSolidexHelper: () => OffchainSolidexHelper;
60
60
  getConfigManager: () => OffchainConfigManager;
61
- getPriceHelper: () => import("./offchainPriceHelper").default;
61
+ getPriceHelper: () => import("./offchainPriceHelperV2").default;
62
62
  getAPRHelper: () => import("./offchainAPRHelper").default;
63
63
  getEndpointManager: () => import("./offchainEndpointManager").default;
64
64
  apolloFetcher: typeof initializer.apolloFetcher;
@@ -7,7 +7,7 @@ import { RiskLevel } from "./vault/offchainLendingVault";
7
7
  import OffchainLendingPool from "./lendingPool";
8
8
  import { LendingPoolVersion } from "./lendingPool/offchainLendingPool";
9
9
  import OffchainAPRHelper from "./offchainAPRHelper";
10
- import OffchainPriceHelper from "./offchainPriceHelper";
10
+ import OffchainPriceHelper from "./offchainPriceHelperV2";
11
11
  import OffchainEndpointManager from './offchainEndpointManager';
12
12
  import OffchainMultichainAccount from "./account/offchainMultichainAccount";
13
13
  import { AddressIndex } from "../config/types";
@@ -20,7 +20,7 @@ const types_1 = require("../config/types");
20
20
  const offchain_1 = __importDefault(require("./offchain"));
21
21
  const subgraphs_1 = require("../config/subgraphs");
22
22
  const offchainAPRHelper_1 = __importDefault(require("./offchainAPRHelper"));
23
- const offchainPriceHelper_1 = __importDefault(require("./offchainPriceHelper"));
23
+ const offchainPriceHelperV2_1 = __importDefault(require("./offchainPriceHelperV2"));
24
24
  const offchainEndpointManager_1 = __importDefault(require("./offchainEndpointManager"));
25
25
  const offchainMultichainAccount_1 = __importDefault(require("./account/offchainMultichainAccount"));
26
26
  // For vaults and pools
@@ -52,7 +52,7 @@ class OffchainMultichain {
52
52
  // Initialize empty
53
53
  this.offchains = {};
54
54
  this.aprHelper = new offchainAPRHelper_1.default(this);
55
- this.priceHelper = new offchainPriceHelper_1.default(this); // Create single instance
55
+ this.priceHelper = new offchainPriceHelperV2_1.default(this); // Create single instance
56
56
  this.endpointManager = new offchainEndpointManager_1.default(this);
57
57
  }
58
58
  static get instance() {
@@ -1,13 +1,14 @@
1
1
  import { Address, Networks } from "../config/types";
2
2
  import OffchainMultichain from "./offchainMultichain";
3
+ export type Token = `${Networks}:${Address}`;
3
4
  export default class OffchainPriceHelper {
4
5
  offchainMultichain: OffchainMultichain;
5
6
  private subgraphTokensPrice;
6
7
  private debankTokensPrice;
7
8
  private coingeckoInitialized;
8
9
  private coingeckoTokenPrices;
9
- private fantomTokenPricesInitialized;
10
- private fantomTokenPrices;
10
+ private geckoTerminalInitialized;
11
+ private geckoTerminalTokenPrices;
11
12
  constructor(offchainMultichain: OffchainMultichain);
12
13
  cleanCache(): void;
13
14
  private addPriceIfMissing;
@@ -17,6 +18,8 @@ export default class OffchainPriceHelper {
17
18
  }>;
18
19
  private getAllCoingeckoPrices;
19
20
  private getCoingeckoTokenPrice;
21
+ private getAllGeckoTerminalPrices;
22
+ private getGeckoTerminalTokenPrice;
20
23
  private getDexscreenerTokenPrice;
21
24
  private initializeDebankTokenPrice;
22
25
  getDebankTokenPrice(network: Networks, tokenAddress: Address): Promise<number>;
@@ -1,5 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ const types_1 = require("../config/types");
3
4
  // coingecko has priority over debank for initialized tokens
4
5
  const coingecko_ids = {
5
6
  //Polygon
@@ -79,46 +80,39 @@ const dexscreener_ids = {
79
80
  // fantom-bomb on scroll (removed from coingecko)
80
81
  "0x6b6882f7642ee1c15f12b51f1a4988b3e7e29f5c": "scroll",
81
82
  };
82
- const fantom_ids = {
83
- // uponly on ftm
84
- "0x28f1d1c509495e5afc23fb47acf6cc5b217ab598": "fantom",
85
- // plus-bet on ftm
86
- "0x39551b1c26ce03714e4661833b0fa730174bd7e9": "fantom",
87
- // tango on ftm
88
- "0xee9ff3efd508741492b5bd45269aa45a43be59c8": "fantom",
89
- // fantomsonicinu
90
- "0x05e31a691405d06708a355c029599c12d5da8b28": "fantom",
91
- //sonic goat
92
- "0x43f9a13675e352154f745d6402e853fecc388aa5": "fantom",
93
- // fantom eco
94
- "0xb8a32897016c1b2ee0797090162eafe58f032795": "fantom",
95
- // hoops
96
- "0x431516e478d73cfab034229c4d7a94a2cbf5787f": "fantom",
97
- // moon bay on ftm
98
- "0xd361474bb19c8b98870bb67f5759cdf277dee7f9": "fantom",
99
- // thc on fantom
100
- "0x479673391b3818f5e3ed2fa69a58e13d685becf6": "fantom",
101
- // equal
102
- "0x3fd3a0c85b70754efc07ac9ac0cbbdce664865a6": "equalizer-dex",
103
- // wftm
104
- "0x21be370d5312f44cb42ce377bc9b8a0cef1a4c83": "wrapped-fantom",
105
- // mftm
106
- "0x62227c75908b7d358a9d70ea4670f57f8b012ccc": "fantom",
107
- // fiery
108
- "0xc36cae799b758d04dac9b3a1fd59755c4a8ae721": "fantom",
109
- // Skitty
110
- "0xad531012c0651a85a212f10fc97b3ec15684548a": "fantom",
111
- // fBomb
112
- "0x74ccbe53f77b08632ce0cb91d3a545bf6b8e0979": "fantom",
113
- // mclb
114
- "0x5deb27e51dbeef691ba1175a2e563870499c2acb": "fantom",
115
- // hedgy
116
- "0x16c22105301cfd85fd0f911920d282d18cc175c1": "fantom",
83
+ const geckoTerminalTokens = [
84
+ "arbitrum:0xde903e2712288a1da82942dddf2c20529565ac30",
85
+ "arbitrum:0x2e9a6df78e42a30712c10a9dc4b1c8656f8f2879",
86
+ "arbitrum:0x3b475f6f2f41853706afc9fa6a6b8c5df1a2724c",
87
+ "polygon:0x1d607faa0a51518a7728580c238d912747e71f7a",
88
+ "polygon:0xc25351811983818c9fe6d8c580531819c8ade90f",
89
+ "polygon:0x4eac4c4e9050464067d673102f8e24b2fcceb350",
90
+ "polygon:0xc25351811983818c9fe6d8c580531819c8ade90f"
91
+ ];
92
+ /** Map of our network to geckoTerminal network id */
93
+ const GECKOTERMINAL_IDS = {
94
+ [types_1.Networks.Avalanche]: "avax",
95
+ [types_1.Networks.Mainnet]: "eth",
96
+ [types_1.Networks.Polygon]: "polygon_pos",
97
+ [types_1.Networks.Arbitrum]: "arbitrum",
98
+ [types_1.Networks.Fantom]: "ftm",
99
+ [types_1.Networks.Base]: "base",
100
+ [types_1.Networks.Scroll]: "scroll",
101
+ [types_1.Networks.Optimism]: "optimism",
102
+ [types_1.Networks.Real]: "re-al",
103
+ [types_1.Networks.Mantle]: "mantle",
104
+ [types_1.Networks.Canto]: "canto",
105
+ [types_1.Networks.Blast]: "blast",
106
+ [types_1.Networks.Sonic]: "sonic",
107
+ [types_1.Networks.Linea]: "linea",
108
+ [types_1.Networks.ZksyncEra]: "zksync",
117
109
  };
110
+ const MAX_GECKO_COINS = 30;
111
+ // NOTE: Geckoterminal and coingecko functions copied from our indexer
118
112
  // Sources used so far:
119
113
  // 1. Our subgraphs
120
114
  // 2. Coingecko
121
- // 3. Equalizer's (fantom) API
115
+ // 3. Geckoterminal
122
116
  // 4. DexScreener
123
117
  class OffchainPriceHelper {
124
118
  // No need for dexscreener mutex since it allows only one token per call
@@ -126,8 +120,8 @@ class OffchainPriceHelper {
126
120
  // Initialize the subgraph prices for each network
127
121
  this.subgraphTokensPrice = {};
128
122
  this.coingeckoInitialized = null;
129
- this.fantomTokenPricesInitialized = null;
130
- this.fantomTokenPrices = {};
123
+ this.geckoTerminalInitialized = null;
124
+ this.geckoTerminalTokenPrices = {};
131
125
  this.offchainMultichain = offchainMultichain;
132
126
  this.debankTokensPrice = {};
133
127
  }
@@ -218,34 +212,51 @@ class OffchainPriceHelper {
218
212
  return geckoPrice || 0;
219
213
  }
220
214
  /* -----------------------------------------------------------------------
221
- * 3. Fantom (Equalizer's API)
215
+ * 3. GeckoTerminal
222
216
  * ----------------------------------------------------------------------*/
223
- // NOTE: Deprecated
224
- // private async initializeFantomTokenPrices(): Promise<void> {
225
- // try {
226
- // const response = await fetch(
227
- // "https://eqapi-beta-8868m.ondigitalocean.app/fantom/v4/tokens",
228
- // );
229
- // if (response.status != 200) return;
230
- // const data = await response.json();
231
- // if (!data?.data) return;
232
- // this.fantomTokenPrices = Object.entries(data.data).reduce(
233
- // (acc, [address, data]: [string, any]) => {
234
- // acc[address.toLowerCase()] = Number(data.priceUsd);
235
- // return acc;
236
- // },
237
- // {} as Record<string, number>,
238
- // );
239
- // } catch {
240
- // this.fantomTokenPrices = {};
241
- // }
242
- // }
243
- //private async getFantomTokenPrice(tokenAddress: Address): Promise<number> {
244
- // if (!this.fantomTokenPricesInitialized)
245
- // this.fantomTokenPricesInitialized = this.initializeFantomTokenPrices();
246
- // await this.fantomTokenPricesInitialized;
247
- // return this.fantomTokenPrices[tokenAddress.toLowerCase()] || 0;
248
- //}
217
+ async getAllGeckoTerminalPrices() {
218
+ // GeckoTerminal only allows to fetch multiple tokens from a single network in 1 api call
219
+ // so we group all the tokens passed by network to loop through each one.
220
+ const tokensByChain = geckoTerminalTokens.reduce((acc, tokenId) => {
221
+ const network = tokenId.split(":")[0];
222
+ if (!acc[network])
223
+ acc[network] = [];
224
+ acc[network].push(tokenId);
225
+ return acc;
226
+ }, {});
227
+ // Go through each network
228
+ try {
229
+ for (const [network, tokens] of Object.entries(tokensByChain)) {
230
+ const geckoNetwork = GECKOTERMINAL_IDS[network];
231
+ if (!geckoNetwork) {
232
+ console.error(`GeckoTerminal ID missing for network: ${network}`);
233
+ continue;
234
+ }
235
+ for (let i = 0; i < tokens.length; i += MAX_GECKO_COINS) {
236
+ const maxTokens = tokens.slice(i, i + MAX_GECKO_COINS);
237
+ const tokenIds = maxTokens.map((tokenId) => tokenId.split(":")[1]).join(",");
238
+ const { data } = await fetch(`https://api.geckoterminal.com/api/v2/simple/networks/${geckoNetwork}/token_price/${tokenIds}`).then((res) => res.json());
239
+ for (const tokenId of maxTokens) {
240
+ const tokenAddress = tokenId.split(":")[1];
241
+ const tokenPrice = data.attributes.token_prices[tokenAddress];
242
+ if (tokenPrice)
243
+ this.geckoTerminalTokenPrices[tokenAddress] = tokenPrice;
244
+ }
245
+ }
246
+ }
247
+ }
248
+ catch (error) {
249
+ console.error("Gecko prices fail: %s", error.message);
250
+ }
251
+ }
252
+ ;
253
+ async getGeckoTerminalTokenPrice(tokenAddress) {
254
+ if (!this.geckoTerminalInitialized)
255
+ this.geckoTerminalInitialized = this.getAllGeckoTerminalPrices();
256
+ await this.geckoTerminalInitialized;
257
+ const geckoPrice = this.geckoTerminalTokenPrices[tokenAddress];
258
+ return geckoPrice || 0;
259
+ }
249
260
  /* -----------------------------------------------------------------------
250
261
  * 4. Dexscreener
251
262
  * ----------------------------------------------------------------------*/
@@ -287,6 +298,11 @@ class OffchainPriceHelper {
287
298
  if (result)
288
299
  return result;
289
300
  }
301
+ if (geckoTerminalTokens.some(token => token.endsWith(tokenAddress.toLowerCase()))) {
302
+ const result = await this.getGeckoTerminalTokenPrice(tokenAddress);
303
+ if (result)
304
+ return result;
305
+ }
290
306
  return 0;
291
307
  }
292
308
  // TODO: Simplify this logic and reove the old temporaries we dont need anymore
@@ -0,0 +1,26 @@
1
+ import { Address, Networks } from "../config/types";
2
+ import OffchainMultichain from "./offchainMultichain";
3
+ export default class OffchainPriceHelper {
4
+ private apiTokens;
5
+ private apiTokensInitialized;
6
+ private offchainPriceHelperV1;
7
+ offchainMultichain: OffchainMultichain;
8
+ constructor(offchainMultichain: OffchainMultichain);
9
+ cleanCache(): void;
10
+ /**
11
+ * NOTE: Used as a fallback at the moment while we deprecate the old price helper
12
+ */
13
+ private getTokenPriceOld;
14
+ /**
15
+ * Initializes token prices from the API
16
+ */
17
+ private initializeTokenPrices;
18
+ /**
19
+ * Gets all tokens data from the API
20
+ */
21
+ private getTokenPrices;
22
+ /**
23
+ * Gets the price of a token from the API, initializes all tokens
24
+ */
25
+ getTokenPrice(network: Networks, tokenAddress: Address): Promise<number>;
26
+ }
@@ -0,0 +1,78 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const chainId_1 = require("../config/chainId");
7
+ const private_api_1 = require("../config/private-api");
8
+ const offchainPriceHelper_1 = __importDefault(require("./offchainPriceHelper"));
9
+ class OffchainPriceHelper {
10
+ constructor(offchainMultichain) {
11
+ // Multichain private api
12
+ this.apiTokens = null;
13
+ this.apiTokensInitialized = null;
14
+ this.offchainMultichain = offchainMultichain;
15
+ this.offchainPriceHelperV1 = new offchainPriceHelper_1.default(offchainMultichain);
16
+ }
17
+ cleanCache() {
18
+ this.apiTokens = null;
19
+ this.apiTokensInitialized = null;
20
+ }
21
+ /**
22
+ * NOTE: Used as a fallback at the moment while we deprecate the old price helper
23
+ */
24
+ async getTokenPriceOld(network, tokenAddress) {
25
+ const price = await this.offchainPriceHelperV1.getDebankTokenPrice(network, tokenAddress);
26
+ if (price === 0) {
27
+ console.log("Missing price for token: %s", network.concat("-", tokenAddress));
28
+ }
29
+ return price;
30
+ }
31
+ /* -----------------------------------------------------------------------
32
+ * 1. Price aggreagator API (railway)
33
+ * ----------------------------------------------------------------------*/
34
+ /**
35
+ * Initializes token prices from the API
36
+ */
37
+ async initializeTokenPrices() {
38
+ try {
39
+ const response = await fetch(private_api_1.PRICE_AGGREGATOR_API_URL);
40
+ if (!response.ok)
41
+ throw new Error(`API response error: ${response.status}`);
42
+ this.apiTokens = await response.json();
43
+ }
44
+ catch (error) {
45
+ console.error("Error fetching token prices:", error);
46
+ this.apiTokens = null;
47
+ }
48
+ }
49
+ /**
50
+ * Gets all tokens data from the API
51
+ */
52
+ async getTokenPrices() {
53
+ if (!this.apiTokensInitialized)
54
+ this.apiTokensInitialized = this.initializeTokenPrices();
55
+ await this.apiTokensInitialized;
56
+ return this.apiTokens;
57
+ }
58
+ /**
59
+ * Gets the price of a token from the API, initializes all tokens
60
+ */
61
+ async getTokenPrice(network, tokenAddress) {
62
+ // Initialize tokens if necessary
63
+ const apiData = await this.getTokenPrices();
64
+ // Not supported
65
+ const chainId = chainId_1.CHAIN_IDS[network];
66
+ if (!chainId)
67
+ return 0;
68
+ // Our price aggregator stores tokens as `chainId-tokenAddress`
69
+ // in case diff tokens have same address on diff networks
70
+ const key = `${chainId}-${tokenAddress.toLowerCase()}`;
71
+ const token = apiData?.tokens[key];
72
+ if (token)
73
+ return parseFloat(token.derivedUSD);
74
+ // Fallback to price old
75
+ return this.getTokenPriceOld(network, tokenAddress);
76
+ }
77
+ }
78
+ exports.default = OffchainPriceHelper;
@@ -78,13 +78,14 @@ class OffchainVault extends offchainPoolToken_1.default {
78
78
  const supplyRate = await this.getSupplyRate();
79
79
  return (0, utils_1.toAPR)(supplyRate);
80
80
  }
81
+ // TODO: Both using the same price function, re-write properly, same as `offchainBorrowable.ts`
81
82
  // Token price getters
82
83
  async getTokenPriceFast(fallback = true) {
83
84
  return this.getTokenPriceAccurate();
84
85
  }
85
86
  async getTokenPriceAccurate() {
86
87
  let tokenAddress = await this.getUnderlyingAddress();
87
- return this.getOffchain().getPriceHelper().getDebankTokenPrice(this.getOffchain().network, tokenAddress);
88
+ return this.getOffchain().getPriceHelper().getTokenPrice(this.getOffchain().network, tokenAddress);
88
89
  }
89
90
  // Flags
90
91
  async isDeprecated() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "impermax-sdk",
3
- "version": "2.1.330",
3
+ "version": "2.1.331",
4
4
  "description": "",
5
5
  "main": "./lib/index.js",
6
6
  "module": "./lib/index.js",