import yargs from "yargs"; import { hideBin } from "yargs/helpers"; import { CosmWasmChain, EvmChain } from "../src/chains"; import { createHash } from "crypto"; import { DefaultStore } from "../src/store"; import { CosmosUpgradeContract, EvmUpgradeContract, getProposalInstructions, MultisigParser, WormholeMultisigInstruction, } from "xc_admin_common"; import SquadsMesh from "@sqds/mesh"; import { getPythClusterApiUrl, PythCluster, } from "@pythnetwork/client/lib/cluster"; import NodeWallet from "@coral-xyz/anchor/dist/cjs/nodewallet"; import { AccountMeta, Keypair, PublicKey } from "@solana/web3.js"; import { EvmContract } from "../src/contracts/evm"; const parser = yargs(hideBin(process.argv)) .scriptName("check_proposal.ts") .usage("Usage: $0 --cluster --proposal ") .options({ cluster: { type: "string", demandOption: true, desc: "Multsig Cluster name to check proposal on can be one of [devnet, testnet, mainnet-beta]", }, proposal: { type: "string", demandOption: true, desc: "The proposal address to check", }, }); async function main() { const argv = await parser.argv; const cluster = argv.cluster as PythCluster; const squad = SquadsMesh.endpoint( getPythClusterApiUrl(cluster), new NodeWallet(Keypair.generate()) // dummy wallet ); const transaction = await squad.getTransaction(new PublicKey(argv.proposal)); const instructions = await getProposalInstructions(squad, transaction); const multisigParser = MultisigParser.fromCluster(cluster); const parsedInstructions = instructions.map((instruction) => { return multisigParser.parseInstruction({ programId: instruction.programId, data: instruction.data as Buffer, keys: instruction.keys as AccountMeta[], }); }); for (const instruction of parsedInstructions) { if (instruction instanceof WormholeMultisigInstruction) { if (instruction.governanceAction instanceof EvmUpgradeContract) { console.log( `Verifying EVM Upgrade Contract on ${instruction.governanceAction.targetChainId}` ); for (const chain of Object.values(DefaultStore.chains)) { if ( chain instanceof EvmChain && chain.isMainnet() === (cluster === "mainnet-beta") && chain.wormholeChainName === instruction.governanceAction.targetChainId ) { const address = instruction.governanceAction.address; const contract = new EvmContract(chain, address); const code = await contract.getCodeDigestWithoutAddress(); // this should be the same keccak256 of the deployedCode property generated by truffle console.log(`Address:${address} digest:${code}`); } } } if (instruction.governanceAction instanceof CosmosUpgradeContract) { console.log( `Verifying Cosmos Upgrade Contract on ${instruction.governanceAction.targetChainId}` ); for (const chain of Object.values(DefaultStore.chains)) { if ( chain instanceof CosmWasmChain && chain.wormholeChainName === instruction.governanceAction.targetChainId ) { const codeId = instruction.governanceAction.codeId; const code = await chain.getCode(Number(codeId)); // this should be the same checksums.txt in our release file console.log( `Code Id:${codeId} digest:${createHash("sha256") .update(code) .digest("hex")}` ); } } } } } } main();