@@ -694,6 +694,50 @@ object "Bootloader" {
694
694
ret := mload (0 )
695
695
}
696
696
697
+
698
+
699
+ /// @notice Overrides the "raw" code hash of the address. "Raw" means that it must use exactly the value
700
+ /// that is stored in the AccountCodeStorage system contract for that address, without applying any
701
+ /// additional transformations.
702
+ /// This method is very unsafe and it shouldn't be used to do long-term modifications.
703
+ /// Right now it's only used to override the bytecode hash of delegated accounts to perform
704
+ /// transaction validation & payment.
705
+ /// @param addr The address of the account to set the code hash of.
706
+ /// @param codeHash The code hash to be set.
707
+ /// @param assertSuccess Whether to revert the bootloader if the call to the AccountCodeStorage fails. If `false`, only
708
+ /// `nearCallPanic` will be issued in case of failure, which is helpful for cases, when the reason for failure is user providing not
709
+ /// enough gas.
710
+ function setRawCodeHash (addr, codeHash, assertSuccess) -> ret {
711
+ mstore (0 , {{RIGHT_PADDED_SET_RAW_CODE_HASH_SELECTOR}})
712
+ mstore (4 , addr)
713
+ mstore (36 , codeHash)
714
+ let success := staticcall (
715
+ gas (),
716
+ ACCOUNT_CODE_STORAGE_ADDR (),
717
+ 0 ,
718
+ 36 ,
719
+ 0 ,
720
+ 32
721
+ )
722
+
723
+ // In case the call to the account code storage fails,
724
+ // it most likely means that the caller did not provide enough gas for
725
+ // the call.
726
+ // In case the caller is certain that the amount of gas provided is enough, i.e.
727
+ // (`assertSuccess` = true), then we should panic.
728
+ if iszero (success) {
729
+ if assertSuccess {
730
+ // The call must've succeeded, but it didn't. So we revert the bootloader.
731
+ assertionError ("getRawCodeHash failed " )
732
+ }
733
+
734
+ // Most likely not enough gas provided, revert the current frame.
735
+ nearCallPanic ()
736
+ }
737
+
738
+ ret := mload (0 )
739
+ }
740
+
697
741
/// @notice Returns the address of EIP-7702 delegation for the account (or zero, if account
698
742
/// is not delegated).
699
743
/// @param addr The address of the account to check.
@@ -2239,28 +2283,48 @@ object "Bootloader" {
2239
2283
}
2240
2284
}
2241
2285
2242
- /// @dev Checks whether an address is an EOA (i.e. has not code deployed on it)
2286
+ /// @dev Checks whether an address is an EOA (i.e. has not code deployed on it or it's a 7702-delegated account )
2243
2287
/// @param addr The address to check
2244
2288
function isEOA (addr) -> ret {
2245
2289
ret := 0
2290
+ let delegation := getDelegationAddress (addr)
2246
2291
2292
+ // TODO: This logic is duplicated in several places, we should create a dedicated method.
2247
2293
if gt (addr, MAX_SYSTEM_CONTRACT_ADDR ()) {
2248
- ret := iszero (getRawCodeHash (addr, false ))
2294
+ ret := or (
2295
+ iszero (getRawCodeHash (addr, false )),
2296
+ gt (delegation, 0 )
2297
+ )
2249
2298
}
2250
2299
}
2251
2300
2252
2301
/// @dev Calls the `payForTransaction` method of an account
2253
2302
function accountPayForTx (account, txDataOffset) -> success {
2303
+ let delegation := getDelegationAddress (account)
2304
+ let rawCodeHash := 0
2305
+ if gt (delegation, 0 ) {
2306
+ rawCodeHash := getRawCodeHash (delegation, true )
2307
+ setRawCodeHash (account, 0 , true )
2308
+ }
2254
2309
success := callAccountMethod ({{PAY_FOR_TX_SELECTOR}}, account, txDataOffset)
2310
+ if gt (delegation, 0 ) {
2311
+ setRawCodeHash (account, rawCodeHash, true )
2312
+ }
2255
2313
}
2256
2314
2257
2315
/// @dev Calls the `prepareForPaymaster` method of an account
2258
2316
function accountPrePaymaster (account, txDataOffset) -> success {
2317
+ // TODO: should we allow delegated accounts to use native paymasters?
2318
+ // TODO: Gut feeling is that the answer is "NO" as we're deprecating EIP-712 txs
2319
+ // TOOD: and native accounts have their own entrypoint.
2259
2320
success := callAccountMethod ({{PRE_PAYMASTER_SELECTOR}}, account, txDataOffset)
2260
2321
}
2261
2322
2262
2323
/// @dev Calls the `validateAndPayForPaymasterTransaction` method of a paymaster
2263
2324
function validateAndPayForPaymasterTransaction (paymaster, txDataOffset) -> success {
2325
+ // TODO: should we allow delegated accounts to use native paymasters?
2326
+ // TODO: Gut feeling is that the answer is "NO" as we're deprecating EIP-712 txs
2327
+ // TOOD: and native accounts have their own entrypoint.
2264
2328
success := callAccountMethod ({{VALIDATE_AND_PAY_PAYMASTER}}, paymaster, txDataOffset)
2265
2329
}
2266
2330
@@ -2501,7 +2565,21 @@ object "Bootloader" {
2501
2565
setHook (VM_HOOK_ACCOUNT_VALIDATION_ENTERED ())
2502
2566
debugLog ("pre-validate " ,0 )
2503
2567
debugLog ("pre-validate " ,from)
2568
+
2569
+ // Override bytecode hash for validation if required.
2570
+ // TODO: It should be safe, since delegation is only allowed for EOAs in the first place.
2571
+ let delegation := getDelegationAddress (from)
2572
+ let rawCodeHash := 0
2573
+ if gt (delegation, 0 ) {
2574
+ rawCodeHash := getRawCodeHash (delegation, true )
2575
+ setRawCodeHash (from, 0 , true )
2576
+ }
2577
+
2504
2578
let success := callAccountMethod ({{VALIDATE_TX_SELECTOR}}, from, txDataOffset)
2579
+
2580
+ if gt (delegation, 0 ) {
2581
+ setRawCodeHash (from, rawCodeHash, true )
2582
+ }
2505
2583
setHook (VM_HOOK_NO_VALIDATION_ENTERED ())
2506
2584
2507
2585
if iszero (success) {
@@ -2645,7 +2723,7 @@ object "Bootloader" {
2645
2723
let innerTxDataOffset := add (txDataOffset, 32 )
2646
2724
let calldataPtr := getDataPtr (innerTxDataOffset)
2647
2725
let value := getValue (innerTxDataOffset)
2648
- ret := msgValueSimulatorMimicCall (delegation , from, value, calldataPtr)
2726
+ ret := msgValueSimulatorMimicCall (from , from, value, calldataPtr)
2649
2727
}
2650
2728
2651
2729
if iszero (ret) {
0 commit comments