/* eslint-disable @typescript-eslint/no-non-null-assertion */ /* eslint-disable @typescript-eslint/no-floating-promises */ /* eslint-disable unicorn/prefer-top-level-await */ /* eslint-disable @typescript-eslint/restrict-template-expressions */ /* eslint-disable no-console */ import { parseVaa } from "@certusone/wormhole-sdk"; import { decodeGovernancePayload } from "@pythnetwork/xc-admin-common"; import yargs from "yargs"; import { hideBin } from "yargs/helpers"; import { COMMON_DEPLOY_OPTIONS } from "./common"; import { toPrivateKey } from "../src/core/base"; import { executeVaa } from "../src/node/utils/executor"; import { SubmittedWormholeMessage } from "../src/node/utils/governance"; import { DefaultStore } from "../src/node/utils/store"; const parser = yargs(hideBin(process.argv)) .usage( "Tries to execute all vaas on a vault.\n" + "Useful for batch upgrades.\n" + "Usage: $0 --vault --private-key (--offset | --sequence ) [--dryrun]", ) .options({ vault: { type: "string", default: "mainnet", choices: ["mainnet", "devnet"], desc: "Which vault to use for fetching VAAs", }, "private-key": COMMON_DEPLOY_OPTIONS["private-key"], offset: { type: "number", desc: "Offset to use from the last executed sequence number", conflicts: ["sequence"], }, sequence: { type: "number", desc: "Specific sequence number to execute", conflicts: ["offset"], }, dryrun: { type: "boolean", default: false, desc: "Whether to execute the VAAs or just print them", }, }) .check((argv) => { if (!argv.offset && !argv.sequence) { throw new Error("Either --offset or --sequence must be provided"); } return true; }); async function main() { const argv = await parser.argv; const vault = argv.vault === "mainnet" ? DefaultStore.vaults[ "mainnet-beta_FVQyHcooAtThJ83XFrNnv74BcinbRH3bRmfFamAHBfuj" ] : DefaultStore.vaults.devnet_6baWtW1zTUVMSJHJQVxDUXWzqrQeYBr6mu31j3bTKwY3; console.log("Executing VAAs for vault", vault?.getId()); console.log( "Executing VAAs for emitter", // eslint-disable-next-line unicorn/no-await-expression-member (await vault?.getEmitter())?.toBase58(), ); let startSequenceNumber: number; let endSequenceNumber: number; if (argv.sequence !== undefined) { startSequenceNumber = argv.sequence; endSequenceNumber = argv.sequence; } else if (argv.offset === undefined) { // this is unreachable but it makes the typescript linter happy. throw new Error("Either --offset or --sequence must be provided"); } else { const lastSequenceNumber = await vault?.getLastSequenceNumber(); startSequenceNumber = (lastSequenceNumber ?? 0) - argv.offset; endSequenceNumber = lastSequenceNumber ?? 0; } console.log( `Going from sequence number ${startSequenceNumber} to ${endSequenceNumber}`, ); for ( let seqNumber = startSequenceNumber; seqNumber <= endSequenceNumber; seqNumber++ ) { const submittedWormholeMessage = new SubmittedWormholeMessage( await vault!.getEmitter(), seqNumber, vault!.cluster, ); const vaa = await submittedWormholeMessage.fetchVaa(); const decodedAction = decodeGovernancePayload(parseVaa(vaa).payload); if (!decodedAction) { console.log("Skipping unknown action for vaa", seqNumber); continue; } console.log("Executing vaa", seqNumber); console.log(decodedAction); if (!argv.dryrun) { await executeVaa(toPrivateKey(argv["private-key"]), vaa); } } } main();