diff --git a/contract_manager/scripts/common.ts b/contract_manager/scripts/common.ts index 9b6f099251..73c1cb7a07 100644 --- a/contract_manager/scripts/common.ts +++ b/contract_manager/scripts/common.ts @@ -78,6 +78,7 @@ export const COMMON_DEPLOY_OPTIONS = { }, chain: { type: "array", + string: true, demandOption: true, desc: "Chains to upload the contract on. Must be one of the chains available in the store", }, @@ -207,22 +208,6 @@ export function findEntropyContract(chain: EvmChain): EvmEntropyContract { throw new Error(`Entropy contract not found for chain ${chain.getId()}`); } -/** - * Finds an EVM chain by its name. - * @param {string} chainName The name of the chain to find. - * @returns The EVM chain instance. - * @throws {Error} an error if the chain is not found or is not an EVM chain. - */ -export function findEvmChain(chainName: string): EvmChain { - const chain = DefaultStore.chains[chainName]; - if (!chain) { - throw new Error(`Chain ${chainName} not found`); - } else if (!(chain instanceof EvmChain)) { - throw new Error(`Chain ${chainName} is not an EVM chain`); - } - return chain; -} - /** * Finds the wormhole contract for a given EVM chain. * @param {EvmChain} chain The EVM chain to find the wormhole contract for. diff --git a/contract_manager/scripts/deploy_evm_contract.ts b/contract_manager/scripts/deploy_evm_contract.ts index af598a04e5..5757f95fb3 100644 --- a/contract_manager/scripts/deploy_evm_contract.ts +++ b/contract_manager/scripts/deploy_evm_contract.ts @@ -33,25 +33,16 @@ const parser = yargs(hideBin(process.argv)) async function main() { const argv = await parser.argv; - const chain = DefaultStore.chains[argv.chain]; - - if (!chain) { - throw new Error(`Chain ${argv.contract} not found`); - } - - if (chain instanceof EvmChain) { - const artifact = JSON.parse(readFileSync(argv["std-output"], "utf8")); - const address = await chain.deploy( - toPrivateKey(argv["private-key"]), - artifact["abi"], - artifact["bytecode"], - argv["deploy-args"] || [] - ); - - console.log(`Deployed contract at ${address}`); - } else { - throw new Error("Chain is not an EVM chain"); - } + const chain = DefaultStore.getChainOrThrow(argv.chain, EvmChain); + const artifact = JSON.parse(readFileSync(argv["std-output"], "utf8")); + const address = await chain.deploy( + toPrivateKey(argv["private-key"]), + artifact["abi"], + artifact["bytecode"], + argv["deploy-args"] || [] + ); + + console.log(`Deployed contract at ${address}`); } main(); diff --git a/contract_manager/scripts/deploy_evm_entropy_contracts.ts b/contract_manager/scripts/deploy_evm_entropy_contracts.ts index c77f26a9f1..7b658eaa97 100644 --- a/contract_manager/scripts/deploy_evm_entropy_contracts.ts +++ b/contract_manager/scripts/deploy_evm_entropy_contracts.ts @@ -172,13 +172,7 @@ async function topupAccountsIfNecessary( async function main() { const argv = await parser.argv; - const chainName = argv.chain; - const chain = DefaultStore.chains[chainName]; - if (!chain) { - throw new Error(`Chain ${chainName} not found`); - } else if (!(chain instanceof EvmChain)) { - throw new Error(`Chain ${chainName} is not an EVM chain`); - } + const chain = DefaultStore.getChainOrThrow(argv.chain, EvmChain); const deploymentConfig: DeploymentConfig = { type: toDeploymentType(argv.deploymentType), diff --git a/contract_manager/scripts/deploy_evm_pricefeed_contracts.ts b/contract_manager/scripts/deploy_evm_pricefeed_contracts.ts index 6f48074a70..265d10a2f0 100644 --- a/contract_manager/scripts/deploy_evm_pricefeed_contracts.ts +++ b/contract_manager/scripts/deploy_evm_pricefeed_contracts.ts @@ -111,12 +111,7 @@ async function main() { const chainNames = argv.chain; for (const chainName of chainNames) { - const chain = DefaultStore.chains[chainName]; - if (!chain) { - throw new Error(`Chain ${chainName} not found`); - } else if (!(chain instanceof EvmChain)) { - throw new Error(`Chain ${chainName} is not an EVM chain`); - } + const chain = DefaultStore.getChainOrThrow(chainName, EvmChain); console.log(`Deploying price feed contracts on ${chain.getId()}...`); diff --git a/contract_manager/scripts/entropy_debug_reveal.ts b/contract_manager/scripts/entropy_debug_reveal.ts index 5102741465..36ebc38ae2 100644 --- a/contract_manager/scripts/entropy_debug_reveal.ts +++ b/contract_manager/scripts/entropy_debug_reveal.ts @@ -1,11 +1,7 @@ import yargs from "yargs"; import { hideBin } from "yargs/helpers"; -import { toPrivateKey } from "../src"; -import { - COMMON_DEPLOY_OPTIONS, - findEntropyContract, - findEvmChain, -} from "./common"; +import { DefaultStore, EvmChain, toPrivateKey } from "../src"; +import { COMMON_DEPLOY_OPTIONS, findEntropyContract } from "./common"; const parser = yargs(hideBin(process.argv)) .usage( @@ -29,7 +25,7 @@ const parser = yargs(hideBin(process.argv)) async function main() { const argv = await parser.argv; - const chain = findEvmChain(argv.chain); + const chain = DefaultStore.getChainOrThrow(argv.chain, EvmChain); const contract = findEntropyContract(chain); const sequenceNumber = argv.sequenceNumber; diff --git a/contract_manager/scripts/generate_governance_set_fee_config.sample.yaml b/contract_manager/scripts/generate_governance_set_fee_config.sample.yaml new file mode 100644 index 0000000000..848e701309 --- /dev/null +++ b/contract_manager/scripts/generate_governance_set_fee_config.sample.yaml @@ -0,0 +1,24 @@ +- chainName: aurora + fee: 3 + exponent: 12 +- chainName: avalanche + fee: 25 + exponent: 13 +- chainName: conflux_espace + fee: 1 + exponent: 17 +- chainName: cronos + fee: 6 + exponent: 16 +- chainName: meter + fee: 2 + exponent: 16 +- chainName: ronin + fee: 1 + exponent: 15 +- chainName: sei_evm_mainnet + fee: 1 + exponent: 16 +- chainName: shimmer + fee: 1 + exponent: 18 diff --git a/contract_manager/scripts/generate_governance_set_fee_payload.ts b/contract_manager/scripts/generate_governance_set_fee_payload.ts index d62000f906..b5ce99f62e 100644 --- a/contract_manager/scripts/generate_governance_set_fee_payload.ts +++ b/contract_manager/scripts/generate_governance_set_fee_payload.ts @@ -1,41 +1,62 @@ import yargs from "yargs"; import { hideBin } from "yargs/helpers"; -import { DefaultStore } from "../src"; -import { Chain } from "../src/chains"; +import { DefaultStore, loadHotWallet } from "../src"; +import { readFileSync } from "fs"; +import { parse } from "yaml"; const parser = yargs(hideBin(process.argv)) - .usage("Usage: $0 --chain --fee --exponent ") + .usage("Usage: $0 --config ") .options({ - chain: { + "config-path": { type: "string", demandOption: true, - desc: "Chain for which to generate the Set Fee payload", + desc: "Path to the config file", }, - fee: { - type: "number", + "ops-key-path": { + type: "string", demandOption: true, - desc: "The new fee to set", + desc: "Path to the ops key file", }, - exponent: { - type: "number", - demandOption: true, - desc: "The new fee exponent to set", + vault: { + type: "string", + default: "mainnet-beta_FVQyHcooAtThJ83XFrNnv74BcinbRH3bRmfFamAHBfuj", + desc: "Vault ID", }, }); async function main() { - const { chain, fee, exponent } = await parser.argv; + const { + "config-path": configPath, + "ops-key-path": opsKeyPath, + vault: vaultId, + } = await parser.argv; + + const config = parse(readFileSync(configPath, "utf8")); + + const updatePayloads: Buffer[] = []; + for (const setFeeEntry of config) { + const chain = DefaultStore.getChainOrThrow(setFeeEntry.chainName); + const payload = chain.generateGovernanceSetFeePayload( + setFeeEntry.fee, + setFeeEntry.exponent + ); + updatePayloads.push(payload); + console.log( + `Generated payload for chain ${setFeeEntry.chainName}:`, + payload.toString("hex") + ); + } + + const vault = DefaultStore.vaults[vaultId]; - const chain_obj = DefaultStore.chains[chain]; - if (!chain_obj) { - throw new Error(`Chain with ID '${chain}' does not exist.`); + if (!vault) { + throw new Error(`Vault with ID '${vaultId}' does not exist.`); } - const payload = chain_obj.generateGovernanceSetFeePayload(fee, exponent); - console.log( - `Generated payload for chain ${chain_obj}:`, - payload.toString("hex") - ); + const keypair = await loadHotWallet(opsKeyPath); + vault.connect(keypair); + const proposal = await vault.proposeWormholeMessage(updatePayloads); + console.log("Proposal address:", proposal.address.toBase58()); } main(); diff --git a/contract_manager/scripts/generate_upgrade_near_contract_proposal.ts b/contract_manager/scripts/generate_upgrade_near_contract_proposal.ts index d4241b7323..5b15834edc 100644 --- a/contract_manager/scripts/generate_upgrade_near_contract_proposal.ts +++ b/contract_manager/scripts/generate_upgrade_near_contract_proposal.ts @@ -31,10 +31,7 @@ async function main() { const argv = await parser.argv; // Near wormhole contracts have the same id on testnet and mainnet. - const chain = DefaultStore.chains.near; - if (!(chain instanceof NearChain)) { - throw new Error("Near chain is missing"); - } + const chain = DefaultStore.getChainOrThrow("near", NearChain); const vault = DefaultStore.vaults[ diff --git a/contract_manager/scripts/generate_upgrade_ton_contract_proposal.ts b/contract_manager/scripts/generate_upgrade_ton_contract_proposal.ts index 277ad611df..b5aa06e4c0 100644 --- a/contract_manager/scripts/generate_upgrade_ton_contract_proposal.ts +++ b/contract_manager/scripts/generate_upgrade_ton_contract_proposal.ts @@ -42,10 +42,10 @@ async function main() { const wormholeChainName = toChainName(chainId); // Get the TON chain instance from DefaultStore based on network - const chain = DefaultStore.chains[isMainnet ? "ton_mainnet" : "ton_testnet"]; - if (!chain || !(chain instanceof TonChain)) { - throw new Error(`Chain configuration not found for TON ${argv.network}`); - } + const chain = DefaultStore.getChainOrThrow( + isMainnet ? "ton_mainnet" : "ton_testnet", + TonChain + ); const vault = DefaultStore.vaults[ diff --git a/contract_manager/scripts/latency_entropy.ts b/contract_manager/scripts/latency_entropy.ts index 4c5d57220a..0f0e9266b0 100644 --- a/contract_manager/scripts/latency_entropy.ts +++ b/contract_manager/scripts/latency_entropy.ts @@ -1,11 +1,7 @@ import yargs from "yargs"; import { hideBin } from "yargs/helpers"; -import { toPrivateKey } from "../src"; -import { - COMMON_DEPLOY_OPTIONS, - findEntropyContract, - findEvmChain, -} from "./common"; +import { DefaultStore, EvmChain, toPrivateKey } from "../src"; +import { COMMON_DEPLOY_OPTIONS, findEntropyContract } from "./common"; const parser = yargs(hideBin(process.argv)) .usage( @@ -24,7 +20,7 @@ const parser = yargs(hideBin(process.argv)) async function main() { const argv = await parser.argv; - const chain = findEvmChain(argv.chain); + const chain = DefaultStore.getChainOrThrow(argv.chain, EvmChain); const contract = findEntropyContract(chain); const provider = await contract.getDefaultProvider(); diff --git a/contract_manager/scripts/latency_entropy_with_callback.ts b/contract_manager/scripts/latency_entropy_with_callback.ts index 97d75cad9f..33480efa5b 100644 --- a/contract_manager/scripts/latency_entropy_with_callback.ts +++ b/contract_manager/scripts/latency_entropy_with_callback.ts @@ -2,16 +2,12 @@ import yargs from "yargs"; import { hideBin } from "yargs/helpers"; import { DefaultStore, + EvmChain, EvmEntropyContract, PrivateKey, toPrivateKey, } from "../src"; -import { - COMMON_DEPLOY_OPTIONS, - findEntropyContract, - findEvmChain, -} from "./common"; -import Web3 from "web3"; +import { COMMON_DEPLOY_OPTIONS, findEntropyContract } from "./common"; const parser = yargs(hideBin(process.argv)) .usage( @@ -111,7 +107,7 @@ async function main() { } } } else if (argv.chain) { - const chain = findEvmChain(argv.chain); + const chain = DefaultStore.getChainOrThrow(argv.chain, EvmChain); const contract = findEntropyContract(chain); await testLatency(contract, privateKey); } diff --git a/contract_manager/scripts/list_entropy_contracts.ts b/contract_manager/scripts/list_entropy_contracts.ts index bbe1bebac5..1b03b2e844 100644 --- a/contract_manager/scripts/list_entropy_contracts.ts +++ b/contract_manager/scripts/list_entropy_contracts.ts @@ -15,7 +15,17 @@ const parser = yargs(hideBin(process.argv)) async function main() { const argv = await parser.argv; - const entries = []; + const entries: { + chain: string; + contract: string; + provider: string; + feeManager: string; + balance: string; + keeperBalance: string; + seq: string; + version: string; + }[] = []; + const keeperAddress = ENTROPY_DEFAULT_KEEPER[argv.testnet ? "testnet" : "mainnet"]; for (const contract of Object.values(DefaultStore.entropy_contracts)) { diff --git a/contract_manager/scripts/list_evm_contracts.ts b/contract_manager/scripts/list_evm_contracts.ts index 2c154dfd41..f0fa89c04d 100644 --- a/contract_manager/scripts/list_evm_contracts.ts +++ b/contract_manager/scripts/list_evm_contracts.ts @@ -14,7 +14,11 @@ const parser = yargs(hideBin(process.argv)) async function main() { const argv = await parser.argv; - const entries = []; + const entries: { + chain: string; + contract: string; + version: string; + }[] = []; for (const contract of Object.values(DefaultStore.contracts)) { if (contract.getChain().isMainnet() === argv.testnet) continue; if (contract instanceof EvmPriceFeedContract) { diff --git a/contract_manager/scripts/list_wormhole_contracts.ts b/contract_manager/scripts/list_wormhole_contracts.ts index 4ff064c1e5..c24647862f 100644 --- a/contract_manager/scripts/list_wormhole_contracts.ts +++ b/contract_manager/scripts/list_wormhole_contracts.ts @@ -14,7 +14,12 @@ const parser = yargs(hideBin(process.argv)) async function main() { const argv = await parser.argv; - const entries = []; + const entries: { + chain: string; + contract: string; + guardianSetIndex: number; + chainId: number; + }[] = []; for (const contract of Object.values(DefaultStore.wormhole_contracts)) { if ( contract instanceof EvmWormholeContract && diff --git a/contract_manager/scripts/load_test_entropy.ts b/contract_manager/scripts/load_test_entropy.ts index 83411b12b3..0ffab3bda5 100644 --- a/contract_manager/scripts/load_test_entropy.ts +++ b/contract_manager/scripts/load_test_entropy.ts @@ -1,16 +1,7 @@ import yargs from "yargs"; import { hideBin } from "yargs/helpers"; -import { - DefaultStore, - EvmEntropyContract, - PrivateKey, - toPrivateKey, -} from "../src"; -import { - COMMON_DEPLOY_OPTIONS, - findEntropyContract, - findEvmChain, -} from "./common"; +import { DefaultStore, EvmChain, toPrivateKey } from "../src"; +import { COMMON_DEPLOY_OPTIONS, findEntropyContract } from "./common"; import Web3 from "web3"; const parser = yargs(hideBin(process.argv)) @@ -23,12 +14,12 @@ const parser = yargs(hideBin(process.argv)) chain: { type: "string", demandOption: true, - desc: "test latency for the contract on this chain", + desc: "Chain to load test the entropy contract on", }, "tester-address": { type: "string", demandOption: true, - desc: "Tester contract address", + desc: "Address of the EntropyTester contract", }, "success-count": { type: "number", @@ -72,7 +63,7 @@ const ABI = [ async function main() { const argv = await parser.argv; const privateKey = toPrivateKey(argv.privateKey); - const chain = findEvmChain(argv.chain); + const chain = DefaultStore.getChainOrThrow(argv.chain, EvmChain); const contract = findEntropyContract(chain); const provider = await contract.getDefaultProvider(); const fee = await contract.getFee(provider); diff --git a/contract_manager/src/chains.ts b/contract_manager/src/chains.ts index 7dcef89d70..2f49c4543b 100644 --- a/contract_manager/src/chains.ts +++ b/contract_manager/src/chains.ts @@ -66,6 +66,7 @@ export type ChainConfig = Record & { }; export abstract class Chain extends Storable { public wormholeChainName: ChainName; + static type: string; /** * Creates a new Chain object diff --git a/contract_manager/src/store.ts b/contract_manager/src/store.ts index 1c787e3a24..8eb82bb7e0 100644 --- a/contract_manager/src/store.ts +++ b/contract_manager/src/store.ts @@ -221,6 +221,30 @@ export class Store { } }); } + + /** + * Returns the chain with the given ID, or throws an error if it doesn't exist or is not of the specified type. + * @param chainId The unique identifier of the chain to retrieve + * @param ChainClass Optional class to validate the chain type. + * @returns The chain instance of type T + * @throws Error if chain doesn't exist or is not of the specified type + * @template T Type of chain to return, extends base Chain class + */ + getChainOrThrow( + chainId: string, + ChainClass?: { new (...args: any[]): T; type: string } + ): T { + const chain = this.chains[chainId]; + if (!chain) { + throw new Error(`Chain with ID '${chainId}' does not exist.`); + } + if (ChainClass && !(chain instanceof ChainClass)) { + throw new Error( + `Chain with ID '${chainId}' is not of type ${ChainClass.type}.` + ); + } + return chain as T; + } } /**