From 64707ceb062bad902dbba27a1c69c555bd632e92 Mon Sep 17 00:00:00 2001 From: tommytrg Date: Mon, 23 Dec 2024 12:26:43 +0100 Subject: [PATCH] refactor(api): simplify code --- .../api/src/web3Middleware/Configuration.ts | 51 +++++---- .../api/src/web3Middleware/NetworkRouter.ts | 98 ++++++++-------- packages/api/src/web3Middleware/PriceFeed.ts | 106 +++++++----------- 3 files changed, 124 insertions(+), 131 deletions(-) diff --git a/packages/api/src/web3Middleware/Configuration.ts b/packages/api/src/web3Middleware/Configuration.ts index 431fccf5..66105435 100644 --- a/packages/api/src/web3Middleware/Configuration.ts +++ b/packages/api/src/web3Middleware/Configuration.ts @@ -1,4 +1,5 @@ import { + FeedConfig, FeedParamsConfig, Network, NetworksConfig, @@ -27,14 +28,8 @@ export class Configuration { const networks = getNetworksListByChain(config) // Put all networks at the same level removing the nested arrays - const networkConfig = networks.reduce((networks, network) => { - network.map((network) => { - networks.push({ - ...network, - }) - }) - return networks - }, []) + const networkConfig = networks.flatMap((network) => network) + const testnetNetworks = networkConfig.filter((network) => !network.mainnet) const mainnetNetworks = networkConfig.filter((network) => network.mainnet) return [ @@ -43,25 +38,14 @@ export class Configuration { ] } - // return networks using the new price feeds router contract + // List networks using the price feeds router contract public listNetworksUsingPriceFeedsContract(): Array { return Object.values(this.configurationFile.chains).flatMap((chain) => Object.entries(chain.networks) .filter(([_, network]) => network.version === '2.0') - .map(([networkKey, network]) => ({ - chain: chain.name, - provider: - network.blockProvider || - getProvider(networkKey.replaceAll('.', '-') as Network) || - '', - address: - network.address || this.configurationFile.contracts['2.0'].address, - pollingPeriod: - network.pollingPeriod || - this.configurationFile.contracts['2.0'].pollingPeriod, - key: this.fromNetworkKeyToNetwork(networkKey), - networkName: network.name, - })), + .map(([networkKey, network]) => + this.createNetworkInfo(chain.name, networkKey, network), + ), ) } @@ -103,6 +87,27 @@ export class Configuration { private fromNetworkKeyToNetwork(networkKey: string): Network { return networkKey.replaceAll('.', '-') as Network } + + // Helper to create a NetworkInfo + private createNetworkInfo( + chainName: string, + networkKey: string, + network: FeedConfig, + ): NetworkInfo { + const { address, pollingPeriod } = this.configurationFile.contracts['2.0'] + + return { + chain: chainName, + provider: + network.blockProvider || + getProvider(this.fromNetworkKeyToNetwork(networkKey)) || + '', + address: network.address || address, + pollingPeriod: network.pollingPeriod || pollingPeriod, + key: this.fromNetworkKeyToNetwork(networkKey), + networkName: network.name, + } + } } export function getChain(network: Network) { diff --git a/packages/api/src/web3Middleware/NetworkRouter.ts b/packages/api/src/web3Middleware/NetworkRouter.ts index bb313163..a2767b10 100644 --- a/packages/api/src/web3Middleware/NetworkRouter.ts +++ b/packages/api/src/web3Middleware/NetworkRouter.ts @@ -48,19 +48,20 @@ export type PartialNetworkSnapshot = { } export class NetworkRouter { - private Web3: typeof Web3 - public contract: any - public network: Network - public networkName: string - public chain: string - public pollingPeriod: number public feeds?: Array<{ name: string }> - public repositories: Repositories + + private Web3: typeof Web3 + private contract: any + private network: Network + private networkName: string + private chain: string + private pollingPeriod: number + private repositories: Repositories private address: string private configuration: Configuration private provider: string private lastSupportedFeedsID = '' - private interval + private interval: NodeJS.Timeout | null = null constructor( configuration: Configuration, @@ -90,48 +91,56 @@ export class NetworkRouter { // Periodically fetch the price feed router contract and store it in mongodb public listen() { this.interval = setInterval(async () => { - const snapshot = await this.getSnapshot() - const insertPromises = snapshot.feeds - .filter((feed) => isFeedWithPrice(feed) && feed.timestamp !== '0') - .map((feed: SupportedFeed & LatestPrice) => ({ - feedFullName: createFeedFullName( - this.network, - feed.caption.split('-').reverse()[1], - feed.caption.split('-').reverse()[0], - ), - drTxHash: toHex(feed.tallyHash).slice(2), - // TODO: deprecate mandatory legacy field in database - requestId: '0', - result: feed.value.toString(), - timestamp: feed.timestamp.toString(), - })) - .map((resultRequest) => { - return this.repositories.resultRequestRepository.insertIfLatest( - resultRequest, - ) - }) - - Promise.all(insertPromises) + try { + const snapshot = await this.getSnapshot() + const insertPromises = snapshot.feeds + .filter((feed) => isFeedWithPrice(feed) && feed.timestamp !== '0') + .map((feed: SupportedFeed & LatestPrice) => ({ + feedFullName: createFeedFullName( + this.network, + feed.caption.split('-').reverse()[1], + feed.caption.split('-').reverse()[0], + ), + drTxHash: toHex(feed.tallyHash).slice(2), + // TODO: deprecate mandatory legacy field in database + requestId: '0', + result: feed.value.toString(), + timestamp: feed.timestamp.toString(), + })) + .map((resultRequest) => { + return this.repositories.resultRequestRepository.insertIfLatest( + resultRequest, + ) + }) + + await Promise.all(insertPromises) + } catch (error) { + console.error('Error in listen interval:', error) + } }, this.pollingPeriod) } public stop() { - clearInterval(this.interval) + if (this.interval) { + clearInterval(this.interval) + this.interval = null + } } - async getSnapshot(): Promise { + public async getSnapshot(): Promise< + NetworkSnapshot | PartialNetworkSnapshot + > { const supportedFeeds = await this.getSupportedFeeds() + const currentSupportedFeedsID = JSON.stringify(supportedFeeds) - const lastSupportedFeedsID = JSON.stringify(supportedFeeds) - - if (this.lastSupportedFeedsID !== lastSupportedFeedsID) { + if (this.lastSupportedFeedsID !== currentSupportedFeedsID) { this.repositories.feedRepository.refreshV2NetworkFeeds( this.network, await this.getFeedInfos(), ) - } - this.lastSupportedFeedsID = JSON.stringify(supportedFeeds) + this.lastSupportedFeedsID = currentSupportedFeedsID + } const feedIds = supportedFeeds.map((feed) => feed.id) const latestPrices = await this.latestPrices(feedIds) @@ -145,26 +154,25 @@ export class NetworkRouter { } } - async getFeedInfos(): Promise> { + public async getFeedInfos(): Promise> { const suppoortedFeeds = await this.getSupportedFeeds() return suppoortedFeeds - .map((supportedFeed) => { - const res = PriceFeed.fromWitnetPriceFeedsContract( + .map((supportedFeed) => + PriceFeed.fromWitnetPriceFeedsContract( this.configuration, supportedFeed, this.address, this.network, this.networkName, this.chain, - ).toJson() - return res - }) - .filter((x) => !!x) + ).toJson(), + ) + .filter(Boolean) } // Wrap supportedFeeds contract method - async getSupportedFeeds(): Promise> { + private async getSupportedFeeds(): Promise> { try { const supportedFeeds = await Web3.utils.waitWithTimeout( this.contract.methods.supportedFeeds().call(), diff --git a/packages/api/src/web3Middleware/PriceFeed.ts b/packages/api/src/web3Middleware/PriceFeed.ts index 454124bc..e5b8c0f3 100644 --- a/packages/api/src/web3Middleware/PriceFeed.ts +++ b/packages/api/src/web3Middleware/PriceFeed.ts @@ -5,49 +5,28 @@ import { createFeedFullName } from '../utils' import { Configuration } from './Configuration' export class PriceFeed { - feedFullName: string - id: string - abi: Array - routerAbi: Array - address: string - routerAddress: string - isRouted: boolean - network: Network - name: string - pollingPeriod: number - label: string - contractId: string - color: string - blockExplorer: string - deviation: string | null - heartbeat: string | null - finality: string - configuration: Configuration - networkName: string - chain: string - - constructor(configuration: Configuration, args: FeedInfo) { - this.configuration = configuration - this.feedFullName = args.feedFullName - this.id = args.id - this.abi = args.abi - this.routerAbi = args.routerAbi - this.address = args.address - this.routerAddress = args.routerAddress - this.isRouted = args.isRouted - this.network = args.network - this.name = args.name - this.pollingPeriod = args.pollingPeriod - this.label = args.label - this.contractId = args.contractId - this.color = args.color - this.blockExplorer = args.blockExplorer - this.deviation = args.deviation - this.heartbeat = args.heartbeat - this.finality = args.finality - this.networkName = args.networkName - this.chain = args.chain - } + constructor( + public configuration: Configuration, + public feedFullName: string, + public id: string, + public abi: Array, + public routerAbi: Array, + public address: string, + public routerAddress: string, + public isRouted: boolean, + public network: Network, + public networkName: string, + public name: string, + public pollingPeriod: number, + public label: string, + public contractId: string, + public color: string, + public blockExplorer: string, + public deviation: string | null, + public heartbeat: string | null, + public finality: string, + public chain: string, + ) {} toJson(): FeedInfo { return { @@ -98,29 +77,30 @@ export class PriceFeed { } const [decimals, adaptedCaption] = feed.caption.split('-').reverse() - return new PriceFeed(configuration, { - feedFullName: createFeedFullName(network, adaptedCaption, decimals), - id: feed.id, - abi: null, + return new PriceFeed( + configuration, + createFeedFullName(network, adaptedCaption, decimals), + feed.id, + null, // TODO: remove any - routerAbi: WitnetPriceFeedsABI as any, - address: null, - routerAddress: address, - isRouted: isRouted, - network: network, - networkName: networkName, - name: adaptedCaption.toLowerCase(), - pollingPeriod: networkConfiguration.pollingPeriod, - label: feedConfiguration.label, + WitnetPriceFeedsABI as any, + null, + address, + isRouted, + network, + networkName, + adaptedCaption.toLowerCase(), + networkConfiguration.pollingPeriod, + feedConfiguration.label, // TODO: This field should be renamed to id4 - contractId: feed.id, - color: networkConfiguration.color, - blockExplorer: networkConfiguration.blockExplorer, - deviation: feedConfiguration.deviationPercentage.toString(), - heartbeat: `${feedConfiguration.maxSecsBetweenUpdates.toString()}000`, - finality: '900000', + feed.id, + networkConfiguration.color, + networkConfiguration.blockExplorer, + feedConfiguration.deviationPercentage.toString(), + `${feedConfiguration.maxSecsBetweenUpdates.toString()}000`, + '900000', chain, - }) + ) } static isRouted(solver: string): boolean {