check_proposal.ts 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. import yargs from "yargs";
  2. import { hideBin } from "yargs/helpers";
  3. import { CosmWasmChain, EvmChain } from "../src/chains";
  4. import { createHash } from "crypto";
  5. import { DefaultStore } from "../src/store";
  6. import {
  7. CosmosUpgradeContract,
  8. EvmUpgradeContract,
  9. getProposalInstructions,
  10. MultisigParser,
  11. WormholeMultisigInstruction,
  12. } from "xc_admin_common";
  13. import SquadsMesh from "@sqds/mesh";
  14. import {
  15. getPythClusterApiUrl,
  16. PythCluster,
  17. } from "@pythnetwork/client/lib/cluster";
  18. import NodeWallet from "@coral-xyz/anchor/dist/cjs/nodewallet";
  19. import { AccountMeta, Keypair, PublicKey } from "@solana/web3.js";
  20. import { EvmContract } from "../src/contracts/evm";
  21. const parser = yargs(hideBin(process.argv))
  22. .scriptName("check_proposal.ts")
  23. .usage("Usage: $0 --cluster <cluster_id> --proposal <proposal_address>")
  24. .options({
  25. cluster: {
  26. type: "string",
  27. demandOption: true,
  28. desc: "Multsig Cluster name to check proposal on can be one of [devnet, testnet, mainnet-beta]",
  29. },
  30. proposal: {
  31. type: "string",
  32. demandOption: true,
  33. desc: "The proposal address to check",
  34. },
  35. });
  36. async function main() {
  37. const argv = await parser.argv;
  38. const cluster = argv.cluster as PythCluster;
  39. const squad = SquadsMesh.endpoint(
  40. getPythClusterApiUrl(cluster),
  41. new NodeWallet(Keypair.generate()) // dummy wallet
  42. );
  43. const transaction = await squad.getTransaction(new PublicKey(argv.proposal));
  44. const instructions = await getProposalInstructions(squad, transaction);
  45. const multisigParser = MultisigParser.fromCluster(cluster);
  46. const parsedInstructions = instructions.map((instruction) => {
  47. return multisigParser.parseInstruction({
  48. programId: instruction.programId,
  49. data: instruction.data as Buffer,
  50. keys: instruction.keys as AccountMeta[],
  51. });
  52. });
  53. for (const instruction of parsedInstructions) {
  54. if (instruction instanceof WormholeMultisigInstruction) {
  55. if (instruction.governanceAction instanceof EvmUpgradeContract) {
  56. console.log(
  57. `Verifying EVM Upgrade Contract on ${instruction.governanceAction.targetChainId}`
  58. );
  59. for (const chain of Object.values(DefaultStore.chains)) {
  60. if (
  61. chain instanceof EvmChain &&
  62. chain.isMainnet() === (cluster === "mainnet-beta") &&
  63. chain.wormholeChainName ===
  64. instruction.governanceAction.targetChainId
  65. ) {
  66. const address = instruction.governanceAction.address;
  67. const contract = new EvmContract(chain, address);
  68. const code = await contract.getCodeDigestWithoutAddress();
  69. // this should be the same keccak256 of the deployedCode property generated by truffle
  70. console.log(`Address:${address} digest:${code}`);
  71. }
  72. }
  73. }
  74. if (instruction.governanceAction instanceof CosmosUpgradeContract) {
  75. console.log(
  76. `Verifying Cosmos Upgrade Contract on ${instruction.governanceAction.targetChainId}`
  77. );
  78. for (const chain of Object.values(DefaultStore.chains)) {
  79. if (
  80. chain instanceof CosmWasmChain &&
  81. chain.wormholeChainName ===
  82. instruction.governanceAction.targetChainId
  83. ) {
  84. const codeId = instruction.governanceAction.codeId;
  85. const code = await chain.getCode(Number(codeId));
  86. // this should be the same checksums.txt in our release file
  87. console.log(
  88. `Code Id:${codeId} digest:${createHash("sha256")
  89. .update(code)
  90. .digest("hex")}`
  91. );
  92. }
  93. }
  94. }
  95. }
  96. }
  97. }
  98. main();