UNPKG

@hyperlane-xyz/sdk

Version:

The official SDK for the Hyperlane Network

84 lines 5.08 kB
import { addBufferToGasLimit, addressToBytes32, objFilter, objMap, objMerge, } from '@hyperlane-xyz/utils'; import { filterOwnableContracts } from '../contracts/contracts.js'; import { HyperlaneDeployer } from '../deploy/HyperlaneDeployer.js'; export class HyperlaneRouterDeployer extends HyperlaneDeployer { async configureClients(contractsMap, configMap) { for (const chain of Object.keys(contractsMap)) { const contracts = contractsMap[chain]; const config = configMap[chain]; await super.configureClient(chain, this.router(contracts), config); } } async enrollRemoteRouters(deployedContractsMap, _, foreignRouters = {}) { this.logger.debug(`Enrolling deployed routers with each other (if not already)...`); // Make all routers aware of each other. // Routers that were deployed. const deployedRouters = objMap(deployedContractsMap, (_, contracts) => this.router(contracts).address); // All routers, including those that were deployed and those with existing deployments. const allRouters = objMerge(deployedRouters, foreignRouters); const allChains = Object.keys(allRouters); await Promise.all(Object.entries(deployedContractsMap).map(async ([chain, contracts]) => { const allRemoteChains = this.multiProvider .getRemoteChains(chain) .filter((c) => allChains.includes(c)); const enrollEntries = await Promise.all(allRemoteChains.map(async (remote) => { const remoteDomain = this.multiProvider.getDomainId(remote); const current = await this.router(contracts).routers(remoteDomain); const expected = addressToBytes32(allRouters[remote]); return current !== expected ? [remoteDomain, expected] : undefined; })); const entries = enrollEntries.filter((entry) => entry !== undefined); const domains = entries.map(([id]) => id); const addresses = entries.map(([, address]) => address); // skip if no enrollments are needed if (domains.length === 0) { return; } await super.runIfOwner(chain, this.router(contracts), async () => { const chains = domains.map((id) => this.multiProvider.getChainName(id)); this.logger.debug(`Enrolling remote routers (${chains.join(', ')}) on ${chain}`); const router = this.router(contracts); const estimatedGas = await router.estimateGas.enrollRemoteRouters(domains, addresses); // deploy with 10% buffer on gas limit const enrollTx = await router.enrollRemoteRouters(domains, addresses, { gasLimit: addBufferToGasLimit(estimatedGas), ...this.multiProvider.getTransactionOverrides(chain), }); await this.multiProvider.handleTx(chain, enrollTx); }); })); } async transferOwnership(contractsMap, configMap) { this.logger.debug(`Transferring ownership of ownables...`); for (const chain of Object.keys(contractsMap)) { const contracts = contractsMap[chain]; const ownables = (await filterOwnableContracts(contracts)); await this.transferOwnershipOfContracts(chain, configMap[chain], ownables); } } async deploy(configMap) { // Only deploy on chains that don't have foreign deployments. const configMapToDeploy = objFilter(configMap, (_chainName, config) => !config.foreignDeployment); // Create a map of chains that have foreign deployments. const foreignDeployments = objFilter(objMap(configMap, (_, config) => config.foreignDeployment), (_chainName, foreignDeployment) => foreignDeployment !== undefined); const deployedContractsMap = await super.deploy(configMapToDeploy); await this.enrollRemoteRouters(deployedContractsMap, configMap, foreignDeployments); await this.deployAndConfigureTokenFees(deployedContractsMap, configMap); await this.configureClients(deployedContractsMap, configMap); await this.transferOwnership(deployedContractsMap, configMap); this.logger.debug(`Finished deploying router contracts for all chains.`); return deployedContractsMap; } async deployAndConfigureTokenFees(deployedContractsMap, configMap) { // Intentionally a no-op in the base deployer. // Token-fee configuration is router-specific (e.g., fungible token routers) // and should be implemented by subclasses that know their router interface. for (const chain of Object.keys(deployedContractsMap)) { const config = configMap[chain]; if (!config.tokenFee) continue; this.logger.debug(`Token fee config detected on ${chain}, no-op in base deployer. Must be handled by subclass if applicable`); } } } //# sourceMappingURL=HyperlaneRouterDeployer.js.map