Fix CLI dry run flag handling (#3698)

### Description

- Fix dry run flag
- Prevent invalid selection in warp config create
- Improve logging of warp validation errors
- Avoid module-scoped logger in SDK
pull/3699/head
J M Rossy 6 months ago committed by GitHub
parent 8246f14d6d
commit bd6ca01fd4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 2
      typescript/cli/src/commands/options.ts
  2. 8
      typescript/cli/src/config/warp.ts
  3. 6
      typescript/cli/src/context/context.ts
  4. 2
      typescript/cli/src/send/transfer.ts
  5. 4
      typescript/cli/src/utils/chains.ts
  6. 20
      typescript/sdk/src/utils/fork.ts

@ -123,7 +123,7 @@ export const dryRunOption: Options = {
type: 'string', type: 'string',
description: description:
'Chain name to fork and simulate deployment. Please ensure an anvil node instance is running during execution via `anvil`.', 'Chain name to fork and simulate deployment. Please ensure an anvil node instance is running during execution via `anvil`.',
alias: ['d'], alias: 'd',
}; };
export const chainCommandOption: Options = { export const chainCommandOption: Options = {

@ -2,12 +2,14 @@ import { confirm, input } from '@inquirer/prompts';
import { ethers } from 'ethers'; import { ethers } from 'ethers';
import { import {
ChainMetadata,
TokenType, TokenType,
WarpCoreConfig, WarpCoreConfig,
WarpCoreConfigSchema, WarpCoreConfigSchema,
WarpRouteDeployConfig, WarpRouteDeployConfig,
WarpRouteDeployConfigSchema, WarpRouteDeployConfigSchema,
} from '@hyperlane-xyz/sdk'; } from '@hyperlane-xyz/sdk';
import { objFilter } from '@hyperlane-xyz/utils';
import { CommandContext } from '../context/types.js'; import { CommandContext } from '../context/types.js';
import { errorRed, logBlue, logGreen } from '../logger.js'; import { errorRed, logBlue, logGreen } from '../logger.js';
@ -66,8 +68,12 @@ export async function createWarpRouteDeployConfig({
? ethers.constants.AddressZero ? ethers.constants.AddressZero
: await input({ message: addressMessage }); : await input({ message: addressMessage });
const syntheticChains = await runMultiChainSelectionStep( const metadataWithoutBase = objFilter(
context.chainMetadata, context.chainMetadata,
(chain, _): _ is ChainMetadata => chain !== baseChain,
);
const syntheticChains = await runMultiChainSelectionStep(
metadataWithoutBase,
'Select chains to which the base token will be connected', 'Select chains to which the base token will be connected',
); );

@ -2,9 +2,11 @@ import { ethers } from 'ethers';
import { IRegistry } from '@hyperlane-xyz/registry'; import { IRegistry } from '@hyperlane-xyz/registry';
import { ChainName, MultiProvider } from '@hyperlane-xyz/sdk'; import { ChainName, MultiProvider } from '@hyperlane-xyz/sdk';
import { isNullish } from '@hyperlane-xyz/utils';
import { isSignCommand } from '../commands/signCommands.js'; import { isSignCommand } from '../commands/signCommands.js';
import { forkNetworkToMultiProvider } from '../deploy/dry-run.js'; import { forkNetworkToMultiProvider } from '../deploy/dry-run.js';
import { logBlue } from '../logger.js';
import { MergedRegistry } from '../registry/MergedRegistry.js'; import { MergedRegistry } from '../registry/MergedRegistry.js';
import { runSingleChainSelectionStep } from '../utils/chains.js'; import { runSingleChainSelectionStep } from '../utils/chains.js';
import { getImpersonatedSigner, getSigner } from '../utils/keys.js'; import { getImpersonatedSigner, getSigner } from '../utils/keys.js';
@ -16,7 +18,7 @@ import {
} from './types.js'; } from './types.js';
export async function contextMiddleware(argv: Record<string, any>) { export async function contextMiddleware(argv: Record<string, any>) {
const isDryRun = !!argv.dryRun; const isDryRun = !isNullish(argv.dryRun);
const requiresKey = isSignCommand(argv); const requiresKey = isSignCommand(argv);
const settings: ContextSettings = { const settings: ContextSettings = {
registryUri: argv.registry, registryUri: argv.registry,
@ -79,6 +81,8 @@ export async function getDryRunContext(
); );
} }
logBlue(`Dry-running against chain: ${chain}`);
const multiProvider = await getMultiProvider(registry); const multiProvider = await getMultiProvider(registry);
await forkNetworkToMultiProvider(multiProvider, chain); await forkNetworkToMultiProvider(multiProvider, chain);
const { key: impersonatedKey, signer: impersonatedSigner } = const { key: impersonatedKey, signer: impersonatedSigner } =

@ -138,7 +138,7 @@ async function executeDelivery({
sender: senderAddress, sender: senderAddress,
}); });
if (errors) { if (errors) {
logRed('Unable to validate transfer', errors); logRed('Error validating transfer', JSON.stringify(errors));
throw new Error('Error validating transfer'); throw new Error('Error validating transfer');
} }

@ -18,7 +18,7 @@ export async function runSingleChainSelectionStep(
const chain = (await select({ const chain = (await select({
message, message,
choices, choices,
pageSize: 20, pageSize: 30,
})) as string; })) as string;
handleNewChain([chain]); handleNewChain([chain]);
return chain; return chain;
@ -35,7 +35,7 @@ export async function runMultiChainSelectionStep(
const chains = (await checkbox({ const chains = (await checkbox({
message, message,
choices, choices,
pageSize: 20, pageSize: 30,
})) as string[]; })) as string[];
handleNewChain(chains); handleNewChain(chains);
if (requireMultiple && chains?.length < 2) { if (requireMultiple && chains?.length < 2) {

@ -5,8 +5,6 @@ import { Address, isValidAddressEvm, rootLogger } from '@hyperlane-xyz/utils';
import { MultiProvider } from '../providers/MultiProvider.js'; import { MultiProvider } from '../providers/MultiProvider.js';
import { ChainName } from '../types.js'; import { ChainName } from '../types.js';
const logger = rootLogger.child({ module: 'fork-utils' });
const ENDPOINT_PREFIX = 'http'; const ENDPOINT_PREFIX = 'http';
const DEFAULT_ANVIL_ENDPOINT = 'http://127.0.0.1:8545'; const DEFAULT_ANVIL_ENDPOINT = 'http://127.0.0.1:8545';
@ -21,7 +19,7 @@ export enum ANVIL_RPC_METHODS {
* Resets the local node to it's original state (anvil [31337] at block zero). * Resets the local node to it's original state (anvil [31337] at block zero).
*/ */
export const resetFork = async (anvilIPAddr?: string, anvilPort?: number) => { export const resetFork = async (anvilIPAddr?: string, anvilPort?: number) => {
logger.info(`Resetting forked network...`); rootLogger.info(`Resetting forked network...`);
const provider = getLocalProvider(anvilIPAddr, anvilPort); const provider = getLocalProvider(anvilIPAddr, anvilPort);
await provider.send(ANVIL_RPC_METHODS.RESET, [ await provider.send(ANVIL_RPC_METHODS.RESET, [
@ -32,7 +30,7 @@ export const resetFork = async (anvilIPAddr?: string, anvilPort?: number) => {
}, },
]); ]);
logger.info(`✅ Successfully reset forked network`); rootLogger.info(`✅ Successfully reset forked network`);
}; };
/** /**
@ -46,7 +44,7 @@ export const setFork = async (
anvilIPAddr?: string, anvilIPAddr?: string,
anvilPort?: number, anvilPort?: number,
) => { ) => {
logger.info(`Forking ${chain} for dry-run...`); rootLogger.info(`Forking ${chain} for dry-run...`);
const provider = getLocalProvider(anvilIPAddr, anvilPort); const provider = getLocalProvider(anvilIPAddr, anvilPort);
const currentChainMetadata = multiProvider.metadata[chain]; const currentChainMetadata = multiProvider.metadata[chain];
@ -61,7 +59,7 @@ export const setFork = async (
multiProvider.setProvider(chain, provider); multiProvider.setProvider(chain, provider);
logger.info(`✅ Successfully forked ${chain} for dry-run`); rootLogger.info(`✅ Successfully forked ${chain} for dry-run`);
}; };
/** /**
@ -74,12 +72,12 @@ export const impersonateAccount = async (
anvilIPAddr?: string, anvilIPAddr?: string,
anvilPort?: number, anvilPort?: number,
): Promise<providers.JsonRpcSigner> => { ): Promise<providers.JsonRpcSigner> => {
logger.info(`Impersonating account (${address})...`); rootLogger.info(`Impersonating account (${address})...`);
const provider = getLocalProvider(anvilIPAddr, anvilPort); const provider = getLocalProvider(anvilIPAddr, anvilPort);
await provider.send(ANVIL_RPC_METHODS.IMPERSONATE_ACCOUNT, [address]); await provider.send(ANVIL_RPC_METHODS.IMPERSONATE_ACCOUNT, [address]);
logger.info(`✅ Successfully impersonated account (${address})`); rootLogger.info(`✅ Successfully impersonated account (${address})`);
return provider.getSigner(address); return provider.getSigner(address);
}; };
@ -93,7 +91,7 @@ export const stopImpersonatingAccount = async (
anvilIPAddr?: string, anvilIPAddr?: string,
anvilPort?: number, anvilPort?: number,
) => { ) => {
logger.info(`Stopping account impersonation for address (${address})...`); rootLogger.info(`Stopping account impersonation for address (${address})...`);
if (isValidAddressEvm(address)) if (isValidAddressEvm(address))
throw new Error( throw new Error(
@ -105,7 +103,7 @@ export const stopImpersonatingAccount = async (
address.substring(2), address.substring(2),
]); ]);
logger.info( rootLogger.info(
`✅ Successfully stopped account impersonation for address (${address})`, `✅ Successfully stopped account impersonation for address (${address})`,
); );
}; };
@ -125,7 +123,7 @@ export const getLocalProvider = (
envUrl = `${ENDPOINT_PREFIX}${anvilIPAddr}:${anvilPort}`; envUrl = `${ENDPOINT_PREFIX}${anvilIPAddr}:${anvilPort}`;
if (urlOverride && !urlOverride.startsWith(ENDPOINT_PREFIX)) { if (urlOverride && !urlOverride.startsWith(ENDPOINT_PREFIX)) {
logger.warn( rootLogger.warn(
` Provided URL override (${urlOverride}) does not begin with ${ENDPOINT_PREFIX}. Defaulting to ${ ` Provided URL override (${urlOverride}) does not begin with ${ENDPOINT_PREFIX}. Defaulting to ${
envUrl ?? DEFAULT_ANVIL_ENDPOINT envUrl ?? DEFAULT_ANVIL_ENDPOINT
}`, }`,

Loading…
Cancel
Save