diff --git a/.changeset/ninety-seas-chew.md b/.changeset/ninety-seas-chew.md new file mode 100644 index 0000000000..96ed1aa57f --- /dev/null +++ b/.changeset/ninety-seas-chew.md @@ -0,0 +1,8 @@ +--- +'@hyperlane-xyz/cli': patch +--- + +Allow users to only configure validators for their chain + +- Don't restrict user to having two chains for ism config +- If the user accidentally picks two chains, we prompt them again to confirm if they don't want to use the hyperlane validators for their multisigConfig diff --git a/typescript/cli/src/config/ism.ts b/typescript/cli/src/config/ism.ts index eb18006077..9f4846ce83 100644 --- a/typescript/cli/src/config/ism.ts +++ b/typescript/cli/src/config/ism.ts @@ -107,7 +107,11 @@ export async function createIsmConfigMap({ }) { logBlue('Creating a new ISM config'); const customChains = readChainConfigsIfExists(chainConfigPath); - const chains = await runMultiChainSelectionStep(customChains); + const chains = await runMultiChainSelectionStep( + customChains, + 'Select chains to configure ISM for', + true, + ); const result: ZodIsmConfigMap = {}; for (const chain of chains) { diff --git a/typescript/cli/src/config/multisig.ts b/typescript/cli/src/config/multisig.ts index d68497195c..19ef2ad5ac 100644 --- a/typescript/cli/src/config/multisig.ts +++ b/typescript/cli/src/config/multisig.ts @@ -1,4 +1,4 @@ -import { input } from '@inquirer/prompts'; +import { confirm, input } from '@inquirer/prompts'; import { z } from 'zod'; import { ChainMap, MultisigConfig } from '@hyperlane-xyz/sdk'; @@ -10,6 +10,7 @@ import { } from '@hyperlane-xyz/utils'; import { errorRed, log, logBlue, logGreen } from '../../logger.js'; +import { sdkContractAddressesMap } from '../context.js'; import { runMultiChainSelectionStep } from '../utils/chains.js'; import { FileFormat, mergeYamlOrJson, readYamlOrJson } from '../utils/files.js'; @@ -72,6 +73,9 @@ export async function createMultisigConfig({ chainConfigPath: string; }) { logBlue('Creating a new multisig config'); + log( + 'Select your own chain below to run your own validators. If you want to reuse existing Hyperlane validators instead of running your own, do not select additional mainnet or testnet chains.', + ); const customChains = readChainConfigsIfExists(chainConfigPath); const chains = await runMultiChainSelectionStep(customChains); @@ -84,6 +88,12 @@ export async function createMultisigConfig({ result[chain] = lastConfig; continue; } + if (Object.keys(sdkContractAddressesMap).includes(chain)) { + const reuseCoreConfig = await confirm({ + message: 'Use existing Hyperlane validators for this chain?', + }); + if (reuseCoreConfig) continue; + } const thresholdInput = await input({ message: 'Enter threshold of signers (number)', @@ -111,7 +121,7 @@ export async function createMultisigConfig({ mergeYamlOrJson(outPath, result, format); } else { errorRed( - `Multisig config is invalid, please see https://github.com/hyperlane-xyz/hyperlane-monorepo/blob/main/typescript/cli/examples/multisig-ism.yaml for an example`, + `Multisig config is invalid, please see https://github.com/hyperlane-xyz/hyperlane-monorepo/blob/main/typescript/cli/examples/ism.yaml for an example`, ); throw new Error('Invalid multisig config'); } diff --git a/typescript/cli/src/deploy/agent.ts b/typescript/cli/src/deploy/agent.ts index 7fbf97ade0..0680eaf0bc 100644 --- a/typescript/cli/src/deploy/agent.ts +++ b/typescript/cli/src/deploy/agent.ts @@ -33,6 +33,7 @@ export async function runKurtosisAgentDeploy({ const selectedRelayChains = await runMultiChainSelectionStep( customChains, 'Select chains to relay between', + true, ); relayChains = selectedRelayChains.join(','); } diff --git a/typescript/cli/src/deploy/core.ts b/typescript/cli/src/deploy/core.ts index 44cd8f12c8..f4b6701450 100644 --- a/typescript/cli/src/deploy/core.ts +++ b/typescript/cli/src/deploy/core.ts @@ -85,6 +85,7 @@ export async function runCoreDeploy({ chains = await runMultiChainSelectionStep( customChains, 'Select chains to connect', + true, ); } const artifacts = await runArtifactStep(chains, artifactsPath); diff --git a/typescript/cli/src/utils/chains.ts b/typescript/cli/src/utils/chains.ts index e824ae57b3..e273498abd 100644 --- a/typescript/cli/src/utils/chains.ts +++ b/typescript/cli/src/utils/chains.ts @@ -5,7 +5,6 @@ import chalk from 'chalk'; import { ChainMap, ChainMetadata, - ChainName, mainnetChainsMetadata, testnetChainsMetadata, } from '@hyperlane-xyz/sdk'; @@ -33,9 +32,9 @@ export async function runSingleChainSelectionStep( export async function runMultiChainSelectionStep( customChains: ChainMap, message = 'Select chains', - chainsToFilterOut: ChainName[] = [], + requireMultiple = false, ) { - const choices = getChainChoices(customChains, chainsToFilterOut); + const choices = getChainChoices(customChains); while (true) { logTip('Use SPACE key to select chains, then press ENTER'); const chains = (await checkbox({ @@ -44,19 +43,17 @@ export async function runMultiChainSelectionStep( pageSize: 20, })) as string[]; handleNewChain(chains); - if (chains?.length >= 2) return chains; - else logRed('Please select at least 2 chains'); + if (requireMultiple && chains?.length < 2) { + logRed('Please select at least 2 chains'); + continue; + } + return chains; } } -function getChainChoices( - customChains: ChainMap, - chainsToFilterOut: ChainName[] = [], -) { +function getChainChoices(customChains: ChainMap) { const chainsToChoices = (chains: ChainMetadata[]) => - chains - .filter((chain) => !chainsToFilterOut.includes(chain.name)) - .map((c) => ({ name: c.name, value: c.name })); + chains.map((c) => ({ name: c.name, value: c.name })); const choices: Parameters['0']['choices'] = [ new Separator('--Custom Chains--'), ...chainsToChoices(Object.values(customChains)),