@@ -5,6 +5,7 @@ import {EIP7702ProxyBase} from "../base/EIP7702ProxyBase.sol";
55import {EIP7702Proxy} from "../../src/EIP7702Proxy.sol " ;
66import {MockImplementation, RevertingInitializerMockImplementation} from "../mocks/MockImplementation.sol " ;
77import {ECDSA} from "openzeppelin-contracts/contracts/utils/cryptography/ECDSA.sol " ;
8+ import {ERC1967Utils } from "openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Utils.sol " ;
89
910contract InitializeTest is EIP7702ProxyBase {
1011 function test_succeeds_withValidSignatureAndArgs (address newOwner ) public {
@@ -157,4 +158,70 @@ contract InitializeTest is EIP7702ProxyBase {
157158 vm.expectRevert (EIP7702Proxy.ZeroValueConstructorArguments.selector );
158159 new EIP7702Proxy (address (_implementation), bytes4 (0 ));
159160 }
161+
162+ function test_succeeds_whenImplementationSlotAlreadySetToDifferentAddress (
163+ address mockPreviousImpl ,
164+ address newOwner ,
165+ uint128 uninitProxyPk
166+ ) public {
167+ vm.assume (mockPreviousImpl != address (0 ));
168+ vm.assume (mockPreviousImpl != address (_implementation));
169+ vm.assume (mockPreviousImpl != address (_eoa));
170+ vm.assume (newOwner != address (0 ));
171+ vm.assume (newOwner != mockPreviousImpl);
172+ vm.assume (newOwner != _eoa);
173+ assumeNotPrecompile (mockPreviousImpl);
174+ assumeNotPrecompile (newOwner);
175+ vm.assume (uninitProxyPk != 0 );
176+ vm.assume (uninitProxyPk != _EOA_PRIVATE_KEY);
177+
178+ // Derive address for uninitProxy from private key
179+ address payable uninitProxy = payable (vm.addr (uninitProxyPk));
180+
181+ // Deploy proxy template and etch its code at the target address
182+ EIP7702Proxy proxyTemplate = new EIP7702Proxy (
183+ address (_implementation),
184+ _initSelector
185+ );
186+ bytes memory proxyCode = address (proxyTemplate).code;
187+ vm.etch (uninitProxy, proxyCode);
188+
189+ // Set the implementation slot to some other address, simulating a previous implementation
190+ vm.store (
191+ uninitProxy,
192+ ERC1967Utils .IMPLEMENTATION_SLOT,
193+ bytes32 (uint256 (uint160 (mockPreviousImpl)))
194+ );
195+
196+ // Verify implementation slot is set to the previous implementation
197+ assertEq (
198+ _getERC1967Implementation (uninitProxy),
199+ mockPreviousImpl,
200+ "Implementation slot should be set to previous implementation "
201+ );
202+
203+ // Initialize the proxy
204+ bytes memory initArgs = _createInitArgs (_newOwner);
205+ bytes32 initHash = keccak256 (
206+ abi.encode (address (proxyTemplate), initArgs)
207+ );
208+ (uint8 v , bytes32 r , bytes32 s ) = vm.sign (uninitProxyPk, initHash);
209+ bytes memory signature = abi.encodePacked (r, s, v);
210+
211+ EIP7702Proxy (uninitProxy).initialize (initArgs, signature);
212+
213+ // Verify implementation slot was changed to the correct implementation
214+ assertEq (
215+ _getERC1967Implementation (uninitProxy),
216+ address (_implementation),
217+ "Implementation slot should be set to correct implementation "
218+ );
219+
220+ // Verify we can make calls through the proxy now
221+ assertEq (
222+ MockImplementation (payable (uninitProxy)).owner (),
223+ _newOwner,
224+ "Should be able to call through proxy after initialization "
225+ );
226+ }
160227}
0 commit comments