Skip to content

Commit

Permalink
feat: 🎸 upgraded to suport openzeppelin 5.0
Browse files Browse the repository at this point in the history
  • Loading branch information
oleggrib committed Jan 8, 2024
1 parent 4ef7a83 commit a53a19b
Show file tree
Hide file tree
Showing 10 changed files with 194 additions and 139 deletions.
27 changes: 15 additions & 12 deletions contracts/helpers/ExampleERC721.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ import "../package/tokens/extensions/Minter.sol";
import "../package/tokens/extensions/ParentContracts.sol";
import "../package/tokens/extensions/SharedHolders.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "../package/tokens/OptimizedEnumerable.sol";
import "../package/tokens/ERC721OptimizedEnumerable.sol";
import "../package/royalty/ERC2981RoyaltyFull.sol";

contract ExampleERC721 is Ownable, ERC2981RoyaltyFull, Minter, SharedHolders, ParentContracts, OptimizedEnumerable {
constructor(string memory name, string memory symbol) OptimizedEnumerable(name, symbol) Ownable(msg.sender) {}
contract ExampleERC721 is Ownable, ERC2981RoyaltyFull, Minter, SharedHolders, ParentContracts, ERC721OptimizedEnumerable {

Check warning on line 12 in contracts/helpers/ExampleERC721.sol

View workflow job for this annotation

GitHub Actions / solhint

Line length must be no more than 120 but current length is 122
constructor(string memory name, string memory symbol) ERC721OptimizedEnumerable(name, symbol) Ownable(msg.sender) {}

function _authorizeAddParent(address newContract) internal override onlyOwner {}

Expand All @@ -22,9 +22,16 @@ contract ExampleERC721 is Ownable, ERC2981RoyaltyFull, Minter, SharedHolders, Pa
address to,
uint256 tokenId,
address auth
) internal override(Minter, OptimizedEnumerable) returns (address) {
) internal override(Minter, ERC721OptimizedEnumerable) returns (address) {
Minter._update(to, tokenId, auth);
return OptimizedEnumerable._update(to, tokenId, auth);
return ERC721OptimizedEnumerable._update(to, tokenId, auth);
}

function _exists(uint256 tokenId) internal view virtual override returns (bool){
if (_ownerOf(tokenId) == address(0)){
return false;
}
return true;
}

function _ownerOf(
Expand All @@ -33,12 +40,8 @@ contract ExampleERC721 is Ownable, ERC2981RoyaltyFull, Minter, SharedHolders, Pa
return ERC721._ownerOf(tokenId);
}

function _exists(uint256 tokenId) internal view override(ERC2981RoyaltyFull, OptimizedEnumerable) returns (bool) {
return OptimizedEnumerable._exists(tokenId);
}

function mint(address to) public virtual {
OptimizedEnumerable._mint(to);
ERC721OptimizedEnumerable._mint(to);
}

function burn(uint256 tokenId) public virtual {
Expand All @@ -52,8 +55,8 @@ contract ExampleERC721 is Ownable, ERC2981RoyaltyFull, Minter, SharedHolders, Pa

function supportsInterface(
bytes4 interfaceId
) public view virtual override(OptimizedEnumerable, DerivedERC2981Royalty) returns (bool) {
) public view virtual override(ERC721OptimizedEnumerable, DerivedERC2981Royalty) returns (bool) {
return
OptimizedEnumerable.supportsInterface(interfaceId) || DerivedERC2981Royalty.supportsInterface(interfaceId);
ERC721OptimizedEnumerable.supportsInterface(interfaceId) || DerivedERC2981Royalty.supportsInterface(interfaceId);

Check warning on line 60 in contracts/helpers/ExampleERC721.sol

View workflow job for this annotation

GitHub Actions / solhint

Line length must be no more than 120 but current length is 125
}
}
2 changes: 1 addition & 1 deletion contracts/package/ERC/IERC5169.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,6 @@ interface IERC5169 {
function scriptURI() external view returns (string[] memory);

/// @notice Update the scriptURI
/// emits event ScriptUpdate(scriptURI memory newScriptURI);
/// emits event ScriptUpdate(string[])
function setScriptURI(string[] memory) external;
}
7 changes: 7 additions & 0 deletions contracts/package/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
## Changes

### v2.5.0
ERC721OptimizedEnumerable + ERC721OptimizedEnumerableUpgradeable refactored for Openzeppelin v5.x

### v2.4.0
Compatability with Openzeppelin v5.x
2 changes: 1 addition & 1 deletion contracts/package/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "stl-contracts",
"version": "2.4.0",
"version": "2.5.1",
"description": "STL contracts",
"repository": {
"type": "git",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,52 +2,70 @@

pragma solidity ^0.8.20;

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol";
import "@openzeppelin/contracts/interfaces/IERC165.sol";
// import "./OptimizedEnumerableBase.sol";

// disable "is IERC721Enumerable" to avoid multiple methods override for OptimizedEnumerableUpgradeable
abstract contract OptimizedEnumerableBase is IERC165 {
contract ERC721OptimizedEnumerable is ERC721 {

uint private _tokenIdCounter;

// count burnt token number to calc totalSupply()
uint256 private _burnt;

//slither-disable-next-line dead-code
function _update(address to, uint256, address) internal virtual returns (address) {
error IndexOutOfBounds();
error ZeroAddressCantBeOwner();

function _update(address to, uint256 tokenId, address from) internal virtual override returns (address) {
if (to == address(0)) {
_burnt++;
}
return address(0);
}
return ERC721._update(to, tokenId, from);
}

function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
return interfaceId == type(IERC721Enumerable).interfaceId || interfaceId == type(IERC165).interfaceId;
constructor(string memory name_, string memory symbol_) ERC721(name_, symbol_) {}

function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return
interfaceId == type(IERC721Enumerable).interfaceId
|| super.supportsInterface(interfaceId);
}

function balanceOf(address owner) public view virtual returns (uint256 balance);
function _mint(address to) internal {
uint newTokenId = _prepareTokenId();
ERC721._mint(to, newTokenId);
}

function ownerOf(uint256 tokenId) public view virtual returns (address owner);
function getNextTokenId() internal view returns (uint){
return _tokenIdCounter;
}

function _exists(uint256 tokenId) internal view virtual returns (bool);
function _prepareTokenId() internal returns (uint) {
return _tokenIdCounter++;
}

/**
* Foreach all minted tokens until reached appropriate index
*/
function tokenOfOwnerByIndex(address owner, uint256 index) public view virtual returns (uint256) {
require(index < balanceOf(owner), "Owner index out of bounds");

uint256 numMinted = _tokenIdCounter;
if (index >= balanceOf(owner)){
revert IndexOutOfBounds();
}

if (owner == address(0)){
revert ZeroAddressCantBeOwner();
}

uint256 numMinted = getNextTokenId();
uint256 tokenIdsIdx = 0;

// Counter overflow is impossible as the loop breaks when uint256 i is equal to another uint256 numMintedSoFar.
unchecked {
for (uint256 i = 0; i < numMinted; i++) {
if (_exists(i) && (ownerOf(i) == owner)) {
for (uint256 i = 0; i < numMinted; i++) {
if (_ownerOf(i) == owner) {
if (tokenIdsIdx == index) {
return i;
}
tokenIdsIdx = tokenIdsIdx + 1;
tokenIdsIdx++;
}
}
}
Expand All @@ -59,23 +77,24 @@ abstract contract OptimizedEnumerableBase is IERC165 {
}

function totalSupply() public view virtual returns (uint256) {
return _tokenIdCounter - _burnt;
return getNextTokenId() - _burnt;
}

/**
* @dev See {IERC721Enumerable-tokenByIndex}.
*/
function tokenByIndex(uint256 index) public view virtual returns (uint256) {
uint256 numMintedSoFar = _tokenIdCounter;
uint256 numMintedSoFar = getNextTokenId();

require(index < totalSupply(), "Index out of bounds");
if (index >= totalSupply()){
revert IndexOutOfBounds();
}

uint256 tokenIdsIdx = 0;

// Counter overflow is impossible as the loop breaks when uint256 i is equal to another uint256 numMintedSoFar.
unchecked {
for (uint256 i = 0; i < numMintedSoFar; i++) {
if (_exists(i)) {
if (_ownerOf(i) != address(0)) {
if (tokenIdsIdx == index) {
return i;
}
Expand All @@ -86,12 +105,9 @@ abstract contract OptimizedEnumerableBase is IERC165 {

// Execution should never reach this point.
assert(false);
// added to stop compiler warnings
return 0;
}

function _prepareTokenId() internal returns (uint) {
uint newTokenId = _tokenIdCounter;
_tokenIdCounter++;
return newTokenId;
}
}


122 changes: 122 additions & 0 deletions contracts/package/tokens/ERC721OptimizedEnumerableUpgradeable.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.20;

import "@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol";

contract ERC721OptimizedEnumerableUpgradeable is IERC721Enumerable, ERC721Upgradeable {

error IndexOutOfBounds();
error ZeroAddressCantBeOwner();

struct ERC721EnumStorage {
uint _tokenIdCounter;
// count burnt token number to calc totalSupply()
uint256 _burnt;
}

function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721Upgradeable, IERC165) returns (bool) {
return
interfaceId == type(IERC721Enumerable).interfaceId
|| super.supportsInterface(interfaceId);
}

// keccak256(abi.encode(uint256(keccak256("stl.storage.ERC721OptimizedEnumerable")) - 1))
bytes32 private constant ERC721OptimizedEnumerableLocation = 0x0c12c17af20e858ae142203eca79d9fe977cde9a6d2226d7db28f4c9277f8085;

function _getERC721EnumStorage() private pure returns (ERC721EnumStorage storage $) {
assembly {
$.slot := ERC721OptimizedEnumerableLocation
}
}

function _update(address to, uint256 tokenId, address from) internal virtual override returns (address) {
if (to == address(0)) {
ERC721EnumStorage storage $ = _getERC721EnumStorage();
$._burnt++;
}
return ERC721Upgradeable._update(to, tokenId, from);
}

function getNextTokenId() internal view returns (uint){
ERC721EnumStorage storage $ = _getERC721EnumStorage();
return $._tokenIdCounter;
}

function _prepareTokenId() internal returns (uint) {
ERC721EnumStorage storage $ = _getERC721EnumStorage();
uint newTokenId = $._tokenIdCounter++;
return newTokenId;
}

Check notice on line 51 in contracts/package/tokens/ERC721OptimizedEnumerableUpgradeable.sol

View workflow job for this annotation

GitHub Actions / slither

3-1-dead-code

ERC721OptimizedEnumerableUpgradeable._prepareTokenId() (contracts/package/tokens/ERC721OptimizedEnumerableUpgradeable.sol#47-51) is never used and should be removed

/**
* Foreach all minted tokens until reached appropriate index
*/
function tokenOfOwnerByIndex(address owner, uint256 index) public view virtual returns (uint256) {
if (index >= balanceOf(owner)){
revert IndexOutOfBounds();
}

if (owner == address(0)){
revert ZeroAddressCantBeOwner();
}

uint256 numMinted = getNextTokenId();
uint256 tokenIdsIdx = 0;

unchecked {
for (uint256 i = 0; i < numMinted; i++) {
if (_ownerOf(i) == owner) {
if (tokenIdsIdx == index) {
return i;
}
tokenIdsIdx++;
}
}
}

// Execution should never reach this point.
assert(false);
// added to stop compiler warnings
return 0;
}

function totalSupply() public view virtual returns (uint256) {
ERC721EnumStorage storage $ = _getERC721EnumStorage();
return $._tokenIdCounter - $._burnt;
}

/**
* @dev See {IERC721Enumerable-tokenByIndex}.
*/
function tokenByIndex(uint256 index) public view virtual returns (uint256) {
uint256 numMintedSoFar = getNextTokenId();

if (index >= totalSupply()){
revert IndexOutOfBounds();
}

uint256 tokenIdsIdx = 0;

unchecked {
for (uint256 i = 0; i < numMintedSoFar; i++) {
if (_ownerOf(i) != address(0)) {
if (tokenIdsIdx == index) {
return i;
}
tokenIdsIdx++;
}
}
}

// Execution should never reach this point.
assert(false);
return 0;
}

function _mint(address to) internal {
uint newTokenId = _prepareTokenId();
ERC721Upgradeable._mint(to, newTokenId);
}

Check notice on line 121 in contracts/package/tokens/ERC721OptimizedEnumerableUpgradeable.sol

View workflow job for this annotation

GitHub Actions / slither

3-1-dead-code

ERC721OptimizedEnumerableUpgradeable._mint(address) (contracts/package/tokens/ERC721OptimizedEnumerableUpgradeable.sol#118-121) is never used and should be removed
}
47 changes: 0 additions & 47 deletions contracts/package/tokens/OptimizedEnumerable.sol

This file was deleted.

Loading

0 comments on commit a53a19b

Please sign in to comment.