Repository: NomicFoundation/hardhat-ignition (ts)

Issue:
Expand value and from to support staticCall/readEventArg
We should expand the options of the `value` property on the actions of the api to include `staticCall` and `readEventArg`.

Pull request:
Support using the result from `m.staticCall` or `m.readEventArgument` as value option
fixes #455 

Patch:
diff --git a/packages/core/src/ignition-module-serializer.ts b/packages/core/src/ignition-module-serializer.ts
index dfe5b60e..d0de4ed4 100644
--- a/packages/core/src/ignition-module-serializer.ts
+++ b/packages/core/src/ignition-module-serializer.ts
@@ -29,6 +29,7 @@ import {
   AccountRuntimeValue,
   AddressResolvableFuture,
   ArgumentType,
+  ContractCallFuture,
   ContractDeploymentFuture,
   ContractFuture,
   Future,
@@ -37,9 +38,10 @@ import {
   IgnitionModuleResult,
   ModuleParameterRuntimeValue,
   ModuleParameterType,
-  ContractCallFuture,
   NamedArtifactContractDeploymentFuture,
+  ReadEventArgumentFuture,
   RuntimeValueType,
+  StaticCallFuture,
 } from "./types/module";
 import {
   FutureToken,
@@ -137,7 +139,9 @@ export class IgnitionModuleSerializer {
               ? this._serializeAccountRuntimeValue(future.from)
               : future.from,
             libraries: this._convertLibrariesToLibraryTokens(future.libraries),
-            value: isRuntimeValue(future.value)
+            value: isFuture(future.value)
+              ? this._convertFutureToFutureToken(future.value)
+              : isRuntimeValue(future.value)
               ? this._serializeModuleParamterRuntimeValue(future.value)
               : this._serializeBigint(future.value),
           };
@@ -161,7 +165,9 @@ export class IgnitionModuleSerializer {
               ? this._serializeAccountRuntimeValue(future.from)
               : future.from,
             libraries: this._convertLibrariesToLibraryTokens(future.libraries),
-            value: isRuntimeValue(future.value)
+            value: isFuture(future.value)
+              ? this._convertFutureToFutureToken(future.value)
+              : isRuntimeValue(future.value)
               ? this._serializeModuleParamterRuntimeValue(future.value)
               : this._serializeBigint(future.value),
           };
@@ -214,7 +220,9 @@ export class IgnitionModuleSerializer {
             contract: this._convertFutureToFutureToken(future.contract),
             functionName: future.functionName,
             args: future.args.map((arg) => context.argReplacer(arg)),
-            value: isRuntimeValue(future.value)
+            value: isFuture(future.value)
+              ? this._convertFutureToFutureToken(future.value)
+              : isRuntimeValue(future.value)
               ? this._serializeModuleParamterRuntimeValue(future.value)
               : this._serializeBigint(future.value),
             from: isRuntimeValue(future.from)
@@ -640,7 +648,13 @@ export class IgnitionModuleDeserializer {
               this._lookup(contractFuturesLookup, lib.futureId),
             ])
           ),
-          this._isSerializedModuleParameterRuntimeValue(serializedFuture.value)
+          this._isSerializedFutureToken(serializedFuture.value)
+            ? (this._lookup(futuresLookup, serializedFuture.value.futureId) as
+                | StaticCallFuture<string, string>
+                | ReadEventArgumentFuture)
+            : this._isSerializedModuleParameterRuntimeValue(
+                serializedFuture.value
+              )
             ? (this._deserializeModuleParameterRuntimeValue(
                 serializedFuture.value
               ) as ModuleParameterRuntimeValue<bigint>) // This is unsafe, but we only serialize valid values
@@ -664,7 +678,13 @@ export class IgnitionModuleDeserializer {
               this._lookup(contractFuturesLookup, lib.futureId),
             ])
           ),
-          this._isSerializedModuleParameterRuntimeValue(serializedFuture.value)
+          this._isSerializedFutureToken(serializedFuture.value)
+            ? (this._lookup(futuresLookup, serializedFuture.value.futureId) as
+                | StaticCallFuture<string, string>
+                | ReadEventArgumentFuture)
+            : this._isSerializedModuleParameterRuntimeValue(
+                serializedFuture.value
+              )
             ? (this._deserializeModuleParameterRuntimeValue(
                 serializedFuture.value
               ) as ModuleParameterRuntimeValue<bigint>) // This is unsafe, but we only serialize valid values
@@ -716,7 +736,13 @@ export class IgnitionModuleDeserializer {
           serializedFuture.args.map((arg) =>
             this._deserializeArgument(arg, futuresLookup)
           ),
-          this._isSerializedModuleParameterRuntimeValue(serializedFuture.value)
+          this._isSerializedFutureToken(serializedFuture.value)
+            ? (this._lookup(futuresLookup, serializedFuture.value.futureId) as
+                | StaticCallFuture<string, string>
+                | ReadEventArgumentFuture)
+            : this._isSerializedModuleParameterRuntimeValue(
+                serializedFuture.value
+              )
             ? (this._deserializeModuleParameterRuntimeValue(
                 serializedFuture.value
               ) as ModuleParameterRuntimeValue<bigint>) // This is unsafe, but we only serialize valid values
diff --git a/packages/core/src/internal/execution/future-processor/helpers/build-initialize-message-for.ts b/packages/core/src/internal/execution/future-processor/helpers/build-initialize-message-for.ts
index 409a4b49..74c6f0de 100644
--- a/packages/core/src/internal/execution/future-processor/helpers/build-initialize-message-for.ts
+++ b/packages/core/src/internal/execution/future-processor/helpers/build-initialize-message-for.ts
@@ -51,7 +51,11 @@ export async function buildInitializeMessageFor(
               accounts
             ),
             libraries: resolveLibraries(future.libraries, deploymentState),
-            value: resolveValue(future.value, deploymentParameters),
+            value: resolveValue(
+              future.value,
+              deploymentParameters,
+              deploymentState
+            ),
             from: resolveFutureFrom(future.from, accounts, defaultSender),
           }
         );
@@ -95,7 +99,11 @@ export async function buildInitializeMessageFor(
               deploymentState
             ),
             artifactId: future.contract.id,
-            value: resolveValue(future.value, deploymentParameters),
+            value: resolveValue(
+              future.value,
+              deploymentParameters,
+              deploymentState
+            ),
             from: resolveFutureFrom(future.from, accounts, defaultSender),
           }
         );
@@ -191,7 +199,11 @@ export async function buildInitializeMessageFor(
               deploymentState,
               deploymentParameters
             ),
-            value: resolveValue(future.value, deploymentParameters),
+            value: resolveValue(
+              future.value,
+              deploymentParameters,
+              deploymentState
+            ),
             data: future.data ?? "0x",
             from: resolveFutureFrom(future.from, accounts, defaultSender),
           }
diff --git a/packages/core/src/internal/execution/future-processor/helpers/future-resolvers.ts b/packages/core/src/internal/execution/future-processor/helpers/future-resolvers.ts
index e661cea6..b63ae092 100644
--- a/packages/core/src/internal/execution/future-processor/helpers/future-resolvers.ts
+++ b/packages/core/src/internal/execution/future-processor/helpers/future-resolvers.ts
@@ -1,6 +1,9 @@
 import { isAddress } from "ethers";
 
-import { isModuleParameterRuntimeValue } from "../../../../type-guards";
+import {
+  isFuture,
+  isModuleParameterRuntimeValue,
+} from "../../../../type-guards";
 import { DeploymentParameters } from "../../../../types/deploy";
 import {
   AccountRuntimeValue,
@@ -9,7 +12,9 @@ import {
   ContractFuture,
   Future,
   ModuleParameterRuntimeValue,
+  ReadEventArgumentFuture,
   SolidityParameterType,
+  StaticCallFuture,
 } from "../../../../types/module";
 import { DeploymentLoader } from "../../../deployment-loader/types";
 import { assertIgnitionInvariant } from "../../../utils/assertions";
@@ -30,23 +35,33 @@ import { convertEvmValueToSolidityParam } from "../../utils/convert-evm-tuple-to
  * @returns the resolved bigint
  */
 export function resolveValue(
-  givenValue: bigint | ModuleParameterRuntimeValue<bigint>,
-  deploymentParameters: DeploymentParameters
+  givenValue:
+    | bigint
+    | ModuleParameterRuntimeValue<bigint>
+    | StaticCallFuture<string, string>
+    | ReadEventArgumentFuture,
+  deploymentParameters: DeploymentParameters,
+  deploymentState: DeploymentState
 ): bigint {
   if (typeof givenValue === "bigint") {
     return givenValue;
   }
 
-  const moduleParam = resolveModuleParameter(givenValue, {
-    deploymentParameters,
-  });
+  let result: SolidityParameterType;
+  if (isFuture(givenValue)) {
+    result = findResultForFutureById(deploymentState, givenValue.id);
+  } else {
+    result = resolveModuleParameter(givenValue, {
+      deploymentParameters,
+    });
+  }
 
   assertIgnitionInvariant(
-    typeof moduleParam === "bigint",
-    "Module parameter used as value must be a bigint"
+    typeof result === "bigint",
+    "Module parameter or future result used as value must be a bigint"
   );
 
-  return moduleParam;
+  return result;
 }
 
 /**
diff --git a/packages/core/src/internal/module-builder.ts b/packages/core/src/internal/module-builder.ts
index d93bf431..584911e4 100644
--- a/packages/core/src/internal/module-builder.ts
+++ b/packages/core/src/internal/module-builder.ts
@@ -10,6 +10,8 @@ import {
   isContractFuture,
   isFuture,
   isModuleParameterRuntimeValue,
+  isNamedStaticCallFuture,
+  isReadEventArgumentFuture,
 } from "../type-guards";
 import { Artifact } from "../types/artifact";
 import {
@@ -258,6 +260,10 @@ class IgnitionModuleBuilderImplementation<
       options.from
     );
 
+    if (isFuture(options.value)) {
+      future.dependencies.add(options.value);
+    }
+
     for (const arg of resolveArgsToFutures(args)) {
       future.dependencies.add(arg);
     }
@@ -310,7 +316,9 @@ class IgnitionModuleBuilderImplementation<
       options.from
     );
 
-    this._module.futures.add(future);
+    if (isFuture(options.value)) {
+      future.dependencies.add(options.value);
+    }
 
     for (const arg of resolveArgsToFutures(args)) {
       future.dependencies.add(arg);
@@ -470,6 +478,10 @@ class IgnitionModuleBuilderImplementation<
 
     future.dependencies.add(contractFuture);
 
+    if (isFuture(options.value)) {
+      future.dependencies.add(options.value);
+    }
+
     for (const arg of resolveArgsToFutures(args)) {
       future.dependencies.add(arg);
     }
@@ -966,10 +978,20 @@ class IgnitionModuleBuilderImplementation<
   }
 
   private _assertValidValue(
-    value: bigint | ModuleParameterRuntimeValue<bigint> | any,
+    value:
+      | bigint
+      | ModuleParameterRuntimeValue<bigint>
+      | StaticCallFuture<string, string>
+      | ReadEventArgumentFuture
+      | any,
     func: (...[]: any[]) => any
   ) {
-    if (!isModuleParameterRuntimeValue(value) && typeof value !== "bigint") {
+    if (
+      !isReadEventArgumentFuture(value) &&
+      !isNamedStaticCallFuture(value) &&
+      !isModuleParameterRuntimeValue(value) &&
+      typeof value !== "bigint"
+    ) {
       this._throwErrorWithStackTrace(
         `Given value option '${value}' is not a \`bigint\``,
         func
diff --git a/packages/core/src/internal/module.ts b/packages/core/src/internal/module.ts
index 966a6e24..6931cbd1 100644
--- a/packages/core/src/internal/module.ts
+++ b/packages/core/src/internal/module.ts
@@ -62,7 +62,11 @@ export class NamedContractDeploymentFutureImplementation<
     public readonly contractName: ContractNameT,
     public readonly constructorArgs: ArgumentType[],
     public readonly libraries: Record<string, ContractFuture<string>>,
-    public readonly value: bigint | ModuleParameterRuntimeValue<bigint>,
+    public readonly value:
+      | bigint
+      | ModuleParameterRuntimeValue<bigint>
+      | StaticCallFuture<string, string>
+      | ReadEventArgumentFuture,
     public readonly from: string | AccountRuntimeValue | undefined
   ) {
     super(id, FutureType.NAMED_ARTIFACT_CONTRACT_DEPLOYMENT, module);
@@ -82,7 +86,11 @@ export class ArtifactContractDeploymentFutureImplementation<
     public readonly constructorArgs: ArgumentType[],
     public readonly artifact: Artifact,
     public readonly libraries: Record<string, ContractFuture<string>>,
-    public readonly value: bigint | ModuleParameterRuntimeValue<bigint>,
+    public readonly value:
+      | bigint
+      | ModuleParameterRuntimeValue<bigint>
+      | StaticCallFuture<string, string>
+      | ReadEventArgumentFuture,
     public readonly from: string | AccountRuntimeValue | undefined
   ) {
     super(id, FutureType.CONTRACT_DEPLOYMENT, module);
@@ -137,7 +145,11 @@ export class NamedContractCallFutureImplementation<
     public readonly functionName: FunctionNameT,
     public readonly contract: ContractFuture<ContractNameT>,
     public readonly args: ArgumentType[],
-    public readonly value: bigint | ModuleParameterRuntimeValue<bigint>,
+    public readonly value:
+      | bigint
+      | ModuleParameterRuntimeValue<bigint>
+      | StaticCallFuture<string, string>
+      | ReadEventArgumentFuture,
     public readonly from: string | AccountRuntimeValue | undefined
   ) {
     super(id, FutureType.CONTRACT_CALL, module);
diff --git a/packages/core/src/internal/reconciliation/helpers/reconcile-value.ts b/packages/core/src/internal/reconciliation/helpers/reconcile-value.ts
index 67d5e58e..f5a46b9c 100644
--- a/packages/core/src/internal/reconciliation/helpers/reconcile-value.ts
+++ b/packages/core/src/internal/reconciliation/helpers/reconcile-value.ts
@@ -31,7 +31,8 @@ export function reconcileValue(
 ): ReconciliationFutureResultFailure | undefined {
   const resolvedValue = resolveValue(
     future.value,
-    context.deploymentParameters
+    context.deploymentParameters,
+    context.deploymentState
   );
 
   return compare(future, "Value", exState.value, resolvedValue);
diff --git a/packages/core/src/types/module-builder.ts b/packages/core/src/types/module-builder.ts
index b24d5fea..be415301 100644
--- a/packages/core/src/types/module-builder.ts
+++ b/packages/core/src/types/module-builder.ts
@@ -3,27 +3,27 @@ import {
   AccountRuntimeValue,
   AddressResolvableFuture,
   ArgumentType,
+  CallableContractFuture,
   ContractAtFuture,
+  ContractCallFuture,
   ContractDeploymentFuture,
-  LibraryDeploymentFuture,
-  CallableContractFuture,
   ContractFuture,
   Future,
   IgnitionModule,
   IgnitionModuleResult,
+  LibraryDeploymentFuture,
   ModuleParameterRuntimeValue,
   ModuleParameterType,
   NamedArtifactContractAtFuture,
-  ContractCallFuture,
   NamedArtifactContractDeploymentFuture,
   NamedArtifactLibraryDeploymentFuture,
-  StaticCallFuture,
   ReadEventArgumentFuture,
   SendDataFuture,
+  StaticCallFuture,
 } from "./module";
 
 /**
- * The options for a `contract` call.
+ * The options for a `contract` deployment.
  *
  * @beta
  */
@@ -31,7 +31,11 @@ export interface ContractOptions {
   id?: string;
   after?: Future[];
   libraries?: Record<string, ContractFuture<string>>;
-  value?: bigint | ModuleParameterRuntimeValue<bigint>;
+  value?:
+    | bigint
+    | ModuleParameterRuntimeValue<bigint>
+    | StaticCallFuture<string, string>
+    | ReadEventArgumentFuture;
   from?: string | AccountRuntimeValue;
 }
 
@@ -55,7 +59,11 @@ export interface LibraryOptions {
 export interface CallOptions {
   id?: string;
   after?: Future[];
-  value?: bigint | ModuleParameterRuntimeValue<bigint>;
+  value?:
+    | bigint
+    | ModuleParameterRuntimeValue<bigint>
+    | StaticCallFuture<string, string>
+    | ReadEventArgumentFuture;
   from?: string | AccountRuntimeValue;
 }
 
diff --git a/packages/core/src/types/module.ts b/packages/core/src/types/module.ts
index 70b45a49..9f0a7385 100644
--- a/packages/core/src/types/module.ts
+++ b/packages/core/src/types/module.ts
@@ -135,7 +135,11 @@ export interface NamedArtifactContractDeploymentFuture<
   contractName: ContractNameT;
   constructorArgs: ArgumentType[];
   libraries: Record<string, ContractFuture<string>>;
-  value: bigint | ModuleParameterRuntimeValue<bigint>;
+  value:
+    | bigint
+    | ModuleParameterRuntimeValue<bigint>
+    | StaticCallFuture<string, string>
+    | ReadEventArgumentFuture;
   from: string | AccountRuntimeValue | undefined;
 }
 
@@ -154,7 +158,11 @@ export interface ContractDeploymentFuture {
   artifact: Artifact;
   constructorArgs: ArgumentType[];
   libraries: Record<string, ContractFuture<string>>;
-  value: bigint | ModuleParameterRuntimeValue<bigint>;
+  value:
+    | bigint
+    | ModuleParameterRuntimeValue<bigint>
+    | StaticCallFuture<string, string>
+    | ReadEventArgumentFuture;
   from: string | AccountRuntimeValue | undefined;
 }
 
@@ -208,7 +216,11 @@ export interface ContractCallFuture<
   contract: ContractFuture<ContractNameT>;
   functionName: FunctionNameT;
   args: ArgumentType[];
-  value: bigint | ModuleParameterRuntimeValue<bigint>;
+  value:
+    | bigint
+    | ModuleParameterRuntimeValue<bigint>
+    | StaticCallFuture<string, string>
+    | ReadEventArgumentFuture;
   from: string | AccountRuntimeValue | undefined;
 }
 
diff --git a/packages/core/src/types/serialization.ts b/packages/core/src/types/serialization.ts
index 26fd30bb..237f22b3 100644
--- a/packages/core/src/types/serialization.ts
+++ b/packages/core/src/types/serialization.ts
@@ -79,7 +79,7 @@ export interface SerializedNamedContractDeploymentFuture
   contractName: string;
   constructorArgs: SerializedArgumentType[];
   libraries: SerializedLibraries;
-  value: SerializedBigInt | SerializedModuleParameterRuntimeValue;
+  value: SerializedBigInt | SerializedModuleParameterRuntimeValue | FutureToken;
   from: string | SerializedAccountRuntimeValue | undefined;
 }
 
@@ -95,7 +95,7 @@ export interface SerializedArtifactContractDeploymentFuture
   constructorArgs: SerializedArgumentType[];
   artifact: Artifact;
   libraries: SerializedLibraries;
-  value: SerializedBigInt | SerializedModuleParameterRuntimeValue;
+  value: SerializedBigInt | SerializedModuleParameterRuntimeValue | FutureToken;
   from: string | SerializedAccountRuntimeValue | undefined;
 }
 
@@ -137,7 +137,7 @@ export interface SerializedNamedContractCallFuture
   functionName: string;
   contract: FutureToken;
   args: SerializedArgumentType[];
-  value: SerializedBigInt | SerializedModuleParameterRuntimeValue;
+  value: SerializedBigInt | SerializedModuleParameterRuntimeValue | FutureToken;
   from: string | SerializedAccountRuntimeValue | undefined;
 }
 


Test patch:
diff --git a/packages/core/test/contract.ts b/packages/core/test/contract.ts
index dfcc44db..840e99ff 100644
--- a/packages/core/test/contract.ts
+++ b/packages/core/test/contract.ts
@@ -7,6 +7,8 @@ import {
   AccountRuntimeValueImplementation,
   ModuleParameterRuntimeValueImplementation,
   NamedContractDeploymentFutureImplementation,
+  NamedStaticCallFutureImplementation,
+  ReadEventArgumentFutureImplementation,
 } from "../src/internal/module";
 import { getFuturesFromModule } from "../src/internal/utils/get-futures-from-module";
 import { FutureType } from "../src/types/module";
@@ -177,6 +179,63 @@ describe("contract", () => {
     );
   });
 
+  it("Should be able to pass a StaticCallFuture as a value option", () => {
+    const moduleWithDependentContracts = buildModule("Module1", (m) => {
+      const contract = m.contract("Contract");
+      const staticCall = m.staticCall(contract, "test");
+
+      const another = m.contract("Another", [], {
+        value: staticCall,
+      });
+
+      return { another };
+    });
+
+    assert.isDefined(moduleWithDependentContracts);
+
+    const anotherFuture = [...moduleWithDependentContracts.futures].find(
+      ({ id }) => id === "Module1#Another"
+    );
+
+    if (
+      !(anotherFuture instanceof NamedContractDeploymentFutureImplementation)
+    ) {
+      assert.fail("Not a named contract deployment");
+    }
+
+    assertInstanceOf(anotherFuture.value, NamedStaticCallFutureImplementation);
+  });
+
+  it("Should be able to pass a ReadEventArgumentFuture as a value option", () => {
+    const moduleWithDependentContracts = buildModule("Module1", (m) => {
+      const contract = m.contract("Contract");
+      const eventArg = m.readEventArgument(contract, "TestEvent", "eventArg");
+
+      const another = m.contract("Another", [], {
+        value: eventArg,
+      });
+
+      return { another };
+    });
+
+    assert.isDefined(moduleWithDependentContracts);
+
+    const anotherFuture = [...moduleWithDependentContracts.futures].find(
+      ({ id }) => id === "Module1#Another"
+    );
+
+    if (
+      !(anotherFuture instanceof NamedContractDeploymentFutureImplementation)
+    ) {
+      assert.fail("Not a named contract deployment");
+    }
+
+    assertInstanceOf(
+      anotherFuture.value,
+      ReadEventArgumentFutureImplementation
+    );
+  });
+
   it("should be able to pass a string as from option", () => {
     const moduleWithDependentContracts = buildModule("Module1", (m) => {
       const another = m.contract("Another", [], { from: "0x2" });
diff --git a/packages/core/test/stored-deployment-serializer.ts b/packages/core/test/ignition-module-serializer.ts
similarity index 91%
rename from packages/core/test/stored-deployment-serializer.ts
rename to packages/core/test/ignition-module-serializer.ts
index afb56e39..85850bcf 100644
--- a/packages/core/test/stored-deployment-serializer.ts
+++ b/packages/core/test/ignition-module-serializer.ts
@@ -53,6 +53,34 @@ describe("stored deployment serializer", () => {
 
       assertSerializableModuleIn(module);
     });
+
+    it("should serialize a contract deployment with a call future as value", () => {
+      const module = buildModule("Module1", (m) => {
+        const contract1 = m.contract("Contract1", []);
+
+        const call1 = m.staticCall(contract1, "getValue");
+
+        const contract2 = m.contract("Contract2", [], { value: call1 });
+
+        return { contract1, contract2 };
+      });
+
+      assertSerializableModuleIn(module);
+    });
+
+    it("should serialize a contract deployment with a read event argument as value", () => {
+      const module = buildModule("Module1", (m) => {
+        const contract1 = m.contract("Contract1", []);
+
+        const event1 = m.readEventArgument(contract1, "Event1", "Value1");
+
+        const contract2 = m.contract("Contract2", [], { value: event1 });
+
+        return { contract1, contract2 };
+      });
+
+      assertSerializableModuleIn(module);
+    });
   });
 
   describe("contractFromArtifact", () => {
@@ -299,6 +327,34 @@ describe("stored deployment serializer", () => {
 
       assertSerializableModuleIn(module);
     });
+
+    it("should serialize a call with a call future as value", () => {
+      const module = buildModule("Module1", (m) => {
+        const contract1 = m.contract("Contract1", []);
+
+        const staticCall1 = m.staticCall(contract1, "getValue");
+
+        m.call(contract1, "lock", [], { value: staticCall1 });
+
+        return { contract1 };
+      });
+
+      assertSerializableModuleIn(module);
+    });
+
+    it("should serialize a call with a read event argument as value", () => {
+      const module = buildModule("Module1", (m) => {
+        const contract1 = m.contract("Contract1", []);
+
+        const event1 = m.readEventArgument(contract1, "Event1", "Value1");
+
+        m.call(contract1, "lock", [], { value: event1 });
+
+        return { contract1 };
+      });
+
+      assertSerializableModuleIn(module);
+    });
   });
 
   describe("static call", () => {
diff --git a/packages/hardhat-plugin/test/contracts.ts b/packages/hardhat-plugin/test/contracts.ts
index 205b1e31..b9cd0a5f 100644
--- a/packages/hardhat-plugin/test/contracts.ts
+++ b/packages/hardhat-plugin/test/contracts.ts
@@ -144,5 +144,69 @@ describe("contract deploys", () => {
         this.hre.ethers.parseEther("2").toString()
       );
     });
+
+    it("should be able to deploy a contract with an endowment via a static call", async function () {
+      const submoduleDefinition = buildModule("submodule", (m) => {
+        const valueContract = m.contract("StaticCallValue");
+
+        const valueResult = m.staticCall(valueContract, "getValue");
+
+        const passingValue = m.contract("PassingValue", [], {
+          value: valueResult,
+        });
+
+        return { passingValue };
+      });
+
+      const moduleDefinition = buildModule("Module", (m) => {
+        const { passingValue } = m.useModule(submoduleDefinition);
+
+        return { passingValue };
+      });
+
+      const result = await this.deploy(moduleDefinition);
+
+      assert.isDefined(result.passingValue);
+
+      const actualInstanceBalance = await this.hre.ethers.provider.getBalance(
+        await result.passingValue.getAddress()
+      );
+
+      assert.equal(actualInstanceBalance.toString(), "42");
+    });
+
+    it("should be able to deploy a contract with an endowment via an event argument", async function () {
+      const submoduleDefinition = buildModule("submodule", (m) => {
+        const valueContract = m.contract("EventArgValue");
+
+        const valueResult = m.readEventArgument(
+          valueContract,
+          "EventValue",
+          "value"
+        );
+
+        const passingValue = m.contract("PassingValue", [], {
+          value: valueResult,
+        });
+
+        return { passingValue };
+      });
+
+      const moduleDefinition = buildModule("Module", (m) => {
+        const { passingValue } = m.useModule(submoduleDefinition);
+
+        return { passingValue };
+      });
+
+      const result = await this.deploy(moduleDefinition);
+
+      assert.isDefined(result.passingValue);
+
+      const actualInstanceBalance = await this.hre.ethers.provider.getBalance(
+        await result.passingValue.getAddress()
+      );
+
+      assert.equal(actualInstanceBalance.toString(), "42");
+    });
   });
 });
diff --git a/packages/hardhat-plugin/test/fixture-projects/minimal/contracts/Contracts.sol b/packages/hardhat-plugin/test/fixture-projects/minimal/contracts/Contracts.sol
index d4559d1a..5b1ae2d7 100644
--- a/packages/hardhat-plugin/test/fixture-projects/minimal/contracts/Contracts.sol
+++ b/packages/hardhat-plugin/test/fixture-projects/minimal/contracts/Contracts.sol
@@ -49,6 +49,20 @@ contract Greeter {
   }
 }
 
+contract StaticCallValue {
+  function getValue() public pure returns (uint256) {
+    return 42;
+  }
+}
+
+contract EventArgValue {
+  event EventValue(uint256 value);
+
+  constructor() {
+    emit EventValue(42);
+  }
+}
+
 contract PassingValue {
   constructor() payable {}