Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve warp and kurtosis deploy command dx #2994

Merged
merged 6 commits into from
Nov 29, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/little-beans-attack.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@hyperlane-xyz/cli': patch
---

Improve warp and kurtosis deploy command UX
5 changes: 5 additions & 0 deletions .changeset/tidy-turtles-rest.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@hyperlane-xyz/sdk': patch
---

Remove neutrontestnet from default chainMetadata map
17 changes: 10 additions & 7 deletions typescript/cli/src/commands/deploy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,26 +38,29 @@ const agentCommand: CommandModule = {
describe: 'Deploy Hyperlane agents with Kurtosis',
builder: (yargs) =>
yargs.options({
originChain: {
origin: {
type: 'string',
description: 'The name of the origin chain to deploy to',
},
agentConfiguration: agentConfigurationOption,
jmrossy marked this conversation as resolved.
Show resolved Hide resolved
relayChains: {
targets: {
type: 'string',
description: 'Comma separated list of chains to relay between',
},
chains: chainsCommandOption,
config: agentConfigurationOption,
}),
handler: async (argv: any) => {
logGray('Hyperlane Agent Deployment with Kurtosis');
logGray('----------------------------------------');
const originChain: string = argv.originChain;
const agentConfigurationPath: string = argv.agentConfiguration;
const relayChains: string = argv.relayChains;
const chainConfigPath: string = argv.chains;
const originChain: string = argv.origin;
const agentConfigurationPath: string = argv.config;
const relayChains: string = argv.targets;
await runKurtosisAgentDeploy({
originChain,
agentConfigurationPath,
relayChains,
chainConfigPath,
agentConfigurationPath,
});
process.exit(0);
},
Expand Down
3 changes: 1 addition & 2 deletions typescript/cli/src/commands/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,12 @@ export const outDirCommandOption: Options = {
export const coreArtifactsOption: Options = {
type: 'string',
description: 'File path to core deployment output artifacts',
alias: 'ca',
alias: 'a',
jmrossy marked this conversation as resolved.
Show resolved Hide resolved
};

export const agentConfigurationOption: Options = {
type: 'string',
description: 'File path to agent configuration artifacts',
alias: 'ac',
};

export const fileFormatOption: Options = {
Expand Down
40 changes: 37 additions & 3 deletions typescript/cli/src/config/artifacts.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { confirm } from '@inquirer/prompts';
import { ZodTypeAny, z } from 'zod';

import { HyperlaneContractsMap } from '@hyperlane-xyz/sdk';
import { ChainName, HyperlaneContractsMap } from '@hyperlane-xyz/sdk';

import { logBlue } from '../../logger.js';
import { readYamlOrJson } from '../utils/files.js';
import { log, logBlue, logRed } from '../../logger.js';
import { readYamlOrJson, runFileSelectionStep } from '../utils/files.js';

const RecursiveObjectSchema: ZodTypeAny = z.lazy(() =>
z.object({}).catchall(z.union([z.string(), RecursiveObjectSchema])),
Expand Down Expand Up @@ -31,3 +32,36 @@ export function readDeploymentArtifacts(filePath: string) {
}
return artifacts;
}

export async function runDeploymentArtifactStep(
artifactsPath?: string,
message?: string,
selectedChains?: ChainName[],
) {
if (!artifactsPath) {
const useArtifacts = await confirm({
message: message || 'Do you want use some existing contract addresses?',
});
if (!useArtifacts) return undefined;

artifactsPath = await runFileSelectionStep(
'./artifacts',
'contract artifacts',
'core-deployment',
);
}
const artifacts = readDeploymentArtifacts(artifactsPath);

if (selectedChains) {
const artifactChains = Object.keys(artifacts).filter((c) =>
selectedChains.includes(c),
);
if (artifactChains.length === 0) {
logRed('No artifacts found for selected chains');
} else {
log(`Found existing artifacts for chains: ${artifactChains.join(', ')}`);
}
}

return artifacts;
}
49 changes: 24 additions & 25 deletions typescript/cli/src/deploy/agent.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,40 @@
import { input } from '@inquirer/prompts';
import terminalLink from 'terminal-link';

import { logBlue, logGreen, logRed } from '../../logger.js';
import { toBase64 } from '@hyperlane-xyz/utils';

import { logBlue, logGreen } from '../../logger.js';
import { getContext } from '../context.js';
import {
runMultiChainSelectionStep,
runSingleChainSelectionStep,
} from '../utils/chains.js';
import { readJson, runFileSelectionStep } from '../utils/files.js';

export async function runKurtosisAgentDeploy({
originChain,
agentConfigurationPath,
relayChains,
chainConfigPath,
agentConfigurationPath,
}: {
originChain: string;
agentConfigurationPath: string;
relayChains: string;
chainConfigPath: string;
agentConfigurationPath: string;
}) {
const { customChains } = getContext(chainConfigPath);

if (!originChain) {
originChain = await input({ message: 'Enter the origin chain' });
originChain = await runSingleChainSelectionStep(
customChains,
'Select the origin chain',
);
}
if (!relayChains) {
relayChains = await input({
message: 'Enter a comma separated list of chains to relay between',
});
relayChains = trimSpaces(relayChains);
const selectedRelayChains = await runMultiChainSelectionStep(
customChains,
'Select chains to relay between',
);
relayChains = selectedRelayChains.join(',');
}

if (!agentConfigurationPath) {
Expand Down Expand Up @@ -48,7 +62,7 @@ export async function runKurtosisAgentDeploy({
args: hyperlanePackageArgs,
};

const base64EncodedPackageConfig = jsonToBase64(kurtosisPackageConfig);
const base64EncodedPackageConfig = toBase64(kurtosisPackageConfig) || '';
const kurtosisCloudUrl = getKurtosisCloudUrl(base64EncodedPackageConfig);

const kurtosisCloudLink = terminalLink(
Expand All @@ -67,18 +81,3 @@ export async function runKurtosisAgentDeploy({

const getKurtosisCloudUrl = (base64Params: string) =>
`https://cloud.kurtosis.com/enclave-manager?package-id=github.com%2Fkurtosis-tech%2Fhyperlane-package&package-args=${base64Params}`;

const trimSpaces = (a: string) =>
a
.split('')
.filter((char) => char !== ' ')
.join('');

function jsonToBase64(jsonData: any): string {
try {
return btoa(JSON.stringify(jsonData));
} catch (error) {
logRed('Error occurred creating kurtosis cloud url.');
return '';
}
}
43 changes: 11 additions & 32 deletions typescript/cli/src/deploy/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import {
import { Address, objFilter, objMerge } from '@hyperlane-xyz/utils';

import { log, logBlue, logGray, logGreen, logRed } from '../../logger.js';
import { readDeploymentArtifacts } from '../config/artifacts.js';
import { runDeploymentArtifactStep } from '../config/artifacts.js';
import { readHookConfig } from '../config/hooks.js';
import { readIsmConfig } from '../config/ism.js';
import { readMultisigConfig } from '../config/multisig.js';
Expand All @@ -52,8 +52,11 @@ import {
TestRecipientConfig,
TestRecipientDeployer,
} from './TestRecipientDeployer.js';
import { isISMConfig, isZODISMConfig } from './utils.js';
import { runPreflightChecksForChains } from './utils.js';
import {
isISMConfig,
isZODISMConfig,
runPreflightChecksForChains,
} from './utils.js';

export async function runCoreDeploy({
key,
Expand Down Expand Up @@ -117,36 +120,12 @@ export async function runCoreDeploy({
await executeDeploy(deploymentParams);
}

async function runArtifactStep(
selectedChains: ChainName[],
artifactsPath?: string,
) {
if (!artifactsPath) {
logBlue(
'\n',
'Deployments can be totally new or can use some existing contract addresses.',
);
const isResume = await confirm({
message: 'Do you want use some existing contract addresses?',
});
if (!isResume) return undefined;

artifactsPath = await runFileSelectionStep(
'./artifacts',
'contract artifacts',
'core-deployment',
);
}
const artifacts = readDeploymentArtifacts(artifactsPath);
const artifactChains = Object.keys(artifacts).filter((c) =>
selectedChains.includes(c),
function runArtifactStep(selectedChains: ChainName[], artifactsPath?: string) {
logBlue(
'\n',
'Deployments can be totally new or can use some existing contract addresses.',
);
if (artifactChains.length === 0) {
logGray('No artifacts found for selected chains');
} else {
log(`Found existing artifacts for chains: ${artifactChains.join(', ')}`);
}
return artifacts;
return runDeploymentArtifactStep(artifactsPath, undefined, selectedChains);
}

async function runIsmStep(selectedChains: ChainName[], ismConfigPath?: string) {
Expand Down
9 changes: 5 additions & 4 deletions typescript/cli/src/deploy/warp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import {
import { Address, ProtocolType, objMap } from '@hyperlane-xyz/utils';

import { log, logBlue, logGray, logGreen } from '../../logger.js';
import { readDeploymentArtifacts } from '../config/artifacts.js';
import { runDeploymentArtifactStep } from '../config/artifacts.js';
import { WarpRouteConfig, readWarpRouteConfig } from '../config/warp.js';
import { MINIMUM_WARP_DEPLOY_GAS } from '../consts.js';
import {
Expand Down Expand Up @@ -65,9 +65,10 @@ export async function runWarpDeploy({
}
const warpRouteConfig = readWarpRouteConfig(warpConfigPath);

const artifacts = coreArtifactsPath
? readDeploymentArtifacts(coreArtifactsPath)
: undefined;
const artifacts = await runDeploymentArtifactStep(
coreArtifactsPath,
'Do you want use some core deployment address artifacts? This is required for warp deployments to PI chains (non-core chains).',
);

const configs = await runBuildConfigStep({
warpRouteConfig,
Expand Down
1 change: 0 additions & 1 deletion typescript/sdk/src/consts/chainMetadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1076,7 +1076,6 @@ export const chainMetadata: ChainMap<ChainMetadata> = {
solanatestnet,
solanadevnet,
nautilus,
neutrontestnet,
};

export const chainIdToMetadata = Object.values(chainMetadata).reduce<
Expand Down
12 changes: 12 additions & 0 deletions typescript/sdk/src/metadata/chainMetadata.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { expect } from 'chai';

import { ProtocolType } from '@hyperlane-xyz/utils';

import { chainMetadata } from '../consts/chainMetadata';

import { ChainMetadata, isValidChainMetadata } from './chainMetadataTypes';

const minimalSchema: ChainMetadata = {
Expand Down Expand Up @@ -61,6 +63,7 @@ describe('ChainMetadataSchema', () => {
}),
).to.eq(true);
});

it('Rejects invalid schemas', () => {
expect(
//@ts-ignore
Expand Down Expand Up @@ -106,4 +109,13 @@ describe('ChainMetadataSchema', () => {
}),
).to.eq(false);
});

it('Works for all SDK chain metadata consts', () => {
for (const chain of Object.keys(chainMetadata)) {
const isValid = isValidChainMetadata(chainMetadata[chain]);
// eslint-disable-next-line no-console
if (!isValid) console.error(`Invalid chain metadata for ${chain}`);
expect(isValid).to.eq(true);
}
});
});
Loading