diff --git a/src/sdk/__contracts/abi/CounterAbi.ts b/src/sdk/__contracts/abi/CounterAbi.ts new file mode 100644 index 00000000..e08ebbf8 --- /dev/null +++ b/src/sdk/__contracts/abi/CounterAbi.ts @@ -0,0 +1,37 @@ +export const CounterAbi = [ + { + inputs: [], + name: "decrementNumber", + outputs: [], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [], + name: "getNumber", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256" + } + ], + stateMutability: "view", + type: "function" + }, + { + inputs: [], + name: "incrementNumber", + outputs: [], + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [], + name: "revertOperation", + outputs: [], + stateMutability: "pure", + type: "function" + } + ] as const + \ No newline at end of file diff --git a/src/sdk/modules/base/BaseValidationModule.ts b/src/sdk/modules/base/BaseValidationModule.ts index 9ac6a31a..2a529ff0 100644 --- a/src/sdk/modules/base/BaseValidationModule.ts +++ b/src/sdk/modules/base/BaseValidationModule.ts @@ -1,15 +1,14 @@ import { type Hex, getAddress } from "viem" import type { Signer } from "../../account/utils/toSigner.js" import { BaseModule } from "./BaseModule.js" -import { type ModuleInfo } from "../utils/Types.js" export abstract class BaseValidationModule extends BaseModule { public getSigner(): Signer { return this.signer } - getDummySignature(params?: ModuleInfo): Hex { - console.log("params", params) + + getDummySignature(): Hex { const moduleAddress = getAddress(this.getAddress()) const dynamicPart = moduleAddress.substring(2).padEnd(40, "0") return `0x0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000${dynamicPart}000000000000000000000000000000000000000000000000000000000000004181d4b4981670cb18f99f0b4a66446df1bf5b204d24cfcb659bf38ba27a4359b5711649ec2423c5e1247245eba2964679b6a1dbb85c992ae40b9b00c6935b02ff1b00000000000000000000000000000000000000000000000000000000000000` diff --git a/src/sdk/modules/utils/Types.ts b/src/sdk/modules/utils/Types.ts index bb256cb5..782e85a9 100644 --- a/src/sdk/modules/utils/Types.ts +++ b/src/sdk/modules/utils/Types.ts @@ -73,6 +73,8 @@ export const moduleTypeIds: ModuleTypeIds = { hook: 4 } +// Todo: moduleInfo marked for removal +// note: set the required needful info in the active module instance. export type ModuleInfo = { /** Smart session mode */ mode?: SmartSessionModeType diff --git a/src/sdk/modules/validators/SmartSessionValidator.ts b/src/sdk/modules/validators/SmartSessionValidator.ts index 8b26195c..47c695c2 100644 --- a/src/sdk/modules/validators/SmartSessionValidator.ts +++ b/src/sdk/modules/validators/SmartSessionValidator.ts @@ -24,6 +24,7 @@ const SIMPLE_SESSION_VALIDATOR_ADDRESS = addresses.SimpleSessionValidator export class SmartSessionValidator extends BaseValidationModule { public client: PublicClient + public activePermissionId: Hex private constructor( moduleConfig: Module, @@ -36,6 +37,7 @@ export class SmartSessionValidator extends BaseValidationModule { super(moduleConfig, signer) const client = smartAccount.client as PublicClient; this.client = client + this.activePermissionId = '0x' this.signer = signer // Review: could be optional override. otherwise use SMART_SESSION_ADDRESS from addresses this.address = moduleConfig.address @@ -68,20 +70,26 @@ export class SmartSessionValidator extends BaseValidationModule { return instance } + public setActivePermissionId(permissionId: Hex) { + this.activePermissionId = permissionId + } + + // Todo: moduleInfo marked for removal public override getDummySignature(moduleInfo?: ModuleInfo): Hex { const signature = encodeSmartSessionSignature({ mode: moduleInfo?.mode ? moduleInfo.mode : SmartSessionMode.USE, - permissionId: moduleInfo?.permissionId ? moduleInfo.permissionId : '0x', + permissionId: moduleInfo?.permissionId ? moduleInfo.permissionId : this.activePermissionId, signature: DUMMY_ECDSA_SIG, }) as Hex return signature } + // Todo: moduleInfo marked for removal override async signUserOpHash(userOpHash: string, moduleInfo?: ModuleInfo): Promise{ const signature = await this.signer.signMessage({ message: { raw: userOpHash as Hex } }) as Hex return encodeSmartSessionSignature({ mode: moduleInfo?.mode ? moduleInfo.mode : SmartSessionMode.USE, - permissionId: moduleInfo?.permissionId ? moduleInfo.permissionId : '0x', + permissionId: moduleInfo?.permissionId ? moduleInfo.permissionId : this.activePermissionId, signature, }) as Hex } diff --git a/src/sdk/modules/validators/smartSessionValidator.test.ts b/src/sdk/modules/validators/smartSessionValidator.test.ts index a56453df..d0615989 100644 --- a/src/sdk/modules/validators/smartSessionValidator.test.ts +++ b/src/sdk/modules/validators/smartSessionValidator.test.ts @@ -1,4 +1,4 @@ -import { encodeAbiParameters, encodePacked, Hex, http, PublicClient, toBytes, toHex, type Account, type Address, type Chain } from "viem" +import { encodeFunctionData, Hex, http, PublicClient, toBytes, toHex, type Account, type Address, type Chain } from "viem" import { TEST_CONTRACTS } from './../../../test/callDatas'; import { afterAll, beforeAll, describe, expect, test } from "vitest" import { toNetwork } from "../../../test/testSetup" @@ -16,6 +16,7 @@ import { createNexusClient } from "../../clients/createNexusClient" import { CreateSessionDataParams, createSmartSessionValidatorModule, isSessionEnabled } from "../.." +import { CounterAbi } from "../../__contracts/abi/CounterAbi"; describe("modules.k1Validator.write", async () => { let network: NetworkConfig @@ -106,8 +107,6 @@ describe("modules.k1Validator.write", async () => { expect(isInstalledBefore).toBe(true) - // const smartAccountSigner = await convertSigner(walletClient) - const smartSessionModule = await createSmartSessionValidatorModule({ smartAccount: nexusClient.account, address: TEST_CONTRACTS.SmartSession.address @@ -170,4 +169,67 @@ describe("modules.k1Validator.write", async () => { }) expect(isEnabled).toBe(true) }, 60000) + + test("should make use of already enabled session (USE mode) to increment a counter using a session key", async () => { + + const isEnabled = await isSessionEnabled({ + client: nexusClient.account.client as PublicClient, + accountAddress: await nexusClient.account.getAddress(), + permissionId: permissionIdCached + }) + expect(isEnabled).toBe(true) + + const smartSessionModule = await createSmartSessionValidatorModule({ + smartAccount: nexusClient.account, + address: TEST_CONTRACTS.SmartSession.address + }) + // set active validation module + + nexusClient.account.setActiveValidationModule(smartSessionModule) + + // must do this as we can not pass moduleInfo from sendUserOperation + smartSessionModule.setActivePermissionId(permissionIdCached) + + // need permissionId from session object (both from some cache) + + const pubClient = nexusClient.account.client as PublicClient + + const counterBefore = await pubClient.readContract({ + address: TEST_CONTRACTS.Counter.address, + abi: CounterAbi, + functionName: "getNumber", + args: [] + }) + + // helpful for out of range test + await testClient.setNextBlockTimestamp({ + timestamp: 3727001666n + }) + + // Make userop to increase counter + const hash = await nexusClient.sendUserOperation({ + calls: [ + { + to: TEST_CONTRACTS.Counter.address, + data: encodeFunctionData({ + abi: CounterAbi, + functionName: "incrementNumber", + args: [] + }) + } + ], + }) + + const { success } = await nexusClient.waitForUserOperationReceipt({ hash }) + expect(success).toBe(true) + + const counterAfter = await pubClient.readContract({ + address: TEST_CONTRACTS.Counter.address, + abi: CounterAbi, + functionName: "getNumber", + args: [] + }) + + expect(counterAfter).toBe(counterBefore + BigInt(1)) + }, 60000) })