瀏覽代碼

update price config file references, add Solana balance tracker, and enable metrics

Daniel Chew 8 月之前
父節點
當前提交
1726486dfe

+ 1 - 1
apps/price_pusher/config.solana.mainnet.sample.json

@@ -8,7 +8,7 @@
   "dynamic-jito-tips": true,
   "jito-bundle-size": "5",
   "updates-per-jito-bundle": "6",
-  "price-config-file": "./price-config.yaml",
+  "price-config-file": "./price-config.stable.sample.yaml",
   "price-service-endpoint": "https://hermes.pyth.network/",
   "pyth-contract-address": "pythWSnswVUd12oZpeFP8e9CVaEqJg25g1Vtc2biRsT",
   "pushing-frequency": "30"

+ 1 - 1
apps/price_pusher/config.solana.testnet.sample.json

@@ -2,7 +2,7 @@
   "endpoint": "https://api.devnet.solana.com",
   "keypair-file": "./id.json",
   "shard-id": 1,
-  "price-config-file": "./price-config.yaml",
+  "price-config-file": "./price-config.stable.sample.yaml",
   "price-service-endpoint": "https://hermes.pyth.network/",
   "pyth-contract-address": "pythWSnswVUd12oZpeFP8e9CVaEqJg25g1Vtc2biRsT",
   "pushing-frequency": "30"

+ 1 - 1
apps/price_pusher/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@pythnetwork/price-pusher",
-  "version": "9.1.3",
+  "version": "9.1.4",
   "description": "Pyth Price Pusher",
   "homepage": "https://pyth.network",
   "main": "lib/index.js",

+ 94 - 0
apps/price_pusher/src/solana/balance-tracker.ts

@@ -0,0 +1,94 @@
+import { Connection, PublicKey, LAMPORTS_PER_SOL } from "@solana/web3.js";
+import {
+  BaseBalanceTracker,
+  BaseBalanceTrackerConfig,
+  IBalanceTracker,
+} from "../interface";
+import { DurationInSeconds } from "../utils";
+import { PricePusherMetrics } from "../metrics";
+import { Logger } from "pino";
+
+/**
+ * Solana-specific configuration for balance tracker
+ */
+export interface SolanaBalanceTrackerConfig extends BaseBalanceTrackerConfig {
+  /** Solana connection instance */
+  connection: Connection;
+  /** Solana public key */
+  publicKey: PublicKey;
+}
+
+/**
+ * Solana-specific implementation of the balance tracker
+ */
+export class SolanaBalanceTracker extends BaseBalanceTracker {
+  private connection: Connection;
+  private publicKey: PublicKey;
+
+  constructor(config: SolanaBalanceTrackerConfig) {
+    super({
+      ...config,
+      logger: config.logger.child({ module: "SolanaBalanceTracker" }),
+    });
+
+    this.connection = config.connection;
+    this.publicKey = config.publicKey;
+  }
+
+  /**
+   * Solana-specific implementation of balance update
+   */
+  protected async updateBalance(): Promise<void> {
+    try {
+      const balanceInLamports = await this.connection.getBalance(
+        this.publicKey,
+      );
+
+      // Convert from lamports to SOL
+      const balanceInSol = balanceInLamports / LAMPORTS_PER_SOL;
+
+      this.metrics.updateWalletBalance(
+        this.address,
+        this.network,
+        balanceInSol,
+      );
+      this.logger.debug(
+        `Updated Solana wallet balance: ${this.address} = ${balanceInSol.toString()} SOL (${balanceInLamports} lamports)`,
+      );
+    } catch (error) {
+      this.logger.error(
+        { error },
+        "Error fetching Solana wallet balance for metrics",
+      );
+    }
+  }
+}
+
+/**
+ * Parameters for creating a Solana balance tracker
+ */
+export interface CreateSolanaBalanceTrackerParams {
+  connection: Connection;
+  publicKey: PublicKey;
+  network: string;
+  updateInterval: DurationInSeconds;
+  metrics: PricePusherMetrics;
+  logger: Logger;
+}
+
+/**
+ * Factory function to create a balance tracker for Solana
+ */
+export function createSolanaBalanceTracker(
+  params: CreateSolanaBalanceTrackerParams,
+): IBalanceTracker {
+  return new SolanaBalanceTracker({
+    connection: params.connection,
+    publicKey: params.publicKey,
+    address: params.publicKey.toString(),
+    network: params.network,
+    updateInterval: params.updateInterval,
+    metrics: params.metrics,
+    logger: params.logger,
+  });
+}

+ 38 - 5
apps/price_pusher/src/solana/command.ts

@@ -21,6 +21,10 @@ import pino from "pino";
 import { Logger } from "pino";
 import { HermesClient } from "@pythnetwork/hermes-client";
 import { filterInvalidPriceItems } from "../utils";
+import { PricePusherMetrics } from "../metrics";
+import { createSolanaBalanceTracker } from "./balance-tracker";
+import { IBalanceTracker } from "../interface";
+
 export default {
   command: "solana",
   describe: "run price pusher for solana",
@@ -99,6 +103,8 @@ export default {
     ...options.pushingFrequency,
     ...options.logLevel,
     ...options.controllerLogLevel,
+    ...options.enableMetrics,
+    ...options.metricsPort,
   },
   handler: async function (argv: any) {
     const {
@@ -122,6 +128,8 @@ export default {
       treasuryId,
       logLevel,
       controllerLogLevel,
+      enableMetrics,
+      metricsPort,
     } = argv;
 
     const logger = pino({ level: logLevel });
@@ -130,6 +138,14 @@ export default {
 
     const hermesClient = new HermesClient(priceServiceEndpoint);
 
+    // Initialize metrics if enabled
+    let metrics: PricePusherMetrics | undefined;
+    if (enableMetrics) {
+      metrics = new PricePusherMetrics(logger.child({ module: "Metrics" }));
+      metrics.start(metricsPort);
+      logger.info(`Metrics server started on port ${metricsPort}`);
+    }
+
     let priceItems = priceConfigs.map(({ id, alias }) => ({ id, alias }));
 
     // Better to filter out invalid price items before creating the pyth listener
@@ -152,11 +168,10 @@ export default {
       logger.child({ module: "PythPriceListener" }),
     );
 
-    const wallet = new NodeWallet(
-      Keypair.fromSecretKey(
-        Uint8Array.from(JSON.parse(fs.readFileSync(keypairFile, "ascii"))),
-      ),
+    const keypair = Keypair.fromSecretKey(
+      Uint8Array.from(JSON.parse(fs.readFileSync(keypairFile, "ascii"))),
     );
+    const wallet = new NodeWallet(keypair);
 
     const connection = new Connection(endpoint, "processed");
     const pythSolanaReceiver = new PythSolanaReceiver({
@@ -166,6 +181,21 @@ export default {
       treasuryId: treasuryId,
     });
 
+    // Create and start the balance tracker if metrics are enabled
+    if (metrics) {
+      const balanceTracker: IBalanceTracker = createSolanaBalanceTracker({
+        connection,
+        publicKey: keypair.publicKey,
+        network: "solana",
+        updateInterval: 60,
+        metrics,
+        logger,
+      });
+
+      // Start the balance tracker
+      await balanceTracker.start();
+    }
+
     // Fetch the account lookup table if provided
     const lookupTableAccount = addressLookupTableAccount
       ? await connection
@@ -220,7 +250,10 @@ export default {
       solanaPriceListener,
       solanaPricePusher,
       logger.child({ module: "Controller" }, { level: controllerLogLevel }),
-      { pushingFrequency },
+      {
+        pushingFrequency,
+        metrics,
+      },
     );
 
     controller.start();