From ff77561960cdecd6092756dae709474dd424cdbe Mon Sep 17 00:00:00 2001 From: Mohammad Amin Khashkhashi Moghaddam Date: Fri, 28 Jul 2023 16:41:41 +0200 Subject: [PATCH] Add sample script that syncs governance vaas for a contract (#989) --- .../scripts/sync_governance_vaas.ts | 105 ++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 contract_manager/scripts/sync_governance_vaas.ts diff --git a/contract_manager/scripts/sync_governance_vaas.ts b/contract_manager/scripts/sync_governance_vaas.ts new file mode 100644 index 00000000..66dc7d9d --- /dev/null +++ b/contract_manager/scripts/sync_governance_vaas.ts @@ -0,0 +1,105 @@ +import yargs from "yargs"; +import { hideBin } from "yargs/helpers"; +import { DefaultStore } from "../src/store"; +import { PriceServiceConnection } from "@pythnetwork/price-service-client"; +import { SubmittedWormholeMessage, Vault } from "../src/governance"; +import { parseVaa } from "@certusone/wormhole-sdk"; +import { decodeGovernancePayload } from "xc_admin_common"; + +const parser = yargs(hideBin(process.argv)) + .usage( + "Tries to execute all vaas on a contract.\n" + + "Useful for recently deployed contracts.\n" + + "Usage: $0 --contract --private-key " + ) + .options({ + contract: { + type: "string", + demandOption: true, + desc: "Contract to execute governance vaas for", + }, + "private-key": { + type: "string", + demandOption: true, + desc: "Private key to sign the transactions executing the governance VAAs. Hex format, without 0x prefix.", + }, + offset: { + type: "number", + desc: "Starting sequence number to use, if not provided will start from contract last executed governance sequence number", + }, + }); + +async function main() { + const argv = await parser.argv; + const contract = DefaultStore.contracts[argv.contract]; + if (!contract) { + throw new Error(`Contract ${argv.contract} not found`); + } + const governanceSource = await contract.getGovernanceDataSource(); + const mainnetVault = + DefaultStore.vaults[ + "mainnet-beta_FVQyHcooAtThJ83XFrNnv74BcinbRH3bRmfFamAHBfuj" + ]; + const devnetVault = + DefaultStore.vaults["devnet_6baWtW1zTUVMSJHJQVxDUXWzqrQeYBr6mu31j3bTKwY3"]; + let matchedVault: Vault; + if ( + (await devnetVault.getEmitter()).toBuffer().toString("hex") === + governanceSource.emitterAddress + ) { + console.log("devnet multisig matches governance source"); + matchedVault = devnetVault; + } else if ( + (await mainnetVault.getEmitter()).toBuffer().toString("hex") === + governanceSource.emitterAddress + ) { + console.log("mainnet multisig matches governance source"); + matchedVault = mainnetVault; + } else { + throw new Error( + "can not find a multisig that matches the governance source of the contract" + ); + } + let lastExecuted = await contract.getLastExecutedGovernanceSequence(); + console.log("last executed governance sequence", lastExecuted); + if (argv.offset && argv.offset > lastExecuted) { + console.log("skipping to offset", argv.offset); + lastExecuted = argv.offset - 1; + } + console.log("Starting from sequence number", lastExecuted); + while (true) { + const submittedWormholeMessage = new SubmittedWormholeMessage( + await matchedVault.getEmitter(), + lastExecuted + 1, + matchedVault.cluster + ); + let vaa: Buffer; + try { + vaa = await submittedWormholeMessage.fetchVaa(); + } catch (e) { + console.log(e); + console.log("no vaa found for sequence", lastExecuted + 1); + break; + } + const parsedVaa = parseVaa(vaa); + const action = decodeGovernancePayload(parsedVaa.payload); + if (!action) { + console.log("can not decode vaa, skipping"); + } else if ( + action.targetChainId === "unset" || + contract.getChain().wormholeChainName === action.targetChainId + ) { + console.log("executing vaa", lastExecuted + 1); + await contract.executeGovernanceInstruction(argv["private-key"], vaa); + } else { + console.log( + `vaa is not for this chain (${ + contract.getChain().wormholeChainName + } != ${action.targetChainId}, skipping` + ); + } + lastExecuted++; + } +} + +main();