@@ -4,6 +4,7 @@ pragma solidity 0.8.28;
44import {ProxyAdmin} from '@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol ' ;
55import {TransparentUpgradeableProxy} from '@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol ' ;
66import {Script} from 'forge-std/Script.sol ' ;
7+ import {console2} from 'forge-std/console2.sol ' ;
78
89import {DelegatedSavingCircles} from '../src/contracts/DelegatedSavingCircles.sol ' ;
910import {SavingCircles} from '../src/contracts/SavingCircles.sol ' ;
@@ -16,35 +17,90 @@ import {SavingCirclesViewer} from '../src/contracts/SavingCirclesViewer.sol';
1617 * @dev This contract is intended for use in Scripts and Integration Tests
1718 */
1819contract Common is Script {
20+ bytes32 internal constant _ERC1967_IMPLEMENTATION_SLOT =
21+ 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc ;
22+ bytes32 internal constant _ERC1967_ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103 ;
23+ bytes4 internal constant _OWNER_SELECTOR = bytes4 (keccak256 ('owner() ' ));
24+ bytes4 internal constant _UPGRADE_INTERFACE_VERSION_SELECTOR = bytes4 (keccak256 ('UPGRADE_INTERFACE_VERSION() ' ));
25+
26+ error InvalidAdminAddress ();
27+ error InvalidAdminProxyAdmin (address admin );
28+ error ProxyAdminOwnerMismatch (address proxyAdmin , address expectedOwner , address actualOwner );
29+ error ProxyAdminNotDeployed (address proxy );
30+ error ProxyImplementationSlotMismatch (address proxy , address expectedImplementation , address actualImplementation );
31+
1932 function setUp () public virtual {}
2033
2134 function _deploySavingCircles () internal returns (SavingCircles) {
2235 return new SavingCircles ();
2336 }
2437
25- function _deployProxyAdmin (address _admin ) internal returns (ProxyAdmin) {
26- return new ProxyAdmin (_admin);
27- }
28-
2938 function _deployTransparentProxy (
3039 address _implementation ,
31- address _proxyAdmin ,
40+ address _adminOwner ,
3241 bytes memory _initData
3342 ) internal returns (TransparentUpgradeableProxy) {
34- return new TransparentUpgradeableProxy (_implementation, _proxyAdmin , _initData);
43+ return new TransparentUpgradeableProxy (_implementation, _adminOwner , _initData);
3544 }
3645
3746 function _deployContracts (address _admin ) internal returns (TransparentUpgradeableProxy) {
47+ _assertValidAdmin (_admin);
48+
49+ SavingCircles implementation = _deploySavingCircles ();
3850 TransparentUpgradeableProxy proxy = _deployTransparentProxy (
39- address (_deploySavingCircles ()),
40- address (_deployProxyAdmin (_admin)),
41- abi.encodeWithSelector (SavingCircles.initialize.selector , _admin)
51+ address (implementation), _admin, abi.encodeWithSelector (SavingCircles.initialize.selector , _admin)
4252 );
4353
4454 // Deploy auxiliary contracts that reference the SavingCircles proxy
4555 new DelegatedSavingCircles (address (proxy));
4656 new SavingCirclesViewer (address (proxy));
4757
58+ address proxyAdmin = _assertDeployment (address (proxy), address (implementation), _admin);
59+
60+ console2.log ('Deployer ' , msg .sender );
61+ console2.log ('Admin ' , _admin);
62+ console2.log ('ProxyAdmin ' , proxyAdmin);
63+ console2.log ('Proxy ' , address (proxy));
64+ console2.log ('Implementation ' , address (implementation));
65+
4866 return proxy;
4967 }
68+
69+ function _assertValidAdmin (address _admin ) internal view {
70+ if (_admin == address (0 )) revert InvalidAdminAddress ();
71+ if (_isProxyAdmin (_admin)) revert InvalidAdminProxyAdmin (_admin);
72+ }
73+
74+ function _assertDeployment (
75+ address _proxy ,
76+ address _implementation ,
77+ address _expectedAdminOwner
78+ ) internal view returns (address proxyAdmin ) {
79+ proxyAdmin = _readAddressFromSlot (_proxy, _ERC1967_ADMIN_SLOT);
80+ if (proxyAdmin == address (0 )) revert ProxyAdminNotDeployed (_proxy);
81+
82+ address actualOwner = ProxyAdmin (proxyAdmin).owner ();
83+ if (actualOwner != _expectedAdminOwner) {
84+ revert ProxyAdminOwnerMismatch (proxyAdmin, _expectedAdminOwner, actualOwner);
85+ }
86+
87+ address actualImplementation = _readAddressFromSlot (_proxy, _ERC1967_IMPLEMENTATION_SLOT);
88+ if (actualImplementation != _implementation) {
89+ revert ProxyImplementationSlotMismatch (_proxy, _implementation, actualImplementation);
90+ }
91+ }
92+
93+ function _readAddressFromSlot (address _contract , bytes32 _slot ) internal view returns (address ) {
94+ return address (uint160 (uint256 (vm.load (_contract, _slot))));
95+ }
96+
97+ function _isProxyAdmin (address _candidate ) internal view returns (bool ) {
98+ if (_candidate.code.length == 0 ) return false ;
99+
100+ (bool ownerCallSuccess ,) = _candidate.staticcall (abi.encodeWithSelector (_OWNER_SELECTOR));
101+ if (! ownerCallSuccess) return false ;
102+
103+ (bool versionCallSuccess ,) = _candidate.staticcall (abi.encodeWithSelector (_UPGRADE_INTERFACE_VERSION_SELECTOR));
104+ return versionCallSuccess;
105+ }
50106}
0 commit comments