@zerodev/permissions 5.6.1 → 5.6.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/_cjs/constants.js +2 -1
  2. package/_cjs/constants.js.map +1 -1
  3. package/_cjs/index.js +5 -1
  4. package/_cjs/index.js.map +1 -1
  5. package/_cjs/migration/isPermissionMigrated.js +22 -0
  6. package/_cjs/migration/isPermissionMigrated.js.map +1 -0
  7. package/_cjs/migration/migrationSessionKeyAccount.js +91 -0
  8. package/_cjs/migration/migrationSessionKeyAccount.js.map +1 -0
  9. package/_cjs/policies/callPolicyUtils.js +27 -0
  10. package/_cjs/policies/callPolicyUtils.js.map +1 -1
  11. package/_cjs/policies/toCallPolicy.js +18 -16
  12. package/_cjs/policies/toCallPolicy.js.map +1 -1
  13. package/_cjs/policies/types.js +1 -0
  14. package/_cjs/policies/types.js.map +1 -1
  15. package/_cjs/serializeMultiChainPermissionAccounts.js +31 -13
  16. package/_cjs/serializeMultiChainPermissionAccounts.js.map +1 -1
  17. package/_cjs/serializePermissionAccount.js +5 -4
  18. package/_cjs/serializePermissionAccount.js.map +1 -1
  19. package/_esm/constants.js +5 -0
  20. package/_esm/constants.js.map +1 -1
  21. package/_esm/index.js +2 -0
  22. package/_esm/index.js.map +1 -1
  23. package/_esm/migration/isPermissionMigrated.js +18 -0
  24. package/_esm/migration/isPermissionMigrated.js.map +1 -0
  25. package/_esm/migration/migrationSessionKeyAccount.js +87 -0
  26. package/_esm/migration/migrationSessionKeyAccount.js.map +1 -0
  27. package/_esm/policies/callPolicyUtils.js +29 -1
  28. package/_esm/policies/callPolicyUtils.js.map +1 -1
  29. package/_esm/policies/toCallPolicy.js +21 -19
  30. package/_esm/policies/toCallPolicy.js.map +1 -1
  31. package/_esm/policies/types.js +1 -0
  32. package/_esm/policies/types.js.map +1 -1
  33. package/_esm/serializeMultiChainPermissionAccounts.js +33 -14
  34. package/_esm/serializeMultiChainPermissionAccounts.js.map +1 -1
  35. package/_esm/serializePermissionAccount.js +6 -4
  36. package/_esm/serializePermissionAccount.js.map +1 -1
  37. package/_types/constants.d.ts +5 -0
  38. package/_types/constants.d.ts.map +1 -1
  39. package/_types/index.d.ts +2 -0
  40. package/_types/index.d.ts.map +1 -1
  41. package/_types/migration/isPermissionMigrated.d.ts +6 -0
  42. package/_types/migration/isPermissionMigrated.d.ts.map +1 -0
  43. package/_types/migration/migrationSessionKeyAccount.d.ts +7 -0
  44. package/_types/migration/migrationSessionKeyAccount.d.ts.map +1 -0
  45. package/_types/policies/callPolicyUtils.d.ts.map +1 -1
  46. package/_types/policies/toCallPolicy.d.ts +7 -6
  47. package/_types/policies/toCallPolicy.d.ts.map +1 -1
  48. package/_types/policies/types.d.ts +21 -2
  49. package/_types/policies/types.d.ts.map +1 -1
  50. package/_types/serializeMultiChainPermissionAccounts.d.ts +3 -0
  51. package/_types/serializeMultiChainPermissionAccounts.d.ts.map +1 -1
  52. package/_types/serializePermissionAccount.d.ts +1 -1
  53. package/_types/serializePermissionAccount.d.ts.map +1 -1
  54. package/_types/types.d.ts +2 -2
  55. package/_types/types.d.ts.map +1 -1
  56. package/constants.ts +7 -0
  57. package/index.ts +2 -0
  58. package/migration/isPermissionMigrated.ts +40 -0
  59. package/migration/migrationSessionKeyAccount.ts +120 -0
  60. package/package.json +1 -1
  61. package/policies/callPolicyUtils.ts +39 -0
  62. package/policies/toCallPolicy.ts +22 -17
  63. package/policies/types.ts +51 -2
  64. package/serializeMultiChainPermissionAccounts.ts +42 -21
  65. package/serializePermissionAccount.ts +9 -4
  66. package/types.ts +2 -2
@@ -0,0 +1,40 @@
1
+ import {
2
+ MIGRATION_HELPER_ADDRESS,
3
+ MigrationHelperAbi
4
+ } from "@zerodev/sdk/accounts"
5
+ import type {
6
+ Address,
7
+ Chain,
8
+ Client,
9
+ Hex,
10
+ JsonRpcAccount,
11
+ LocalAccount,
12
+ Transport
13
+ } from "viem"
14
+ import { readContract } from "viem/actions"
15
+ import { getAction } from "viem/utils"
16
+
17
+ export const isPermissionMigrated = async (
18
+ client: Client<
19
+ Transport,
20
+ Chain | undefined,
21
+ JsonRpcAccount | LocalAccount | undefined
22
+ >,
23
+ params: { account: Address; permissionId: Hex }
24
+ ): Promise<boolean> => {
25
+ try {
26
+ const [, , p] = await getAction(
27
+ client,
28
+ readContract,
29
+ "readContract"
30
+ )({
31
+ address: MIGRATION_HELPER_ADDRESS,
32
+ abi: MigrationHelperAbi,
33
+ functionName: "isMigrated",
34
+ args: [params.account, [], [params.permissionId]]
35
+ })
36
+ return p[0]
37
+ } catch {
38
+ return false
39
+ }
40
+ }
@@ -0,0 +1,120 @@
1
+ import { KernelV3AccountAbi, KernelV3ExecuteAbi } from "@zerodev/sdk"
2
+ import {
3
+ type CreateKernelAccountReturnType,
4
+ MIGRATION_HELPER_ADDRESS,
5
+ MigrationHelperAbi
6
+ } from "@zerodev/sdk/accounts"
7
+ import { CALL_TYPE } from "@zerodev/sdk/constants"
8
+ import {
9
+ type Call,
10
+ type Hex,
11
+ concat,
12
+ decodeFunctionData,
13
+ encodeAbiParameters,
14
+ encodeFunctionData,
15
+ getAbiItem,
16
+ parseAbiParameters,
17
+ toFunctionSelector,
18
+ zeroAddress
19
+ } from "viem"
20
+ import { isPermissionMigrated } from "./isPermissionMigrated.js"
21
+
22
+ export const migrationSessionKeyAccount = async (params: {
23
+ account: CreateKernelAccountReturnType<"0.7">
24
+ permissionId: Hex
25
+ }): Promise<CreateKernelAccountReturnType<"0.7">> => {
26
+ const account = params.account
27
+ const installFallbackCallData = encodeFunctionData({
28
+ abi: KernelV3AccountAbi,
29
+ functionName: "installModule",
30
+ args: [
31
+ 3n,
32
+ MIGRATION_HELPER_ADDRESS,
33
+ concat([
34
+ toFunctionSelector(
35
+ getAbiItem({
36
+ abi: MigrationHelperAbi,
37
+ name: "migrateWithCall"
38
+ })
39
+ ),
40
+ zeroAddress,
41
+ encodeAbiParameters(
42
+ parseAbiParameters(
43
+ "bytes selectorInitData, bytes hookInitData"
44
+ ),
45
+ [CALL_TYPE.DELEGATE_CALL, "0x0000"]
46
+ )
47
+ ])
48
+ ]
49
+ })
50
+ const installFallbackCall = {
51
+ to: account.address,
52
+ data: installFallbackCallData,
53
+ value: 0n
54
+ }
55
+ const uninstallFallbackCallData = encodeFunctionData({
56
+ abi: KernelV3AccountAbi,
57
+ functionName: "uninstallModule",
58
+ args: [
59
+ 3n,
60
+ MIGRATION_HELPER_ADDRESS,
61
+ concat([
62
+ toFunctionSelector(
63
+ getAbiItem({
64
+ abi: MigrationHelperAbi,
65
+ name: "migrateWithCall"
66
+ })
67
+ ),
68
+ "0x"
69
+ ])
70
+ ]
71
+ })
72
+ const uninstallFallbackCall = {
73
+ to: account.address,
74
+ data: uninstallFallbackCallData,
75
+ value: 0n
76
+ }
77
+ return {
78
+ ...params.account,
79
+ async encodeCalls(calls, callType) {
80
+ const isMigrated = await isPermissionMigrated(account.client, {
81
+ account: account.address,
82
+ permissionId: params.permissionId
83
+ })
84
+ const executeCallData = await account.encodeCalls(calls, callType)
85
+ if (isMigrated) {
86
+ return executeCallData
87
+ }
88
+ const {
89
+ args: [execMode, executionCalldata]
90
+ } = decodeFunctionData({
91
+ abi: [getAbiItem({ abi: KernelV3ExecuteAbi, name: "execute" })],
92
+ data: executeCallData
93
+ })
94
+ const migrationCallData = encodeFunctionData({
95
+ abi: MigrationHelperAbi,
96
+ functionName: "migrateWithCall",
97
+ args: [[], [params.permissionId], execMode, executionCalldata]
98
+ })
99
+
100
+ const migrationCall = {
101
+ to: MIGRATION_HELPER_ADDRESS,
102
+ data: migrationCallData,
103
+ value: 0n
104
+ } as Call
105
+
106
+ if (account.kernelVersion !== "0.3.0") {
107
+ return account.encodeCalls([migrationCall], "delegatecall")
108
+ }
109
+
110
+ migrationCall.to = account.address
111
+ const finalCalls = [
112
+ installFallbackCall,
113
+ migrationCall,
114
+ uninstallFallbackCall
115
+ ]
116
+
117
+ return account.encodeCalls(finalCalls, "call")
118
+ }
119
+ }
120
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zerodev/permissions",
3
- "version": "5.6.1",
3
+ "version": "5.6.3",
4
4
  "author": "ZeroDev",
5
5
  "main": "./_cjs/index.js",
6
6
  "module": "./_esm/index.js",
@@ -5,7 +5,9 @@ import {
5
5
  type Hex,
6
6
  encodeAbiParameters,
7
7
  isHex,
8
+ keccak256,
8
9
  pad,
10
+ size,
9
11
  toFunctionSelector,
10
12
  toHex
11
13
  } from "viem"
@@ -99,6 +101,7 @@ export function getPermissionFromABI<
99
101
  // Generate permission from the target function
100
102
  const functionSelector = toFunctionSelector(targetFunction)
101
103
  let paramRules: ParamRule[] = []
104
+
102
105
  if (args && Array.isArray(args)) {
103
106
  paramRules = (args as CombinedArgs<AbiFunction["inputs"]>)
104
107
  .map((arg, i) => {
@@ -132,6 +135,41 @@ export function getPermissionFromABI<
132
135
  { size: 32 }
133
136
  )
134
137
  )
138
+ } else if (arg.condition === ParamCondition.SLICE_EQUAL) {
139
+ if (!("start" in arg) || !("length" in arg)) {
140
+ throw new Error(
141
+ "start and length are required for SLICE_EQUAL condition"
142
+ )
143
+ }
144
+ const functionArgsType = targetFunction.inputs[i].type
145
+ const { start, length, value } = arg
146
+
147
+ let hexValue: Hex
148
+
149
+ // functionArgsType can be "string" or "bytes"
150
+ if (functionArgsType === "string") {
151
+ hexValue = toHex(value as Parameters<typeof toHex>[0])
152
+ } else if (functionArgsType === "bytes") {
153
+ hexValue = isHex(value, { strict: true })
154
+ ? value
155
+ : toHex(value as Parameters<typeof toHex>[0])
156
+ } else {
157
+ throw new Error(
158
+ `Unsupported function argument type: ${functionArgsType} could be "string" or "bytes"`
159
+ )
160
+ }
161
+
162
+ if (size(hexValue) !== length) {
163
+ throw new Error(
164
+ "Value length is not equal to the given length"
165
+ )
166
+ }
167
+
168
+ params = [
169
+ toHex(start, { size: 32 }),
170
+ toHex(length, { size: 32 }),
171
+ keccak256(hexValue)
172
+ ]
135
173
  } else {
136
174
  params = [
137
175
  pad(
@@ -144,6 +182,7 @@ export function getPermissionFromABI<
144
182
  )
145
183
  ]
146
184
  }
185
+
147
186
  return {
148
187
  params,
149
188
  offset: i * 32,
@@ -1,10 +1,11 @@
1
- import type { Abi, Address, Hex } from "viem"
1
+ import type { Abi, Address, Hex, Narrow } from "viem"
2
2
  import { concatHex, pad } from "viem"
3
3
  import {
4
4
  CALL_POLICY_CONTRACT_V0_0_1,
5
5
  CALL_POLICY_CONTRACT_V0_0_2,
6
6
  CALL_POLICY_CONTRACT_V0_0_3,
7
7
  CALL_POLICY_CONTRACT_V0_0_4,
8
+ CALL_POLICY_CONTRACT_V0_0_5,
8
9
  PolicyFlags
9
10
  } from "../constants.js"
10
11
  import type { Policy, PolicyParams } from "../types.js"
@@ -12,13 +13,14 @@ import {
12
13
  encodePermissionData,
13
14
  getPermissionFromABI
14
15
  } from "./callPolicyUtils.js"
15
- import { CallType, type Permission } from "./types.js"
16
+ import { CallType, type InferPermissions, type Permission } from "./types.js"
16
17
 
17
18
  export enum CallPolicyVersion {
18
19
  V0_0_1 = "0.0.1",
19
20
  V0_0_2 = "0.0.2",
20
21
  V0_0_3 = "0.0.3",
21
- V0_0_4 = "0.0.4"
22
+ V0_0_4 = "0.0.4",
23
+ V0_0_5 = "0.0.5"
22
24
  }
23
25
 
24
26
  export const getCallPolicyAddress = (
@@ -35,35 +37,38 @@ export const getCallPolicyAddress = (
35
37
  return CALL_POLICY_CONTRACT_V0_0_3
36
38
  case CallPolicyVersion.V0_0_4:
37
39
  return CALL_POLICY_CONTRACT_V0_0_4
40
+ case CallPolicyVersion.V0_0_5:
41
+ return CALL_POLICY_CONTRACT_V0_0_5
38
42
  }
39
43
  }
40
44
 
41
45
  export type CallPolicyParams<
42
- TAbi extends Abi | readonly unknown[],
43
- TFunctionName extends string | undefined = string
46
+ permissions extends readonly Permission<
47
+ Abi,
48
+ string
49
+ >[] = readonly Permission<Abi, string>[]
44
50
  > = PolicyParams & {
45
51
  policyVersion: CallPolicyVersion
46
- permissions?: Permission<TAbi, TFunctionName>[]
52
+ permissions?: InferPermissions<Narrow<permissions>>
47
53
  }
48
54
 
49
55
  export function toCallPolicy<
50
- TAbi extends Abi | readonly unknown[],
51
- TFunctionName extends string | undefined = string
56
+ const permissions extends readonly Permission<Abi, string>[]
52
57
  >({
53
58
  policyAddress,
54
59
  policyFlag = PolicyFlags.FOR_ALL_VALIDATION,
55
60
  policyVersion,
56
- permissions = []
57
- }: CallPolicyParams<TAbi, TFunctionName>): Policy {
61
+ permissions: inputPermissions
62
+ }: CallPolicyParams<permissions>): Policy {
58
63
  const callPolicyAddress = getCallPolicyAddress(policyVersion, policyAddress)
59
64
 
60
- const generatedPermissionParams = permissions?.map((perm) => {
65
+ const generatedPermissionParams = inputPermissions?.map((perm) => {
61
66
  // Natural discrimination: if abi and functionName are present, do ABI-based validation
62
67
  if (perm.abi && perm.functionName) {
63
68
  return getPermissionFromABI({
64
69
  abi: perm.abi as Abi,
65
70
  functionName: perm.functionName as string,
66
- args: perm.args as [],
71
+ args: perm.args,
67
72
  policyAddress: callPolicyAddress,
68
73
  selector: perm.selector
69
74
  })
@@ -76,8 +81,8 @@ export function toCallPolicy<
76
81
  }
77
82
  })
78
83
 
79
- permissions =
80
- permissions?.map((perm, index) => ({
84
+ const processedPermissions =
85
+ inputPermissions?.map((perm, index) => ({
81
86
  ...perm,
82
87
  callType: perm.callType ?? CallType.CALL,
83
88
  selector:
@@ -92,7 +97,7 @@ export function toCallPolicy<
92
97
  })) ?? []
93
98
 
94
99
  const encodedPermissionData = encodePermissionData(
95
- permissions,
100
+ processedPermissions,
96
101
  callPolicyAddress
97
102
  )
98
103
 
@@ -108,8 +113,8 @@ export function toCallPolicy<
108
113
  policyVersion,
109
114
  policyAddress,
110
115
  policyFlag,
111
- permissions
112
- } as unknown as CallPolicyParams<Abi | readonly unknown[], string> & {
116
+ permissions: processedPermissions
117
+ } as unknown as CallPolicyParams<permissions> & {
113
118
  type: "call"
114
119
  }
115
120
  }
package/policies/types.ts CHANGED
@@ -7,8 +7,10 @@ import type {
7
7
  AbiParameterToPrimitiveType,
8
8
  AbiStateMutability,
9
9
  Address,
10
+ ContractFunctionName,
10
11
  Hex,
11
- Narrow
12
+ Narrow,
13
+ Prettify
12
14
  } from "viem"
13
15
 
14
16
  export enum CallType {
@@ -24,7 +26,8 @@ export enum ParamCondition {
24
26
  GREATER_THAN_OR_EQUAL = 3,
25
27
  LESS_THAN_OR_EQUAL = 4,
26
28
  NOT_EQUAL = 5,
27
- ONE_OF = 6
29
+ ONE_OF = 6,
30
+ SLICE_EQUAL = 7
28
31
  }
29
32
 
30
33
  export interface ParamRule {
@@ -113,6 +116,12 @@ type ConditionValue<
113
116
  condition: ParamCondition.ONE_OF
114
117
  value: AbiParameterToPrimitiveType<TAbiParameter, TAbiParameterKind>[]
115
118
  }
119
+ | {
120
+ condition: ParamCondition.SLICE_EQUAL
121
+ value: AbiParameterToPrimitiveType<TAbiParameter, TAbiParameterKind>
122
+ start: number
123
+ length: number
124
+ }
116
125
  | {
117
126
  condition: Exclude<ParamCondition, ParamCondition.ONE_OF>
118
127
  value: AbiParameterToPrimitiveType<TAbiParameter, TAbiParameterKind>
@@ -149,3 +158,43 @@ export type GeneratePermissionFromArgsParameters<
149
158
  : _FunctionName extends string
150
159
  ? { abi: [Narrow<TAbi[number]>] } & GetFunctionArgs<TAbi, _FunctionName>
151
160
  : never)
161
+
162
+ // infer permission parameters from `unknown` - similar to GetMulticallContractParameters
163
+ export type GetPermissionParameters<permission> = permission extends {
164
+ abi: infer abi extends Abi
165
+ } // 1. Check if `abi` is const-asserted or defined inline
166
+ ? // 1a. Check if `functionName` is valid for `abi`
167
+ permission extends {
168
+ functionName: infer functionName extends ContractFunctionName<abi>
169
+ }
170
+ ? // Use PermissionWithABI which supports CombinedArgs
171
+ PermissionWithABI<abi, functionName>
172
+ : // 1b. `functionName` is invalid, check if `abi` is declared as `Abi`
173
+ Abi extends abi
174
+ ? PermissionWithABI<abi, string> // `abi` declared as `Abi`, unable to infer types further
175
+ : // `abi` is const-asserted or defined inline, infer types for `functionName` and `args`
176
+ PermissionWithABI<abi, string>
177
+ : permission extends { target: Address } // manual permission
178
+ ? PermissionManual
179
+ : never // invalid permission
180
+
181
+ // Process permissions array - similar to MulticallContracts
182
+ export type InferPermissions<
183
+ permissions extends readonly unknown[],
184
+ result extends readonly unknown[] = []
185
+ > = permissions extends readonly [] // no permissions, return empty
186
+ ? readonly []
187
+ : permissions extends readonly [infer permission] // one permission left before returning `result`
188
+ ? readonly [...result, Prettify<GetPermissionParameters<permission>>]
189
+ : permissions extends readonly [infer permission, ...infer rest] // grab first permission and recurse through `rest`
190
+ ? InferPermissions<
191
+ [...rest],
192
+ [...result, Prettify<GetPermissionParameters<permission>>]
193
+ >
194
+ : readonly unknown[] extends permissions
195
+ ? permissions
196
+ : // If `permissions` is *some* array but we couldn't assign `unknown[]` to it, then it must hold some known/homogenous type!
197
+ permissions extends readonly (infer permission)[]
198
+ ? readonly Prettify<GetPermissionParameters<permission>>[]
199
+ : // Fallback
200
+ readonly Permission<Abi, string>[]
@@ -19,6 +19,8 @@ import {
19
19
  export type MultiChainPermissionAccountsParams = {
20
20
  account: SmartAccount<KernelSmartAccountImplementation>
21
21
  privateKey?: Hex
22
+ permissionPlugin?: PermissionPlugin
23
+ isExternalPermissionPlugin?: boolean
22
24
  }
23
25
 
24
26
  export const serializeMultiChainPermissionAccounts = async (
@@ -26,13 +28,21 @@ export const serializeMultiChainPermissionAccounts = async (
26
28
  ): Promise<string[]> => {
27
29
  if (params.length === 0) return []
28
30
 
31
+ let isPreInstalled = false
29
32
  const permissionParamsPerAccounts = params.map((param) => {
30
- if (!isPermissionValidatorPlugin(param.account.kernelPluginManager)) {
33
+ if (
34
+ isPermissionValidatorPlugin(param.account.kernelPluginManager) &&
35
+ !param.isExternalPermissionPlugin
36
+ ) {
37
+ return (
38
+ param.account.kernelPluginManager as PermissionPlugin
39
+ ).getPluginSerializationParams()
40
+ } else if (param.permissionPlugin) {
41
+ isPreInstalled = !param.isExternalPermissionPlugin
42
+ return param.permissionPlugin.getPluginSerializationParams()
43
+ } else {
31
44
  throw new Error("Account plugin is not a permission validator")
32
45
  }
33
- return (
34
- param.account.kernelPluginManager as PermissionPlugin
35
- ).getPluginSerializationParams()
36
46
  })
37
47
 
38
48
  const actions = params.map((param) =>
@@ -43,23 +53,30 @@ export const serializeMultiChainPermissionAccounts = async (
43
53
  param.account.kernelPluginManager.getValidityData()
44
54
  )
45
55
 
46
- const pluginEnableTypedDatas = await Promise.all(
47
- params.map(async (param) => {
48
- return param.account.kernelPluginManager.getPluginsEnableTypedData(
49
- param.account.address
50
- )
51
- })
52
- )
53
-
54
- // build merkle tree for enable signatures
55
- const leaves = pluginEnableTypedDatas.map((typedData) => {
56
- return hashTypedData(typedData)
57
- })
56
+ let leaves: Hex[] = []
57
+ let merkleTree: MerkleTree = new MerkleTree(leaves)
58
+
59
+ if (!isPreInstalled) {
60
+ const pluginEnableTypedDatas = await Promise.all(
61
+ params.map(async (param) => {
62
+ return param.account.kernelPluginManager.getPluginsEnableTypedData(
63
+ param.account.address,
64
+ param.isExternalPermissionPlugin
65
+ ? param.permissionPlugin
66
+ : undefined // override permission plugin if externalPlugin
67
+ )
68
+ })
69
+ )
58
70
 
59
- const merkleTree = new MerkleTree(leaves, keccak256, {
60
- sortPairs: true
61
- })
71
+ // build merkle tree for enable signatures
72
+ leaves = pluginEnableTypedDatas.map((typedData) => {
73
+ return hashTypedData(typedData)
74
+ })
62
75
 
76
+ merkleTree = new MerkleTree(leaves, keccak256, {
77
+ sortPairs: true
78
+ })
79
+ }
63
80
  const merkleRoot = merkleTree.getHexRoot() as Hex
64
81
 
65
82
  const toEthSignedMessageHash = hashMessage({ raw: merkleRoot })
@@ -67,7 +84,8 @@ export const serializeMultiChainPermissionAccounts = async (
67
84
  let signature: Hex = "0x"
68
85
  if (
69
86
  params[0].account.kernelPluginManager.sudoValidator?.source ===
70
- "MultiChainECDSAValidator"
87
+ "MultiChainECDSAValidator" &&
88
+ !isPreInstalled
71
89
  ) {
72
90
  signature =
73
91
  await params[0].account.kernelPluginManager.sudoValidator?.signMessage(
@@ -80,7 +98,8 @@ export const serializeMultiChainPermissionAccounts = async (
80
98
  }
81
99
  if (
82
100
  params[0].account.kernelPluginManager.sudoValidator?.source ===
83
- "MultiChainWebAuthnValidator"
101
+ "MultiChainWebAuthnValidator" &&
102
+ !isPreInstalled
84
103
  ) {
85
104
  const encodedSignature =
86
105
  await params[0].account.kernelPluginManager.sudoValidator?.signMessage(
@@ -96,6 +115,8 @@ export const serializeMultiChainPermissionAccounts = async (
96
115
  // get enable signatures for multi-chain validator
97
116
  const enableSignatures = await Promise.all(
98
117
  params.map(async (param, index) => {
118
+ if (isPreInstalled) return undefined
119
+
99
120
  if (!param.account.kernelPluginManager.sudoValidator) {
100
121
  throw new Error(
101
122
  "No sudo validator found, check if sudo validator is multi-chain validator"
@@ -13,7 +13,8 @@ export const serializePermissionAccount = async (
13
13
  privateKey?: Hex,
14
14
  enableSignature?: Hex,
15
15
  eip7702Auth?: SignAuthorizationReturnType,
16
- permissionPlugin?: PermissionPlugin
16
+ permissionPlugin?: PermissionPlugin,
17
+ isExternalPermissionPlugin?: boolean
17
18
  ): Promise<string> => {
18
19
  let permissionParams: PermissionData
19
20
  let isPreInstalled = false
@@ -21,13 +22,16 @@ export const serializePermissionAccount = async (
21
22
  const validityData = account.kernelPluginManager.getValidityData()
22
23
 
23
24
  // Check if permission plugin is in kernelPluginManager
24
- if (isPermissionValidatorPlugin(account.kernelPluginManager)) {
25
+ if (
26
+ isPermissionValidatorPlugin(account.kernelPluginManager) &&
27
+ !isExternalPermissionPlugin
28
+ ) {
25
29
  permissionParams =
26
30
  account.kernelPluginManager.getPluginSerializationParams()
27
31
  } else if (permissionPlugin) {
28
32
  // Permission plugin provided externally (initConfig case)
29
33
  permissionParams = permissionPlugin.getPluginSerializationParams()
30
- isPreInstalled = true
34
+ isPreInstalled = !isExternalPermissionPlugin
31
35
  } else {
32
36
  throw new Error("No permission validator found in account or provided")
33
37
  }
@@ -36,7 +40,8 @@ export const serializePermissionAccount = async (
36
40
  ? undefined
37
41
  : (enableSignature ??
38
42
  (await account.kernelPluginManager.getPluginEnableSignature(
39
- account.address
43
+ account.address,
44
+ isExternalPermissionPlugin ? permissionPlugin : undefined // override permission plugin if externalPlugin
40
45
  )))
41
46
  const _eip7702Auth = account.authorization
42
47
  ? (eip7702Auth ?? (await account?.eip7702Authorization?.()))
package/types.ts CHANGED
@@ -5,7 +5,7 @@ import type {
5
5
  GetKernelVersion,
6
6
  PluginValidityData
7
7
  } from "@zerodev/sdk/types"
8
- import type { Abi, Address, Hex, LocalAccount } from "viem"
8
+ import type { Address, Hex, LocalAccount } from "viem"
9
9
  import type { EntryPointVersion } from "viem/account-abstraction"
10
10
  import type { SignAuthorizationReturnType } from "viem/accounts"
11
11
  import type { PolicyFlags } from "./constants.js"
@@ -42,7 +42,7 @@ export type Policy = {
42
42
  getPolicyInfoInBytes: () => Hex
43
43
  // return params directly to serialize/deserialize Policy
44
44
  policyParams:
45
- | (CallPolicyParams<Abi | readonly unknown[], string> & {
45
+ | (CallPolicyParams & {
46
46
  type: "call"
47
47
  })
48
48
  | (GasPolicyParams & { type: "gas" })