sync_governance_vaas.ts 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. /* eslint-disable no-console */
  2. /* eslint-disable @typescript-eslint/no-non-null-assertion */
  3. /* eslint-disable unicorn/no-await-expression-member */
  4. import { parseVaa } from "@certusone/wormhole-sdk";
  5. import { decodeGovernancePayload } from "@pythnetwork/xc-admin-common";
  6. import yargs from "yargs";
  7. import { hideBin } from "yargs/helpers";
  8. import { toPrivateKey } from "../src/core/base";
  9. import { SubmittedWormholeMessage, Vault } from "../src/node/utils/governance";
  10. import { DefaultStore } from "../src/node/utils/store";
  11. const parser = yargs(hideBin(process.argv))
  12. .usage(
  13. "Tries to execute all vaas on a contract.\n" +
  14. "Useful for recently deployed contracts.\n" +
  15. "Usage: $0 --contract <contract_id> --private-key <private-key>",
  16. )
  17. .options({
  18. contract: {
  19. type: "string",
  20. demandOption: true,
  21. desc: "Contract to execute governance vaas for",
  22. },
  23. "private-key": {
  24. type: "string",
  25. demandOption: true,
  26. desc: "Private key to sign the transactions executing the governance VAAs. Hex format, without 0x prefix.",
  27. },
  28. offset: {
  29. type: "number",
  30. desc: "Starting sequence number to use, if not provided will start from contract last executed governance sequence number",
  31. },
  32. });
  33. async function main() {
  34. const argv = await parser.argv;
  35. const contract = DefaultStore.contracts[argv.contract];
  36. if (!contract) {
  37. throw new Error(`Contract ${argv.contract} not found`);
  38. }
  39. const governanceSource = await contract.getGovernanceDataSource();
  40. const mainnetVault =
  41. DefaultStore.vaults[
  42. "mainnet-beta_FVQyHcooAtThJ83XFrNnv74BcinbRH3bRmfFamAHBfuj"
  43. ]!;
  44. const devnetVault =
  45. DefaultStore.vaults.devnet_6baWtW1zTUVMSJHJQVxDUXWzqrQeYBr6mu31j3bTKwY3!;
  46. let matchedVault: Vault;
  47. if (
  48. (await devnetVault.getEmitter()).toBuffer().toString("hex") ===
  49. governanceSource.emitterAddress
  50. ) {
  51. console.log("devnet multisig matches governance source");
  52. matchedVault = devnetVault;
  53. } else if (
  54. (await mainnetVault.getEmitter()).toBuffer().toString("hex") ===
  55. governanceSource.emitterAddress
  56. ) {
  57. console.log("mainnet multisig matches governance source");
  58. matchedVault = mainnetVault;
  59. } else {
  60. throw new Error(
  61. "can not find a multisig that matches the governance source of the contract",
  62. );
  63. }
  64. let lastExecuted = await contract.getLastExecutedGovernanceSequence();
  65. console.log("last executed governance sequence", lastExecuted);
  66. if (argv.offset && argv.offset > lastExecuted) {
  67. console.log("skipping to offset", argv.offset);
  68. lastExecuted = argv.offset - 1;
  69. }
  70. console.log("Starting from sequence number", lastExecuted);
  71. // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
  72. while (true) {
  73. const submittedWormholeMessage = new SubmittedWormholeMessage(
  74. await matchedVault.getEmitter(),
  75. lastExecuted + 1,
  76. matchedVault.cluster,
  77. );
  78. let vaa: Buffer;
  79. try {
  80. vaa = await submittedWormholeMessage.fetchVaa();
  81. } catch (error) {
  82. console.log(error);
  83. console.log("no vaa found for sequence", lastExecuted + 1);
  84. break;
  85. }
  86. const parsedVaa = parseVaa(vaa);
  87. const action = decodeGovernancePayload(parsedVaa.payload);
  88. if (!action) {
  89. console.log("can not decode vaa, skipping");
  90. } else if (
  91. action.targetChainId === "unset" ||
  92. contract.getChain().wormholeChainName === action.targetChainId
  93. ) {
  94. console.log("executing vaa", lastExecuted + 1);
  95. await contract.executeGovernanceInstruction(
  96. toPrivateKey(argv["private-key"]),
  97. vaa,
  98. );
  99. } else {
  100. console.log(
  101. `vaa is not for this chain (${
  102. contract.getChain().wormholeChainName
  103. } != ${action.targetChainId}, skipping`,
  104. );
  105. }
  106. lastExecuted++;
  107. }
  108. }
  109. // eslint-disable-next-line @typescript-eslint/no-floating-promises, unicorn/prefer-top-level-await
  110. main();