diff --git a/typescript/infra/config/environments/mainnet2/igp.ts b/typescript/infra/config/environments/mainnet2/igp.ts index cebb144e1ea..89a63e8b7fa 100644 --- a/typescript/infra/config/environments/mainnet2/igp.ts +++ b/typescript/infra/config/environments/mainnet2/igp.ts @@ -43,7 +43,6 @@ export const igp: ChainMap = objMap( ), ]), ), - upgrade: core[chain].upgrade, }; }, ); diff --git a/typescript/infra/config/environments/test/index.ts b/typescript/infra/config/environments/test/index.ts index d5b010c2eb2..cae9de8572b 100644 --- a/typescript/infra/config/environments/test/index.ts +++ b/typescript/infra/config/environments/test/index.ts @@ -1,6 +1,6 @@ import { JsonRpcProvider } from '@ethersproject/providers'; -import { MultiProvider } from '@hyperlane-xyz/sdk'; +import { MultiProvider, TestChains } from '@hyperlane-xyz/sdk'; import { EnvironmentConfig } from '../../../src/config'; @@ -25,9 +25,11 @@ export const environment: EnvironmentConfig = { // NOTE: Does not work from hardhat.config.ts getMultiProvider: async () => { const mp = MultiProvider.createTestMultiProvider(); - const provider = mp.getProvider('test1') as JsonRpcProvider; - const signer = provider.getSigner(0); - mp.setSharedSigner(signer); + TestChains.forEach((chain, index) => { + const provider = mp.getProvider(chain) as JsonRpcProvider; + const signer = provider.getSigner(index); + mp.setSigner(chain, signer); + }); return mp; }, storageGasOracleConfig, diff --git a/typescript/infra/hardhat.config.ts b/typescript/infra/hardhat.config.ts index 91c97a1ae06..806cbbad371 100644 --- a/typescript/infra/hardhat.config.ts +++ b/typescript/infra/hardhat.config.ts @@ -5,6 +5,7 @@ import { HardhatRuntimeEnvironment } from 'hardhat/types'; import { TestSendReceiver__factory } from '@hyperlane-xyz/core'; import { ChainName, HyperlaneCore, MultiProvider } from '@hyperlane-xyz/sdk'; +import { utils } from '@hyperlane-xyz/utils'; import { sleep } from './src/utils/utils'; @@ -41,7 +42,6 @@ task('kathy', 'Dispatches random hyperlane messages') ) => { const timeout = Number.parseInt(taskArgs.timeout); const environment = 'test'; - const interchainGasPayment = hre.ethers.utils.parseUnits('100', 'gwei'); const [signer] = await hre.ethers.getSigners(); const multiProvider = MultiProvider.createTestMultiProvider({ signer }); const core = HyperlaneCore.fromEnvironment(environment, multiProvider); @@ -50,9 +50,11 @@ task('kathy', 'Dispatches random hyperlane messages') list[Math.floor(Math.random() * list.length)]; // Deploy a recipient - const recipientF = new TestSendReceiver__factory(signer); - const recipient = await recipientF.deploy(); - await recipient.deployTransaction.wait(); + const recipient = await multiProvider.handleDeploy( + 'test1', + new TestSendReceiver__factory(), + [], + ); const isAutomine: boolean = await hre.network.provider.send( 'hardhat_getAutomine', @@ -68,19 +70,18 @@ task('kathy', 'Dispatches random hyperlane messages') const remote: ChainName = randomElement(core.remoteChains(local)); const remoteId = multiProvider.getDomainId(remote); const mailbox = core.getContracts(local).mailbox; - await recipient.dispatchToSelf(mailbox.address, remoteId, '0x1234', { - value: interchainGasPayment, - // Some behavior is dependent upon the previous block hash - // so gas estimation may sometimes be incorrect. Just avoid - // estimation to avoid this. - gasLimit: 150_000, - gasPrice: 2_000_000_000, - }); - console.log( - `send to ${recipient.address} on ${remote} via mailbox ${ - mailbox.address - } on ${local} with nonce ${await mailbox.nonce()}`, + const igp = await mailbox.defaultHook(); + const tx = await recipient.dispatchToSelf( + mailbox.address, + igp, + remoteId, + '0x1234', + { + value: 150_000, + }, ); + const receipt = await tx.wait(); + console.log(`${local} => ${remote} (gasUsed=${receipt.gasUsed})`); console.log(await chainSummary(core, local)); console.log(await chainSummary(core, remote)); diff --git a/typescript/infra/scripts/deploy.ts b/typescript/infra/scripts/deploy.ts index 2a3a8ae8f10..7788b5cfce6 100644 --- a/typescript/infra/scripts/deploy.ts +++ b/typescript/infra/scripts/deploy.ts @@ -71,10 +71,14 @@ async function main() { deployer = new HyperlaneIsmFactoryDeployer(multiProvider); } else if (module === Modules.CORE) { config = envConfig.core; - const ismFactory = HyperlaneIsmFactory.fromEnvironment( - deployEnvToSdkEnv[environment], - multiProvider, - ); + // TODO: clean this up + const ismFactory = + environment === 'test' + ? undefined + : HyperlaneIsmFactory.fromEnvironment( + deployEnvToSdkEnv[environment], + multiProvider, + ); deployer = new HyperlaneCoreDeployer(multiProvider, ismFactory); } else if (module === Modules.HOOK) { config = envConfig.hooks; diff --git a/typescript/sdk/src/core/HyperlaneCoreDeployer.ts b/typescript/sdk/src/core/HyperlaneCoreDeployer.ts index db1c929ede8..6fa8508f41f 100644 --- a/typescript/sdk/src/core/HyperlaneCoreDeployer.ts +++ b/typescript/sdk/src/core/HyperlaneCoreDeployer.ts @@ -15,6 +15,7 @@ import { IgpFactories } from '../gas/contracts'; import { OverheadIgpConfig } from '../gas/types'; import { HyperlaneIsmFactory } from '../ism/HyperlaneIsmFactory'; import { HyperlaneIsmFactoryDeployer } from '../ism/HyperlaneIsmFactoryDeployer'; +import { IsmFactoryFactories } from '../ism/contracts'; import { IsmConfig } from '../ism/types'; import { MultiProvider } from '../providers/MultiProvider'; import { ChainMap, ChainName } from '../types'; @@ -106,13 +107,15 @@ export class HyperlaneCoreDeployer extends HyperlaneDeployer< } async deployIsm(chain: ChainName, config: IsmConfig): Promise { - if (!this.ismFactory) { + let ismFactory = this.ismFactory; + // TODO: merge cached and new ISM factories + if (!ismFactory) { const contracts = await this.ismFactoryDeployer.deploy([chain]); - this.ismFactory = new HyperlaneIsmFactory(contracts, this.multiProvider); + ismFactory = new HyperlaneIsmFactory(contracts, this.multiProvider); } this.logger(`Deploying new ISM to ${chain}`); - const ism = await this.ismFactory.deploy(chain, config); + const ism = await ismFactory.deploy(chain, config); return ism.address; } @@ -148,13 +151,13 @@ export class HyperlaneCoreDeployer extends HyperlaneDeployer< const timelockController = igpContracts.timelockController; const proxyAdmin = igpContracts.proxyAdmin; - const defaultHook = igpContracts.defaultIsmInterchainGasPaymaster.address; + const defaultHook = igpContracts.interchainGasPaymaster; const mailbox = await this.deployMailbox( chain, config.defaultIsm, proxyAdmin.address, - defaultHook, + defaultHook.address, config.owner, ); @@ -174,4 +177,8 @@ export class HyperlaneCoreDeployer extends HyperlaneDeployer< igpContracts(): ChainMap> { return this.igpDeployer.deployedContracts; } + + ismContracts(): ChainMap> { + return this.ismFactoryDeployer.deployedContracts; + } } diff --git a/typescript/sdk/src/ism/HyperlaneIsmFactory.ts b/typescript/sdk/src/ism/HyperlaneIsmFactory.ts index 48b3642652c..797cb547f78 100644 --- a/typescript/sdk/src/ism/HyperlaneIsmFactory.ts +++ b/typescript/sdk/src/ism/HyperlaneIsmFactory.ts @@ -24,7 +24,7 @@ import { appFromAddressesMapHelper, } from '../contracts'; import { MultiProvider } from '../providers/MultiProvider'; -import { ChainMap, ChainName } from '../types'; +import { ChainName } from '../types'; import { IsmFactoryFactories, ismFactoryFactories } from './contracts'; import { @@ -101,7 +101,7 @@ export class HyperlaneIsmFactory extends HyperlaneApp { return this.deployRoutingIsm(chain, config); } else if (config.type === ModuleType.AGGREGATION) { this.logger(`Deploying Aggregation ISM to ${chain}`); - return this.deployAggregationIsm(chain, config); + return this.deployAggregationIsm(chain, config, origin); } else { throw new Error(`Unsupported ISM type`); } @@ -152,45 +152,20 @@ export class HyperlaneIsmFactory extends HyperlaneApp { private async deployRoutingIsm(chain: ChainName, config: RoutingIsmConfig) { const signer = this.multiProvider.getSigner(chain); const routingIsmFactory = this.getContracts(chain).routingIsmFactory; - const isms: ChainMap = {}; - // deploy for all origins in parallel, keep running even if some fail - await Promise.allSettled( - Object.keys(config.domains).map(async (origin) => { - const ism = await this.deploy(chain, config.domains[origin], origin); - isms[origin] = ism.address; - }), - ).then((results) => { - results.forEach((result) => { - if (result.status === 'rejected') { - this.logger(`Failed to deploy routing ISM: ${result.reason}`); - } - }); - }); - const domains = Object.keys(isms).map((chain) => - this.multiProvider.getDomainId(chain), - ); - const submoduleAddresses = Object.values(isms); + let domains = []; + let isms = []; + for (const origin in config.domains) { + const ism = await this.deploy(chain, config.domains[origin], origin); + const domain = this.multiProvider.getDomainId(origin); + isms.push(ism.address); + domains.push(domain); + } const overrides = this.multiProvider.getTransactionOverrides(chain); - const tx = await routingIsmFactory.deploy( - domains, - submoduleAddresses, - overrides, - ); + const tx = await routingIsmFactory.deploy(domains, isms, overrides); const receipt = await this.multiProvider.handleTx(chain, tx); - // TODO: Break this out into a generalized function - const dispatchLogs = receipt.logs - .map((log) => { - try { - return routingIsmFactory.interface.parseLog(log); - } catch (e) { - return undefined; - } - }) - .filter( - (log): log is ethers.utils.LogDescription => - !!log && log.name === 'ModuleDeployed', - ); - const moduleAddress = dispatchLogs[0].args['module']; + const moduleAddress = receipt.events!.find( + (e) => e.event === 'ModuleDeployed', + )!.args!['module']; const routingIsm = DomainRoutingIsm__factory.connect( moduleAddress, this.multiProvider.getSigner(chain), @@ -200,20 +175,21 @@ export class HyperlaneIsmFactory extends HyperlaneApp { chain, await routingIsm.transferOwnership(config.owner, overrides), ); - const address = dispatchLogs[0].args['module']; - return IRoutingIsm__factory.connect(address, signer); + return IRoutingIsm__factory.connect(moduleAddress, signer); } private async deployAggregationIsm( chain: ChainName, config: AggregationIsmConfig, + origin?: ChainName, ) { const signer = this.multiProvider.getSigner(chain); const aggregationIsmFactory = this.getContracts(chain).aggregationIsmFactory; const addresses: types.Address[] = []; for (const module of config.modules) { - addresses.push((await this.deploy(chain, module)).address); + const submodule = await this.deploy(chain, module, origin); + addresses.push(submodule.address); } const address = await this.deployMOfNFactory( chain,