impermax-sdk 2.1.512 → 2.1.514

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.
@@ -3,7 +3,7 @@ import OffchainLendingPool from './lendingPool';
3
3
  import OffchainSolidexHelper from './offchainSolidexHelper';
4
4
  import OffchainAccount from './account';
5
5
  import { Address, AddressIndex, Factory, FactoryIndex, LendingPoolIndex, Networks, WhitelistState, Extension } from '../config/types';
6
- import { LendingPoolData, VaultData, VaultPosition, TvlData, UserData, XIbexData, NftlpData, PoolChart, NewlyEarnedFees, NftlpStats, XIbexUserData, NewlyEarnedReward } from './offchainTypes';
6
+ import { LendingPoolData, VaultData, VaultPosition, TvlData, UserData, XIbexData, NftlpData, PoolChart, NewlyEarnedFees, NftlpStats, XIbexUserData, NewlyEarnedReward, NetworkTokenData } from './offchainTypes';
7
7
  import OffchainVault from './vault/offchainVault';
8
8
  import OffchainConfigManager from './configManager';
9
9
  import { PairState } from '../config/whitelist';
@@ -121,4 +121,5 @@ export default class Offchain {
121
121
  protected fetchNftlpsData: typeof initializer.fetchNftlpsData;
122
122
  protected initializeNftlpsData: typeof initializer.initializeNftlpsData;
123
123
  getPairsList(factory: Factory, state?: PairState): Address[];
124
+ getNetworkTokens(): Promise<NetworkTokenData[]>;
124
125
  }
@@ -205,5 +205,67 @@ class Offchain {
205
205
  pairs.push(...blacklisted);
206
206
  return pairs.map(i => i.toLowerCase());
207
207
  }
208
+ async getNetworkTokens() {
209
+ const tokenMap = new Map();
210
+ try {
211
+ const lendingPoolsData = await this.getLendingPoolsData();
212
+ // 1. Go through each factory
213
+ const factoryPromises = Object.entries(lendingPoolsData).map(async ([factory, pools]) => {
214
+ // 2. Go through each pool in the factory
215
+ const poolPromises = Object.keys(pools).map(async (poolId) => {
216
+ try {
217
+ const lendingPool = await this.getLendingPool(factory, poolId);
218
+ if (!lendingPool)
219
+ return [];
220
+ // 3. Get both borrowables borrowables from this pool
221
+ const [borrowableA, borrowableB] = await Promise.all([lendingPool.getBorrowableA(), lendingPool.getBorrowableB()]);
222
+ // 4. Get underlying tokens from both borrowables
223
+ const tokenPromises = [borrowableA, borrowableB].map(async (borrowable) => {
224
+ try {
225
+ const [address, symbol, name, decimals] = await Promise.all([
226
+ borrowable.getUnderlyingAddress(),
227
+ borrowable.getSymbol(),
228
+ borrowable.getName(),
229
+ borrowable.getDecimals(),
230
+ ]);
231
+ if (!address)
232
+ return null;
233
+ return {
234
+ token: `${this.network}:${address}`,
235
+ id: address,
236
+ symbol,
237
+ name,
238
+ decimals,
239
+ chainId: this.chainId,
240
+ };
241
+ }
242
+ catch (error) {
243
+ console.error(`Error getting token details for borrowable in pool ${poolId}:`, error);
244
+ return null;
245
+ }
246
+ });
247
+ // The token's data like symbol etc.
248
+ const tokens = await Promise.all(tokenPromises);
249
+ return tokens.filter((token) => token !== null);
250
+ }
251
+ catch (error) {
252
+ console.error(`Error processing pool ${poolId} in factory ${factory} on ${this.network}:`, error);
253
+ return [];
254
+ }
255
+ });
256
+ const poolResults = await Promise.all(poolPromises);
257
+ return poolResults.flat();
258
+ });
259
+ const factoryResults = await Promise.all(factoryPromises);
260
+ const networkTokens = factoryResults.flat();
261
+ // Need to put then in a set to return unique tokens
262
+ networkTokens.forEach(tokenData => tokenMap.set(tokenData.token, tokenData));
263
+ return Array.from(tokenMap.values());
264
+ }
265
+ catch (error) {
266
+ console.error(`Error processing network ${this.network}:`, error);
267
+ return [];
268
+ }
269
+ }
208
270
  }
209
271
  exports.default = Offchain;
@@ -14,7 +14,7 @@ import { AddressIndex } from "../config/types";
14
14
  import OffchainAccount from "./account/offchainAccount";
15
15
  import { PairState } from '../config/whitelist';
16
16
  import { LlamaTvlChart } from './offchainAPRHelper';
17
- import { Token } from "./offchainPriceHelper";
17
+ import { NetworkTokenData } from "./offchainTypes";
18
18
  export declare enum SortDirection {
19
19
  ASC = "asc",
20
20
  DESC = "desc"
@@ -105,6 +105,6 @@ export default class OffchainMultichain {
105
105
  */
106
106
  getTvlData(params?: MultichainTvlParams): Promise<MultichainTvlData>;
107
107
  getImpermaxTvlChart(network?: Networks): Promise<LlamaTvlChart>;
108
- getNetworkTokens(networks?: Networks[]): Promise<Token[]>;
108
+ getNetworkTokens(networks?: Networks[]): Promise<NetworkTokenData[]>;
109
109
  }
110
110
  export {};
@@ -296,21 +296,19 @@ class OffchainMultichain {
296
296
  // ERC20 TOKENS
297
297
  //
298
298
  async getNetworkTokens(networks) {
299
- const lendingPools = await this.getLendingPoolList({ networks });
300
- const tokenSet = new Set();
301
- await Promise.all(lendingPools.map(async (pool) => {
302
- const network = pool.getOffchain().network;
303
- const [borrowableA, borrowableB] = await Promise.all([
304
- pool.getBorrowableA(),
305
- pool.getBorrowableB()
306
- ]);
307
- const addresses = await Promise.all([
308
- borrowableA.getUnderlyingAddress(),
309
- borrowableB.getUnderlyingAddress()
310
- ]);
311
- addresses.forEach(addr => tokenSet.add(`${network}:${addr}`));
312
- }));
313
- return Array.from(tokenSet);
299
+ const allNetworks = networks || Object.values(types_1.Networks);
300
+ const networkPromises = allNetworks.map(async (network) => {
301
+ try {
302
+ const offchain = this.getOffchain(network);
303
+ return await offchain.getNetworkTokens();
304
+ }
305
+ catch (error) {
306
+ console.error(`Error processing network ${network}:`, error);
307
+ return [];
308
+ }
309
+ });
310
+ const results = await Promise.all(networkPromises);
311
+ return results.flat();
314
312
  }
315
313
  }
316
314
  exports.default = OffchainMultichain;
@@ -1,4 +1,4 @@
1
- import { Address, AddressIndex, PoolTokenType, ProposalState, WhitelistState, VaultType, Extension, Factory, Borrowable } from '../config/types';
1
+ import { Address, AddressIndex, PoolTokenType, ProposalState, WhitelistState, VaultType, Extension, Factory, Borrowable, Networks } from '../config/types';
2
2
  import { Amms } from '../config/amms';
3
3
  export declare const isV3Factory: (factory: string) => boolean;
4
4
  export interface TokenData {
@@ -14,6 +14,14 @@ export interface PoolTokenData {
14
14
  exchangeRate: string;
15
15
  totalBalanceUSD: string;
16
16
  }
17
+ export type NetworkTokenData = {
18
+ token: `${Networks}:${Address}`;
19
+ id: Address;
20
+ symbol: string;
21
+ name: string;
22
+ decimals: number;
23
+ chainId: number;
24
+ };
17
25
  export interface BorrowableData extends PoolTokenData {
18
26
  underlying: TokenData;
19
27
  totalBorrows: string;
@@ -8,7 +8,7 @@ import OnchainInteractions from './interactions';
8
8
  import { OnchainConfig } from './onchainTypes';
9
9
  import OnchainConfigManager from './configManager';
10
10
  import OnchainPermitHelper from "./onchainPermitHelper";
11
- import Multicall from '@dopex-io/web3-multicall';
11
+ import OnchainMulticall from './onchainMulticall';
12
12
  import OnchainStakingModule from './staking/onchainStakingModule';
13
13
  export default class Onchain {
14
14
  readonly network: Networks;
@@ -26,7 +26,7 @@ export default class Onchain {
26
26
  protected lendingVaults: AddressIndex<OnchainLendingVault>;
27
27
  protected accounts: AddressIndex<OnchainAccount>;
28
28
  protected interactions: AddressIndex<OnchainInteractions>;
29
- multicall: Multicall;
29
+ multicall: OnchainMulticall;
30
30
  protected stakingModule: OnchainStakingModule;
31
31
  constructor(cfg: OnchainConfig);
32
32
  cleanCache(): void;
@@ -12,6 +12,7 @@ const interactions_1 = __importDefault(require("./interactions"));
12
12
  const configManager_1 = __importDefault(require("./configManager"));
13
13
  const onchainPermitHelper_1 = __importDefault(require("./onchainPermitHelper"));
14
14
  const web3_multicall_1 = __importDefault(require("@dopex-io/web3-multicall"));
15
+ const onchainMulticall_1 = __importDefault(require("./onchainMulticall"));
15
16
  const onchainStakingModule_1 = __importDefault(require("./staking/onchainStakingModule"));
16
17
  class Onchain {
17
18
  constructor(cfg) {
@@ -34,11 +35,13 @@ class Onchain {
34
35
  this.accounts = {};
35
36
  this.lendingVaults = {};
36
37
  this.interactions = {};
37
- this.multicall = new web3_multicall_1.default({
38
+ const multicall = new web3_multicall_1.default({
38
39
  chainId: cfg.chainId,
39
40
  provider: cfg.web3,
40
41
  multicallAddress: "0xcA11bde05977b3631167028862bE2a173976CA11"
41
42
  });
43
+ // Using default settings, See OnchainMulticall constructor
44
+ this.multicall = new onchainMulticall_1.default(multicall);
42
45
  }
43
46
  cleanCache() {
44
47
  for (const factory in this.factories) {
@@ -0,0 +1,37 @@
1
+ import Multicall from '@dopex-io/web3-multicall';
2
+ interface MulticallConfig {
3
+ /** Max amount of transactions per multicall call */
4
+ batchSize: number;
5
+ /** Time in ms to wait before sending (0 still gets all from current event loop which is probably enough on most cases) */
6
+ timeWindow: number;
7
+ }
8
+ /**
9
+ * Similar to https://github.com/greg-schrammel/multicall-provider but for web3.js
10
+ *
11
+ * Example usage:
12
+ *
13
+ * const underlyingAddress = await this.getOnchain().multicall.call(poolToken.methods.underlying());
14
+ *
15
+ * Do not use call() when passing method! ie:
16
+ * wrong: onchain.multicall.call(poolToken.methods.underlying().call()):
17
+ * right: onchain.multicall.call(poolToken.methods.underlying())
18
+ *
19
+ * How it works:
20
+ * 1. onchainLendingVault: `onchain.multicall.call(methods.exchangeRate())` - adds to queue, timeoutId is null, sets timer to `timeWindow`
21
+ * 2. onchainPoolToken : `onchain.multicall.call(methods.totalSupply())` - adds to queue, clears old timer, sets new timer to `timeWindow`
22
+ * 3. onchainBorrowable : `onchain.multicall.call(methods.underlying())` - adds to queue, clears old timer, sets new timer to `timeWindow`
23
+ * ...
24
+ * 4. Process all when either `timeWindow` expires OR `batchSize` is reached
25
+ */
26
+ export default class OnchainMulticall {
27
+ private multicall;
28
+ private config;
29
+ private queue;
30
+ private timeoutId;
31
+ private isProcessing;
32
+ constructor(multicall: Multicall, config?: MulticallConfig);
33
+ getEthBalance(address: string): any;
34
+ call<T = any>(contractMethod: any): Promise<T>;
35
+ private processBatch;
36
+ }
37
+ export {};
@@ -0,0 +1,85 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ /**
4
+ * Similar to https://github.com/greg-schrammel/multicall-provider but for web3.js
5
+ *
6
+ * Example usage:
7
+ *
8
+ * const underlyingAddress = await this.getOnchain().multicall.call(poolToken.methods.underlying());
9
+ *
10
+ * Do not use call() when passing method! ie:
11
+ * wrong: onchain.multicall.call(poolToken.methods.underlying().call()):
12
+ * right: onchain.multicall.call(poolToken.methods.underlying())
13
+ *
14
+ * How it works:
15
+ * 1. onchainLendingVault: `onchain.multicall.call(methods.exchangeRate())` - adds to queue, timeoutId is null, sets timer to `timeWindow`
16
+ * 2. onchainPoolToken : `onchain.multicall.call(methods.totalSupply())` - adds to queue, clears old timer, sets new timer to `timeWindow`
17
+ * 3. onchainBorrowable : `onchain.multicall.call(methods.underlying())` - adds to queue, clears old timer, sets new timer to `timeWindow`
18
+ * ...
19
+ * 4. Process all when either `timeWindow` expires OR `batchSize` is reached
20
+ */
21
+ class OnchainMulticall {
22
+ constructor(multicall, config = { batchSize: 25, timeWindow: 0 }) {
23
+ this.queue = [];
24
+ this.timeoutId = null;
25
+ this.isProcessing = false;
26
+ this.multicall = multicall;
27
+ this.config = config;
28
+ }
29
+ getEthBalance(address) {
30
+ return this.multicall.getEthBalance(address);
31
+ }
32
+ async call(contractMethod) {
33
+ return new Promise((resolve, reject) => {
34
+ const queuedCall = { contractMethod, resolve, reject };
35
+ this.queue.push(queuedCall);
36
+ if (this.timeoutId)
37
+ clearTimeout(this.timeoutId);
38
+ this.timeoutId = setTimeout(() => this.processBatch(), this.config.timeWindow);
39
+ if (this.queue.length >= this.config.batchSize) {
40
+ if (this.timeoutId) {
41
+ clearTimeout(this.timeoutId);
42
+ this.timeoutId = null;
43
+ }
44
+ // Process all in next event loop
45
+ if (!this.isProcessing)
46
+ setTimeout(() => this.processBatch(), 0);
47
+ }
48
+ });
49
+ }
50
+ // TODO: Test fallback in case of multicall failure
51
+ async processBatch() {
52
+ if (this.isProcessing || this.queue.length === 0)
53
+ return;
54
+ this.isProcessing = true;
55
+ this.timeoutId = null;
56
+ const batch = this.queue.splice(0, Math.min(this.config.batchSize, this.queue.length));
57
+ try {
58
+ const contractMethods = batch.map(call => call.contractMethod);
59
+ // console.log("Multicall methods: ", contractMethods)
60
+ const results = await this.multicall.aggregate(contractMethods);
61
+ for (let i = 0; i < batch.length; i++) {
62
+ const call = batch[i];
63
+ const result = results[i];
64
+ call.resolve(result);
65
+ }
66
+ }
67
+ catch (error) {
68
+ console.log('Multicall failed, using fallback call: ', error);
69
+ for (const call of batch) {
70
+ try {
71
+ const result = await call.contractMethod.call();
72
+ call.resolve(result);
73
+ }
74
+ catch (singleCallError) {
75
+ call.reject(new Error(`Individual call failed: ${singleCallError.message}`));
76
+ }
77
+ }
78
+ }
79
+ this.isProcessing = false;
80
+ // Execute again until queue is empty
81
+ if (this.queue.length > 0)
82
+ setTimeout(() => this.processBatch(), 0);
83
+ }
84
+ }
85
+ exports.default = OnchainMulticall;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "impermax-sdk",
3
- "version": "2.1.512",
3
+ "version": "2.1.514",
4
4
  "description": "",
5
5
  "main": "./lib/index.js",
6
6
  "module": "./lib/index.js",