Skip to content

Commit 112c353

Browse files
committed
dependency review
1 parent 9b7b59c commit 112c353

File tree

3 files changed

+38
-23
lines changed

3 files changed

+38
-23
lines changed

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,7 @@ out/
1111
docs/
1212

1313
# Dotenv file
14-
.env
14+
.env
15+
16+
# Library folder
17+
/lib

.gitmodules

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
[submodule "lib/forge-std"]
22
path = lib/forge-std
33
url = https://github.com/foundry-rs/forge-std
4-
[submodule "lib/openzeppelin-contracts"]
5-
path = lib/openzeppelin-contracts
6-
url = https://github.com/OpenZeppelin/openzeppelin-contracts
74
[submodule "lib/smart-wallet"]
85
path = lib/smart-wallet
96
url = https://github.com/coinbase/smart-wallet
107
[submodule "lib/solady"]
118
path = lib/solady
12-
url = https://github.com/vectorized/solady
9+
url = https://github.com/transmissions11/solady
10+
[submodule "lib/openzeppelin-contracts"]
11+
path = lib/openzeppelin-contracts
12+
url = https://github.com/OpenZeppelin/openzeppelin-contracts

src/EIP7702Proxy.sol

Lines changed: 30 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ pragma solidity ^0.8.23;
44
import {Proxy} from "openzeppelin-contracts/contracts/proxy/Proxy.sol";
55
import {ERC1967Utils} from "openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Utils.sol";
66
import {ECDSA} from "openzeppelin-contracts/contracts/utils/cryptography/ECDSA.sol";
7-
import {Address} from "openzeppelin-contracts/contracts/utils/Address.sol";
7+
import {StorageSlot} from "openzeppelin-contracts/contracts/utils/StorageSlot.sol";
88

99
/// @title EIP7702Proxy
1010
/// @notice Proxy contract designed for EIP-7702 smart accounts
@@ -24,6 +24,10 @@ contract EIP7702Proxy is Proxy {
2424
/// @notice Function selector on the implementation that is guarded from direct calls
2525
bytes4 immutable guardedInitializer;
2626

27+
/// @dev Storage slot with the initialized flag
28+
bytes32 internal constant INITIALIZED_SLOT =
29+
bytes32(uint256(keccak256("EIP7702Proxy.initialized")) - 1);
30+
2731
/// @notice Emitted when the implementation is upgraded
2832
event Upgraded(address indexed implementation);
2933

@@ -33,8 +37,8 @@ contract EIP7702Proxy is Proxy {
3337
/// @notice Emitted when the `guardedInitializer` is called
3438
error InvalidInitializer();
3539

36-
/// @notice Emitted when initialization is attempted on a non-initial implementation
37-
error InvalidImplementation();
40+
/// @notice Emitted when trying to delegate before initialization
41+
error ProxyNotInitialized();
3842

3943
/// @notice Emitted when constructor arguments are zero
4044
error ZeroValueConstructorArguments();
@@ -52,6 +56,11 @@ contract EIP7702Proxy is Proxy {
5256
guardedInitializer = initializer;
5357
}
5458

59+
/// @dev Checks if proxy has been initialized by checking the initialized flag
60+
function _isInitialized() internal view returns (bool) {
61+
return StorageSlot.getBooleanSlot(INITIALIZED_SLOT).value;
62+
}
63+
5564
/// @notice Initializes the proxy and implementation with a signed payload
5665
///
5766
/// @dev Signature must be from this contract's address
@@ -62,17 +71,20 @@ contract EIP7702Proxy is Proxy {
6271
bytes calldata args,
6372
bytes calldata signature
6473
) external {
65-
// construct hash incompatible with wallet RPCs to avoid phishing
74+
// Construct hash without Ethereum signed message prefix to prevent phishing via standard wallet signing.
75+
// Since this proxy is designed for EIP-7702 (where the proxy address is an EOA),
76+
// using a raw hash ensures that initialization signatures cannot be obtained through normal
77+
// wallet "Sign Message" prompts. This prevents malicious dapps from tricking users into
78+
// initializing their account via standard wallet signing flows.
79+
// Wallets must implement custom signing logic at a lower level to support initialization.
6680
bytes32 hash = keccak256(abi.encode(proxy, args));
6781
address recovered = ECDSA.recover(hash, signature);
6882
if (recovered != address(this)) revert InvalidSignature();
6983

70-
// enforce initialization only on initial implementation
71-
address implementation = _implementation();
72-
if (implementation != initialImplementation)
73-
revert InvalidImplementation();
84+
// Set initialized flag before upgrading
85+
StorageSlot.getBooleanSlot(INITIALIZED_SLOT).value = true;
7486

75-
// Set the ERC-1967 implementation slot, emit Upgraded event, call the initializer on the initial implementation
87+
// Set the ERC-1967 implementation slot, emit Upgraded event, call the initializer
7688
ERC1967Utils.upgradeToAndCall(
7789
initialImplementation,
7890
abi.encodePacked(guardedInitializer, args)
@@ -91,6 +103,9 @@ contract EIP7702Proxy is Proxy {
91103
bytes32 hash,
92104
bytes calldata signature
93105
) external returns (bytes4) {
106+
// Check initialization status first
107+
if (!_isInitialized()) revert ProxyNotInitialized();
108+
94109
// First try delegatecall to implementation
95110
(bool success, bytes memory result) = _implementation().delegatecall(
96111
msg.data
@@ -117,22 +132,19 @@ contract EIP7702Proxy is Proxy {
117132
return ERC1271_FAIL_VALUE;
118133
}
119134

120-
/// @inheritdoc Proxy
121-
function _implementation() internal view override returns (address) {
122-
address implementation = ERC1967Utils.getImplementation();
123-
return
124-
implementation != address(0)
125-
? implementation
126-
: initialImplementation;
127-
}
128-
129135
/// @inheritdoc Proxy
130136
/// @dev Handles ERC-1271 signature validation by enforcing an ecrecover check if signatures fail `isValidSignature` check
131137
/// @dev Guards a specified initializer function from being called directly
132138
function _fallback() internal override {
139+
if (!_isInitialized()) revert ProxyNotInitialized();
140+
133141
// block guarded initializer from being called
134142
if (msg.sig == guardedInitializer) revert InvalidInitializer();
135143

136144
_delegate(_implementation());
137145
}
146+
147+
function _implementation() internal view override returns (address) {
148+
return ERC1967Utils.getImplementation();
149+
}
138150
}

0 commit comments

Comments
 (0)