Skip to content

Commit

Permalink
CLI warp route deploys do not support ISM configuration (#3611)
Browse files Browse the repository at this point in the history
### Description
This PR fixes multiple related issues (see Related issues). The primary
changes are
1) Update the warp-route-deployment.yaml to a more sensible
[schema](https://github.com/hyperlane-xyz/hyperlane-monorepo/blob/75d590eff85d03b7a8bf408838bd9e93aac15134/typescript/cli/examples/fork/warp-route-deployment.yaml).
This schema _sets_ us up to allow multi-chain collateral deployments
2) Use zod to define and validate schemas
3) Removes [intermediary config
objects](https://github.com/hyperlane-xyz/hyperlane-monorepo/blob/6c42a6458dd3bfe0dc542833c38e5f959be316ab/typescript/cli/src/deploy/warp.ts#L176-L214),
and completely rely on warp config file

### Drive-by changes
- Updates dry run to allow a user to specify what chain to do a dry run
on:
`hyperlane deploy warp -d sepolia`

### Related issues

- Fixes #3479 
- Fixes #3135 
- Fixes #3188 

### Backward compatibility
**Not backwards compatible, warp route schema has changed**

### Testing
Manual 
- used `sh ci-test.sh pi_with_core_chain` to test out create ERC20,
ERC721, CollateralVault, Native warp configs
- used `sh ci-test.sh pi_with_core_chain` to test out deploy ERC20,
ERC721, CollateralVault, Native warp configs

Unit Tests
- Unit tests added to test out some business logic related to the schema
fields
  • Loading branch information
ltyu authored Apr 24, 2024
1 parent 811ecfb commit f8b6ea4
Show file tree
Hide file tree
Showing 28 changed files with 533 additions and 239 deletions.
6 changes: 6 additions & 0 deletions .changeset/blue-eyes-hunt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@hyperlane-xyz/cli': minor
'@hyperlane-xyz/sdk': minor
---

Update the warp-route-deployment.yaml to a more sensible schema. This schema sets us up to allow multi-chain collateral deployments. Removes intermediary config objects by using zod instead.
6 changes: 4 additions & 2 deletions typescript/cli/ci-test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,8 @@ run_hyperlane_deploy_core_dry_run() {
BEFORE_CORE_DRY_RUN=$(cast balance $DEPLOYER --rpc-url http://127.0.0.1:${CHAIN1_PORT});

echo -e "\nDry-running contract deployments to Alfajores"
yarn workspace @hyperlane-xyz/cli run hyperlane deploy core --dry-run \
yarn workspace @hyperlane-xyz/cli run hyperlane deploy core \
--dry-run alfajores \
--targets alfajores \
--chains ${EXAMPLES_PATH}/dry-run/anvil-chains.yaml \
--artifacts /tmp/empty-artifacts.json \
Expand Down Expand Up @@ -163,7 +164,8 @@ run_hyperlane_deploy_warp_dry_run() {
BEFORE_WARP_DRY_RUN=$(cast balance $DEPLOYER --rpc-url http://127.0.0.1:${CHAIN1_PORT});

echo -e "\nDry-running warp route deployments to Alfajores"
yarn workspace @hyperlane-xyz/cli run hyperlane deploy warp --dry-run \
yarn workspace @hyperlane-xyz/cli run hyperlane deploy warp \
--dry-run alfajores \
--chains ${EXAMPLES_PATH}/dry-run/anvil-chains.yaml \
--core $CORE_ARTIFACTS_PATH \
--config ${EXAMPLES_PATH}/dry-run/warp-route-deployment.yaml \
Expand Down
7 changes: 3 additions & 4 deletions typescript/cli/examples/dry-run/warp-route-deployment.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
base:
chainName: alfajores
alfajores:
type: native
synthetics:
- chainName: fuji
fuji:
type: synthetic
26 changes: 17 additions & 9 deletions typescript/cli/examples/fork/warp-route-deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,25 @@
# fastCollateral
# fastSynthetic
---
base:
chainName: anvil
anvil:
type: native
# address: 0x123... # Required for collateral types
# token: "0x123" # Collateral/vault address. Required for collateral types
# owner: "0x123" # Optional owner address for synthetic token
# mailbox: "0x123" # mailbox address route
# interchainGasPaymaster: "0x123" # Optional interchainGasPaymaster address
# isNft: true # If the token is an NFT (ERC721), set to true
# owner: 0x123 # Optional owner address for synthetic token
# mailbox: 0x123 # Optional mailbox address route
# interchainGasPaymaster: 0x123 # Optional interchainGasPaymaster address
synthetics:
- chainName: ethereum
# You can optionally set the token metadata, otherwise the base token's will be used
# You can optionally set the token metadata
# name: "MyCollateralToken"
# symbol: "MCT"
# totalSupply: 10000000

ethereum:
type: synthetic
# token: "0x123" # Collateral/vault address. Required for collateral types
# owner: "0x123" # Optional owner address for synthetic token
# mailbox: "0x123" # mailbox address route
# interchainGasPaymaster: "0x123" # Optional interchainGasPaymaster address
# You can optionally set the token metadata
# name: "MySyntheticToken"
# symbol: "MST"
# totalSupply: 10000000
27 changes: 17 additions & 10 deletions typescript/cli/examples/warp-route-deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,31 @@
# Token Types:
# native
# collateral
# collateralVault
# synthetic
# collateralUri
# syntheticUri
# fastCollateral
# fastSynthetic
---
base:
chainName: anvil1
anvil1:
type: native
# address: 0x123... # Required for collateral types. For collateralVault types, specifies the ERC4626 vault to deposit collateral into
# token: "0x123" # Collateral/vault address. Required for collateral types
# owner: "0x123" # Optional owner address for synthetic token
# mailbox: "0x123" # mailbox address route
# interchainGasPaymaster: "0x123" # Optional interchainGasPaymaster address
# isNft: true # If the token is an NFT (ERC721), set to true
# owner: 0x123 # Optional owner address for synthetic token
# mailbox: 0x123 # Optional mailbox address route
# interchainGasPaymaster: 0x123 # Optional interchainGasPaymaster address
synthetics:
- chainName: anvil2
# You can optionally set the token metadata, otherwise the base token's will be used
# You can optionally set the token metadata
# name: "MyCollateralToken"
# symbol: "MCT"
# totalSupply: 10000000

anvil2:
type: synthetic
# token: "0x123" # Collateral/vault address. Required for collateral types
# owner: "0x123" # Optional owner address for synthetic token
# mailbox: "0x123" # mailbox address route
# interchainGasPaymaster: "0x123" # Optional interchainGasPaymaster address
# You can optionally set the token metadata
# name: "MySyntheticToken"
# symbol: "MST"
# totalSupply: 10000000
4 changes: 2 additions & 2 deletions typescript/cli/src/commands/deploy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ const coreCommand: CommandModule = {
const ismConfigPath: string = argv.ism;
const hookConfigPath: string = argv.hook;
const skipConfirmation: boolean = argv.yes;
const dryRun: boolean = argv.dryRun;
const dryRun: string = argv.dryRun;

logGray(
`Hyperlane permissionless core deployment${dryRun ? ' dry-run' : ''}`,
Expand Down Expand Up @@ -159,7 +159,7 @@ const warpCommand: CommandModule = {
const coreArtifactsPath: string | undefined = argv.core;
const outPath: string = argv.out;
const skipConfirmation: boolean = argv.yes;
const dryRun: boolean = argv.dryRun;
const dryRun: string = argv.dryRun;

logGray(`Hyperlane warp route deployment${dryRun ? ' dry-run' : ''}`);
logGray('------------------------------------------------');
Expand Down
5 changes: 2 additions & 3 deletions typescript/cli/src/commands/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,9 +141,8 @@ export const skipConfirmationOption: Options = {
};

export const dryRunOption: Options = {
type: 'boolean',
type: 'string',
description:
'Simulate deployment on forked network. Please ensure an anvil node instance is running during execution via `anvil`.',
default: false,
'Chain name to fork and simulate deployment. Please ensure an anvil node instance is running during execution via `anvil`.',
alias: ['d', 'dr'],
};
97 changes: 24 additions & 73 deletions typescript/cli/src/config/warp.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import { confirm, input } from '@inquirer/prompts';
import { ethers } from 'ethers';
import { z } from 'zod';

import { TokenType, ZHash } from '@hyperlane-xyz/sdk';
import {
TokenType,
WarpRouteDeployConfig,
WarpRouteDeployConfigSchema,
} from '@hyperlane-xyz/sdk';

import { errorRed, logBlue, logGreen } from '../logger.js';
import {
Expand All @@ -13,63 +16,6 @@ import { FileFormat, readYamlOrJson, writeYamlOrJson } from '../utils/files.js';

import { readChainConfigsIfExists } from './chain.js';

const ConnectionConfigSchema = {
mailbox: ZHash.optional(),
interchainSecurityModule: ZHash.optional(),
foreignDeployment: z.string().optional(),
};

export const WarpRouteDeployConfigSchema = z.object({
base: z
.object({
type: z
.literal(TokenType.native)
.or(z.literal(TokenType.collateral))
.or(z.literal(TokenType.collateralVault)),
chainName: z.string(),
address: ZHash.optional(),
isNft: z.boolean().optional(),
name: z.string().optional(),
symbol: z.string().optional(),
decimals: z.number().optional(),
...ConnectionConfigSchema,
})
.refine(
(data) => {
// For collateralVault Warp Routes, address will specify the vault
if (
data.type === TokenType.collateralVault &&
data.address === ethers.constants.AddressZero
)
return false;

return true;
},
{
message: 'Vault address is required when type is collateralVault',
path: ['address'],
},
),
synthetics: z
.array(
z.object({
chainName: z.string(),
name: z.string().optional(),
symbol: z.string().optional(),
totalSupply: z.number().optional(),
...ConnectionConfigSchema,
}),
)
.nonempty(),
});

type InferredType = z.infer<typeof WarpRouteDeployConfigSchema>;
// A workaround for Zod's terrible typing for nonEmpty arrays
export type WarpRouteDeployConfig = {
base: InferredType['base'];
synthetics: Array<InferredType['synthetics'][0]>;
};

export function readWarpRouteDeployConfig(filePath: string) {
const config = readYamlOrJson(filePath);
if (!config)
Expand Down Expand Up @@ -133,23 +79,28 @@ export async function createWarpRouteDeployConfig({
);

// TODO add more prompts here to support customizing the token metadata
let baseType: TokenType;
let result: WarpRouteDeployConfig;
if (isNative) {
baseType = TokenType.native;
result = {
[baseChain]: {
type: TokenType.native,
},
};
} else {
baseType = isYieldBearing
? TokenType.collateralVault
: TokenType.collateral;
result = {
[baseChain]: {
type: isYieldBearing ? TokenType.collateralVault : TokenType.collateral,
token: baseAddress,
isNft,
},
};
}
const result: WarpRouteDeployConfig = {
base: {
chainName: baseChain,
type: baseType,
address: baseAddress,
isNft,
},
synthetics: syntheticChains.map((chain) => ({ chainName: chain })),
};

syntheticChains.map((chain) => {
result[chain] = {
type: TokenType.synthetic,
};
});

if (isValidWarpRouteDeployConfig(result)) {
logGreen(`Warp Route config is valid, writing to file ${outPath}`);
Expand Down
6 changes: 3 additions & 3 deletions typescript/cli/src/deploy/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,12 +87,12 @@ export async function runCoreDeploy({
artifactsPath?: string;
outPath: string;
skipConfirmation: boolean;
dryRun: boolean;
dryRun: string;
}) {
const context = dryRun
? await getDryRunContext({
chainConfigPath,
chains,
chains: [dryRun],
keyConfig: { key },
skipConfirmation,
})
Expand Down Expand Up @@ -280,7 +280,7 @@ interface DeployParams {
hooksConfig?: ChainMap<HooksConfig>;
outPath: string;
skipConfirmation: boolean;
dryRun: boolean;
dryRun: string;
}

async function runDeployPlanStep({
Expand Down
4 changes: 2 additions & 2 deletions typescript/cli/src/deploy/dry-run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,9 @@ export async function verifyAnvil() {
/**
* Evaluates if an error is related to the current dry-run.
* @param error the thrown error
* @param dryRun whether or not the current command is being dry-run
* @param dryRun the chain name to execute the dry-run on
*/
export function evaluateIfDryRunFailure(error: any, dryRun: boolean) {
export function evaluateIfDryRunFailure(error: any, dryRun: string) {
if (dryRun && error.message.includes('call revert exception'))
warnYellow(
'⛔️ [dry-run] The current RPC may not support forking. Please consider using a different RPC provider.',
Expand Down
2 changes: 1 addition & 1 deletion typescript/cli/src/deploy/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ export async function completeDeploy(
multiProvider: MultiProvider,
userAddress: Address,
chains: ChainName[],
dryRun: boolean = false,
dryRun: string,
) {
if (chains.length > 0) logPink(`⛽️ Gas Usage Statistics`);
for (const chain of chains) {
Expand Down
Loading

0 comments on commit f8b6ea4

Please sign in to comment.