diff --git a/core/src/por/api.ts b/core/src/por/api.ts deleted file mode 100644 index f54700f5e..000000000 --- a/core/src/por/api.ts +++ /dev/null @@ -1,91 +0,0 @@ -import { IData } from '@bisonai/orakl-util' -import axios from 'axios' -import { Logger } from 'pino/pino' -import { OraklError, OraklErrorCode } from '../errors' -import { CHAIN, ORAKL_NETWORK_API_URL } from '../settings' -import { IAggregator } from '../types' -import { buildUrl } from '../utils' - -export async function loadAggregator({ - aggregatorHash, - logger -}: { - aggregatorHash: string - logger: Logger -}) { - try { - const url = buildUrl(ORAKL_NETWORK_API_URL, `aggregator/${aggregatorHash}/${CHAIN}`) - const aggregator: IAggregator = (await axios.get(url))?.data - return aggregator - } catch (e) { - logger.error(`Failed to load aggregator with :${aggregatorHash}`) - throw new OraklError(OraklErrorCode.FailedToGetAggregator) - } -} - -export async function insertData({ - aggregatorId, - feedId, - value, - logger -}: { - aggregatorId: string - feedId: bigint - value: number - logger: Logger -}) { - const timestamp = new Date(Date.now()).toISOString() - - const data: IData[] = [ - { - aggregatorId: aggregatorId, - feedId, - timestamp, - value - } - ] - - try { - const url = buildUrl(ORAKL_NETWORK_API_URL, 'data') - const response = await axios.post(url, { data }) - - return { - status: response?.status, - statusText: response?.statusText, - data: response?.data - } - } catch (e) { - logger.error(`Failed to insert Data. API-URL:${ORAKL_NETWORK_API_URL}, Data: ${data}`) - throw new OraklError(OraklErrorCode.FailedInsertData) - } -} - -export async function insertAggregateData({ - aggregatorId, - value, - logger -}: { - aggregatorId: string - value: number - logger: Logger -}) { - const timestamp = new Date(Date.now()).toISOString() - const data = { - aggregatorId, - timestamp, - value - } - - try { - const url = buildUrl(ORAKL_NETWORK_API_URL, 'aggregate') - const response = await axios.post(url, { data }) - return { - status: response?.status, - statusText: response?.statusText, - data: response?.data - } - } catch (e) { - logger.error(`Failed to insert Aggregated Data API-URL:${ORAKL_NETWORK_API_URL}, Data: ${data}`) - throw new OraklError(OraklErrorCode.FailedInsertAggregatedData) - } -} diff --git a/core/src/por/fetcher.ts b/core/src/por/fetcher.ts deleted file mode 100644 index 60da963fe..000000000 --- a/core/src/por/fetcher.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { buildReducer, checkDataFormat, pipe, REDUCER_MAPPING } from '@bisonai/orakl-util' -import axios from 'axios' -import { Logger } from 'pino/pino' -import { IAggregator } from '../types' - -import { insertAggregateData, insertData, loadAggregator } from './api' - -async function extractFeed(adapter) { - const feeds = adapter.feeds.map((f) => { - return { - id: f.id, - name: f.name, - url: f.definition.url, - headers: f.definition.headers, - method: f.definition.method, - reducers: f.definition.reducers - } - }) - return feeds[0] -} - -async function fetchData(feed, logger) { - try { - const rawDatum = await (await axios.get(feed.url)).data - const reducers = buildReducer(REDUCER_MAPPING, feed.reducers) - const datum = pipe(...reducers)(rawDatum) - checkDataFormat(datum) - return datum - } catch (e) { - logger.error(`Fetching data failed for url:${feed.url}`) - logger.error(e) - throw e - } -} - -export async function fetchWithAggregator({ - aggregatorHash, - logger -}: { - aggregatorHash: string - logger: Logger -}) { - const aggregator: IAggregator = await loadAggregator({ aggregatorHash, logger }) - const adapter = aggregator.adapter - const feed = await extractFeed(adapter) - const value = await fetchData(feed, logger) - - await insertData({ aggregatorId: aggregator.id, feedId: feed.id, value, logger }) - await insertAggregateData({ aggregatorId: aggregator.id, value, logger }) - - return { value: BigInt(value), aggregator } -} diff --git a/core/src/por/main.ts b/core/src/por/main.ts deleted file mode 100644 index 98c6e8627..000000000 --- a/core/src/por/main.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { logger } from 'ethers' -import { buildLogger } from '../logger' -import { POR_AGGREGATOR_HASH, POR_TIMEOUT } from '../settings' -import { hookConsoleError } from '../utils' -import { fetchWithAggregator } from './fetcher' -import { reportData } from './reporter' -import { callWithTimeout } from './utils' - -const LOGGER = buildLogger() - -const _main = async () => { - hookConsoleError(LOGGER) - - const { value, aggregator } = await fetchWithAggregator({ - aggregatorHash: POR_AGGREGATOR_HASH, - logger: LOGGER - }) - - logger.info(`Fetched data:${value}`) - - await reportData({ value, aggregator, logger: LOGGER }) -} - -const main = async () => { - try { - await callWithTimeout(_main(), POR_TIMEOUT) - } catch (error) { - if (error instanceof Error && error.message === 'Timeout') { - throw new Error(`Main function timed out`) - } else { - throw error - } - } -} - -main().catch((error) => { - console.error(error) - process.exitCode = 1 -}) diff --git a/core/src/por/reporter.ts b/core/src/por/reporter.ts deleted file mode 100644 index 6f3fe2dd8..000000000 --- a/core/src/por/reporter.ts +++ /dev/null @@ -1,129 +0,0 @@ -import { Aggregator__factory } from '@bisonai/orakl-contracts' -import { ethers } from 'ethers' -import { Logger } from 'pino' -import { getReporterByOracleAddress } from '../api' -import { buildWallet, sendTransaction } from '../reporter/utils' -import { - CHAIN, - FALLBACK_PROVIDER_URL, - POR_GAS_MINIMUM, - POR_LATENCY_BUFFER, - POR_SERVICE_NAME, - PROVIDER, - PROVIDER_URL -} from '../settings' -import { IAggregator, IReporterConfig } from '../types' -import { buildTransaction } from '../worker/data-feed.utils' -import { checkRpcUrl } from './utils' - -async function shouldReport({ - aggregator, - value, - logger, - provider -}: { - aggregator: IAggregator - value: bigint - logger: Logger - provider: ethers.providers.JsonRpcProvider -}) { - const contract = new ethers.Contract(aggregator.address, Aggregator__factory.abi, provider) - const latestRoundData = await contract.latestRoundData() - - // Check Submission Hearbeat - const updatedAt = Number(latestRoundData.updatedAt) * 1000 // convert to milliseconds - const now = Date.now() - const heartbeat = aggregator.heartbeat - - if (heartbeat < POR_LATENCY_BUFFER) { - throw Error('Heartbeat cannot be smaller then latency buffer.') - } - - if (updatedAt + heartbeat - POR_LATENCY_BUFFER < now) { - logger.info('Should report by heartbeat check') - logger.info(`Last submission time:${updatedAt}, heartbeat:${heartbeat}`) - return true - } - - // Check deviation threashold - if (aggregator.threshold && latestRoundData.answer) { - const latestSubmission = Number(latestRoundData.answer) - const currentSubmission = Number(value) - - const range = latestSubmission * aggregator.threshold - const l = latestSubmission - range - const r = latestSubmission + range - - if (currentSubmission < l || currentSubmission > r) { - logger.info('Should report by deviation check') - logger.info(`Latest submission:${latestSubmission}, currentSubmission:${currentSubmission}`) - return true - } - } - return false -} - -export async function reportData({ - value, - aggregator, - logger -}: { - value: bigint - aggregator: IAggregator - logger: Logger -}) { - let provider = PROVIDER - let providerUrl = PROVIDER_URL - if (!(await checkRpcUrl(providerUrl)) && FALLBACK_PROVIDER_URL) { - if (!(await checkRpcUrl(FALLBACK_PROVIDER_URL))) { - throw Error( - `PROVIDER_URL(${PROVIDER_URL}) and FALLBACK_PROVIDER_URL(${FALLBACK_PROVIDER_URL}) are both dead` - ) - } - provider = new ethers.providers.JsonRpcProvider(FALLBACK_PROVIDER_URL) - providerUrl = FALLBACK_PROVIDER_URL - } - - const oracleAddress = aggregator.address - const reporter: IReporterConfig = await getReporterByOracleAddress({ - service: POR_SERVICE_NAME, - chain: CHAIN, - oracleAddress, - logger: logger - }) - - const iface = new ethers.utils.Interface(Aggregator__factory.abi) - const contract = new ethers.Contract(oracleAddress, Aggregator__factory.abi, provider) - const queriedRoundId = 0 - const state = await contract.oracleRoundState(reporter.address, queriedRoundId) - const roundId = state._roundId - - if (roundId == 1 || (await shouldReport({ aggregator, value, logger, provider }))) { - const tx = buildTransaction({ - payloadParameters: { - roundId, - submission: value - }, - to: oracleAddress, - gasMinimum: POR_GAS_MINIMUM, - iface, - logger - }) - - const wallet = await buildWallet({ privateKey: reporter.privateKey, providerUrl: providerUrl }) - const txParams = { wallet, ...tx, logger } - - const NUM_TRANSACTION_TRIALS = 3 - for (let i = 0; i < NUM_TRANSACTION_TRIALS; ++i) { - logger.info(`Reporting to round:${roundId} with value:${value}`) - try { - await sendTransaction(txParams) - break - } catch (e) { - logger.error('Failed to send transaction') - logger.error(e) - throw e - } - } - } -} diff --git a/core/src/por/utils.ts b/core/src/por/utils.ts deleted file mode 100644 index 8b8cfee12..000000000 --- a/core/src/por/utils.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { ethers } from 'ethers' -import { RPC_URL_TIMEOUT } from '../settings' - -export async function checkRpcUrl(url: string) { - try { - const provider = new ethers.providers.JsonRpcProvider(url) - const blockNumberPromise = provider.getBlockNumber() - const result = await callWithTimeout(blockNumberPromise, RPC_URL_TIMEOUT) - - if (result instanceof Error && result.message === 'Timeout') { - console.error(`failed to connect rpc url due to timeout: ${url}`) - return false - } else { - console.info(`json rpc is alive: ${url}`) - return true - } - } catch (error) { - console.error(`Error connecting to URL ${url}: ${error.message}`) - return false - } -} - -export const callWithTimeout = (promise, timeout) => - Promise.race([ - promise, - new Promise((_, reject) => setTimeout(() => reject(new Error('Timeout')), timeout)) - ])