diff --git a/packages/ua-utils-evm-hardhat/src/tasks/oapp/wire.ts b/packages/ua-utils-evm-hardhat/src/tasks/oapp/wire.ts index 3ccfff06e..4d619fff5 100644 --- a/packages/ua-utils-evm-hardhat/src/tasks/oapp/wire.ts +++ b/packages/ua-utils-evm-hardhat/src/tasks/oapp/wire.ts @@ -13,10 +13,20 @@ import { import { OAppOmniGraphHardhat, OAppOmniGraphHardhatSchema } from '@/oapp' import { OAppOmniGraph, configureOApp } from '@layerzerolabs/ua-utils' import { createOAppFactory } from '@layerzerolabs/ua-utils-evm' -import { OmniGraphBuilderHardhat, createConnectedContractFactory } from '@layerzerolabs/utils-evm-hardhat' -import { OmniTransaction } from '@layerzerolabs/utils' +import { + OmniGraphBuilderHardhat, + OmniPointHardhat, + createConnectedContractFactory, + createOmniGraphHardhatTransformer, + createOmniNodeHardhatTransformer, + createOmniPointHardhatTransformer, +} from '@layerzerolabs/utils-evm-hardhat' +import { OmniTransaction, firstFactory, formatEid, sequence } from '@layerzerolabs/utils' import { printTransactions } from '@layerzerolabs/utils' import { resolve } from 'path' +import { createContractFactory } from '@layerzerolabs/utils-evm-hardhat' +import { createDeployFactory } from '@layerzerolabs/utils-evm-hardhat' +import { WithContractName } from '@layerzerolabs/utils-evm-hardhat' interface TaskArgs { oappConfig: string @@ -83,6 +93,22 @@ const action: ActionType = async ({ oappConfig: oappConfigPath, logLev logger.verbose(`Config file '${oappConfigPath}' has correct structure`) logger.debug(`The hardhat config is:\n\n${printJson(hardhatGraph)}`) + const getTags = async (point: WithContractName) => { + await promptToContinue( + `Contract ${point.contractName} has not been deployed yet for ${formatEid( + point.eid + )}. Would you like to deploy it now?` + ) + + return undefined + } + const contractFactory = createConnectedContractFactory( + firstFactory(createDeployFactory(getTags), createContractFactory()) + ) + const pointTransformer = createOmniPointHardhatTransformer(contractFactory) + const nodeTransformer = createOmniNodeHardhatTransformer(pointTransformer) + const graphTransformer = createOmniGraphHardhatTransformer(nodeTransformer, undefined, sequence) + // What we need to do now is transform the config from hardhat format to the generic format // with addresses instead of contractNames logger.verbose(`Transforming '${oappConfigPath}' from hardhat-specific format to generic format`) @@ -90,7 +116,7 @@ const action: ActionType = async ({ oappConfig: oappConfigPath, logLev try { // The transformation is achieved using a builder that also validates the resulting graph // (i.e. makes sure that all the contracts exist and connections are valid) - const builder = await OmniGraphBuilderHardhat.fromConfig(hardhatGraph) + const builder = await OmniGraphBuilderHardhat.fromConfig(hardhatGraph, graphTransformer) // We only need the graph so we throw away the builder graph = builder.graph @@ -104,7 +130,7 @@ const action: ActionType = async ({ oappConfig: oappConfigPath, logLev // At this point we are ready to create the list of transactions logger.verbose(`Creating a list of wiring transactions`) - const contractFactory = createConnectedContractFactory() + const oAppFactory = createOAppFactory(contractFactory) let transactions: OmniTransaction[] diff --git a/packages/utils-evm-hardhat/src/omnigraph/contracts.ts b/packages/utils-evm-hardhat/src/omnigraph/contracts.ts index 076d32f5c..f0f386097 100644 --- a/packages/utils-evm-hardhat/src/omnigraph/contracts.ts +++ b/packages/utils-evm-hardhat/src/omnigraph/contracts.ts @@ -1,8 +1,13 @@ import pMemoize from 'p-memoize' import { ProviderFactory, connectOmniContract } from '@layerzerolabs/utils-evm' -import { createContractFactory } from '@/omnigraph/coordinates' -import type { OmniContractFactoryHardhat } from '@/omnigraph/types' +import { createContractFactory, omniDeploymentToContract } from '@/omnigraph/coordinates' +import type { OmniContractFactoryHardhat, OmniPointHardhat, WithContractName } from '@/omnigraph/types' import { createProviderFactory } from '@/provider' +import { Address, Factory } from '@layerzerolabs/utils' +import assert from 'assert' +import { HardhatRuntimeEnvironmentWithDeployments, assertHardhatDeploy } from '@/internal/assertions' +import { createNetworkEnvironmentFactory } from '@/runtime' +import { hasContractName } from './schema' export const createConnectedContractFactory = ( contractFactory: OmniContractFactoryHardhat = createContractFactory(), @@ -14,3 +19,59 @@ export const createConnectedContractFactory = ( return connectOmniContract(contract, provider) }) + +export const createDeployFactory = + ( + getTags: Factory< + [WithContractName, HardhatRuntimeEnvironmentWithDeployments], + string | string[] | null | undefined + >, + environmentFactory = createNetworkEnvironmentFactory() + ) => + async (point: OmniPointHardhat) => { + assert(hasContractName(point), `Deployment factory requires a contractName to be specified`) + + const env = await environmentFactory(point.eid) + assertHardhatDeploy(env) + + const tags = await getTags(point, env) + + try { + const deployments = await env.deployments.run(tags ?? undefined, { + writeDeploymentsToFiles: true, + }) + + const deployment = deployments[point.contractName] + assert( + deployment != null, + `Could not find deployment for contract ${point.contractName} after deploying with ${tags ?? 'no tags'}` + ) + + return omniDeploymentToContract({ eid: point.eid, deployment }) + } catch (error) { + throw new Error(`Unable to deploy contract ${point.contractName}: ${error}`) + } + } + +export const createUndeployedContractFactory = + ( + deploy: (point: OmniPointHardhat) => Promise
, + contractFactory = createContractFactory() + ): OmniContractFactoryHardhat => + async (point: OmniPointHardhat) => { + try { + return await contractFactory(point) + } catch (error) { + let address: Address | null | undefined + + try { + address = await deploy(point) + } catch { + // TODO Do we need to wrap the error here? + } + + if (address == null) throw error + + return await contractFactory({ ...point, address }) + } + }