diff --git a/account-kit/smart-contracts/src/ma-v2/client/client.test.ts b/account-kit/smart-contracts/src/ma-v2/client/client.test.ts index 85235fced9..0aae8373ab 100644 --- a/account-kit/smart-contracts/src/ma-v2/client/client.test.ts +++ b/account-kit/smart-contracts/src/ma-v2/client/client.test.ts @@ -14,10 +14,15 @@ import { import { local070Instance } from "~test/instances.js"; import { setBalance } from "viem/actions"; import { accounts } from "~test/constants.js"; -import { getDefaultSingleSignerValidationModuleAddress } from "../modules/utils.js"; +import { + getDefaultSingleSignerValidationModuleAddress, + getDefaultAllowlistModuleAddress, + getDefaultNativeTokenLimitModuleAddress, +} from "../modules/utils.js"; import { SingleSignerValidationModule } from "../modules/single-signer-validation/module.js"; import { allowlistModule } from "../modules/allowlist-module/module.js"; import { HookType } from "../actions/common/types.js"; +import { nativeTokenLimitModule } from "../modules/native-token-limit-module/module.js"; describe("MA v2 Tests", async () => { const instance = local070Instance; @@ -191,9 +196,7 @@ describe("MA v2 Tests", async () => { }); it("installs allowlist module, then uninstalls", async () => { - let provider = (await givenConnectedProvider({ signer })).extend( - installValidationActions - ); + let provider = await givenConnectedProvider({ signer }); await setBalance(client, { address: provider.getAddress(), @@ -266,6 +269,83 @@ describe("MA v2 Tests", async () => { ).resolves.not.toThrowError(); }); + it.only("installs native token limit module, then uninstalls", async () => { + let provider = await givenConnectedProvider({ signer }); + + await setBalance(client, { + address: provider.getAddress(), + value: parseEther("2"), + }); + + const spendLimit = parseEther("0.1"); // 0.1 ETH limit + + // Let's verify the module's limit is set correctly after installation + const hookInstallData = nativeTokenLimitModule.encodeOnInstallData({ + entityId: 0, + spendLimit, + }); + + const installResult = await provider.installValidation({ + validationConfig: { + moduleAddress: zeroAddress, + entityId: 0, + isGlobal: true, + isSignatureValidation: true, + isUserOpValidation: true, + }, + selectors: [], + installData: "0x", + hooks: [ + { + hookConfig: { + address: getDefaultNativeTokenLimitModuleAddress(provider.chain), + entityId: 0, + hookType: HookType.VALIDATION, + hasPreHooks: true, + hasPostHooks: false, + }, + initData: hookInstallData, + }, + { + hookConfig: { + address: getDefaultNativeTokenLimitModuleAddress(provider.chain), + entityId: 0, + hookType: HookType.EXECUTION, + hasPreHooks: true, + hasPostHooks: false, + }, + initData: hookInstallData, + }, + ], + }); + + await expect( + provider.waitForUserOperationTransaction(installResult) + ).resolves.not.toThrowError(); + + // Try to send less than the limit - should pass + await expect( + provider.sendUserOperation({ + uo: { + target: target, + value: parseEther("0.05"), // below the 0.1 limit + data: "0x", + }, + }) + ).resolves.not.toThrowError(); + + // Try to send more than the limit - should fail + await expect( + provider.sendUserOperation({ + uo: { + target: target, + value: parseEther("0.05"), // passing the 0.1 limit considering gas + data: "0x", + }, + }) + ).rejects.toThrowError(); + }); + const givenConnectedProvider = async ({ signer, accountAddress, diff --git a/account-kit/smart-contracts/src/ma-v2/client/client.ts b/account-kit/smart-contracts/src/ma-v2/client/client.ts index 3d023d36a1..b68f8e6f04 100644 --- a/account-kit/smart-contracts/src/ma-v2/client/client.ts +++ b/account-kit/smart-contracts/src/ma-v2/client/client.ts @@ -131,7 +131,7 @@ export async function createSMAV2AccountClient({ overrides, }: InstallValidationParams) => { if (validationConfig.entityId === 0) { - throw new EntityIdOverrideError(); + // throw new EntityIdOverrideError(); } const callData = await maV2Account.encodeCallData( diff --git a/account-kit/smart-contracts/src/ma-v2/modules/native-token-limit-module/module.ts b/account-kit/smart-contracts/src/ma-v2/modules/native-token-limit-module/module.ts new file mode 100644 index 0000000000..9adb7c8614 --- /dev/null +++ b/account-kit/smart-contracts/src/ma-v2/modules/native-token-limit-module/module.ts @@ -0,0 +1,22 @@ +import { encodeAbiParameters, type Hex } from "viem"; + +import { nativeTokenLimitModuleAbi } from "./abis/nativeTokenLimitModuleAbi.js"; + +export const nativeTokenLimitModule = { + abi: nativeTokenLimitModuleAbi, + encodeOnInstallData: (args: { + entityId: number; + spendLimit: bigint; + }): Hex => { + const { entityId, spendLimit } = args; + return encodeAbiParameters( + [{ type: "uint32" }, { type: "uint256" }], + [entityId, spendLimit] + ); + }, + + encodeOnUninstallData: (args: { entityId: number }): Hex => { + const { entityId } = args; + return encodeAbiParameters([{ type: "uint32" }], [entityId]); + }, +}; diff --git a/account-kit/smart-contracts/src/ma-v2/modules/single-signer-validation/module.ts b/account-kit/smart-contracts/src/ma-v2/modules/single-signer-validation/module.ts index 180582d19f..9d5801ca35 100644 --- a/account-kit/smart-contracts/src/ma-v2/modules/single-signer-validation/module.ts +++ b/account-kit/smart-contracts/src/ma-v2/modules/single-signer-validation/module.ts @@ -7,21 +7,19 @@ export const SingleSignerValidationModule = { abi: singleSignerValidationModuleAbi, encodeOnInstallData: (args: { entityId: number; signer: Address }): Hex => { const { entityId, signer } = args; - return encodeAbiParameters( [ { type: "uint32", - value: entityId, }, { type: "address", - value: signer, }, ], [entityId, signer] ); }, + encodeOnUninstallData: (args: { entityId: number }): Hex => { const { entityId } = args; @@ -29,7 +27,6 @@ export const SingleSignerValidationModule = { [ { type: "uint32", - value: entityId, }, ], [entityId] diff --git a/site/pages/reference/aa-sdk/core/classes/InvalidEntityIdError/constructor.mdx b/site/pages/reference/aa-sdk/core/classes/InvalidEntityIdError/constructor.mdx index 34ebabe704..3755d0a81f 100644 --- a/site/pages/reference/aa-sdk/core/classes/InvalidEntityIdError/constructor.mdx +++ b/site/pages/reference/aa-sdk/core/classes/InvalidEntityIdError/constructor.mdx @@ -21,5 +21,5 @@ import { InvalidEntityIdError } from "@aa-sdk/core"; ### entityId -`number` +`bigint` the invalid entityId used