Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
163 changes: 162 additions & 1 deletion packages/permissionless/accounts/kernel/toKernelSmartAccount.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
type LocalAccount,
type TypedDataDefinition,
concatHex,
decodeFunctionData,
encodeAbiParameters,
encodeFunctionData,
keccak256,
Expand All @@ -32,10 +33,13 @@ import {
getUserOperationHash,
toSmartAccount
} from "viem/account-abstraction"
import { getChainId } from "viem/actions"
import { getChainId, readContract } from "viem/actions"
import { getAction } from "viem/utils"
import { getAccountNonce } from "../../actions/public/getAccountNonce.js"
import { getSenderAddress } from "../../actions/public/getSenderAddress.js"
import { encode7579Calls } from "../../utils/encode7579Calls.js"
import { encodeInstallModule } from "../../utils/encodeInstallModule.js"
import { encodeUninstallModule } from "../../utils/encodeUninstallModule.js"
import { type EthereumProvider, toOwner } from "../../utils/toOwner.js"
import { KernelInitAbi } from "./abi/KernelAccountAbi.js"
import {
Expand All @@ -59,6 +63,29 @@ import { signTypedData } from "./utils/signTypedData.js"

type EntryPointVersion = "0.6" | "0.7"

const migrationHelperAbi = [
{
type: "function",
name: "migrateWithCall",
inputs: [
{
name: "validators",
type: "address[]",
internalType: "contract IValidator[]"
},
{
name: "permissionIds",
type: "bytes4[]",
internalType: "bytes4[]"
},
{ name: "execMode", type: "bytes32", internalType: "ExecMode" },
{ name: "execData", type: "bytes", internalType: "bytes" }
],
outputs: [],
stateMutability: "nonpayable"
}
]

/**
* The account creation ABI for a kernel smart account (from the KernelFactory)
*/
Expand Down Expand Up @@ -99,6 +126,9 @@ export type KernelVersion<entryPointVersion extends EntryPointVersion> =
? "0.2.1" | "0.2.2" | "0.2.3" | "0.2.4"
: "0.3.0-beta" | "0.3.1" | "0.3.2" | "0.3.3"

export const MIGRATION_HELPER_ADDRESS =
"0x03EB97959433D55748839D27C93330Cb85F31A93"

/**
* Default addresses map for different kernel smart account versions
*/
Expand Down Expand Up @@ -660,6 +690,41 @@ export async function toKernelSmartAccount<
return { accountAddress, getFactoryArgs }
})()

const getKernelAccountPatchedStatus = async () => {
const rootValidator = await getAction(
client,
readContract,
"readContract"
)({
address: accountAddress,
abi: [
{
type: "function",
name: "rootValidator",
inputs: [],
outputs: [
{
name: "",
type: "bytes21",
internalType: "ValidationId"
}
],
stateMutability: "view"
}
],
functionName: "rootValidator",
args: []
})

const patchedRootValidator =
"0x017ab16ff354acb328452f1d445b3ddee9a91e9e69"

return rootValidator.toLowerCase() === patchedRootValidator
}

let isKernelAccountPatched =
validatorAddress !== "0xbA45a2BFb8De3D24cA9D7F1B551E14dFF5d690Fd"

return toSmartAccount({
client,
entryPoint,
Expand All @@ -679,6 +744,102 @@ export async function toKernelSmartAccount<
return accountAddress
},
async encodeCalls(calls) {
if (!isKernelAccountPatched) {
const isDeployed =
"isDeployed" in this && (await (this as any).isDeployed())
isKernelAccountPatched =
isDeployed && (await getKernelAccountPatchedStatus())
}
if (!isKernelAccountPatched) {
const [installFallbackCall] = encodeInstallModule({
account: this as any,
modules: [
{
type: "fallback",
address: MIGRATION_HELPER_ADDRESS,
context:
"0x36f541c10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000001FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000"
}
]
})

const [uninstallFallbackCall] = encodeUninstallModule({
account: this as any,
modules: [
{
type: "fallback",
address: MIGRATION_HELPER_ADDRESS,
context: "0x36f541c1"
}
]
})

const executeCallData = encodeCallData({
calls,
kernelVersion
})

const { args } = decodeFunctionData({
abi: [
{
type: "function",
name: "execute",
inputs: [
{
name: "execMode",
type: "bytes32",
internalType: "ExecMode"
},
{
name: "executionCalldata",
type: "bytes",
internalType: "bytes"
}
],
outputs: [],
stateMutability: "payable"
}
],
data: executeCallData
})

const migrationCallData = encodeFunctionData({
abi: migrationHelperAbi,
functionName: "migrateWithCall",
args: [[], [], ...args] as readonly any[]
})

if (kernelVersion !== "0.3.0-beta") {
return encode7579Calls({
mode: {
type: "delegatecall",
revertOnError: false,
selector: "0x",
context: "0x"
},
callData: [
{
to: MIGRATION_HELPER_ADDRESS,
data: migrationCallData,
value: 0n
}
]
})
}

return encodeCallData({
calls: [
installFallbackCall,
{
to: accountAddress,
data: migrationCallData,
value: 0n
},
uninstallFallbackCall
],
kernelVersion
})
}
return encodeCallData({ calls, kernelVersion })
},
async decodeCalls(callData) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export type SupportsExecutionModeParameters<
callType extends CallType = CallType
> = GetSmartAccountParameter<TSmartAccount> & ExecutionMode<callType>

function parseCallType(callType: CallType) {
export function getCallType(callType: CallType) {
switch (callType) {
case "call":
return "0x00"
Expand All @@ -53,7 +53,7 @@ export function encodeExecutionMode<callType extends CallType>({
return encodePacked(
["bytes1", "bytes1", "bytes4", "bytes4", "bytes22"],
[
toHex(toBytes(parseCallType(type), { size: 1 })),
toHex(toBytes(getCallType(type), { size: 1 })),
toHex(toBytes(revertOnError ? "0x01" : "0x00", { size: 1 })),
toHex(toBytes("0x0", { size: 4 })),
toHex(toBytes(selector ?? "0x", { size: 4 })),
Expand Down
6 changes: 6 additions & 0 deletions packages/permissionless/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ import {
type EncodeInstallModuleParameters,
encodeInstallModule
} from "./encodeInstallModule.js"
import {
type EncodeUninstallModuleParameters,
encodeUninstallModule
} from "./encodeUninstallModule.js"
import { getPackedUserOperation } from "./getPackedUserOperation.js"

import {
Expand Down Expand Up @@ -48,6 +52,8 @@ export {
decodeNonce,
type EncodeInstallModuleParameters,
encodeInstallModule,
type EncodeUninstallModuleParameters,
encodeUninstallModule,
type EncodeCallDataParams,
encode7579Calls,
decode7579Calls,
Expand Down
1 change: 1 addition & 0 deletions packages/wagmi-demo/src/PasskeysDemo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ function KernelSmartAccountDemo() {
client: publicClient,
version: "0.3.1",
owners: [toWebAuthnAccount({ credential })],
index: 17n,
entryPoint: {
address: entryPoint07Address,
version: "0.7"
Expand Down
Loading