UNPKG

@hyperlane-xyz/cli

Version:

A command-line utility for common Hyperlane operations

167 lines 10.6 kB
import { expect } from 'chai'; import { Wallet } from 'ethers'; import { TokenRouter__factory } from '@hyperlane-xyz/core'; import { TokenType, } from '@hyperlane-xyz/sdk'; import { getContext } from '../../context/context.js'; import { readYamlOrJson, writeYamlOrJson } from '../../utils/files.js'; import { ANVIL_KEY, CHAIN_NAME_2, CHAIN_NAME_3, CORE_CONFIG_PATH, DEFAULT_E2E_TEST_TIMEOUT, REGISTRY_PATH, TEMP_PATH, WARP_CONFIG_PATH_2, WARP_CONFIG_PATH_EXAMPLE, WARP_CORE_CONFIG_PATH_2, deployOrUseExistingCore, extendWarpConfig, getCombinedWarpRoutePath, getDomainId, setupIncompleteWarpRouteExtension, } from '../commands/helpers.js'; import { hyperlaneWarpDeploy, readWarpConfig } from '../commands/warp.js'; describe('hyperlane warp apply recovery extension tests', async function () { this.timeout(2 * DEFAULT_E2E_TEST_TIMEOUT); let chain2Addresses = {}; before(async function () { await deployOrUseExistingCore(CHAIN_NAME_2, CORE_CONFIG_PATH, ANVIL_KEY); chain2Addresses = await deployOrUseExistingCore(CHAIN_NAME_3, CORE_CONFIG_PATH, ANVIL_KEY); // Create a new warp config using the example const warpConfig = readYamlOrJson(WARP_CONFIG_PATH_EXAMPLE); const anvil2Config = { anvil2: { ...warpConfig.anvil1 } }; writeYamlOrJson(WARP_CONFIG_PATH_2, anvil2Config); }); beforeEach(async function () { await hyperlaneWarpDeploy(WARP_CONFIG_PATH_2); }); it('should recover and re-enroll routers after direct contract-level unenrollment through TokenRouter interface', async () => { const { multiProvider } = await getContext({ registryUris: [REGISTRY_PATH], key: ANVIL_KEY, }); const warpConfigPath = `${TEMP_PATH}/warp-route-deployment-2.yaml`; // Initial setup with chain3 using extendWarpConfig await extendWarpConfig({ chain: CHAIN_NAME_2, chainToExtend: CHAIN_NAME_3, extendedConfig: { decimals: 18, mailbox: chain2Addresses.mailbox, name: 'Ether', owner: new Wallet(ANVIL_KEY).address, symbol: 'ETH', type: TokenType.native, }, warpCorePath: WARP_CORE_CONFIG_PATH_2, warpDeployPath: warpConfigPath, }); const COMBINED_WARP_CORE_CONFIG_PATH = getCombinedWarpRoutePath('ETH', [ CHAIN_NAME_2, CHAIN_NAME_3, ]); const warpCoreConfig = readYamlOrJson(COMBINED_WARP_CORE_CONFIG_PATH); const deployedTokenRoute = warpCoreConfig.tokens.find((t) => t.chainName === CHAIN_NAME_2)?.addressOrDenom; if (!deployedTokenRoute) { throw new Error('Failed to find deployed token route address'); } // Manually call unenrollRemoteRouters const chain3Id = await getDomainId(CHAIN_NAME_3, ANVIL_KEY); const tokenRouter = TokenRouter__factory.connect(deployedTokenRoute, new Wallet(ANVIL_KEY).connect(multiProvider.getProvider(CHAIN_NAME_2))); await tokenRouter.unenrollRemoteRouters([chain3Id]); // Verify the router was unenrolled const beforeRecoveryConfig = await readWarpConfig(CHAIN_NAME_2, COMBINED_WARP_CORE_CONFIG_PATH, warpConfigPath); expect(Object.keys(beforeRecoveryConfig[CHAIN_NAME_2].remoteRouters || {})).to.not.include(chain3Id.toString()); // Re-extend to fix the configuration await extendWarpConfig({ chain: CHAIN_NAME_2, chainToExtend: CHAIN_NAME_3, extendedConfig: { decimals: 18, mailbox: chain2Addresses.mailbox, name: 'Ether', owner: new Wallet(ANVIL_KEY).address, symbol: 'ETH', type: TokenType.native, }, warpCorePath: WARP_CORE_CONFIG_PATH_2, warpDeployPath: warpConfigPath, }); const recoveredConfig = await readWarpConfig(CHAIN_NAME_2, COMBINED_WARP_CORE_CONFIG_PATH, warpConfigPath); expect(Object.keys(recoveredConfig[CHAIN_NAME_2].remoteRouters)).to.include(chain3Id.toString()); }); it('should complete warp route extension when previous attempt left incomplete enrollment or destination gas settings (second attempt on new combined config)', async () => { const { chain2DomainId, chain3DomainId, warpConfigPath, configToExtend, combinedWarpCorePath, } = await setupIncompleteWarpRouteExtension(chain2Addresses); // Verify initial state - neither chain should be enrolled in the other const initialConfig2 = await readWarpConfig(CHAIN_NAME_2, combinedWarpCorePath, warpConfigPath); const initialConfig3 = await readWarpConfig(CHAIN_NAME_3, combinedWarpCorePath, warpConfigPath); // Check remote routers initial state expect(Object.keys(initialConfig2[CHAIN_NAME_2].remoteRouters)).to.not.include(chain3DomainId); expect(Object.keys(initialConfig3[CHAIN_NAME_3].remoteRouters)).to.not.include(chain2DomainId); // Check destination gas initial state expect(Object.keys(initialConfig2[CHAIN_NAME_2].destinationGas || {})).to.not.include(chain3DomainId); expect(Object.keys(initialConfig3[CHAIN_NAME_3].destinationGas || {})).to.not.include(chain2DomainId); // Complete the extension await extendWarpConfig({ chain: CHAIN_NAME_2, chainToExtend: CHAIN_NAME_3, extendedConfig: configToExtend, warpCorePath: combinedWarpCorePath, warpDeployPath: warpConfigPath, }); // Verify both chains are now properly configured const finalConfig2 = await readWarpConfig(CHAIN_NAME_2, combinedWarpCorePath, warpConfigPath); const finalConfig3 = await readWarpConfig(CHAIN_NAME_3, combinedWarpCorePath, warpConfigPath); // Check remote routers final state expect(Object.keys(finalConfig2[CHAIN_NAME_2].remoteRouters)).to.include(chain3DomainId); expect(Object.keys(finalConfig3[CHAIN_NAME_3].remoteRouters)).to.include(chain2DomainId); // Check destination gas final state expect(Object.keys(finalConfig2[CHAIN_NAME_2].destinationGas)).to.include(chain3DomainId); expect(Object.keys(finalConfig3[CHAIN_NAME_3].destinationGas)).to.include(chain2DomainId); }); it('should complete warp route extension when previous attempt left incomplete enrollment or destination gas settings (second attempt with same config)', async () => { const { chain2DomainId, chain3DomainId, warpConfigPath, configToExtend, combinedWarpCorePath, } = await setupIncompleteWarpRouteExtension(chain2Addresses); // Verify initial state - neither chain should be enrolled in the other const initialConfig2 = await readWarpConfig(CHAIN_NAME_2, combinedWarpCorePath, warpConfigPath); const initialConfig3 = await readWarpConfig(CHAIN_NAME_3, combinedWarpCorePath, warpConfigPath); // Check remote routers initial state expect(Object.keys(initialConfig2[CHAIN_NAME_2].remoteRouters)).to.not.include(chain3DomainId); expect(Object.keys(initialConfig3[CHAIN_NAME_3].remoteRouters)).to.not.include(chain2DomainId); // Check destination gas initial state expect(Object.keys(initialConfig2[CHAIN_NAME_2].destinationGas || {})).to.not.include(chain3DomainId); expect(Object.keys(initialConfig3[CHAIN_NAME_3].destinationGas || {})).to.not.include(chain2DomainId); // Complete the extension await extendWarpConfig({ chain: CHAIN_NAME_2, chainToExtend: CHAIN_NAME_3, extendedConfig: configToExtend, warpCorePath: WARP_CORE_CONFIG_PATH_2, warpDeployPath: combinedWarpCorePath, }); // Verify both chains are now properly configured const finalConfig2 = await readWarpConfig(CHAIN_NAME_2, combinedWarpCorePath, warpConfigPath); const finalConfig3 = await readWarpConfig(CHAIN_NAME_3, combinedWarpCorePath, warpConfigPath); // Check remote routers final state expect(Object.keys(finalConfig2[CHAIN_NAME_2].remoteRouters)).to.include(chain3DomainId); expect(Object.keys(finalConfig3[CHAIN_NAME_3].remoteRouters)).to.include(chain2DomainId); // Check destination gas final state expect(Object.keys(finalConfig2[CHAIN_NAME_2].destinationGas)).to.include(chain3DomainId); expect(Object.keys(finalConfig3[CHAIN_NAME_3].destinationGas)).to.include(chain2DomainId); }); it('should set correct gas values when completing warp route extension', async () => { const { chain2DomainId, chain3DomainId, warpConfigPath, configToExtend, combinedWarpCorePath, } = await setupIncompleteWarpRouteExtension(chain2Addresses); // Verify initial state - gas values should not be set const initialConfig2 = await readWarpConfig(CHAIN_NAME_2, combinedWarpCorePath, warpConfigPath); const initialConfig3 = await readWarpConfig(CHAIN_NAME_3, combinedWarpCorePath, warpConfigPath); // Check initial gas values expect(initialConfig2[CHAIN_NAME_2].destinationGas?.[chain3DomainId]).to.be .undefined; expect(initialConfig3[CHAIN_NAME_3].destinationGas?.[chain2DomainId]).to.be .undefined; // Set specific gas values for the extension const customGasValue = '300000'; configToExtend.gas = parseInt(customGasValue); // Complete the extension with custom gas value await extendWarpConfig({ chain: CHAIN_NAME_2, chainToExtend: CHAIN_NAME_3, extendedConfig: configToExtend, warpCorePath: combinedWarpCorePath, warpDeployPath: warpConfigPath, }); // Verify gas values are correctly set after extension const finalConfig2 = await readWarpConfig(CHAIN_NAME_2, combinedWarpCorePath, warpConfigPath); const finalConfig3 = await readWarpConfig(CHAIN_NAME_3, combinedWarpCorePath, warpConfigPath); // Check gas value is set correctly expect(finalConfig2[CHAIN_NAME_2].destinationGas[chain3DomainId]).to.equal(customGasValue); // Verify remote routers are also properly set expect(Object.keys(finalConfig2[CHAIN_NAME_2].remoteRouters)).to.include(chain3DomainId); expect(Object.keys(finalConfig3[CHAIN_NAME_3].remoteRouters)).to.include(chain2DomainId); }); }); //# sourceMappingURL=warp-extend-recovery.e2e-test.js.map