// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; abstract contract Initializable { uint8 private _initialized; bool private _initializing; event Initialized(uint8 version); modifier initializer() { bool isTopLevelCall = !_initializing; require( (isTopLevelCall && _initialized < 1) || (!Address.isContract(address(this)) && _initialized == 1), "Initializable: contract is already initialized" ); _initialized = 1; if (isTopLevelCall) { _initializing = true; } _; if (isTopLevelCall) { _initializing = false; emit Initialized(1); } } modifier reinitializer(uint8 version) { require( !_initializing && _initialized < version, "Initializable: contract is already initialized" ); _initialized = version; _initializing = true; _; _initializing = false; emit Initialized(version); } modifier onlyInitializing() { require(_initializing, "Initializable: contract is not initializing"); _; } function _disableInitializers() internal virtual { require(!_initializing, "Initializable: contract is initializing"); if (_initialized != type(uint8).max) { _initialized = type(uint8).max; emit Initialized(type(uint8).max); } } function _getInitializedVersion() internal view returns (uint8) { return _initialized; } function _isInitializing() internal view returns (bool) { return _initializing; } } contract Implementation4 is Initializable { uint256 internal _value; function initialize() public initializer {} function setValue(uint256 _number) public { _value = _number; } function getValue() public view returns (uint256) { return _value; } fallback() external { _value = 1; } } contract Implementation2 is Initializable { uint256 internal _value; function initialize() public initializer {} function setValue(uint256 _number) public { _value = _number; } function getValue() public view returns (uint256) { return _value; } } abstract contract Proxy { function _delegate(address implementation) internal virtual { assembly { calldatacopy(0, 0, calldatasize()) let result := delegatecall( gas(), implementation, 0, calldatasize(), 0, 0 ) returndatacopy(0, 0, returndatasize()) switch result case 0 { revert(0, returndatasize()) } default { return(0, returndatasize()) } } } function _implementation() internal view virtual returns (address); function _fallback() internal virtual { _beforeFallback(); _delegate(_implementation()); } fallback() external payable virtual { _fallback(); } receive() external payable virtual { _fallback(); } function _beforeFallback() internal virtual {} } interface IBeacon { function implementation() external view returns (address); } interface IERC1822Proxiable { function proxiableUUID() external view returns (bytes32); } library Address { function isContract(address account) internal view returns (bool) { return account.code.length > 0; } function sendValue(address payable recipient, uint256 amount) internal { require( address(this).balance >= amount, "Address: insufficient balance" ); (bool success, ) = recipient.call{value: amount}(""); require( success, "Address: unable to send value, recipient may have reverted" ); } function functionCall( address target, bytes memory data ) internal returns (bytes memory) { return functionCallWithValue( target, data, 0, "Address: low-level call failed" ); } function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue( target, data, value, "Address: low-level call with value failed" ); } function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require( address(this).balance >= value, "Address: insufficient balance for call" ); (bool success, bytes memory returndata) = target.call{value: value}( data ); return verifyCallResultFromTarget( target, success, returndata, errorMessage ); } function functionStaticCall( address target, bytes memory data ) internal view returns (bytes memory) { return functionStaticCall( target, data, "Address: low-level static call failed" ); } function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget( target, success, returndata, errorMessage ); } function functionDelegateCall( address target, bytes memory data ) internal returns (bytes memory) { return functionDelegateCall( target, data, "Address: low-level delegate call failed" ); } function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget( target, success, returndata, errorMessage ); } function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert( bytes memory returndata, string memory errorMessage ) private pure { if (returndata.length > 0) { assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } library StorageSlot { struct AddressSlot { address value; } struct BooleanSlot { bool value; } struct Bytes32Slot { bytes32 value; } struct Uint256Slot { uint256 value; } function getAddressSlot( bytes32 slot ) internal pure returns (AddressSlot storage r) { assembly { r.slot := slot } } function getBooleanSlot( bytes32 slot ) internal pure returns (BooleanSlot storage r) { assembly { r.slot := slot } } function getBytes32Slot( bytes32 slot ) internal pure returns (Bytes32Slot storage r) { assembly { r.slot := slot } } function getUint256Slot( bytes32 slot ) internal pure returns (Uint256Slot storage r) { assembly { r.slot := slot } } } abstract contract ERC1967Upgrade { bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143; bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; event Upgraded(address indexed implementation); function _getImplementation() internal view returns (address) { return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; } function _setImplementation(address newImplementation) private { require( Address.isContract(newImplementation), "ERC1967: new implementation is not a contract" ); StorageSlot .getAddressSlot(_IMPLEMENTATION_SLOT) .value = newImplementation; } function _upgradeTo(address newImplementation) internal { _setImplementation(newImplementation); emit Upgraded(newImplementation); } function _upgradeToAndCall( address newImplementation, bytes memory data, bool forceCall ) internal { _upgradeTo(newImplementation); if (data.length > 0 || forceCall) { Address.functionDelegateCall(newImplementation, data); } } function _upgradeToAndCallUUPS( address newImplementation, bytes memory data, bool forceCall ) internal { if (StorageSlot.getBooleanSlot(_ROLLBACK_SLOT).value) { _setImplementation(newImplementation); } else { try IERC1822Proxiable(newImplementation).proxiableUUID() returns ( bytes32 slot ) { require( slot == _IMPLEMENTATION_SLOT, "ERC1967Upgrade: unsupported proxiableUUID" ); } catch { revert("ERC1967Upgrade: new implementation is not UUPS"); } _upgradeToAndCall(newImplementation, data, forceCall); } } bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; event AdminChanged(address previousAdmin, address newAdmin); function _getAdmin() internal view returns (address) { return StorageSlot.getAddressSlot(_ADMIN_SLOT).value; } function _setAdmin(address newAdmin) private { require( newAdmin != address(0), "ERC1967: new admin is the zero address" ); StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin; } function _changeAdmin(address newAdmin) internal { emit AdminChanged(_getAdmin(), newAdmin); _setAdmin(newAdmin); } bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50; event BeaconUpgraded(address indexed beacon); function _getBeacon() internal view returns (address) { return StorageSlot.getAddressSlot(_BEACON_SLOT).value; } function _setBeacon(address newBeacon) private { require( Address.isContract(newBeacon), "ERC1967: new beacon is not a contract" ); require( Address.isContract(IBeacon(newBeacon).implementation()), "ERC1967: beacon implementation is not a contract" ); StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon; } function _upgradeBeaconToAndCall( address newBeacon, bytes memory data, bool forceCall ) internal { _setBeacon(newBeacon); emit BeaconUpgraded(newBeacon); if (data.length > 0 || forceCall) { Address.functionDelegateCall( IBeacon(newBeacon).implementation(), data ); } } } contract ERC1967Proxy is Proxy, ERC1967Upgrade { constructor(address _logic, bytes memory _data) payable { _upgradeToAndCall(_logic, _data, false); } function _implementation() internal view virtual override returns (address impl) { return ERC1967Upgrade._getImplementation(); } } contract TransparentUpgradeableProxy is ERC1967Proxy { constructor(address _logic) payable ERC1967Proxy(_logic, "") { _changeAdmin(msg.sender); } modifier ifAdmin() { if (msg.sender == _getAdmin()) { _; } else { _fallback(); } } function admin() external payable ifAdmin returns (address admin_) { _requireZeroValue(); admin_ = _getAdmin(); } function implementation() external payable ifAdmin returns (address implementation_) { _requireZeroValue(); implementation_ = _implementation(); } function changeAdmin(address newAdmin) external payable virtual ifAdmin { _requireZeroValue(); _changeAdmin(newAdmin); } function upgradeTo(address newImplementation) external payable ifAdmin { _requireZeroValue(); _upgradeToAndCall(newImplementation, bytes(""), false); } function upgradeToAndCall( address newImplementation, bytes calldata data ) external payable ifAdmin { _upgradeToAndCall(newImplementation, data, true); } function _admin() internal view virtual returns (address) { return _getAdmin(); } function _beforeFallback() internal virtual override { require( msg.sender != _getAdmin(), "TransparentUpgradeableProxy: admin cannot fallback to proxy target" ); super._beforeFallback(); } function _requireZeroValue() private { require(msg.value == 0); } } contract TestHelper { function getValue(address proxyAddress) public returns (uint256) { Implementation2 proxyInstance2 = Implementation2(proxyAddress); return proxyInstance2.getValue(); } } contract TransparentUpgradeableProxyTestRunner { function test() public { assert(0 == getValue()); } function getValue() public returns (uint256) { Implementation4 instance4 = new Implementation4(); TransparentUpgradeableProxy proxy = new TransparentUpgradeableProxy( address(instance4) ); Implementation2 instance2 = new Implementation2(); proxy.upgradeTo(address(instance2)); //use helper because proxy admin can't call getValue() TestHelper h = new TestHelper(); return h.getValue(address(proxy)); } }