Skip to content

Commit

Permalink
Merge pull request #116 from zerodevapp/feat/enable-recovery
Browse files Browse the repository at this point in the history
feat: added encodeModuleInstallCallData to kernelAccount, a flow for enabling recovery using that | updated to latest permissionless and viem with getAction bug fix
  • Loading branch information
SahilVasava authored Apr 15, 2024
2 parents a8a9ebb + 0d9709c commit ed5840d
Show file tree
Hide file tree
Showing 32 changed files with 344 additions and 94 deletions.
Binary file modified bun.lockb
Binary file not shown.
22 changes: 16 additions & 6 deletions packages/core/accounts/kernel/createKernelAccount.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ export type KernelSmartAccount<
getNonce: (customNonceKey?: bigint) => Promise<bigint>
generateInitCode: () => Promise<Hex>
encodeCallData: (args: KernelEncodeCallDataArgs) => Promise<Hex>
encodeModuleInstallCallData: () => Promise<Hex>
}

export type CreateKernelAccountParameters<entryPoint extends EntryPoint> = {
Expand Down Expand Up @@ -267,21 +268,23 @@ export async function createKernelAccount<
plugins,
entryPoint: entryPointAddress,
index = 0n,
factoryAddress = KERNEL_ADDRESSES.FACTORY_ADDRESS_V0_6,
accountLogicAddress = KERNEL_ADDRESSES.ACCOUNT_LOGIC_V0_6,
factoryAddress,
accountLogicAddress,
factoryStakerAddress = KERNEL_ADDRESSES.FACTORY_STAKER,
deployedAccountAddress
}: CreateKernelAccountParameters<entryPoint>
): Promise<KernelSmartAccount<entryPoint, TTransport, TChain>> {
const entryPointVersion = getEntryPointVersion(entryPointAddress)
accountLogicAddress =
entryPointVersion === "v0.6"
accountLogicAddress ??
(entryPointVersion === "v0.6"
? KERNEL_ADDRESSES.ACCOUNT_LOGIC_V0_6
: KERNEL_ADDRESSES.ACCOUNT_LOGIC_V0_7
: KERNEL_ADDRESSES.ACCOUNT_LOGIC_V0_7)
factoryAddress =
entryPointVersion === "v0.6"
factoryAddress ??
(entryPointVersion === "v0.6"
? KERNEL_ADDRESSES.FACTORY_ADDRESS_V0_6
: KERNEL_ADDRESSES.FACTORY_ADDRESS_V0_7
: KERNEL_ADDRESSES.FACTORY_ADDRESS_V0_7)

const kernelPluginManager = isKernelPluginManager<entryPoint>(plugins)
? plugins
Expand All @@ -294,6 +297,8 @@ export async function createKernelAccount<
})
// Helper to generate the init code for the smart account
const generateInitCode = async () => {
if (!accountLogicAddress || !factoryAddress)
throw new Error("Missing account logic address or factory address")
return getAccountInitCode<entryPoint>({
index,
factoryAddress,
Expand Down Expand Up @@ -323,6 +328,11 @@ export async function createKernelAccount<
return {
kernelPluginManager,
generateInitCode,
encodeModuleInstallCallData: async () => {
return await kernelPluginManager.encodeModuleInstallCallData(
accountAddress
)
},
...toSmartAccount({
address: accountAddress,
publicKey: accountAddress,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import type { ENTRYPOINT_ADDRESS_V06_TYPE } from "permissionless/types/entrypoint"
import { type Address, type Hex, encodeFunctionData } from "viem"
import type { PluginInstallData } from "../../../../../types/kernel.js"
import { KernelAccountAbi } from "../../../abi/KernelAccountAbi.js"
import { encodeCallData } from "./encodeCallData.js"

export const encodeModuleInstallCallData = async ({
accountAddress,
enableData,
executor,
selector,
validAfter,
validUntil,
validator
}: {
accountAddress: Address
} & PluginInstallData<ENTRYPOINT_ADDRESS_V06_TYPE>): Promise<Hex> => {
return encodeCallData({
to: accountAddress,
value: 0n,
data: encodeFunctionData({
abi: KernelAccountAbi,
functionName: "setExecution",
args: [
selector,
executor,
validator,
validUntil,
validAfter,
enableData
]
}),
callType: "call"
})
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { getAction } from "permissionless"
import type { Address, Client } from "viem"
import { readContract } from "viem/actions"
import { getAction } from "viem/utils"
import { KernelV3AccountAbi } from "../../../abi/kernel_v_3_0_0/KernelAccountAbi.js"

export const getKernelV3Nonce = async (
Expand All @@ -10,7 +10,8 @@ export const getKernelV3Nonce = async (
try {
const nonce = await getAction(
client,
readContract
readContract,
"sendTransaction"
)({
abi: KernelV3AccountAbi,
address: accountAddress,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ export const getPluginsEnableTypedData = async <
accountAddress: Address
chainId: number
kernelVersion: string
// { action, validator }: Kernel2_0_plugins
} & Kernel2_0_plugins<entryPoint> &
PluginValidityData): Promise<
Parameters<CustomSource["signTypedData"]>[0]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { getAction } from "permissionless"
import type { Address, Client } from "viem"
import { readContract } from "viem/actions"
import { getAction } from "viem/utils"
import { KernelModuleIsInitializedAbi } from "../../../abi/kernel_v_3_0_0/KernelModuleAbi.js"

export const isPluginInitialized = async (
Expand All @@ -11,7 +11,8 @@ export const isPluginInitialized = async (
try {
return await getAction(
client,
readContract
readContract,
"readContract"
)({
abi: KernelModuleIsInitializedAbi,
address: pluginAddress,
Expand Down
3 changes: 3 additions & 0 deletions packages/core/accounts/kernel/v1/createKernelV1Account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,9 @@ export async function createKernelV1Account<
return {
...account,
generateInitCode,
encodeModuleInstallCallData: async () => {
throw new Error("Not implemented")
},
client: client,
publicKey: accountAddress,
entryPoint: entryPointAddress,
Expand Down
22 changes: 7 additions & 15 deletions packages/core/accounts/kernel/v2/createKernelV2Account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,7 @@ import {
getSenderAddress,
isSmartAccountDeployed
} from "permissionless"
import {
SignTransactionNotSupportedBySmartAccount,
type SmartAccount
} from "permissionless/accounts"
import { SignTransactionNotSupportedBySmartAccount } from "permissionless/accounts"
import type {
ENTRYPOINT_ADDRESS_V06_TYPE,
EntryPoint
Expand Down Expand Up @@ -47,20 +44,10 @@ import {
isKernelPluginManager,
toKernelPluginManager
} from "../../utils/toKernelPluginManager.js"
import { type KernelSmartAccount } from "../createKernelAccount.js"
import { KernelAccountV2Abi } from "./abi/KernelAccountV2Abi.js"
import { KernelFactoryV2Abi } from "./abi/KernelFactoryV2Abi.js"

export type KernelSmartAccount<
entryPoint extends EntryPoint,
transport extends Transport = Transport,
chain extends Chain | undefined = Chain | undefined
> = SmartAccount<entryPoint, "kernelSmartAccount", transport, chain> & {
kernelPluginManager: KernelPluginManager<entryPoint>
getNonce: (customNonceKey?: bigint) => Promise<bigint>
generateInitCode: () => Promise<Hex>
encodeCallData: (args: KernelEncodeCallDataArgs) => Promise<Hex>
}

// Safe's library for create and create2: https://github.com/safe-global/safe-contracts/blob/0acdd35a203299585438f53885df630f9d486a86/contracts/libraries/CreateCall.sol
// Address was found here: https://github.com/safe-global/safe-deployments/blob/926ec6bbe2ebcac3aa2c2c6c0aff74aa590cbc6a/src/assets/v1.4.1/create_call.json
const createCallAddress = "0x9b35Af71d77eaf8d7e40252370304687390A1A52"
Expand Down Expand Up @@ -289,6 +276,11 @@ export async function createKernelV2Account<
source: "kernelSmartAccount",
kernelPluginManager,
generateInitCode,
encodeModuleInstallCallData: async () => {
return await kernelPluginManager.encodeModuleInstallCallData(
accountAddress
)
},
async getFactory() {
if (smartAccountDeployed) return undefined

Expand Down
5 changes: 3 additions & 2 deletions packages/core/accounts/utils/6492.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
// copied from: https://github.com/alchemyplatform/aa-sdk/blob/266c9757cd721ef0bd97d04c0b592a329f8a9da5/packages/core/src/signer/utils.ts

import { getAction } from "permissionless"
import {
type Address,
type Chain,
Expand All @@ -14,6 +13,7 @@ import {
parseAbiParameters
} from "viem"
import { getStorageAt } from "viem/actions"
import { getAction } from "viem/utils"

export type SignWith6492Params = {
factoryAddress: Address
Expand Down Expand Up @@ -85,7 +85,8 @@ export const getKernelImplementationAddress = async <
try {
const strgAddr = await getAction(
client,
getStorageAt
getStorageAt,
"getStorageAt"
)({
address: accountAddress,
slot: "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc"
Expand Down
19 changes: 19 additions & 0 deletions packages/core/accounts/utils/toKernelPluginManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
zeroAddress
} from "viem"
import { getChainId } from "viem/actions"
import { encodeModuleInstallCallData as encodeModuleInstallCallDataEpV06 } from "../../accounts/kernel/utils/account/ep0_6/encodeModuleInstallCallData.js"
import { VALIDATOR_MODE, VALIDATOR_TYPE } from "../../constants.js"
import {
type KernelPluginManager,
Expand Down Expand Up @@ -193,6 +194,24 @@ export async function toKernelPluginManager<
return {
...activeValidator,
getIdentifier,
encodeModuleInstallCallData: async (accountAddress: Address) => {
if (!action) {
throw new Error("Action data must be set")
}
if (!regular) throw new Error("regular validator not set")
if (entryPointVersion === "v0.6") {
return await encodeModuleInstallCallDataEpV06({
accountAddress,
selector: action.selector,
executor: action.address,
validator: regular?.address,
validUntil,
validAfter,
enableData: await regular.getEnableData(accountAddress)
})
}
throw new Error("EntryPoint v0.7 not supported yet")
},
signUserOperation: async (userOperation) => {
const userOpSig =
await activeValidator.signUserOperation(userOperation)
Expand Down
5 changes: 3 additions & 2 deletions packages/core/actions/account-client/signUserOperation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ import type {
} from "permissionless/types"
import {
AccountOrClientNotFoundError,
getAction,
parseAccount
} from "permissionless/utils"
import type { Chain, Client, Transport } from "viem"
import { getAction } from "viem/utils"

export type SignUserOperationParameters<
entryPoint extends EntryPoint,
Expand Down Expand Up @@ -60,7 +60,8 @@ export async function signUserOperation<

const userOperation = await getAction(
client,
prepareUserOperationRequest<entryPoint, TTransport, TChain, TAccount>
prepareUserOperationRequest<entryPoint, TTransport, TChain, TAccount>,
"prepareUserOperationRequest"
)(args)

userOperation.signature = await account.signUserOperation(
Expand Down
4 changes: 2 additions & 2 deletions packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,8 @@
}
},
"peerDependencies": {
"viem": "^2.0.0",
"permissionless": "^0.1.16"
"viem": "^2.9.17",
"permissionless": "^0.1.17"
},
"dependencies": {
"semver": "^7.6.0"
Expand Down
19 changes: 18 additions & 1 deletion packages/core/types/kernel.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import type { EntryPoint } from "permissionless/types"
import type {
ENTRYPOINT_ADDRESS_V06_TYPE,
EntryPoint
} from "permissionless/types"
import type { GetEntryPointVersion } from "permissionless/types/entrypoint"
import type {
UserOperation,
Expand Down Expand Up @@ -151,8 +154,22 @@ export type KernelPluginManager<entryPoint extends EntryPoint> =
getAction(): Action
getValidityData(): PluginValidityData
getIdentifier(isSudo?: boolean): Hex
encodeModuleInstallCallData: (accountAddress: Address) => Promise<Hex>
}

export type PluginInstallData<entryPoint extends EntryPoint> =
entryPoint extends ENTRYPOINT_ADDRESS_V06_TYPE
? {
selector: Hex
executor: Address
validator: Address
validUntil: number
validAfter: number
enableData: Hex
}
: // TODO: Add support for EP v0.7
never

export type KernelPluginManagerParams<entryPoint extends EntryPoint> = {
sudo?: KernelValidator<entryPoint>
regular?: KernelValidator<entryPoint>
Expand Down
3 changes: 2 additions & 1 deletion packages/core/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,8 @@ export const fixSignedData = (sig: Hex): Hex => {

let { r, s, v } = hexToSignature(signature)
if (v === 0n || v === 1n) v += 27n
const joined = signatureToHex({ r, s, v })
// biome-ignore lint/style/noNonNullAssertion: <explanation>
const joined = signatureToHex({ r, s, v: v! })
return joined
}

Expand Down
4 changes: 2 additions & 2 deletions packages/presets/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
"typescript": "^5.0.0",
"@zerodev/sdk": "^5.2.0",
"@zerodev/ecdsa-validator": "^5.2.0",
"permissionless": "^0.1.16",
"viem": "^2.0.0"
"permissionless": "^0.1.17",
"viem": "^2.9.17"
}
}
4 changes: 2 additions & 2 deletions packages/test/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@
},
"dependencies": {
"dotenv": "^16.3.1",
"viem": "^2.0.0",
"viem": "^2.9.17",
"@zerodev/sdk": "workspace:*",
"@zerodev/ecdsa-validator": "workspace:*",
"@zerodev/session-key": "workspace:*",
"@zerodev/modular-permission": "workspace:*",
"permissionless": "^0.1.16"
"permissionless": "^0.1.17"
}
}
Loading

0 comments on commit ed5840d

Please sign in to comment.