update_all_pricefeeds.ts 3.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. /* eslint-disable @typescript-eslint/restrict-template-expressions */
  2. /* eslint-disable no-console */
  3. /* eslint-disable @typescript-eslint/prefer-nullish-coalescing */
  4. import type { PriceFeedMetadata } from "@pythnetwork/hermes-client";
  5. import { HermesClient } from "@pythnetwork/hermes-client";
  6. import yargs from "yargs";
  7. import { hideBin } from "yargs/helpers";
  8. import { toPrivateKey } from "../src/core/base";
  9. import { DefaultStore } from "../src/node/utils/store";
  10. const parser = yargs(hideBin(process.argv))
  11. .usage("Update the set of price feeds in a network. Usage: $0")
  12. .options({
  13. "private-key": {
  14. type: "string",
  15. demandOption: true,
  16. desc: "Private key to sign the transactions with",
  17. },
  18. contract: {
  19. type: "string",
  20. demandOption: true,
  21. desc: "Contract to update price feeds for (e.g mumbai_0xff1a0f4744e8582DF1aE09D5611b887B6a12925C)",
  22. },
  23. endpoint: {
  24. type: "string",
  25. desc: "Hermes endpoint to use, defaults to https://hermes.pyth.network",
  26. },
  27. encoding: {
  28. type: "string",
  29. desc: "Encoding to use for the price feeds (hex or base64), defaults to hex",
  30. choices: ["hex", "base64"],
  31. default: "hex",
  32. },
  33. "chunk-size": {
  34. type: "number",
  35. desc: "Chunk size to use for the price feeds, defaults to 150",
  36. default: 150,
  37. },
  38. });
  39. // This script is intended to update all pricefeeds after we deploy pyth pricefeeds contract.
  40. // It will fetch all pricefeeds from hermes and update the pricefeeds contract with the new pricefeeds.
  41. async function main() {
  42. const argv = await parser.argv;
  43. let priceFeedsMetadata: PriceFeedMetadata[] = [];
  44. const client = new HermesClient(
  45. argv.endpoint || "https://hermes.pyth.network",
  46. );
  47. const contract = DefaultStore.contracts[argv.contract];
  48. const privateKey = toPrivateKey(argv["private-key"]);
  49. const encoding = argv.encoding || "hex";
  50. priceFeedsMetadata = await client.getPriceFeeds();
  51. const priceFeedIds = priceFeedsMetadata.map((feed) => feed.id);
  52. console.log(`Fetched ${priceFeedIds.length} price feed IDs`);
  53. // We can adjust the chunk size based on the chain. Don't exceed 150 for now.
  54. // TODO: Add a check for the chain's block gas limit and adjust the chunk size accordingly.
  55. const chunkSize = argv.chunkSize;
  56. for (let i = 0; i < priceFeedIds.length; i += chunkSize) {
  57. console.log(
  58. `Processing chunk ${i / chunkSize + 1} of ${Math.ceil(
  59. priceFeedIds.length / chunkSize,
  60. )}`,
  61. );
  62. const chunk = priceFeedIds.slice(i, i + chunkSize);
  63. console.log(`length: ${chunk.length}`);
  64. const updates = await client.getLatestPriceUpdates(chunk, {
  65. parsed: false,
  66. });
  67. console.log(
  68. await contract?.executeUpdatePriceFeed(
  69. privateKey,
  70. updates.binary.data.map((update) =>
  71. encoding === "hex"
  72. ? Buffer.from(update, "hex")
  73. : Buffer.from(update, "base64"),
  74. ),
  75. ),
  76. );
  77. // Wait for 2 seconds to avoid rate limiting and nonce collision
  78. await new Promise((resolve) => setTimeout(resolve, 2000));
  79. }
  80. }
  81. // eslint-disable-next-line @typescript-eslint/no-floating-promises, unicorn/prefer-top-level-await
  82. main();