@zerodev/sdk 5.4.9 → 5.4.11

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 (59) hide show
  1. package/_cjs/accounts/kernel/abi/kernel_v_3_0_0/KernelModuleAbi.js +38 -1
  2. package/_cjs/accounts/kernel/abi/kernel_v_3_0_0/KernelModuleAbi.js.map +1 -1
  3. package/_cjs/accounts/kernel/createKernelAccount.js +64 -1
  4. package/_cjs/accounts/kernel/createKernelAccount.js.map +1 -1
  5. package/_cjs/accounts/kernel/utils/plugins/ep0_7/getPluginInstallCallData.js +18 -0
  6. package/_cjs/accounts/kernel/utils/plugins/ep0_7/getPluginInstallCallData.js.map +1 -0
  7. package/_cjs/accounts/utils/toKernelPluginManager.js +1 -0
  8. package/_cjs/accounts/utils/toKernelPluginManager.js.map +1 -1
  9. package/_cjs/actions/public/index.js +3 -1
  10. package/_cjs/actions/public/index.js.map +1 -1
  11. package/_cjs/actions/public/isPluginInstalled.js +23 -0
  12. package/_cjs/actions/public/isPluginInstalled.js.map +1 -0
  13. package/_cjs/constants.js +10 -1
  14. package/_cjs/constants.js.map +1 -1
  15. package/_cjs/types/index.js.map +1 -1
  16. package/_cjs/types/kernel.js.map +1 -1
  17. package/_esm/accounts/kernel/abi/kernel_v_3_0_0/KernelModuleAbi.js +37 -0
  18. package/_esm/accounts/kernel/abi/kernel_v_3_0_0/KernelModuleAbi.js.map +1 -1
  19. package/_esm/accounts/kernel/createKernelAccount.js +76 -5
  20. package/_esm/accounts/kernel/createKernelAccount.js.map +1 -1
  21. package/_esm/accounts/kernel/utils/plugins/ep0_7/getPluginInstallCallData.js +14 -0
  22. package/_esm/accounts/kernel/utils/plugins/ep0_7/getPluginInstallCallData.js.map +1 -0
  23. package/_esm/accounts/utils/toKernelPluginManager.js +1 -0
  24. package/_esm/accounts/utils/toKernelPluginManager.js.map +1 -1
  25. package/_esm/actions/public/index.js +1 -0
  26. package/_esm/actions/public/index.js.map +1 -1
  27. package/_esm/actions/public/isPluginInstalled.js +44 -0
  28. package/_esm/actions/public/isPluginInstalled.js.map +1 -0
  29. package/_esm/constants.js +9 -0
  30. package/_esm/constants.js.map +1 -1
  31. package/_esm/types/index.js.map +1 -1
  32. package/_esm/types/kernel.js.map +1 -1
  33. package/_types/accounts/kernel/abi/kernel_v_3_0_0/KernelModuleAbi.d.ts +41 -0
  34. package/_types/accounts/kernel/abi/kernel_v_3_0_0/KernelModuleAbi.d.ts.map +1 -1
  35. package/_types/accounts/kernel/createKernelAccount.d.ts +6 -2
  36. package/_types/accounts/kernel/createKernelAccount.d.ts.map +1 -1
  37. package/_types/accounts/kernel/utils/plugins/ep0_7/getPluginInstallCallData.d.ts +5 -0
  38. package/_types/accounts/kernel/utils/plugins/ep0_7/getPluginInstallCallData.d.ts.map +1 -0
  39. package/_types/accounts/utils/toKernelPluginManager.d.ts.map +1 -1
  40. package/_types/actions/public/index.d.ts +1 -0
  41. package/_types/actions/public/index.d.ts.map +1 -1
  42. package/_types/actions/public/isPluginInstalled.d.ts +37 -0
  43. package/_types/actions/public/isPluginInstalled.d.ts.map +1 -0
  44. package/_types/constants.d.ts +9 -0
  45. package/_types/constants.d.ts.map +1 -1
  46. package/_types/types/index.d.ts +1 -1
  47. package/_types/types/index.d.ts.map +1 -1
  48. package/_types/types/kernel.d.ts +8 -1
  49. package/_types/types/kernel.d.ts.map +1 -1
  50. package/accounts/kernel/abi/kernel_v_3_0_0/KernelModuleAbi.ts +39 -0
  51. package/accounts/kernel/createKernelAccount.ts +123 -5
  52. package/accounts/kernel/utils/plugins/ep0_7/getPluginInstallCallData.ts +19 -0
  53. package/accounts/utils/toKernelPluginManager.ts +1 -0
  54. package/actions/public/index.ts +1 -0
  55. package/actions/public/isPluginInstalled.ts +62 -0
  56. package/constants.ts +12 -0
  57. package/package.json +1 -1
  58. package/types/index.ts +2 -1
  59. package/types/kernel.ts +10 -1
@@ -1,4 +1,5 @@
1
1
  import {
2
+ http,
2
3
  type Address,
3
4
  type Assign,
4
5
  type Client,
@@ -6,8 +7,10 @@ import {
6
7
  type Hex,
7
8
  type SignableMessage,
8
9
  type TypedDataDefinition,
10
+ concat,
9
11
  concatHex,
10
12
  createNonceManager,
13
+ createWalletClient,
11
14
  encodeFunctionData,
12
15
  getTypesForEIP712Domain,
13
16
  hashMessage,
@@ -26,11 +29,17 @@ import {
26
29
  entryPoint07Address,
27
30
  toSmartAccount
28
31
  } from "viem/account-abstraction"
29
- import { getChainId } from "viem/actions"
32
+ import {
33
+ type SignAuthorizationReturnType,
34
+ privateKeyToAccount
35
+ } from "viem/accounts"
36
+ import { getChainId, getCode, writeContract } from "viem/actions"
37
+ import { odysseyTestnet } from "viem/chains"
30
38
  import { getAction } from "viem/utils"
31
39
  import {
32
40
  getAccountNonce,
33
- getSenderAddress
41
+ getSenderAddress,
42
+ isPluginInstalled
34
43
  } from "../../actions/public/index.js"
35
44
  import {
36
45
  KernelVersionToAddressesMap,
@@ -42,7 +51,8 @@ import type {
42
51
  GetEntryPointAbi,
43
52
  GetKernelVersion,
44
53
  KernelPluginManager,
45
- KernelPluginManagerParams
54
+ KernelPluginManagerParams,
55
+ PluginMigrationData
46
56
  } from "../../types/kernel.js"
47
57
  import { KERNEL_FEATURES, hasKernelFeature } from "../../utils.js"
48
58
  import { validateKernelVersionWithEntryPoint } from "../../utils.js"
@@ -51,7 +61,10 @@ import {
51
61
  toKernelPluginManager
52
62
  } from "../utils/toKernelPluginManager.js"
53
63
  import { KernelInitAbi } from "./abi/KernelAccountAbi.js"
54
- import { KernelV3InitAbi } from "./abi/kernel_v_3_0_0/KernelAccountAbi.js"
64
+ import {
65
+ KernelV3AccountAbi,
66
+ KernelV3InitAbi
67
+ } from "./abi/kernel_v_3_0_0/KernelAccountAbi.js"
55
68
  import { KernelV3FactoryAbi } from "./abi/kernel_v_3_0_0/KernelFactoryAbi.js"
56
69
  import { KernelFactoryStakerAbi } from "./abi/kernel_v_3_0_0/KernelFactoryStakerAbi.js"
57
70
  import { KernelV3_1AccountAbi } from "./abi/kernel_v_3_1/KernelAccountAbi.js"
@@ -61,6 +74,7 @@ import { encodeCallData as encodeCallDataEpV07 } from "./utils/account/ep0_7/enc
61
74
  import { encodeDeployCallData as encodeDeployCallDataV07 } from "./utils/account/ep0_7/encodeDeployCallData.js"
62
75
  import { accountMetadata } from "./utils/common/accountMetadata.js"
63
76
  import { eip712WrapHash } from "./utils/common/eip712WrapHash.js"
77
+ import { getPluginInstallCallData } from "./utils/plugins/ep0_7/getPluginInstallCallData.js"
64
78
 
65
79
  type SignMessageParameters = {
66
80
  message: SignableMessage
@@ -91,6 +105,7 @@ export type KernelSmartAccountImplementation<
91
105
  bytecode
92
106
  }: EncodeDeployDataParameters) => Promise<Hex>
93
107
  signMessage: (parameters: SignMessageParameters) => Promise<Hex>
108
+ eip7702Auth?: SignAuthorizationReturnType
94
109
  }
95
110
  >
96
111
 
@@ -117,6 +132,8 @@ export type CreateKernelAccountParameters<
117
132
  kernelVersion: GetKernelVersion<entryPointVersion>
118
133
  initConfig?: KernelVerion extends "0.3.1" ? Hex[] : never
119
134
  useMetaFactory?: boolean
135
+ eip7702Auth?: SignAuthorizationReturnType
136
+ pluginMigrations?: PluginMigrationData[]
120
137
  }
121
138
 
122
139
  /**
@@ -329,6 +346,11 @@ const getDefaultAddresses = <entryPointVersion extends EntryPointVersion>(
329
346
  }
330
347
  }
331
348
 
349
+ type PluginInstallationCache = {
350
+ pendingPlugins: PluginMigrationData[]
351
+ allInstalled: boolean
352
+ }
353
+
332
354
  /**
333
355
  * Build a kernel smart account from a private key, that use the ECDSA signer behind the scene
334
356
  * @param client
@@ -355,7 +377,9 @@ export async function createKernelAccount<
355
377
  address,
356
378
  kernelVersion,
357
379
  initConfig,
358
- useMetaFactory = true
380
+ useMetaFactory = true,
381
+ eip7702Auth,
382
+ pluginMigrations
359
383
  }: CreateKernelAccountParameters<entryPointVersion, KernelVersion>
360
384
  ): Promise<CreateKernelAccountReturnType<entryPointVersion>> {
361
385
  const { accountImplementationAddress, factoryAddress, metaFactoryAddress } =
@@ -449,7 +473,82 @@ export async function createKernelAccount<
449
473
  version: entryPoint?.version ?? "0.7"
450
474
  } as const
451
475
 
476
+ if (eip7702Auth && client.chain && client.chain.id === odysseyTestnet.id) {
477
+ let code = await getCode(client, { address: accountAddress })
478
+ const isEip7702Authorized =
479
+ code?.length && code.length > 0 && code.startsWith("0xef")
480
+ console.log("Code before:", code)
481
+ console.log("Is Eip7702 Authorized:", isEip7702Authorized)
482
+ if (!isEip7702Authorized) {
483
+ const sponsorWalletClient = createWalletClient({
484
+ account: privateKeyToAccount(
485
+ // NOTE: Don't worry about this private key, it's just for testing
486
+ "0x688b84097239bc2bca41079d02fae599964a5844bc9e64f524206ad53a927bb9"
487
+ ),
488
+ chain: client.chain,
489
+ transport: http()
490
+ })
491
+ console.log("Authorizing eip7702 account...")
492
+ const txHash = await writeContract(sponsorWalletClient, {
493
+ address: accountAddress,
494
+ abi: KernelV3AccountAbi,
495
+ functionName: "initialize",
496
+ args: [
497
+ concat([
498
+ "0x01",
499
+ "0x845ADb2C711129d4f3966735eD98a9F09fC4cE57"
500
+ ]),
501
+ zeroAddress,
502
+ accountAddress,
503
+ "0x"
504
+ ],
505
+ authorizationList: [eip7702Auth]
506
+ })
507
+ console.log(
508
+ `Authorized eip7702 account: https://explorer-odyssey.t.conduit.xyz/tx/${txHash}`
509
+ )
510
+ code = await getCode(client, { address: accountAddress })
511
+ while (code?.length === undefined || code.length === 0) {
512
+ code = await getCode(client, { address: accountAddress })
513
+ }
514
+ console.log("Code after:", code)
515
+ }
516
+ }
517
+
518
+ // Cache for plugin installation status
519
+ const pluginCache: PluginInstallationCache = {
520
+ pendingPlugins: pluginMigrations || [],
521
+ allInstalled: false
522
+ }
523
+
524
+ const checkPluginInstallationStatus = async () => {
525
+ // Skip if no plugins or all are installed
526
+ if (!pluginCache.pendingPlugins.length || pluginCache.allInstalled) {
527
+ pluginCache.allInstalled = true
528
+ return
529
+ }
530
+
531
+ // Check all pending plugins in parallel
532
+ const installationResults = await Promise.all(
533
+ pluginCache.pendingPlugins.map((plugin) =>
534
+ isPluginInstalled(client, {
535
+ address: accountAddress,
536
+ plugin
537
+ })
538
+ )
539
+ )
540
+
541
+ // Filter out installed plugins
542
+ pluginCache.pendingPlugins = pluginCache.pendingPlugins.filter(
543
+ (_, index) => !installationResults[index]
544
+ )
545
+ pluginCache.allInstalled = pluginCache.pendingPlugins.length === 0
546
+ }
547
+
548
+ await checkPluginInstallationStatus()
549
+
452
550
  return toSmartAccount<KernelSmartAccountImplementation<entryPointVersion>>({
551
+ eip7702Auth,
453
552
  kernelVersion,
454
553
  kernelPluginManager,
455
554
  factoryAddress: (await getFactoryArgs()).factory,
@@ -487,6 +586,25 @@ export async function createKernelAccount<
487
586
  return encodeDeployCallDataV07(_tx)
488
587
  },
489
588
  async encodeCalls(calls, callType) {
589
+ // Check plugin status only if we have pending plugins
590
+ await checkPluginInstallationStatus()
591
+
592
+ // Add plugin installation calls if needed
593
+ if (
594
+ pluginCache.pendingPlugins.length > 0 &&
595
+ entryPoint.version === "0.7" &&
596
+ kernelPluginManager.activeValidatorMode === "sudo"
597
+ ) {
598
+ const pluginInstallCalls = pluginCache.pendingPlugins.map(
599
+ (plugin) => getPluginInstallCallData(accountAddress, plugin)
600
+ )
601
+ return encodeCallDataEpV07(
602
+ [...calls, ...pluginInstallCalls],
603
+ callType,
604
+ plugins.hook ? true : undefined
605
+ )
606
+ }
607
+
490
608
  if (
491
609
  calls.length === 1 &&
492
610
  (!callType || callType === "call") &&
@@ -0,0 +1,19 @@
1
+ import { type Address, encodeFunctionData } from "viem"
2
+ import type { PluginMigrationData } from "../../../../../types/kernel.js"
3
+ import { KernelModuleInstallAbi } from "../../../abi/kernel_v_3_0_0/KernelModuleAbi.js"
4
+ import type { CallArgs } from "../../types.js"
5
+
6
+ export const getPluginInstallCallData = (
7
+ accountAddress: Address,
8
+ plugin: PluginMigrationData
9
+ ): CallArgs => {
10
+ const data = encodeFunctionData({
11
+ abi: KernelModuleInstallAbi,
12
+ functionName: "installModule",
13
+ args: [plugin.type, plugin.address, plugin.data]
14
+ })
15
+ return {
16
+ to: accountAddress,
17
+ data
18
+ }
19
+ }
@@ -264,6 +264,7 @@ export async function toKernelPluginManager<
264
264
  return {
265
265
  sudoValidator: sudo,
266
266
  regularValidator: regular,
267
+ activeValidatorMode: sudo && !regular ? "sudo" : "regular",
267
268
  ...activeValidator,
268
269
  hook,
269
270
  getIdentifier,
@@ -9,3 +9,4 @@ export {
9
9
  } from "./getSenderAddress.js"
10
10
  export { isSmartAccountDeployed } from "./isSmartAccountDeployed.js"
11
11
  export { getKernelImplementationAddress } from "./getKernelImplementationAddress.js"
12
+ export { isPluginInstalled } from "./isPluginInstalled.js"
@@ -0,0 +1,62 @@
1
+ import type { Address, Client, Hex } from "viem"
2
+ import { readContract } from "viem/actions"
3
+ import { getAction } from "viem/utils"
4
+ import { KernelModuleIsModuleInstalledAbi } from "../../accounts/kernel/abi/kernel_v_3_0_0/KernelModuleAbi.js"
5
+ import type { PLUGIN_TYPE } from "../../constants.js"
6
+
7
+ export type IsPluginInstalledParams = {
8
+ address: Address
9
+ plugin: {
10
+ type: (typeof PLUGIN_TYPE)[keyof typeof PLUGIN_TYPE]
11
+ address: Address
12
+ data?: Hex
13
+ }
14
+ }
15
+
16
+ /**
17
+ * Returns whether a plugin is installed on the account.
18
+ *
19
+ * @param client - Client to use
20
+ * @param args - {@link IsPluginInstalledParams} address and plugin details
21
+ * @returns boolean indicating if plugin is installed
22
+ *
23
+ * @example
24
+ * import { createPublicClient } from "viem"
25
+ * import { isPluginInstalled } from "@zerodev/sdk"
26
+ *
27
+ * const client = createPublicClient({
28
+ * chain: mainnet,
29
+ * transport: http()
30
+ * })
31
+ *
32
+ * const isInstalled = await isPluginInstalled(client, {
33
+ * address: accountAddress,
34
+ * plugin: {
35
+ * type: PLUGIN_TYPE.VALIDATOR,
36
+ * address: validatorAddress,
37
+ * data: "0x"
38
+ * }
39
+ * })
40
+ */
41
+ export const isPluginInstalled = async (
42
+ client: Client,
43
+ args: IsPluginInstalledParams
44
+ ): Promise<boolean> => {
45
+ const { address, plugin } = args
46
+ const { type, address: pluginAddress, data = "0x" } = plugin
47
+
48
+ try {
49
+ return await getAction(
50
+ client,
51
+ readContract,
52
+ "readContract"
53
+ )({
54
+ address,
55
+ abi: KernelModuleIsModuleInstalledAbi,
56
+ functionName: "isModuleInstalled",
57
+ args: [BigInt(type), pluginAddress, data]
58
+ })
59
+ } catch (error) {
60
+ return false
61
+ }
62
+ }
package/constants.ts CHANGED
@@ -120,6 +120,15 @@ export enum EXEC_TYPE {
120
120
  TRY_EXEC = "0x01"
121
121
  }
122
122
 
123
+ export const PLUGIN_TYPE = {
124
+ VALIDATOR: 1,
125
+ EXECUTOR: 2,
126
+ FALLBACK: 3,
127
+ HOOK: 4,
128
+ POLICY: 5,
129
+ SIGNER: 6
130
+ }
131
+
123
132
  // Safe's library for create and create2: https://github.com/safe-global/safe-contracts/blob/0acdd35a203299585438f53885df630f9d486a86/contracts/libraries/CreateCall.sol
124
133
  // Address was found here: https://github.com/safe-global/safe-deployments/blob/926ec6bbe2ebcac3aa2c2c6c0aff74aa590cbc6a/src/assets/v1.4.1/create_call.json
125
134
  export const safeCreateCallAddress =
@@ -147,3 +156,6 @@ export const getEntryPoint = <TEntryPointVersion extends EntryPointVersion>(
147
156
  version: entryPointVersion
148
157
  }
149
158
  }
159
+
160
+ export const KERNEL_7702_DELEGATION_ADDRESS =
161
+ "0x94F097E1ebEB4ecA3AAE54cabb08905B239A7D27"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zerodev/sdk",
3
- "version": "5.4.9",
3
+ "version": "5.4.11",
4
4
  "author": "ZeroDev",
5
5
  "main": "./_cjs/index.js",
6
6
  "module": "./_esm/index.js",
package/types/index.ts CHANGED
@@ -14,7 +14,8 @@ export type {
14
14
  KERNEL_VERSION_TYPE,
15
15
  GetKernelVersion,
16
16
  GetEntryPointAbi,
17
- EntryPointType
17
+ EntryPointType,
18
+ PluginMigrationData
18
19
  } from "./kernel.js"
19
20
 
20
21
  export { ValidatorMode } from "./kernel.js"
package/types/kernel.ts CHANGED
@@ -5,7 +5,7 @@ import type {
5
5
  entryPoint06Abi,
6
6
  entryPoint07Abi
7
7
  } from "viem/account-abstraction"
8
- import type { VALIDATOR_TYPE } from "../constants.js"
8
+ import type { PLUGIN_TYPE, VALIDATOR_TYPE } from "../constants.js"
9
9
  export type ZeroDevPaymasterRpcSchema<
10
10
  entryPointVersion extends EntryPointVersion
11
11
  > = [
@@ -154,10 +154,13 @@ export type ValidatorInitData = {
154
154
  initConfig?: Hex[]
155
155
  }
156
156
 
157
+ export type ActiveValidatorMode = "sudo" | "regular"
158
+
157
159
  export type KernelPluginManager<entryPointVersion extends EntryPointVersion> =
158
160
  KernelValidator & {
159
161
  sudoValidator?: KernelValidator
160
162
  regularValidator?: KernelValidator
163
+ activeValidatorMode: ActiveValidatorMode
161
164
  hook?: KernelValidatorHook
162
165
  getPluginEnableSignature(accountAddress: Address): Promise<Hex>
163
166
  getValidatorInitData(): Promise<ValidatorInitData>
@@ -221,6 +224,12 @@ export enum ValidatorMode {
221
224
  enable = "0x00000002"
222
225
  }
223
226
 
227
+ export type PluginMigrationData = {
228
+ type: (typeof PLUGIN_TYPE)[keyof typeof PLUGIN_TYPE]
229
+ address: Address
230
+ data: Hex
231
+ }
232
+
224
233
  export type CallType = "call" | "delegatecall"
225
234
 
226
235
  export type KernelEncodeCallDataArgs = {