migrate fork util to SDK (#3625)

### Description

* Migrates fork util to SDK

### Drive-by changes

* None

### Related issues

- Fixes https://github.com/hyperlane-xyz/hyperlane-monorepo/issues/3624

### Backward compatibility

* Yes

### Testing

* Manual on core & warp
pull/3654/head
Noah Bayindirli 🥂 6 months ago committed by GitHub
parent e10735a718
commit 450e8e0d55
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 6
      .changeset/nice-pianos-tease.md
  2. 13
      typescript/cli/src/deploy/dry-run.ts
  3. 7
      typescript/cli/src/deploy/utils.ts
  4. 3
      typescript/cli/src/utils/keys.ts
  5. 8
      typescript/sdk/src/index.ts
  6. 55
      typescript/sdk/src/utils/fork.ts

@ -0,0 +1,6 @@
---
'@hyperlane-xyz/cli': minor
'@hyperlane-xyz/sdk': minor
---
Migrate fork util from CLI to SDK. Anvil IP & Port are now optionally passed into fork util by client.

@ -1,13 +1,14 @@
import { MultiProvider } from '@hyperlane-xyz/sdk';
import { Command } from '../commands/deploy.js';
import { logGray, logGreen, warnYellow } from '../logger.js';
import { import {
ANVIL_RPC_METHODS, ANVIL_RPC_METHODS,
MultiProvider,
getLocalProvider, getLocalProvider,
resetFork, resetFork,
setFork, setFork,
} from '../utils/fork.js'; } from '@hyperlane-xyz/sdk';
import { Command } from '../commands/deploy.js';
import { logGray, logGreen, warnYellow } from '../logger.js';
import { ENV } from '../utils/env.js';
import { toUpperCamelCase } from './utils.js'; import { toUpperCamelCase } from './utils.js';
@ -33,7 +34,7 @@ export async function forkNetworkToMultiProvider(
export async function verifyAnvil() { export async function verifyAnvil() {
logGray('🔎 Verifying anvil node is running...'); logGray('🔎 Verifying anvil node is running...');
const provider = getLocalProvider(); const provider = getLocalProvider(ENV.ANVIL_IP_ADDR, ENV.ANVIL_PORT);
try { try {
await provider.send(ANVIL_RPC_METHODS.NODE_INFO, []); await provider.send(ANVIL_RPC_METHODS.NODE_INFO, []);
} catch (error: any) { } catch (error: any) {

@ -6,6 +6,7 @@ import {
IsmConfig, IsmConfig,
MultiProvider, MultiProvider,
MultisigConfig, MultisigConfig,
getLocalProvider,
} from '@hyperlane-xyz/sdk'; } from '@hyperlane-xyz/sdk';
import { Address, ProtocolType } from '@hyperlane-xyz/utils'; import { Address, ProtocolType } from '@hyperlane-xyz/utils';
@ -13,7 +14,7 @@ import { Command } from '../commands/deploy.js';
import { parseIsmConfig } from '../config/ism.js'; import { parseIsmConfig } from '../config/ism.js';
import { log, logGreen, logPink } from '../logger.js'; import { log, logGreen, logPink } from '../logger.js';
import { assertGasBalances } from '../utils/balances.js'; import { assertGasBalances } from '../utils/balances.js';
import { getLocalProvider } from '../utils/fork.js'; import { ENV } from '../utils/env.js';
import { assertSigner } from '../utils/keys.js'; import { assertSigner } from '../utils/keys.js';
import { completeDryRun } from './dry-run.js'; import { completeDryRun } from './dry-run.js';
@ -111,7 +112,7 @@ export async function prepareDeploy(
await Promise.all( await Promise.all(
chains.map(async (chain: ChainName) => { chains.map(async (chain: ChainName) => {
const provider = dryRun const provider = dryRun
? getLocalProvider() ? getLocalProvider(ENV.ANVIL_IP_ADDR, ENV.ANVIL_PORT)
: multiProvider.getProvider(chain); : multiProvider.getProvider(chain);
const currentBalance = await provider.getBalance(userAddress); const currentBalance = await provider.getBalance(userAddress);
initialBalances[chain] = currentBalance; initialBalances[chain] = currentBalance;
@ -131,7 +132,7 @@ export async function completeDeploy(
if (chains.length > 0) logPink(` Gas Usage Statistics`); if (chains.length > 0) logPink(` Gas Usage Statistics`);
for (const chain of chains) { for (const chain of chains) {
const provider = dryRun const provider = dryRun
? getLocalProvider() ? getLocalProvider(ENV.ANVIL_IP_ADDR, ENV.ANVIL_PORT)
: multiProvider.getProvider(chain); : multiProvider.getProvider(chain);
const currentBalance = await provider.getBalance(userAddress); const currentBalance = await provider.getBalance(userAddress);
const balanceDelta = initialBalances[chain].sub(currentBalance); const balanceDelta = initialBalances[chain].sub(currentBalance);

@ -1,12 +1,11 @@
import { input } from '@inquirer/prompts'; import { input } from '@inquirer/prompts';
import { ethers, providers } from 'ethers'; import { ethers, providers } from 'ethers';
import { impersonateAccount } from '@hyperlane-xyz/sdk';
import { Address, ensure0x } from '@hyperlane-xyz/utils'; import { Address, ensure0x } from '@hyperlane-xyz/utils';
import { ContextSettings, KeyConfig } from '../context.js'; import { ContextSettings, KeyConfig } from '../context.js';
import { impersonateAccount } from './fork.js';
const ETHEREUM_ADDRESS_LENGTH = 42; const ETHEREUM_ADDRESS_LENGTH = 42;
const DEFAULT_KEY_TYPE = 'private key'; const DEFAULT_KEY_TYPE = 'private key';
const IMPERSONATED_KEY_TYPE = 'address'; const IMPERSONATED_KEY_TYPE = 'address';

@ -442,6 +442,14 @@ export {
} from './types.js'; } from './types.js';
export { MultiGeneric } from './utils/MultiGeneric.js'; export { MultiGeneric } from './utils/MultiGeneric.js';
export { filterByChains } from './utils/filter.js'; export { filterByChains } from './utils/filter.js';
export {
ANVIL_RPC_METHODS,
resetFork,
setFork,
impersonateAccount,
stopImpersonatingAccount,
getLocalProvider,
} from './utils/fork.js';
export { multisigIsmVerificationCost } from './utils/ism.js'; export { multisigIsmVerificationCost } from './utils/ism.js';
export { export {
SealevelAccountDataWrapper, SealevelAccountDataWrapper,

@ -1,12 +1,11 @@
import { providers } from 'ethers'; import { providers } from 'ethers';
import { ChainName, MultiProvider } from '@hyperlane-xyz/sdk'; import { Address, isValidAddressEvm, rootLogger } from '@hyperlane-xyz/utils';
import { Address, isValidAddressEvm } from '@hyperlane-xyz/utils';
import { logGray, logGreen } from '../logger.js'; import { MultiProvider } from '../providers/MultiProvider.js';
import { warnYellow } from '../logger.js'; import { ChainName } from '../types.js';
import { ENV } from './env.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';
@ -19,12 +18,12 @@ export enum ANVIL_RPC_METHODS {
} }
/** /**
* Resets the local node to it's original start (anvil [31337] at block zero). * Resets the local node to it's original state (anvil [31337] at block zero).
*/ */
export const resetFork = async () => { export const resetFork = async (anvilIPAddr?: string, anvilPort?: number) => {
logGray(`Resetting forked network...`); logger.info(`Resetting forked network...`);
const provider = getLocalProvider(); const provider = getLocalProvider(anvilIPAddr, anvilPort);
await provider.send(ANVIL_RPC_METHODS.RESET, [ await provider.send(ANVIL_RPC_METHODS.RESET, [
{ {
forking: { forking: {
@ -33,7 +32,7 @@ export const resetFork = async () => {
}, },
]); ]);
logGreen(`✅ Successfully reset forked network`); logger.info(`✅ Successfully reset forked network`);
}; };
/** /**
@ -44,10 +43,12 @@ export const resetFork = async () => {
export const setFork = async ( export const setFork = async (
multiProvider: MultiProvider, multiProvider: MultiProvider,
chain: ChainName | number, chain: ChainName | number,
anvilIPAddr?: string,
anvilPort?: number,
) => { ) => {
logGray(`Forking ${chain} for dry-run...`); logger.info(`Forking ${chain} for dry-run...`);
const provider = getLocalProvider(); const provider = getLocalProvider(anvilIPAddr, anvilPort);
const currentChainMetadata = multiProvider.metadata[chain]; const currentChainMetadata = multiProvider.metadata[chain];
await provider.send(ANVIL_RPC_METHODS.RESET, [ await provider.send(ANVIL_RPC_METHODS.RESET, [
@ -60,7 +61,7 @@ export const setFork = async (
multiProvider.setProvider(chain, provider); multiProvider.setProvider(chain, provider);
logGreen(`✅ Successfully forked ${chain} for dry-run`); logger.info(`✅ Successfully forked ${chain} for dry-run`);
}; };
/** /**
@ -70,13 +71,15 @@ export const setFork = async (
*/ */
export const impersonateAccount = async ( export const impersonateAccount = async (
address: Address, address: Address,
anvilIPAddr?: string,
anvilPort?: number,
): Promise<providers.JsonRpcSigner> => { ): Promise<providers.JsonRpcSigner> => {
logGray(`Impersonating account (${address})...`); logger.info(`Impersonating account (${address})...`);
const provider = getLocalProvider(); const provider = getLocalProvider(anvilIPAddr, anvilPort);
await provider.send(ANVIL_RPC_METHODS.IMPERSONATE_ACCOUNT, [address]); await provider.send(ANVIL_RPC_METHODS.IMPERSONATE_ACCOUNT, [address]);
logGreen(`✅ Successfully impersonated account (${address})`); logger.info(`✅ Successfully impersonated account (${address})`);
return provider.getSigner(address); return provider.getSigner(address);
}; };
@ -85,20 +88,24 @@ export const impersonateAccount = async (
* Stops account impersonation. * Stops account impersonation.
* @param address the address to stop impersonating * @param address the address to stop impersonating
*/ */
export const stopImpersonatingAccount = async (address: Address) => { export const stopImpersonatingAccount = async (
logGray(`Stopping account impersonation for address (${address})...`); address: Address,
anvilIPAddr?: string,
anvilPort?: number,
) => {
logger.info(`Stopping account impersonation for address (${address})...`);
if (isValidAddressEvm(address)) if (isValidAddressEvm(address))
throw new Error( throw new Error(
`Cannot stop account impersonation: invalid address format: ${address}`, `Cannot stop account impersonation: invalid address format: ${address}`,
); );
const provider = getLocalProvider(); const provider = getLocalProvider(anvilIPAddr, anvilPort);
await provider.send(ANVIL_RPC_METHODS.STOP_IMPERSONATING_ACCOUNT, [ await provider.send(ANVIL_RPC_METHODS.STOP_IMPERSONATING_ACCOUNT, [
address.substring(2), address.substring(2),
]); ]);
logGreen( logger.info(
`✅ Successfully stopped account impersonation for address (${address})`, `✅ Successfully stopped account impersonation for address (${address})`,
); );
}; };
@ -109,14 +116,16 @@ export const stopImpersonatingAccount = async (address: Address) => {
* @returns a local JSON-RPC provider * @returns a local JSON-RPC provider
*/ */
export const getLocalProvider = ( export const getLocalProvider = (
anvilIPAddr?: string,
anvilPort?: number,
urlOverride?: string, urlOverride?: string,
): providers.JsonRpcProvider => { ): providers.JsonRpcProvider => {
let envUrl; let envUrl;
if (ENV.ANVIL_IP_ADDR && ENV.ANVIL_PORT) if (anvilIPAddr && anvilPort)
envUrl = `${ENDPOINT_PREFIX}${ENV.ANVIL_IP_ADDR}:${ENV.ANVIL_PORT}`; envUrl = `${ENDPOINT_PREFIX}${anvilIPAddr}:${anvilPort}`;
if (urlOverride && !urlOverride.startsWith(ENDPOINT_PREFIX)) { if (urlOverride && !urlOverride.startsWith(ENDPOINT_PREFIX)) {
warnYellow( logger.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