Skip to content

Commit

Permalink
Add the ability to use AccountRuntimeValues as default values for mod… (
Browse files Browse the repository at this point in the history
#679)

Allow Ignition modules to specify module parameters where the default value is an account runtime value:

```
const owner = m.getParameter<string>('owner', m.getAccount(0));
```

The module parameter type has been expanded to included Account Runtime Values, but user facing usages have been swapped for `SolidityParameterType`.

Tests have been added around reconciliation, validation and serialization.

Resolves #673
  • Loading branch information
zoeyTM authored Jan 25, 2024
1 parent 8dcd288 commit ec1fdee
Show file tree
Hide file tree
Showing 23 changed files with 590 additions and 40 deletions.
24 changes: 19 additions & 5 deletions packages/core/src/ignition-module-serializer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -804,7 +804,7 @@ export class IgnitionModuleDeserializer {
)
? (this._deserializeModuleParameterRuntimeValue(
serializedFuture.address
) as ModuleParameterRuntimeValue<string>) // This is unsafe, but we only serialize valid valus
) as ModuleParameterRuntimeValue<string>) // This is unsafe, but we only serialize valid values
: serializedFuture.address,
serializedFuture.artifact
);
Expand Down Expand Up @@ -839,7 +839,7 @@ export class IgnitionModuleDeserializer {
: this._isSerializedModuleParameterRuntimeValue(serializedFuture.to)
? (this._deserializeModuleParameterRuntimeValue(
serializedFuture.to
) as ModuleParameterRuntimeValue<string>) // This is unsafe, but we only serialize valid valus
) as ModuleParameterRuntimeValue<string>) // This is unsafe, but we only serialize valid values
: this._isSerializedAccountRuntimeValue(serializedFuture.to)
? this._deserializeAccountRuntimeValue(serializedFuture.to)
: serializedFuture.to,
Expand Down Expand Up @@ -897,10 +897,24 @@ export class IgnitionModuleDeserializer {
): ModuleParameterRuntimeValue<ModuleParameterType> {
let defaultValue: ModuleParameterType | undefined;
if (serialized.defaultValue !== undefined) {
// We cast here because we receive an `unknow`, but we known it came from serializing a ModuleParameterType
defaultValue = this._jsonParseWithBigint(
// We cast here because we receive an `unknown`, but we known it came from
// serializing a ModuleParameterType
const parsedDefaultValue = this._jsonParseWithBigint(
serialized.defaultValue
) as ModuleParameterType;
);

if (
typeof parsedDefaultValue === "object" &&
parsedDefaultValue !== null &&
"accountIndex" in parsedDefaultValue &&
typeof parsedDefaultValue.accountIndex === "number"
) {
defaultValue = new AccountRuntimeValueImplementation(
parsedDefaultValue.accountIndex
);
} else {
defaultValue = parsedDefaultValue as ModuleParameterType;
}
}

return new ModuleParameterRuntimeValueImplementation(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ export async function buildInitializeMessageFor(
value: resolveValue(
future.value,
deploymentParameters,
deploymentState
deploymentState,
accounts
),
from: resolveFutureFrom(future.from, accounts, defaultSender),
}
Expand Down Expand Up @@ -103,7 +104,8 @@ export async function buildInitializeMessageFor(
value: resolveValue(
future.value,
deploymentParameters,
deploymentState
deploymentState,
accounts
),
from: resolveFutureFrom(future.from, accounts, defaultSender),
}
Expand Down Expand Up @@ -150,7 +152,8 @@ export async function buildInitializeMessageFor(
contractAddress: resolveAddressLike(
future.address,
deploymentState,
deploymentParameters
deploymentParameters,
accounts
),
artifactId: future.id,
}
Expand Down Expand Up @@ -204,7 +207,8 @@ export async function buildInitializeMessageFor(
value: resolveValue(
future.value,
deploymentParameters,
deploymentState
deploymentState,
accounts
),
data: future.data ?? "0x",
from: resolveFutureFrom(future.from, accounts, defaultSender),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ export function resolveValue(
| StaticCallFuture<string, string>
| ReadEventArgumentFuture,
deploymentParameters: DeploymentParameters,
deploymentState: DeploymentState
deploymentState: DeploymentState,
accounts: string[]
): bigint {
if (typeof givenValue === "bigint") {
return givenValue;
Expand All @@ -54,6 +55,7 @@ export function resolveValue(
} else {
result = resolveModuleParameter(givenValue, {
deploymentParameters,
accounts,
});
}

Expand Down Expand Up @@ -85,7 +87,10 @@ export function resolveArgs(
return resolveAccountRuntimeValue(arv, accounts);
},
moduleParameterRuntimeValue: (mprv) => {
return resolveModuleParameter(mprv, { deploymentParameters });
return resolveModuleParameter(mprv, {
deploymentParameters,
accounts,
});
},
});

Expand Down Expand Up @@ -174,7 +179,12 @@ export function resolveSendToAddress(
return resolveAccountRuntimeValue(to, accounts);
}

return resolveAddressLike(to, deploymentState, deploymentParameters);
return resolveAddressLike(
to,
deploymentState,
deploymentParameters,
accounts
);
}

/**
Expand All @@ -188,7 +198,8 @@ export function resolveAddressLike(
| AddressResolvableFuture
| ModuleParameterRuntimeValue<string>,
deploymentState: DeploymentState,
deploymentParameters: DeploymentParameters
deploymentParameters: DeploymentParameters,
accounts: string[]
): string {
if (typeof addressLike === "string") {
return addressLike;
Expand All @@ -197,6 +208,7 @@ export function resolveAddressLike(
if (isModuleParameterRuntimeValue(addressLike)) {
const addressFromParam = resolveModuleParameter(addressLike, {
deploymentParameters,
accounts,
});

assertIgnitionInvariant(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ export function reconcileAddress(
const resolvedAddress = resolveAddressLike(
future.address,
context.deploymentState,
context.deploymentParameters
context.deploymentParameters,
context.accounts
);

return compare(future, "Address", exState.contractAddress, resolvedAddress);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ export function reconcileContract(
const resolvedAddress = resolveAddressLike(
future.contract,
context.deploymentState,
context.deploymentParameters
context.deploymentParameters,
context.accounts
);

return compare(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {
ContractDeploymentFuture,
ContractCallFuture,
ContractDeploymentFuture,
NamedArtifactContractDeploymentFuture,
SendDataFuture,
} from "../../../types/module";
Expand Down Expand Up @@ -32,7 +32,8 @@ export function reconcileValue(
const resolvedValue = resolveValue(
future.value,
context.deploymentParameters,
context.deploymentState
context.deploymentState,
context.accounts
);

return compare(future, "Value", exState.value, resolvedValue);
Expand Down
37 changes: 27 additions & 10 deletions packages/core/src/internal/utils/resolve-module-parameter.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,25 @@
import { isAccountRuntimeValue } from "../../type-guards";
import { DeploymentParameters } from "../../types/deploy";
import {
ModuleParameterRuntimeValue,
ModuleParameterType,
SolidityParameterType,
} from "../../types/module";
import { resolveAccountRuntimeValue } from "../execution/future-processor/helpers/future-resolvers";

import { assertIgnitionInvariant } from "./assertions";

export function resolveModuleParameter(
moduleParamRuntimeValue: ModuleParameterRuntimeValue<ModuleParameterType>,
context: { deploymentParameters: DeploymentParameters }
): ModuleParameterType {
context: { deploymentParameters: DeploymentParameters; accounts: string[] }
): SolidityParameterType {
if (context.deploymentParameters === undefined) {
assertIgnitionInvariant(
moduleParamRuntimeValue.defaultValue !== undefined,
`No default value provided for module parameter ${moduleParamRuntimeValue.moduleId}/${moduleParamRuntimeValue.name}`
);

return moduleParamRuntimeValue.defaultValue;
return _resolveDefaultValue(moduleParamRuntimeValue, context.accounts);
}

const moduleParameters =
Expand All @@ -28,19 +31,33 @@ export function resolveModuleParameter(
`No default value provided for module parameter ${moduleParamRuntimeValue.moduleId}/${moduleParamRuntimeValue.name}`
);

return moduleParamRuntimeValue.defaultValue;
return _resolveDefaultValue(moduleParamRuntimeValue, context.accounts);
}

const moduleParamValue = moduleParameters[moduleParamRuntimeValue.name];

if (moduleParamValue === undefined) {
assertIgnitionInvariant(
moduleParamRuntimeValue.defaultValue !== undefined,
`No default value provided for module parameter ${moduleParamRuntimeValue.moduleId}/${moduleParamRuntimeValue.name}`
);

return moduleParamRuntimeValue.defaultValue;
return _resolveDefaultValue(moduleParamRuntimeValue, context.accounts);
}

return moduleParamValue;
}

function _resolveDefaultValue(
moduleParamRuntimeValue: ModuleParameterRuntimeValue<ModuleParameterType>,
accounts: string[]
): SolidityParameterType {
assertIgnitionInvariant(
moduleParamRuntimeValue.defaultValue !== undefined,
`No default value provided for module parameter ${moduleParamRuntimeValue.moduleId}/${moduleParamRuntimeValue.name}`
);

if (isAccountRuntimeValue(moduleParamRuntimeValue.defaultValue)) {
return resolveAccountRuntimeValue(
moduleParamRuntimeValue.defaultValue,
accounts
);
}

return moduleParamRuntimeValue.defaultValue;
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { ERRORS } from "../../errors-list";
import { validateContractConstructorArgsLength } from "../../execution/abi";
import { validateLibraryNames } from "../../execution/libraries";
import {
filterToAccountRuntimeValues,
retrieveNestedRuntimeValues,
validateAccountRuntimeValue,
} from "../utils";
Expand Down Expand Up @@ -41,7 +42,7 @@ export async function validateArtifactContractDeployment(
const runtimeValues = retrieveNestedRuntimeValues(future.constructorArgs);
const moduleParams = runtimeValues.filter(isModuleParameterRuntimeValue);
const accountParams = [
...runtimeValues.filter(isAccountRuntimeValue),
...filterToAccountRuntimeValues(runtimeValues),
...(isAccountRuntimeValue(future.from) ? [future.from] : []),
];

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { ContractCallFuture } from "../../../types/module";
import { ERRORS } from "../../errors-list";
import { validateArtifactFunction } from "../../execution/abi";
import {
filterToAccountRuntimeValues,
retrieveNestedRuntimeValues,
validateAccountRuntimeValue,
} from "../utils";
Expand Down Expand Up @@ -52,7 +53,7 @@ export async function validateNamedContractCall(
const runtimeValues = retrieveNestedRuntimeValues(future.args);
const moduleParams = runtimeValues.filter(isModuleParameterRuntimeValue);
const accountParams = [
...runtimeValues.filter(isAccountRuntimeValue),
...filterToAccountRuntimeValues(runtimeValues),
...(isAccountRuntimeValue(future.from) ? [future.from] : []),
];

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { ERRORS } from "../../errors-list";
import { validateContractConstructorArgsLength } from "../../execution/abi";
import { validateLibraryNames } from "../../execution/libraries";
import {
filterToAccountRuntimeValues,
retrieveNestedRuntimeValues,
validateAccountRuntimeValue,
} from "../utils";
Expand Down Expand Up @@ -52,7 +53,7 @@ export async function validateNamedContractDeployment(
const runtimeValues = retrieveNestedRuntimeValues(future.constructorArgs);
const moduleParams = runtimeValues.filter(isModuleParameterRuntimeValue);
const accountParams = [
...runtimeValues.filter(isAccountRuntimeValue),
...filterToAccountRuntimeValues(runtimeValues),
...(isAccountRuntimeValue(future.from) ? [future.from] : []),
];

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
validateFunctionArgumentParamType,
} from "../../execution/abi";
import {
filterToAccountRuntimeValues,
retrieveNestedRuntimeValues,
validateAccountRuntimeValue,
} from "../utils";
Expand Down Expand Up @@ -64,7 +65,7 @@ export async function validateNamedStaticCall(
const runtimeValues = retrieveNestedRuntimeValues(future.args);
const moduleParams = runtimeValues.filter(isModuleParameterRuntimeValue);
const accountParams = [
...runtimeValues.filter(isAccountRuntimeValue),
...filterToAccountRuntimeValues(runtimeValues),
...(isAccountRuntimeValue(future.from) ? [future.from] : []),
];

Expand Down
22 changes: 21 additions & 1 deletion packages/core/src/internal/validation/utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { IgnitionError } from "../../errors";
import { isFuture, isRuntimeValue } from "../../type-guards";
import {
isAccountRuntimeValue,
isFuture,
isRuntimeValue,
} from "../../type-guards";
import {
AccountRuntimeValue,
ArgumentType,
Expand Down Expand Up @@ -29,6 +33,22 @@ export function validateAccountRuntimeValue(
return errors;
}

export function filterToAccountRuntimeValues(
runtimeValues: RuntimeValue[]
): AccountRuntimeValue[] {
return runtimeValues
.map((rv) => {
if (isAccountRuntimeValue(rv)) {
return rv;
} else if (isAccountRuntimeValue(rv.defaultValue)) {
return rv.defaultValue;
} else {
return undefined;
}
})
.filter((rv): rv is AccountRuntimeValue => rv !== undefined);
}

export function retrieveNestedRuntimeValues(
args: ArgumentType[]
): RuntimeValue[] {
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/types/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,7 @@ export type SolidityParameterType =
*
* @beta
*/
export type ModuleParameterType = SolidityParameterType;
export type ModuleParameterType = SolidityParameterType | AccountRuntimeValue;

/**
* The different runtime values supported by Ignition.
Expand Down Expand Up @@ -395,7 +395,7 @@ export interface ModuleParameterRuntimeValue<
* @beta
*/
export interface ModuleParameters {
[parameterName: string]: ModuleParameterType;
[parameterName: string]: SolidityParameterType;
}

/**
Expand Down
Loading

0 comments on commit ec1fdee

Please sign in to comment.