@@ -15,6 +15,7 @@ import {
1515 type LocalAccount ,
1616 type TypedDataDefinition ,
1717 concatHex ,
18+ decodeFunctionData ,
1819 encodeAbiParameters ,
1920 encodeFunctionData ,
2021 keccak256 ,
@@ -32,10 +33,13 @@ import {
3233 getUserOperationHash ,
3334 toSmartAccount
3435} from "viem/account-abstraction"
35- import { getChainId } from "viem/actions"
36+ import { getChainId , readContract } from "viem/actions"
3637import { getAction } from "viem/utils"
3738import { getAccountNonce } from "../../actions/public/getAccountNonce.js"
3839import { getSenderAddress } from "../../actions/public/getSenderAddress.js"
40+ import { encode7579Calls } from "../../utils/encode7579Calls.js"
41+ import { encodeInstallModule } from "../../utils/encodeInstallModule.js"
42+ import { encodeUninstallModule } from "../../utils/encodeUninstallModule.js"
3943import { type EthereumProvider , toOwner } from "../../utils/toOwner.js"
4044import { KernelInitAbi } from "./abi/KernelAccountAbi.js"
4145import {
@@ -59,6 +63,29 @@ import { signTypedData } from "./utils/signTypedData.js"
5963
6064type EntryPointVersion = "0.6" | "0.7"
6165
66+ const migrationHelperAbi = [
67+ {
68+ type : "function" ,
69+ name : "migrateWithCall" ,
70+ inputs : [
71+ {
72+ name : "validators" ,
73+ type : "address[]" ,
74+ internalType : "contract IValidator[]"
75+ } ,
76+ {
77+ name : "permissionIds" ,
78+ type : "bytes4[]" ,
79+ internalType : "bytes4[]"
80+ } ,
81+ { name : "execMode" , type : "bytes32" , internalType : "ExecMode" } ,
82+ { name : "execData" , type : "bytes" , internalType : "bytes" }
83+ ] ,
84+ outputs : [ ] ,
85+ stateMutability : "nonpayable"
86+ }
87+ ]
88+
6289/**
6390 * The account creation ABI for a kernel smart account (from the KernelFactory)
6491 */
@@ -99,6 +126,9 @@ export type KernelVersion<entryPointVersion extends EntryPointVersion> =
99126 ? "0.2.1" | "0.2.2" | "0.2.3" | "0.2.4"
100127 : "0.3.0-beta" | "0.3.1" | "0.3.2" | "0.3.3"
101128
129+ export const MIGRATION_HELPER_ADDRESS =
130+ "0x03EB97959433D55748839D27C93330Cb85F31A93"
131+
102132/**
103133 * Default addresses map for different kernel smart account versions
104134 */
@@ -660,6 +690,41 @@ export async function toKernelSmartAccount<
660690 return { accountAddress, getFactoryArgs }
661691 } ) ( )
662692
693+ const getKernelAccountPatchedStatus = async ( ) => {
694+ const rootValidator = await getAction (
695+ client ,
696+ readContract ,
697+ "readContract"
698+ ) ( {
699+ address : accountAddress ,
700+ abi : [
701+ {
702+ type : "function" ,
703+ name : "rootValidator" ,
704+ inputs : [ ] ,
705+ outputs : [
706+ {
707+ name : "" ,
708+ type : "bytes21" ,
709+ internalType : "ValidationId"
710+ }
711+ ] ,
712+ stateMutability : "view"
713+ }
714+ ] ,
715+ functionName : "rootValidator" ,
716+ args : [ ]
717+ } )
718+
719+ const patchedRootValidator =
720+ "0x017ab16ff354acb328452f1d445b3ddee9a91e9e69"
721+
722+ return rootValidator . toLowerCase ( ) === patchedRootValidator
723+ }
724+
725+ let isKernelAccountPatched =
726+ validatorAddress !== "0xbA45a2BFb8De3D24cA9D7F1B551E14dFF5d690Fd"
727+
663728 return toSmartAccount ( {
664729 client,
665730 entryPoint,
@@ -679,6 +744,102 @@ export async function toKernelSmartAccount<
679744 return accountAddress
680745 } ,
681746 async encodeCalls ( calls ) {
747+ if ( ! isKernelAccountPatched ) {
748+ const isDeployed =
749+ "isDeployed" in this && ( await ( this as any ) . isDeployed ( ) )
750+ isKernelAccountPatched =
751+ isDeployed && ( await getKernelAccountPatchedStatus ( ) )
752+ }
753+ if ( ! isKernelAccountPatched ) {
754+ const [ installFallbackCall ] = encodeInstallModule ( {
755+ account : this as any ,
756+ modules : [
757+ {
758+ type : "fallback" ,
759+ address : MIGRATION_HELPER_ADDRESS ,
760+ context :
761+ "0x36f541c10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000001FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000"
762+ }
763+ ]
764+ } )
765+
766+ const [ uninstallFallbackCall ] = encodeUninstallModule ( {
767+ account : this as any ,
768+ modules : [
769+ {
770+ type : "fallback" ,
771+ address : MIGRATION_HELPER_ADDRESS ,
772+ context : "0x36f541c1"
773+ }
774+ ]
775+ } )
776+
777+ const executeCallData = encodeCallData ( {
778+ calls,
779+ kernelVersion
780+ } )
781+
782+ const { args } = decodeFunctionData ( {
783+ abi : [
784+ {
785+ type : "function" ,
786+ name : "execute" ,
787+ inputs : [
788+ {
789+ name : "execMode" ,
790+ type : "bytes32" ,
791+ internalType : "ExecMode"
792+ } ,
793+ {
794+ name : "executionCalldata" ,
795+ type : "bytes" ,
796+ internalType : "bytes"
797+ }
798+ ] ,
799+ outputs : [ ] ,
800+ stateMutability : "payable"
801+ }
802+ ] ,
803+ data : executeCallData
804+ } )
805+
806+ const migrationCallData = encodeFunctionData ( {
807+ abi : migrationHelperAbi ,
808+ functionName : "migrateWithCall" ,
809+ args : [ [ ] , [ ] , ...args ] as readonly any [ ]
810+ } )
811+
812+ if ( kernelVersion !== "0.3.0-beta" ) {
813+ return encode7579Calls ( {
814+ mode : {
815+ type : "delegatecall" ,
816+ revertOnError : false ,
817+ selector : "0x" ,
818+ context : "0x"
819+ } ,
820+ callData : [
821+ {
822+ to : MIGRATION_HELPER_ADDRESS ,
823+ data : migrationCallData ,
824+ value : 0n
825+ }
826+ ]
827+ } )
828+ }
829+
830+ return encodeCallData ( {
831+ calls : [
832+ installFallbackCall ,
833+ {
834+ to : accountAddress ,
835+ data : migrationCallData ,
836+ value : 0n
837+ } ,
838+ uninstallFallbackCall
839+ ] ,
840+ kernelVersion
841+ } )
842+ }
682843 return encodeCallData ( { calls, kernelVersion } )
683844 } ,
684845 async decodeCalls ( callData ) {
0 commit comments