@zerodev/sdk 4.2.2 → 4.3.0

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 (65) hide show
  1. package/dist/cjs/kernel-zerodev/abis/SessionKeyValidatorAbi.d.ts +58 -4
  2. package/dist/cjs/kernel-zerodev/abis/SessionKeyValidatorAbi.js +75 -4
  3. package/dist/cjs/kernel-zerodev/abis/SessionKeyValidatorAbi.js.map +1 -1
  4. package/dist/cjs/kernel-zerodev/client/create-client.js +1 -0
  5. package/dist/cjs/kernel-zerodev/client/create-client.js.map +1 -1
  6. package/dist/cjs/kernel-zerodev/constants.d.ts +1 -1
  7. package/dist/cjs/kernel-zerodev/constants.js +2 -2
  8. package/dist/cjs/kernel-zerodev/constants.js.map +1 -1
  9. package/dist/cjs/kernel-zerodev/middleware/gas-estimator.d.ts +4 -0
  10. package/dist/cjs/kernel-zerodev/middleware/gas-estimator.js +15 -7
  11. package/dist/cjs/kernel-zerodev/middleware/gas-estimator.js.map +1 -1
  12. package/dist/cjs/kernel-zerodev/validator/base.d.ts +1 -1
  13. package/dist/cjs/kernel-zerodev/validator/base.js +3 -3
  14. package/dist/cjs/kernel-zerodev/validator/base.js.map +1 -1
  15. package/dist/cjs/kernel-zerodev/validator/session-key-validator.d.ts +18 -7
  16. package/dist/cjs/kernel-zerodev/validator/session-key-validator.js +117 -63
  17. package/dist/cjs/kernel-zerodev/validator/session-key-validator.js.map +1 -1
  18. package/dist/cjs/kernel-zerodev/validator/types.d.ts +1 -1
  19. package/dist/cjs/kernel-zerodev/validator/types.js.map +1 -1
  20. package/dist/cjs/kernel-zerodev/validator-provider/base.js +9 -0
  21. package/dist/cjs/kernel-zerodev/validator-provider/base.js.map +1 -1
  22. package/dist/esm/kernel-zerodev/abis/SessionKeyValidatorAbi.d.ts +58 -4
  23. package/dist/esm/kernel-zerodev/abis/SessionKeyValidatorAbi.js +75 -4
  24. package/dist/esm/kernel-zerodev/abis/SessionKeyValidatorAbi.js.map +1 -1
  25. package/dist/esm/kernel-zerodev/client/create-client.js +1 -0
  26. package/dist/esm/kernel-zerodev/client/create-client.js.map +1 -1
  27. package/dist/esm/kernel-zerodev/constants.d.ts +1 -1
  28. package/dist/esm/kernel-zerodev/constants.js +2 -2
  29. package/dist/esm/kernel-zerodev/constants.js.map +1 -1
  30. package/dist/esm/kernel-zerodev/middleware/gas-estimator.d.ts +4 -0
  31. package/dist/esm/kernel-zerodev/middleware/gas-estimator.js +15 -6
  32. package/dist/esm/kernel-zerodev/middleware/gas-estimator.js.map +1 -1
  33. package/dist/esm/kernel-zerodev/validator/base.d.ts +1 -1
  34. package/dist/esm/kernel-zerodev/validator/base.js +3 -3
  35. package/dist/esm/kernel-zerodev/validator/base.js.map +1 -1
  36. package/dist/esm/kernel-zerodev/validator/session-key-validator.d.ts +18 -7
  37. package/dist/esm/kernel-zerodev/validator/session-key-validator.js +118 -64
  38. package/dist/esm/kernel-zerodev/validator/session-key-validator.js.map +1 -1
  39. package/dist/esm/kernel-zerodev/validator/types.d.ts +1 -1
  40. package/dist/esm/kernel-zerodev/validator/types.js.map +1 -1
  41. package/dist/esm/kernel-zerodev/validator-provider/base.js +9 -0
  42. package/dist/esm/kernel-zerodev/validator-provider/base.js.map +1 -1
  43. package/dist/types/kernel-zerodev/abis/SessionKeyValidatorAbi.d.ts +58 -4
  44. package/dist/types/kernel-zerodev/abis/SessionKeyValidatorAbi.d.ts.map +1 -1
  45. package/dist/types/kernel-zerodev/client/create-client.d.ts.map +1 -1
  46. package/dist/types/kernel-zerodev/constants.d.ts +1 -1
  47. package/dist/types/kernel-zerodev/middleware/gas-estimator.d.ts +4 -0
  48. package/dist/types/kernel-zerodev/middleware/gas-estimator.d.ts.map +1 -1
  49. package/dist/types/kernel-zerodev/validator/base.d.ts +1 -1
  50. package/dist/types/kernel-zerodev/validator/base.d.ts.map +1 -1
  51. package/dist/types/kernel-zerodev/validator/session-key-validator.d.ts +18 -7
  52. package/dist/types/kernel-zerodev/validator/session-key-validator.d.ts.map +1 -1
  53. package/dist/types/kernel-zerodev/validator/types.d.ts +1 -1
  54. package/dist/types/kernel-zerodev/validator/types.d.ts.map +1 -1
  55. package/dist/types/kernel-zerodev/validator-provider/base.d.ts.map +1 -1
  56. package/package.json +5 -4
  57. package/src/kernel-zerodev/__tests__/config/index.ts +18 -0
  58. package/src/kernel-zerodev/abis/SessionKeyValidatorAbi.ts +75 -4
  59. package/src/kernel-zerodev/client/create-client.ts +1 -0
  60. package/src/kernel-zerodev/constants.ts +2 -2
  61. package/src/kernel-zerodev/middleware/gas-estimator.ts +21 -7
  62. package/src/kernel-zerodev/validator/base.ts +4 -4
  63. package/src/kernel-zerodev/validator/session-key-validator.ts +159 -88
  64. package/src/kernel-zerodev/validator/types.ts +1 -1
  65. package/src/kernel-zerodev/validator-provider/base.ts +13 -0
@@ -1,4 +1,9 @@
1
1
  export const SessionKeyValidatorAbi = [
2
+ {
3
+ inputs: [],
4
+ name: "NotImplemented",
5
+ type: "error",
6
+ },
2
7
  {
3
8
  inputs: [
4
9
  {
@@ -25,6 +30,72 @@ export const SessionKeyValidatorAbi = [
25
30
  stateMutability: "payable",
26
31
  type: "function",
27
32
  },
33
+ {
34
+ inputs: [
35
+ {
36
+ internalType: "bytes32",
37
+ name: "permissionKey",
38
+ type: "bytes32",
39
+ },
40
+ {
41
+ internalType: "address",
42
+ name: "kernel",
43
+ type: "address",
44
+ },
45
+ ],
46
+ name: "executionStatus",
47
+ outputs: [
48
+ {
49
+ internalType: "ValidAfter",
50
+ name: "validAfter",
51
+ type: "uint48",
52
+ },
53
+ {
54
+ internalType: "uint48",
55
+ name: "runs",
56
+ type: "uint48",
57
+ },
58
+ ],
59
+ stateMutability: "view",
60
+ type: "function",
61
+ },
62
+ {
63
+ inputs: [
64
+ {
65
+ internalType: "uint128",
66
+ name: "nonce",
67
+ type: "uint128",
68
+ },
69
+ ],
70
+ name: "invalidateNonce",
71
+ outputs: [],
72
+ stateMutability: "nonpayable",
73
+ type: "function",
74
+ },
75
+ {
76
+ inputs: [
77
+ {
78
+ internalType: "address",
79
+ name: "kernel",
80
+ type: "address",
81
+ },
82
+ ],
83
+ name: "nonces",
84
+ outputs: [
85
+ {
86
+ internalType: "uint128",
87
+ name: "lastNonce",
88
+ type: "uint128",
89
+ },
90
+ {
91
+ internalType: "uint128",
92
+ name: "invalidNonce",
93
+ type: "uint128",
94
+ },
95
+ ],
96
+ stateMutability: "view",
97
+ type: "function",
98
+ },
28
99
  {
29
100
  inputs: [
30
101
  {
@@ -61,9 +132,9 @@ export const SessionKeyValidatorAbi = [
61
132
  type: "address",
62
133
  },
63
134
  {
64
- internalType: "bool",
65
- name: "enabled",
66
- type: "bool",
135
+ internalType: "uint256",
136
+ name: "nonce",
137
+ type: "uint256",
67
138
  },
68
139
  ],
69
140
  stateMutability: "view",
@@ -183,7 +254,7 @@ export const SessionKeyValidatorAbi = [
183
254
  },
184
255
  {
185
256
  internalType: "bytes32",
186
- name: "userOpHash",
257
+ name: "",
187
258
  type: "bytes32",
188
259
  },
189
260
  {
@@ -29,6 +29,7 @@ function isMethodInErc4337RpcSchema(
29
29
  "eth_supportedEntryPoints",
30
30
  "eth_maxPriorityFeePerGas",
31
31
  "rundler_maxPriorityFeePerGas",
32
+ "pimlico_getUserOperationGasPrice",
32
33
  ] as const
33
34
  ).includes(variable as MethodsOfErc4337RpcSchema);
34
35
  }
@@ -26,7 +26,7 @@ export const ERC165_SESSION_KEY_VALIDATOR_ADDRESS =
26
26
  "0xe149290800De29D4b0BF9dB82c508255D81902E6";
27
27
  export const TOKEN_ACTION = "0x2087C7FfD0d0DAE80a00EE74325aBF3449e0eaf1";
28
28
  export const SESSION_KEY_VALIDATOR_ADDRESS =
29
- "0x1C1D5b70aD6e0c04366aab100261A6Bcc251EA3f";
29
+ "0xB8E3c4bEaACAd06f6092793012DA4a8cB23D6123";
30
30
  export const RECOVERY_VALIDATOR_ADDRESS =
31
31
  "0x4fd47D861c349bD49DC61341a922cb72F9dF7E8d";
32
32
  export const RECOVERY_ACTION = "0x2f65dB8039fe5CAEE0a8680D2879deB800F31Ae1";
@@ -102,6 +102,6 @@ export const CHAIN_ID_TO_NODE: { [key: number]: string } = {
102
102
  10200: "https://nd-810-853-201.p2pify.com/e828b09f0d43591de96c297b3f36fffd",
103
103
  59144: `https://linea-mainnet.infura.io/v3/${INFURA_API_KEY}`,
104
104
  59140: `https://linea-goerli.infura.io/v3/${INFURA_API_KEY}`,
105
- 204: 'https://opbnb.rpc.thirdweb.com/eed98c1f30120c0508f17c1f01d3102b',
105
+ 204: "https://opbnb.rpc.thirdweb.com/eed98c1f30120c0508f17c1f01d3102b",
106
106
  // 5611: 'opBnb-testnet',
107
107
  };
@@ -9,6 +9,7 @@ import {
9
9
  } from "@alchemy/aa-core";
10
10
  import { ENTRYPOINT_ADDRESS } from "../constants.js";
11
11
  import { calcPreVerificationGas } from "../utils/calc-pre-verification-gas.js";
12
+ import { type PaymasterAndBundlerProviders } from "../paymaster/types.js";
12
13
 
13
14
  export const withZeroDevGasEstimator = (
14
15
  provider: ZeroDevProvider
@@ -121,17 +122,30 @@ export const getPreVerificationGas = async (
121
122
  return calcPreVerificationGas(p);
122
123
  };
123
124
 
125
+ export const GAS_PRICE_RPC_METHODS_BY_BUNDLER: {
126
+ [K in PaymasterAndBundlerProviders]: string;
127
+ } = {
128
+ STACKUP: "eth_maxPriorityFeePerGas",
129
+ ALCHEMY: "rundler_maxPriorityFeePerGas",
130
+ PIMLICO: "pimlico_getUserOperationGasPrice",
131
+ };
132
+
124
133
  export const eip1559GasPrice = async (provider: ZeroDevProvider) => {
125
- const [fee, block] = await Promise.all([
126
- provider.bundlerProvider === "ALCHEMY"
127
- ? (provider.rpcClient.request({
128
- // @ts-expect-error
129
- method: "rundler_maxPriorityFeePerGas",
130
- }) as Promise<Hex>)
131
- : provider.rpcClient.getMaxPriorityFeePerGas(),
134
+ let [fee, block] = await Promise.all([
135
+ provider.rpcClient.request({
136
+ method:
137
+ // @ts-expect-error
138
+ GAS_PRICE_RPC_METHODS_BY_BUNDLER[provider.bundlerProvider] ??
139
+ "eth_maxPriorityFeePerGas",
140
+ params: [],
141
+ }) as any,
132
142
  provider.rpcClient.getBlock({ blockTag: "latest" }),
133
143
  ]);
134
144
 
145
+ if (provider.bundlerProvider === "PIMLICO") {
146
+ fee = fee.standard.maxPriorityFeePerGas;
147
+ }
148
+
135
149
  const tip = BigInt(fee);
136
150
  const buffer = (tip / 100n) * 13n;
137
151
  let maxPriorityFeePerGas = tip + buffer;
@@ -93,7 +93,7 @@ export abstract class KernelBaseValidator {
93
93
 
94
94
  abstract encodeDisable(enableData: Hex): Hex;
95
95
 
96
- abstract getEnableData(): Promise<Hex>;
96
+ abstract getEnableData(kernelAccountAddress?: Address): Promise<Hex>;
97
97
 
98
98
  abstract signMessage(message: Uint8Array | string | Hex): Promise<Hex>;
99
99
 
@@ -141,7 +141,7 @@ export abstract class KernelBaseValidator {
141
141
  calldata
142
142
  );
143
143
  if (validatorMode === ValidatorMode.enable) {
144
- const enableData = await this.getEnableData();
144
+ const enableData = await this.getEnableData(kernelAccountAddress);
145
145
  const enableDataLength = enableData.length / 2 - 1;
146
146
  const enableSigLength = 65;
147
147
  const staticDummySig = concatHex([
@@ -241,7 +241,7 @@ export abstract class KernelBaseValidator {
241
241
  { size: 32 }
242
242
  ),
243
243
  executor: executor as Address,
244
- enableData: await validator.getEnableData(),
244
+ enableData: await validator.getEnableData(kernel),
245
245
  },
246
246
  primaryType: "ValidatorApproved",
247
247
  });
@@ -297,7 +297,7 @@ export abstract class KernelBaseValidator {
297
297
  if (mode === ValidatorMode.sudo || mode === ValidatorMode.plugin) {
298
298
  return concatHex([this.mode, await this.signUserOp(userOp)]);
299
299
  } else {
300
- const enableData = await this.getEnableData();
300
+ const enableData = await this.getEnableData(userOp.sender);
301
301
  const enableDataLength = enableData.length / 2 - 1;
302
302
  const enableSignature = this.getEnableSignature();
303
303
  if (!enableSignature) {
@@ -20,7 +20,6 @@ import {
20
20
  concat,
21
21
  pad,
22
22
  toHex,
23
- keccak256,
24
23
  encodeAbiParameters,
25
24
  concatHex,
26
25
  zeroAddress,
@@ -28,13 +27,13 @@ import {
28
27
  isHex,
29
28
  getFunctionSelector,
30
29
  type GetAbiItemParameters,
30
+ keccak256,
31
31
  } from "viem";
32
32
  import { formatAbiItem } from "viem/utils";
33
33
  import { SessionKeyValidatorAbi } from "../abis/SessionKeyValidatorAbi.js";
34
34
  import { DUMMY_ECDSA_SIG } from "../constants.js";
35
35
  import { KernelAccountAbi } from "../abis/KernelAccountAbi.js";
36
36
  import { MerkleTree } from "merkletreejs";
37
- import { Operation } from "../provider.js";
38
37
  import { getChainId } from "../api/index.js";
39
38
  import { fixSignedData } from "../utils.js";
40
39
  import type { GetAbiItemReturnType } from "viem/dist/types/utils/abi/getAbiItem.js";
@@ -75,6 +74,16 @@ export enum ParamOperator {
75
74
  NOT_EQUAL = 5,
76
75
  }
77
76
 
77
+ export type SessionNonces = {
78
+ lastNonce: bigint;
79
+ invalidNonce: bigint;
80
+ };
81
+
82
+ export type ExecutionRule = {
83
+ validAfter: number; // 48 bits
84
+ interval: number; // 48 bits
85
+ runs: number; // 48 bits
86
+ };
78
87
  export interface ParamRules {
79
88
  offset: number;
80
89
  condition: ParamOperator;
@@ -83,10 +92,11 @@ export interface ParamRules {
83
92
 
84
93
  export type Permission = {
85
94
  target: Address;
95
+ index?: number;
86
96
  rules?: ParamRules[];
87
97
  sig?: Hex;
88
98
  valueLimit?: bigint;
89
- operation?: Operation;
99
+ executionRule?: ExecutionRule;
90
100
  };
91
101
 
92
102
  export interface SessionKeyData {
@@ -141,7 +151,6 @@ export function getPermissionFromABI<
141
151
  target,
142
152
  args,
143
153
  functionName,
144
- operation,
145
154
  valueLimit,
146
155
  }: GeneratePermissionFromArgsParameters<TAbi, TFunctionName>): Permission {
147
156
  const abiItem = getAbiItem({
@@ -175,7 +184,6 @@ export function getPermissionFromABI<
175
184
  sig: functionSelector,
176
185
  rules: paramRules,
177
186
  target,
178
- operation: operation ?? Operation.Call,
179
187
  valueLimit: valueLimit ?? 0n,
180
188
  };
181
189
  }
@@ -195,18 +203,20 @@ export class SessionKeyValidator extends KernelBaseValidator {
195
203
  paymaster: params.sessionKeyData.paymaster ?? zeroAddress,
196
204
  };
197
205
  this.sessionKeyData.permissions = this.sessionKeyData.permissions?.map(
198
- (perm) => ({
206
+ (perm, index) => ({
199
207
  ...perm,
200
- operation: perm.operation ?? Operation.Call,
201
208
  valueLimit: perm.valueLimit ?? 0n,
202
209
  sig: perm.sig ?? pad("0x", { size: 4 }),
203
210
  rules: perm.rules ?? [],
211
+ index,
212
+ executionRule: perm.executionRule ?? {
213
+ validAfter: 0,
214
+ interval: 0,
215
+ runs: 0,
216
+ },
204
217
  })
205
218
  );
206
219
  this.merkleTree = this.getMerkleTree();
207
- if (this.shouldDelegateViaFallback()) {
208
- throw Error("Session key permissions not set");
209
- }
210
220
  this.selector =
211
221
  params.selector ??
212
222
  getFunctionSelector("execute(address, uint256, bytes, uint8)");
@@ -230,19 +240,54 @@ export class SessionKeyValidator extends KernelBaseValidator {
230
240
  return this.merkleTree.getHexRoot() === pad("0x00", { size: 32 });
231
241
  }
232
242
 
233
- findMatchingPermission(callData: Hex): Permission | undefined {
243
+ findMatchingPermissions(
244
+ callData: Hex
245
+ ): Permission | Permission[] | undefined {
234
246
  try {
235
247
  const { functionName, args } = decodeFunctionData({
236
248
  abi: KernelAccountAbi,
237
249
  data: callData,
238
250
  });
239
251
 
240
- if (functionName !== "execute") return undefined;
252
+ if (functionName !== "execute" && functionName !== "executeBatch")
253
+ return undefined;
254
+ if (functionName === "execute") {
255
+ const [to, value, data] = args;
256
+ return this.filterPermissions([to], [data], [value])?.[0];
257
+ } else if (functionName === "executeBatch") {
258
+ let targets: Hex[] = [],
259
+ values: bigint[] = [],
260
+ dataArray: Hex[] = [];
261
+ args[0].forEach((arg) => {
262
+ targets.push(arg.to);
263
+ values.push(arg.value);
264
+ dataArray.push(arg.data);
265
+ });
266
+ return this.filterPermissions(targets, dataArray, values);
267
+ } else {
268
+ throw Error("Invalid function");
269
+ }
270
+ } catch (error) {
271
+ return undefined;
272
+ }
273
+ }
241
274
 
275
+ private filterPermissions(
276
+ targets: Address[],
277
+ dataArray: Hex[],
278
+ values: bigint[]
279
+ ): Permission[] | undefined {
280
+ if (
281
+ targets.length !== dataArray.length ||
282
+ targets.length !== values.length
283
+ ) {
284
+ throw Error("Invalid arguments");
285
+ }
286
+ const filteredPermissions = targets.map((target, index) => {
242
287
  const permissionsList = this.sessionKeyData.permissions;
243
288
  if (!permissionsList || !permissionsList.length) return undefined;
244
289
 
245
- const targetToMatch = args[0].toLowerCase();
290
+ const targetToMatch = target.toLowerCase();
246
291
 
247
292
  // Filter permissions by target
248
293
  let targetPermissions = permissionsList.filter(
@@ -259,20 +304,13 @@ export class SessionKeyValidator extends KernelBaseValidator {
259
304
 
260
305
  if (!targetPermissions.length) return undefined;
261
306
 
262
- const operationPermissions = this.filterByOperation(
263
- targetPermissions,
264
- args[3]
265
- );
266
-
267
- if (!operationPermissions.length) return undefined;
268
-
269
307
  const signaturePermissions = this.filterBySignature(
270
- operationPermissions,
271
- args[2].slice(0, 10).toLowerCase()
308
+ targetPermissions,
309
+ dataArray[index].slice(0, 10).toLowerCase()
272
310
  );
273
311
 
274
312
  const valueLimitPermissions = signaturePermissions.filter(
275
- (permission) => (permission.valueLimit ?? 0n) >= args[1]
313
+ (permission) => (permission.valueLimit ?? 0n) >= values[index]
276
314
  );
277
315
 
278
316
  if (!valueLimitPermissions.length) return undefined;
@@ -287,20 +325,11 @@ export class SessionKeyValidator extends KernelBaseValidator {
287
325
  }
288
326
  });
289
327
 
290
- return this.findPermissionByRule(sortedPermissions, args[2]);
291
- } catch (error) {
292
- return undefined;
293
- }
294
- }
295
-
296
- private filterByOperation(
297
- permissions: Permission[],
298
- operation: Operation
299
- ): Permission[] {
300
- return permissions.filter(
301
- (permission) =>
302
- permission.operation === operation || Operation.Call === operation
303
- );
328
+ return this.findPermissionByRule(sortedPermissions, dataArray[index]);
329
+ });
330
+ return filteredPermissions.every((permission) => permission !== undefined)
331
+ ? (filteredPermissions as Permission[])
332
+ : undefined;
304
333
  }
305
334
 
306
335
  private filterBySignature(
@@ -368,34 +397,43 @@ export class SessionKeyValidator extends KernelBaseValidator {
368
397
 
369
398
  // Having one leaf returns empty array in getProof(). To hack it we push the leaf twice
370
399
  // issue - https://github.com/merkletreejs/merkletreejs/issues/58
371
- if (permissionPacked?.length === 1)
400
+ if (permissionPacked && permissionPacked.length === 1)
372
401
  permissionPacked.push(permissionPacked[0]);
373
402
 
374
403
  return permissionPacked && permissionPacked.length !== 0
375
404
  ? new MerkleTree(permissionPacked, keccak256, {
376
- sortPairs: true,
377
405
  hashLeaves: true,
406
+ complete: true,
407
+ sort: true,
378
408
  })
379
409
  : new MerkleTree([pad("0x00", { size: 32 })], keccak256, {
380
410
  hashLeaves: false,
411
+ complete: true,
381
412
  });
382
413
  }
383
414
 
384
- encodePermissionData(permission: Permission, merkleProof?: string[]): Hex {
415
+ encodePermissionData(
416
+ permission: Permission | Permission[],
417
+ merkleProof?: string[] | string[][]
418
+ ): Hex {
385
419
  let permissionParam = {
386
420
  components: [
387
421
  {
388
- name: "target",
389
- type: "address",
422
+ name: "index",
423
+ type: "uint32",
390
424
  },
391
425
  {
392
- name: "valueLimit",
393
- type: "uint256",
426
+ name: "target",
427
+ type: "address",
394
428
  },
395
429
  {
396
430
  name: "sig",
397
431
  type: "bytes4",
398
432
  },
433
+ {
434
+ name: "valueLimit",
435
+ type: "uint256",
436
+ },
399
437
  {
400
438
  components: [
401
439
  {
@@ -416,13 +454,27 @@ export class SessionKeyValidator extends KernelBaseValidator {
416
454
  type: "tuple[]",
417
455
  },
418
456
  {
419
- internalType: "enum Operation",
420
- name: "operation",
421
- type: "uint8",
457
+ components: [
458
+ {
459
+ name: "interval",
460
+ type: "uint48",
461
+ },
462
+ {
463
+ name: "runs",
464
+ type: "uint48",
465
+ },
466
+ {
467
+ internalType: "ValidAfter",
468
+ name: "validAfter",
469
+ type: "uint48",
470
+ },
471
+ ],
472
+ name: "executionRule",
473
+ type: "tuple",
422
474
  },
423
475
  ],
424
476
  name: "permission",
425
- type: "tuple",
477
+ type: Array.isArray(permission) ? "tuple[]" : "tuple",
426
478
  };
427
479
  let params;
428
480
  let values;
@@ -431,7 +483,7 @@ export class SessionKeyValidator extends KernelBaseValidator {
431
483
  permissionParam,
432
484
  {
433
485
  name: "merkleProof",
434
- type: "bytes32[]",
486
+ type: Array.isArray(merkleProof[0]) ? "bytes32[][]" : "bytes32[]",
435
487
  },
436
488
  ];
437
489
  values = [permission, merkleProof];
@@ -460,16 +512,41 @@ export class SessionKeyValidator extends KernelBaseValidator {
460
512
  return await Promise.resolve(this.sessionKey);
461
513
  }
462
514
 
463
- async getEnableData(): Promise<Hex> {
515
+ async getSessionNonces(
516
+ kernelAccountAddress: Address
517
+ ): Promise<SessionNonces> {
518
+ if (!this.publicClient) {
519
+ throw new Error("Validator uninitialized: PublicClient missing");
520
+ }
521
+ const nonce = await this.publicClient.readContract({
522
+ abi: SessionKeyValidatorAbi,
523
+ address: this.validatorAddress,
524
+ functionName: "nonces",
525
+ args: [kernelAccountAddress],
526
+ });
527
+ return { lastNonce: nonce[0], invalidNonce: nonce[1] };
528
+ }
529
+
530
+ async getEnableData(
531
+ kernelAccountAddress?: Address,
532
+ enabledLastNonce?: bigint
533
+ ): Promise<Hex> {
464
534
  if (!this.merkleTree) {
465
535
  throw Error("SessionKeyValidator: MerkleTree not generated");
466
536
  }
537
+ if (!kernelAccountAddress) {
538
+ throw Error("SessionKeyValidator: Kernel account address not provided");
539
+ }
540
+ const lastNonce =
541
+ enabledLastNonce ??
542
+ (await this.getSessionNonces(kernelAccountAddress)).lastNonce + 1n;
467
543
  return concat([
468
544
  await this.sessionKey.getAddress(),
469
545
  pad(this.merkleTree.getHexRoot() as Hex, { size: 32 }),
470
546
  pad(toHex(this.sessionKeyData.validAfter), { size: 6 }),
471
547
  pad(toHex(this.sessionKeyData.validUntil), { size: 6 }),
472
548
  this.sessionKeyData.paymaster!,
549
+ pad(toHex(lastNonce), { size: 32 }),
473
550
  ]);
474
551
  }
475
552
 
@@ -494,21 +571,32 @@ export class SessionKeyValidator extends KernelBaseValidator {
494
571
  });
495
572
  const enableDataHex = concatHex([
496
573
  await this.sessionKey.getAddress(),
497
- pad(enableData[0], { size: 4 }),
574
+ pad(enableData[0], { size: 32 }),
498
575
  pad(toHex(enableData[1]), { size: 6 }),
499
576
  pad(toHex(enableData[2]), { size: 6 }),
500
577
  enableData[3],
578
+ pad(toHex(enableData[4]), { size: 32 }),
501
579
  ]);
502
580
  return (
503
581
  execDetail.validator.toLowerCase() ===
504
582
  this.validatorAddress.toLowerCase() &&
505
- enableData[4] &&
506
- enableDataHex.toLowerCase() === (await this.getEnableData()).toLowerCase()
583
+ enableDataHex.toLowerCase() ===
584
+ (
585
+ await this.getEnableData(kernelAccountAddress, enableData[4])
586
+ ).toLowerCase()
507
587
  );
508
588
  }
509
589
 
510
590
  async getDummyUserOpSignature(callData: Hex): Promise<Hex> {
511
- const matchingPermission = this.findMatchingPermission(callData);
591
+ return concatHex([
592
+ await this.sessionKey.getAddress(),
593
+ DUMMY_ECDSA_SIG,
594
+ this.getEncodedPermissionProofData(callData),
595
+ ]);
596
+ }
597
+
598
+ private getEncodedPermissionProofData(callData: Hex): Hex {
599
+ const matchingPermission = this.findMatchingPermissions(callData);
512
600
  if (!matchingPermission && !this.shouldDelegateViaFallback()) {
513
601
  throw Error(
514
602
  "SessionKeyValidator: No matching permission found for the userOp"
@@ -520,20 +608,24 @@ export class SessionKeyValidator extends KernelBaseValidator {
520
608
  matchingPermission
521
609
  ? this.encodePermissionData(matchingPermission)
522
610
  : "0x";
523
- const merkleProof = this.merkleTree.getHexProof(
524
- keccak256(encodedPermissionData)
525
- );
526
- const encodedData =
527
- this.sessionKeyData.permissions &&
611
+ let merkleProof: string[] | string[][] = [];
612
+ if (Array.isArray(matchingPermission)) {
613
+ let encodedPerms = matchingPermission.map((permission) =>
614
+ keccak256(this.encodePermissionData(permission))
615
+ );
616
+ merkleProof = encodedPerms.map((perm) =>
617
+ this.merkleTree.getHexProof(perm)
618
+ );
619
+ } else if (matchingPermission) {
620
+ merkleProof = this.merkleTree.getHexProof(
621
+ keccak256(encodedPermissionData)
622
+ );
623
+ }
624
+ return this.sessionKeyData.permissions &&
528
625
  this.sessionKeyData.permissions.length !== 0 &&
529
626
  matchingPermission
530
- ? this.encodePermissionData(matchingPermission, merkleProof)
531
- : "0x";
532
- return concatHex([
533
- await this.sessionKey.getAddress(),
534
- DUMMY_ECDSA_SIG,
535
- encodedData,
536
- ]);
627
+ ? this.encodePermissionData(matchingPermission, merkleProof)
628
+ : "0x";
537
629
  }
538
630
 
539
631
  encodeEnable(sessionKeyEnableData: Hex): Hex {
@@ -574,31 +666,10 @@ export class SessionKeyValidator extends KernelBaseValidator {
574
666
  );
575
667
  const formattedMessage = typeof hash === "string" ? toBytes(hash) : hash;
576
668
 
577
- const matchingPermission = this.findMatchingPermission(userOp.callData);
578
- if (!matchingPermission && !this.shouldDelegateViaFallback()) {
579
- throw Error(
580
- "SessionKeyValidator: No matching permission found for the userOp"
581
- );
582
- }
583
- const encodedPermissionData =
584
- this.sessionKeyData.permissions &&
585
- this.sessionKeyData.permissions.length !== 0 &&
586
- matchingPermission
587
- ? this.encodePermissionData(matchingPermission)
588
- : "0x";
589
- const merkleProof = this.merkleTree.getHexProof(
590
- keccak256(encodedPermissionData)
591
- );
592
- const encodedData =
593
- this.sessionKeyData.permissions &&
594
- this.sessionKeyData.permissions.length !== 0 &&
595
- matchingPermission
596
- ? this.encodePermissionData(matchingPermission, merkleProof)
597
- : "0x";
598
669
  const signature = concat([
599
670
  await this.sessionKey.getAddress(),
600
671
  await this.sessionKey.signMessage(formattedMessage),
601
- encodedData,
672
+ this.getEncodedPermissionProofData(userOp.callData),
602
673
  ]);
603
674
  return signature;
604
675
  }
@@ -120,7 +120,7 @@ export type GeneratePermissionFromArgsParameters<
120
120
  _FunctionName = TAbi extends Abi
121
121
  ? InferFunctionName<TAbi, TFunctionName>
122
122
  : never
123
- > = Pick<Permission, "operation" | "target" | "valueLimit"> & {
123
+ > = Pick<Permission, "target" | "valueLimit"> & {
124
124
  functionName?: _FunctionName;
125
125
  } & (TFunctionName extends string
126
126
  ? { abi: Narrow<TAbi> } & GetFunctionArgs<TAbi, TFunctionName>
@@ -75,6 +75,19 @@ export abstract class ValidatorProvider<
75
75
  bundlerProvider,
76
76
  });
77
77
  this.defaultProvider = params.defaultProvider;
78
+ if (
79
+ (typeof params.opts?.providerConfig?.chain === "number" &&
80
+ typeof params.defaultProvider?.chain === "number" &&
81
+ params.opts?.providerConfig?.chain !== params.defaultProvider?.chain) ||
82
+ (typeof params.opts?.providerConfig?.chain === "object" &&
83
+ typeof params.defaultProvider?.chain === "object" &&
84
+ params.opts?.providerConfig?.chain.id !==
85
+ params.defaultProvider?.chain.id)
86
+ ) {
87
+ throw new Error(
88
+ "chainId mismatch between default provider and current provider - check projectIds"
89
+ );
90
+ }
78
91
  this.connect(
79
92
  () =>
80
93
  new KernelSmartContractAccount({