@@ -664,6 +664,12 @@ struct Frame<T: Config> {
664664 /// The delegate call info of the currently executing frame which was spawned by
665665 /// `delegate_call`.
666666 delegate : Option < DelegateInfo < T > > ,
667+ /// The address where the code (and immutable data) originates from.
668+ ///
669+ /// For regular contracts, this equals the contract's own address.
670+ /// For delegated accounts (EIP-7702), this is the delegation target's address.
671+ /// For explicit delegate_call, this is the callee's address.
672+ code_address : H160 ,
667673 /// The output of the last executed call frame.
668674 last_frame_output : ExecReturnValue ,
669675 /// The set of contracts that were created during this call stack.
@@ -1054,111 +1060,134 @@ where
10541060 input_data : & [ u8 ] ,
10551061 exec_config : & ExecConfig < T > ,
10561062 ) -> Result < Option < ( Frame < T > , ExecutableOrPrecompile < T , E , Self > ) > , ExecError > {
1057- let ( account_id, contract_info, executable, delegate, entry_point) = match frame_args {
1058- FrameArgs :: Call { dest, cached_info, delegated_call } => {
1059- let address = T :: AddressMapper :: to_address ( & dest) ;
1060- let precompile = <AllPrecompiles < T > >:: get ( address. as_fixed_bytes ( ) ) ;
1061-
1062- // which contract info to load is unaffected by the fact if this
1063- // is a delegate call or not
1064- let contract = match ( cached_info, & precompile) {
1065- ( Some ( info) , _) => CachedContract :: Cached ( info) ,
1066- ( None , None ) =>
1067- if let Some ( info) = AccountInfo :: < T > :: load_contract ( & address) {
1068- CachedContract :: Cached ( info)
1069- } else {
1070- CachedContract :: None
1063+ let ( account_id, contract_info, executable, delegate, code_address, entry_point) =
1064+ match frame_args {
1065+ FrameArgs :: Call { dest, cached_info, delegated_call } => {
1066+ let address = T :: AddressMapper :: to_address ( & dest) ;
1067+ let precompile = <AllPrecompiles < T > >:: get ( address. as_fixed_bytes ( ) ) ;
1068+
1069+ // which contract info to load is unaffected by the fact if this
1070+ // is a delegate call or not
1071+ let contract = match ( cached_info, & precompile) {
1072+ ( Some ( info) , _) => CachedContract :: Cached ( info) ,
1073+ ( None , None ) => {
1074+ if let Some ( info) = AccountInfo :: < T > :: load_contract ( & address) {
1075+ CachedContract :: Cached ( info)
1076+ } else {
1077+ CachedContract :: None
1078+ }
10711079 } ,
1072- ( None , Some ( precompile) ) if precompile. has_contract_info ( ) => {
1073- log:: trace!( target: LOG_TARGET , "found precompile for address {address:?}" ) ;
1074- if let Some ( info) = AccountInfo :: < T > :: load_contract ( & address) {
1075- CachedContract :: Cached ( info)
1076- } else {
1077- let info = ContractInfo :: new ( & address, 0u32 . into ( ) , H256 :: zero ( ) ) ?;
1078- CachedContract :: Cached ( info)
1079- }
1080- } ,
1081- ( None , Some ( _) ) => CachedContract :: None ,
1082- } ;
1080+ ( None , Some ( precompile) ) if precompile. has_contract_info ( ) => {
1081+ log:: trace!( target: LOG_TARGET , "found precompile for address {address:?}" ) ;
1082+ if let Some ( info) = AccountInfo :: < T > :: load_contract ( & address) {
1083+ CachedContract :: Cached ( info)
1084+ } else {
1085+ let info = ContractInfo :: new ( & address, 0u32 . into ( ) , H256 :: zero ( ) ) ?;
1086+ CachedContract :: Cached ( info)
1087+ }
1088+ } ,
1089+ ( None , Some ( _) ) => CachedContract :: None ,
1090+ } ;
10831091
1084- let delegated_call = delegated_call. or_else ( || {
1085- exec_config. mock_handler . as_ref ( ) . and_then ( |mock_handler| {
1086- mock_handler. mock_delegated_caller ( address, input_data)
1087- } )
1088- } ) ;
1089- // in case of delegate the executable is not the one at `address`
1090- let executable = if let Some ( delegated_call) = & delegated_call {
1091- if let Some ( precompile) =
1092- <AllPrecompiles < T > >:: get ( delegated_call. callee . as_fixed_bytes ( ) )
1093- {
1094- ExecutableOrPrecompile :: Precompile {
1095- instance : precompile,
1096- _phantom : Default :: default ( ) ,
1092+ let delegated_call = delegated_call. or_else ( || {
1093+ exec_config. mock_handler . as_ref ( ) . and_then ( |mock_handler| {
1094+ mock_handler. mock_delegated_caller ( address, input_data)
1095+ } )
1096+ } ) ;
1097+ // in case of delegate the executable is not the one at `address`
1098+ // code_address tracks where the code (and immutable data) comes from
1099+ let ( executable, code_address) = if let Some ( delegated_call) = & delegated_call {
1100+ if let Some ( precompile) =
1101+ <AllPrecompiles < T > >:: get ( delegated_call. callee . as_fixed_bytes ( ) )
1102+ {
1103+ (
1104+ ExecutableOrPrecompile :: Precompile {
1105+ instance : precompile,
1106+ _phantom : Default :: default ( ) ,
1107+ } ,
1108+ delegated_call. callee ,
1109+ )
1110+ } else {
1111+ let Some ( info) =
1112+ AccountInfo :: < T > :: load_contract ( & delegated_call. callee )
1113+ else {
1114+ return Ok ( None ) ;
1115+ } ;
1116+ let executable = E :: from_storage ( info. code_hash , meter) ?;
1117+ ( ExecutableOrPrecompile :: Executable ( executable) , delegated_call. callee )
10971118 }
10981119 } else {
1099- let Some ( info) = AccountInfo :: < T > :: load_contract ( & delegated_call. callee )
1100- else {
1101- return Ok ( None ) ;
1102- } ;
1103- let executable = E :: from_storage ( info. code_hash , meter) ?;
1104- ExecutableOrPrecompile :: Executable ( executable)
1105- }
1106- } else {
1107- if let Some ( precompile) = precompile {
1108- ExecutableOrPrecompile :: Precompile {
1109- instance : precompile,
1110- _phantom : Default :: default ( ) ,
1120+ // For regular calls, check if the address is delegated (EIP-7702)
1121+ // If so, use the delegation target as the code source
1122+ let code_addr =
1123+ AccountInfo :: < T > :: get_delegation_target ( & address) . unwrap_or ( address) ;
1124+ if let Some ( precompile) = precompile {
1125+ (
1126+ ExecutableOrPrecompile :: Precompile {
1127+ instance : precompile,
1128+ _phantom : Default :: default ( ) ,
1129+ } ,
1130+ code_addr,
1131+ )
1132+ } else {
1133+ let Some ( info) = AccountInfo :: < T > :: load_contract ( & address) else {
1134+ return Ok ( None ) ;
1135+ } ;
1136+ let executable = E :: from_storage ( info. code_hash , meter) ?;
1137+ ( ExecutableOrPrecompile :: Executable ( executable) , code_addr)
11111138 }
1112- } else {
1113- let Some ( info) = AccountInfo :: < T > :: load_contract ( & address) else {
1114- return Ok ( None ) ;
1115- } ;
1116- let executable = E :: from_storage ( info. code_hash , meter) ?;
1117- ExecutableOrPrecompile :: Executable ( executable)
1118- }
1119- } ;
1139+ } ;
11201140
1121- ( dest, contract, executable, delegated_call, ExportedFunction :: Call )
1122- } ,
1123- FrameArgs :: Instantiate { sender, executable, salt, input_data } => {
1124- let deployer = T :: AddressMapper :: to_address ( & sender) ;
1125- let account_nonce = <System < T > >:: account_nonce ( & sender) ;
1126- let address = if let Some ( salt) = salt {
1127- address:: create2 ( & deployer, executable. code ( ) , input_data, salt)
1128- } else {
1129- use sp_runtime:: Saturating ;
1130- address:: create1 (
1131- & deployer,
1132- // the Nonce from the origin has been incremented pre-dispatch, so we
1133- // need to subtract 1 to get the nonce at the time of the call.
1134- if origin_is_caller {
1135- account_nonce. saturating_sub ( 1u32 . into ( ) ) . saturated_into ( )
1136- } else {
1137- account_nonce. saturated_into ( )
1138- } ,
1141+ (
1142+ dest,
1143+ contract,
1144+ executable,
1145+ delegated_call,
1146+ code_address,
1147+ ExportedFunction :: Call ,
11391148 )
1140- } ;
1141- let contract = ContractInfo :: new (
1142- & address,
1143- <System < T > >:: account_nonce ( & sender) ,
1144- * executable. code_hash ( ) ,
1145- ) ?;
1146- (
1147- T :: AddressMapper :: to_fallback_account_id ( & address) ,
1148- CachedContract :: Cached ( contract) ,
1149- ExecutableOrPrecompile :: Executable ( executable) ,
1150- None ,
1151- ExportedFunction :: Constructor ,
1152- )
1153- } ,
1154- } ;
1149+ } ,
1150+ FrameArgs :: Instantiate { sender, executable, salt, input_data } => {
1151+ let deployer = T :: AddressMapper :: to_address ( & sender) ;
1152+ let account_nonce = <System < T > >:: account_nonce ( & sender) ;
1153+ let address = if let Some ( salt) = salt {
1154+ address:: create2 ( & deployer, executable. code ( ) , input_data, salt)
1155+ } else {
1156+ use sp_runtime:: Saturating ;
1157+ address:: create1 (
1158+ & deployer,
1159+ // the Nonce from the origin has been incremented pre-dispatch, so we
1160+ // need to subtract 1 to get the nonce at the time of the call.
1161+ if origin_is_caller {
1162+ account_nonce. saturating_sub ( 1u32 . into ( ) ) . saturated_into ( )
1163+ } else {
1164+ account_nonce. saturated_into ( )
1165+ } ,
1166+ )
1167+ } ;
1168+ let contract = ContractInfo :: new (
1169+ & address,
1170+ <System < T > >:: account_nonce ( & sender) ,
1171+ * executable. code_hash ( ) ,
1172+ ) ?;
1173+ (
1174+ T :: AddressMapper :: to_fallback_account_id ( & address) ,
1175+ CachedContract :: Cached ( contract) ,
1176+ ExecutableOrPrecompile :: Executable ( executable) ,
1177+ None ,
1178+ address, // For instantiate, code_address is the new contract's address
1179+ ExportedFunction :: Constructor ,
1180+ )
1181+ } ,
1182+ } ;
11551183
11561184 let frame = Frame {
11571185 delegate,
11581186 value_transferred,
11591187 contract_info,
11601188 account_id,
11611189 entry_point,
1190+ code_address,
11621191 frame_meter : meter. new_nested ( call_resources) ?,
11631192 allows_reentry : true ,
11641193 read_only,
@@ -1938,13 +1967,9 @@ where
19381967 return Err ( Error :: < T > :: InvalidImmutableAccess . into ( ) ) ;
19391968 }
19401969
1941- // Immutable is read from contract code being executed
1942- let address = self
1943- . top_frame ( )
1944- . delegate
1945- . as_ref ( )
1946- . map ( |d| d. callee )
1947- . unwrap_or ( T :: AddressMapper :: to_address ( self . account_id ( ) ) ) ;
1970+ // Immutable data is read from the address where the code originates.
1971+ // This handles regular contracts, delegated accounts (EIP-7702), and delegate_call.
1972+ let address = self . top_frame ( ) . code_address ;
19481973 Ok ( <ImmutableDataOf < T > >:: get ( address) . ok_or_else ( || Error :: < T > :: InvalidImmutableAccess ) ?)
19491974 }
19501975
0 commit comments