Skip to content

Commit

Permalink
feat: adds time range module
Browse files Browse the repository at this point in the history
fix: lint

fix: review fixes

feat: add view functions and user op calldata encodings

feat: adds time module impl

feat: adds time range module tests

refactor: removes use of addresses, meta, and value field in args passed to encodeAbiParameters

Co-authored-by: howydev <132113803+howydev@users.noreply.github.com>
  • Loading branch information
linnall and howydev authored Dec 20, 2024
1 parent 2c27b4c commit ca24d50
Show file tree
Hide file tree
Showing 3 changed files with 192 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {
AccountNotFoundError,
IncompatibleClientError,
isSmartAccountClient,
EntityIdOverrideError,
// EntityIdOverrideError,
type GetEntryPointFromAccount,
type SendUserOperationResult,
type UserOperationOverridesParameter,
Expand All @@ -20,7 +20,7 @@ import {

import { type SMAV2AccountClient } from "../../client/client.js";
import { type SMAV2Account } from "../../account/semiModularAccountV2.js";
import { DEFAULT_OWNER_ENTITY_ID } from "../../utils.js";
// import { DEFAULT_OWNER_ENTITY_ID } from "../../utils.js";

export type InstallValidationParams<
TSigner extends SmartAccountSigner = SmartAccountSigner
Expand Down
126 changes: 126 additions & 0 deletions account-kit/smart-contracts/src/ma-v2/client/client.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,14 @@ import { accounts } from "~test/constants.js";
import {
getDefaultPaymasterGuardModuleAddress,
getDefaultSingleSignerValidationModuleAddress,
getDefaultTimeRangeModuleAddress,
} from "../modules/utils.js";
import { SingleSignerValidationModule } from "../modules/single-signer-validation/module.js";
import { installValidationActions } from "../actions/install-validation/installValidation.js";
import { paymaster070 } from "~test/paymaster/paymaster070.js";
import { PaymasterGuardModule } from "../modules/paymaster-guard-module/module.js";
import { HookType } from "../actions/common/types.js";
import { TimeRangeModule } from "../modules/time-range-module/module.js";

describe("MA v2 Tests", async () => {
const instance = local070Instance;
Expand Down Expand Up @@ -347,6 +349,130 @@ describe("MA v2 Tests", async () => {
).resolves.not.toThrowError();
});

it("installs time range module, then uninstalls module within valid time range", async () => {
let provider = (
await givenConnectedProvider({
signer,
})
).extend(installValidationActions);

await setBalance(client, {
address: provider.getAddress(),
value: parseEther("2"),
});

const hookInstallData = TimeRangeModule.encodeOnInstallData({
entityId: 0,
validAfter: 0,
validUntil: 10000000000,
});

const installResult = await provider.installValidation({
validationConfig: {
moduleAddress: zeroAddress,
entityId: 0,
isGlobal: true,
isSignatureValidation: true,
isUserOpValidation: true,
},
selectors: [],
installData: "0x",
hooks: [
{
hookConfig: {
address: getDefaultTimeRangeModuleAddress(provider.chain),
entityId: 0, // uint32
hookType: HookType.VALIDATION,
hasPreHooks: true,
hasPostHooks: true,
},
initData: hookInstallData,
},
],
});

// verify hook installtion succeeded
await provider.waitForUserOperationTransaction(installResult);

const hookUninstallData = TimeRangeModule.encodeOnUninstallData({
entityId: 0,
});

const uninstallResult = await provider.uninstallValidation({
moduleAddress: zeroAddress,
entityId: 0,
uninstallData: "0x",
hookUninstallDatas: [hookUninstallData],
});

// verify uninstall
await expect(
provider.waitForUserOperationTransaction(uninstallResult)
).resolves.not.toThrowError();
});

it("installs time range module, then uninstalls module outside valid time range", async () => {
let provider = (
await givenConnectedProvider({
signer,
})
).extend(installValidationActions);

await setBalance(client, {
address: provider.getAddress(),
value: parseEther("2"),
});

const hookInstallData = TimeRangeModule.encodeOnInstallData({
entityId: 0,
validAfter: 0,
validUntil: 1,
});

const installResult = await provider.installValidation({
validationConfig: {
moduleAddress: zeroAddress,
entityId: 0,
isGlobal: true,
isSignatureValidation: true,
isUserOpValidation: true,
},
selectors: [],
installData: "0x",
hooks: [
{
hookConfig: {
address: getDefaultTimeRangeModuleAddress(provider.chain),
entityId: 0, // uint32
hookType: HookType.VALIDATION,
hasPreHooks: true,
hasPostHooks: true,
},
initData: hookInstallData,
},
],
});

// verify hook installtion succeeded
await provider.waitForUserOperationTransaction(installResult);

const hookUninstallData = TimeRangeModule.encodeOnUninstallData({
entityId: 0,
});

const uninstallResult = await provider.uninstallValidation({
moduleAddress: zeroAddress,
entityId: 0,
uninstallData: "0x",
hookUninstallDatas: [hookUninstallData],
});

// uninstall should fail
await expect(
provider.waitForUserOperationTransaction(uninstallResult)
).rejects.toThrowError();
});

const givenConnectedProvider = async ({
signer,
accountAddress,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { encodeAbiParameters, type Hex } from "viem";

import { timeRangeModuleAbi } from "./abis/timeRangeModuleAbi.js";

// Todo: some unified type for ERC-6900 v0.8 modules. I couldn't figure out how to parameterize the class itself over the abi type parameters for onInstall and onUninstall.
export const TimeRangeModule = {
abi: timeRangeModuleAbi,
encodeOnInstallData: (args: {
entityId: number;
validUntil: number;
validAfter: number;
}): Hex => {
const { entityId, validUntil, validAfter } = args;

return encodeAbiParameters(
[
{
type: "uint32",
},
{
type: "uint48",
},
{
type: "uint48",
},
],
[entityId, validUntil, validAfter]
);
},
encodeOnUninstallData: (args: { entityId: number }): Hex => {
const { entityId } = args;

return encodeAbiParameters(
[
{
type: "uint32",
},
],
[entityId]
);
},
encodeSetTimeRange: (args: {
entityId: number;
validUntil: number;
validAfter: number;
}): Hex => {
const { entityId, validUntil, validAfter } = args;

return encodeAbiParameters(
[
{
type: "uint32",
},
{
type: "uint48",
},
{
type: "uint48",
},
],
[entityId, validUntil, validAfter]
);
},
};

0 comments on commit ca24d50

Please sign in to comment.