Hey OZ Community!
I am trying to upgrade an ERC721Upgradeable contract without enumerability to extend it to have the enumerability features. Running into deploy time errors on the upgradeProxy
. See below for code examples and logs from the console on deploy.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721URIStorageUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721BurnableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
contract ERC721Non is Initializable, ERC721Upgradeable, ERC721URIStorageUpgradeable, PausableUpgradeable, AccessControlUpgradeable, ERC721BurnableUpgradeable, UUPSUpgradeable {
bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE");
bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
bytes32 public constant UPGRADER_ROLE = keccak256("UPGRADER_ROLE");
/// @custom:oz-upgrades-unsafe-allow constructor
constructor() initializer {}
function initialize() initializer public {
__ERC721_init("ERC721Non", "NON");
__ERC721URIStorage_init();
__Pausable_init();
__AccessControl_init();
__ERC721Burnable_init();
__UUPSUpgradeable_init();
_grantRole(DEFAULT_ADMIN_ROLE, msg.sender);
_grantRole(PAUSER_ROLE, msg.sender);
_grantRole(MINTER_ROLE, msg.sender);
_grantRole(UPGRADER_ROLE, msg.sender);
}
function pause() public onlyRole(PAUSER_ROLE) {
_pause();
}
function unpause() public onlyRole(PAUSER_ROLE) {
_unpause();
}
function safeMint(address to, uint256 tokenId, string memory uri)
public
onlyRole(MINTER_ROLE)
{
_safeMint(to, tokenId);
_setTokenURI(tokenId, uri);
}
function _beforeTokenTransfer(address from, address to, uint256 tokenId)
internal
whenNotPaused
override
{
super._beforeTokenTransfer(from, to, tokenId);
}
function _authorizeUpgrade(address newImplementation)
internal
onlyRole(UPGRADER_ROLE)
override
{}
// The following functions are overrides required by Solidity.
function _burn(uint256 tokenId)
internal
override(ERC721Upgradeable, ERC721URIStorageUpgradeable)
{
super._burn(tokenId);
}
function tokenURI(uint256 tokenId)
public
view
override(ERC721Upgradeable, ERC721URIStorageUpgradeable)
returns (string memory)
{
return super.tokenURI(tokenId);
}
function supportsInterface(bytes4 interfaceId)
public
view
override(ERC721Upgradeable, AccessControlUpgradeable)
returns (bool)
{
return super.supportsInterface(interfaceId);
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721EnumerableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721URIStorageUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721BurnableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
contract ERC721Is is Initializable, ERC721Upgradeable, ERC721EnumerableUpgradeable, ERC721URIStorageUpgradeable, PausableUpgradeable, AccessControlUpgradeable, ERC721BurnableUpgradeable, UUPSUpgradeable {
bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE");
bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
bytes32 public constant UPGRADER_ROLE = keccak256("UPGRADER_ROLE");
/// @custom:oz-upgrades-unsafe-allow constructor
constructor() initializer {}
function initialize() initializer public {
__ERC721_init("ERC721Is", "IS");
__ERC721Enumerable_init();
__ERC721URIStorage_init();
__Pausable_init();
__AccessControl_init();
__ERC721Burnable_init();
__UUPSUpgradeable_init();
_grantRole(DEFAULT_ADMIN_ROLE, msg.sender);
_grantRole(PAUSER_ROLE, msg.sender);
_grantRole(MINTER_ROLE, msg.sender);
_grantRole(UPGRADER_ROLE, msg.sender);
}
function pause() public onlyRole(PAUSER_ROLE) {
_pause();
}
function unpause() public onlyRole(PAUSER_ROLE) {
_unpause();
}
function safeMint(address to, uint256 tokenId, string memory uri)
public
onlyRole(MINTER_ROLE)
{
_safeMint(to, tokenId);
_setTokenURI(tokenId, uri);
}
function _beforeTokenTransfer(address from, address to, uint256 tokenId)
internal
whenNotPaused
override(ERC721Upgradeable, ERC721EnumerableUpgradeable)
{
super._beforeTokenTransfer(from, to, tokenId);
}
function _authorizeUpgrade(address newImplementation)
internal
onlyRole(UPGRADER_ROLE)
override
{}
// The following functions are overrides required by Solidity.
function _burn(uint256 tokenId)
internal
override(ERC721Upgradeable, ERC721URIStorageUpgradeable)
{
super._burn(tokenId);
}
function tokenURI(uint256 tokenId)
public
view
override(ERC721Upgradeable, ERC721URIStorageUpgradeable)
returns (string memory)
{
return super.tokenURI(tokenId);
}
function supportsInterface(bytes4 interfaceId)
public
view
override(ERC721Upgradeable, ERC721EnumerableUpgradeable, AccessControlUpgradeable)
returns (bool)
{
return super.supportsInterface(interfaceId);
}
}
Here is the console output on upgradeProxy
.
StorageUpgradeErrors: New storage layout is incompatible
@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721EnumerableUpgradeable.sol:22: Inserted `_ownedTokens`
> New variables should be placed after all existing inherited variables
@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721EnumerableUpgradeable.sol:25: Inserted `_ownedTokensIndex`
> New variables should be placed after all existing inherited variables
@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721EnumerableUpgradeable.sol:28: Inserted `_allTokens`
> New variables should be placed after all existing inherited variables
@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721EnumerableUpgradeable.sol:31: Inserted `_allTokensIndex`
> New variables should be placed after all existing inherited variables
@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721EnumerableUpgradeable.sol:175: Inserted `__gap`
> New variables should be placed after all existing inherited variables
at assertStorageUpgradeSafe (/Users/nolanjacobson/DraftKings-ERC721-Upgradeable-DK-Demo/node_modules/@openzeppelin/upgrades-core/dist/storage/index.js:27:15)
at deployImpl (/Users/nolanjacobson/DraftKings-ERC721-Upgradeable-DK-Demo/node_modules/@openzeppelin/hardhat-upgrades/dist/utils/deploy-impl.js:49:58)
at async Proxy.upgradeProxy (/Users/nolanjacobson/DraftKings-ERC721-Upgradeable-DK-Demo/node_modules/@openzeppelin/hardhat-upgrades/dist/upgrade-proxy.js:9:36)
at async main (/Users/nolanjacobson/DraftKings-ERC721-Upgradeable-DK-Demo/scripts/deploy_upgradable.js:13:20) {
report: LayoutCompatibilityReport {
ops: [
{
kind: 'insert',
totalCost: 2,
predecessor: {
kind: 'nop',
totalCost: 0,
predecessor: { kind: 'nop', totalCost: 0, predecessor: [Object] }
},
updated: {
label: '_ownedTokens',
offset: 0,
slot: '151',
type: {
id: 't_mapping(t_address,t_mapping(t_uint256,t_uint256))',
head: 't_mapping',
args: [Array],
tail: undefined,
rets: undefined,
item: [Object]
},
contract: 'ERC721EnumerableUpgradeable',
src: '@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721EnumerableUpgradeable.sol:22'
}
},
{
kind: 'insert',
totalCost: 4,
predecessor: {
kind: 'insert',
totalCost: 2,
predecessor: { kind: 'nop', totalCost: 0, predecessor: [Object] },
updated: {
label: '_ownedTokens',
offset: 0,
slot: '151',
type: [Object],
contract: 'ERC721EnumerableUpgradeable',
src: '@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721EnumerableUpgradeable.sol:22'
}
},
updated: {
label: '_ownedTokensIndex',
offset: 0,
slot: '152',
type: {
id: 't_mapping(t_uint256,t_uint256)',
head: 't_mapping',
args: [Array],
tail: undefined,
rets: undefined,
item: [Object]
},
contract: 'ERC721EnumerableUpgradeable',
src: '@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721EnumerableUpgradeable.sol:25'
}
},
{
kind: 'insert',
totalCost: 6,
predecessor: {
kind: 'insert',
totalCost: 4,
predecessor: {
kind: 'insert',
totalCost: 2,
predecessor: [Object],
updated: [Object]
},
updated: {
label: '_ownedTokensIndex',
offset: 0,
slot: '152',
type: [Object],
contract: 'ERC721EnumerableUpgradeable',
src: '@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721EnumerableUpgradeable.sol:25'
}
},
updated: {
label: '_allTokens',
offset: 0,
slot: '153',
type: {
id: 't_array(t_uint256)dyn_storage',
head: 't_array',
args: [Array],
tail: 'dyn_storage',
rets: undefined,
item: [Object]
},
contract: 'ERC721EnumerableUpgradeable',
src: '@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721EnumerableUpgradeable.sol:28'
}
},
{
kind: 'insert',
totalCost: 8,
predecessor: {
kind: 'insert',
totalCost: 6,
predecessor: {
kind: 'insert',
totalCost: 4,
predecessor: [Object],
updated: [Object]
},
updated: {
label: '_allTokens',
offset: 0,
slot: '153',
type: [Object],
contract: 'ERC721EnumerableUpgradeable',
src: '@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721EnumerableUpgradeable.sol:28'
}
},
updated: {
label: '_allTokensIndex',
offset: 0,
slot: '154',
type: {
id: 't_mapping(t_uint256,t_uint256)',
head: 't_mapping',
args: [Array],
tail: undefined,
rets: undefined,
item: [Object]
},
contract: 'ERC721EnumerableUpgradeable',
src: '@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721EnumerableUpgradeable.sol:31'
}
},
{
kind: 'insert',
totalCost: 10,
predecessor: {
kind: 'insert',
totalCost: 8,
predecessor: {
kind: 'insert',
totalCost: 6,
predecessor: [Object],
updated: [Object]
},
updated: {
label: '_allTokensIndex',
offset: 0,
slot: '154',
type: [Object],
contract: 'ERC721EnumerableUpgradeable',
src: '@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721EnumerableUpgradeable.sol:31'
}
},
updated: {
label: '__gap',
offset: 0,
slot: '155',
type: {
id: 't_array(t_uint256)46_storage',
head: 't_array',
args: [Array],
tail: '46_storage',
rets: undefined,
item: [Object]
},
contract: 'ERC721EnumerableUpgradeable',
src: '@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721EnumerableUpgradeable.sol:175'
}
}
]
}
}