1
1
//SPDX-License-Identifier: MIT
2
- // Adapted from <https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.9.0/contracts/proxy/utils/UUPSUpgradeable.sol>
3
-
4
- /**
5
- * @authors: [@malatrax]
6
- * @reviewers: []
7
- * @auditors: []
8
- * @bounties: []
9
- * @deployments: []
10
- */
2
+
11
3
pragma solidity 0.8.24 ;
12
4
13
- /**
14
- * @title UUPS Proxiable
15
- * @author Simon Malatrait <[email protected] >
16
- * @dev This contract implements an upgradeability mechanism designed for UUPS proxies.
17
- * The functions included here can perform an upgrade of an UUPS Proxy, when this contract is set as the implementation behind such a proxy.
18
- *
19
- * IMPORTANT: A UUPS proxy requires its upgradeability functions to be in the implementation as opposed to the transparent proxy.
20
- * This means that if the proxy is upgraded to an implementation that does not support this interface, it will no longer be upgradeable.
21
- *
22
- * A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is
23
- * reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing
24
- * `UUPSProxiable` with a custom implementation of upgrades.
25
- *
26
- * The `_authorizeUpgrade` function must be overridden to include access restriction to the upgrade mechanism.
27
- */
5
+ /// @title UUPS Proxiable
6
+ /// @author Simon Malatrait <[email protected] >
7
+ /// @dev This contract implements an upgradeability mechanism designed for UUPS proxies.
8
+ /// @dev Adapted from <https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.9.0/contracts/proxy/utils/UUPSUpgradeable.sol>
9
+ /// The functions included here can perform an upgrade of an UUPS Proxy, when this contract is set as the implementation behind such a proxy.
10
+ ///
11
+ /// IMPORTANT: A UUPS proxy requires its upgradeability functions to be in the implementation as opposed to the transparent proxy.
12
+ /// This means that if the proxy is upgraded to an implementation that does not support this interface, it will no longer be upgradeable.
13
+ ///
14
+ /// A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is
15
+ /// reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing
16
+ /// `UUPSProxiable` with a custom implementation of upgrades.
17
+ ///
18
+ /// The `_authorizeUpgrade` function must be overridden to include access restriction to the upgrade mechanism.
28
19
abstract contract UUPSProxiable {
29
20
// ************************************* //
30
21
// * Event * //
31
22
// ************************************* //
32
23
33
- /**
34
- * Emitted when the `implementation` has been successfully upgraded.
35
- * @param newImplementation Address of the new implementation the proxy is now forwarding calls to.
36
- */
24
+ /// @dev Emitted when the `implementation` has been successfully upgraded.
25
+ /// @param newImplementation Address of the new implementation the proxy is now forwarding calls to.
37
26
event Upgraded (address indexed newImplementation );
38
27
39
28
// ************************************* //
40
29
// * Error * //
41
30
// ************************************* //
42
31
43
- /**
44
- * @dev The call is from an unauthorized context.
45
- */
32
+ /// @dev The call is from an unauthorized context.
46
33
error UUPSUnauthorizedCallContext ();
47
34
48
- /**
49
- * @dev The storage `slot` is unsupported as a UUID.
50
- */
35
+ /// @dev The storage `slot` is unsupported as a UUID.
51
36
error UUPSUnsupportedProxiableUUID (bytes32 slot );
52
37
53
- /// The `implementation` is not UUPS-compliant
38
+ /// @dev The `implementation` is not UUPS-compliant
54
39
error InvalidImplementation (address implementation );
55
40
56
41
/// Failed Delegated call
@@ -60,48 +45,40 @@ abstract contract UUPSProxiable {
60
45
// * Storage * //
61
46
// ************************************* //
62
47
63
- /**
64
- * @dev Storage slot with the address of the current implementation.
65
- * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
66
- * validated in the constructor.
67
- * NOTE: bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1)
68
- */
48
+ /// @dev Storage slot with the address of the current implementation.
49
+ /// @dev This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
50
+ /// @dev validated in the constructor.
51
+ /// @dev NOTE: bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1)
69
52
bytes32 private constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc ;
70
53
71
- /**
72
- * @dev Storage variable of the proxiable contract address.
73
- * It is used to check whether or not the current call is from the proxy.
74
- */
54
+ /// @dev Storage variable of the proxiable contract address.
55
+ /// @dev It is used to check whether or not the current call is from the proxy.
56
+ /// @custom:oz-upgrades-unsafe-allow state-variable-immutable
75
57
address private immutable __self = address (this );
76
58
77
59
// ************************************* //
78
60
// * Governance * //
79
61
// ************************************* //
80
62
81
- /**
82
- * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract.
83
- * @dev Called by {upgradeToAndCall}.
84
- */
63
+ /// @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract.
64
+ /// @dev Called by {upgradeToAndCall}.
85
65
function _authorizeUpgrade (address newImplementation ) internal virtual ;
86
66
87
67
// ************************************* //
88
68
// * State Modifiers * //
89
69
// ************************************* //
90
70
91
- /**
92
- * @dev Upgrade mechanism including access control and UUPS-compliance.
93
- * @param newImplementation Address of the new implementation contract.
94
- * @param data Data used in a delegate call to `newImplementation` if non-empty. This will typically be an encoded
95
- * function call, and allows initializing the storage of the proxy like a Solidity constructor.
96
- *
97
- * @dev Reverts if the execution is not performed via delegatecall or the execution
98
- * context is not of a proxy with an ERC1967-compliant implementation pointing to self.
99
- */
71
+ /// @dev Upgrade mechanism including access control and UUPS-compliance.
72
+ /// @param newImplementation Address of the new implementation contract.
73
+ /// @param data Data used in a delegate call to `newImplementation` if non-empty. This will typically be an encoded
74
+ /// function call, and allows initializing the storage of the proxy like a Solidity constructor.
75
+ /// @dev Reverts if the execution is not performed via delegatecall or the execution
76
+ /// context is not of a proxy with an ERC1967-compliant implementation pointing to self.
100
77
function upgradeToAndCall (address newImplementation , bytes memory data ) public payable virtual {
101
78
_authorizeUpgrade (newImplementation);
102
79
103
- /* Check that the execution is being performed through a delegatecall call and that the execution context is
104
- a proxy contract with an implementation (as defined in ERC1967) pointing to self. */
80
+ // Check that the execution is being performed through a delegatecall call and that the execution context is
81
+ // a proxy contract with an implementation (as defined in ERC1967) pointing to self.
105
82
if (address (this ) == __self || _getImplementation () != __self) {
106
83
revert UUPSUnauthorizedCallContext ();
107
84
}
@@ -118,6 +95,7 @@ abstract contract UUPSProxiable {
118
95
119
96
if (data.length != 0 ) {
120
97
// The return data is not checked (checking, in case of success, that the newImplementation code is non-empty if the return data is empty) because the authorized callee is trusted.
98
+ /// @custom:oz-upgrades-unsafe-allow delegatecall
121
99
(bool success , ) = newImplementation.delegatecall (data);
122
100
if (! success) {
123
101
revert FailedDelegateCall ();
@@ -132,14 +110,12 @@ abstract contract UUPSProxiable {
132
110
// * Public Views * //
133
111
// ************************************* //
134
112
135
- /**
136
- * @dev Implementation of the ERC1822 `proxiableUUID` function. This returns the storage slot used by the
137
- * implementation. It is used to validate the implementation's compatibility when performing an upgrade.
138
- *
139
- * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
140
- * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
141
- * function revert if invoked through a proxy. This is guaranteed by the if statement.
142
- */
113
+ /// @dev Implementation of the ERC1822 `proxiableUUID` function. This returns the storage slot used by the
114
+ /// implementation. It is used to validate the implementation's compatibility when performing an upgrade.
115
+ ///
116
+ /// IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
117
+ /// bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
118
+ /// function revert if invoked through a proxy. This is guaranteed by the if statement.
143
119
function proxiableUUID () external view virtual returns (bytes32 ) {
144
120
if (address (this ) != __self) {
145
121
// Must not be called through delegatecall
@@ -148,10 +124,8 @@ abstract contract UUPSProxiable {
148
124
return IMPLEMENTATION_SLOT;
149
125
}
150
126
151
- /**
152
- * @notice Returns the version of the contract.
153
- * @return Version string.
154
- */
127
+ /// @dev Returns the version of the implementation.
128
+ /// @return Version string.
155
129
function version () external view virtual returns (string memory );
156
130
157
131
// ************************************* //
0 commit comments