import yargs from "yargs"; import { hideBin } from "yargs/helpers"; import { DefaultStore } from "../src/store"; import { SubmittedWormholeMessage, Vault } from "../src/governance"; import { parseVaa } from "@certusone/wormhole-sdk"; import { decodeGovernancePayload } from "xc_admin_common"; import { toPrivateKey } from "../src"; 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); // eslint-disable-next-line no-constant-condition 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( toPrivateKey(argv["private-key"]), vaa ); } else { console.log( `vaa is not for this chain (${ contract.getChain().wormholeChainName } != ${action.targetChainId}, skipping` ); } lastExecuted++; } } main();