Update "Using with Upgrades" page for 5.0 (#4659)

(cherry picked from commit 0f89a7e5f8)
pull/4662/head
Eric Lau 1 year ago
parent bd25a0a26f
commit 6a0cfcedf0
  1. 20
      docs/modules/ROOT/pages/upgradeable.adoc

@ -2,7 +2,7 @@
If your contract is going to be deployed with upgradeability, such as using the xref:upgrades-plugins::index.adoc[OpenZeppelin Upgrades Plugins], you will need to use the Upgradeable variant of OpenZeppelin Contracts.
This variant is available as a separate package called `@openzeppelin/contracts-upgradeable`, which is hosted in the repository https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable[OpenZeppelin/openzeppelin-contracts-upgradeable].
This variant is available as a separate package called `@openzeppelin/contracts-upgradeable`, which is hosted in the repository https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable[OpenZeppelin/openzeppelin-contracts-upgradeable]. It uses `@openzeppelin/contracts` as a peer dependency.
It follows all of the rules for xref:upgrades-plugins::writing-upgradeable.adoc[Writing Upgradeable Contracts]: constructors are replaced by initializer functions, state variables are initialized in initializer functions, and we additionally check for storage incompatibilities across minor versions.
@ -13,12 +13,12 @@ TIP: OpenZeppelin provides a full suite of tools for deploying and securing upgr
=== Installation
```console
$ npm install @openzeppelin/contracts-upgradeable
$ npm install @openzeppelin/contracts-upgradeable @openzeppelin/contracts
```
=== Usage
The package replicates the structure of the main OpenZeppelin Contracts package, but every file and contract has the suffix `Upgradeable`.
The Upgradeable package replicates the structure of the main OpenZeppelin Contracts package, but every file and contract has the suffix `Upgradeable`.
```diff
-import {ERC721} from "@openzeppelin/contracts/token/ERC721/ERC721.sol";
@ -28,6 +28,8 @@ The package replicates the structure of the main OpenZeppelin Contracts package,
+contract MyCollectible is ERC721Upgradeable {
```
NOTE: Interfaces and libraries are not included in the Upgradeable package, but are instead imported from the main OpenZeppelin Contracts package.
Constructors are replaced by internal initializer functions following the naming convention `+__{ContractName}_init+`. Since these are internal, you must always define your own public initializer function and call the parent initializer of the contract you extend.
```diff
@ -50,8 +52,8 @@ async function main() {
const mc = await upgrades.deployProxy(MyCollectible);
await mc.deployed();
console.log("MyCollectible deployed to:", mc.address);
await mc.waitForDeployment();
console.log("MyCollectible deployed to:", await mc.getAddress());
}
main();
@ -66,8 +68,10 @@ Initializer functions are not linearized by the compiler like constructors. Beca
The function `+__{ContractName}_init_unchained+` found in every contract is the initializer function minus the calls to parent initializers, and can be used to avoid the double initialization problem, but doing this manually is not recommended. We hope to be able to implement safety checks for this in future versions of the Upgrades Plugins.
=== Storage Gaps
=== Namespaced Storage
You may notice that contracts use a struct with the `@custom:storage-location erc7201:<NAMESPACE_ID>` annotation to store the contract's state variables. This follows the https://eips.ethereum.org/EIPS/eip-7201[ERC-7201: Namespaced Storage Layout] pattern, where each contract has its own storage layout in a namespace that is separate from other contracts in the inheritance chain.
You may notice that every contract includes a state variable named `+__gap+`. This is empty reserved space in storage that is put in place in Upgradeable contracts. It allows us to freely add new state variables in the future without compromising the storage compatibility with existing deployments.
Without namespaced storage, it isn't safe to simply add a state variable because it "shifts down" all of the state variables below in the inheritance chain. This makes the storage layouts incompatible, as explained in xref:upgrades-plugins::writing-upgradeable.adoc#modifying-your-contracts[Writing Upgradeable Contracts].
It isn't safe to simply add a state variable because it "shifts down" all of the state variables below in the inheritance chain. This makes the storage layouts incompatible, as explained in xref:upgrades-plugins::writing-upgradeable.adoc#modifying-your-contracts[Writing Upgradeable Contracts]. The size of the `+__gap+` array is calculated so that the amount of storage used by a contract always adds up to the same number (in this case 50 storage slots).
The namespaced storage pattern used in the Upgradeable package allows us to freely add new state variables in the future without compromising the storage compatibility with existing deployments. It also allows changing the inheritance order with no impact on the resulting storage layout, as long as all inherited contracts use namespaced storage.
Loading…
Cancel
Save