Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions apps/api/src/api/services/priceFeed.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import Big from 'big.js';
import logger from '../../config/logger';
import { getTokenOutAmount } from './nablaReads/outAmount';
import { ApiManager } from './pendulum/apiManager';
import { SlackNotifier } from './slack.service';

// Cache entry interface
interface CacheEntry<T> {
Expand Down Expand Up @@ -54,6 +55,19 @@ export class PriceFeedService {

logger.info(`PriceFeedService initialized with CoinGecko API URL: ${this.coingeckoApiBaseUrl}`);
logger.info(`Cache TTLs configured - Crypto: ${this.cryptoCacheTtlMs}ms, Fiat: ${this.fiatCacheTtlMs}ms`);

// Start cron job to check onchain oracle prices
this.checkOnchainOraclePricesUpToDate().catch((error) => {
logger.error(`Error checking onchain oracle prices: ${error.message}`);
});
setInterval(
() => {
this.checkOnchainOraclePricesUpToDate().catch((error) => {
logger.error(`Error checking onchain oracle prices: ${error.message}`);
});
},
24 * 60 * 60 * 1000,
); // Check every 24 hours
}

/**
Expand Down Expand Up @@ -371,6 +385,56 @@ export class PriceFeedService {
return amount;
}
}

// Checks if the onchain oracle prices are up to date. Sends a warning to Slack if not.
async checkOnchainOraclePricesUpToDate(): Promise<void> {
logger.info('Performing onchain oracle prices check...');

const apiManager = ApiManager.getInstance();
const pendulumApi = await apiManager.getApi('pendulum');
const pendulumApiInstance = pendulumApi.api;

try {
// Check if the oracle prices are up to date
const allPricesEncoded = await pendulumApiInstance.query.diaOracleModule.coinInfosMap.entries();

const prices = allPricesEncoded.map(([key, priceData]) => {
const price = priceData.toHuman() as { name: string; lastUpdateTimestamp: string };
return {
name: price.name,
lastUpdateTimestamp: price.lastUpdateTimestamp.replaceAll(',', ''),
};
});

const outdatedPrices = [];
for (const price of prices) {
const lastUpdateTimestamp = parseInt(price.lastUpdateTimestamp, 10);
const currentTime = Math.floor(Date.now() / 1000); // Current time in seconds
const isPriceUpToDate = currentTime - lastUpdateTimestamp < 3600; // Check if updated within the last hour

if (!isPriceUpToDate) {
logger.warn(
`Onchain oracle price for ${price.name} is not up to date. Last update: ${lastUpdateTimestamp}, Current time: ${currentTime}`,
);

outdatedPrices.push(price);
}
}

if (outdatedPrices.length > 0) {
const slackNotifier = new SlackNotifier();
await slackNotifier.sendMessage({
text: `⚠️ Onchain oracle prices are not up to date! The following prices are outdated:\n${outdatedPrices.join(
', ',
)}`,
});
} else {
logger.info('All onchain oracle prices are up to date.');
}
} catch (error) {
logger.error(`Error checking onchain oracle prices: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
}
}

export const priceFeedService = PriceFeedService.getInstance();
Loading