UNPKG

@hyperlane-xyz/sdk

Version:

The official SDK for the Hyperlane Network

181 lines 7.71 kB
import { constants } from 'ethers'; import { ERC20__factory, ERC721Enumerable__factory, IERC4626__factory, IXERC20Lockbox__factory, } from '@hyperlane-xyz/core'; import { ProtocolType, assert, objKeys, objMap, rootLogger, } from '@hyperlane-xyz/utils'; import { GasRouterDeployer } from '../router/GasRouterDeployer.js'; import { TokenType, gasOverhead } from './config.js'; import { hypERC20contracts, hypERC20factories, hypERC721contracts, hypERC721factories, } from './contracts.js'; import { TokenMetadataSchema, isCollateralTokenConfig, isNativeTokenConfig, isSyntheticRebaseTokenConfig, isSyntheticTokenConfig, isTokenMetadata, isXERC20TokenConfig, } from './types.js'; class TokenDeployer extends GasRouterDeployer { constructor(multiProvider, factories, loggerName, ismFactory, contractVerifier, concurrentDeploy = false) { super(multiProvider, factories, { logger: rootLogger.child({ module: loggerName }), ismFactory, contractVerifier, concurrentDeploy, }); // factories not used in deploy } async constructorArgs(_, config) { // TODO: derive as specified in https://github.com/hyperlane-xyz/hyperlane-monorepo/issues/5296 const scale = config.scale ?? 1; if (isCollateralTokenConfig(config) || isXERC20TokenConfig(config)) { return [config.token, scale, config.mailbox]; } else if (isNativeTokenConfig(config)) { return [scale, config.mailbox]; } else if (isSyntheticTokenConfig(config)) { assert(config.decimals, 'decimals is undefined for config'); // decimals must be defined by this point return [config.decimals, scale, config.mailbox]; } else if (isSyntheticRebaseTokenConfig(config)) { const collateralDomain = this.multiProvider.getDomainId(config.collateralChainName); return [config.decimals, scale, config.mailbox, collateralDomain]; } else { throw new Error('Unknown token type when constructing arguments'); } } async initializeArgs(chain, config) { const signer = await this.multiProvider.getSigner(chain).getAddress(); const defaultArgs = [ config.hook ?? constants.AddressZero, config.interchainSecurityModule ?? constants.AddressZero, // TransferOwnership will happen later in RouterDeployer signer, ]; if (isCollateralTokenConfig(config) || isXERC20TokenConfig(config) || isNativeTokenConfig(config)) { return defaultArgs; } else if (isSyntheticTokenConfig(config)) { return [ config.initialSupply ?? 0, config.name, config.symbol, ...defaultArgs, ]; } else if (isSyntheticRebaseTokenConfig(config)) { return [0, config.name, config.symbol, ...defaultArgs]; } else { throw new Error('Unknown collateral type when initializing arguments'); } } static async deriveTokenMetadata(multiProvider, configMap) { for (const [chain, config] of Object.entries(configMap)) { if (isTokenMetadata(config)) { return TokenMetadataSchema.parse(config); } else if (multiProvider.getProtocol(chain) !== ProtocolType.Ethereum) { // If the config didn't specify the token metadata, we can only now // derive it for Ethereum chains. So here we skip non-Ethereum chains. continue; } if (isNativeTokenConfig(config)) { const nativeToken = multiProvider.getChainMetadata(chain).nativeToken; if (nativeToken) { return TokenMetadataSchema.parse({ ...nativeToken, }); } } if (isCollateralTokenConfig(config) || isXERC20TokenConfig(config)) { const provider = multiProvider.getProvider(chain); if (config.isNft) { const erc721 = ERC721Enumerable__factory.connect(config.token, provider); const [name, symbol] = await Promise.all([ erc721.name(), erc721.symbol(), ]); return TokenMetadataSchema.parse({ name, symbol, }); } let token; switch (config.type) { case TokenType.XERC20Lockbox: token = await IXERC20Lockbox__factory.connect(config.token, provider).callStatic.ERC20(); break; case TokenType.collateralVault: token = await IERC4626__factory.connect(config.token, provider).callStatic.asset(); break; default: token = config.token; break; } const erc20 = ERC20__factory.connect(token, provider); const [name, symbol, decimals] = await Promise.all([ erc20.name(), erc20.symbol(), erc20.decimals(), ]); return TokenMetadataSchema.parse({ name, symbol, decimals, }); } } return undefined; } async deploy(configMap) { let tokenMetadata; try { tokenMetadata = await TokenDeployer.deriveTokenMetadata(this.multiProvider, configMap); } catch (err) { this.logger.error('Failed to derive token metadata', err, configMap); throw err; } const resolvedConfigMap = objMap(configMap, (_, config) => ({ ...tokenMetadata, gas: gasOverhead(config.type), ...config, })); return super.deploy(resolvedConfigMap); } } export class HypERC20Deployer extends TokenDeployer { constructor(multiProvider, ismFactory, contractVerifier, concurrentDeploy = false) { super(multiProvider, hypERC20factories, 'HypERC20Deployer', ismFactory, contractVerifier, concurrentDeploy); } router(contracts) { for (const key of objKeys(hypERC20factories)) { if (contracts[key]) { return contracts[key]; } } throw new Error('No matching contract found'); } routerContractKey(config) { assert(config.type in hypERC20factories, 'Invalid ERC20 token type'); return config.type; } routerContractName(config) { return hypERC20contracts[this.routerContractKey(config)]; } } export class HypERC721Deployer extends TokenDeployer { constructor(multiProvider, ismFactory, contractVerifier) { super(multiProvider, hypERC721factories, 'HypERC721Deployer', ismFactory, contractVerifier); } router(contracts) { for (const key of objKeys(hypERC721factories)) { if (contracts[key]) { return contracts[key]; } } throw new Error('No matching contract found'); } routerContractKey(config) { assert(config.type in hypERC721factories, 'Invalid ERC721 token type'); return config.type; } routerContractName(config) { return hypERC721contracts[this.routerContractKey(config)]; } } //# sourceMappingURL=deploy.js.map