Skip to content

Commit 54e88eb

Browse files
committed
honor any owner signature
1 parent be46e72 commit 54e88eb

File tree

1 file changed

+37
-15
lines changed

1 file changed

+37
-15
lines changed

src/EIP7702Proxy.sol

Lines changed: 37 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ 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";
77
import {StorageSlot} from "openzeppelin-contracts/contracts/utils/StorageSlot.sol";
8+
import {IERC1271} from "openzeppelin-contracts/contracts/interfaces/IERC1271.sol";
89

910
/// @title EIP7702Proxy
1011
/// @notice Proxy contract designed for EIP-7702 smart accounts
@@ -164,11 +165,11 @@ contract EIP7702Proxy is Proxy {
164165
receive() external payable {}
165166

166167
/**
167-
* @notice Resets the ERC-1967 implementation slot after signature verification
168-
* @dev Uses raw hash (no Ethereum signed message prefix) to prevent phishing
168+
* @notice Resets the ERC-1967 implementation slot after signature verification from any valid owner
169+
* @dev Uses the implementation's isValidSignature to verify owner signatures
169170
* @param newImplementation The implementation address to set
170-
* @param nonce The nonce for this operation (verified against NonceTracker)
171-
* @param signature The EOA signature authorizing this change
171+
* @param nonce The nonce for this operation
172+
* @param signature The SignatureWrapper from any valid owner
172173
*/
173174
function resetImplementation(
174175
address newImplementation,
@@ -182,22 +183,43 @@ contract EIP7702Proxy is Proxy {
182183
revert NonceAlreadyUsed();
183184
}
184185

185-
// Raw hash without Ethereum signed message prefix
186+
// Hash includes newImplementation and nonce
186187
bytes32 hash = keccak256(abi.encode(newImplementation, nonce));
187188

188-
// Verify signature is from this address (the EOA)
189-
address recovered = ECDSA.recover(hash, signature);
190-
if (recovered != address(this)) {
191-
revert InvalidSignature();
189+
// First try validating against new implementation's isValidSignature
190+
(bool success, bytes memory result) = newImplementation.call(
191+
abi.encodeWithSelector(
192+
IERC1271.isValidSignature.selector,
193+
hash,
194+
signature
195+
)
196+
);
197+
198+
// Check if implementation validation succeeded
199+
if (
200+
success &&
201+
result.length == 32 &&
202+
abi.decode(result, (bytes4)) == ERC1271_MAGIC_VALUE
203+
) {
204+
// Valid owner signature, proceed with reset
205+
ERC1967Utils.upgradeToAndCall(newImplementation, "");
206+
emit ImplementationReset(newImplementation);
207+
return;
192208
}
193209

194-
// Reset the implementation slot
195-
ERC1967Utils.upgradeToAndCall(
196-
newImplementation,
197-
"" // No initialization needed
198-
);
210+
// If implementation check failed, try direct EOA signature
211+
if (signature.length == 65) {
212+
address recovered = ECDSA.recover(hash, signature);
213+
if (recovered == address(this)) {
214+
// Valid EOA signature, proceed with reset
215+
ERC1967Utils.upgradeToAndCall(newImplementation, "");
216+
emit ImplementationReset(newImplementation);
217+
return;
218+
}
219+
}
199220

200-
emit ImplementationReset(newImplementation);
221+
// If both checks fail, revert
222+
revert InvalidSignature();
201223
}
202224
}
203225

0 commit comments

Comments
 (0)