Browse Source

feat(apps/price_pusher)!: switch to structured logger via pino (#1714)

* feat(apps/price_pusher)!: switch to structured logger via pino

This change switches from `console` to `pino` for logging that is a
structured logger and allows us to have json formatted loggers. In
adition to just that change, pino does an amazing job at logging the
errors by including all their data + the stacktrace.

This change does minimal change to the log level and the `console.log`
is changed to info or debug level based on my judgement.

This change is marked as breaking because it breaks any reliability/ops
based on the logs.

* fix: address review comments

* fix: add @solana/web3.js deps as its used

* refactor: make it more configurable
Ali Behjati 1 year ago
parent
commit
2faaa4366c

+ 25 - 13
apps/price_pusher/README.md

@@ -83,14 +83,14 @@ To run the price pusher, please run the following commands, replacing the comman
 
 
 ```sh
 ```sh
 # Please run the two following commands once from the root of the repo to build the code.
 # Please run the two following commands once from the root of the repo to build the code.
-npm install
+pnpm install
 pnpm exec lerna run build --scope @pythnetwork/price-pusher --include-dependencies
 pnpm exec lerna run build --scope @pythnetwork/price-pusher --include-dependencies
 
 
 # Navigate to the price_pusher folder
 # Navigate to the price_pusher folder
 cd apps/price_pusher
 cd apps/price_pusher
 
 
 # For EVM
 # For EVM
-npm run start -- evm --endpoint wss://example-rpc.com \
+pnpm run start evm --endpoint wss://example-rpc.com \
     --pyth-contract-address 0xff1a0f4744e8582DF...... \
     --pyth-contract-address 0xff1a0f4744e8582DF...... \
     --price-service-endpoint https://example-hermes-rpc.com \
     --price-service-endpoint https://example-hermes-rpc.com \
     --price-config-file "path/to/price-config.beta.sample.yaml" \
     --price-config-file "path/to/price-config.beta.sample.yaml" \
@@ -100,7 +100,7 @@ npm run start -- evm --endpoint wss://example-rpc.com \
     [--override-gas-price-multiplier 1.1]
     [--override-gas-price-multiplier 1.1]
 
 
 # For Injective
 # For Injective
-npm run start -- injective --grpc-endpoint https://grpc-endpoint.com \
+pnpm run start injective --grpc-endpoint https://grpc-endpoint.com \
     --pyth-contract-address inj1z60tg0... --price-service-endpoint "https://example-hermes-rpc.com" \
     --pyth-contract-address inj1z60tg0... --price-service-endpoint "https://example-hermes-rpc.com" \
     --price-config-file "path/to/price-config.beta.sample.yaml" \
     --price-config-file "path/to/price-config.beta.sample.yaml" \
     --mnemonic-file "path/to/mnemonic.txt" \
     --mnemonic-file "path/to/mnemonic.txt" \
@@ -110,7 +110,7 @@ npm run start -- injective --grpc-endpoint https://grpc-endpoint.com \
     [--polling-frequency 5]
     [--polling-frequency 5]
 
 
 # For Aptos
 # For Aptos
-npm run start -- aptos --endpoint https://fullnode.testnet.aptoslabs.com/v1 \
+pnpm run start aptos --endpoint https://fullnode.testnet.aptoslabs.com/v1 \
     --pyth-contract-address 0x7e783b349d3e89cf5931af376ebeadbfab855b3fa239b7ada8f5a92fbea6b387 \
     --pyth-contract-address 0x7e783b349d3e89cf5931af376ebeadbfab855b3fa239b7ada8f5a92fbea6b387 \
     --price-service-endpoint "https://example-hermes-rpc.com" \
     --price-service-endpoint "https://example-hermes-rpc.com" \
     --price-config-file "path/to/price-config.beta.sample.yaml" \
     --price-config-file "path/to/price-config.beta.sample.yaml" \
@@ -119,7 +119,7 @@ npm run start -- aptos --endpoint https://fullnode.testnet.aptoslabs.com/v1 \
     [--polling-frequency 5]
     [--polling-frequency 5]
 
 
 # For Sui
 # For Sui
-npm run start -- sui \
+pnpm run start sui \
   --endpoint https://sui-testnet-rpc.allthatnode.com \
   --endpoint https://sui-testnet-rpc.allthatnode.com \
   --pyth-package-id 0x975e063f398f720af4f33ec06a927f14ea76ca24f7f8dd544aa62ab9d5d15f44 \
   --pyth-package-id 0x975e063f398f720af4f33ec06a927f14ea76ca24f7f8dd544aa62ab9d5d15f44 \
   --pyth-state-id 0xd8afde3a48b4ff7212bd6829a150f43f59043221200d63504d981f62bff2e27a \
   --pyth-state-id 0xd8afde3a48b4ff7212bd6829a150f43f59043221200d63504d981f62bff2e27a \
@@ -134,7 +134,7 @@ npm run start -- sui \
   [--num-gas-objects 30]
   [--num-gas-objects 30]
 
 
 # For Near
 # For Near
-npm run start -- near \
+pnpm run start near \
   --node-url https://rpc.testnet.near.org \
   --node-url https://rpc.testnet.near.org \
   --network testnet \
   --network testnet \
   --account-id payer.testnet \
   --account-id payer.testnet \
@@ -146,7 +146,7 @@ npm run start -- near \
   [--polling-frequency 5]
   [--polling-frequency 5]
 
 
 # For Solana, using Jito (recommended)
 # For Solana, using Jito (recommended)
-npm run start -- solana \
+pnpm run start solana \
   --endpoint https://api.mainnet-beta.solana.com \
   --endpoint https://api.mainnet-beta.solana.com \
   --keypair-file ./id.json \
   --keypair-file ./id.json \
   --shard-id 1 \
   --shard-id 1 \
@@ -161,7 +161,7 @@ npm run start -- solana \
   [--polling-frequency 5]
   [--polling-frequency 5]
 
 
 # For Solana, using Solana RPC
 # For Solana, using Solana RPC
-npm run start -- solana \
+pnpm run start solana \
   --endpoint https://api.devnet.solana.com \
   --endpoint https://api.devnet.solana.com \
   --keypair-file ./id.json \
   --keypair-file ./id.json \
   --shard-id 1 \
   --shard-id 1 \
@@ -184,23 +184,35 @@ docker run public.ecr.aws/pyth-network/xc-price-pusher:v<version> -- <above-argu
 To know more about the arguments the price-pusher accepts. You can run:
 To know more about the arguments the price-pusher accepts. You can run:
 
 
 ```sh
 ```sh
-npm run start -- --help
+pnpm run start --help
 
 
 # for specific network run
 # for specific network run
-npm run start -- {network} --help
+pnpm run start {network} --help
 ```
 ```
 
 
+### Logging
+
+By default, the logging is set to `info`. You can change the logging level by passing the argument `--log-level` with the desired level.
+The available levels are `error`, `warn`, `info`, `debug`, and `trace`. Also, the logs have JSON format. If you wish to run the code with
+human-readable logs, you can pipe the output of the program to `pino-pretty`. See the example below for more information on how to do this.
+
+You can configure the log level of some of the modules of the price pusher as well. The available modules are PriceServiceConnection, which
+is responsible for connecting to the Hermes price service, and Controller, which is responsible for checking the prices from the Hermes
+and the on-chain Pyth contract and deciding whether to push a new price. You can configure the log level of these modules by passing the
+`--price-service-connection-log-level` and `--controller-log-level` arguments, respectively.
+
 ### Example
 ### Example
 
 
 For example, to push `BTC/USD` and `BNB/USD` prices on Fantom testnet, run the following command:
 For example, to push `BTC/USD` and `BNB/USD` prices on Fantom testnet, run the following command:
 
 
 ```sh
 ```sh
-npm run dev -- evm \
+pnpm run dev evm \
   --endpoint https://endpoints.omniatech.io/v1/fantom/testnet/public \
   --endpoint https://endpoints.omniatech.io/v1/fantom/testnet/public \
   --pyth-contract-address 0x5744Cbf430D99456a0A8771208b674F27f8EF0Fb \
   --pyth-contract-address 0x5744Cbf430D99456a0A8771208b674F27f8EF0Fb \
   --price-service-endpoint https://hermes.pyth.network \
   --price-service-endpoint https://hermes.pyth.network \
   --mnemonic-file "./mnemonic" \
   --mnemonic-file "./mnemonic" \
-  --price-config-file "./price-config.stable.sample.yaml"
+  --price-config-file "./price-config.stable.sample.yaml" \
+  | pnpm exec pino-pretty # Make logs human-readable
 ```
 ```
 
 
 [`price-config.stable.sample.yaml`](./price-config.stable.sample.yaml) contains configuration for `BTC/USD`
 [`price-config.stable.sample.yaml`](./price-config.stable.sample.yaml) contains configuration for `BTC/USD`
@@ -210,7 +222,7 @@ contains the same configuration for `BTC/USD` and `BNB/USD` on Pyth beta data so
 You can also provide a config file instead of providing command line options, run the following command:
 You can also provide a config file instead of providing command line options, run the following command:
 
 
 ```sh
 ```sh
-npm run start -- injective --config "./config.injective.sample.json"
+pnpm run start injective --config "./config.injective.sample.json"
 ```
 ```
 
 
 [`config.injective.sample.json`](./config.injective.sample.json) contains configuration to publish on Injective testnet.
 [`config.injective.sample.json`](./config.injective.sample.json) contains configuration to publish on Injective testnet.

+ 5 - 1
apps/price_pusher/package.json

@@ -1,6 +1,6 @@
 {
 {
   "name": "@pythnetwork/price-pusher",
   "name": "@pythnetwork/price-pusher",
-  "version": "6.8.0",
+  "version": "7.0.0-alpha",
   "description": "Pyth Price Pusher",
   "description": "Pyth Price Pusher",
   "homepage": "https://pyth.network",
   "homepage": "https://pyth.network",
   "main": "lib/index.js",
   "main": "lib/index.js",
@@ -46,6 +46,7 @@
     "@typescript-eslint/parser": "^6.0.0",
     "@typescript-eslint/parser": "^6.0.0",
     "eslint": "^8.13.0",
     "eslint": "^8.13.0",
     "jest": "^29.7.0",
     "jest": "^29.7.0",
+    "pino-pretty": "^11.2.1",
     "prettier": "^2.6.2",
     "prettier": "^2.6.2",
     "ts-jest": "^29.1.1",
     "ts-jest": "^29.1.1",
     "ts-node": "^10.9.1",
     "ts-node": "^10.9.1",
@@ -62,11 +63,14 @@
     "@pythnetwork/pyth-solana-receiver": "workspace:*",
     "@pythnetwork/pyth-solana-receiver": "workspace:*",
     "@pythnetwork/pyth-sui-js": "workspace:*",
     "@pythnetwork/pyth-sui-js": "workspace:*",
     "@pythnetwork/solana-utils": "workspace:*",
     "@pythnetwork/solana-utils": "workspace:*",
+    "@solana/web3.js": "^1.93.0",
     "@truffle/hdwallet-provider": "^2.1.3",
     "@truffle/hdwallet-provider": "^2.1.3",
+    "@types/pino": "^7.0.5",
     "aptos": "^1.8.5",
     "aptos": "^1.8.5",
     "jito-ts": "^3.0.1",
     "jito-ts": "^3.0.1",
     "joi": "^17.6.0",
     "joi": "^17.6.0",
     "near-api-js": "^3.0.2",
     "near-api-js": "^3.0.2",
+    "pino": "^9.2.0",
     "web3": "^1.8.1",
     "web3": "^1.8.1",
     "web3-core": "^1.8.1",
     "web3-core": "^1.8.1",
     "web3-eth-contract": "^1.8.1",
     "web3-eth-contract": "^1.8.1",

+ 24 - 18
apps/price_pusher/src/aptos/aptos.ts

@@ -7,17 +7,19 @@ import {
 import { AptosAccount, AptosClient } from "aptos";
 import { AptosAccount, AptosClient } from "aptos";
 import { DurationInSeconds } from "../utils";
 import { DurationInSeconds } from "../utils";
 import { PriceServiceConnection } from "@pythnetwork/price-service-client";
 import { PriceServiceConnection } from "@pythnetwork/price-service-client";
+import { Logger } from "pino";
 
 
 export class AptosPriceListener extends ChainPriceListener {
 export class AptosPriceListener extends ChainPriceListener {
   constructor(
   constructor(
     private pythModule: string,
     private pythModule: string,
     private endpoint: string,
     private endpoint: string,
     priceItems: PriceItem[],
     priceItems: PriceItem[],
+    private logger: Logger,
     config: {
     config: {
       pollingFrequency: DurationInSeconds;
       pollingFrequency: DurationInSeconds;
     }
     }
   ) {
   ) {
-    super("aptos", config.pollingFrequency, priceItems);
+    super(config.pollingFrequency, priceItems);
   }
   }
 
 
   async getOnChainPriceInfo(priceId: string): Promise<PriceInfo | undefined> {
   async getOnChainPriceInfo(priceId: string): Promise<PriceInfo | undefined> {
@@ -46,7 +48,7 @@ export class AptosPriceListener extends ChainPriceListener {
       const price =
       const price =
         multiplier * Number(priceItemRes.price_feed.price.price.magnitude);
         multiplier * Number(priceItemRes.price_feed.price.price.magnitude);
 
 
-      console.log(
+      this.logger.debug(
         `Polled an Aptos on-chain price for feed ${this.priceIdToAlias.get(
         `Polled an Aptos on-chain price for feed ${this.priceIdToAlias.get(
           priceId
           priceId
         )} (${priceId}).`
         )} (${priceId}).`
@@ -57,11 +59,11 @@ export class AptosPriceListener extends ChainPriceListener {
         conf: priceItemRes.price_feed.price.conf,
         conf: priceItemRes.price_feed.price.conf,
         publishTime: Number(priceItemRes.price_feed.price.timestamp),
         publishTime: Number(priceItemRes.price_feed.price.timestamp),
       };
       };
-    } catch (e) {
-      console.error(
-        `Polling Aptos on-chain price for ${priceId} failed. Error:`
+    } catch (err) {
+      this.logger.error(
+        err,
+        `Polling Aptos on-chain price for ${priceId} failed.`
       );
       );
-      console.error(e);
       return undefined;
       return undefined;
     }
     }
   }
   }
@@ -88,6 +90,7 @@ export class AptosPricePusher implements IPricePusher {
 
 
   constructor(
   constructor(
     private priceServiceConnection: PriceServiceConnection,
     private priceServiceConnection: PriceServiceConnection,
+    private logger: Logger,
     private pythContractAddress: string,
     private pythContractAddress: string,
     private endpoint: string,
     private endpoint: string,
     private mnemonic: string,
     private mnemonic: string,
@@ -126,9 +129,8 @@ export class AptosPricePusher implements IPricePusher {
     try {
     try {
       // get the latest VAAs for updatePriceFeed and then push them
       // get the latest VAAs for updatePriceFeed and then push them
       priceFeedUpdateData = await this.getPriceFeedsUpdateData(priceIds);
       priceFeedUpdateData = await this.getPriceFeedsUpdateData(priceIds);
-    } catch (e) {
-      console.error("Error fetching the latest vaas to push");
-      console.error(e);
+    } catch (err) {
+      this.logger.error(err, "Error fetching the latest vaas to push.");
       return;
       return;
     }
     }
 
 
@@ -158,7 +160,10 @@ export class AptosPricePusher implements IPricePusher {
       const signedTx = await client.signTransaction(account, rawTx);
       const signedTx = await client.signTransaction(account, rawTx);
       const pendingTx = await client.submitTransaction(signedTx);
       const pendingTx = await client.submitTransaction(signedTx);
 
 
-      console.log("Successfully broadcasted txHash:", pendingTx.hash);
+      this.logger.debug(
+        { hash: pendingTx.hash },
+        "Successfully broadcasted tx."
+      );
 
 
       // Sometimes broadcasted txs don't make it on-chain and they cause our sequence number
       // Sometimes broadcasted txs don't make it on-chain and they cause our sequence number
       // to go out of sync. Missing transactions are rare and we don't want this check to block
       // to go out of sync. Missing transactions are rare and we don't want this check to block
@@ -167,9 +172,8 @@ export class AptosPricePusher implements IPricePusher {
       this.waitForTransactionConfirmation(client, pendingTx.hash);
       this.waitForTransactionConfirmation(client, pendingTx.hash);
 
 
       return;
       return;
-    } catch (e: any) {
-      console.error("Error executing messages");
-      console.error(e);
+    } catch (err: any) {
+      this.logger.error(err, "Error executing messages");
 
 
       // Reset the sequence number to re-sync it (in case that was the issue)
       // Reset the sequence number to re-sync it (in case that was the issue)
       this.lastSequenceNumber = undefined;
       this.lastSequenceNumber = undefined;
@@ -189,10 +193,12 @@ export class AptosPricePusher implements IPricePusher {
         timeoutSecs: 10,
         timeoutSecs: 10,
       });
       });
 
 
-      console.log(`Transaction with txHash "${txHash}" confirmed.`);
-    } catch (e) {
-      console.error(`Transaction with txHash "${txHash}" failed to confirm.`);
-      console.error(e);
+      this.logger.info({ hash: txHash }, `Transaction confirmed.`);
+    } catch (err) {
+      this.logger.error(
+        { err, hash: txHash },
+        `Transaction failed to confirm.`
+      );
 
 
       this.lastSequenceNumber = undefined;
       this.lastSequenceNumber = undefined;
     }
     }
@@ -218,7 +224,7 @@ export class AptosPricePusher implements IPricePusher {
           this.lastSequenceNumber = Number(
           this.lastSequenceNumber = Number(
             (await client.getAccount(account.address())).sequence_number
             (await client.getAccount(account.address())).sequence_number
           );
           );
-          console.log(
+          this.logger.debug(
             `Fetched account sequence number: ${this.lastSequenceNumber}`
             `Fetched account sequence number: ${this.lastSequenceNumber}`
           );
           );
           return this.lastSequenceNumber;
           return this.lastSequenceNumber;

+ 21 - 10
apps/price_pusher/src/aptos/command.ts

@@ -11,6 +11,7 @@ import {
   APTOS_ACCOUNT_HD_PATH,
   APTOS_ACCOUNT_HD_PATH,
 } from "./aptos";
 } from "./aptos";
 import { AptosAccount } from "aptos";
 import { AptosAccount } from "aptos";
+import pino from "pino";
 
 
 export default {
 export default {
   command: "aptos",
   command: "aptos",
@@ -37,6 +38,9 @@ export default {
     ...options.pythContractAddress,
     ...options.pythContractAddress,
     ...options.pollingFrequency,
     ...options.pollingFrequency,
     ...options.pushingFrequency,
     ...options.pushingFrequency,
+    ...options.logLevel,
+    ...options.priceServiceConnectionLogLevel,
+    ...options.controllerLogLevel,
   },
   },
   handler: function (argv: any) {
   handler: function (argv: any) {
     // FIXME: type checks for this
     // FIXME: type checks for this
@@ -49,44 +53,50 @@ export default {
       pushingFrequency,
       pushingFrequency,
       pollingFrequency,
       pollingFrequency,
       overrideGasPriceMultiplier,
       overrideGasPriceMultiplier,
+      logLevel,
+      priceServiceConnectionLogLevel,
+      controllerLogLevel,
     } = argv;
     } = argv;
 
 
+    const logger = pino({ level: logLevel });
+
     const priceConfigs = readPriceConfigFile(priceConfigFile);
     const priceConfigs = readPriceConfigFile(priceConfigFile);
     const priceServiceConnection = new PriceServiceConnection(
     const priceServiceConnection = new PriceServiceConnection(
       priceServiceEndpoint,
       priceServiceEndpoint,
       {
       {
-        logger: {
-          // Log only warnings and errors from the price service client
-          info: () => undefined,
-          warn: console.warn,
-          error: console.error,
-          debug: () => undefined,
-          trace: () => undefined,
-        },
+        logger: logger.child(
+          { module: "PriceServiceConnection" },
+          { level: priceServiceConnectionLogLevel }
+        ),
       }
       }
     );
     );
+
     const mnemonic = fs.readFileSync(mnemonicFile, "utf-8").trim();
     const mnemonic = fs.readFileSync(mnemonicFile, "utf-8").trim();
     const account = AptosAccount.fromDerivePath(
     const account = AptosAccount.fromDerivePath(
       APTOS_ACCOUNT_HD_PATH,
       APTOS_ACCOUNT_HD_PATH,
       mnemonic
       mnemonic
     );
     );
-    console.log(`Pushing from account address: ${account.address()}`);
+    logger.info(`Pushing from account address: ${account.address()}`);
 
 
     const priceItems = priceConfigs.map(({ id, alias }) => ({ id, alias }));
     const priceItems = priceConfigs.map(({ id, alias }) => ({ id, alias }));
 
 
     const pythListener = new PythPriceListener(
     const pythListener = new PythPriceListener(
       priceServiceConnection,
       priceServiceConnection,
-      priceItems
+      priceItems,
+      logger.child({ module: "PythPriceListener" })
     );
     );
 
 
     const aptosListener = new AptosPriceListener(
     const aptosListener = new AptosPriceListener(
       pythContractAddress,
       pythContractAddress,
       endpoint,
       endpoint,
       priceItems,
       priceItems,
+      logger.child({ module: "AptosPriceListener" }),
       { pollingFrequency }
       { pollingFrequency }
     );
     );
+
     const aptosPusher = new AptosPricePusher(
     const aptosPusher = new AptosPricePusher(
       priceServiceConnection,
       priceServiceConnection,
+      logger.child({ module: "AptosPricePusher" }),
       pythContractAddress,
       pythContractAddress,
       endpoint,
       endpoint,
       mnemonic,
       mnemonic,
@@ -98,6 +108,7 @@ export default {
       pythListener,
       pythListener,
       aptosListener,
       aptosListener,
       aptosPusher,
       aptosPusher,
+      logger.child({ module: "Controller" }, { level: controllerLogLevel }),
       { pushingFrequency }
       { pushingFrequency }
     );
     );
 
 

+ 13 - 6
apps/price_pusher/src/controller.ts

@@ -2,6 +2,7 @@ import { UnixTimestamp } from "@pythnetwork/price-service-client";
 import { DurationInSeconds, sleep } from "./utils";
 import { DurationInSeconds, sleep } from "./utils";
 import { IPriceListener, IPricePusher } from "./interface";
 import { IPriceListener, IPricePusher } from "./interface";
 import { PriceConfig, shouldUpdate, UpdateCondition } from "./price-config";
 import { PriceConfig, shouldUpdate, UpdateCondition } from "./price-config";
+import { Logger } from "pino";
 
 
 export class Controller {
 export class Controller {
   private pushingFrequency: DurationInSeconds;
   private pushingFrequency: DurationInSeconds;
@@ -10,6 +11,7 @@ export class Controller {
     private sourcePriceListener: IPriceListener,
     private sourcePriceListener: IPriceListener,
     private targetPriceListener: IPriceListener,
     private targetPriceListener: IPriceListener,
     private targetChainPricePusher: IPricePusher,
     private targetChainPricePusher: IPricePusher,
+    private logger: Logger,
     config: {
     config: {
       pushingFrequency: DurationInSeconds;
       pushingFrequency: DurationInSeconds;
     }
     }
@@ -45,7 +47,8 @@ export class Controller {
         const priceShouldUpdate = shouldUpdate(
         const priceShouldUpdate = shouldUpdate(
           priceConfig,
           priceConfig,
           sourceLatestPrice,
           sourceLatestPrice,
-          targetLatestPrice
+          targetLatestPrice,
+          this.logger
         );
         );
         if (priceShouldUpdate == UpdateCondition.YES) {
         if (priceShouldUpdate == UpdateCondition.YES) {
           pushThresholdMet = true;
           pushThresholdMet = true;
@@ -60,17 +63,21 @@ export class Controller {
         }
         }
       }
       }
       if (pushThresholdMet) {
       if (pushThresholdMet) {
-        console.log(
-          "Some of the above values passed the threshold. Will push the price."
+        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"
         // note that the priceIds are without leading "0x"
         const priceIds = pricesToPush.map((priceConfig) => priceConfig.id);
         const priceIds = pricesToPush.map((priceConfig) => priceConfig.id);
         this.targetChainPricePusher.updatePriceFeed(priceIds, pubTimesToPush);
         this.targetChainPricePusher.updatePriceFeed(priceIds, pubTimesToPush);
       } else {
       } else {
-        console.log(
-          "None of the above values passed the threshold. No push needed."
-        );
+        this.logger.info("None of the checks were triggered. No push needed.");
       }
       }
 
 
       await sleep(this.pushingFrequency * 1000);
       await sleep(this.pushingFrequency * 1000);

+ 34 - 16
apps/price_pusher/src/evm/command.ts

@@ -1,12 +1,13 @@
 import { PriceServiceConnection } from "@pythnetwork/price-service-client";
 import { PriceServiceConnection } from "@pythnetwork/price-service-client";
+import fs from "fs";
+import { Options } from "yargs";
 import * as options from "../options";
 import * as options from "../options";
 import { readPriceConfigFile } from "../price-config";
 import { readPriceConfigFile } from "../price-config";
-import fs from "fs";
 import { PythPriceListener } from "../pyth-price-listener";
 import { PythPriceListener } from "../pyth-price-listener";
 import { Controller } from "../controller";
 import { Controller } from "../controller";
-import { Options } from "yargs";
 import { EvmPriceListener, EvmPricePusher, PythContractFactory } from "./evm";
 import { EvmPriceListener, EvmPricePusher, PythContractFactory } from "./evm";
 import { getCustomGasStation } from "./custom-gas-station";
 import { getCustomGasStation } from "./custom-gas-station";
+import pino from "pino";
 
 
 export default {
 export default {
   command: "evm",
   command: "evm",
@@ -72,6 +73,9 @@ export default {
     ...options.pythContractAddress,
     ...options.pythContractAddress,
     ...options.pollingFrequency,
     ...options.pollingFrequency,
     ...options.pushingFrequency,
     ...options.pushingFrequency,
+    ...options.logLevel,
+    ...options.priceServiceConnectionLogLevel,
+    ...options.controllerLogLevel,
   },
   },
   handler: function (argv: any) {
   handler: function (argv: any) {
     // FIXME: type checks for this
     // FIXME: type checks for this
@@ -89,29 +93,32 @@ export default {
       overrideGasPriceMultiplierCap,
       overrideGasPriceMultiplierCap,
       gasLimit,
       gasLimit,
       updateFeeMultiplier,
       updateFeeMultiplier,
+      logLevel,
+      priceServiceConnectionLogLevel,
+      controllerLogLevel,
     } = argv;
     } = argv;
 
 
+    const logger = pino({ level: logLevel });
+
     const priceConfigs = readPriceConfigFile(priceConfigFile);
     const priceConfigs = readPriceConfigFile(priceConfigFile);
     const priceServiceConnection = new PriceServiceConnection(
     const priceServiceConnection = new PriceServiceConnection(
       priceServiceEndpoint,
       priceServiceEndpoint,
       {
       {
-        logger: {
-          // Log only warnings and errors from the price service client
-          info: () => undefined,
-          warn: console.warn,
-          error: console.error,
-          debug: () => undefined,
-          trace: () => undefined,
-        },
+        logger: logger.child(
+          { module: "PriceServiceConnection" },
+          { level: priceServiceConnectionLogLevel }
+        ),
       }
       }
     );
     );
+
     const mnemonic = fs.readFileSync(mnemonicFile, "utf-8").trim();
     const mnemonic = fs.readFileSync(mnemonicFile, "utf-8").trim();
 
 
     const priceItems = priceConfigs.map(({ id, alias }) => ({ id, alias }));
     const priceItems = priceConfigs.map(({ id, alias }) => ({ id, alias }));
 
 
     const pythListener = new PythPriceListener(
     const pythListener = new PythPriceListener(
       priceServiceConnection,
       priceServiceConnection,
-      priceItems
+      priceItems,
+      logger.child({ module: "PythPriceListener" })
     );
     );
 
 
     const pythContractFactory = new PythContractFactory(
     const pythContractFactory = new PythContractFactory(
@@ -119,20 +126,30 @@ export default {
       mnemonic,
       mnemonic,
       pythContractAddress
       pythContractAddress
     );
     );
-    console.log(
+    logger.info(
       `Pushing updates from wallet address: ${pythContractFactory
       `Pushing updates from wallet address: ${pythContractFactory
         .createWeb3PayerProvider()
         .createWeb3PayerProvider()
         .getAddress()}`
         .getAddress()}`
     );
     );
 
 
-    const evmListener = new EvmPriceListener(pythContractFactory, priceItems, {
-      pollingFrequency,
-    });
+    const evmListener = new EvmPriceListener(
+      pythContractFactory,
+      priceItems,
+      logger.child({ module: "EvmPriceListener" }),
+      {
+        pollingFrequency,
+      }
+    );
 
 
-    const gasStation = getCustomGasStation(customGasStation, txSpeed);
+    const gasStation = getCustomGasStation(
+      logger.child({ module: "CustomGasStation" }),
+      customGasStation,
+      txSpeed
+    );
     const evmPusher = new EvmPricePusher(
     const evmPusher = new EvmPricePusher(
       priceServiceConnection,
       priceServiceConnection,
       pythContractFactory,
       pythContractFactory,
+      logger.child({ module: "EvmPricePusher" }),
       overrideGasPriceMultiplier,
       overrideGasPriceMultiplier,
       overrideGasPriceMultiplierCap,
       overrideGasPriceMultiplierCap,
       updateFeeMultiplier,
       updateFeeMultiplier,
@@ -145,6 +162,7 @@ export default {
       pythListener,
       pythListener,
       evmListener,
       evmListener,
       evmPusher,
       evmPusher,
+      logger.child({ module: "Controller" }, { level: controllerLogLevel }),
       { pushingFrequency }
       { pushingFrequency }
     );
     );
 
 

+ 9 - 5
apps/price_pusher/src/evm/custom-gas-station.ts

@@ -6,6 +6,7 @@ import {
   txSpeeds,
   txSpeeds,
   customGasChainIds,
   customGasChainIds,
 } from "../utils";
 } from "../utils";
+import { Logger } from "pino";
 
 
 type chainMethods = Record<CustomGasChainId, () => Promise<string | undefined>>;
 type chainMethods = Record<CustomGasChainId, () => Promise<string | undefined>>;
 
 
@@ -15,7 +16,9 @@ export class CustomGasStation {
   private chainMethods: chainMethods = {
   private chainMethods: chainMethods = {
     137: this.fetchMaticMainnetGasPrice.bind(this),
     137: this.fetchMaticMainnetGasPrice.bind(this),
   };
   };
-  constructor(chain: number, speed: string) {
+  private logger: Logger;
+  constructor(logger: Logger, chain: number, speed: string) {
+    this.logger = logger;
     this.speed = verifyValidOption(speed, txSpeeds);
     this.speed = verifyValidOption(speed, txSpeeds);
     this.chain = verifyValidOption(chain, customGasChainIds);
     this.chain = verifyValidOption(chain, customGasChainIds);
   }
   }
@@ -31,21 +34,22 @@ export class CustomGasStation {
       const gasPrice = jsonRes[this.speed].maxFee;
       const gasPrice = jsonRes[this.speed].maxFee;
       const gweiGasPrice = Web3.utils.toWei(gasPrice.toFixed(2), "Gwei");
       const gweiGasPrice = Web3.utils.toWei(gasPrice.toFixed(2), "Gwei");
       return gweiGasPrice.toString();
       return gweiGasPrice.toString();
-    } catch (e) {
-      console.error(
+    } catch (err) {
+      this.logger.error(
+        err,
         "Failed to fetch gas price from Matic mainnet. Returning undefined"
         "Failed to fetch gas price from Matic mainnet. Returning undefined"
       );
       );
-      console.error(e);
       return undefined;
       return undefined;
     }
     }
   }
   }
 }
 }
 
 
 export function getCustomGasStation(
 export function getCustomGasStation(
+  logger: Logger,
   customGasStation?: number,
   customGasStation?: number,
   txSpeed?: string
   txSpeed?: string
 ) {
 ) {
   if (customGasStation && txSpeed) {
   if (customGasStation && txSpeed) {
-    return new CustomGasStation(customGasStation, txSpeed);
+    return new CustomGasStation(logger, customGasStation, txSpeed);
   }
   }
 }
 }

+ 42 - 24
apps/price_pusher/src/evm/evm.ts

@@ -11,6 +11,7 @@ import AbstractPythAbi from "@pythnetwork/pyth-sdk-solidity/abis/AbstractPyth.js
 import HDWalletProvider from "@truffle/hdwallet-provider";
 import HDWalletProvider from "@truffle/hdwallet-provider";
 import Web3 from "web3";
 import Web3 from "web3";
 import { HttpProvider, WebsocketProvider } from "web3-core";
 import { HttpProvider, WebsocketProvider } from "web3-core";
+import { Logger } from "pino";
 import { isWsEndpoint } from "../utils";
 import { isWsEndpoint } from "../utils";
 import {
 import {
   PriceServiceConnection,
   PriceServiceConnection,
@@ -24,28 +25,33 @@ import { ProviderOrUrl } from "@truffle/hdwallet-provider/dist/constructor/types
 export class EvmPriceListener extends ChainPriceListener {
 export class EvmPriceListener extends ChainPriceListener {
   private pythContractFactory: PythContractFactory;
   private pythContractFactory: PythContractFactory;
   private pythContract: Contract;
   private pythContract: Contract;
+  private logger: Logger;
 
 
   constructor(
   constructor(
     pythContractFactory: PythContractFactory,
     pythContractFactory: PythContractFactory,
     priceItems: PriceItem[],
     priceItems: PriceItem[],
+    logger: Logger,
     config: {
     config: {
       pollingFrequency: DurationInSeconds;
       pollingFrequency: DurationInSeconds;
     }
     }
   ) {
   ) {
-    super("Evm", config.pollingFrequency, priceItems);
+    super(config.pollingFrequency, priceItems);
 
 
     this.pythContractFactory = pythContractFactory;
     this.pythContractFactory = pythContractFactory;
     this.pythContract = this.pythContractFactory.createPythContract();
     this.pythContract = this.pythContractFactory.createPythContract();
+    this.logger = logger;
   }
   }
 
 
   // This method should be awaited on and once it finishes it has the latest value
   // This method should be awaited on and once it finishes it has the latest value
   // for the given price feeds (if they exist).
   // for the given price feeds (if they exist).
   async start() {
   async start() {
     if (this.pythContractFactory.hasWebsocketProvider()) {
     if (this.pythContractFactory.hasWebsocketProvider()) {
-      console.log("Subscribing to the target network pyth contract events...");
+      this.logger.info(
+        "Subscribing to the target network pyth contract events..."
+      );
       this.startSubscription();
       this.startSubscription();
     } else {
     } else {
-      console.log(
+      this.logger.info(
         "The target network RPC endpoint is not Websocket. " +
         "The target network RPC endpoint is not Websocket. " +
           "Listening for updates only via polling...."
           "Listening for updates only via polling...."
       );
       );
@@ -71,12 +77,15 @@ export class EvmPriceListener extends ChainPriceListener {
 
 
   private onPriceFeedUpdate(err: Error | null, event: EventData) {
   private onPriceFeedUpdate(err: Error | null, event: EventData) {
     if (err !== null) {
     if (err !== null) {
-      console.error("PriceFeedUpdate EventEmitter received an error..");
+      this.logger.error(
+        err,
+        "PriceFeedUpdate EventEmitter received an error.."
+      );
       throw err;
       throw err;
     }
     }
 
 
     const priceId = removeLeading0x(event.returnValues.id);
     const priceId = removeLeading0x(event.returnValues.id);
-    console.log(
+    this.logger.debug(
       `Received a new Evm PriceFeedUpdate event for price feed ${this.priceIdToAlias.get(
       `Received a new Evm PriceFeedUpdate event for price feed ${this.priceIdToAlias.get(
         priceId
         priceId
       )} (${priceId}).`
       )} (${priceId}).`
@@ -99,13 +108,12 @@ export class EvmPriceListener extends ChainPriceListener {
       priceRaw = await this.pythContract.methods
       priceRaw = await this.pythContract.methods
         .getPriceUnsafe(addLeading0x(priceId))
         .getPriceUnsafe(addLeading0x(priceId))
         .call();
         .call();
-    } catch (e) {
-      console.error(`Polling on-chain price for ${priceId} failed. Error:`);
-      console.error(e);
+    } catch (err) {
+      this.logger.error(err, `Polling on-chain price for ${priceId} failed.`);
       return undefined;
       return undefined;
     }
     }
 
 
-    console.log(
+    this.logger.debug(
       `Polled an EVM on chain price for feed ${this.priceIdToAlias.get(
       `Polled an EVM on chain price for feed ${this.priceIdToAlias.get(
         priceId
         priceId
       )} (${priceId}).`
       )} (${priceId}).`
@@ -129,6 +137,7 @@ export class EvmPricePusher implements IPricePusher {
   constructor(
   constructor(
     private connection: PriceServiceConnection,
     private connection: PriceServiceConnection,
     pythContractFactory: PythContractFactory,
     pythContractFactory: PythContractFactory,
+    private logger: Logger,
     private overrideGasPriceMultiplier: number,
     private overrideGasPriceMultiplier: number,
     private overrideGasPriceMultiplierCap: number,
     private overrideGasPriceMultiplierCap: number,
     private updateFeeMultiplier: number,
     private updateFeeMultiplier: number,
@@ -163,8 +172,6 @@ export class EvmPricePusher implements IPricePusher {
       priceIdsWith0x
       priceIdsWith0x
     );
     );
 
 
-    console.log("Pushing ", priceIdsWith0x);
-
     let updateFee;
     let updateFee;
 
 
     try {
     try {
@@ -172,10 +179,11 @@ export class EvmPricePusher implements IPricePusher {
         .getUpdateFee(priceFeedUpdateData)
         .getUpdateFee(priceFeedUpdateData)
         .call();
         .call();
       updateFee = Number(updateFee) * (this.updateFeeMultiplier || 1);
       updateFee = Number(updateFee) * (this.updateFeeMultiplier || 1);
-      console.log(`Update fee: ${updateFee}`);
+      this.logger.debug(`Update fee: ${updateFee}`);
     } catch (e: any) {
     } catch (e: any) {
-      console.error(
-        "An unidentified error has occured when getting the update fee:"
+      this.logger.error(
+        e,
+        "An unidentified error has occured when getting the update fee."
       );
       );
       throw e;
       throw e;
     }
     }
@@ -213,7 +221,7 @@ export class EvmPricePusher implements IPricePusher {
 
 
     const txNonce = lastExecutedNonce + 1;
     const txNonce = lastExecutedNonce + 1;
 
 
-    console.log(`Using gas price: ${gasPrice} and nonce: ${txNonce}`);
+    this.logger.debug(`Using gas price: ${gasPrice} and nonce: ${txNonce}`);
 
 
     this.pythContract.methods
     this.pythContract.methods
       .updatePriceFeedsIfNecessary(
       .updatePriceFeedsIfNecessary(
@@ -228,7 +236,7 @@ export class EvmPricePusher implements IPricePusher {
         gasLimit: this.gasLimit,
         gasLimit: this.gasLimit,
       })
       })
       .on("transactionHash", (hash: string) => {
       .on("transactionHash", (hash: string) => {
-        console.log(`Successful. Tx hash: ${hash}`);
+        this.logger.info({ hash }, "Price update successful");
       })
       })
       .on("error", (err: Error, receipt?: TransactionReceipt) => {
       .on("error", (err: Error, receipt?: TransactionReceipt) => {
         if (err.message.includes("revert")) {
         if (err.message.includes("revert")) {
@@ -236,7 +244,8 @@ export class EvmPricePusher implements IPricePusher {
           // doesn't return any information why the call has reverted. Assuming that
           // doesn't return any information why the call has reverted. Assuming that
           // the update data is valid there is no possible rejection cause other than
           // the update data is valid there is no possible rejection cause other than
           // the target chain price being already updated.
           // the target chain price being already updated.
-          console.log(
+          this.logger.info(
+            { err, receipt },
             "Execution reverted. With high probability, the target chain price " +
             "Execution reverted. With high probability, the target chain price " +
               "has already updated, Skipping this push."
               "has already updated, Skipping this push."
           );
           );
@@ -248,7 +257,8 @@ export class EvmPricePusher implements IPricePusher {
           err.message.includes("nonce too low") ||
           err.message.includes("nonce too low") ||
           err.message.includes("invalid nonce")
           err.message.includes("invalid nonce")
         ) {
         ) {
-          console.log(
+          this.logger.info(
+            { err, receipt },
             "The nonce is incorrect (are multiple users using this account?). Skipping this push."
             "The nonce is incorrect (are multiple users using this account?). Skipping this push."
           );
           );
           return;
           return;
@@ -259,7 +269,8 @@ export class EvmPricePusher implements IPricePusher {
           // LastPushAttempt was stored with the class
           // LastPushAttempt was stored with the class
           // Next time the update will be executing, it will check the last attempt
           // Next time the update will be executing, it will check the last attempt
           // and increase the gas price accordingly.
           // and increase the gas price accordingly.
-          console.log(
+          this.logger.info(
+            { err, receipt },
             "The transaction failed with error: max fee per gas less than block base fee "
             "The transaction failed with error: max fee per gas less than block base fee "
           );
           );
           return;
           return;
@@ -268,12 +279,16 @@ export class EvmPricePusher implements IPricePusher {
         if (
         if (
           err.message.includes("sender doesn't have enough funds to send tx.")
           err.message.includes("sender doesn't have enough funds to send tx.")
         ) {
         ) {
-          console.error("Payer is out of balance, please top it up.");
+          this.logger.error(
+            { err, receipt },
+            "Payer is out of balance, please top it up."
+          );
           throw err;
           throw err;
         }
         }
 
 
         if (err.message.includes("transaction underpriced")) {
         if (err.message.includes("transaction underpriced")) {
-          console.error(
+          this.logger.error(
+            { err, receipt },
             "The gas price of the transaction is too low. Skipping this push. " +
             "The gas price of the transaction is too low. Skipping this push. " +
               "You might want to use a custom gas station or increase the override gas price " +
               "You might want to use a custom gas station or increase the override gas price " +
               "multiplier to increase the likelihood of the transaction landing on-chain."
               "multiplier to increase the likelihood of the transaction landing on-chain."
@@ -282,14 +297,17 @@ export class EvmPricePusher implements IPricePusher {
         }
         }
 
 
         if (err.message.includes("could not replace existing tx")) {
         if (err.message.includes("could not replace existing tx")) {
-          console.log(
+          this.logger.error(
+            { err, receipt },
             "A transaction with the same nonce has been mined and this one is no longer needed."
             "A transaction with the same nonce has been mined and this one is no longer needed."
           );
           );
           return;
           return;
         }
         }
 
 
-        console.error("An unidentified error has occured:");
-        console.error(receipt);
+        this.logger.error(
+          { err, receipt },
+          "An unidentified error has occured."
+        );
         throw err;
         throw err;
       });
       });
 
 

+ 18 - 9
apps/price_pusher/src/injective/command.ts

@@ -7,6 +7,7 @@ import { PythPriceListener } from "../pyth-price-listener";
 import { Controller } from "../controller";
 import { Controller } from "../controller";
 import { Options } from "yargs";
 import { Options } from "yargs";
 import { getNetworkInfo } from "@injectivelabs/networks";
 import { getNetworkInfo } from "@injectivelabs/networks";
+import pino from "pino";
 
 
 export default {
 export default {
   command: "injective",
   command: "injective",
@@ -35,6 +36,9 @@ export default {
     ...options.pythContractAddress,
     ...options.pythContractAddress,
     ...options.pollingFrequency,
     ...options.pollingFrequency,
     ...options.pushingFrequency,
     ...options.pushingFrequency,
+    ...options.logLevel,
+    ...options.priceServiceConnectionLogLevel,
+    ...options.controllerLogLevel,
   },
   },
   handler: function (argv: any) {
   handler: function (argv: any) {
     // FIXME: type checks for this
     // FIXME: type checks for this
@@ -48,8 +52,13 @@ export default {
       pushingFrequency,
       pushingFrequency,
       pollingFrequency,
       pollingFrequency,
       network,
       network,
+      logLevel,
+      priceServiceConnectionLogLevel,
+      controllerLogLevel,
     } = argv;
     } = argv;
 
 
+    const logger = pino({ level: logLevel });
+
     if (network !== "testnet" && network !== "mainnet") {
     if (network !== "testnet" && network !== "mainnet") {
       throw new Error("Please specify network. One of [testnet, mainnet]");
       throw new Error("Please specify network. One of [testnet, mainnet]");
     }
     }
@@ -58,14 +67,10 @@ export default {
     const priceServiceConnection = new PriceServiceConnection(
     const priceServiceConnection = new PriceServiceConnection(
       priceServiceEndpoint,
       priceServiceEndpoint,
       {
       {
-        logger: {
-          // Log only warnings and errors from the price service client
-          info: () => undefined,
-          warn: console.warn,
-          error: console.error,
-          debug: () => undefined,
-          trace: () => undefined,
-        },
+        logger: logger.child(
+          { module: "PriceServiceConnection" },
+          { level: priceServiceConnectionLogLevel }
+        ),
       }
       }
     );
     );
     const mnemonic = fs.readFileSync(mnemonicFile, "utf-8").trim();
     const mnemonic = fs.readFileSync(mnemonicFile, "utf-8").trim();
@@ -74,13 +79,15 @@ export default {
 
 
     const pythListener = new PythPriceListener(
     const pythListener = new PythPriceListener(
       priceServiceConnection,
       priceServiceConnection,
-      priceItems
+      priceItems,
+      logger.child({ module: "PythPriceListener" })
     );
     );
 
 
     const injectiveListener = new InjectivePriceListener(
     const injectiveListener = new InjectivePriceListener(
       pythContractAddress,
       pythContractAddress,
       grpcEndpoint,
       grpcEndpoint,
       priceItems,
       priceItems,
+      logger.child({ module: "InjectivePriceListener" }),
       {
       {
         pollingFrequency,
         pollingFrequency,
       }
       }
@@ -89,6 +96,7 @@ export default {
       priceServiceConnection,
       priceServiceConnection,
       pythContractAddress,
       pythContractAddress,
       grpcEndpoint,
       grpcEndpoint,
+      logger.child({ module: "InjectivePricePusher" }),
       mnemonic,
       mnemonic,
       {
       {
         chainId: getNetworkInfo(network).chainId,
         chainId: getNetworkInfo(network).chainId,
@@ -101,6 +109,7 @@ export default {
       pythListener,
       pythListener,
       injectiveListener,
       injectiveListener,
       injectivePusher,
       injectivePusher,
+      logger.child({ module: "Controller" }, { level: controllerLogLevel }),
       { pushingFrequency }
       { pushingFrequency }
     );
     );
 
 

+ 19 - 20
apps/price_pusher/src/injective/injective.ts

@@ -19,6 +19,7 @@ import {
   TxResponse,
   TxResponse,
   createTransactionFromMsg,
   createTransactionFromMsg,
 } from "@injectivelabs/sdk-ts";
 } from "@injectivelabs/sdk-ts";
+import { Logger } from "pino";
 import { Account } from "@injectivelabs/sdk-ts/dist/cjs/client/chain/types/auth";
 import { Account } from "@injectivelabs/sdk-ts/dist/cjs/client/chain/types/auth";
 
 
 const DEFAULT_GAS_PRICE = 500000000;
 const DEFAULT_GAS_PRICE = 500000000;
@@ -46,11 +47,12 @@ export class InjectivePriceListener extends ChainPriceListener {
     private pythContractAddress: string,
     private pythContractAddress: string,
     private grpcEndpoint: string,
     private grpcEndpoint: string,
     priceItems: PriceItem[],
     priceItems: PriceItem[],
+    private logger: Logger,
     config: {
     config: {
       pollingFrequency: DurationInSeconds;
       pollingFrequency: DurationInSeconds;
     }
     }
   ) {
   ) {
-    super("Injective", config.pollingFrequency, priceItems);
+    super(config.pollingFrequency, priceItems);
   }
   }
 
 
   async getOnChainPriceInfo(
   async getOnChainPriceInfo(
@@ -66,13 +68,12 @@ export class InjectivePriceListener extends ChainPriceListener {
 
 
       const json = Buffer.from(data).toString();
       const json = Buffer.from(data).toString();
       priceQueryResponse = JSON.parse(json);
       priceQueryResponse = JSON.parse(json);
-    } catch (e) {
-      console.error(`Polling on-chain price for ${priceId} failed. Error:`);
-      console.error(e);
+    } catch (err) {
+      this.logger.error(err, `Polling on-chain price for ${priceId} failed.`);
       return undefined;
       return undefined;
     }
     }
 
 
-    console.log(
+    this.logger.debug(
       `Polled an Injective on chain price for feed ${this.priceIdToAlias.get(
       `Polled an Injective on chain price for feed ${this.priceIdToAlias.get(
         priceId
         priceId
       )} (${priceId}).`
       )} (${priceId}).`
@@ -100,6 +101,7 @@ export class InjectivePricePusher implements IPricePusher {
     private priceServiceConnection: PriceServiceConnection,
     private priceServiceConnection: PriceServiceConnection,
     private pythContractAddress: string,
     private pythContractAddress: string,
     private grpcEndpoint: string,
     private grpcEndpoint: string,
+    private logger: Logger,
     mnemonic: string,
     mnemonic: string,
     chainConfig?: Partial<InjectiveConfig>
     chainConfig?: Partial<InjectiveConfig>
   ) {
   ) {
@@ -207,9 +209,8 @@ export class InjectivePricePusher implements IPricePusher {
     try {
     try {
       // get the latest VAAs for updatePriceFeed and then push them
       // get the latest VAAs for updatePriceFeed and then push them
       priceFeedUpdateObject = await this.getPriceFeedUpdateObject(priceIds);
       priceFeedUpdateObject = await this.getPriceFeedUpdateObject(priceIds);
-    } catch (e) {
-      console.error("Error fetching the latest vaas to push");
-      console.error(e);
+    } catch (err) {
+      this.logger.error(err, "Error fetching the latest vaas to push");
       return;
       return;
     }
     }
 
 
@@ -229,9 +230,8 @@ export class InjectivePricePusher implements IPricePusher {
 
 
       const json = Buffer.from(data).toString();
       const json = Buffer.from(data).toString();
       updateFeeQueryResponse = JSON.parse(json);
       updateFeeQueryResponse = JSON.parse(json);
-    } catch (e) {
-      console.error("Error fetching update fee");
-      console.error(e);
+    } catch (err) {
+      this.logger.error(err, "Error fetching update fee");
       return;
       return;
     }
     }
 
 
@@ -244,22 +244,21 @@ export class InjectivePricePusher implements IPricePusher {
       });
       });
 
 
       const rs = await this.signAndBroadcastMsg(executeMsg);
       const rs = await this.signAndBroadcastMsg(executeMsg);
-      console.log("Succesfully broadcasted txHash:", rs.txHash);
-    } catch (e: any) {
-      if (e.message.match(/account inj[a-zA-Z0-9]+ not found/) !== null) {
-        console.error(e);
+      this.logger.info({ hash: rs.txHash }, "Succesfully broadcasted txHash");
+    } catch (err: any) {
+      if (err.message.match(/account inj[a-zA-Z0-9]+ not found/) !== null) {
+        this.logger.error(err, "Account not found");
         throw new Error("Please check the mnemonic");
         throw new Error("Please check the mnemonic");
       }
       }
 
 
       if (
       if (
-        e.message.match(/insufficient/) !== null &&
-        e.message.match(/funds/) !== null
+        err.message.match(/insufficient/) !== null &&
+        err.message.match(/funds/) !== null
       ) {
       ) {
-        console.error(e);
+        this.logger.error(err, "Insufficient funds");
         throw new Error("Insufficient funds");
         throw new Error("Insufficient funds");
       }
       }
-      console.error("Error executing messages");
-      console.log(e);
+      this.logger.error(err, "Error executing messages");
     }
     }
   }
   }
 }
 }

+ 0 - 4
apps/price_pusher/src/interface.ts

@@ -23,7 +23,6 @@ export abstract class ChainPriceListener implements IPriceListener {
   protected priceIdToAlias: Map<HexString, string>;
   protected priceIdToAlias: Map<HexString, string>;
 
 
   constructor(
   constructor(
-    private chain: string,
     private pollingFrequency: DurationInSeconds,
     private pollingFrequency: DurationInSeconds,
     protected priceItems: PriceItem[]
     protected priceItems: PriceItem[]
   ) {
   ) {
@@ -34,9 +33,6 @@ export abstract class ChainPriceListener implements IPriceListener {
   }
   }
 
 
   async start() {
   async start() {
-    console.log(
-      `Polling the prices on ${this.chain} every ${this.pollingFrequency} seconds...`
-    );
     setInterval(this.pollPrices.bind(this), this.pollingFrequency * 1000);
     setInterval(this.pollPrices.bind(this), this.pollingFrequency * 1000);
 
 
     await this.pollPrices();
     await this.pollPrices();

+ 29 - 13
apps/price_pusher/src/near/command.ts

@@ -5,6 +5,7 @@ import { PythPriceListener } from "../pyth-price-listener";
 import { Controller } from "../controller";
 import { Controller } from "../controller";
 import { Options } from "yargs";
 import { Options } from "yargs";
 import { NearAccount, NearPriceListener, NearPricePusher } from "./near";
 import { NearAccount, NearPriceListener, NearPricePusher } from "./near";
+import pino from "pino";
 
 
 export default {
 export default {
   command: "near",
   command: "near",
@@ -36,6 +37,9 @@ export default {
     ...options.pythContractAddress,
     ...options.pythContractAddress,
     ...options.pollingFrequency,
     ...options.pollingFrequency,
     ...options.pushingFrequency,
     ...options.pushingFrequency,
+    ...options.logLevel,
+    ...options.priceServiceConnectionLogLevel,
+    ...options.controllerLogLevel,
   },
   },
   handler: function (argv: any) {
   handler: function (argv: any) {
     // FIXME: type checks for this
     // FIXME: type checks for this
@@ -49,20 +53,21 @@ export default {
       pythContractAddress,
       pythContractAddress,
       pushingFrequency,
       pushingFrequency,
       pollingFrequency,
       pollingFrequency,
+      logLevel,
+      priceServiceConnectionLogLevel,
+      controllerLogLevel,
     } = argv;
     } = argv;
 
 
+    const logger = pino({ level: logLevel });
+
     const priceConfigs = readPriceConfigFile(priceConfigFile);
     const priceConfigs = readPriceConfigFile(priceConfigFile);
     const priceServiceConnection = new PriceServiceConnection(
     const priceServiceConnection = new PriceServiceConnection(
       priceServiceEndpoint,
       priceServiceEndpoint,
       {
       {
-        logger: {
-          // Log only warnings and errors from the price service client
-          info: () => undefined,
-          warn: console.warn,
-          error: console.error,
-          debug: () => undefined,
-          trace: () => undefined,
-        },
+        logger: logger.child(
+          { module: "PriceServiceConnection" },
+          { level: priceServiceConnectionLogLevel }
+        ),
       }
       }
     );
     );
 
 
@@ -70,7 +75,8 @@ export default {
 
 
     const pythListener = new PythPriceListener(
     const pythListener = new PythPriceListener(
       priceServiceConnection,
       priceServiceConnection,
-      priceItems
+      priceItems,
+      logger
     );
     );
 
 
     const nearAccount = new NearAccount(
     const nearAccount = new NearAccount(
@@ -81,17 +87,27 @@ export default {
       pythContractAddress
       pythContractAddress
     );
     );
 
 
-    const nearListener = new NearPriceListener(nearAccount, priceItems, {
-      pollingFrequency,
-    });
+    const nearListener = new NearPriceListener(
+      nearAccount,
+      priceItems,
+      logger.child({ module: "NearPriceListener" }),
+      {
+        pollingFrequency,
+      }
+    );
 
 
-    const nearPusher = new NearPricePusher(nearAccount, priceServiceConnection);
+    const nearPusher = new NearPricePusher(
+      nearAccount,
+      priceServiceConnection,
+      logger.child({ module: "NearPricePusher" })
+    );
 
 
     const controller = new Controller(
     const controller = new Controller(
       priceConfigs,
       priceConfigs,
       pythListener,
       pythListener,
       nearListener,
       nearListener,
       nearPusher,
       nearPusher,
+      logger.child({ module: "Controller" }, { level: controllerLogLevel }),
       { pushingFrequency }
       { pushingFrequency }
     );
     );
 
 

+ 19 - 24
apps/price_pusher/src/near/near.ts

@@ -21,23 +21,25 @@ import {
   FinalExecutionOutcome,
   FinalExecutionOutcome,
 } from "near-api-js/lib/providers/provider";
 } from "near-api-js/lib/providers/provider";
 import { InMemoryKeyStore } from "near-api-js/lib/key_stores";
 import { InMemoryKeyStore } from "near-api-js/lib/key_stores";
+import { Logger } from "pino";
 
 
 export class NearPriceListener extends ChainPriceListener {
 export class NearPriceListener extends ChainPriceListener {
   constructor(
   constructor(
     private account: NearAccount,
     private account: NearAccount,
     priceItems: PriceItem[],
     priceItems: PriceItem[],
+    private logger: Logger,
     config: {
     config: {
       pollingFrequency: DurationInSeconds;
       pollingFrequency: DurationInSeconds;
     }
     }
   ) {
   ) {
-    super("near", config.pollingFrequency, priceItems);
+    super(config.pollingFrequency, priceItems);
   }
   }
 
 
   async getOnChainPriceInfo(priceId: string): Promise<PriceInfo | undefined> {
   async getOnChainPriceInfo(priceId: string): Promise<PriceInfo | undefined> {
     try {
     try {
       const priceRaw = await this.account.getPriceUnsafe(priceId);
       const priceRaw = await this.account.getPriceUnsafe(priceId);
 
 
-      console.log(
+      this.logger.debug(
         `Polled a NEAR on chain price for feed ${this.priceIdToAlias.get(
         `Polled a NEAR on chain price for feed ${this.priceIdToAlias.get(
           priceId
           priceId
         )} (${priceId}) ${JSON.stringify(priceRaw)}.`
         )} (${priceId}) ${JSON.stringify(priceRaw)}.`
@@ -52,9 +54,8 @@ export class NearPriceListener extends ChainPriceListener {
       } else {
       } else {
         return undefined;
         return undefined;
       }
       }
-    } catch (e) {
-      console.error(`Polling on-chain price for ${priceId} failed. Error:`);
-      console.error(e);
+    } catch (err) {
+      this.logger.error(err, `Polling on-chain price for ${priceId} failed.:`);
       return undefined;
       return undefined;
     }
     }
   }
   }
@@ -63,7 +64,8 @@ export class NearPriceListener extends ChainPriceListener {
 export class NearPricePusher implements IPricePusher {
 export class NearPricePusher implements IPricePusher {
   constructor(
   constructor(
     private account: NearAccount,
     private account: NearAccount,
-    private connection: PriceServiceConnection
+    private connection: PriceServiceConnection,
+    private logger: Logger
   ) {}
   ) {}
 
 
   async updatePriceFeed(
   async updatePriceFeed(
@@ -80,20 +82,18 @@ export class NearPricePusher implements IPricePusher {
     let priceFeedUpdateData;
     let priceFeedUpdateData;
     try {
     try {
       priceFeedUpdateData = await this.getPriceFeedsUpdateData(priceIds);
       priceFeedUpdateData = await this.getPriceFeedsUpdateData(priceIds);
-    } catch (e: any) {
-      console.error(new Date(), "getPriceFeedsUpdateData failed:", e);
+    } catch (err: any) {
+      this.logger.error(err, "getPriceFeedsUpdateData failed");
       return;
       return;
     }
     }
 
 
-    console.log("Pushing ", priceIds);
-
     for (const data of priceFeedUpdateData) {
     for (const data of priceFeedUpdateData) {
       let updateFee;
       let updateFee;
       try {
       try {
         updateFee = await this.account.getUpdateFeeEstimate(data);
         updateFee = await this.account.getUpdateFeeEstimate(data);
-        console.log(`Update fee: ${updateFee}`);
-      } catch (e: any) {
-        console.error(new Date(), "getUpdateFeeEstimate failed:", e);
+        this.logger.debug(`Update fee: ${updateFee}`);
+      } catch (err: any) {
+        this.logger.error(err, "getUpdateFeeEstimate failed");
         continue;
         continue;
       }
       }
 
 
@@ -116,20 +116,15 @@ export class NearPricePusher implements IPricePusher {
           true
           true
         );
         );
         if (is_success) {
         if (is_success) {
-          console.log(
-            new Date(),
-            "updatePriceFeeds successful. Tx hash: ",
-            outcome["transaction"]["hash"]
+          this.logger.info(
+            { hash: outcome["transaction"]["hash"] },
+            "updatePriceFeeds successful."
           );
           );
         } else {
         } else {
-          console.error(
-            new Date(),
-            "updatePriceFeeds failed:",
-            JSON.stringify(failureMessages, undefined, 2)
-          );
+          this.logger.error({ failureMessages }, "updatePriceFeeds failed");
         }
         }
-      } catch (e: any) {
-        console.error(new Date(), "updatePriceFeeds failed:", e);
+      } catch (err: any) {
+        this.logger.error(err, "updatePriceFeeds failed");
       }
       }
     }
     }
   }
   }

+ 30 - 0
apps/price_pusher/src/options.ts

@@ -56,3 +56,33 @@ export const mnemonicFile = {
     required: true,
     required: true,
   } as Options,
   } as Options,
 };
 };
+
+export const logLevel = {
+  "log-level": {
+    description: "Log level",
+    type: "string",
+    required: false,
+    default: "info",
+    choices: ["trace", "debug", "info", "warn", "error"],
+  } as Options,
+};
+
+export const priceServiceConnectionLogLevel = {
+  "price-service-connection-log-level": {
+    description: "Log level for the price service connection.",
+    type: "string",
+    required: false,
+    default: "warn",
+    choices: ["trace", "debug", "info", "warn", "error"],
+  } as Options,
+};
+
+export const controllerLogLevel = {
+  "controller-log-level": {
+    description: "Log level for the controller.",
+    type: "string",
+    required: false,
+    default: "info",
+    choices: ["trace", "debug", "info", "warn", "error"],
+  } as Options,
+};

+ 8 - 9
apps/price_pusher/src/price-config.ts

@@ -2,6 +2,7 @@ import { HexString } from "@pythnetwork/price-service-client";
 import Joi from "joi";
 import Joi from "joi";
 import YAML from "yaml";
 import YAML from "yaml";
 import fs from "fs";
 import fs from "fs";
+import { Logger } from "pino";
 import { DurationInSeconds, PctNumber, removeLeading0x } from "./utils";
 import { DurationInSeconds, PctNumber, removeLeading0x } from "./utils";
 import { PriceInfo } from "./interface";
 import { PriceInfo } from "./interface";
 
 
@@ -90,7 +91,8 @@ export enum UpdateCondition {
 export function shouldUpdate(
 export function shouldUpdate(
   priceConfig: PriceConfig,
   priceConfig: PriceConfig,
   sourceLatestPrice: PriceInfo | undefined,
   sourceLatestPrice: PriceInfo | undefined,
-  targetLatestPrice: PriceInfo | undefined
+  targetLatestPrice: PriceInfo | undefined,
+  logger: Logger
 ): UpdateCondition {
 ): UpdateCondition {
   const priceId = priceConfig.id;
   const priceId = priceConfig.id;
 
 
@@ -101,7 +103,7 @@ export function shouldUpdate(
 
 
   // It means that price never existed there. So we should push the latest price feed.
   // It means that price never existed there. So we should push the latest price feed.
   if (targetLatestPrice === undefined) {
   if (targetLatestPrice === undefined) {
-    console.log(
+    logger.info(
       `${priceConfig.alias} (${priceId}) is not available on the target network. Pushing the price.`
       `${priceConfig.alias} (${priceId}) is not available on the target network. Pushing the price.`
     );
     );
     return UpdateCondition.YES;
     return UpdateCondition.YES;
@@ -125,13 +127,10 @@ export function shouldUpdate(
     (Number(sourceLatestPrice.conf) / Number(sourceLatestPrice.price)) * 100
     (Number(sourceLatestPrice.conf) / Number(sourceLatestPrice.price)) * 100
   );
   );
 
 
-  console.log(`Analyzing price ${priceConfig.alias} (${priceId})`);
-
-  console.log("Source latest price: ", sourceLatestPrice);
-  console.log("Target latest price: ", targetLatestPrice);
-
-  console.log(
-    `Time difference: ${timeDifference} (< ${priceConfig.timeDifference}? / early: < ${priceConfig.earlyUpdateTimeDifference}) OR ` +
+  logger.info(
+    { sourcePrice: sourceLatestPrice, targetPrice: targetLatestPrice },
+    `Analyzing price ${priceConfig.alias} (${priceId}). ` +
+      `Time difference: ${timeDifference} (< ${priceConfig.timeDifference}? / early: < ${priceConfig.earlyUpdateTimeDifference}) OR ` +
       `Price deviation: ${priceDeviationPct.toFixed(5)}% (< ${
       `Price deviation: ${priceDeviationPct.toFixed(5)}% (< ${
         priceConfig.priceDeviation
         priceConfig.priceDeviation
       }%? / early: < ${priceConfig.earlyUpdatePriceDeviation}%?) OR ` +
       }%? / early: < ${priceConfig.earlyUpdatePriceDeviation}%?) OR ` +

+ 9 - 2
apps/price_pusher/src/pyth-price-listener.ts

@@ -4,20 +4,27 @@ import {
   PriceServiceConnection,
   PriceServiceConnection,
 } from "@pythnetwork/price-service-client";
 } from "@pythnetwork/price-service-client";
 import { PriceInfo, IPriceListener, PriceItem } from "./interface";
 import { PriceInfo, IPriceListener, PriceItem } from "./interface";
+import { Logger } from "pino";
 
 
 export class PythPriceListener implements IPriceListener {
 export class PythPriceListener implements IPriceListener {
   private connection: PriceServiceConnection;
   private connection: PriceServiceConnection;
   private priceIds: HexString[];
   private priceIds: HexString[];
   private priceIdToAlias: Map<HexString, string>;
   private priceIdToAlias: Map<HexString, string>;
   private latestPriceInfo: Map<HexString, PriceInfo>;
   private latestPriceInfo: Map<HexString, PriceInfo>;
+  private logger: Logger;
 
 
-  constructor(connection: PriceServiceConnection, priceItems: PriceItem[]) {
+  constructor(
+    connection: PriceServiceConnection,
+    priceItems: PriceItem[],
+    logger: Logger
+  ) {
     this.connection = connection;
     this.connection = connection;
     this.priceIds = priceItems.map((priceItem) => priceItem.id);
     this.priceIds = priceItems.map((priceItem) => priceItem.id);
     this.priceIdToAlias = new Map(
     this.priceIdToAlias = new Map(
       priceItems.map((priceItem) => [priceItem.id, priceItem.alias])
       priceItems.map((priceItem) => [priceItem.id, priceItem.alias])
     );
     );
     this.latestPriceInfo = new Map();
     this.latestPriceInfo = new Map();
+    this.logger = logger;
   }
   }
 
 
   // This method should be awaited on and once it finishes it has the latest value
   // This method should be awaited on and once it finishes it has the latest value
@@ -42,7 +49,7 @@ export class PythPriceListener implements IPriceListener {
   }
   }
 
 
   private onNewPriceFeed(priceFeed: PriceFeed) {
   private onNewPriceFeed(priceFeed: PriceFeed) {
-    console.log(
+    this.logger.debug(
       `Received new price feed update from Pyth price service: ${this.priceIdToAlias.get(
       `Received new price feed update from Pyth price service: ${this.priceIdToAlias.get(
         priceFeed.id
         priceFeed.id
       )} ${priceFeed.id}`
       )} ${priceFeed.id}`

+ 24 - 13
apps/price_pusher/src/solana/command.ts

@@ -18,6 +18,8 @@ import {
   SearcherClient,
   SearcherClient,
   searcherClient,
   searcherClient,
 } from "jito-ts/dist/sdk/block-engine/searcher";
 } from "jito-ts/dist/sdk/block-engine/searcher";
+import pino from "pino";
+import { Logger } from "pino";
 
 
 export default {
 export default {
   command: "solana",
   command: "solana",
@@ -69,6 +71,9 @@ export default {
     ...options.pythContractAddress,
     ...options.pythContractAddress,
     ...options.pollingFrequency,
     ...options.pollingFrequency,
     ...options.pushingFrequency,
     ...options.pushingFrequency,
+    ...options.logLevel,
+    ...options.priceServiceConnectionLogLevel,
+    ...options.controllerLogLevel,
   },
   },
   handler: function (argv: any) {
   handler: function (argv: any) {
     const {
     const {
@@ -85,21 +90,22 @@ export default {
       jitoKeypairFile,
       jitoKeypairFile,
       jitoTipLamports,
       jitoTipLamports,
       jitoBundleSize,
       jitoBundleSize,
+      logLevel,
+      priceServiceConnectionLogLevel,
+      controllerLogLevel,
     } = argv;
     } = argv;
 
 
+    const logger = pino({ level: logLevel });
+
     const priceConfigs = readPriceConfigFile(priceConfigFile);
     const priceConfigs = readPriceConfigFile(priceConfigFile);
 
 
     const priceServiceConnection = new PriceServiceConnection(
     const priceServiceConnection = new PriceServiceConnection(
       priceServiceEndpoint,
       priceServiceEndpoint,
       {
       {
-        logger: {
-          // Log only warnings and errors from the price service client
-          info: () => undefined,
-          warn: console.warn,
-          error: console.error,
-          debug: () => undefined,
-          trace: () => undefined,
-        },
+        logger: logger.child(
+          { module: "PriceServiceConnection" },
+          { level: priceServiceConnectionLogLevel }
+        ),
       }
       }
     );
     );
 
 
@@ -107,7 +113,8 @@ export default {
 
 
     const pythListener = new PythPriceListener(
     const pythListener = new PythPriceListener(
       priceServiceConnection,
       priceServiceConnection,
-      priceItems
+      priceItems,
+      logger.child({ module: "PythPriceListener" })
     );
     );
 
 
     const wallet = new NodeWallet(
     const wallet = new NodeWallet(
@@ -132,17 +139,19 @@ export default {
       solanaPricePusher = new SolanaPricePusherJito(
       solanaPricePusher = new SolanaPricePusherJito(
         pythSolanaReceiver,
         pythSolanaReceiver,
         priceServiceConnection,
         priceServiceConnection,
+        logger.child({ module: "SolanaPricePusherJito" }),
         shardId,
         shardId,
         jitoTipLamports,
         jitoTipLamports,
         jitoClient,
         jitoClient,
         jitoBundleSize
         jitoBundleSize
       );
       );
 
 
-      onBundleResult(jitoClient);
+      onBundleResult(jitoClient, logger.child({ module: "JitoClient" }));
     } else {
     } else {
       solanaPricePusher = new SolanaPricePusher(
       solanaPricePusher = new SolanaPricePusher(
         pythSolanaReceiver,
         pythSolanaReceiver,
         priceServiceConnection,
         priceServiceConnection,
+        logger.child({ module: "SolanaPricePusher" }),
         shardId,
         shardId,
         computeUnitPriceMicroLamports
         computeUnitPriceMicroLamports
       );
       );
@@ -152,6 +161,7 @@ export default {
       pythSolanaReceiver,
       pythSolanaReceiver,
       shardId,
       shardId,
       priceItems,
       priceItems,
+      logger.child({ module: "SolanaPriceListener" }),
       { pollingFrequency }
       { pollingFrequency }
     );
     );
 
 
@@ -160,6 +170,7 @@ export default {
       pythListener,
       pythListener,
       solanaPriceListener,
       solanaPriceListener,
       solanaPricePusher,
       solanaPricePusher,
+      logger.child({ module: "Controller" }, { level: controllerLogLevel }),
       { pushingFrequency }
       { pushingFrequency }
     );
     );
 
 
@@ -167,11 +178,11 @@ export default {
   },
   },
 };
 };
 
 
-export const onBundleResult = (c: SearcherClient) => {
+export const onBundleResult = (c: SearcherClient, logger: Logger) => {
   c.onBundleResult(
   c.onBundleResult(
     () => undefined,
     () => undefined,
-    (e) => {
-      console.log("Error in bundle result: ", e);
+    (err) => {
+      logger.error(err, "Error in bundle result");
     }
     }
   );
   );
 };
 };

+ 16 - 13
apps/price_pusher/src/solana/solana.ts

@@ -13,17 +13,19 @@ import {
 } from "@pythnetwork/solana-utils";
 } from "@pythnetwork/solana-utils";
 import { SearcherClient } from "jito-ts/dist/sdk/block-engine/searcher";
 import { SearcherClient } from "jito-ts/dist/sdk/block-engine/searcher";
 import { sliceAccumulatorUpdateData } from "@pythnetwork/price-service-sdk";
 import { sliceAccumulatorUpdateData } from "@pythnetwork/price-service-sdk";
+import { Logger } from "pino";
 
 
 export class SolanaPriceListener extends ChainPriceListener {
 export class SolanaPriceListener extends ChainPriceListener {
   constructor(
   constructor(
     private pythSolanaReceiver: PythSolanaReceiver,
     private pythSolanaReceiver: PythSolanaReceiver,
     private shardId: number,
     private shardId: number,
     priceItems: PriceItem[],
     priceItems: PriceItem[],
+    private logger: Logger,
     config: {
     config: {
       pollingFrequency: DurationInSeconds;
       pollingFrequency: DurationInSeconds;
     }
     }
   ) {
   ) {
-    super("solana", config.pollingFrequency, priceItems);
+    super(config.pollingFrequency, priceItems);
   }
   }
 
 
   async getOnChainPriceInfo(priceId: string): Promise<PriceInfo | undefined> {
   async getOnChainPriceInfo(priceId: string): Promise<PriceInfo | undefined> {
@@ -33,7 +35,7 @@ export class SolanaPriceListener extends ChainPriceListener {
           this.shardId,
           this.shardId,
           Buffer.from(priceId, "hex")
           Buffer.from(priceId, "hex")
         );
         );
-      console.log(
+      this.logger.debug(
         `Polled a Solana on chain price for feed ${this.priceIdToAlias.get(
         `Polled a Solana on chain price for feed ${this.priceIdToAlias.get(
           priceId
           priceId
         )} (${priceId}).`
         )} (${priceId}).`
@@ -47,9 +49,8 @@ export class SolanaPriceListener extends ChainPriceListener {
       } else {
       } else {
         return undefined;
         return undefined;
       }
       }
-    } catch (e) {
-      console.error(`Polling on-chain price for ${priceId} failed. Error:`);
-      console.error(e);
+    } catch (err) {
+      this.logger.error({ err, priceId }, `Polling on-chain price failed.`);
       return undefined;
       return undefined;
     }
     }
   }
   }
@@ -59,6 +60,7 @@ export class SolanaPricePusher implements IPricePusher {
   constructor(
   constructor(
     private pythSolanaReceiver: PythSolanaReceiver,
     private pythSolanaReceiver: PythSolanaReceiver,
     private priceServiceConnection: PriceServiceConnection,
     private priceServiceConnection: PriceServiceConnection,
+    private logger: Logger,
     private shardId: number,
     private shardId: number,
     private computeUnitPriceMicroLamports: number
     private computeUnitPriceMicroLamports: number
   ) {}
   ) {}
@@ -77,8 +79,8 @@ export class SolanaPricePusher implements IPricePusher {
       priceFeedUpdateData = await this.priceServiceConnection.getLatestVaas(
       priceFeedUpdateData = await this.priceServiceConnection.getLatestVaas(
         priceIds
         priceIds
       );
       );
-    } catch (e: any) {
-      console.error(new Date(), "getPriceFeedsUpdateData failed:", e);
+    } catch (err: any) {
+      this.logger.error(err, "getPriceFeedsUpdateData failed:");
       return;
       return;
     }
     }
 
 
@@ -96,14 +98,14 @@ export class SolanaPricePusher implements IPricePusher {
     });
     });
 
 
     try {
     try {
-      await sendTransactions(
+      const signatures = await sendTransactions(
         transactions,
         transactions,
         this.pythSolanaReceiver.connection,
         this.pythSolanaReceiver.connection,
         this.pythSolanaReceiver.wallet
         this.pythSolanaReceiver.wallet
       );
       );
-      console.log(new Date(), "updatePriceFeed successful");
-    } catch (e: any) {
-      console.error(new Date(), "updatePriceFeed failed", e);
+      this.logger.info({ signatures }, "updatePriceFeed successful");
+    } catch (err: any) {
+      this.logger.error(err, "updatePriceFeed failed");
       return;
       return;
     }
     }
   }
   }
@@ -115,6 +117,7 @@ export class SolanaPricePusherJito implements IPricePusher {
   constructor(
   constructor(
     private pythSolanaReceiver: PythSolanaReceiver,
     private pythSolanaReceiver: PythSolanaReceiver,
     private priceServiceConnection: PriceServiceConnection,
     private priceServiceConnection: PriceServiceConnection,
+    private logger: Logger,
     private shardId: number,
     private shardId: number,
     private jitoTipLamports: number,
     private jitoTipLamports: number,
     private searcherClient: SearcherClient,
     private searcherClient: SearcherClient,
@@ -131,8 +134,8 @@ export class SolanaPricePusherJito implements IPricePusher {
       priceFeedUpdateData = await this.priceServiceConnection.getLatestVaas(
       priceFeedUpdateData = await this.priceServiceConnection.getLatestVaas(
         priceIds
         priceIds
       );
       );
-    } catch (e: any) {
-      console.error(new Date(), "getPriceFeedsUpdateData failed:", e);
+    } catch (err: any) {
+      this.logger.error(err, "getPriceFeedsUpdateData failed");
       return;
       return;
     }
     }
 
 

+ 19 - 10
apps/price_pusher/src/sui/command.ts

@@ -7,6 +7,7 @@ import { Controller } from "../controller";
 import { Options } from "yargs";
 import { Options } from "yargs";
 import { SuiPriceListener, SuiPricePusher } from "./sui";
 import { SuiPriceListener, SuiPricePusher } from "./sui";
 import { Ed25519Keypair } from "@mysten/sui.js/keypairs/ed25519";
 import { Ed25519Keypair } from "@mysten/sui.js/keypairs/ed25519";
+import pino from "pino";
 
 
 export default {
 export default {
   command: "sui",
   command: "sui",
@@ -68,6 +69,9 @@ export default {
     ...options.mnemonicFile,
     ...options.mnemonicFile,
     ...options.pollingFrequency,
     ...options.pollingFrequency,
     ...options.pushingFrequency,
     ...options.pushingFrequency,
+    ...options.logLevel,
+    ...options.priceServiceConnectionLogLevel,
+    ...options.controllerLogLevel,
   },
   },
   handler: async function (argv: any) {
   handler: async function (argv: any) {
     const {
     const {
@@ -83,20 +87,21 @@ export default {
       ignoreGasObjects,
       ignoreGasObjects,
       gasBudget,
       gasBudget,
       accountIndex,
       accountIndex,
+      logLevel,
+      priceServiceConnectionLogLevel,
+      controllerLogLevel,
     } = argv;
     } = argv;
 
 
+    const logger = pino({ level: logLevel });
+
     const priceConfigs = readPriceConfigFile(priceConfigFile);
     const priceConfigs = readPriceConfigFile(priceConfigFile);
     const priceServiceConnection = new PriceServiceConnection(
     const priceServiceConnection = new PriceServiceConnection(
       priceServiceEndpoint,
       priceServiceEndpoint,
       {
       {
-        logger: {
-          // Log only warnings and errors from the price service client
-          info: () => undefined,
-          warn: console.warn,
-          error: console.error,
-          debug: () => undefined,
-          trace: () => undefined,
-        },
+        logger: logger.child(
+          { module: "PriceServiceConnection" },
+          { level: priceServiceConnectionLogLevel }
+        ),
         priceFeedRequestConfig: {
         priceFeedRequestConfig: {
           binary: true,
           binary: true,
         },
         },
@@ -107,7 +112,7 @@ export default {
       mnemonic,
       mnemonic,
       `m/44'/784'/${accountIndex}'/0'/0'`
       `m/44'/784'/${accountIndex}'/0'/0'`
     );
     );
-    console.log(
+    logger.info(
       `Pushing updates from wallet address: ${keypair
       `Pushing updates from wallet address: ${keypair
         .getPublicKey()
         .getPublicKey()
         .toSuiAddress()}`
         .toSuiAddress()}`
@@ -117,7 +122,8 @@ export default {
 
 
     const pythListener = new PythPriceListener(
     const pythListener = new PythPriceListener(
       priceServiceConnection,
       priceServiceConnection,
-      priceItems
+      priceItems,
+      logger.child({ module: "PythPriceListener" })
     );
     );
 
 
     const suiListener = new SuiPriceListener(
     const suiListener = new SuiPriceListener(
@@ -125,10 +131,12 @@ export default {
       wormholeStateId,
       wormholeStateId,
       endpoint,
       endpoint,
       priceItems,
       priceItems,
+      logger.child({ module: "SuiPriceListener" }),
       { pollingFrequency }
       { pollingFrequency }
     );
     );
     const suiPusher = await SuiPricePusher.createWithAutomaticGasPool(
     const suiPusher = await SuiPricePusher.createWithAutomaticGasPool(
       priceServiceConnection,
       priceServiceConnection,
+      logger.child({ module: "SuiPricePusher" }),
       pythStateId,
       pythStateId,
       wormholeStateId,
       wormholeStateId,
       endpoint,
       endpoint,
@@ -143,6 +151,7 @@ export default {
       pythListener,
       pythListener,
       suiListener,
       suiListener,
       suiPusher,
       suiPusher,
+      logger.child({ module: "Controller" }, { level: controllerLogLevel }),
       { pushingFrequency }
       { pushingFrequency }
     );
     );
 
 

+ 46 - 35
apps/price_pusher/src/sui/sui.ts

@@ -10,6 +10,7 @@ import { SuiPythClient } from "@pythnetwork/pyth-sui-js";
 import { Ed25519Keypair } from "@mysten/sui.js/keypairs/ed25519";
 import { Ed25519Keypair } from "@mysten/sui.js/keypairs/ed25519";
 import { TransactionBlock } from "@mysten/sui.js/transactions";
 import { TransactionBlock } from "@mysten/sui.js/transactions";
 import { SuiClient, SuiObjectRef, PaginatedCoins } from "@mysten/sui.js/client";
 import { SuiClient, SuiObjectRef, PaginatedCoins } from "@mysten/sui.js/client";
+import { Logger } from "pino";
 
 
 const GAS_FEE_FOR_SPLIT = 2_000_000_000;
 const GAS_FEE_FOR_SPLIT = 2_000_000_000;
 // TODO: read this from on chain config
 // TODO: read this from on chain config
@@ -22,23 +23,26 @@ type SuiAddress = string;
 export class SuiPriceListener extends ChainPriceListener {
 export class SuiPriceListener extends ChainPriceListener {
   private pythClient: SuiPythClient;
   private pythClient: SuiPythClient;
   private provider: SuiClient;
   private provider: SuiClient;
+  private logger: Logger;
 
 
   constructor(
   constructor(
     pythStateId: ObjectId,
     pythStateId: ObjectId,
     wormholeStateId: ObjectId,
     wormholeStateId: ObjectId,
     endpoint: string,
     endpoint: string,
     priceItems: PriceItem[],
     priceItems: PriceItem[],
+    logger: Logger,
     config: {
     config: {
       pollingFrequency: DurationInSeconds;
       pollingFrequency: DurationInSeconds;
     }
     }
   ) {
   ) {
-    super("sui", config.pollingFrequency, priceItems);
+    super(config.pollingFrequency, priceItems);
     this.provider = new SuiClient({ url: endpoint });
     this.provider = new SuiClient({ url: endpoint });
     this.pythClient = new SuiPythClient(
     this.pythClient = new SuiPythClient(
       this.provider,
       this.provider,
       pythStateId,
       pythStateId,
       wormholeStateId
       wormholeStateId
     );
     );
+    this.logger = logger;
   }
   }
 
 
   async getOnChainPriceInfo(priceId: string): Promise<PriceInfo | undefined> {
   async getOnChainPriceInfo(priceId: string): Promise<PriceInfo | undefined> {
@@ -78,9 +82,11 @@ export class SuiPriceListener extends ChainPriceListener {
         conf,
         conf,
         publishTime: Number(timestamp),
         publishTime: Number(timestamp),
       };
       };
-    } catch (e) {
-      console.error(`Polling Sui on-chain price for ${priceId} failed. Error:`);
-      console.error(e);
+    } catch (err) {
+      this.logger.error(
+        err,
+        `Polling Sui on-chain price for ${priceId} failed.`
+      );
       return undefined;
       return undefined;
     }
     }
   }
   }
@@ -104,6 +110,7 @@ export class SuiPricePusher implements IPricePusher {
   constructor(
   constructor(
     private readonly signer: Ed25519Keypair,
     private readonly signer: Ed25519Keypair,
     private readonly provider: SuiClient,
     private readonly provider: SuiClient,
+    private logger: Logger,
     private priceServiceConnection: PriceServiceConnection,
     private priceServiceConnection: PriceServiceConnection,
     private pythPackageId: string,
     private pythPackageId: string,
     private pythStateId: string,
     private pythStateId: string,
@@ -157,6 +164,7 @@ export class SuiPricePusher implements IPricePusher {
    */
    */
   static async createWithAutomaticGasPool(
   static async createWithAutomaticGasPool(
     priceServiceConnection: PriceServiceConnection,
     priceServiceConnection: PriceServiceConnection,
+    logger: Logger,
     pythStateId: string,
     pythStateId: string,
     wormholeStateId: string,
     wormholeStateId: string,
     endpoint: string,
     endpoint: string,
@@ -185,7 +193,8 @@ export class SuiPricePusher implements IPricePusher {
       keypair,
       keypair,
       provider,
       provider,
       numGasObjects,
       numGasObjects,
-      ignoreGasObjects
+      ignoreGasObjects,
+      logger
     );
     );
 
 
     const pythClient = new SuiPythClient(
     const pythClient = new SuiPythClient(
@@ -197,6 +206,7 @@ export class SuiPricePusher implements IPricePusher {
     return new SuiPricePusher(
     return new SuiPricePusher(
       keypair,
       keypair,
       provider,
       provider,
+      logger,
       priceServiceConnection,
       priceServiceConnection,
       pythPackageId,
       pythPackageId,
       pythStateId,
       pythStateId,
@@ -222,7 +232,7 @@ export class SuiPricePusher implements IPricePusher {
       throw new Error("Invalid arguments");
       throw new Error("Invalid arguments");
 
 
     if (this.gasPool.length === 0) {
     if (this.gasPool.length === 0) {
-      console.warn("Skipping update: no available gas coin.");
+      this.logger.warn("Skipping update: no available gas coin.");
       return;
       return;
     }
     }
 
 
@@ -266,7 +276,7 @@ export class SuiPricePusher implements IPricePusher {
   private async sendTransactionBlock(tx: TransactionBlock): Promise<void> {
   private async sendTransactionBlock(tx: TransactionBlock): Promise<void> {
     const gasObject = this.gasPool.shift();
     const gasObject = this.gasPool.shift();
     if (gasObject === undefined) {
     if (gasObject === undefined) {
-      console.warn("No available gas coin. Skipping push.");
+      this.logger.warn("No available gas coin. Skipping push.");
       return;
       return;
     }
     }
 
 
@@ -286,31 +296,29 @@ export class SuiPricePusher implements IPricePusher {
         ?.map((obj) => obj.reference)
         ?.map((obj) => obj.reference)
         .find((ref) => ref.objectId === gasObject.objectId);
         .find((ref) => ref.objectId === gasObject.objectId);
 
 
-      console.log(
-        "Successfully updated price with transaction digest ",
-        result.digest
+      this.logger.info(
+        { hash: result.digest },
+        "Successfully updated price with transaction digest"
       );
       );
-    } catch (e: any) {
-      console.log("Error when signAndExecuteTransactionBlock");
+    } catch (err: any) {
       if (
       if (
-        String(e).includes("Balance of gas object") ||
-        String(e).includes("GasBalanceTooLow")
+        String(err).includes("Balance of gas object") ||
+        String(err).includes("GasBalanceTooLow")
       ) {
       ) {
+        this.logger.error(err, "Insufficient gas balance");
         // If the error is caused by insufficient gas, we should panic
         // If the error is caused by insufficient gas, we should panic
-        throw e;
+        throw err;
       } else {
       } else {
+        this.logger.error(
+          err,
+          "Failed to update price. Trying to refresh gas object references."
+        );
         // Refresh the coin object here in case the error is caused by an object version mismatch.
         // Refresh the coin object here in case the error is caused by an object version mismatch.
         nextGasObject = await SuiPricePusher.tryRefreshObjectReference(
         nextGasObject = await SuiPricePusher.tryRefreshObjectReference(
           this.provider,
           this.provider,
           gasObject
           gasObject
         );
         );
       }
       }
-      console.error(e);
-
-      if ("data" in e) {
-        console.error("Error has .data field:");
-        console.error(JSON.stringify(e.data));
-      }
     }
     }
 
 
     if (nextGasObject !== undefined) {
     if (nextGasObject !== undefined) {
@@ -326,20 +334,24 @@ export class SuiPricePusher implements IPricePusher {
     signer: Ed25519Keypair,
     signer: Ed25519Keypair,
     provider: SuiClient,
     provider: SuiClient,
     numGasObjects: number,
     numGasObjects: number,
-    ignoreGasObjects: string[]
+    ignoreGasObjects: string[],
+    logger: Logger
   ): Promise<SuiObjectRef[]> {
   ): Promise<SuiObjectRef[]> {
     const signerAddress = await signer.toSuiAddress();
     const signerAddress = await signer.toSuiAddress();
 
 
     if (ignoreGasObjects.length > 0) {
     if (ignoreGasObjects.length > 0) {
-      console.log("Ignoring some gas objects for coin merging:");
-      console.log(ignoreGasObjects);
+      logger.info(
+        { ignoreGasObjects },
+        "Ignoring some gas objects for coin merging"
+      );
     }
     }
 
 
     const consolidatedCoin = await SuiPricePusher.mergeGasCoinsIntoOne(
     const consolidatedCoin = await SuiPricePusher.mergeGasCoinsIntoOne(
       signer,
       signer,
       provider,
       provider,
       signerAddress,
       signerAddress,
-      ignoreGasObjects
+      ignoreGasObjects,
+      logger
     );
     );
     const coinResult = await provider.getObject({
     const coinResult = await provider.getObject({
       id: consolidatedCoin.objectId,
       id: consolidatedCoin.objectId,
@@ -366,7 +378,7 @@ export class SuiPricePusher implements IPricePusher {
       numGasObjects,
       numGasObjects,
       consolidatedCoin
       consolidatedCoin
     );
     );
-    console.log("Gas pool is filled with coins: ", gasPool);
+    logger.info({ gasPool }, "Gas pool is filled with coins");
     return gasPool;
     return gasPool;
   }
   }
 
 
@@ -470,7 +482,8 @@ export class SuiPricePusher implements IPricePusher {
     signer: Ed25519Keypair,
     signer: Ed25519Keypair,
     provider: SuiClient,
     provider: SuiClient,
     owner: SuiAddress,
     owner: SuiAddress,
-    initialLockedAddresses: string[]
+    initialLockedAddresses: string[],
+    logger: Logger
   ): Promise<SuiObjectRef> {
   ): Promise<SuiObjectRef> {
     const gasCoins = await SuiPricePusher.getAllGasCoins(provider, owner);
     const gasCoins = await SuiPricePusher.getAllGasCoins(provider, owner);
     // skip merging if there is only one coin
     // skip merging if there is only one coin
@@ -500,17 +513,15 @@ export class SuiPricePusher implements IPricePusher {
           transactionBlock: mergeTx,
           transactionBlock: mergeTx,
           options: { showEffects: true },
           options: { showEffects: true },
         });
         });
-      } catch (e) {
-        console.log("Merge transaction failed with error:");
-        console.log(e);
-        console.log((e as any).data);
-        console.log(JSON.stringify(e));
+      } catch (err) {
+        logger.error(err, "Merge transaction failed with error");
+
         if (
         if (
-          String(e).includes(
+          String(err).includes(
             "quorum of validators because of locked objects. Retried a conflicting transaction"
             "quorum of validators because of locked objects. Retried a conflicting transaction"
           )
           )
         ) {
         ) {
-          Object.values((e as any).data).forEach((lockedObjects: any) => {
+          Object.values((err as any).data).forEach((lockedObjects: any) => {
             lockedObjects.forEach((lockedObject: [string, number, string]) => {
             lockedObjects.forEach((lockedObject: [string, number, string]) => {
               lockedAddresses.add(lockedObject[0]);
               lockedAddresses.add(lockedObject[0]);
             });
             });
@@ -519,7 +530,7 @@ export class SuiPricePusher implements IPricePusher {
           i--;
           i--;
           continue;
           continue;
         }
         }
-        throw e;
+        throw err;
       }
       }
       const error = mergeResult?.effects?.status.error;
       const error = mergeResult?.effects?.status.error;
       if (error) {
       if (error) {

+ 235 - 87
pnpm-lock.yaml

@@ -235,9 +235,15 @@ importers:
       '@pythnetwork/solana-utils':
       '@pythnetwork/solana-utils':
         specifier: workspace:*
         specifier: workspace:*
         version: link:../../target_chains/solana/sdk/js/solana_utils
         version: link:../../target_chains/solana/sdk/js/solana_utils
+      '@solana/web3.js':
+        specifier: ^1.93.0
+        version: 1.93.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)
       '@truffle/hdwallet-provider':
       '@truffle/hdwallet-provider':
         specifier: ^2.1.3
         specifier: ^2.1.3
         version: 2.1.5(@babel/core@7.24.7)(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)
         version: 2.1.5(@babel/core@7.24.7)(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)
+      '@types/pino':
+        specifier: ^7.0.5
+        version: 7.0.5
       aptos:
       aptos:
         specifier: ^1.8.5
         specifier: ^1.8.5
         version: 1.8.5
         version: 1.8.5
@@ -250,6 +256,9 @@ importers:
       near-api-js:
       near-api-js:
         specifier: ^3.0.2
         specifier: ^3.0.2
         version: 3.0.4(encoding@0.1.13)
         version: 3.0.4(encoding@0.1.13)
+      pino:
+        specifier: ^9.2.0
+        version: 9.2.0
       web3:
       web3:
         specifier: ^1.8.1
         specifier: ^1.8.1
         version: 1.8.2(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)
         version: 1.8.2(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)
@@ -287,6 +296,9 @@ importers:
       jest:
       jest:
         specifier: ^29.7.0
         specifier: ^29.7.0
         version: 29.7.0(@types/node@20.14.2)(ts-node@10.9.1(@types/node@20.14.2)(typescript@5.4.5))
         version: 29.7.0(@types/node@20.14.2)(ts-node@10.9.1(@types/node@20.14.2)(typescript@5.4.5))
+      pino-pretty:
+        specifier: ^11.2.1
+        version: 11.2.1
       prettier:
       prettier:
         specifier: ^2.6.2
         specifier: ^2.6.2
         version: 2.8.8
         version: 2.8.8
@@ -322,7 +334,7 @@ importers:
         version: 0.49.1
         version: 0.49.1
       '@pythnetwork/client':
       '@pythnetwork/client':
         specifier: ^2.21.0
         specifier: ^2.21.0
-        version: 2.21.0(@solana/web3.js@1.90.0(bufferutil@4.0.7)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.7)(encoding@0.1.13)(utf-8-validate@5.0.10)
+        version: 2.21.0(@solana/web3.js@1.92.3(bufferutil@4.0.7)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.7)(encoding@0.1.13)(utf-8-validate@5.0.10)
       '@pythnetwork/contract-manager':
       '@pythnetwork/contract-manager':
         specifier: workspace:*
         specifier: workspace:*
         version: 'link:'
         version: 'link:'
@@ -944,7 +956,7 @@ importers:
         version: 0.0.12(eslint@9.5.0)(typescript@4.9.5)(webpack@5.91.0)
         version: 0.0.12(eslint@9.5.0)(typescript@4.9.5)(webpack@5.91.0)
       '@pythnetwork/client':
       '@pythnetwork/client':
         specifier: ^2.17.0
         specifier: ^2.17.0
-        version: 2.21.0(@solana/web3.js@1.90.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)
+        version: 2.21.0(@solana/web3.js@1.92.3(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)
       dotenv:
       dotenv:
         specifier: ^16.0.3
         specifier: ^16.0.3
         version: 16.4.5
         version: 16.4.5
@@ -1575,7 +1587,7 @@ importers:
         version: 0.49.1
         version: 0.49.1
       '@pythnetwork/client':
       '@pythnetwork/client':
         specifier: ^2.17.0
         specifier: ^2.17.0
-        version: 2.21.0(@solana/web3.js@1.92.3(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)
+        version: 2.21.0(@solana/web3.js@1.93.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)
       '@pythnetwork/contract-manager':
       '@pythnetwork/contract-manager':
         specifier: workspace:*
         specifier: workspace:*
         version: link:../../../contract_manager
         version: link:../../../contract_manager
@@ -5943,6 +5955,9 @@ packages:
   '@solana/web3.js@1.92.3':
   '@solana/web3.js@1.92.3':
     resolution: {integrity: sha512-NVBWvb9zdJIAx6X+caXaIICCEQfQaQ8ygykCjJW4u2z/sIKcvPj3ZIIllnx0MWMc3IxGq15ozGYDOQIMbwUcHw==}
     resolution: {integrity: sha512-NVBWvb9zdJIAx6X+caXaIICCEQfQaQ8ygykCjJW4u2z/sIKcvPj3ZIIllnx0MWMc3IxGq15ozGYDOQIMbwUcHw==}
 
 
+  '@solana/web3.js@1.93.0':
+    resolution: {integrity: sha512-suf4VYwWxERz4tKoPpXCRHFRNst7jmcFUaD65kII+zg9urpy5PeeqgLV6G5eWGzcVzA9tZeXOju1A1Y+0ojEVw==}
+
   '@solflare-wallet/metamask-sdk@1.0.3':
   '@solflare-wallet/metamask-sdk@1.0.3':
     resolution: {integrity: sha512-os5Px5PTMYKGS5tzOoyjDxtOtj0jZKnbI1Uwt8+Jsw1HHIA+Ib2UACCGNhQ/un2f8sIbTfLD1WuucNMOy8KZpQ==}
     resolution: {integrity: sha512-os5Px5PTMYKGS5tzOoyjDxtOtj0jZKnbI1Uwt8+Jsw1HHIA+Ib2UACCGNhQ/un2f8sIbTfLD1WuucNMOy8KZpQ==}
     peerDependencies:
     peerDependencies:
@@ -6181,6 +6196,9 @@ packages:
   '@swc/counter@0.1.3':
   '@swc/counter@0.1.3':
     resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==}
     resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==}
 
 
+  '@swc/helpers@0.5.11':
+    resolution: {integrity: sha512-YNlnKRWF2sVojTpIyzwou9XoTNbzbzONwRhOoniEioF1AtaitTvVZblaQRrAzChWQ1bLYyYSWzM18y4WwgzJ+A==}
+
   '@swc/helpers@0.5.5':
   '@swc/helpers@0.5.5':
     resolution: {integrity: sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A==}
     resolution: {integrity: sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A==}
 
 
@@ -6685,6 +6703,10 @@ packages:
   '@types/pbkdf2@3.1.0':
   '@types/pbkdf2@3.1.0':
     resolution: {integrity: sha512-Cf63Rv7jCQ0LaL8tNXmEyqTHuIJxRdlS5vMh1mj5voN4+QFhVZnlZruezqpWYDiJ8UTzhP0VmeLXCmBk66YrMQ==}
     resolution: {integrity: sha512-Cf63Rv7jCQ0LaL8tNXmEyqTHuIJxRdlS5vMh1mj5voN4+QFhVZnlZruezqpWYDiJ8UTzhP0VmeLXCmBk66YrMQ==}
 
 
+  '@types/pino@7.0.5':
+    resolution: {integrity: sha512-wKoab31pknvILkxAF8ss+v9iNyhw5Iu/0jLtRkUD74cNfOOLJNnqfFKAv0r7wVaTQxRZtWrMpGfShwwBjOcgcg==}
+    deprecated: This is a stub types definition. pino provides its own type definitions, so you do not need this installed.
+
   '@types/prettier@2.7.2':
   '@types/prettier@2.7.2':
     resolution: {integrity: sha512-KufADq8uQqo1pYKVIYzfKbJfBAc0sOeXqGbFaSpv8MRmC/zXgowNZmFcbngndGk922QDmOASEXUZCaY48gs4cg==}
     resolution: {integrity: sha512-KufADq8uQqo1pYKVIYzfKbJfBAc0sOeXqGbFaSpv8MRmC/zXgowNZmFcbngndGk922QDmOASEXUZCaY48gs4cg==}
 
 
@@ -8651,6 +8673,9 @@ packages:
   colorette@1.4.0:
   colorette@1.4.0:
     resolution: {integrity: sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==}
     resolution: {integrity: sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==}
 
 
+  colorette@2.0.20:
+    resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==}
+
   colors@1.0.3:
   colors@1.0.3:
     resolution: {integrity: sha512-pFGrxThWcWQ2MsAz6RtgeWe4NK2kUE1WfsrvvlctdII745EW9I0yflqhe7++M5LEc7bV2c/9/5zc8sFcpL0Drw==}
     resolution: {integrity: sha512-pFGrxThWcWQ2MsAz6RtgeWe4NK2kUE1WfsrvvlctdII745EW9I0yflqhe7++M5LEc7bV2c/9/5zc8sFcpL0Drw==}
     engines: {node: '>=0.1.90'}
     engines: {node: '>=0.1.90'}
@@ -9059,6 +9084,9 @@ packages:
   dateformat@3.0.3:
   dateformat@3.0.3:
     resolution: {integrity: sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==}
     resolution: {integrity: sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==}
 
 
+  dateformat@4.6.3:
+    resolution: {integrity: sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==}
+
   dayjs@1.11.11:
   dayjs@1.11.11:
     resolution: {integrity: sha512-okzr3f11N6WuqYtZSvm+F776mB41wRZMhKP+hc34YdW+KmtYYK9iqvHSwo2k9FEH3fhGXvOPV6yz2IcSrfRUDg==}
     resolution: {integrity: sha512-okzr3f11N6WuqYtZSvm+F776mB41wRZMhKP+hc34YdW+KmtYYK9iqvHSwo2k9FEH3fhGXvOPV6yz2IcSrfRUDg==}
 
 
@@ -10301,6 +10329,9 @@ packages:
     resolution: {integrity: sha512-I2FldZwnCbcY6iL+H0rp9m4D+O3PotuFu9FasWjMCzUedYHMP89/37JbSt6/n7Yq/IZmJDW0B2h30sPYdzrfzw==}
     resolution: {integrity: sha512-I2FldZwnCbcY6iL+H0rp9m4D+O3PotuFu9FasWjMCzUedYHMP89/37JbSt6/n7Yq/IZmJDW0B2h30sPYdzrfzw==}
     engines: {node: '>=8.0.0'}
     engines: {node: '>=8.0.0'}
 
 
+  fast-copy@3.0.2:
+    resolution: {integrity: sha512-dl0O9Vhju8IrcLndv2eU4ldt1ftXMqqfgN4H1cpmGV7P6jeB9FwpN9a2c8DPGE1Ys88rNUJVYDHq73CGAGOPfQ==}
+
   fast-deep-equal@3.1.3:
   fast-deep-equal@3.1.3:
     resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
     resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
 
 
@@ -10929,6 +10960,9 @@ packages:
   header-case@1.0.1:
   header-case@1.0.1:
     resolution: {integrity: sha512-i0q9mkOeSuhXw6bGgiQCCBgY/jlZuV/7dZXyZ9c6LcBrqwvT8eT719E9uxE5LiZftdl+z81Ugbg/VvXV4OJOeQ==}
     resolution: {integrity: sha512-i0q9mkOeSuhXw6bGgiQCCBgY/jlZuV/7dZXyZ9c6LcBrqwvT8eT719E9uxE5LiZftdl+z81Ugbg/VvXV4OJOeQ==}
 
 
+  help-me@5.0.0:
+    resolution: {integrity: sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==}
+
   hermes-estree@0.19.1:
   hermes-estree@0.19.1:
     resolution: {integrity: sha512-daLGV3Q2MKk8w4evNMKwS8zBE/rcpA800nu1Q5kM08IKijoSnPe9Uo1iIxzPKRkn95IxxsgBMPeYHt3VG4ej2g==}
     resolution: {integrity: sha512-daLGV3Q2MKk8w4evNMKwS8zBE/rcpA800nu1Q5kM08IKijoSnPe9Uo1iIxzPKRkn95IxxsgBMPeYHt3VG4ej2g==}
 
 
@@ -13788,6 +13822,10 @@ packages:
   pino-abstract-transport@1.2.0:
   pino-abstract-transport@1.2.0:
     resolution: {integrity: sha512-Guhh8EZfPCfH+PMXAb6rKOjGQEoy0xlAIn+irODG5kgfYV+BQ0rGYYWTIel3P5mmyXqkYkPmdIkywsn6QKUR1Q==}
     resolution: {integrity: sha512-Guhh8EZfPCfH+PMXAb6rKOjGQEoy0xlAIn+irODG5kgfYV+BQ0rGYYWTIel3P5mmyXqkYkPmdIkywsn6QKUR1Q==}
 
 
+  pino-pretty@11.2.1:
+    resolution: {integrity: sha512-O05NuD9tkRasFRWVaF/uHLOvoRDFD7tb5VMertr78rbsYFjYp48Vg3477EshVAF5eZaEw+OpDl/tu+B0R5o+7g==}
+    hasBin: true
+
   pino-std-serializers@4.0.0:
   pino-std-serializers@4.0.0:
     resolution: {integrity: sha512-cK0pekc1Kjy5w9V2/n+8MkZwusa6EyyxfeQCB799CQRhRt/CqYKiWs5adeu8Shve2ZNffvfC/7J64A2PJo1W/Q==}
     resolution: {integrity: sha512-cK0pekc1Kjy5w9V2/n+8MkZwusa6EyyxfeQCB799CQRhRt/CqYKiWs5adeu8Shve2ZNffvfC/7J64A2PJo1W/Q==}
 
 
@@ -14724,6 +14762,9 @@ packages:
   rpc-websockets@8.0.1:
   rpc-websockets@8.0.1:
     resolution: {integrity: sha512-PptrPRK40uQvifq5sCcObmqInVcZXhy+RRrirzdE5KUPvDI47y1wPvfckD2QzqngOU9xaPW/dT+G+b+wj6M1MQ==}
     resolution: {integrity: sha512-PptrPRK40uQvifq5sCcObmqInVcZXhy+RRrirzdE5KUPvDI47y1wPvfckD2QzqngOU9xaPW/dT+G+b+wj6M1MQ==}
 
 
+  rpc-websockets@9.0.2:
+    resolution: {integrity: sha512-YzggvfItxMY3Lwuax5rC18inhbjJv9Py7JXRHxTIi94JOLrqBsSsUUc5bbl5W6c11tXhdfpDPK0KzBhoGe8jjw==}
+
   rtcpeerconnection-shim@1.2.15:
   rtcpeerconnection-shim@1.2.15:
     resolution: {integrity: sha512-C6DxhXt7bssQ1nHb154lqeL0SXz5Dx4RczXZu2Aa/L1NJFnEVDxFwCBo3fqtuljhHIGceg5JKBV4XJ0gW5JKyw==}
     resolution: {integrity: sha512-C6DxhXt7bssQ1nHb154lqeL0SXz5Dx4RczXZu2Aa/L1NJFnEVDxFwCBo3fqtuljhHIGceg5JKBV4XJ0gW5JKyw==}
     engines: {node: '>=6.0.0', npm: '>=3.10.0'}
     engines: {node: '>=6.0.0', npm: '>=3.10.0'}
@@ -14827,6 +14868,9 @@ packages:
     resolution: {integrity: sha512-TKWX8xvoGHrxVdqbYeZM9w+izTF4b9z3NhSaDkdn81btvuh+ivbIMGT/zQvDtTFWhRlThpoz6LEYTr7n8A5GcA==}
     resolution: {integrity: sha512-TKWX8xvoGHrxVdqbYeZM9w+izTF4b9z3NhSaDkdn81btvuh+ivbIMGT/zQvDtTFWhRlThpoz6LEYTr7n8A5GcA==}
     engines: {node: '>=14.0.0'}
     engines: {node: '>=14.0.0'}
 
 
+  secure-json-parse@2.7.0:
+    resolution: {integrity: sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==}
+
   selfsigned@2.4.1:
   selfsigned@2.4.1:
     resolution: {integrity: sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==}
     resolution: {integrity: sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==}
     engines: {node: '>=10'}
     engines: {node: '>=10'}
@@ -19786,7 +19830,7 @@ snapshots:
 
 
   '@censo-custody/solana-wallet-adapter@0.1.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)':
   '@censo-custody/solana-wallet-adapter@0.1.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)':
     dependencies:
     dependencies:
-      '@solana/web3.js': 1.90.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)
+      '@solana/web3.js': 1.92.3(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)
       bs58: 4.0.1
       bs58: 4.0.1
       eventemitter3: 4.0.7
       eventemitter3: 4.0.7
       uuid: 8.3.2
       uuid: 8.3.2
@@ -19820,11 +19864,11 @@ snapshots:
     dependencies:
     dependencies:
       '@certusone/wormhole-sdk-proto-web': 0.0.7(google-protobuf@3.21.2)
       '@certusone/wormhole-sdk-proto-web': 0.0.7(google-protobuf@3.21.2)
       '@certusone/wormhole-sdk-wasm': 0.0.1
       '@certusone/wormhole-sdk-wasm': 0.0.1
-      '@coral-xyz/borsh': 0.2.6(@solana/web3.js@1.90.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10))
+      '@coral-xyz/borsh': 0.2.6(@solana/web3.js@1.92.3(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10))
       '@mysten/sui.js': 0.32.2(bufferutil@4.0.8)(utf-8-validate@5.0.10)
       '@mysten/sui.js': 0.32.2(bufferutil@4.0.8)(utf-8-validate@5.0.10)
       '@project-serum/anchor': 0.25.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)
       '@project-serum/anchor': 0.25.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)
-      '@solana/spl-token': 0.3.7(@solana/web3.js@1.90.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)
-      '@solana/web3.js': 1.90.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)
+      '@solana/spl-token': 0.3.7(@solana/web3.js@1.92.3(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)
+      '@solana/web3.js': 1.92.3(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)
       '@terra-money/terra.js': 3.1.9
       '@terra-money/terra.js': 3.1.9
       '@xpla/xpla.js': 0.2.3
       '@xpla/xpla.js': 0.2.3
       algosdk: 2.7.0
       algosdk: 2.7.0
@@ -19855,11 +19899,11 @@ snapshots:
     dependencies:
     dependencies:
       '@certusone/wormhole-sdk-proto-web': 0.0.6(google-protobuf@3.21.2)
       '@certusone/wormhole-sdk-proto-web': 0.0.6(google-protobuf@3.21.2)
       '@certusone/wormhole-sdk-wasm': 0.0.1
       '@certusone/wormhole-sdk-wasm': 0.0.1
-      '@coral-xyz/borsh': 0.2.6(@solana/web3.js@1.90.0(bufferutil@4.0.7)(encoding@0.1.13)(utf-8-validate@5.0.10))
+      '@coral-xyz/borsh': 0.2.6(@solana/web3.js@1.92.3(bufferutil@4.0.7)(encoding@0.1.13)(utf-8-validate@5.0.10))
       '@mysten/sui.js': 0.32.2(bufferutil@4.0.7)(utf-8-validate@5.0.10)
       '@mysten/sui.js': 0.32.2(bufferutil@4.0.7)(utf-8-validate@5.0.10)
       '@project-serum/anchor': 0.25.0(bufferutil@4.0.7)(encoding@0.1.13)(utf-8-validate@5.0.10)
       '@project-serum/anchor': 0.25.0(bufferutil@4.0.7)(encoding@0.1.13)(utf-8-validate@5.0.10)
-      '@solana/spl-token': 0.3.7(@solana/web3.js@1.90.0(bufferutil@4.0.7)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.7)(encoding@0.1.13)(utf-8-validate@5.0.10)
-      '@solana/web3.js': 1.90.0(bufferutil@4.0.7)(encoding@0.1.13)(utf-8-validate@5.0.10)
+      '@solana/spl-token': 0.3.7(@solana/web3.js@1.92.3(bufferutil@4.0.7)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.7)(encoding@0.1.13)(utf-8-validate@5.0.10)
+      '@solana/web3.js': 1.92.3(bufferutil@4.0.7)(encoding@0.1.13)(utf-8-validate@5.0.10)
       '@terra-money/terra.js': 3.1.9
       '@terra-money/terra.js': 3.1.9
       '@xpla/xpla.js': 0.2.3
       '@xpla/xpla.js': 0.2.3
       algosdk: 2.7.0
       algosdk: 2.7.0
@@ -19890,11 +19934,11 @@ snapshots:
     dependencies:
     dependencies:
       '@certusone/wormhole-sdk-proto-web': 0.0.6(google-protobuf@3.21.2)
       '@certusone/wormhole-sdk-proto-web': 0.0.6(google-protobuf@3.21.2)
       '@certusone/wormhole-sdk-wasm': 0.0.1
       '@certusone/wormhole-sdk-wasm': 0.0.1
-      '@coral-xyz/borsh': 0.2.6(@solana/web3.js@1.90.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10))
+      '@coral-xyz/borsh': 0.2.6(@solana/web3.js@1.92.3(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10))
       '@mysten/sui.js': 0.32.2(bufferutil@4.0.8)(utf-8-validate@5.0.10)
       '@mysten/sui.js': 0.32.2(bufferutil@4.0.8)(utf-8-validate@5.0.10)
       '@project-serum/anchor': 0.25.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)
       '@project-serum/anchor': 0.25.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)
-      '@solana/spl-token': 0.3.7(@solana/web3.js@1.90.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)
-      '@solana/web3.js': 1.90.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)
+      '@solana/spl-token': 0.3.7(@solana/web3.js@1.92.3(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)
+      '@solana/web3.js': 1.92.3(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)
       '@terra-money/terra.js': 3.1.9
       '@terra-money/terra.js': 3.1.9
       '@xpla/xpla.js': 0.2.3
       '@xpla/xpla.js': 0.2.3
       algosdk: 2.7.0
       algosdk: 2.7.0
@@ -19939,8 +19983,8 @@ snapshots:
 
 
   '@coral-xyz/anchor@0.27.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)':
   '@coral-xyz/anchor@0.27.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)':
     dependencies:
     dependencies:
-      '@coral-xyz/borsh': 0.27.0(@solana/web3.js@1.90.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10))
-      '@solana/web3.js': 1.90.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)
+      '@coral-xyz/borsh': 0.27.0(@solana/web3.js@1.92.3(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10))
+      '@solana/web3.js': 1.92.3(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)
       base64-js: 1.5.1
       base64-js: 1.5.1
       bn.js: 5.2.1
       bn.js: 5.2.1
       bs58: 4.0.1
       bs58: 4.0.1
@@ -19961,9 +20005,9 @@ snapshots:
 
 
   '@coral-xyz/anchor@0.29.0(bufferutil@4.0.7)(encoding@0.1.13)(utf-8-validate@5.0.10)':
   '@coral-xyz/anchor@0.29.0(bufferutil@4.0.7)(encoding@0.1.13)(utf-8-validate@5.0.10)':
     dependencies:
     dependencies:
-      '@coral-xyz/borsh': 0.29.0(@solana/web3.js@1.90.0(bufferutil@4.0.7)(encoding@0.1.13)(utf-8-validate@5.0.10))
+      '@coral-xyz/borsh': 0.29.0(@solana/web3.js@1.92.3(bufferutil@4.0.7)(encoding@0.1.13)(utf-8-validate@5.0.10))
       '@noble/hashes': 1.4.0
       '@noble/hashes': 1.4.0
-      '@solana/web3.js': 1.90.0(bufferutil@4.0.7)(encoding@0.1.13)(utf-8-validate@5.0.10)
+      '@solana/web3.js': 1.92.3(bufferutil@4.0.7)(encoding@0.1.13)(utf-8-validate@5.0.10)
       bn.js: 5.2.1
       bn.js: 5.2.1
       bs58: 4.0.1
       bs58: 4.0.1
       buffer-layout: 1.2.2
       buffer-layout: 1.2.2
@@ -19982,9 +20026,9 @@ snapshots:
 
 
   '@coral-xyz/anchor@0.29.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)':
   '@coral-xyz/anchor@0.29.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)':
     dependencies:
     dependencies:
-      '@coral-xyz/borsh': 0.29.0(@solana/web3.js@1.90.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10))
+      '@coral-xyz/borsh': 0.29.0(@solana/web3.js@1.92.3(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10))
       '@noble/hashes': 1.4.0
       '@noble/hashes': 1.4.0
-      '@solana/web3.js': 1.90.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)
+      '@solana/web3.js': 1.92.3(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)
       bn.js: 5.2.1
       bn.js: 5.2.1
       bs58: 4.0.1
       bs58: 4.0.1
       buffer-layout: 1.2.2
       buffer-layout: 1.2.2
@@ -20003,9 +20047,9 @@ snapshots:
 
 
   '@coral-xyz/anchor@0.30.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)':
   '@coral-xyz/anchor@0.30.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)':
     dependencies:
     dependencies:
-      '@coral-xyz/borsh': 0.30.0(@solana/web3.js@1.90.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10))
+      '@coral-xyz/borsh': 0.30.0(@solana/web3.js@1.93.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10))
       '@noble/hashes': 1.4.0
       '@noble/hashes': 1.4.0
-      '@solana/web3.js': 1.90.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)
+      '@solana/web3.js': 1.93.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)
       bn.js: 5.2.1
       bn.js: 5.2.1
       bs58: 4.0.1
       bs58: 4.0.1
       buffer-layout: 1.2.2
       buffer-layout: 1.2.2
@@ -20022,33 +20066,33 @@ snapshots:
       - encoding
       - encoding
       - utf-8-validate
       - utf-8-validate
 
 
-  '@coral-xyz/borsh@0.2.6(@solana/web3.js@1.90.0(bufferutil@4.0.7)(encoding@0.1.13)(utf-8-validate@5.0.10))':
+  '@coral-xyz/borsh@0.2.6(@solana/web3.js@1.92.3(bufferutil@4.0.7)(encoding@0.1.13)(utf-8-validate@5.0.10))':
     dependencies:
     dependencies:
-      '@solana/web3.js': 1.90.0(bufferutil@4.0.7)(encoding@0.1.13)(utf-8-validate@5.0.10)
+      '@solana/web3.js': 1.92.3(bufferutil@4.0.7)(encoding@0.1.13)(utf-8-validate@5.0.10)
       bn.js: 5.2.1
       bn.js: 5.2.1
       buffer-layout: 1.2.2
       buffer-layout: 1.2.2
 
 
-  '@coral-xyz/borsh@0.2.6(@solana/web3.js@1.90.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10))':
+  '@coral-xyz/borsh@0.2.6(@solana/web3.js@1.92.3(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10))':
     dependencies:
     dependencies:
-      '@solana/web3.js': 1.90.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)
+      '@solana/web3.js': 1.92.3(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)
       bn.js: 5.2.1
       bn.js: 5.2.1
       buffer-layout: 1.2.2
       buffer-layout: 1.2.2
 
 
-  '@coral-xyz/borsh@0.27.0(@solana/web3.js@1.90.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10))':
+  '@coral-xyz/borsh@0.27.0(@solana/web3.js@1.92.3(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10))':
     dependencies:
     dependencies:
-      '@solana/web3.js': 1.90.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)
+      '@solana/web3.js': 1.92.3(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)
       bn.js: 5.2.1
       bn.js: 5.2.1
       buffer-layout: 1.2.2
       buffer-layout: 1.2.2
 
 
-  '@coral-xyz/borsh@0.28.0(@solana/web3.js@1.90.0(bufferutil@4.0.7)(encoding@0.1.13)(utf-8-validate@5.0.10))':
+  '@coral-xyz/borsh@0.28.0(@solana/web3.js@1.90.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10))':
     dependencies:
     dependencies:
-      '@solana/web3.js': 1.90.0(bufferutil@4.0.7)(encoding@0.1.13)(utf-8-validate@5.0.10)
+      '@solana/web3.js': 1.90.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)
       bn.js: 5.2.1
       bn.js: 5.2.1
       buffer-layout: 1.2.2
       buffer-layout: 1.2.2
 
 
-  '@coral-xyz/borsh@0.28.0(@solana/web3.js@1.90.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10))':
+  '@coral-xyz/borsh@0.28.0(@solana/web3.js@1.92.3(bufferutil@4.0.7)(encoding@0.1.13)(utf-8-validate@5.0.10))':
     dependencies:
     dependencies:
-      '@solana/web3.js': 1.90.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)
+      '@solana/web3.js': 1.92.3(bufferutil@4.0.7)(encoding@0.1.13)(utf-8-validate@5.0.10)
       bn.js: 5.2.1
       bn.js: 5.2.1
       buffer-layout: 1.2.2
       buffer-layout: 1.2.2
 
 
@@ -20058,21 +20102,27 @@ snapshots:
       bn.js: 5.2.1
       bn.js: 5.2.1
       buffer-layout: 1.2.2
       buffer-layout: 1.2.2
 
 
-  '@coral-xyz/borsh@0.29.0(@solana/web3.js@1.90.0(bufferutil@4.0.7)(encoding@0.1.13)(utf-8-validate@5.0.10))':
+  '@coral-xyz/borsh@0.28.0(@solana/web3.js@1.93.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10))':
     dependencies:
     dependencies:
-      '@solana/web3.js': 1.90.0(bufferutil@4.0.7)(encoding@0.1.13)(utf-8-validate@5.0.10)
+      '@solana/web3.js': 1.93.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)
       bn.js: 5.2.1
       bn.js: 5.2.1
       buffer-layout: 1.2.2
       buffer-layout: 1.2.2
 
 
-  '@coral-xyz/borsh@0.29.0(@solana/web3.js@1.90.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10))':
+  '@coral-xyz/borsh@0.29.0(@solana/web3.js@1.92.3(bufferutil@4.0.7)(encoding@0.1.13)(utf-8-validate@5.0.10))':
     dependencies:
     dependencies:
-      '@solana/web3.js': 1.90.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)
+      '@solana/web3.js': 1.92.3(bufferutil@4.0.7)(encoding@0.1.13)(utf-8-validate@5.0.10)
       bn.js: 5.2.1
       bn.js: 5.2.1
       buffer-layout: 1.2.2
       buffer-layout: 1.2.2
 
 
-  '@coral-xyz/borsh@0.30.0(@solana/web3.js@1.90.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10))':
+  '@coral-xyz/borsh@0.29.0(@solana/web3.js@1.92.3(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10))':
     dependencies:
     dependencies:
-      '@solana/web3.js': 1.90.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)
+      '@solana/web3.js': 1.92.3(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)
+      bn.js: 5.2.1
+      buffer-layout: 1.2.2
+
+  '@coral-xyz/borsh@0.30.0(@solana/web3.js@1.93.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10))':
+    dependencies:
+      '@solana/web3.js': 1.93.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)
       bn.js: 5.2.1
       bn.js: 5.2.1
       buffer-layout: 1.2.2
       buffer-layout: 1.2.2
 
 
@@ -20578,7 +20628,7 @@ snapshots:
 
 
   '@ensdomains/ensjs@2.1.0(bufferutil@4.0.8)(utf-8-validate@5.0.10)':
   '@ensdomains/ensjs@2.1.0(bufferutil@4.0.8)(utf-8-validate@5.0.10)':
     dependencies:
     dependencies:
-      '@babel/runtime': 7.23.9
+      '@babel/runtime': 7.24.7
       '@ensdomains/address-encoder': 0.1.9
       '@ensdomains/address-encoder': 0.1.9
       '@ensdomains/ens': 0.4.5
       '@ensdomains/ens': 0.4.5
       '@ensdomains/resolver': 0.2.4
       '@ensdomains/resolver': 0.2.4
@@ -22609,7 +22659,7 @@ snapshots:
       '@keystonehq/bc-ur-registry': 0.5.5
       '@keystonehq/bc-ur-registry': 0.5.5
       '@keystonehq/bc-ur-registry-sol': 0.3.1
       '@keystonehq/bc-ur-registry-sol': 0.3.1
       '@keystonehq/sdk': 0.13.1
       '@keystonehq/sdk': 0.13.1
-      '@solana/web3.js': 1.90.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)
+      '@solana/web3.js': 1.92.3(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)
       bs58: 5.0.0
       bs58: 5.0.0
       uuid: 8.3.2
       uuid: 8.3.2
     transitivePeerDependencies:
     transitivePeerDependencies:
@@ -24179,8 +24229,8 @@ snapshots:
 
 
   '@project-serum/anchor@0.25.0(bufferutil@4.0.7)(encoding@0.1.13)(utf-8-validate@5.0.10)':
   '@project-serum/anchor@0.25.0(bufferutil@4.0.7)(encoding@0.1.13)(utf-8-validate@5.0.10)':
     dependencies:
     dependencies:
-      '@project-serum/borsh': 0.2.5(@solana/web3.js@1.90.0(bufferutil@4.0.7)(encoding@0.1.13)(utf-8-validate@5.0.10))
-      '@solana/web3.js': 1.90.0(bufferutil@4.0.7)(encoding@0.1.13)(utf-8-validate@5.0.10)
+      '@project-serum/borsh': 0.2.5(@solana/web3.js@1.92.3(bufferutil@4.0.7)(encoding@0.1.13)(utf-8-validate@5.0.10))
+      '@solana/web3.js': 1.92.3(bufferutil@4.0.7)(encoding@0.1.13)(utf-8-validate@5.0.10)
       base64-js: 1.5.1
       base64-js: 1.5.1
       bn.js: 5.2.1
       bn.js: 5.2.1
       bs58: 4.0.1
       bs58: 4.0.1
@@ -24201,8 +24251,8 @@ snapshots:
 
 
   '@project-serum/anchor@0.25.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)':
   '@project-serum/anchor@0.25.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)':
     dependencies:
     dependencies:
-      '@project-serum/borsh': 0.2.5(@solana/web3.js@1.90.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10))
-      '@solana/web3.js': 1.90.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)
+      '@project-serum/borsh': 0.2.5(@solana/web3.js@1.92.3(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10))
+      '@solana/web3.js': 1.92.3(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)
       base64-js: 1.5.1
       base64-js: 1.5.1
       bn.js: 5.2.1
       bn.js: 5.2.1
       bs58: 4.0.1
       bs58: 4.0.1
@@ -24221,15 +24271,15 @@ snapshots:
       - encoding
       - encoding
       - utf-8-validate
       - utf-8-validate
 
 
-  '@project-serum/borsh@0.2.5(@solana/web3.js@1.90.0(bufferutil@4.0.7)(encoding@0.1.13)(utf-8-validate@5.0.10))':
+  '@project-serum/borsh@0.2.5(@solana/web3.js@1.92.3(bufferutil@4.0.7)(encoding@0.1.13)(utf-8-validate@5.0.10))':
     dependencies:
     dependencies:
-      '@solana/web3.js': 1.90.0(bufferutil@4.0.7)(encoding@0.1.13)(utf-8-validate@5.0.10)
+      '@solana/web3.js': 1.92.3(bufferutil@4.0.7)(encoding@0.1.13)(utf-8-validate@5.0.10)
       bn.js: 5.2.1
       bn.js: 5.2.1
       buffer-layout: 1.2.2
       buffer-layout: 1.2.2
 
 
-  '@project-serum/borsh@0.2.5(@solana/web3.js@1.90.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10))':
+  '@project-serum/borsh@0.2.5(@solana/web3.js@1.92.3(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10))':
     dependencies:
     dependencies:
-      '@solana/web3.js': 1.90.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)
+      '@solana/web3.js': 1.92.3(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)
       bn.js: 5.2.1
       bn.js: 5.2.1
       buffer-layout: 1.2.2
       buffer-layout: 1.2.2
 
 
@@ -24262,22 +24312,22 @@ snapshots:
 
 
   '@protobufjs/utf8@1.1.0': {}
   '@protobufjs/utf8@1.1.0': {}
 
 
-  '@pythnetwork/client@2.21.0(@solana/web3.js@1.90.0(bufferutil@4.0.7)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.7)(encoding@0.1.13)(utf-8-validate@5.0.10)':
+  '@pythnetwork/client@2.21.0(@solana/web3.js@1.90.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)':
     dependencies:
     dependencies:
-      '@coral-xyz/anchor': 0.29.0(bufferutil@4.0.7)(encoding@0.1.13)(utf-8-validate@5.0.10)
-      '@coral-xyz/borsh': 0.28.0(@solana/web3.js@1.90.0(bufferutil@4.0.7)(encoding@0.1.13)(utf-8-validate@5.0.10))
-      '@solana/web3.js': 1.90.0(bufferutil@4.0.7)(encoding@0.1.13)(utf-8-validate@5.0.10)
+      '@coral-xyz/anchor': 0.29.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)
+      '@coral-xyz/borsh': 0.28.0(@solana/web3.js@1.90.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10))
+      '@solana/web3.js': 1.90.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)
       buffer: 6.0.3
       buffer: 6.0.3
     transitivePeerDependencies:
     transitivePeerDependencies:
       - bufferutil
       - bufferutil
       - encoding
       - encoding
       - utf-8-validate
       - utf-8-validate
 
 
-  '@pythnetwork/client@2.21.0(@solana/web3.js@1.90.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)':
+  '@pythnetwork/client@2.21.0(@solana/web3.js@1.92.3(bufferutil@4.0.7)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.7)(encoding@0.1.13)(utf-8-validate@5.0.10)':
     dependencies:
     dependencies:
-      '@coral-xyz/anchor': 0.29.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)
-      '@coral-xyz/borsh': 0.28.0(@solana/web3.js@1.90.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10))
-      '@solana/web3.js': 1.90.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)
+      '@coral-xyz/anchor': 0.29.0(bufferutil@4.0.7)(encoding@0.1.13)(utf-8-validate@5.0.10)
+      '@coral-xyz/borsh': 0.28.0(@solana/web3.js@1.92.3(bufferutil@4.0.7)(encoding@0.1.13)(utf-8-validate@5.0.10))
+      '@solana/web3.js': 1.92.3(bufferutil@4.0.7)(encoding@0.1.13)(utf-8-validate@5.0.10)
       buffer: 6.0.3
       buffer: 6.0.3
     transitivePeerDependencies:
     transitivePeerDependencies:
       - bufferutil
       - bufferutil
@@ -24295,6 +24345,17 @@ snapshots:
       - encoding
       - encoding
       - utf-8-validate
       - utf-8-validate
 
 
+  '@pythnetwork/client@2.21.0(@solana/web3.js@1.93.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)':
+    dependencies:
+      '@coral-xyz/anchor': 0.29.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)
+      '@coral-xyz/borsh': 0.28.0(@solana/web3.js@1.93.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10))
+      '@solana/web3.js': 1.93.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)
+      buffer: 6.0.3
+    transitivePeerDependencies:
+      - bufferutil
+      - encoding
+      - utf-8-validate
+
   '@pythnetwork/price-service-client@1.9.0(bufferutil@4.0.8)(utf-8-validate@5.0.10)':
   '@pythnetwork/price-service-client@1.9.0(bufferutil@4.0.8)(utf-8-validate@5.0.10)':
     dependencies:
     dependencies:
       '@pythnetwork/price-service-sdk': 1.7.1
       '@pythnetwork/price-service-sdk': 1.7.1
@@ -24321,7 +24382,7 @@ snapshots:
 
 
   '@radix-ui/react-arrow@1.0.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
   '@radix-ui/react-arrow@1.0.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
     dependencies:
     dependencies:
-      '@babel/runtime': 7.23.9
+      '@babel/runtime': 7.24.7
       '@radix-ui/react-primitive': 1.0.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
       '@radix-ui/react-primitive': 1.0.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
       react: 18.3.1
       react: 18.3.1
       react-dom: 18.3.1(react@18.3.1)
       react-dom: 18.3.1(react@18.3.1)
@@ -24428,7 +24489,7 @@ snapshots:
 
 
   '@radix-ui/react-use-callback-ref@1.0.0(react@18.3.1)':
   '@radix-ui/react-use-callback-ref@1.0.0(react@18.3.1)':
     dependencies:
     dependencies:
-      '@babel/runtime': 7.23.9
+      '@babel/runtime': 7.24.7
       react: 18.3.1
       react: 18.3.1
 
 
   '@radix-ui/react-use-controllable-state@1.0.0(react@18.3.1)':
   '@radix-ui/react-use-controllable-state@1.0.0(react@18.3.1)':
@@ -24439,24 +24500,24 @@ snapshots:
 
 
   '@radix-ui/react-use-escape-keydown@1.0.2(react@18.3.1)':
   '@radix-ui/react-use-escape-keydown@1.0.2(react@18.3.1)':
     dependencies:
     dependencies:
-      '@babel/runtime': 7.23.9
+      '@babel/runtime': 7.24.7
       '@radix-ui/react-use-callback-ref': 1.0.0(react@18.3.1)
       '@radix-ui/react-use-callback-ref': 1.0.0(react@18.3.1)
       react: 18.3.1
       react: 18.3.1
 
 
   '@radix-ui/react-use-layout-effect@1.0.0(react@18.3.1)':
   '@radix-ui/react-use-layout-effect@1.0.0(react@18.3.1)':
     dependencies:
     dependencies:
-      '@babel/runtime': 7.23.9
+      '@babel/runtime': 7.24.7
       react: 18.3.1
       react: 18.3.1
 
 
   '@radix-ui/react-use-rect@1.0.0(react@18.3.1)':
   '@radix-ui/react-use-rect@1.0.0(react@18.3.1)':
     dependencies:
     dependencies:
-      '@babel/runtime': 7.23.9
+      '@babel/runtime': 7.24.7
       '@radix-ui/rect': 1.0.0
       '@radix-ui/rect': 1.0.0
       react: 18.3.1
       react: 18.3.1
 
 
   '@radix-ui/react-use-size@1.0.0(react@18.3.1)':
   '@radix-ui/react-use-size@1.0.0(react@18.3.1)':
     dependencies:
     dependencies:
-      '@babel/runtime': 7.23.9
+      '@babel/runtime': 7.24.7
       '@radix-ui/react-use-layout-effect': 1.0.0(react@18.3.1)
       '@radix-ui/react-use-layout-effect': 1.0.0(react@18.3.1)
       react: 18.3.1
       react: 18.3.1
 
 
@@ -24469,7 +24530,7 @@ snapshots:
 
 
   '@radix-ui/rect@1.0.0':
   '@radix-ui/rect@1.0.0':
     dependencies:
     dependencies:
-      '@babel/runtime': 7.23.9
+      '@babel/runtime': 7.24.7
 
 
   '@react-aria/focus@3.17.1(react@18.3.1)':
   '@react-aria/focus@3.17.1(react@18.3.1)':
     dependencies:
     dependencies:
@@ -25017,7 +25078,7 @@ snapshots:
   '@solana/buffer-layout-utils@0.2.0(bufferutil@4.0.7)(encoding@0.1.13)(utf-8-validate@5.0.10)':
   '@solana/buffer-layout-utils@0.2.0(bufferutil@4.0.7)(encoding@0.1.13)(utf-8-validate@5.0.10)':
     dependencies:
     dependencies:
       '@solana/buffer-layout': 4.0.1
       '@solana/buffer-layout': 4.0.1
-      '@solana/web3.js': 1.90.0(bufferutil@4.0.7)(encoding@0.1.13)(utf-8-validate@5.0.10)
+      '@solana/web3.js': 1.92.3(bufferutil@4.0.7)(encoding@0.1.13)(utf-8-validate@5.0.10)
       bigint-buffer: 1.1.5
       bigint-buffer: 1.1.5
       bignumber.js: 9.1.2
       bignumber.js: 9.1.2
     transitivePeerDependencies:
     transitivePeerDependencies:
@@ -25028,7 +25089,7 @@ snapshots:
   '@solana/buffer-layout-utils@0.2.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)':
   '@solana/buffer-layout-utils@0.2.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)':
     dependencies:
     dependencies:
       '@solana/buffer-layout': 4.0.1
       '@solana/buffer-layout': 4.0.1
-      '@solana/web3.js': 1.90.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)
+      '@solana/web3.js': 1.92.3(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)
       bigint-buffer: 1.1.5
       bigint-buffer: 1.1.5
       bignumber.js: 9.1.2
       bignumber.js: 9.1.2
     transitivePeerDependencies:
     transitivePeerDependencies:
@@ -25040,22 +25101,33 @@ snapshots:
     dependencies:
     dependencies:
       buffer: 6.0.3
       buffer: 6.0.3
 
 
-  '@solana/spl-token@0.3.7(@solana/web3.js@1.90.0(bufferutil@4.0.7)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.7)(encoding@0.1.13)(utf-8-validate@5.0.10)':
+  '@solana/spl-token@0.3.7(@solana/web3.js@1.90.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)':
+    dependencies:
+      '@solana/buffer-layout': 4.0.1
+      '@solana/buffer-layout-utils': 0.2.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)
+      '@solana/web3.js': 1.90.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)
+      buffer: 6.0.3
+    transitivePeerDependencies:
+      - bufferutil
+      - encoding
+      - utf-8-validate
+
+  '@solana/spl-token@0.3.7(@solana/web3.js@1.92.3(bufferutil@4.0.7)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.7)(encoding@0.1.13)(utf-8-validate@5.0.10)':
     dependencies:
     dependencies:
       '@solana/buffer-layout': 4.0.1
       '@solana/buffer-layout': 4.0.1
       '@solana/buffer-layout-utils': 0.2.0(bufferutil@4.0.7)(encoding@0.1.13)(utf-8-validate@5.0.10)
       '@solana/buffer-layout-utils': 0.2.0(bufferutil@4.0.7)(encoding@0.1.13)(utf-8-validate@5.0.10)
-      '@solana/web3.js': 1.90.0(bufferutil@4.0.7)(encoding@0.1.13)(utf-8-validate@5.0.10)
+      '@solana/web3.js': 1.92.3(bufferutil@4.0.7)(encoding@0.1.13)(utf-8-validate@5.0.10)
       buffer: 6.0.3
       buffer: 6.0.3
     transitivePeerDependencies:
     transitivePeerDependencies:
       - bufferutil
       - bufferutil
       - encoding
       - encoding
       - utf-8-validate
       - utf-8-validate
 
 
-  '@solana/spl-token@0.3.7(@solana/web3.js@1.90.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)':
+  '@solana/spl-token@0.3.7(@solana/web3.js@1.92.3(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)':
     dependencies:
     dependencies:
       '@solana/buffer-layout': 4.0.1
       '@solana/buffer-layout': 4.0.1
       '@solana/buffer-layout-utils': 0.2.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)
       '@solana/buffer-layout-utils': 0.2.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)
-      '@solana/web3.js': 1.90.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)
+      '@solana/web3.js': 1.92.3(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)
       buffer: 6.0.3
       buffer: 6.0.3
     transitivePeerDependencies:
     transitivePeerDependencies:
       - bufferutil
       - bufferutil
@@ -25561,7 +25633,7 @@ snapshots:
       - encoding
       - encoding
       - utf-8-validate
       - utf-8-validate
 
 
-  '@solana/web3.js@1.90.0(bufferutil@4.0.7)(encoding@0.1.13)(utf-8-validate@5.0.10)':
+  '@solana/web3.js@1.90.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)':
     dependencies:
     dependencies:
       '@babel/runtime': 7.23.9
       '@babel/runtime': 7.23.9
       '@noble/curves': 1.4.0
       '@noble/curves': 1.4.0
@@ -25574,7 +25646,7 @@ snapshots:
       bs58: 4.0.1
       bs58: 4.0.1
       buffer: 6.0.3
       buffer: 6.0.3
       fast-stable-stringify: 1.0.0
       fast-stable-stringify: 1.0.0
-      jayson: 4.1.0(bufferutil@4.0.7)(utf-8-validate@5.0.10)
+      jayson: 4.1.0(bufferutil@4.0.8)(utf-8-validate@5.0.10)
       node-fetch: 2.7.0(encoding@0.1.13)
       node-fetch: 2.7.0(encoding@0.1.13)
       rpc-websockets: 7.5.1
       rpc-websockets: 7.5.1
       superstruct: 0.14.2
       superstruct: 0.14.2
@@ -25583,9 +25655,9 @@ snapshots:
       - encoding
       - encoding
       - utf-8-validate
       - utf-8-validate
 
 
-  '@solana/web3.js@1.90.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)':
+  '@solana/web3.js@1.92.3(bufferutil@4.0.7)(encoding@0.1.13)(utf-8-validate@5.0.10)':
     dependencies:
     dependencies:
-      '@babel/runtime': 7.23.9
+      '@babel/runtime': 7.24.7
       '@noble/curves': 1.4.0
       '@noble/curves': 1.4.0
       '@noble/hashes': 1.4.0
       '@noble/hashes': 1.4.0
       '@solana/buffer-layout': 4.0.1
       '@solana/buffer-layout': 4.0.1
@@ -25596,10 +25668,10 @@ snapshots:
       bs58: 4.0.1
       bs58: 4.0.1
       buffer: 6.0.3
       buffer: 6.0.3
       fast-stable-stringify: 1.0.0
       fast-stable-stringify: 1.0.0
-      jayson: 4.1.0(bufferutil@4.0.8)(utf-8-validate@5.0.10)
+      jayson: 4.1.0(bufferutil@4.0.7)(utf-8-validate@5.0.10)
       node-fetch: 2.7.0(encoding@0.1.13)
       node-fetch: 2.7.0(encoding@0.1.13)
-      rpc-websockets: 7.5.1
-      superstruct: 0.14.2
+      rpc-websockets: 8.0.1
+      superstruct: 1.0.4
     transitivePeerDependencies:
     transitivePeerDependencies:
       - bufferutil
       - bufferutil
       - encoding
       - encoding
@@ -25627,6 +25699,28 @@ snapshots:
       - encoding
       - encoding
       - utf-8-validate
       - utf-8-validate
 
 
+  '@solana/web3.js@1.93.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)':
+    dependencies:
+      '@babel/runtime': 7.24.7
+      '@noble/curves': 1.4.0
+      '@noble/hashes': 1.4.0
+      '@solana/buffer-layout': 4.0.1
+      agentkeepalive: 4.5.0
+      bigint-buffer: 1.1.5
+      bn.js: 5.2.1
+      borsh: 0.7.0
+      bs58: 4.0.1
+      buffer: 6.0.3
+      fast-stable-stringify: 1.0.0
+      jayson: 4.1.0(bufferutil@4.0.8)(utf-8-validate@5.0.10)
+      node-fetch: 2.7.0(encoding@0.1.13)
+      rpc-websockets: 9.0.2
+      superstruct: 1.0.4
+    transitivePeerDependencies:
+      - bufferutil
+      - encoding
+      - utf-8-validate
+
   '@solflare-wallet/metamask-sdk@1.0.3(@solana/web3.js@1.90.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10))':
   '@solflare-wallet/metamask-sdk@1.0.3(@solana/web3.js@1.90.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10))':
     dependencies:
     dependencies:
       '@solana/wallet-standard-features': 1.2.0
       '@solana/wallet-standard-features': 1.2.0
@@ -25650,7 +25744,7 @@ snapshots:
   '@sqds/mesh@1.0.6(bufferutil@4.0.7)(encoding@0.1.13)(utf-8-validate@5.0.10)':
   '@sqds/mesh@1.0.6(bufferutil@4.0.7)(encoding@0.1.13)(utf-8-validate@5.0.10)':
     dependencies:
     dependencies:
       '@project-serum/anchor': 0.25.0(bufferutil@4.0.7)(encoding@0.1.13)(utf-8-validate@5.0.10)
       '@project-serum/anchor': 0.25.0(bufferutil@4.0.7)(encoding@0.1.13)(utf-8-validate@5.0.10)
-      '@solana/web3.js': 1.90.0(bufferutil@4.0.7)(encoding@0.1.13)(utf-8-validate@5.0.10)
+      '@solana/web3.js': 1.92.3(bufferutil@4.0.7)(encoding@0.1.13)(utf-8-validate@5.0.10)
       bn.js: 5.2.1
       bn.js: 5.2.1
     transitivePeerDependencies:
     transitivePeerDependencies:
       - bufferutil
       - bufferutil
@@ -25660,7 +25754,7 @@ snapshots:
   '@sqds/mesh@1.0.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)':
   '@sqds/mesh@1.0.6(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)':
     dependencies:
     dependencies:
       '@project-serum/anchor': 0.25.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)
       '@project-serum/anchor': 0.25.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)
-      '@solana/web3.js': 1.90.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)
+      '@solana/web3.js': 1.92.3(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)
       bn.js: 5.2.1
       bn.js: 5.2.1
     transitivePeerDependencies:
     transitivePeerDependencies:
       - bufferutil
       - bufferutil
@@ -25753,7 +25847,7 @@ snapshots:
 
 
   '@strike-protocols/solana-wallet-adapter@0.1.8(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)':
   '@strike-protocols/solana-wallet-adapter@0.1.8(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)':
     dependencies:
     dependencies:
-      '@solana/web3.js': 1.90.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)
+      '@solana/web3.js': 1.92.3(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)
       bs58: 4.0.1
       bs58: 4.0.1
       eventemitter3: 4.0.7
       eventemitter3: 4.0.7
       uuid: 8.3.2
       uuid: 8.3.2
@@ -25948,6 +26042,10 @@ snapshots:
 
 
   '@swc/counter@0.1.3': {}
   '@swc/counter@0.1.3': {}
 
 
+  '@swc/helpers@0.5.11':
+    dependencies:
+      tslib: 2.6.3
+
   '@swc/helpers@0.5.5':
   '@swc/helpers@0.5.5':
     dependencies:
     dependencies:
       '@swc/counter': 0.1.3
       '@swc/counter': 0.1.3
@@ -26150,7 +26248,7 @@ snapshots:
   '@toruslabs/solana-embed@0.3.4(@babel/runtime@7.24.7)(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)':
   '@toruslabs/solana-embed@0.3.4(@babel/runtime@7.24.7)(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)':
     dependencies:
     dependencies:
       '@babel/runtime': 7.24.7
       '@babel/runtime': 7.24.7
-      '@solana/web3.js': 1.90.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)
+      '@solana/web3.js': 1.92.3(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)
       '@toruslabs/base-controllers': 2.9.0(@babel/runtime@7.24.7)(bufferutil@4.0.8)(utf-8-validate@5.0.10)
       '@toruslabs/base-controllers': 2.9.0(@babel/runtime@7.24.7)(bufferutil@4.0.8)(utf-8-validate@5.0.10)
       '@toruslabs/http-helpers': 3.4.0(@babel/runtime@7.24.7)
       '@toruslabs/http-helpers': 3.4.0(@babel/runtime@7.24.7)
       '@toruslabs/openlogin-jrpc': 3.2.0(@babel/runtime@7.24.7)
       '@toruslabs/openlogin-jrpc': 3.2.0(@babel/runtime@7.24.7)
@@ -26768,6 +26866,10 @@ snapshots:
     dependencies:
     dependencies:
       '@types/node': 20.14.2
       '@types/node': 20.14.2
 
 
+  '@types/pino@7.0.5':
+    dependencies:
+      pino: 9.2.0
+
   '@types/prettier@2.7.2': {}
   '@types/prettier@2.7.2': {}
 
 
   '@types/prop-types@15.7.12': {}
   '@types/prop-types@15.7.12': {}
@@ -26906,7 +27008,7 @@ snapshots:
       '@typescript-eslint/type-utils': 6.21.0(eslint@8.57.0)(typescript@5.4.5)
       '@typescript-eslint/type-utils': 6.21.0(eslint@8.57.0)(typescript@5.4.5)
       '@typescript-eslint/utils': 6.21.0(eslint@8.57.0)(typescript@5.4.5)
       '@typescript-eslint/utils': 6.21.0(eslint@8.57.0)(typescript@5.4.5)
       '@typescript-eslint/visitor-keys': 6.21.0
       '@typescript-eslint/visitor-keys': 6.21.0
-      debug: 4.3.4(supports-color@8.1.1)
+      debug: 4.3.4
       eslint: 8.57.0
       eslint: 8.57.0
       graphemer: 1.4.0
       graphemer: 1.4.0
       ignore: 5.3.1
       ignore: 5.3.1
@@ -27006,7 +27108,7 @@ snapshots:
       '@typescript-eslint/types': 6.21.0
       '@typescript-eslint/types': 6.21.0
       '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.4.5)
       '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.4.5)
       '@typescript-eslint/visitor-keys': 6.21.0
       '@typescript-eslint/visitor-keys': 6.21.0
-      debug: 4.3.4(supports-color@8.1.1)
+      debug: 4.3.4
       eslint: 8.57.0
       eslint: 8.57.0
     optionalDependencies:
     optionalDependencies:
       typescript: 5.4.5
       typescript: 5.4.5
@@ -27110,7 +27212,7 @@ snapshots:
     dependencies:
     dependencies:
       '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.4.5)
       '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.4.5)
       '@typescript-eslint/utils': 6.21.0(eslint@8.57.0)(typescript@5.4.5)
       '@typescript-eslint/utils': 6.21.0(eslint@8.57.0)(typescript@5.4.5)
-      debug: 4.3.4(supports-color@8.1.1)
+      debug: 4.3.4
       eslint: 8.57.0
       eslint: 8.57.0
       ts-api-utils: 1.3.0(typescript@5.4.5)
       ts-api-utils: 1.3.0(typescript@5.4.5)
     optionalDependencies:
     optionalDependencies:
@@ -27186,7 +27288,7 @@ snapshots:
     dependencies:
     dependencies:
       '@typescript-eslint/types': 6.21.0
       '@typescript-eslint/types': 6.21.0
       '@typescript-eslint/visitor-keys': 6.21.0
       '@typescript-eslint/visitor-keys': 6.21.0
-      debug: 4.3.4(supports-color@8.1.1)
+      debug: 4.3.4
       globby: 11.1.0
       globby: 11.1.0
       is-glob: 4.0.3
       is-glob: 4.0.3
       minimatch: 9.0.3
       minimatch: 9.0.3
@@ -28587,7 +28689,7 @@ snapshots:
 
 
   axios@0.21.4:
   axios@0.21.4:
     dependencies:
     dependencies:
-      follow-redirects: 1.15.6(debug@4.3.4)
+      follow-redirects: 1.15.6
     transitivePeerDependencies:
     transitivePeerDependencies:
       - debug
       - debug
 
 
@@ -28605,7 +28707,7 @@ snapshots:
 
 
   axios@0.27.2:
   axios@0.27.2:
     dependencies:
     dependencies:
-      follow-redirects: 1.15.6(debug@4.3.4)
+      follow-redirects: 1.15.6
       form-data: 4.0.0
       form-data: 4.0.0
     transitivePeerDependencies:
     transitivePeerDependencies:
       - debug
       - debug
@@ -29586,6 +29688,8 @@ snapshots:
 
 
   colorette@1.4.0: {}
   colorette@1.4.0: {}
 
 
+  colorette@2.0.20: {}
+
   colors@1.0.3: {}
   colors@1.0.3: {}
 
 
   colors@1.4.0: {}
   colors@1.4.0: {}
@@ -30206,6 +30310,8 @@ snapshots:
 
 
   dateformat@3.0.3: {}
   dateformat@3.0.3: {}
 
 
+  dateformat@4.6.3: {}
+
   dayjs@1.11.11: {}
   dayjs@1.11.11: {}
 
 
   debounce-fn@4.0.0:
   debounce-fn@4.0.0:
@@ -30242,6 +30348,10 @@ snapshots:
     optionalDependencies:
     optionalDependencies:
       supports-color: 8.1.1
       supports-color: 8.1.1
 
 
+  debug@4.3.4:
+    dependencies:
+      ms: 2.1.2
+
   debug@4.3.4(supports-color@8.1.1):
   debug@4.3.4(supports-color@8.1.1):
     dependencies:
     dependencies:
       ms: 2.1.2
       ms: 2.1.2
@@ -31384,7 +31494,7 @@ snapshots:
       ajv: 6.12.6
       ajv: 6.12.6
       chalk: 4.1.2
       chalk: 4.1.2
       cross-spawn: 7.0.3
       cross-spawn: 7.0.3
-      debug: 4.3.4(supports-color@8.1.1)
+      debug: 4.3.4
       doctrine: 3.0.0
       doctrine: 3.0.0
       escape-string-regexp: 4.0.0
       escape-string-regexp: 4.0.0
       eslint-scope: 7.2.2
       eslint-scope: 7.2.2
@@ -31516,7 +31626,7 @@ snapshots:
   eth-block-tracker@4.4.3(@babel/core@7.24.7):
   eth-block-tracker@4.4.3(@babel/core@7.24.7):
     dependencies:
     dependencies:
       '@babel/plugin-transform-runtime': 7.19.6(@babel/core@7.24.7)
       '@babel/plugin-transform-runtime': 7.19.6(@babel/core@7.24.7)
-      '@babel/runtime': 7.23.9
+      '@babel/runtime': 7.24.7
       eth-query: 2.1.2
       eth-query: 2.1.2
       json-rpc-random-id: 1.0.1
       json-rpc-random-id: 1.0.1
       pify: 3.0.0
       pify: 3.0.0
@@ -32022,6 +32132,8 @@ snapshots:
     dependencies:
     dependencies:
       pure-rand: 6.0.4
       pure-rand: 6.0.4
 
 
+  fast-copy@3.0.2: {}
+
   fast-deep-equal@3.1.3: {}
   fast-deep-equal@3.1.3: {}
 
 
   fast-glob@3.2.7:
   fast-glob@3.2.7:
@@ -32178,6 +32290,8 @@ snapshots:
 
 
   flow-parser@0.237.2: {}
   flow-parser@0.237.2: {}
 
 
+  follow-redirects@1.15.6: {}
+
   follow-redirects@1.15.6(debug@4.3.4):
   follow-redirects@1.15.6(debug@4.3.4):
     optionalDependencies:
     optionalDependencies:
       debug: 4.3.4(supports-color@8.1.1)
       debug: 4.3.4(supports-color@8.1.1)
@@ -32878,6 +32992,8 @@ snapshots:
       no-case: 2.3.2
       no-case: 2.3.2
       upper-case: 1.1.3
       upper-case: 1.1.3
 
 
+  help-me@5.0.0: {}
+
   hermes-estree@0.19.1: {}
   hermes-estree@0.19.1: {}
 
 
   hermes-estree@0.20.1: {}
   hermes-estree@0.20.1: {}
@@ -37417,6 +37533,23 @@ snapshots:
       readable-stream: 4.5.2
       readable-stream: 4.5.2
       split2: 4.2.0
       split2: 4.2.0
 
 
+  pino-pretty@11.2.1:
+    dependencies:
+      colorette: 2.0.20
+      dateformat: 4.6.3
+      fast-copy: 3.0.2
+      fast-safe-stringify: 2.1.1
+      help-me: 5.0.0
+      joycon: 3.1.1
+      minimist: 1.2.7
+      on-exit-leak-free: 2.1.2
+      pino-abstract-transport: 1.2.0
+      pump: 3.0.0
+      readable-stream: 4.5.2
+      secure-json-parse: 2.7.0
+      sonic-boom: 4.0.1
+      strip-json-comments: 3.1.1
+
   pino-std-serializers@4.0.0: {}
   pino-std-serializers@4.0.0: {}
 
 
   pino-std-serializers@7.0.0: {}
   pino-std-serializers@7.0.0: {}
@@ -38647,6 +38780,19 @@ snapshots:
       bufferutil: 4.0.8
       bufferutil: 4.0.8
       utf-8-validate: 5.0.10
       utf-8-validate: 5.0.10
 
 
+  rpc-websockets@9.0.2:
+    dependencies:
+      '@swc/helpers': 0.5.11
+      '@types/uuid': 8.3.4
+      '@types/ws': 8.5.4
+      buffer: 6.0.3
+      eventemitter3: 5.0.1
+      uuid: 8.3.2
+      ws: 8.17.0(bufferutil@4.0.8)(utf-8-validate@5.0.10)
+    optionalDependencies:
+      bufferutil: 4.0.8
+      utf-8-validate: 5.0.10
+
   rtcpeerconnection-shim@1.2.15:
   rtcpeerconnection-shim@1.2.15:
     dependencies:
     dependencies:
       sdp: 2.12.0
       sdp: 2.12.0
@@ -38767,6 +38913,8 @@ snapshots:
       node-addon-api: 5.1.0
       node-addon-api: 5.1.0
       node-gyp-build: 4.6.0
       node-gyp-build: 4.6.0
 
 
+  secure-json-parse@2.7.0: {}
+
   selfsigned@2.4.1:
   selfsigned@2.4.1:
     dependencies:
     dependencies:
       '@types/node-forge': 1.3.11
       '@types/node-forge': 1.3.11