feat(cli,sdk): ensure consistency while passing ContractVerifier from CLI (#4151)

### Description

- ensures consistency while passing ContractVerifier from CLI

### Drive-by changes

- logging

### Related issues

- https://github.com/hyperlane-xyz/hyperlane-monorepo/issues/4130

### Backward compatibility

- some breaking sdk-side changes

### Testing

- manual
pull/4131/merge
Noah Bayindirli 🥂 4 months ago committed by GitHub
parent 40255575c0
commit e5807d4801
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 36
      typescript/cli/src/context/context.ts
  2. 29
      typescript/cli/src/deploy/core.ts
  3. 68
      typescript/cli/src/deploy/warp.ts
  4. 24
      typescript/sdk/src/core/EvmCoreModule.ts
  5. 4
      typescript/sdk/src/core/EvmIcaModule.ts
  6. 12
      typescript/sdk/src/deploy/EvmModuleDeployer.ts
  7. 4
      typescript/sdk/src/deploy/HyperlaneDeployer.ts
  8. 41
      typescript/sdk/src/deploy/verify/ContractVerifier.ts
  9. 27
      typescript/sdk/src/hook/EvmHookModule.ts
  10. 26
      typescript/sdk/src/ism/EvmIsmModule.ts
  11. 5
      typescript/sdk/src/providers/MultiProvider.ts
  12. 51
      typescript/sdk/src/token/EvmERC20WarpModule.ts

@ -1,3 +1,4 @@
import { confirm } from '@inquirer/prompts';
import { ethers } from 'ethers';
import {
@ -7,6 +8,8 @@ import {
} from '@hyperlane-xyz/registry';
import { FileSystemRegistry } from '@hyperlane-xyz/registry/fs';
import {
ChainMap,
ChainMetadata,
ChainName,
MultiProvider,
SubmissionStrategy,
@ -20,6 +23,7 @@ import { forkNetworkToMultiProvider, verifyAnvil } from '../deploy/dry-run.js';
import { logBlue } from '../logger.js';
import { runSingleChainSelectionStep } from '../utils/chains.js';
import { readYamlOrJson } from '../utils/files.js';
import { detectAndConfirmOrPrompt } from '../utils/input.js';
import { getImpersonatedSigner, getSigner } from '../utils/keys.js';
import {
@ -199,3 +203,35 @@ function getSubmissionStrategy(
);
return SubmissionStrategySchema.parse(submissionStrategyFileContent);
}
export async function getOrRequestApiKeys(
chains: ChainName[],
chainMetadata: ChainMap<ChainMetadata>,
): Promise<ChainMap<string>> {
const apiKeys: ChainMap<string> = {};
for (const chain of chains) {
const wantApiKey = await confirm({
default: false,
message: `Do you want to use an API key to verify on this (${chain}) chain's block explorer`,
});
if (wantApiKey) {
apiKeys[chain] = await detectAndConfirmOrPrompt(
async () => {
const blockExplorers = chainMetadata[chain].blockExplorers;
if (!(blockExplorers && blockExplorers.length > 0)) return;
for (const blockExplorer of blockExplorers) {
/* The current apiKeys mapping only accepts one key, even if there are multiple explorer options present. */
if (blockExplorer.apiKey) return blockExplorer.apiKey;
}
return undefined;
},
`Enter an API key for the ${chain} explorer`,
`${chain} api key`,
`${chain} metadata blockExplorers config`,
);
}
}
return apiKeys;
}

@ -1,8 +1,17 @@
import { stringify as yamlStringify } from 'yaml';
import { ChainName, CoreConfig, EvmCoreModule } from '@hyperlane-xyz/sdk';
import { buildArtifact as coreBuildArtifact } from '@hyperlane-xyz/core/buildArtifact.js';
import {
ChainMap,
ChainName,
ContractVerifier,
CoreConfig,
EvmCoreModule,
ExplorerLicenseType,
} from '@hyperlane-xyz/sdk';
import { MINIMUM_CORE_DEPLOY_GAS } from '../consts.js';
import { getOrRequestApiKeys } from '../context/context.js';
import { WriteCommandContext } from '../context/types.js';
import { log, logBlue, logGreen } from '../logger.js';
import { runSingleChainSelectionStep } from '../utils/chains.js';
@ -39,6 +48,7 @@ export async function runCoreDeploy({
dryRunChain,
registry,
skipConfirmation,
multiProvider,
} = context;
// Select a dry-run chain if it's not supplied
@ -51,6 +61,11 @@ export async function runCoreDeploy({
'Select chain to connect:',
);
}
let apiKeys: ChainMap<string> = {};
if (!skipConfirmation)
apiKeys = await getOrRequestApiKeys([chain], chainMetadata);
const deploymentParams: DeployParams = {
context,
chain,
@ -68,11 +83,19 @@ export async function runCoreDeploy({
const initialBalances = await prepareDeploy(context, userAddress, [chain]);
logBlue('All systems ready, captain! Beginning deployment...');
const contractVerifier = new ContractVerifier(
multiProvider,
apiKeys,
coreBuildArtifact,
ExplorerLicenseType.MIT,
);
logBlue('🚀 All systems ready, captain! Beginning deployment...');
const evmCoreModule = await EvmCoreModule.create({
chain,
config,
multiProvider: context.multiProvider,
multiProvider,
contractVerifier,
});
await completeDeploy(context, 'core', initialBalances, userAddress, [chain]);

@ -1,12 +1,16 @@
import { confirm } from '@inquirer/prompts';
import { stringify as yamlStringify } from 'yaml';
import { buildArtifact as coreBuildArtifact } from '@hyperlane-xyz/core/buildArtifact.js';
import { IRegistry } from '@hyperlane-xyz/registry';
import {
AggregationIsmConfig,
ChainMap,
ChainName,
ContractVerifier,
EvmERC20WarpModule,
EvmIsmModule,
ExplorerLicenseType,
HypERC20Deployer,
HypERC721Deployer,
HyperlaneAddresses,
@ -38,6 +42,7 @@ import {
import { readWarpRouteDeployConfig } from '../config/warp.js';
import { MINIMUM_WARP_DEPLOY_GAS } from '../consts.js';
import { getOrRequestApiKeys } from '../context/context.js';
import { WriteCommandContext } from '../context/types.js';
import {
log,
@ -75,7 +80,7 @@ export async function runWarpRouteDeploy({
context: WriteCommandContext;
warpRouteDeploymentConfigPath?: string;
}) {
const { signer, skipConfirmation } = context;
const { signer, skipConfirmation, chainMetadata } = context;
if (
!warpRouteDeploymentConfigPath ||
@ -98,13 +103,18 @@ export async function runWarpRouteDeploy({
context,
);
const chains = Object.keys(warpRouteConfig);
let apiKeys: ChainMap<string> = {};
if (!skipConfirmation)
apiKeys = await getOrRequestApiKeys(chains, chainMetadata);
const deploymentParams = {
context,
warpDeployConfig: warpRouteConfig,
};
await runDeployPlanStep(deploymentParams);
const chains = Object.keys(warpRouteConfig);
await runPreflightChecksForChains({
context,
@ -116,7 +126,7 @@ export async function runWarpRouteDeploy({
const initialBalances = await prepareDeploy(context, userAddress, chains);
await executeDeploy(deploymentParams);
await executeDeploy(deploymentParams, apiKeys);
await completeDeploy(context, 'warp', initialBalances, userAddress, chains);
}
@ -134,8 +144,8 @@ async function runDeployPlanStep({ context, warpDeployConfig }: DeployParams) {
if (!isConfirmed) throw new Error('Deployment cancelled');
}
async function executeDeploy(params: DeployParams) {
logBlue('All systems ready, captain! Beginning deployment...');
async function executeDeploy(params: DeployParams, apiKeys: ChainMap<string>) {
logBlue('🚀 All systems ready, captain! Beginning deployment...');
const {
warpDeployConfig,
@ -151,7 +161,17 @@ async function executeDeploy(params: DeployParams) {
? { [dryRunChain]: warpDeployConfig[dryRunChain] }
: warpDeployConfig;
const ismFactoryDeployer = new HyperlaneProxyFactoryDeployer(multiProvider);
const contractVerifier = new ContractVerifier(
multiProvider,
apiKeys,
coreBuildArtifact,
ExplorerLicenseType.MIT,
);
const ismFactoryDeployer = new HyperlaneProxyFactoryDeployer(
multiProvider,
contractVerifier,
);
// For each chain in WarpRouteConfig, deploy each Ism Factory, if it's not in the registry
// Then return a modified config with the ism address as a string
@ -160,6 +180,7 @@ async function executeDeploy(params: DeployParams) {
multiProvider,
registry,
ismFactoryDeployer,
contractVerifier,
);
const deployedContracts = await deployer.deploy(modifiedConfig);
@ -179,6 +200,7 @@ async function deployAndResolveWarpIsm(
multiProvider: MultiProvider,
registry: IRegistry,
ismFactoryDeployer: HyperlaneProxyFactoryDeployer,
contractVerifier?: ContractVerifier,
): Promise<WarpRouteDeployConfig> {
return promiseObjAll(
objMap(warpConfig, async (chain, config) => {
@ -226,6 +248,7 @@ async function deployAndResolveWarpIsm(
staticMessageIdMultisigIsmFactory:
chainAddresses.staticMessageIdMultisigIsmFactory,
},
contractVerifier,
);
logGreen(
@ -246,6 +269,7 @@ async function createWarpIsm(
warpConfig: WarpRouteDeployConfig,
multiProvider: MultiProvider,
factoryAddresses: HyperlaneAddresses<any>,
contractVerifier?: ContractVerifier,
): Promise<string> {
const {
domainRoutingIsmFactory,
@ -266,6 +290,7 @@ async function createWarpIsm(
staticMessageIdMultisigIsmFactory,
},
config: warpConfig[chain].interchainSecurityModule!,
contractVerifier,
});
const { deployedIsm } = evmIsmModule.serialize();
return deployedIsm;
@ -337,7 +362,7 @@ export async function runWarpRouteApply(params: ApplyParams) {
const {
warpDeployConfig,
warpCoreConfig,
context: { registry, multiProvider },
context: { registry, multiProvider, chainMetadata, skipConfirmation },
} = params;
// Addresses used to get static Ism factories
@ -349,6 +374,19 @@ export async function runWarpRouteApply(params: ApplyParams) {
warpCoreConfig.tokens.map((token) => [token.chainName, token]),
);
const chains = Object.keys(warpDeployConfig);
let apiKeys: ChainMap<string> = {};
if (!skipConfirmation)
apiKeys = await getOrRequestApiKeys(chains, chainMetadata);
const contractVerifier = new ContractVerifier(
multiProvider,
apiKeys,
coreBuildArtifact,
ExplorerLicenseType.MIT,
);
// Attempt to update Warp Routes
// Can update existing or deploy new contracts
logGray(`Comparing target and onchain Warp configs`);
@ -359,13 +397,17 @@ export async function runWarpRouteApply(params: ApplyParams) {
config.ismFactoryAddresses = addresses[
chain
] as ProxyFactoryFactoriesAddresses;
const evmERC20WarpModule = new EvmERC20WarpModule(multiProvider, {
config,
chain,
addresses: {
deployedTokenRoute: warpCoreByChain[chain].addressOrDenom!,
const evmERC20WarpModule = new EvmERC20WarpModule(
multiProvider,
{
config,
chain,
addresses: {
deployedTokenRoute: warpCoreByChain[chain].addressOrDenom!,
},
},
});
contractVerifier,
);
const transactions = await evmERC20WarpModule.update(config);
// Send Txs

@ -12,6 +12,7 @@ import {
ProxyFactoryFactories,
proxyFactoryFactories,
} from '../deploy/contracts.js';
import { ContractVerifier } from '../deploy/verify/ContractVerifier.js';
import { HyperlaneIsmFactory } from '../ism/HyperlaneIsmFactory.js';
import { MultiProvider } from '../providers/MultiProvider.js';
import { AnnotatedEV5Transaction } from '../providers/ProviderType.js';
@ -72,12 +73,14 @@ export class EvmCoreModule extends HyperlaneModule<
chain: ChainNameOrId;
config: CoreConfig;
multiProvider: MultiProvider;
contractVerifier?: ContractVerifier;
}): Promise<EvmCoreModule> {
const { chain, config, multiProvider } = params;
const { chain, config, multiProvider, contractVerifier } = params;
const addresses = await EvmCoreModule.deploy({
config,
multiProvider,
chain,
contractVerifier,
});
// Create CoreModule and deploy the Core contracts
@ -98,18 +101,18 @@ export class EvmCoreModule extends HyperlaneModule<
config: CoreConfig;
multiProvider: MultiProvider;
chain: ChainNameOrId;
contractVerifier?: ContractVerifier;
}): Promise<DeployedCoreAdresses> {
const { config, multiProvider, chain } = params;
const { config, multiProvider, chain, contractVerifier } = params;
const chainName = multiProvider.getChainName(chain);
// Deploy Ism Factories
const ismFactoryFactories = await EvmCoreModule.deployIsmFactories({
chainName,
config,
multiProvider,
contractVerifier,
});
// Deploy IsmFactory to be used in CoreDeployer
const ismFactory = new HyperlaneIsmFactory(
attachContractsMap(
{ [chainName]: ismFactoryFactories },
@ -118,8 +121,11 @@ export class EvmCoreModule extends HyperlaneModule<
multiProvider,
);
// Initialize Deployer
const coreDeployer = new HyperlaneCoreDeployer(multiProvider, ismFactory);
const coreDeployer = new HyperlaneCoreDeployer(
multiProvider,
ismFactory,
contractVerifier,
);
// Deploy proxyAdmin
const proxyAdmin = (
@ -144,6 +150,7 @@ export class EvmCoreModule extends HyperlaneModule<
mailbox: mailbox.address,
owner: await multiProvider.getSigner(chain).getAddress(),
},
contractVerifier,
})
).serialize();
@ -189,12 +196,13 @@ export class EvmCoreModule extends HyperlaneModule<
chainName: string;
config: CoreConfig;
multiProvider: MultiProvider;
contractVerifier?: ContractVerifier;
}): Promise<HyperlaneAddresses<ProxyFactoryFactories>> {
const { chainName, config, multiProvider } = params;
const { chainName, config, multiProvider, contractVerifier } = params;
// ChainMap is still needed for HyperlaneIsmFactory
const proxyFactoryDeployer = new HyperlaneProxyFactoryDeployer(
multiProvider,
contractVerifier,
);
const ismFactoriesFactory = await proxyFactoryDeployer.deploy({
[chainName]: config,

@ -2,6 +2,7 @@ import { ProtocolType, rootLogger } from '@hyperlane-xyz/utils';
import { serializeContracts } from '../contracts/contracts.js';
import { HyperlaneAddresses } from '../contracts/types.js';
import { ContractVerifier } from '../deploy/verify/ContractVerifier.js';
import { InterchainAccountDeployer } from '../middleware/account/InterchainAccountDeployer.js';
import { InterchainAccountFactories } from '../middleware/account/contracts.js';
import { MultiProvider } from '../providers/MultiProvider.js';
@ -55,13 +56,16 @@ export class EvmIcaModule extends HyperlaneModule<
chain,
config,
multiProvider,
contractVerifier,
}: {
chain: ChainNameOrId;
config: InterchainAccountConfig;
multiProvider: MultiProvider;
contractVerifier?: ContractVerifier;
}): Promise<EvmIcaModule> {
const interchainAccountDeployer = new InterchainAccountDeployer(
multiProvider,
contractVerifier,
);
const deployedContracts = await interchainAccountDeployer.deployContracts(
multiProvider.getChainName(chain),

@ -30,13 +30,15 @@ export class EvmModuleDeployer<Factories extends HyperlaneFactories> {
protected readonly logger = rootLogger.child({
module: 'EvmModuleDeployer',
}),
protected readonly contractVerifier = new ContractVerifier(
protected readonly contractVerifier?: ContractVerifier,
) {
this.contractVerifier ??= new ContractVerifier(
multiProvider,
{},
coreBuildArtifact,
ExplorerLicenseType.MIT,
),
) {}
);
}
// Deploys a contract from a factory
public async deployContractFromFactory<F extends ethers.ContractFactory>({
@ -53,9 +55,9 @@ export class EvmModuleDeployer<Factories extends HyperlaneFactories> {
initializeArgs?: Parameters<Awaited<ReturnType<F['deploy']>>['initialize']>;
}): Promise<ReturnType<F['deploy']>> {
this.logger.info(
`Deploy ${contractName} on ${chain} with constructor args (${constructorArgs.join(
`Deploying ${contractName} on ${chain} with constructor args (${constructorArgs.join(
', ',
)})`,
)})...`,
);
const contract = await this.multiProvider.handleDeploy(
chain,

@ -389,9 +389,9 @@ export abstract class HyperlaneDeployer<
}
this.logger.info(
`Deploy ${contractName} on ${chain} with constructor args (${constructorArgs.join(
`Deploying ${contractName} on ${chain} with constructor args (${constructorArgs.join(
', ',
)})`,
)})...`,
);
const contract = await this.multiProvider.handleDeploy(
chain,

@ -192,14 +192,13 @@ export class ContractVerifier {
input: ContractVerificationInput,
verificationLogger: Logger,
): Promise<void> {
if (!input.isProxy) return;
verificationLogger.debug(`📝 Verifying proxy at ${input.address}...`);
try {
const proxyGuid = await this.submitForm(
const { proxyGuid } = await this.markProxy(
chain,
ExplorerApiActions.MARK_PROXY,
input,
verificationLogger,
{ address: input.address },
);
if (!proxyGuid) return;
@ -216,7 +215,7 @@ export class ContractVerifier {
input.address,
);
verificationLogger.debug(
`Successfully verified proxy ${addressUrl}#readProxyContract`,
`Successfully verified proxy ${addressUrl}#readProxyContract`,
);
} catch (error) {
verificationLogger.debug(
@ -226,12 +225,34 @@ export class ContractVerifier {
}
}
private async markProxy(
chain: ChainName,
input: ContractVerificationInput,
verificationLogger: Logger,
): Promise<{ proxyGuid: any }> {
try {
return this.submitForm(
chain,
ExplorerApiActions.MARK_PROXY,
verificationLogger,
{ address: input.address },
);
} catch (error) {
verificationLogger.debug(
`Marking of proxy at ${input.address} failed: ${error}`,
);
throw error;
}
}
private async verifyImplementation(
chain: ChainName,
input: ContractVerificationInput,
verificationLogger: Logger,
): Promise<void> {
verificationLogger.debug(`Verifying implementation at ${input.address}`);
verificationLogger.debug(
`📝 Verifying implementation at ${input.address}...`,
);
const sourceName = this.contractSourceMap[input.name];
if (!sourceName) {
@ -267,7 +288,9 @@ export class ContractVerifier {
chain,
input.address,
);
verificationLogger.debug(`Successfully verified ${addressUrl}#code`);
verificationLogger.debug(
`✅ Successfully verified implementation ${addressUrl}#code`,
);
}
async verifyContract(
@ -320,7 +343,7 @@ export class ContractVerifier {
return;
}
await this.verifyImplementation(chain, input, verificationLogger);
await this.verifyProxy(chain, input, verificationLogger);
if (input.isProxy) await this.verifyProxy(chain, input, verificationLogger);
else await this.verifyImplementation(chain, input, verificationLogger);
}
}

@ -95,7 +95,7 @@ export class EvmHookModule extends HyperlaneModule<
HookConfig,
HyperlaneAddresses<ProxyFactoryFactories> & HookModuleAddresses
>,
contractVerifier?: ContractVerifier,
protected readonly contractVerifier?: ContractVerifier,
) {
params.config = HookConfigSchema.parse(params.config);
super(params);
@ -226,25 +226,29 @@ export class EvmHookModule extends HyperlaneModule<
proxyFactoryFactories,
coreAddresses,
multiProvider,
contractVerifier,
}: {
chain: ChainNameOrId;
config: HookConfig;
proxyFactoryFactories: HyperlaneAddresses<ProxyFactoryFactories>;
coreAddresses: CoreAddresses;
multiProvider: MultiProvider;
contractVerifier?: ContractVerifier;
}): Promise<EvmHookModule> {
// instantiate new EvmHookModule
const module = new EvmHookModule(multiProvider, {
addresses: {
...proxyFactoryFactories,
...coreAddresses,
deployedHook: ethers.constants.AddressZero,
const module = new EvmHookModule(
multiProvider,
{
addresses: {
...proxyFactoryFactories,
...coreAddresses,
deployedHook: ethers.constants.AddressZero,
},
chain,
config,
},
chain,
config,
});
contractVerifier,
);
// deploy hook and assign address to module
const deployedHook = await module.deploy({ config });
module.args.addresses.deployedHook = deployedHook.address;
@ -751,6 +755,7 @@ export class EvmHookModule extends HyperlaneModule<
proxyFactoryFactories: this.args.addresses,
mailbox: mailbox,
multiProvider: this.multiProvider,
contractVerifier: this.contractVerifier,
})
).serialize().deployedIsm;

@ -87,7 +87,7 @@ export class EvmIsmModule extends HyperlaneModule<
IsmConfig,
HyperlaneAddresses<ProxyFactoryFactories> & IsmModuleAddresses
>,
contractVerifier?: ContractVerifier,
protected readonly contractVerifier?: ContractVerifier,
) {
params.config = IsmConfigSchema.parse(params.config);
super(params);
@ -234,25 +234,29 @@ export class EvmIsmModule extends HyperlaneModule<
proxyFactoryFactories,
mailbox,
multiProvider,
contractVerifier,
}: {
chain: ChainNameOrId;
config: IsmConfig;
proxyFactoryFactories: HyperlaneAddresses<ProxyFactoryFactories>;
mailbox: Address;
multiProvider: MultiProvider;
contractVerifier?: ContractVerifier;
}): Promise<EvmIsmModule> {
// instantiate new EvmIsmModule
const module = new EvmIsmModule(multiProvider, {
addresses: {
...proxyFactoryFactories,
mailbox,
deployedIsm: ethers.constants.AddressZero,
const module = new EvmIsmModule(
multiProvider,
{
addresses: {
...proxyFactoryFactories,
mailbox,
deployedIsm: ethers.constants.AddressZero,
},
chain,
config,
},
chain,
config,
});
contractVerifier,
);
// deploy ISM and assign address to module
const deployedIsm = await module.deploy({ config });
module.args.addresses.deployedIsm = deployedIsm.address;

@ -311,7 +311,10 @@ export class MultiProvider<MetaExt = {}> extends ChainMetadataManager<MetaExt> {
...overrides,
});
this.logger.trace({ transaction: deployTx }, `Deploying contract`);
this.logger.trace(
`Deploying contract ${contract.address} on ${chainNameOrId}:`,
{ transaction: deployTx },
);
// wait for deploy tx to be confirmed
await this.handleTx(chainNameOrId, contract.deployTransaction);

@ -1,4 +1,6 @@
import { MailboxClient__factory } from '@hyperlane-xyz/core';
import { buildArtifact as coreBuildArtifact } from '@hyperlane-xyz/core/buildArtifact.js';
import { ContractVerifier, ExplorerLicenseType } from '@hyperlane-xyz/sdk';
import {
Address,
Domain,
@ -44,10 +46,17 @@ export class EvmERC20WarpModule extends HyperlaneModule<
deployedTokenRoute: Address;
}
>,
protected readonly contractVerifier?: ContractVerifier,
) {
super(args);
this.reader = new EvmERC20WarpRouteReader(multiProvider, args.chain);
this.domainId = multiProvider.getDomainId(args.chain);
this.contractVerifier ??= new ContractVerifier(
multiProvider,
{},
coreBuildArtifact,
ExplorerLicenseType.MIT,
);
}
/**
@ -143,16 +152,21 @@ export class EvmERC20WarpModule extends HyperlaneModule<
'Ism Factories addresses not provided',
);
const ismModule = new EvmIsmModule(this.multiProvider, {
chain: this.args.chain,
config: expectedConfig.interchainSecurityModule,
addresses: {
...expectedConfig.ismFactoryAddresses,
mailbox: expectedConfig.mailbox,
deployedIsm: (actualConfig.interchainSecurityModule as DerivedIsmConfig)
.address,
const ismModule = new EvmIsmModule(
this.multiProvider,
{
chain: this.args.chain,
config: expectedConfig.interchainSecurityModule,
addresses: {
...expectedConfig.ismFactoryAddresses,
mailbox: expectedConfig.mailbox,
deployedIsm: (
actualConfig.interchainSecurityModule as DerivedIsmConfig
).address,
},
},
});
this.contractVerifier,
);
this.logger.info(
`Comparing target ISM config with ${this.args.chain} chain`,
);
@ -176,18 +190,23 @@ export class EvmERC20WarpModule extends HyperlaneModule<
chain: ChainNameOrId;
config: TokenRouterConfig;
multiProvider: MultiProvider;
contractVerifier?: ContractVerifier;
}): Promise<EvmERC20WarpModule> {
const { chain, config, multiProvider } = params;
const { chain, config, multiProvider, contractVerifier } = params;
const chainName = multiProvider.getChainName(chain);
const deployer = new HypERC20Deployer(multiProvider);
const deployedContracts = await deployer.deployContracts(chainName, config);
return new EvmERC20WarpModule(multiProvider, {
addresses: {
deployedTokenRoute: deployedContracts[config.type].address,
return new EvmERC20WarpModule(
multiProvider,
{
addresses: {
deployedTokenRoute: deployedContracts[config.type].address,
},
chain,
config,
},
chain,
config,
});
contractVerifier,
);
}
}

Loading…
Cancel
Save