Repository: NomicFoundation/hardhat-ignition
Pull request #560 (2023-10-16 18:52:43)

Define call ids based on the entire id of the contract being called, not just its name (PR 2)
This PR introduces a small change that makes working with multiple instances of the same contract in a module easier.


Patch:
diff --git a/examples/complete/ignition/modules/CompleteModule.js b/examples/complete/ignition/modules/CompleteModule.js
index 5e5e6022..ef8bef31 100644
--- a/examples/complete/ignition/modules/CompleteModule.js
+++ b/examples/complete/ignition/modules/CompleteModule.js
@@ -23,8 +23,8 @@ module.exports = buildModule("CompleteModule", (m) => {
   });
   const duplicateWithLib = m.contractAt(
     "ContractWithLibrary",
-    withLibArtifact,
     withLib,
+    withLibArtifact,
     { id: "ContractWithLibrary2" }
   );
 
diff --git a/packages/core/src/deploy.ts b/packages/core/src/deploy.ts
index 90860a90..d8aa3d73 100644
--- a/packages/core/src/deploy.ts
+++ b/packages/core/src/deploy.ts
@@ -117,7 +117,6 @@ export async function deploy<
 
   const deployer = new Deployer(
     resolvedConfig,
-    deploymentDir,
     executionStrategy,
     jsonRpcClient,
     artifactResolver,
diff --git a/packages/core/src/internal/deployer.ts b/packages/core/src/internal/deployer.ts
index 5c128ffa..f44f00c1 100644
--- a/packages/core/src/internal/deployer.ts
+++ b/packages/core/src/internal/deployer.ts
@@ -47,7 +47,6 @@ import { findStatus } from "./views/find-status";
 export class Deployer {
   constructor(
     private readonly _config: DeployConfig,
-    private readonly _deploymentDir: string | undefined,
     private readonly _executionStrategy: ExecutionStrategy,
     private readonly _jsonRpcClient: JsonRpcClient,
     private readonly _artifactResolver: ArtifactResolver,
@@ -75,8 +74,7 @@ export class Deployer {
     defaultSender: string
   ): Promise<DeploymentResult> {
     let deploymentState = await this._getOrInitializeDeploymentState(
-      ignitionModule.id,
-      this._deploymentDir
+      ignitionModule.id
     );
 
     const contracts =
@@ -219,14 +217,13 @@ export class Deployer {
   }
 
   private async _getOrInitializeDeploymentState(
-    moduleId: string,
-    deploymentDir: string | undefined
+    moduleId: string
   ): Promise<DeploymentState> {
     const chainId = await this._jsonRpcClient.getChainId();
     const deploymentState = await loadDeploymentState(this._deploymentLoader);
 
     if (deploymentState === undefined) {
-      this._emitDeploymentStartEvent(moduleId, deploymentDir);
+      this._emitDeploymentStartEvent(moduleId);
 
       return initializeDeploymentState(chainId, this._deploymentLoader);
     }
@@ -239,10 +236,7 @@ export class Deployer {
     return deploymentState;
   }
 
-  private _emitDeploymentStartEvent(
-    moduleId: string,
-    deploymentDir: string | undefined
-  ): void {
+  private _emitDeploymentStartEvent(moduleId: string): void {
     if (this._executionEventListener === undefined) {
       return;
     }
@@ -250,7 +244,6 @@ export class Deployer {
     this._executionEventListener.deploymentStart({
       type: ExecutionEventType.DEPLOYMENT_START,
       moduleName: moduleId,
-      deploymentDir: deploymentDir ?? undefined,
     });
   }
 
diff --git a/packages/core/src/internal/module-builder.ts b/packages/core/src/internal/module-builder.ts
index 01207508..c0150666 100644
--- a/packages/core/src/internal/module-builder.ts
+++ b/packages/core/src/internal/module-builder.ts
@@ -18,24 +18,24 @@ import {
   AccountRuntimeValue,
   AddressResolvableFuture,
   ArgumentType,
-  CallableContractFuture,
   ContractAtFuture,
-  ContractCallFuture,
   ContractDeploymentFuture,
+  LibraryDeploymentFuture,
+  CallableContractFuture,
   ContractFuture,
   FutureType,
   IgnitionModule,
   IgnitionModuleResult,
-  LibraryDeploymentFuture,
   ModuleParameterRuntimeValue,
   ModuleParameterType,
   ModuleParameters,
   NamedArtifactContractAtFuture,
+  ContractCallFuture,
   NamedArtifactContractDeploymentFuture,
   NamedArtifactLibraryDeploymentFuture,
+  StaticCallFuture,
   ReadEventArgumentFuture,
   SendDataFuture,
-  StaticCallFuture,
 } from "../types/module";
 import {
   CallOptions,
@@ -494,7 +494,8 @@ class IgnitionModuleBuilderImplementation<
     const futureId = toCallFutureId(
       this._module.id,
       options.id,
-      contractFuture.contractName,
+      contractFuture.module.id,
+      contractFuture.id,
       functionName
     );
 
@@ -562,7 +563,8 @@ class IgnitionModuleBuilderImplementation<
     const futureId = toCallFutureId(
       this._module.id,
       options.id,
-      contractFuture.contractName,
+      contractFuture.module.id,
+      contractFuture.id,
       functionName
     );
 
@@ -610,25 +612,20 @@ class IgnitionModuleBuilderImplementation<
   ): NamedArtifactContractAtFuture<ContractNameT>;
   public contractAt(
     contractName: string,
-    artifact: Artifact,
     address:
       | string
       | AddressResolvableFuture
       | ModuleParameterRuntimeValue<string>,
+    artifact: Artifact,
     options?: ContractAtOptions
   ): ContractAtFuture;
   public contractAt<ContractNameT extends string>(
     contractName: ContractNameT,
-    addressOrArtifact:
-      | string
-      | AddressResolvableFuture
-      | ModuleParameterRuntimeValue<string>
-      | Artifact,
-    optionsOrAddress?:
-      | ContractAtOptions
+    address:
       | string
       | AddressResolvableFuture
       | ModuleParameterRuntimeValue<string>,
+    artifactOrOptions?: Artifact | ContractAtOptions,
     options?: ContractAtOptions
   ) {
     if (typeof contractName !== "string") {
@@ -638,32 +635,19 @@ class IgnitionModuleBuilderImplementation<
       );
     }
 
-    if (isArtifactType(addressOrArtifact)) {
-      if (
-        !(
-          typeof optionsOrAddress === "string" ||
-          isFuture(optionsOrAddress) ||
-          isModuleParameterRuntimeValue(optionsOrAddress)
-        )
-      ) {
-        this._throwErrorWithStackTrace(
-          `Invalid parameter "address" provided to contractAt "${contractName}" in module "${this._module.id}"`,
-          this.contractAt
-        );
-      }
-
+    if (isArtifactType(artifactOrOptions)) {
       return this._contractAtFromArtifact(
         contractName,
-        addressOrArtifact,
-        optionsOrAddress,
+        address,
+        artifactOrOptions,
         options
       );
     }
 
     return this._namedArtifactContractAt(
       contractName,
-      addressOrArtifact,
-      optionsOrAddress as ContractAtOptions
+      address,
+      artifactOrOptions
     );
   }
 
@@ -710,11 +694,11 @@ class IgnitionModuleBuilderImplementation<
 
   private _contractAtFromArtifact(
     contractName: string,
-    artifact: Artifact,
     address:
       | string
       | AddressResolvableFuture
       | ModuleParameterRuntimeValue<string>,
+    artifact: Artifact,
     options: ContractAtOptions = {}
   ): ContractAtFuture {
     const futureId = toDeploymentFutureId(
diff --git a/packages/core/src/internal/utils/future-id-builders.ts b/packages/core/src/internal/utils/future-id-builders.ts
index 0768e1b3..be8ffe31 100644
--- a/packages/core/src/internal/utils/future-id-builders.ts
+++ b/packages/core/src/internal/utils/future-id-builders.ts
@@ -4,6 +4,12 @@
  */
 const MODULE_SEPERATOR = "#";
 
+/**
+ * The separator in ids that depend on futures that belong to a submodule.
+ * This separator is used to split the submodule and the rest of the dependency's id.
+ */
+const SUBMODULE_SEPARATOR = "~";
+
 /**
  * The seperator in ids that indicated different subparts of the future key.
  */
@@ -43,13 +49,25 @@ export function toDeploymentFutureId(
 export function toCallFutureId(
   moduleId: string,
   userProvidedId: string | undefined,
-  contractName: string,
+  contractModuleId: string,
+  contractId: string,
   functionName: string
 ) {
-  const futureKey =
-    userProvidedId ?? `${contractName}${SUBKEY_SEPERATOR}${functionName}`;
+  if (userProvidedId !== undefined) {
+    return `${moduleId}${MODULE_SEPERATOR}${userProvidedId}`;
+  }
 
-  return `${moduleId}${MODULE_SEPERATOR}${futureKey}`;
+  // If the contract belongs to the call's module, we just need to add the function name
+  if (moduleId === contractModuleId) {
+    return `${contractId}${SUBKEY_SEPERATOR}${functionName}`;
+  }
+
+  // We replace the MODULE_SEPARATOR for SUBMODULE_SEPARATOR
+  const submoduleContractId = `${contractModuleId}${SUBMODULE_SEPARATOR}${contractId.substring(
+    contractModuleId.length + MODULE_SEPERATOR.length
+  )}`;
+
+  return `${moduleId}${MODULE_SEPERATOR}${submoduleContractId}${SUBKEY_SEPERATOR}${functionName}`;
 }
 
 /**
diff --git a/packages/core/src/types/execution-events.ts b/packages/core/src/types/execution-events.ts
index ecc19467..91d478de 100644
--- a/packages/core/src/types/execution-events.ts
+++ b/packages/core/src/types/execution-events.ts
@@ -75,7 +75,6 @@ export enum ExecutionEventType {
 export interface DeploymentStartEvent {
   type: ExecutionEventType.DEPLOYMENT_START;
   moduleName: string;
-  deploymentDir: string | undefined;
 }
 
 /**
diff --git a/packages/core/src/types/module-builder.ts b/packages/core/src/types/module-builder.ts
index 5555459a..be415301 100644
--- a/packages/core/src/types/module-builder.ts
+++ b/packages/core/src/types/module-builder.ts
@@ -185,11 +185,11 @@ export interface IgnitionModuleBuilder {
 
   contractAt(
     contractName: string,
-    artifact: Artifact,
     address:
       | string
       | AddressResolvableFuture
       | ModuleParameterRuntimeValue<string>,
+    artifact: Artifact,
     options?: ContractAtOptions
   ): ContractAtFuture;
 
diff --git a/packages/hardhat-plugin/src/ui/helpers/calculate-deploying-module-panel.ts b/packages/hardhat-plugin/src/ui/helpers/calculate-deploying-module-panel.ts
index 5066120a..694e98f8 100644
--- a/packages/hardhat-plugin/src/ui/helpers/calculate-deploying-module-panel.ts
+++ b/packages/hardhat-plugin/src/ui/helpers/calculate-deploying-module-panel.ts
@@ -3,7 +3,8 @@ import chalk from "chalk";
 import { UiState } from "../types";
 
 export function calculateDeployingModulePanel(state: UiState): string {
-  return `Hardhat Ignition 🚀
+  return `
+Hardhat Ignition 🚀
 
 ${chalk.bold(`Deploying [ ${state.moduleName ?? "unknown"} ]`)}
 `;
diff --git a/packages/hardhat-plugin/src/ui/helpers/calculate-deployment-complete-display.ts b/packages/hardhat-plugin/src/ui/helpers/calculate-deployment-complete-display.ts
index 0e2cbd1b..31cc9905 100644
--- a/packages/hardhat-plugin/src/ui/helpers/calculate-deployment-complete-display.ts
+++ b/packages/hardhat-plugin/src/ui/helpers/calculate-deployment-complete-display.ts
@@ -38,7 +38,8 @@ function _displaySuccessfulDeployment(
   result: SuccessfulDeploymentResult,
   { moduleName }: { moduleName: string }
 ): string {
-  let text = `[ ${moduleName} ] successfully deployed 🚀
+  let text = `
+[ ${moduleName} ] successfully deployed 🚀
 
 ${chalk.bold("Deployed Addresses")}
 
@@ -61,7 +62,8 @@ function _displayValidationErrors(
   result: ValidationErrorDeploymentResult,
   { moduleName }: { moduleName: string }
 ): string {
-  let text = `[ ${moduleName} ] validation failed ⛔
+  let text = `
+[ ${moduleName} ] validation failed ⛔
 
 The module contains futures that would fail to execute:
 
@@ -86,7 +88,8 @@ function _displayReconciliationErrors(
   result: ReconciliationErrorDeploymentResult,
   { moduleName }: { moduleName: string }
 ): string {
-  let text = `[ ${moduleName} ] reconciliation failed ⛔
+  let text = `
+[ ${moduleName} ] reconciliation failed ⛔
 
 The module contains changes to executed futures:
 
@@ -111,7 +114,7 @@ function _displayPreviousRunErrors(
   result: PreviousRunErrorDeploymentResult,
   { moduleName }: { moduleName: string }
 ): string {
-  let text = `[ ${moduleName} ] deployment cancelled ⛔\n\n`;
+  let text = `\n[ ${moduleName} ] deployment cancelled ⛔\n\n`;
 
   text += `These futures failed or timed out on a previous run:\n`;
 
@@ -130,7 +133,7 @@ function _displayExecutionErrors(
 ) {
   const sections: string[] = [];
 
-  let text = `[ ${moduleName} ] failed ⛔\n\n`;
+  let text = `\n[ ${moduleName} ] failed ⛔\n\n`;
 
   if (result.timedOut.length > 0) {
     let timedOutSection = `Transactions remain unconfirmed after fee bump:\n`;
diff --git a/packages/hardhat-plugin/src/ui/helpers/calculate-deployment-status-display.ts b/packages/hardhat-plugin/src/ui/helpers/calculate-deployment-status-display.ts
index 637a8006..843f4e97 100644
--- a/packages/hardhat-plugin/src/ui/helpers/calculate-deployment-status-display.ts
+++ b/packages/hardhat-plugin/src/ui/helpers/calculate-deployment-status-display.ts
@@ -21,7 +21,7 @@ export function calculateDeploymentStatusDisplay(
 }
 
 function _calculateSuccess(deploymentId: string, statusResult: StatusResult) {
-  let successText = `[ ${deploymentId} ] successfully deployed 🚀\n\n`;
+  let successText = `\n[ ${deploymentId} ] successfully deployed 🚀\n\n`;
 
   if (Object.values(statusResult.contracts).length === 0) {
     successText += chalk.italic("No contracts were deployed");
@@ -40,7 +40,7 @@ function _calculateStartedButUnfinished(
   deploymentId: string,
   statusResult: StatusResult
 ) {
-  let startedText = `[ ${deploymentId} ] has futures that have started but not finished ⛔\n\n`;
+  let startedText = `\n[ ${deploymentId} ] has futures that have started but not finished ⛔\n\n`;
 
   startedText += Object.values(statusResult.started)
     .map((futureId) => ` - ${futureId}`)
@@ -50,7 +50,7 @@ function _calculateStartedButUnfinished(
 }
 
 function _calculateFailed(deploymentId: string, statusResult: StatusResult) {
-  let failedExecutionText = `[ ${deploymentId} ] failed ⛔\n`;
+  let failedExecutionText = `\n[ ${deploymentId} ] failed ⛔\n`;
 
   const sections: string[] = [];
 
diff --git a/packages/hardhat-plugin/src/ui/helpers/calculate-starting-message.ts b/packages/hardhat-plugin/src/ui/helpers/calculate-starting-message.ts
deleted file mode 100644
index a199fe6f..00000000
--- a/packages/hardhat-plugin/src/ui/helpers/calculate-starting-message.ts
+++ /dev/null
@@ -1,30 +0,0 @@
-import chalk from "chalk";
-
-/**
- * Display the temporary starting message. Note this does not print a newline.
- *
- * @param state - the UI state
- */
-export function calculateStartingMessage({
-  moduleName,
-  deploymentDir,
-}: {
-  moduleName: string | null;
-  deploymentDir: string | undefined | null;
-}): string {
-  const warningMessage = chalk.yellow(
-    chalk.bold(
-      `You are running Hardhat Ignition against an in-process instance of Hardhat Network.
-This will execute the deployment, but the results will be lost.
-You can use --network <network-name> to deploy to a different network.`
-    )
-  );
-
-  const startingMessage = `Hardhat Ignition starting for [ ${
-    moduleName ?? "unknown"
-  } ]...`;
-
-  return deploymentDir === undefined
-    ? `${warningMessage}\n\n${startingMessage}`
-    : startingMessage;
-}
diff --git a/packages/hardhat-plugin/src/ui/helpers/display-starting-message.ts b/packages/hardhat-plugin/src/ui/helpers/display-starting-message.ts
new file mode 100644
index 00000000..58e8b434
--- /dev/null
+++ b/packages/hardhat-plugin/src/ui/helpers/display-starting-message.ts
@@ -0,0 +1,12 @@
+import { UiState } from "../types";
+
+/**
+ * Display the temporary starting message. Note this does not print a newline.
+ *
+ * @param state - the UI state
+ */
+export function displayStartingMessage(state: UiState) {
+  process.stdout.write(
+    `Hardhat Ignition starting for [ ${state.moduleName ?? "unknown"} ]...`
+  );
+}
diff --git a/packages/hardhat-plugin/src/ui/pretty-event-handler.ts b/packages/hardhat-plugin/src/ui/pretty-event-handler.ts
index 72e9c5c3..c74fbbb7 100644
--- a/packages/hardhat-plugin/src/ui/pretty-event-handler.ts
+++ b/packages/hardhat-plugin/src/ui/pretty-event-handler.ts
@@ -36,7 +36,7 @@ import {
 import { calculateBatchDisplay } from "./helpers/calculate-batch-display";
 import { calculateDeployingModulePanel } from "./helpers/calculate-deploying-module-panel";
 import { calculateDeploymentCompleteDisplay } from "./helpers/calculate-deployment-complete-display";
-import { calculateStartingMessage } from "./helpers/calculate-starting-message";
+import { displayStartingMessage } from "./helpers/display-starting-message";
 import {
   UiBatches,
   UiFuture,
@@ -54,7 +54,6 @@ export class PrettyEventHandler implements ExecutionEventListener {
     status: UiStateDeploymentStatus.UNSTARTED,
     chainId: null,
     moduleName: null,
-    deploymentDir: null,
     batches: [],
     currentBatch: 0,
     result: null,
@@ -76,10 +75,9 @@ export class PrettyEventHandler implements ExecutionEventListener {
       ...this.state,
       status: UiStateDeploymentStatus.DEPLOYING,
       moduleName: event.moduleName,
-      deploymentDir: event.deploymentDir,
     };
 
-    process.stdout.write(calculateStartingMessage(this.state));
+    displayStartingMessage(this.state);
   }
 
   public runStart(event: RunStartEvent): void {
@@ -260,6 +258,7 @@ export class PrettyEventHandler implements ExecutionEventListener {
 
     if (originalStatus !== UiStateDeploymentStatus.UNSTARTED) {
       this._redisplayCurrentBatch();
+      this._clearUpToHeight(1);
     }
 
     console.log(calculateDeploymentCompleteDisplay(event, this.state));
diff --git a/packages/hardhat-plugin/src/ui/types.ts b/packages/hardhat-plugin/src/ui/types.ts
index 0c2e5066..d9e3d007 100644
--- a/packages/hardhat-plugin/src/ui/types.ts
+++ b/packages/hardhat-plugin/src/ui/types.ts
@@ -56,7 +56,6 @@ export interface UiState {
   status: UiStateDeploymentStatus;
   chainId: number | null;
   moduleName: string | null;
-  deploymentDir: string | undefined | null;
   batches: UiBatches;
   currentBatch: number;
   result: DeploymentResult | null;


Test patch:
diff --git a/packages/core/test/contractAtFromArtifact.ts b/packages/core/test/contractAtFromArtifact.ts
index 62ea7af6..20b22a6d 100644
--- a/packages/core/test/contractAtFromArtifact.ts
+++ b/packages/core/test/contractAtFromArtifact.ts
@@ -23,7 +23,7 @@ describe("contractAtFromArtifact", () => {
 
   it("should be able to setup a contract at a given address", () => {
     const moduleWithContractFromArtifact = buildModule("Module1", (m) => {
-      const contract1 = m.contractAt("Contract1", fakeArtifact, "0xtest");
+      const contract1 = m.contractAt("Contract1", "0xtest", fakeArtifact);
 
       return { contract1 };
     });
@@ -53,7 +53,7 @@ describe("contractAtFromArtifact", () => {
   it("should be able to pass an after dependency", () => {
     const moduleWithDependentContracts = buildModule("Module1", (m) => {
       const example = m.contract("Example");
-      const another = m.contractAt("Another", fakeArtifact, "0xtest", {
+      const another = m.contractAt("Another", "0xtest", fakeArtifact, {
         after: [example],
       });
 
@@ -74,7 +74,7 @@ describe("contractAtFromArtifact", () => {
       const example = m.contract("Example");
       const call = m.staticCall(example, "getAddress");
 
-      const another = m.contractAt("Another", fakeArtifact, call);
+      const another = m.contractAt("Another", call, fakeArtifact);
 
       return { example, another };
     });
@@ -96,11 +96,11 @@ describe("contractAtFromArtifact", () => {
       const paramWithDefault = m.getParameter("addressWithDefault", "0x000000");
       const paramWithoutDefault = m.getParameter("addressWithoutDefault");
 
-      const withDefault = m.contractAt("C", fakeArtifact, paramWithDefault);
+      const withDefault = m.contractAt("C", paramWithDefault, fakeArtifact);
       const withoutDefault = m.contractAt(
         "C2",
-        fakeArtifact,
-        paramWithoutDefault
+        paramWithoutDefault,
+        fakeArtifact
       );
 
       return { withDefault, withoutDefault };
@@ -129,14 +129,14 @@ describe("contractAtFromArtifact", () => {
       const moduleWithSameContractTwice = buildModule("Module1", (m) => {
         const sameContract1 = m.contractAt(
           "SameContract",
-          fakeArtifact,
           "0x123",
+          fakeArtifact,
           { id: "first" }
         );
         const sameContract2 = m.contractAt(
           "SameContract",
-          fakeArtifact,
           "0x123",
+          fakeArtifact,
           {
             id: "second",
           }
@@ -162,13 +162,13 @@ describe("contractAtFromArtifact", () => {
           buildModule("Module1", (m) => {
             const sameContract1 = m.contractAt(
               "SameContract",
-              fakeArtifact,
-              "0x123"
+              "0x123",
+              fakeArtifact
             );
             const sameContract2 = m.contractAt(
               "SameContract",
-              fakeArtifact,
-              "0x123"
+              "0x123",
+              fakeArtifact
             );
 
             return { sameContract1, sameContract2 };
@@ -183,16 +183,16 @@ describe("contractAtFromArtifact", () => {
           buildModule("Module1", (m) => {
             const sameContract1 = m.contractAt(
               "SameContract",
-              fakeArtifact,
               "0x123",
+              fakeArtifact,
               {
                 id: "same",
               }
             );
             const sameContract2 = m.contractAt(
               "SameContract",
-              fakeArtifact,
               "0x123",
+              fakeArtifact,
               {
                 id: "same",
               }
@@ -211,11 +211,11 @@ describe("contractAtFromArtifact", () => {
         assert.throws(
           () =>
             buildModule("Module1", (m) => {
-              const another = m.contractAt("Another", fakeArtifact, 42 as any);
+              const another = m.contractAt("Another", 42 as any, fakeArtifact);
 
               return { another };
             }),
-          /Invalid parameter "address" provided to contractAt "Another" in module "Module1"/
+          /Invalid address given/
         );
       });
     });
@@ -223,7 +223,7 @@ describe("contractAtFromArtifact", () => {
     it("should not validate a missing module parameter", async () => {
       const module = buildModule("Module1", (m) => {
         const p = m.getParameter("p");
-        const another = m.contractAt("Another", fakeArtifact, p);
+        const another = m.contractAt("Another", p, fakeArtifact);
 
         return { another };
       });
@@ -248,7 +248,7 @@ describe("contractAtFromArtifact", () => {
     it("should validate a missing module parameter if a default parameter is present", async () => {
       const module = buildModule("Module1", (m) => {
         const p = m.getParameter("p", "0x1234");
-        const another = m.contractAt("Another", fakeArtifact, p);
+        const another = m.contractAt("Another", p, fakeArtifact);
 
         return { another };
       });
@@ -272,7 +272,7 @@ describe("contractAtFromArtifact", () => {
     it("should not validate a module parameter of the wrong type", async () => {
       const module = buildModule("Module1", (m) => {
         const p = m.getParameter("p", 123 as unknown as string);
-        const another = m.contractAt("Another", fakeArtifact, p);
+        const another = m.contractAt("Another", p, fakeArtifact);
 
         return { another };
       });
diff --git a/packages/core/test/ignition-module-serializer.ts b/packages/core/test/ignition-module-serializer.ts
index 6a88e6da..85850bcf 100644
--- a/packages/core/test/ignition-module-serializer.ts
+++ b/packages/core/test/ignition-module-serializer.ts
@@ -165,7 +165,7 @@ describe("stored deployment serializer", () => {
 
     it("should serialize a contractAt", () => {
       const module = buildModule("Module1", (m) => {
-        const contract1 = m.contractAt("Contract1", fakeArtifact, "0x0");
+        const contract1 = m.contractAt("Contract1", "0x0", fakeArtifact);
 
         return { contract1 };
       });
@@ -175,9 +175,9 @@ describe("stored deployment serializer", () => {
 
     it("should serialize a contractAt with a future address", () => {
       const module = buildModule("Module1", (m) => {
-        const contract1 = m.contractAt("Contract1", fakeArtifact, "0x0");
+        const contract1 = m.contractAt("Contract1", "0x0", fakeArtifact);
         const call = m.staticCall(contract1, "getAddress");
-        const contract2 = m.contractAt("Contract2", fakeArtifact, call);
+        const contract2 = m.contractAt("Contract2", call, fakeArtifact);
 
         return { contract1, contract2 };
       });
@@ -187,8 +187,8 @@ describe("stored deployment serializer", () => {
 
     it("should serialize a contractAt with dependency", () => {
       const module = buildModule("Module1", (m) => {
-        const contract1 = m.contractAt("Contract1", fakeArtifact, "0x0");
-        const contract2 = m.contractAt("Contract2", fakeArtifact, "0x0", {
+        const contract1 = m.contractAt("Contract1", "0x0", fakeArtifact);
+        const contract2 = m.contractAt("Contract2", "0x0", fakeArtifact, {
           after: [contract1],
         });
 
diff --git a/packages/core/test/reconciliation/futures/reconcileArtifactContractAt.ts b/packages/core/test/reconciliation/futures/reconcileArtifactContractAt.ts
index 9f65af58..ca8e5bbe 100644
--- a/packages/core/test/reconciliation/futures/reconcileArtifactContractAt.ts
+++ b/packages/core/test/reconciliation/futures/reconcileArtifactContractAt.ts
@@ -69,7 +69,7 @@ describe("Reconciliation - artifact contract at", () => {
 
   it("should reconcile when using an address string", async () => {
     const submoduleDefinition = buildModule("Submodule", (m) => {
-      const contract1 = m.contractAt("Contract1", mockArtifact, exampleAddress);
+      const contract1 = m.contractAt("Contract1", exampleAddress, mockArtifact);
 
       return { contract1 };
     });
@@ -97,7 +97,7 @@ describe("Reconciliation - artifact contract at", () => {
       const example = m.contract("Example");
       const call = m.staticCall(example, "getAddress");
 
-      const another = m.contractAt("Another", mockArtifact, call);
+      const another = m.contractAt("Another", call, mockArtifact);
 
       return { another };
     });
@@ -143,8 +143,8 @@ describe("Reconciliation - artifact contract at", () => {
     const moduleDefinition = buildModule("Module", (m) => {
       const contract1 = m.contractAt(
         "ContractChanged",
-        mockArtifact,
         exampleAddress,
+        mockArtifact,
         {
           id: "Factory",
         }
@@ -179,8 +179,8 @@ describe("Reconciliation - artifact contract at", () => {
     const moduleDefinition = buildModule("Module", (m) => {
       const contract1 = m.contractAt(
         "Contract1",
-        mockArtifact,
         exampleAddress,
+        mockArtifact,
         {
           id: "Factory",
         }
diff --git a/packages/core/test/utils/future-id-builders.ts b/packages/core/test/utils/future-id-builders.ts
index 74dcfaa9..5673afa0 100644
--- a/packages/core/test/utils/future-id-builders.ts
+++ b/packages/core/test/utils/future-id-builders.ts
@@ -25,16 +25,41 @@ describe("future id rules", () => {
   });
 
   describe("call ids", () => {
-    it("the fallback id should be built based on the contractName and function name", () => {
+    it("the fallback id should be built based on the contract id and function name if they belong to the same module", () => {
       assert.equal(
-        toCallFutureId("MyModule", undefined, "MyContract", "MyFunction"),
+        toCallFutureId(
+          "MyModule",
+          undefined,
+          "MyModule",
+          "MyModule#MyContract",
+          "MyFunction"
+        ),
         "MyModule#MyContract.MyFunction"
       );
     });
 
+    it("should name a call to a future coming from a module representing the submodule relationship, and including namespaced by module id", () => {
+      assert.equal(
+        toCallFutureId(
+          "MyModule",
+          undefined,
+          "Submodule",
+          "Submodule#MyContract",
+          "MyFunction"
+        ),
+        "MyModule#Submodule~MyContract.MyFunction"
+      );
+    });
+
     it("namespaces the user provided id to the module", () => {
       assert.equal(
-        toCallFutureId("MyModule", "MyId", "MyContract", "MyFunction"),
+        toCallFutureId(
+          "MyModule",
+          "MyId",
+          "MyModule",
+          "MyModule#MyContract",
+          "MyFunction"
+        ),
         "MyModule#MyId"
       );
     });
diff --git a/packages/core/test/validations/id-rules.ts b/packages/core/test/validations/id-rules.ts
index 0ec38ffe..b2428735 100644
--- a/packages/core/test/validations/id-rules.ts
+++ b/packages/core/test/validations/id-rules.ts
@@ -122,8 +122,8 @@ describe("id rules", () => {
         buildModule("MyModule", (m) => {
           const myContractAt = m.contractAt(
             "MyContract",
-            fakeArtifact,
             exampleAddress,
+            fakeArtifact,
             {
               id: "MyContractAt:v2",
             }
@@ -218,8 +218,8 @@ describe("id rules", () => {
         buildModule("MyModule", (m) => {
           const myContractAt = m.contractAt(
             "MyContractAt:v2",
-            fakeArtifact,
-            exampleAddress
+            exampleAddress,
+            fakeArtifact
           );
 
           return { myContractAt };
diff --git a/packages/hardhat-plugin/test/events.ts b/packages/hardhat-plugin/test/events.ts
index e20f6132..c61ff3ef 100644
--- a/packages/hardhat-plugin/test/events.ts
+++ b/packages/hardhat-plugin/test/events.ts
@@ -48,7 +48,7 @@ describe("events", () => {
         "fooAddress"
       );
 
-      const foo = m.contractAt("Foo", artifact, newAddress);
+      const foo = m.contractAt("Foo", newAddress, artifact);
 
       return { fooFactory, foo };
     });
diff --git a/packages/hardhat-plugin/test/execution/deploy-contract-at-from-artifact.ts b/packages/hardhat-plugin/test/execution/deploy-contract-at-from-artifact.ts
index fb934be7..5e81e72c 100644
--- a/packages/hardhat-plugin/test/execution/deploy-contract-at-from-artifact.ts
+++ b/packages/hardhat-plugin/test/execution/deploy-contract-at-from-artifact.ts
@@ -38,7 +38,7 @@ describe.skip("execution - deploy contractAt from artifact", function () {
     const fooArtifact = await this.hre.artifacts.readArtifact("Foo");
 
     const contractAtModuleDefinition = buildModule("FooModule", (m) => {
-      const atFoo = m.contractAt("AtFoo", fooArtifact, fooAddress);
+      const atFoo = m.contractAt("AtFoo", fooAddress, fooArtifact);
 
       return { atFoo };
     });
diff --git a/packages/hardhat-plugin/test/existing-contract.ts b/packages/hardhat-plugin/test/existing-contract.ts
index 53e549cf..890762fe 100644
--- a/packages/hardhat-plugin/test/existing-contract.ts
+++ b/packages/hardhat-plugin/test/existing-contract.ts
@@ -31,11 +31,11 @@ describe("existing contract", () => {
       await firstResult.usesContract.getAddress();
 
     const secondModuleDefinition = buildModule("SecondModule", (m) => {
-      const bar = m.contractAt("Bar", barArtifact, barAddress);
+      const bar = m.contractAt("Bar", barAddress, barArtifact);
       const usesContract = m.contractAt(
         "UsesContract",
-        usesContractArtifact,
-        usesContractAddress
+        usesContractAddress,
+        usesContractArtifact
       );
 
       m.call(usesContract, "setAddress", [bar]);
diff --git a/packages/hardhat-plugin/test/static-calls.ts b/packages/hardhat-plugin/test/static-calls.ts
index 891522b6..8c34694a 100644
--- a/packages/hardhat-plugin/test/static-calls.ts
+++ b/packages/hardhat-plugin/test/static-calls.ts
@@ -44,7 +44,7 @@ describe("static calls", () => {
         after: [createCall],
       });
 
-      const foo = m.contractAt("Foo", artifact, newAddress);
+      const foo = m.contractAt("Foo", newAddress, artifact);
 
       return { fooFactory, foo };
     });
@@ -167,7 +167,7 @@ describe("static calls", () => {
         after: [createCall],
       });
 
-      const foo = m.contractAt("Foo", artifact, nonAddress);
+      const foo = m.contractAt("Foo", nonAddress, artifact);
 
       return { fooFactory, foo };
     });
diff --git a/packages/hardhat-plugin/test/ui/helpers/calculate-batch-display.ts b/packages/hardhat-plugin/test/ui/helpers/calculate-batch-display.ts
index 289bc40d..55f8f1e7 100644
--- a/packages/hardhat-plugin/test/ui/helpers/calculate-batch-display.ts
+++ b/packages/hardhat-plugin/test/ui/helpers/calculate-batch-display.ts
@@ -12,7 +12,6 @@ const exampleState: UiState = {
   status: UiStateDeploymentStatus.DEPLOYING,
   chainId: 31337,
   moduleName: "ExampleModule",
-  deploymentDir: "/users/example",
   batches: [],
   currentBatch: 1,
   result: null,
diff --git a/packages/hardhat-plugin/test/ui/helpers/calculate-deployment-complete-display.ts b/packages/hardhat-plugin/test/ui/helpers/calculate-deployment-complete-display.ts
index b87cd6ea..bff11fad 100644
--- a/packages/hardhat-plugin/test/ui/helpers/calculate-deployment-complete-display.ts
+++ b/packages/hardhat-plugin/test/ui/helpers/calculate-deployment-complete-display.ts
@@ -19,6 +19,7 @@ describe("ui - calculate deployment complete display", () => {
   describe("successful deployment", () => {
     it("should render a sucessful deployment", () => {
       const expectedText = testFormat(`
+
         [ MyModule ] successfully deployed 🚀
 
         ${chalk.bold("Deployed Addresses")}
@@ -54,6 +55,7 @@ describe("ui - calculate deployment complete display", () => {
 
     it("should render a sucessful deployment with no contracts", () => {
       const expectedText = testFormat(`
+
         [ MyModule ] successfully deployed 🚀
 
         ${chalk.bold("Deployed Addresses")}
@@ -79,6 +81,7 @@ describe("ui - calculate deployment complete display", () => {
   describe("validation failures", () => {
     it("should render multiple validation errors on multiple futures", () => {
       const expectedText = testFormat(`
+
         [ MyModule ] validation failed ⛔
 
         The module contains futures that would fail to execute:
@@ -119,6 +122,7 @@ describe("ui - calculate deployment complete display", () => {
   describe("reconciliation errors", () => {
     it("should render a multiple reconciliation errors on multiple futures", () => {
       const expectedText = testFormat(`
+
         [ MyModule ] reconciliation failed ⛔
 
         The module contains changes to executed futures:
@@ -159,6 +163,7 @@ describe("ui - calculate deployment complete display", () => {
   describe("previous run errors", () => {
     it("should render a multiple previous run errors on multiple futures", () => {
       const expectedText = testFormat(`
+
         [ MyModule ] deployment cancelled ⛔
 
         These futures failed or timed out on a previous run:
@@ -191,6 +196,7 @@ describe("ui - calculate deployment complete display", () => {
   describe("execution errors", () => {
     it("should render an execution failure with multiple of each problem type", () => {
       const expectedText = testFormat(`
+
         [ MyModule ] failed ⛔
 
         Transactions remain unconfirmed after fee bump:
diff --git a/packages/hardhat-plugin/test/ui/helpers/calculate-deployment-status-display.ts b/packages/hardhat-plugin/test/ui/helpers/calculate-deployment-status-display.ts
index 6fbcf177..c6d750e1 100644
--- a/packages/hardhat-plugin/test/ui/helpers/calculate-deployment-status-display.ts
+++ b/packages/hardhat-plugin/test/ui/helpers/calculate-deployment-status-display.ts
@@ -20,6 +20,7 @@ describe("ui - calculate deployment status display", () => {
   describe("successful deployment", () => {
     it("should render a sucessful deployment", () => {
       const expectedText = testFormat(`
+
         [ deployment-01 ] successfully deployed 🚀
 
         ${chalk.bold("Deployed Addresses")}
@@ -54,6 +55,7 @@ describe("ui - calculate deployment status display", () => {
 
     it("should render a sucessful deployment with no deploys", () => {
       const expectedText = testFormat(`
+
         [ deployment-01 ] successfully deployed 🚀
 
         ${chalk.italic("No contracts were deployed")}`);
@@ -76,6 +78,7 @@ describe("ui - calculate deployment status display", () => {
   describe("failed deployment", () => {
     it("should render an execution failure with multiple of each problem type", () => {
       const expectedText = testFormat(`
+
         [ deployment-01 ] failed ⛔
 
         Transactions remain unconfirmed after fee bump:
@@ -151,6 +154,7 @@ describe("ui - calculate deployment status display", () => {
   describe("deployment with started but unfinished futures (e.g. simulation errors)", () => {
     it("should render a sucessful deployment", () => {
       const expectedText = testFormat(`
+
         [ deployment-01 ] has futures that have started but not finished ⛔
 
          - MyModule#Token
diff --git a/packages/hardhat-plugin/test/ui/helpers/calculate-starting-message.ts b/packages/hardhat-plugin/test/ui/helpers/calculate-starting-message.ts
deleted file mode 100644
index 1eb12ba1..00000000
--- a/packages/hardhat-plugin/test/ui/helpers/calculate-starting-message.ts
+++ /dev/null
@@ -1,34 +0,0 @@
-import { assert } from "chai";
-import chalk from "chalk";
-
-import { calculateStartingMessage } from "../../../src/ui/helpers/calculate-starting-message";
-
-describe("ui - calculate starting message display", () => {
-  it("should display the starting message", () => {
-    const expectedText = `Hardhat Ignition starting for [ MyModule ]...`;
-
-    const actualText = calculateStartingMessage({
-      moduleName: "MyModule",
-      deploymentDir: "/users/example",
-    });
-
-    assert.equal(actualText, expectedText);
-  });
-
-  it("should display the warning for an ephemeral network", () => {
-    const warningMessage = `You are running Hardhat Ignition against an in-process instance of Hardhat Network.
-This will execute the deployment, but the results will be lost.
-You can use --network <network-name> to deploy to a different network.`;
-
-    const expectedText = `${chalk.yellow(
-      chalk.bold(warningMessage)
-    )}\n\nHardhat Ignition starting for [ MyModule ]...`;
-
-    const actualText = calculateStartingMessage({
-      moduleName: "MyModule",
-      deploymentDir: undefined,
-    });
-
-    assert.equal(actualText, expectedText);
-  });
-});
diff --git a/packages/ui/test/to-mermaid.ts b/packages/ui/test/to-mermaid.ts
index d22a828e..62c0fc2e 100644
--- a/packages/ui/test/to-mermaid.ts
+++ b/packages/ui/test/to-mermaid.ts
@@ -205,8 +205,8 @@ describe("to-mermaid", () => {
       });
       const duplicateWithLib = m.contractAt(
         "ContractWithLibrary",
-        withLibArtifact,
         withLib,
+        withLibArtifact,
         { id: "ContractWithLibrary2" }
       );