0
# Proxy and Upgradeability
1
2
Core upgradeability infrastructure including the Initializable base contract and UUPS upgrade pattern for implementing upgradeable smart contracts with secure state preservation.
3
4
## Capabilities
5
6
### Initializable Base Contract
7
8
Foundational contract that controls the initialization of upgradeable contracts.
9
10
```solidity { .api }
11
/**
12
* @dev Helper to support initializer functions
13
*/
14
abstract contract Initializable {
15
/**
16
* @dev Triggered when the contract has been initialized or reinitialized
17
*/
18
event Initialized(uint64 version);
19
20
/**
21
* @dev Modifier used by the initializer function of a contract
22
*/
23
modifier initializer();
24
25
/**
26
* @dev Modifier used by reinitializer functions
27
*/
28
modifier reinitializer(uint64 version);
29
30
/**
31
* @dev Modifier that restricts functions to the initializing phase
32
*/
33
modifier onlyInitializing();
34
35
/**
36
* @dev Locks the contract, preventing any future reinitialization
37
*/
38
function _disableInitializers() internal;
39
40
/**
41
* @dev Returns the highest version that has been initialized
42
*/
43
function _getInitializedVersion() internal view returns (uint64);
44
45
/**
46
* @dev Returns true if the contract is currently initializing
47
*/
48
function _isInitializing() internal view returns (bool);
49
}
50
```
51
52
### UUPS Upgradeable Pattern
53
54
Universal Upgradeable Proxy Standard implementation that allows contracts to upgrade themselves.
55
56
```solidity { .api }
57
/**
58
* @dev Implementation of the UUPS (Universal Upgradeable Proxy Standard) pattern
59
*/
60
abstract contract UUPSUpgradeable {
61
function __UUPSUpgradeable_init() internal onlyInitializing;
62
63
/**
64
* @dev The version of the upgrade interface of the contract
65
*/
66
string constant UPGRADE_INTERFACE_VERSION = "5.0.0";
67
68
/**
69
* @dev Storage slot with the address of the current implementation
70
*/
71
bytes32 internal constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
72
73
/**
74
* @dev Upgrade the implementation of the proxy to newImplementation and call a function on the new implementation
75
*/
76
function upgradeToAndCall(address newImplementation, bytes memory data) external payable;
77
78
/**
79
* @dev Returns the current implementation address
80
*/
81
function proxiableUUID() external view returns (bytes32);
82
83
/**
84
* @dev Function that should revert when msg.sender is not authorized to upgrade the contract
85
*/
86
function _authorizeUpgrade(address newImplementation) internal virtual;
87
88
/**
89
* @dev Returns the current implementation address
90
*/
91
function _getImplementation() internal view returns (address);
92
93
/**
94
* @dev Stores a new address in the EIP-1967 implementation slot
95
*/
96
function _setImplementation(address newImplementation) private;
97
}
98
99
// Events
100
event Upgraded(address indexed implementation);
101
```
102
103
## Upgrade Patterns
104
105
### Storage Layout Considerations
106
107
All upgradeable contracts use ERC-7201 namespaced storage to prevent storage collisions:
108
109
```solidity
110
// Example storage pattern used in upgradeable contracts
111
struct ContractNameStorage {
112
// Contract state variables
113
mapping(address => uint256) _balances;
114
uint256 _totalSupply;
115
string _name;
116
string _symbol;
117
}
118
119
// Storage location calculation
120
bytes32 private constant ContractNameStorageLocation =
121
keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ContractName")) - 1)) & ~bytes32(uint256(0xff));
122
123
function _getContractNameStorage() private pure returns (ContractNameStorage storage $) {
124
assembly {
125
$.slot := ContractNameStorageLocation
126
}
127
}
128
```
129
130
### Initialization Pattern
131
132
Standard initialization pattern for upgradeable contracts:
133
134
```solidity
135
// Internal initialization functions
136
function __ContractName_init(/* parameters */) internal onlyInitializing {
137
__ContractName_init_unchained(/* parameters */);
138
}
139
140
function __ContractName_init_unchained(/* parameters */) internal onlyInitializing {
141
ContractNameStorage storage $ = _getContractNameStorage();
142
// Initialize contract state
143
}
144
```
145
146
## Usage Examples
147
148
### Basic Upgradeable Contract
149
150
```solidity
151
import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
152
import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
153
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
154
155
contract MyUpgradeableContract is Initializable, UUPSUpgradeable, OwnableUpgradeable {
156
uint256 public value;
157
158
/// @custom:oz-upgrades-unsafe-allow constructor
159
constructor() {
160
_disableInitializers();
161
}
162
163
function initialize(address initialOwner, uint256 initialValue) initializer public {
164
__Ownable_init(initialOwner);
165
__UUPSUpgradeable_init();
166
value = initialValue;
167
}
168
169
function setValue(uint256 newValue) public onlyOwner {
170
value = newValue;
171
}
172
173
function _authorizeUpgrade(address newImplementation) internal override onlyOwner {}
174
}
175
```
176
177
### Upgradeable Token Contract
178
179
```solidity
180
import {ERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";
181
import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
182
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
183
184
contract UpgradeableToken is ERC20Upgradeable, UUPSUpgradeable, OwnableUpgradeable {
185
/// @custom:oz-upgrades-unsafe-allow constructor
186
constructor() {
187
_disableInitializers();
188
}
189
190
function initialize(
191
string memory name,
192
string memory symbol,
193
address initialOwner,
194
uint256 initialSupply
195
) initializer public {
196
__ERC20_init(name, symbol);
197
__Ownable_init(initialOwner);
198
__UUPSUpgradeable_init();
199
200
if (initialSupply > 0) {
201
_mint(initialOwner, initialSupply);
202
}
203
}
204
205
function mint(address to, uint256 amount) public onlyOwner {
206
_mint(to, amount);
207
}
208
209
function _authorizeUpgrade(address newImplementation) internal override onlyOwner {}
210
}
211
```
212
213
### Contract V2 with New Features
214
215
```solidity
216
// Upgraded version of the contract with new functionality
217
contract MyUpgradeableContractV2 is MyUpgradeableContract {
218
uint256 public newFeature;
219
220
function initializeV2(uint256 newFeatureValue) reinitializer(2) public {
221
newFeature = newFeatureValue;
222
}
223
224
function setNewFeature(uint256 newValue) public onlyOwner {
225
newFeature = newValue;
226
}
227
228
function getVersion() public pure returns (string memory) {
229
return "2.0.0";
230
}
231
}
232
```
233
234
### Deployment Script Pattern
235
236
```solidity
237
// Example deployment script for upgradeable contracts
238
import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
239
240
contract DeployUpgradeable {
241
function deploy() external returns (address) {
242
// Deploy implementation
243
MyUpgradeableContract implementation = new MyUpgradeableContract();
244
245
// Encode initializer call
246
bytes memory data = abi.encodeCall(
247
MyUpgradeableContract.initialize,
248
(msg.sender, 100) // initialOwner, initialValue
249
);
250
251
// Deploy proxy
252
ERC1967Proxy proxy = new ERC1967Proxy(address(implementation), data);
253
254
return address(proxy);
255
}
256
}
257
```
258
259
## Best Practices
260
261
### Constructor Disabling
262
263
Always disable initializers in the constructor to prevent initialization of the implementation contract:
264
265
```solidity
266
/// @custom:oz-upgrades-unsafe-allow constructor
267
constructor() {
268
_disableInitializers();
269
}
270
```
271
272
### Storage Gap Pattern
273
274
For contracts that may be inherited, consider adding storage gaps:
275
276
```solidity
277
// Reserve storage slots for future variables
278
uint256[50] private __gap;
279
```
280
281
### Upgrade Authorization
282
283
Always implement proper authorization for upgrades:
284
285
```solidity
286
function _authorizeUpgrade(address newImplementation) internal override onlyOwner {
287
// Additional upgrade validation logic can be added here
288
}
289
```