UNPKG

cosmic-interchain-cli

Version:

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

168 lines 7.04 kB
import { input, select } from '@inquirer/prompts'; import { stringify as yamlStringify } from 'yaml'; import { IsmType, TokenType, WarpCoreConfigSchema, WarpRouteDeployConfigSchema, } from '@hyperlane-xyz/sdk'; import { assert, objMap, promiseObjAll } from '@hyperlane-xyz/utils'; import { errorRed, log, logBlue, logGreen } from '../logger.js'; import { runMultiChainSelectionStep } from '../utils/chains.js'; import { indentYamlOrJson, readYamlOrJson, writeYamlOrJson, } from '../utils/files.js'; import { detectAndConfirmOrPrompt } from '../utils/input.js'; import { createAdvancedIsmConfig } from './ism.js'; const TYPE_DESCRIPTIONS = { [TokenType.synthetic]: 'A new ERC20 with remote transfer functionality', [TokenType.collateral]: 'Extends an existing ERC20 with remote transfer functionality', [TokenType.native]: 'Extends the native token with remote transfer functionality', [TokenType.collateralVault]: 'Extends an existing ERC4626 with remote transfer functionality', [TokenType.collateralFiat]: 'Extends an existing FiatToken with remote transfer functionality', [TokenType.XERC20]: 'Extends an existing xERC20 with Warp Route functionality', [TokenType.XERC20Lockbox]: 'Extends an existing xERC20 Lockbox with Warp Route functionality', // TODO: describe [TokenType.fastSynthetic]: '', [TokenType.syntheticUri]: '', [TokenType.fastCollateral]: '', [TokenType.collateralUri]: '', [TokenType.nativeScaled]: '', }; const TYPE_CHOICES = Object.values(TokenType).map((type) => ({ name: type, value: type, description: TYPE_DESCRIPTIONS[type], })); async function fillDefaults(context, config) { return promiseObjAll(objMap(config, async (chain, config) => { let mailbox = config.mailbox; if (!mailbox) { const addresses = await context.registry.getChainAddresses(chain); assert(addresses, `No addresses found for chain ${chain}`); mailbox = addresses.mailbox; } let owner = config.owner; if (!owner) { owner = (await context.signer?.getAddress()) ?? (await context.multiProvider.getSignerAddress(chain)); } return { owner, mailbox, ...config, }; })); } export async function readWarpRouteDeployConfig(filePath, context) { let config = readYamlOrJson(filePath); if (!config) throw new Error(`No warp route deploy config found at ${filePath}`); if (context) { config = await fillDefaults(context, config); } return WarpRouteDeployConfigSchema.parse(config); } export function isValidWarpRouteDeployConfig(config) { return WarpRouteDeployConfigSchema.safeParse(config).success; } export async function createWarpRouteDeployConfig({ context, outPath, advanced = false, }) { logBlue('Creating a new warp route deployment config...'); const owner = await detectAndConfirmOrPrompt(async () => context.signer?.getAddress(), 'Enter the desired', 'owner address', 'signer'); const warpChains = await runMultiChainSelectionStep(context.chainMetadata, 'Select chains to connect', 1); const result = {}; for (const chain of warpChains) { logBlue(`${chain}: Configuring warp route...`); const type = await select({ message: `Select ${chain}'s token type`, choices: TYPE_CHOICES, }); // TODO: restore NFT prompting const isNft = type === TokenType.syntheticUri || type === TokenType.collateralUri; const mailbox = await detectAndConfirmOrPrompt(async () => { const addresses = await context.registry.getChainAddresses(chain); return addresses?.mailbox; }, `For ${chain}, enter the`, 'mailbox address', 'hyperlane-registry'); const interchainSecurityModule = advanced ? await createAdvancedIsmConfig(context) : createDefaultWarpIsmConfig(owner); switch (type) { case TokenType.collateral: case TokenType.XERC20: case TokenType.XERC20Lockbox: case TokenType.collateralFiat: case TokenType.collateralUri: case TokenType.fastCollateral: result[chain] = { mailbox, type, owner, isNft, interchainSecurityModule, token: await input({ message: `Enter the existing token address on chain ${chain}`, }), }; break; case TokenType.collateralVault: result[chain] = { mailbox, type, owner, isNft, interchainSecurityModule, token: await input({ message: `Enter the ERC-4626 vault address on chain ${chain}`, }), }; break; default: result[chain] = { mailbox, type, owner, isNft, interchainSecurityModule, }; } } try { const warpRouteDeployConfig = WarpRouteDeployConfigSchema.parse(result); logBlue(`Warp Route config is valid, writing to file ${outPath}:\n`); log(indentYamlOrJson(yamlStringify(warpRouteDeployConfig, null, 2), 4)); writeYamlOrJson(outPath, warpRouteDeployConfig, 'yaml'); logGreen('✅ Successfully created new warp route deployment config.'); } catch (e) { errorRed(`Warp route deployment config is invalid, please see https://github.com/hyperlane-xyz/hyperlane-monorepo/blob/main/typescript/cli/examples/warp-route-deployment.yaml for an example.`); throw e; } } // Note, this is different than the function above which reads a config // for a DEPLOYMENT. This gets a config for using a warp route (aka WarpCoreConfig) export function readWarpCoreConfig(filePath) { const config = readYamlOrJson(filePath); if (!config) throw new Error(`No warp route config found at ${filePath}`); return WarpCoreConfigSchema.parse(config); } /** * Creates a default configuration for an ISM with a TRUSTED_RELAYER and FALLBACK_ROUTING. * * Properties relayer and owner are both set as input owner. * * @param owner - The address of the owner of the ISM. * @returns The default Aggregation ISM configuration. */ function createDefaultWarpIsmConfig(owner) { return { type: IsmType.AGGREGATION, modules: [ { type: IsmType.TRUSTED_RELAYER, relayer: owner, }, { type: IsmType.FALLBACK_ROUTING, domains: {}, owner, }, ], threshold: 1, }; } //# sourceMappingURL=warp.js.map