check_proposal.ts 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  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. EvmSetWormholeAddress,
  9. EvmUpgradeContract,
  10. getProposalInstructions,
  11. MultisigParser,
  12. WormholeMultisigInstruction,
  13. } from "xc_admin_common";
  14. import SquadsMesh from "@sqds/mesh";
  15. import {
  16. getPythClusterApiUrl,
  17. PythCluster,
  18. } from "@pythnetwork/client/lib/cluster";
  19. import NodeWallet from "@coral-xyz/anchor/dist/cjs/nodewallet";
  20. import { AccountMeta, Keypair, PublicKey } from "@solana/web3.js";
  21. import { EvmContract, WormholeEvmContract } from "../src/contracts/evm";
  22. import Web3 from "web3";
  23. const parser = yargs(hideBin(process.argv))
  24. .usage("Usage: $0 --cluster <cluster_id> --proposal <proposal_address>")
  25. .options({
  26. cluster: {
  27. type: "string",
  28. demandOption: true,
  29. desc: "Multsig Cluster name to check proposal on can be one of [devnet, testnet, mainnet-beta]",
  30. },
  31. proposal: {
  32. type: "string",
  33. demandOption: true,
  34. desc: "The proposal address to check",
  35. },
  36. });
  37. async function main() {
  38. const argv = await parser.argv;
  39. const cluster = argv.cluster as PythCluster;
  40. const squad = SquadsMesh.endpoint(
  41. getPythClusterApiUrl(cluster),
  42. new NodeWallet(Keypair.generate()) // dummy wallet
  43. );
  44. const transaction = await squad.getTransaction(new PublicKey(argv.proposal));
  45. const instructions = await getProposalInstructions(squad, transaction);
  46. const multisigParser = MultisigParser.fromCluster(cluster);
  47. const parsedInstructions = instructions.map((instruction) => {
  48. return multisigParser.parseInstruction({
  49. programId: instruction.programId,
  50. data: instruction.data as Buffer,
  51. keys: instruction.keys as AccountMeta[],
  52. });
  53. });
  54. for (const instruction of parsedInstructions) {
  55. if (instruction instanceof WormholeMultisigInstruction) {
  56. if (instruction.governanceAction instanceof EvmSetWormholeAddress) {
  57. console.log(
  58. `Verifying EVM set wormhole address on ${instruction.governanceAction.targetChainId}`
  59. );
  60. for (const chain of Object.values(DefaultStore.chains)) {
  61. if (
  62. chain instanceof EvmChain &&
  63. chain.wormholeChainName ===
  64. instruction.governanceAction.targetChainId
  65. ) {
  66. const address = instruction.governanceAction.address;
  67. const contract = new WormholeEvmContract(chain, address);
  68. const currentIndex = await contract.getCurrentGuardianSetIndex();
  69. const guardianSet = await contract.getGuardianSet();
  70. const proxyContract = new EvmContract(chain, address);
  71. const proxyCode = await proxyContract.getCode();
  72. const receiverImplementation =
  73. await proxyContract.getImplementationAddress();
  74. const implementationCode = await new EvmContract(
  75. chain,
  76. receiverImplementation
  77. ).getCode();
  78. const proxyDigest = Web3.utils.keccak256(proxyCode);
  79. const implementationDigest =
  80. Web3.utils.keccak256(implementationCode);
  81. const guardianSetDigest = Web3.utils.keccak256(
  82. JSON.stringify(guardianSet)
  83. );
  84. console.log(
  85. `${chain.getId()} Address:\t\t${address}\nproxy digest:\t\t${proxyDigest}\nimplementation digest:\t${implementationDigest} \nguardian set index:\t${currentIndex} \nguardian set:\t\t${guardianSetDigest}`
  86. );
  87. }
  88. }
  89. }
  90. if (instruction.governanceAction instanceof EvmUpgradeContract) {
  91. console.log(
  92. `Verifying EVM Upgrade Contract on ${instruction.governanceAction.targetChainId}`
  93. );
  94. for (const chain of Object.values(DefaultStore.chains)) {
  95. if (
  96. chain instanceof EvmChain &&
  97. chain.isMainnet() === (cluster === "mainnet-beta") &&
  98. chain.wormholeChainName ===
  99. instruction.governanceAction.targetChainId
  100. ) {
  101. const address = instruction.governanceAction.address;
  102. const contract = new EvmContract(chain, address);
  103. const code = await contract.getCodeDigestWithoutAddress();
  104. // this should be the same keccak256 of the deployedCode property generated by truffle
  105. console.log(`${chain.getId()} Address:${address} digest:${code}`);
  106. }
  107. }
  108. }
  109. if (instruction.governanceAction instanceof CosmosUpgradeContract) {
  110. console.log(
  111. `Verifying Cosmos Upgrade Contract on ${instruction.governanceAction.targetChainId}`
  112. );
  113. for (const chain of Object.values(DefaultStore.chains)) {
  114. if (
  115. chain instanceof CosmWasmChain &&
  116. chain.wormholeChainName ===
  117. instruction.governanceAction.targetChainId
  118. ) {
  119. const codeId = instruction.governanceAction.codeId;
  120. const code = await chain.getCode(Number(codeId));
  121. // this should be the same checksums.txt in our release file
  122. console.log(
  123. `${chain.getId()} Code Id:${codeId} digest:${createHash("sha256")
  124. .update(code)
  125. .digest("hex")}`
  126. );
  127. }
  128. }
  129. }
  130. }
  131. }
  132. }
  133. main();