pyth-crosschain/contract_manager/scripts/check_proposal.ts

140 lines
5.4 KiB
TypeScript

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,
EvmSetWormholeAddress,
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, WormholeEvmContract } from "../src/contracts/evm";
import Web3 from "web3";
const parser = yargs(hideBin(process.argv))
.usage("Usage: $0 --cluster <cluster_id> --proposal <proposal_address>")
.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 EvmSetWormholeAddress) {
console.log(
`Verifying EVM set wormhole address 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 WormholeEvmContract(chain, address);
const currentIndex = await contract.getCurrentGuardianSetIndex();
const guardianSet = await contract.getGuardianSet();
const proxyContract = new EvmContract(chain, address);
const proxyCode = await proxyContract.getCode();
const receiverImplementation =
await proxyContract.getImplementationAddress();
const implementationCode = await new EvmContract(
chain,
receiverImplementation
).getCode();
const proxyDigest = Web3.utils.keccak256(proxyCode);
const implementationDigest =
Web3.utils.keccak256(implementationCode);
const guardianSetDigest = Web3.utils.keccak256(
JSON.stringify(guardianSet)
);
console.log(
`${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}`
);
}
}
}
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(`${chain.getId()} 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(
`${chain.getId()} Code Id:${codeId} digest:${createHash("sha256")
.update(code)
.digest("hex")}`
);
}
}
}
}
}
}
main();