@pythnetwork/price-pusher
Version:
Pyth Price Pusher
123 lines (122 loc) • 4.45 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.BaseBalanceTracker = exports.ChainPriceListener = void 0;
class ChainPriceListener {
pollingFrequency;
priceItems;
latestPriceInfo;
priceIdToAlias;
constructor(pollingFrequency, priceItems) {
this.pollingFrequency = pollingFrequency;
this.priceItems = priceItems;
this.latestPriceInfo = new Map();
this.priceIdToAlias = new Map(priceItems.map(({ id, alias }) => [id, alias]));
}
async start() {
setInterval(this.pollPrices.bind(this), this.pollingFrequency * 1000);
await this.pollPrices();
}
async pollPrices() {
for (const { id: priceId } of this.priceItems) {
const currentPriceInfo = await this.getOnChainPriceInfo(priceId);
if (currentPriceInfo !== undefined) {
this.updateLatestPriceInfo(priceId, currentPriceInfo);
}
}
}
updateLatestPriceInfo(priceId, observedPrice) {
const cachedLatestPriceInfo = this.getLatestPriceInfo(priceId);
// Ignore the observed price if the cache already has newer
// price. This could happen because we are using polling and
// subscription at the same time.
if (cachedLatestPriceInfo !== undefined &&
cachedLatestPriceInfo.publishTime > observedPrice.publishTime) {
return;
}
this.latestPriceInfo.set(priceId, observedPrice);
}
// Should return undefined only when the price does not exist.
getLatestPriceInfo(priceId) {
return this.latestPriceInfo.get(priceId);
}
}
exports.ChainPriceListener = ChainPriceListener;
/**
* Abstract base class that implements common functionality for all balance trackers
*/
class BaseBalanceTracker {
address;
network;
updateInterval;
metrics;
logger;
isRunning = false;
constructor(config) {
this.address = config.address;
this.network = config.network;
this.updateInterval = config.updateInterval;
this.metrics = config.metrics;
this.logger = config.logger;
}
async start() {
if (this.isRunning) {
return;
}
this.isRunning = true;
// Initial balance update
await this.updateBalance();
// Start the update loop
this.startUpdateLoop();
}
async startUpdateLoop() {
// We're using dynamic import to avoid circular dependencies
const { sleep } = await Promise.resolve().then(() => __importStar(require("./utils")));
// Run in a loop to regularly update the balance
for (;;) {
// Wait first, since we already did the initial update in start()
await sleep(this.updateInterval * 1000);
// Only continue if we're still running
if (!this.isRunning) {
break;
}
await this.updateBalance();
}
}
stop() {
this.isRunning = false;
}
}
exports.BaseBalanceTracker = BaseBalanceTracker;