@pythnetwork/price-pusher
Version:
Pyth Price Pusher
104 lines (103 loc) • 5.35 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Controller = void 0;
const utils_1 = require("./utils");
const price_config_1 = require("./price-config");
class Controller {
priceConfigs;
sourcePriceListener;
targetPriceListener;
targetChainPricePusher;
logger;
pushingFrequency;
metrics;
constructor(priceConfigs, sourcePriceListener, targetPriceListener, targetChainPricePusher, logger, config) {
this.priceConfigs = priceConfigs;
this.sourcePriceListener = sourcePriceListener;
this.targetPriceListener = targetPriceListener;
this.targetChainPricePusher = targetChainPricePusher;
this.logger = logger;
this.pushingFrequency = config.pushingFrequency;
this.metrics = config.metrics;
// Set the number of price feeds if metrics are enabled
this.metrics?.setPriceFeedsTotal(this.priceConfigs.length);
}
async start() {
// start the listeners
await this.sourcePriceListener.start();
await this.targetPriceListener.start();
// wait for the listeners to get updated. There could be a restart
// before this run and we need to respect the cooldown duration as
// their might be a message sent before.
await (0, utils_1.sleep)(this.pushingFrequency * 1000);
for (;;) {
// We will push all prices whose update condition is YES or EARLY as long as there is
// at least one YES.
let pushThresholdMet = false;
const pricesToPush = [];
const pubTimesToPush = [];
for (const priceConfig of this.priceConfigs) {
const priceId = priceConfig.id;
const alias = priceConfig.alias;
const targetLatestPrice = this.targetPriceListener.getLatestPriceInfo(priceId);
const sourceLatestPrice = this.sourcePriceListener.getLatestPriceInfo(priceId);
// Update metrics for the last published time if available
if (this.metrics && targetLatestPrice) {
this.metrics.updateLastPublishedTime(priceId, alias, targetLatestPrice);
}
const priceShouldUpdate = (0, price_config_1.shouldUpdate)(priceConfig, sourceLatestPrice, targetLatestPrice, this.logger);
// Record update condition in metrics
if (this.metrics) {
this.metrics.recordUpdateCondition(priceId, alias, priceShouldUpdate);
}
if (priceShouldUpdate == price_config_1.UpdateCondition.YES) {
pushThresholdMet = true;
}
if (priceShouldUpdate == price_config_1.UpdateCondition.YES ||
priceShouldUpdate == price_config_1.UpdateCondition.EARLY) {
pricesToPush.push(priceConfig);
pubTimesToPush.push((targetLatestPrice?.publishTime || 0) + 1);
}
}
if (pushThresholdMet) {
this.logger.info({
priceIds: pricesToPush.map((priceConfig) => ({
id: priceConfig.id,
alias: priceConfig.alias,
})),
}, "Some of the checks triggered pushing update. Will push the updates for some feeds.");
// note that the priceIds are without leading "0x"
const priceIds = pricesToPush.map((priceConfig) => priceConfig.id);
try {
await this.targetChainPricePusher.updatePriceFeed(priceIds, pubTimesToPush);
// Record successful updates
if (this.metrics) {
for (const config of pricesToPush) {
const triggerValue = (0, price_config_1.shouldUpdate)(config, this.sourcePriceListener.getLatestPriceInfo(config.id), this.targetPriceListener.getLatestPriceInfo(config.id), this.logger) === price_config_1.UpdateCondition.YES
? "yes"
: "early";
this.metrics.recordPriceUpdate(config.id, config.alias, triggerValue);
}
}
}
catch (error) {
this.logger.error({ error, priceIds }, "Error pushing price updates to chain");
// Record errors in metrics
if (this.metrics) {
for (const config of pricesToPush) {
const triggerValue = (0, price_config_1.shouldUpdate)(config, this.sourcePriceListener.getLatestPriceInfo(config.id), this.targetPriceListener.getLatestPriceInfo(config.id), this.logger) === price_config_1.UpdateCondition.YES
? "yes"
: "early";
this.metrics.recordPriceUpdateError(config.id, config.alias, triggerValue);
}
}
}
}
else {
this.logger.info("None of the checks were triggered. No push needed.");
}
await (0, utils_1.sleep)(this.pushingFrequency * 1000);
}
}
}
exports.Controller = Controller;