UNPKG

@hyperlane-xyz/sdk

Version:

The official SDK for the Hyperlane Network

131 lines 6.9 kB
import { IPostDispatchHook__factory, } from '@hyperlane-xyz/core'; import { addBufferToGasLimit, isZeroishAddress, rootLogger, } from '@hyperlane-xyz/utils'; import { HyperlaneDeployer } from '../deploy/HyperlaneDeployer.js'; import { HyperlaneHookDeployer } from '../hook/HyperlaneHookDeployer.js'; import { moduleMatchesConfig } from '../ism/utils.js'; import { TestRecipientDeployer } from './TestRecipientDeployer.js'; import { coreFactories } from './contracts.js'; export class HyperlaneCoreDeployer extends HyperlaneDeployer { ismFactory; hookDeployer; testRecipient; constructor(multiProvider, ismFactory, contractVerifier, concurrentDeploy = false, chainTimeoutMs = 1000 * 60 * 10) { super(multiProvider, coreFactories, { logger: rootLogger.child({ module: 'CoreDeployer' }), chainTimeoutMs, ismFactory, contractVerifier, concurrentDeploy, }); this.ismFactory = ismFactory; this.hookDeployer = new HyperlaneHookDeployer(multiProvider, {}, ismFactory, contractVerifier, concurrentDeploy); this.testRecipient = new TestRecipientDeployer(multiProvider, contractVerifier, concurrentDeploy); } cacheAddressesMap(addressesMap) { this.hookDeployer.cacheAddressesMap(addressesMap); this.testRecipient.cacheAddressesMap(addressesMap); super.cacheAddressesMap(addressesMap); } async deployMailbox(chain, config, proxyAdmin) { const domain = this.multiProvider.getDomainId(chain); const mailbox = await this.deployProxiedContract(chain, 'mailbox', 'mailbox', proxyAdmin, [domain]); let defaultIsm = await mailbox.defaultIsm(); const matches = await moduleMatchesConfig(chain, defaultIsm, config.defaultIsm, this.multiProvider, this.ismFactory.getContracts(chain)); if (!matches) { this.logger.debug('Deploying default ISM'); defaultIsm = await this.deployIsm(chain, config.defaultIsm, mailbox.address); } this.cachedAddresses[chain].interchainSecurityModule = defaultIsm; const hookAddresses = { mailbox: mailbox.address, proxyAdmin }; this.logger.debug('Deploying default hook'); const defaultHook = await this.deployHook(chain, config.defaultHook, hookAddresses); this.logger.debug('Deploying required hook'); const requiredHook = await this.deployHook(chain, config.requiredHook, hookAddresses); const txOverrides = this.multiProvider.getTransactionOverrides(chain); // Check if the mailbox has already been initialized const currentDefaultIsm = await mailbox.defaultIsm(); if (isZeroishAddress(currentDefaultIsm)) { // If the default ISM is the zero address, the mailbox hasn't been initialized this.logger.debug('Initializing mailbox'); try { const estimatedGas = await mailbox.estimateGas.initialize(config.owner, defaultIsm, defaultHook.address, requiredHook.address); await this.multiProvider.handleTx(chain, mailbox.initialize(config.owner, defaultIsm, defaultHook.address, requiredHook.address, { gasLimit: addBufferToGasLimit(estimatedGas), ...txOverrides, })); } catch (e) { // If we still get an error here, it's likely a genuine error this.logger.error('Failed to initialize mailbox:', e); throw e; } } else { // If the default ISM is not the zero address, the mailbox has likely been initialized this.logger.debug('Mailbox appears to be already initialized'); } await this.configureHook(chain, mailbox, defaultHook.address, (_mailbox) => _mailbox.defaultHook(), (_mailbox, _hook) => _mailbox.populateTransaction.setDefaultHook(_hook, { ...txOverrides })); await this.configureHook(chain, mailbox, requiredHook.address, (_mailbox) => _mailbox.requiredHook(), (_mailbox, _hook) => _mailbox.populateTransaction.setRequiredHook(_hook, { ...txOverrides })); await this.configureIsm(chain, mailbox, defaultIsm, (_mailbox) => _mailbox.defaultIsm(), (_mailbox, _module) => _mailbox.populateTransaction.setDefaultIsm(_module)); return mailbox; } async deployValidatorAnnounce(chain, mailboxAddress) { const validatorAnnounce = await this.deployContract(chain, 'validatorAnnounce', [mailboxAddress]); return validatorAnnounce; } async deployHook(chain, config, coreAddresses) { if (typeof config === 'string') { return IPostDispatchHook__factory.connect(config, this.multiProvider.getProvider(chain)); } const hooks = await this.hookDeployer.deployContracts(chain, config, coreAddresses); this.addDeployedContracts(chain, this.hookDeployer.deployedContracts[chain], this.hookDeployer.verificationInputs[chain]); if (typeof config === 'string') { return Object.values(hooks)[0]; } else { return hooks[config.type]; } } async deployIsm(chain, config, mailbox) { const ism = await this.ismFactory.deploy({ destination: chain, config, mailbox, }); this.addDeployedContracts(chain, this.ismFactory.deployedIsms[chain]); return ism.address; } async deployTestRecipient(chain, interchainSecurityModule) { const testRecipient = await this.testRecipient.deployContracts(chain, { interchainSecurityModule, }); this.addDeployedContracts(chain, testRecipient); return testRecipient.testRecipient; } async deployContracts(chain, config) { if (config.remove) { // skip deploying to chains configured to be removed return undefined; } const proxyAdmin = await this.deployContract(chain, 'proxyAdmin', []); const mailbox = await this.deployMailbox(chain, config, proxyAdmin.address); const validatorAnnounce = await this.deployValidatorAnnounce(chain, mailbox.address); if (config.upgrade) { const timelockController = await this.deployTimelock(chain, config.upgrade.timelock); config.ownerOverrides = { ...config.ownerOverrides, proxyAdmin: timelockController.address, }; } const testRecipient = await this.deployTestRecipient(chain, this.cachedAddresses[chain].interchainSecurityModule); const contracts = { mailbox, proxyAdmin, validatorAnnounce, testRecipient, }; await this.transferOwnershipOfContracts(chain, config, contracts); return contracts; } } //# sourceMappingURL=HyperlaneCoreDeployer.js.map