UNPKG

cosmic-interchain-cli

Version:

A command-line utility for Cosmic Wire's interchain messaging protocol

147 lines 5.83 kB
import { confirm } from '@inquirer/prompts'; import { GithubRegistry, MergedRegistry, } from '@hyperlane-xyz/registry'; import { FileSystemRegistry } from '@hyperlane-xyz/registry/fs'; import { MultiProvider, } from '@hyperlane-xyz/sdk'; import { isHttpsUrl, isNullish, rootLogger } from '@hyperlane-xyz/utils'; import { isSignCommand } from '../commands/signCommands.js'; import { forkNetworkToMultiProvider, verifyAnvil } from '../deploy/dry-run.js'; import { logBlue } from '../logger.js'; import { runSingleChainSelectionStep } from '../utils/chains.js'; import { detectAndConfirmOrPrompt } from '../utils/input.js'; import { getImpersonatedSigner, getSigner } from '../utils/keys.js'; export async function contextMiddleware(argv) { const isDryRun = !isNullish(argv.dryRun); const requiresKey = isSignCommand(argv); const settings = { registryUri: argv.registry, registryOverrideUri: argv.overrides, key: argv.key, fromAddress: argv.fromAddress, requiresKey, skipConfirmation: argv.yes, }; if (!isDryRun && settings.fromAddress) throw new Error("'--from-address' or '-f' should only be used for dry-runs"); const context = isDryRun ? await getDryRunContext(settings, argv.dryRun) : await getContext(settings); argv.context = context; } /** * Retrieves context for the user-selected command * @returns context for the current command */ export async function getContext({ registryUri, registryOverrideUri, key, requiresKey, skipConfirmation, }) { const registry = getRegistry(registryUri, registryOverrideUri); let signer = undefined; if (key || requiresKey) { ({ key, signer } = await getSigner({ key, skipConfirmation })); } const multiProvider = await getMultiProvider(registry, signer); return { registry, chainMetadata: multiProvider.metadata, multiProvider, key, signer, skipConfirmation: !!skipConfirmation, }; } /** * Retrieves dry-run context for the user-selected command * @returns dry-run context for the current command */ export async function getDryRunContext({ registryUri, registryOverrideUri, key, fromAddress, skipConfirmation, }, chain) { const registry = getRegistry(registryUri, registryOverrideUri); const chainMetadata = await registry.getMetadata(); if (!chain) { if (skipConfirmation) throw new Error('No chains provided'); chain = await runSingleChainSelectionStep(chainMetadata, 'Select chain to dry-run against:'); } logBlue(`Dry-running against chain: ${chain}`); await verifyAnvil(); let multiProvider = await getMultiProvider(registry); multiProvider = await forkNetworkToMultiProvider(multiProvider, chain); const { impersonatedKey, impersonatedSigner } = await getImpersonatedSigner({ fromAddress, key, skipConfirmation, }); multiProvider.setSharedSigner(impersonatedSigner); return { registry, chainMetadata: multiProvider.metadata, key: impersonatedKey, signer: impersonatedSigner, multiProvider: multiProvider, skipConfirmation: !!skipConfirmation, isDryRun: true, dryRunChain: chain, }; } /** * Creates a new MergedRegistry using the provided URIs * The intention of the MergedRegistry is to join the common data * from a primary URI (such as the Hyperlane default Github repo) * and an override one (such as a local directory) * @returns a new MergedRegistry */ function getRegistry(primaryRegistryUri, overrideRegistryUri) { const logger = rootLogger.child({ module: 'MergedRegistry' }); const registries = [primaryRegistryUri, overrideRegistryUri] .map((uri) => uri.trim()) .filter((uri) => !!uri) .map((uri, index) => { const childLogger = logger.child({ uri, index }); if (isHttpsUrl(uri)) { return new GithubRegistry({ uri, logger: childLogger }); } else { return new FileSystemRegistry({ uri, logger: childLogger, }); } }); return new MergedRegistry({ registries, logger, }); } /** * Retrieves a new MultiProvider based on all known chain metadata & custom user chains * @param customChains Custom chains specified by the user * @returns a new MultiProvider */ async function getMultiProvider(registry, signer) { const chainMetadata = await registry.getMetadata(); const multiProvider = new MultiProvider(chainMetadata); if (signer) multiProvider.setSharedSigner(signer); return multiProvider; } export async function getOrRequestApiKeys(chains, chainMetadata) { const apiKeys = {}; for (const chain of chains) { const wantApiKey = await confirm({ default: false, message: `Do you want to use an API key to verify on this (${chain}) chain's block explorer`, }); if (wantApiKey) { apiKeys[chain] = await detectAndConfirmOrPrompt(async () => { const blockExplorers = chainMetadata[chain].blockExplorers; if (!(blockExplorers && blockExplorers.length > 0)) return; for (const blockExplorer of blockExplorers) { /* The current apiKeys mapping only accepts one key, even if there are multiple explorer options present. */ if (blockExplorer.apiKey) return blockExplorer.apiKey; } return undefined; }, `Enter an API key for the ${chain} explorer`, `${chain} api key`, `${chain} metadata blockExplorers config`); } } return apiKeys; } //# sourceMappingURL=context.js.map