@@ -9,35 +9,48 @@ import {Address} from "openzeppelin-contracts/contracts/utils/Address.sol";
99/// @title EIP7702Proxy
1010/// @notice Proxy contract designed for EIP-7702 smart accounts
1111/// @dev Implements ERC-1967 with an initial implementation and guarded initialization
12+ /// @author Coinbase (https://github.com/base-org/eip-7702-proxy)
1213contract EIP7702Proxy is Proxy {
13- // ERC1271 interface constants
14+ /// @notice ERC1271 interface constants
1415 bytes4 internal constant ERC1271_MAGIC_VALUE = 0x1626ba7e ;
15- bytes4 internal constant ERC1271_ISVALIDSIGNATURE_SELECTOR = 0x1626ba7e ;
1616 bytes4 internal constant ERC1271_FAIL_VALUE = 0xffffffff ;
1717
1818 /// @notice Address of this proxy contract (stored as immutable)
1919 address immutable proxy;
20+
2021 /// @notice Initial implementation address set during construction
2122 address immutable initialImplementation;
23+
2224 /// @notice Function selector on the implementation that is guarded from direct calls
2325 bytes4 immutable guardedInitializer;
2426
27+ /// @notice Emitted when the implementation is upgraded
2528 event Upgraded (address indexed implementation );
2629
30+ /// @notice Emitted when the initialization signature is invalid
2731 error InvalidSignature ();
32+
33+ /// @notice Emitted when the `guardedInitializer` is called
2834 error InvalidInitializer ();
35+
36+ /// @notice Emitted when initialization is attempted on a non-initial implementation
2937 error InvalidImplementation ();
3038
39+ /// @notice Initializes the proxy with an initial implementation and guarded initializer
40+ /// @param implementation The initial implementation address
41+ /// @param initializer The selector of the `guardedInitializer` function
3142 constructor (address implementation , bytes4 initializer ) {
3243 proxy = address (this );
3344 initialImplementation = implementation;
3445 guardedInitializer = initializer;
3546 }
3647
3748 /// @notice Initializes the proxy and implementation with a signed payload
49+ ///
50+ /// @dev Signature must be from this contract's address
51+ ///
3852 /// @param args The initialization arguments for the implementation
3953 /// @param signature The signature authorizing initialization
40- /// @dev Signature must be from this contract's address
4154 function initialize (
4255 bytes calldata args ,
4356 bytes calldata signature
@@ -52,22 +65,21 @@ contract EIP7702Proxy is Proxy {
5265 if (implementation != initialImplementation)
5366 revert InvalidImplementation ();
5467
55- // Set the ERC-1967 implementation slot and emit Upgraded event
56- ERC1967Utils .upgradeToAndCall (initialImplementation, "" );
57-
58- Address.functionDelegateCall (
68+ // Set the ERC-1967 implementation slot, emit Upgraded event, call the initializer on the initial implementation
69+ ERC1967Utils .upgradeToAndCall (
5970 initialImplementation,
6071 abi.encodePacked (guardedInitializer, args)
6172 );
6273 }
6374
64- /**
65- * @notice Handles ERC-1271 signature validation by enforcing a final ecrecover check if signatures fail `isValidSignature` check
66- * @dev This ensures EOA signatures are considered valid regardless of the implementation's `isValidSignature` implementation
67- * @param hash The hash of the message being signed
68- * @param signature The signature of the message
69- * @return The result of the `isValidSignature` check
70- */
75+ /// @notice Handles ERC-1271 signature validation by enforcing a final ecrecover check if signatures fail `isValidSignature` check
76+ ///
77+ /// @dev This ensures EOA signatures are considered valid regardless of the implementation's `isValidSignature` implementation
78+ ///
79+ /// @param hash The hash of the message being signed
80+ /// @param signature The signature of the message
81+ ///
82+ /// @return The result of the `isValidSignature` check
7183 function isValidSignature (
7284 bytes32 hash ,
7385 bytes calldata signature
@@ -83,28 +95,19 @@ contract EIP7702Proxy is Proxy {
8395 result.length == 32 &&
8496 abi.decode (result, (bytes4 )) == ERC1271_MAGIC_VALUE
8597 ) {
86- assembly {
87- mstore (0 , ERC1271_MAGIC_VALUE )
88- return (0 , 32 )
89- }
98+ return ERC1271_MAGIC_VALUE ;
9099 }
91100
92101 // Only try ECDSA if signature is the right length (65 bytes)
93102 if (signature.length == 65 ) {
94103 address recovered = ECDSA.recover (hash, signature);
95104 if (recovered == address (this )) {
96- assembly {
97- mstore (0 , ERC1271_MAGIC_VALUE )
98- return (0 , 32 )
99- }
105+ return ERC1271_MAGIC_VALUE ;
100106 }
101107 }
102108
103109 // If all checks fail, return failure value
104- assembly {
105- mstore (0 , ERC1271_FAIL_VALUE )
106- return (0 , 32 )
107- }
110+ return ERC1271_FAIL_VALUE ;
108111 }
109112
110113 /// @inheritdoc Proxy
0 commit comments