From 039fb4a4b18c05fa88fab726873e5fcec97f0e62 Mon Sep 17 00:00:00 2001 From: huyhuynh3103 Date: Tue, 9 Apr 2024 14:35:13 +0700 Subject: [PATCH 01/22] forge install: openzeppelin-contracts-upgradeable v4.9.5 --- .gitmodules | 3 +++ lib/openzeppelin-contracts-upgradeable | 1 + 2 files changed, 4 insertions(+) create mode 160000 lib/openzeppelin-contracts-upgradeable diff --git a/.gitmodules b/.gitmodules index e3d8d16..3183c85 100644 --- a/.gitmodules +++ b/.gitmodules @@ -6,3 +6,6 @@ path = lib/openzeppelin-contracts url = https://github.com/openzeppelin/openzeppelin-contracts branch = v4.8.2 +[submodule "lib/openzeppelin-contracts-upgradeable"] + path = lib/openzeppelin-contracts-upgradeable + url = https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable diff --git a/lib/openzeppelin-contracts-upgradeable b/lib/openzeppelin-contracts-upgradeable new file mode 160000 index 0000000..a40cb0b --- /dev/null +++ b/lib/openzeppelin-contracts-upgradeable @@ -0,0 +1 @@ +Subproject commit a40cb0bda838c2ef3dfc252c179f5c37c32e80c4 From c20636c10a15e3dae845b725347c3e49e6b1ff41 Mon Sep 17 00:00:00 2001 From: huyhuynh3103 Date: Tue, 9 Apr 2024 16:56:18 +0700 Subject: [PATCH 02/22] feat: implement ERC721CommonUpgradeable --- src/upgradable/ERC721CommonUpgradeable.sol | 86 +++++++++ ...interPauserAutoIdCustomizedUpgradeable.sol | 170 ++++++++++++++++++ .../refs/ERC721NonceUpgradeable.sol | 36 ++++ 3 files changed, 292 insertions(+) create mode 100644 src/upgradable/ERC721CommonUpgradeable.sol create mode 100644 src/upgradable/ERC721PresetMinterPauserAutoIdCustomizedUpgradeable.sol create mode 100644 src/upgradable/refs/ERC721NonceUpgradeable.sol diff --git a/src/upgradable/ERC721CommonUpgradeable.sol b/src/upgradable/ERC721CommonUpgradeable.sol new file mode 100644 index 0000000..545f042 --- /dev/null +++ b/src/upgradable/ERC721CommonUpgradeable.sol @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.0; + +import "../refs/IERC721State.sol"; +import "./refs/ERC721NonceUpgradeable.sol"; +import "./ERC721PresetMinterPauserAutoIdCustomizedUpgradeable.sol"; + +abstract contract ERC721CommonUpgradeable is + ERC721NonceUpgradeable, + ERC721PresetMinterPauserAutoIdCustomizedUpgradeable, + IERC721State +{ + constructor() { + _disableInitializers(); + } + + /** + * @inheritdoc IERC721State + */ + function stateOf(uint256 _tokenId) external view virtual override returns (bytes memory) { + require(_exists(_tokenId), "ERC721Common: query for non-existent token"); + return abi.encodePacked(ownerOf(_tokenId), nonces[_tokenId], _tokenId); + } + + /** + * @dev Override `ERC721-_baseURI`. + */ + function _baseURI() + internal + view + virtual + override(ERC721Upgradeable, ERC721PresetMinterPauserAutoIdCustomizedUpgradeable) + returns (string memory) + { + return super._baseURI(); + } + + /** + * @dev Override `IERC165-supportsInterface`. + */ + function supportsInterface(bytes4 interfaceId) + public + view + virtual + override(ERC721Upgradeable, ERC721PresetMinterPauserAutoIdCustomizedUpgradeable) + returns (bool) + { + return super.supportsInterface(interfaceId); + } + + /** + * @dev Override `ERC721PresetMinterPauserAutoIdCustomized-_beforeTokenTransfer`. + */ + function _beforeTokenTransfer(address _from, address _to, uint256 _firstTokenId, uint256 _batchSize) + internal + virtual + override(ERC721NonceUpgradeable, ERC721PresetMinterPauserAutoIdCustomizedUpgradeable) + { + super._beforeTokenTransfer(_from, _to, _firstTokenId, _batchSize); + } + + /** + * @dev Bulk create new tokens for `_recipients`. Tokens ID will be automatically + * assigned (and available on the emitted {IERC721-Transfer} event), and the token + * URI autogenerated based on the base URI passed at construction. + * + * See {ERC721-_mint}. + * + * Requirements: + * + * - the caller must have the `MINTER_ROLE`. + */ + function bulkMint(address[] calldata _recipients) + external + virtual + onlyRole(MINTER_ROLE) + returns (uint256[] memory _tokenIds) + { + require(_recipients.length > 0, "ERC721Common: invalid array lengths"); + _tokenIds = new uint256[](_recipients.length); + + for (uint256 _i = 0; _i < _recipients.length; _i++) { + _tokenIds[_i] = _mintFor(_recipients[_i]); + } + } +} diff --git a/src/upgradable/ERC721PresetMinterPauserAutoIdCustomizedUpgradeable.sol b/src/upgradable/ERC721PresetMinterPauserAutoIdCustomizedUpgradeable.sol new file mode 100644 index 0000000..4f1491b --- /dev/null +++ b/src/upgradable/ERC721PresetMinterPauserAutoIdCustomizedUpgradeable.sol @@ -0,0 +1,170 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/presets/ERC721PresetMinterPauserAutoId.sol) + +pragma solidity ^0.8.0; + +import "../../lib/openzeppelin-contracts-upgradeable/contracts/token/ERC721/ERC721Upgradeable.sol"; +import "../../lib/openzeppelin-contracts-upgradeable/contracts/token/ERC721/extensions/ERC721EnumerableUpgradeable.sol"; +import "../../lib/openzeppelin-contracts-upgradeable/contracts/token/ERC721/extensions/ERC721BurnableUpgradeable.sol"; +import "../../lib/openzeppelin-contracts-upgradeable/contracts/token/ERC721/extensions/ERC721PausableUpgradeable.sol"; +import "../../lib/openzeppelin-contracts-upgradeable/contracts/access/AccessControlEnumerableUpgradeable.sol"; +import "../../lib/openzeppelin-contracts-upgradeable/contracts/utils/ContextUpgradeable.sol"; +import "../../lib/openzeppelin-contracts-upgradeable/contracts/utils/CountersUpgradeable.sol"; +import {Initializable} from "../../lib/openzeppelin-contracts-upgradeable/contracts/proxy/utils/Initializable.sol"; + +/** + * @dev {ERC721} token, including: + * + * - ability for holders to burn (destroy) their tokens + * - a minter role that allows for token minting (creation) + * - a pauser role that allows to stop all token transfers + * - token ID and URI autogeneration + * + * This contract uses {AccessControl} to lock permissioned functions using the + * different roles - head to its documentation for details. + * + * The account that deploys the contract will be granted the minter and pauser + * roles, as well as the default admin role, which will let it grant both minter + * and pauser roles to other accounts. + * + * _Deprecated in favor of https://wizard.openzeppelin.com/[Contracts Wizard]._ + */ +contract ERC721PresetMinterPauserAutoIdCustomizedUpgradeable is + Initializable, + ContextUpgradeable, + AccessControlEnumerableUpgradeable, + ERC721EnumerableUpgradeable, + ERC721BurnableUpgradeable, + ERC721PausableUpgradeable +{ + using CountersUpgradeable for CountersUpgradeable.Counter; + + bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); + bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE"); + + CountersUpgradeable.Counter private _tokenIdTracker; + + string private _baseTokenURI; + + function initialize(string memory name, string memory symbol, string memory baseTokenURI) public virtual initializer { + __ERC721PresetMinterPauserAutoId_init(name, symbol, baseTokenURI); + } + /** + * @dev Grants `DEFAULT_ADMIN_ROLE`, `MINTER_ROLE` and `PAUSER_ROLE` to the + * account that deploys the contract. + * + * Token URIs will be autogenerated based on `baseURI` and their token IDs. + * See {ERC721-tokenURI}. + */ + + function __ERC721PresetMinterPauserAutoId_init(string memory name, string memory symbol, string memory baseTokenURI) + internal + onlyInitializing + { + __ERC721_init_unchained(name, symbol); + __Pausable_init_unchained(); + __ERC721PresetMinterPauserAutoId_init_unchained(name, symbol, baseTokenURI); + } + + function __ERC721PresetMinterPauserAutoId_init_unchained(string memory, string memory, string memory baseTokenURI) + internal + onlyInitializing + { + _baseTokenURI = baseTokenURI; + + _setupRole(DEFAULT_ADMIN_ROLE, _msgSender()); + + _setupRole(MINTER_ROLE, _msgSender()); + _setupRole(PAUSER_ROLE, _msgSender()); + } + + function _baseURI() internal view virtual override returns (string memory) { + return _baseTokenURI; + } + + /** + * @dev Creates a new token for `to`. Its token ID will be automatically + * assigned (and available on the emitted {IERC721-Transfer} event), and the token + * URI autogenerated based on the base URI passed at construction. + * + * See {ERC721-_mint}. + * + * Requirements: + * + * - the caller must have the `MINTER_ROLE`. + */ + function mint(address to) public virtual returns (uint256 tokenId) { + require(hasRole(MINTER_ROLE, _msgSender()), "ERC721PresetMinterPauserAutoId: must have minter role to mint"); + tokenId = _mintFor(to); + } + + /** + * @dev Pauses all token transfers. + * + * See {ERC721Pausable} and {Pausable-_pause}. + * + * Requirements: + * + * - the caller must have the `PAUSER_ROLE`. + */ + function pause() public virtual { + require(hasRole(PAUSER_ROLE, _msgSender()), "ERC721PresetMinterPauserAutoId: must have pauser role to pause"); + _pause(); + } + + /** + * @dev Unpauses all token transfers. + * + * See {ERC721Pausable} and {Pausable-_unpause}. + * + * Requirements: + * + * - the caller must have the `PAUSER_ROLE`. + */ + function unpause() public virtual { + require(hasRole(PAUSER_ROLE, _msgSender()), "ERC721PresetMinterPauserAutoId: must have pauser role to unpause"); + _unpause(); + } + + function _beforeTokenTransfer(address from, address to, uint256 firstTokenId, uint256 batchSize) + internal + virtual + override(ERC721Upgradeable, ERC721EnumerableUpgradeable, ERC721PausableUpgradeable) + { + super._beforeTokenTransfer(from, to, firstTokenId, batchSize); + } + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) + public + view + virtual + override(AccessControlEnumerableUpgradeable, ERC721Upgradeable, ERC721EnumerableUpgradeable) + returns (bool) + { + return super.supportsInterface(interfaceId); + } + + /** + * @dev Helper function to mint for address `to`. + * + * See {ERC721-_mint}. + * + */ + function _mintFor(address to) internal virtual returns (uint256 _tokenId) { + // We cannot just use balanceOf to create the new tokenId because tokens + // can be burned (destroyed), so we need a separate counter. + _tokenId = _tokenIdTracker.current(); + _mint(to, _tokenId); + _tokenIdTracker.increment(); + } + + /** + * @dev This empty reserved space is put in place to allow future versions to add new + * variables without shifting down storage in the inheritance chain. + * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps + */ + uint256[48] private __gap; +} diff --git a/src/upgradable/refs/ERC721NonceUpgradeable.sol b/src/upgradable/refs/ERC721NonceUpgradeable.sol new file mode 100644 index 0000000..14b7faa --- /dev/null +++ b/src/upgradable/refs/ERC721NonceUpgradeable.sol @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "../../../lib/openzeppelin-contracts-upgradeable/contracts/token/ERC721/ERC721Upgradeable.sol"; + +/** + * @title ERC721NonceUpgradeable + * @dev This contract provides a nonce that will be increased whenever the token is tranferred. + */ +abstract contract ERC721NonceUpgradeable is ERC721Upgradeable { + /// @dev Emitted when the token nonce is updated + event NonceUpdated(uint256 indexed _tokenId, uint256 indexed _nonce); + + /// @dev Mapping from token id => token nonce + mapping(uint256 => uint256) public nonces; + + /** + * @dev This empty reserved space is put in place to allow future versions to add new + * variables without shifting down storage in the inheritance chain. + */ + uint256[50] private ______gap; + + /** + * @dev Override `ERC721-_beforeTokenTransfer`. + */ + function _beforeTokenTransfer(address _from, address _to, uint256 _firstTokenId, uint256 _batchSize) + internal + virtual + override + { + for (uint256 _tokenId = _firstTokenId; _tokenId < _firstTokenId + _batchSize; _tokenId++) { + emit NonceUpdated(_tokenId, ++nonces[_tokenId]); + } + super._beforeTokenTransfer(_from, _to, _firstTokenId, _batchSize); + } +} From 542d571a86ee4e326db6286ef9915741f0eed7fe Mon Sep 17 00:00:00 2001 From: huyhuynh3103 Date: Tue, 9 Apr 2024 17:02:54 +0700 Subject: [PATCH 03/22] chore: add branch of openzeppelin-contracts-upgradeable --- .gitmodules | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitmodules b/.gitmodules index 3183c85..1674f48 100644 --- a/.gitmodules +++ b/.gitmodules @@ -9,3 +9,4 @@ [submodule "lib/openzeppelin-contracts-upgradeable"] path = lib/openzeppelin-contracts-upgradeable url = https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable + branch = v4.9.5 From 3f61357f098c0e89e19f51698f619d1b0e6c30eb Mon Sep 17 00:00:00 2001 From: huyhuynh3103 Date: Fri, 12 Apr 2024 14:15:12 +0700 Subject: [PATCH 04/22] feat: rename folder and add test --- src/mock/SampleERC721Upgradeable.sol | 6 ++ .../ERC721CommonUpgradeable.sol | 0 ...interPauserAutoIdCustomizedUpgradeable.sol | 1 + .../refs/ERC721NonceUpgradeable.sol | 0 test/foundry/SampleERC721Upgradeable.t.sol | 101 ++++++++++++++++++ 5 files changed, 108 insertions(+) create mode 100644 src/mock/SampleERC721Upgradeable.sol rename src/{upgradable => upgradeable}/ERC721CommonUpgradeable.sol (100%) rename src/{upgradable => upgradeable}/ERC721PresetMinterPauserAutoIdCustomizedUpgradeable.sol (99%) rename src/{upgradable => upgradeable}/refs/ERC721NonceUpgradeable.sol (100%) create mode 100644 test/foundry/SampleERC721Upgradeable.t.sol diff --git a/src/mock/SampleERC721Upgradeable.sol b/src/mock/SampleERC721Upgradeable.sol new file mode 100644 index 0000000..32bdd04 --- /dev/null +++ b/src/mock/SampleERC721Upgradeable.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.0; + +import "../upgradeable/ERC721CommonUpgradeable.sol"; + +contract SampleERC721Upgradeable is ERC721CommonUpgradeable {} diff --git a/src/upgradable/ERC721CommonUpgradeable.sol b/src/upgradeable/ERC721CommonUpgradeable.sol similarity index 100% rename from src/upgradable/ERC721CommonUpgradeable.sol rename to src/upgradeable/ERC721CommonUpgradeable.sol diff --git a/src/upgradable/ERC721PresetMinterPauserAutoIdCustomizedUpgradeable.sol b/src/upgradeable/ERC721PresetMinterPauserAutoIdCustomizedUpgradeable.sol similarity index 99% rename from src/upgradable/ERC721PresetMinterPauserAutoIdCustomizedUpgradeable.sol rename to src/upgradeable/ERC721PresetMinterPauserAutoIdCustomizedUpgradeable.sol index 4f1491b..3087f07 100644 --- a/src/upgradable/ERC721PresetMinterPauserAutoIdCustomizedUpgradeable.sol +++ b/src/upgradeable/ERC721PresetMinterPauserAutoIdCustomizedUpgradeable.sol @@ -64,6 +64,7 @@ contract ERC721PresetMinterPauserAutoIdCustomizedUpgradeable is __ERC721_init_unchained(name, symbol); __Pausable_init_unchained(); __ERC721PresetMinterPauserAutoId_init_unchained(name, symbol, baseTokenURI); + _tokenIdTracker.increment(); } function __ERC721PresetMinterPauserAutoId_init_unchained(string memory, string memory, string memory baseTokenURI) diff --git a/src/upgradable/refs/ERC721NonceUpgradeable.sol b/src/upgradeable/refs/ERC721NonceUpgradeable.sol similarity index 100% rename from src/upgradable/refs/ERC721NonceUpgradeable.sol rename to src/upgradeable/refs/ERC721NonceUpgradeable.sol diff --git a/test/foundry/SampleERC721Upgradeable.t.sol b/test/foundry/SampleERC721Upgradeable.t.sol new file mode 100644 index 0000000..679303b --- /dev/null +++ b/test/foundry/SampleERC721Upgradeable.t.sol @@ -0,0 +1,101 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.13; + +import "forge-std/Test.sol"; +import {ERC721NonceUpgradeable} from "src/upgradeable/refs/ERC721NonceUpgradeable.sol"; +import {Strings} from "../../lib/openzeppelin-contracts/contracts/utils/Strings.sol"; +import {TransparentUpgradeableProxy} from + "../../lib/openzeppelin-contracts/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; +import { + SampleERC721Upgradeable, + ERC721CommonUpgradeable, + ERC721PresetMinterPauserAutoIdCustomizedUpgradeable, + IERC721State +} from "src/mock/SampleERC721Upgradeable.sol"; + +contract SampleERC721Upgradeable_Test is Test { + using Strings for uint256; + + event NonceUpdated(uint256 indexed _tokenId, uint256 indexed _nonce); + + string public constant NAME = "SampleERC721"; + string public constant SYMBOL = "NFT"; + string public constant BASE_URI = "http://example.com/"; + + address _proxyAdmin; + + ERC721CommonUpgradeable internal _t; + + function setUp() public virtual { + _proxyAdmin = makeAddr("proxy-admin"); + + bytes memory initializeData = + abi.encodeCall(ERC721PresetMinterPauserAutoIdCustomizedUpgradeable.initialize, (NAME, SYMBOL, BASE_URI)); + TransparentUpgradeableProxy proxy = + new TransparentUpgradeableProxy(address(new SampleERC721Upgradeable()), _proxyAdmin, initializeData); + _t = SampleERC721Upgradeable(address(proxy)); + } + + function testName() public virtual { + assertEq(_token().name(), NAME); + } + + function testSymbol() public virtual { + assertEq(_token().symbol(), SYMBOL); + } + + function testFirstTokenId() public virtual { + (uint256 _tokenId,) = _mint(address(1)); + assertNotEq(_tokenId, 0); + } + + function testTokenURI(address _from) public virtual { + vm.assume(_from.code.length == 0 && _from != address(0)); + (uint256 _tokenId,) = _mint(_from); + assertEq(_token().tokenURI(_tokenId), string(abi.encodePacked(BASE_URI, _tokenId.toString()))); + } + + function testNonce(address _from, address _to, uint256 _transferTimes) public virtual { + vm.assume(_from.code.length == 0 && _to.code.length == 0 && _from != address(0) && _to != address(0)); + vm.assume(_transferTimes > 0 && _transferTimes < 10); + (uint256 _tokenId, uint256 _nonce) = _mint(_from); + + for (uint256 _i; _i < _transferTimes; _i++) { + vm.expectEmit(true, true, true, true, address(_token())); + emit NonceUpdated(_tokenId, ++_nonce); + _transferFrom(_from, _to, _tokenId); + + vm.expectEmit(true, true, true, true, address(_token())); + emit NonceUpdated(_tokenId, ++_nonce); + _transferFrom(_to, _from, _tokenId); + } + + assertEq(_nonce, _token().nonces(_tokenId)); + } + + function testState(address _from, address _to) public virtual { + vm.assume(_from.code.length == 0 && _to.code.length == 0 && _from != address(0) && _to != address(0)); + (uint256 _tokenId,) = _mint(_from); + + bytes32 _state0 = keccak256(_token().stateOf(_tokenId)); + _transferFrom(_from, _to, _tokenId); + _transferFrom(_to, _from, _tokenId); + bytes32 _state1 = keccak256(_token().stateOf(_tokenId)); + assertNotEq(_state0, _state1); + } + + function _mint(address _user) internal virtual returns (uint256 _tokenId, uint256 _nonce) { + _token().mint(_user); + uint256 _balance = _token().balanceOf(_user); + return (_token().tokenOfOwnerByIndex(_user, _balance - 1), 1); + } + + function _transferFrom(address _from, address _to, uint256 _tokenId) internal virtual { + vm.prank(_from); + _token().transferFrom(_from, _to, _tokenId); + } + + function _token() internal view virtual returns (ERC721CommonUpgradeable) { + return _t; + } +} From eac699319d0522329ea99b5e9ce50fa201be908b Mon Sep 17 00:00:00 2001 From: huyhuynh3103 Date: Fri, 12 Apr 2024 14:43:17 +0700 Subject: [PATCH 05/22] feat: remove oz --- .gitmodules | 4 ---- lib/openzeppelin-contracts-upgradeable | 1 - 2 files changed, 5 deletions(-) delete mode 160000 lib/openzeppelin-contracts-upgradeable diff --git a/.gitmodules b/.gitmodules index 1674f48..e3d8d16 100644 --- a/.gitmodules +++ b/.gitmodules @@ -6,7 +6,3 @@ path = lib/openzeppelin-contracts url = https://github.com/openzeppelin/openzeppelin-contracts branch = v4.8.2 -[submodule "lib/openzeppelin-contracts-upgradeable"] - path = lib/openzeppelin-contracts-upgradeable - url = https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable - branch = v4.9.5 diff --git a/lib/openzeppelin-contracts-upgradeable b/lib/openzeppelin-contracts-upgradeable deleted file mode 160000 index a40cb0b..0000000 --- a/lib/openzeppelin-contracts-upgradeable +++ /dev/null @@ -1 +0,0 @@ -Subproject commit a40cb0bda838c2ef3dfc252c179f5c37c32e80c4 From bd2f6dfbcf74a01caa886eb19d07f0bc3ac311e7 Mon Sep 17 00:00:00 2001 From: huyhuynh3103 Date: Fri, 12 Apr 2024 16:33:14 +0700 Subject: [PATCH 06/22] forge install: openzeppelin-contracts-upgradeable v4.9.5 --- .gitmodules | 3 +++ lib/openzeppelin-contracts-upgradeable | 1 + 2 files changed, 4 insertions(+) create mode 160000 lib/openzeppelin-contracts-upgradeable diff --git a/.gitmodules b/.gitmodules index e3d8d16..3183c85 100644 --- a/.gitmodules +++ b/.gitmodules @@ -6,3 +6,6 @@ path = lib/openzeppelin-contracts url = https://github.com/openzeppelin/openzeppelin-contracts branch = v4.8.2 +[submodule "lib/openzeppelin-contracts-upgradeable"] + path = lib/openzeppelin-contracts-upgradeable + url = https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable diff --git a/lib/openzeppelin-contracts-upgradeable b/lib/openzeppelin-contracts-upgradeable new file mode 160000 index 0000000..a40cb0b --- /dev/null +++ b/lib/openzeppelin-contracts-upgradeable @@ -0,0 +1 @@ +Subproject commit a40cb0bda838c2ef3dfc252c179f5c37c32e80c4 From 69b57690b7ab8bf8973dac84cf447f22863fdd68 Mon Sep 17 00:00:00 2001 From: huyhuynh3103 Date: Mon, 15 Apr 2024 17:19:00 +0700 Subject: [PATCH 07/22] feat: add deployment scripts --- .../deploy/logic/erc721-upgradeable-logic.sol | 16 ++++++++++++ scripts/deploy/proxy-admin.ts | 16 ++++++++++++ .../deploy/proxy/erc721-upgradeable-proxy.ts | 25 +++++++++++++++++++ 3 files changed, 57 insertions(+) create mode 100644 scripts/deploy/logic/erc721-upgradeable-logic.sol create mode 100644 scripts/deploy/proxy-admin.ts create mode 100644 scripts/deploy/proxy/erc721-upgradeable-proxy.ts diff --git a/scripts/deploy/logic/erc721-upgradeable-logic.sol b/scripts/deploy/logic/erc721-upgradeable-logic.sol new file mode 100644 index 0000000..63c45ab --- /dev/null +++ b/scripts/deploy/logic/erc721-upgradeable-logic.sol @@ -0,0 +1,16 @@ +import { HardhatRuntimeEnvironment } from 'hardhat/types'; + +const deploy = async ({ getNamedAccounts, deployments, ethers }: HardhatRuntimeEnvironment) => { + const { deploy } = deployments; + const { deployer } = await getNamedAccounts(); + await deploy('SampleERC721CommonUpgradeableLogic', { + contract: 'ERC721CommonUpgradeable', + from: deployer, + log: true, + }); +}; + +deploy.tags = ['SampleERC721CommonUpgradeableLogic']; +deploy.dependencies = ['VerifyContracts']; + +export default deploy; diff --git a/scripts/deploy/proxy-admin.ts b/scripts/deploy/proxy-admin.ts new file mode 100644 index 0000000..6295715 --- /dev/null +++ b/scripts/deploy/proxy-admin.ts @@ -0,0 +1,16 @@ +import { HardhatRuntimeEnvironment } from 'hardhat/types'; + +const deploy = async ({ getNamedAccounts, deployments, ethers }: HardhatRuntimeEnvironment) => { + const { deploy } = deployments; + const { deployer } = await getNamedAccounts(); + await deploy('ProxyAdmin', { + contract: 'ProxyAdmin', + from: deployer, + log: true, + }); +}; + +deploy.tags = ['ProxyAdmin']; +deploy.dependencies = ['VerifyContracts']; + +export default deploy; diff --git a/scripts/deploy/proxy/erc721-upgradeable-proxy.ts b/scripts/deploy/proxy/erc721-upgradeable-proxy.ts new file mode 100644 index 0000000..b0f7b01 --- /dev/null +++ b/scripts/deploy/proxy/erc721-upgradeable-proxy.ts @@ -0,0 +1,25 @@ +import { ERC721CommonUpgradeable__factory } from '../../typechain-types'; +import { HardhatRuntimeEnvironment } from 'hardhat/types'; + +const erc721Interface = ERC721CommonUpgradeable__factory.createInterface(); + +const deploy = async ({ getNamedAccounts, deployments, network }: HardhatRuntimeEnvironment) => { + const { deploy } = deployments; + const { deployer } = await getNamedAccounts(); + const proxyAdmin = await deployments.get('ProxyAdmin'); + const logicContract = await deployments.get('SampleERC721CommonUpgradeableLogic'); + + const data = erc721Interface.encodeFunctionData('initialize', ['SampleERC721', 'NFT', 'http://example.com/']); + + await deploy('SampleERC721CommonUpgradeableProxy', { + contract: 'TransparentUpgradeableProxy', + from: deployer, + log: true, + args: [logicContract.address, proxyAdmin, data], + }); +}; + +deploy.tags = ['SampleERC721CommonUpgradeableProxy']; +deploy.dependencies = ['VerifyContracts', 'ProxyAdmin', 'SampleERC721CommonUpgradeableLogic']; + +export default deploy; From 741c81fbd79d72d7e876253ffc08e68af750d788 Mon Sep 17 00:00:00 2001 From: huyhuynh3103 Date: Tue, 16 Apr 2024 09:51:51 +0700 Subject: [PATCH 08/22] chore: remove OZ --- .gitmodules | 3 --- lib/openzeppelin-contracts-upgradeable | 1 - 2 files changed, 4 deletions(-) delete mode 160000 lib/openzeppelin-contracts-upgradeable diff --git a/.gitmodules b/.gitmodules index 3183c85..e3d8d16 100644 --- a/.gitmodules +++ b/.gitmodules @@ -6,6 +6,3 @@ path = lib/openzeppelin-contracts url = https://github.com/openzeppelin/openzeppelin-contracts branch = v4.8.2 -[submodule "lib/openzeppelin-contracts-upgradeable"] - path = lib/openzeppelin-contracts-upgradeable - url = https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable diff --git a/lib/openzeppelin-contracts-upgradeable b/lib/openzeppelin-contracts-upgradeable deleted file mode 160000 index a40cb0b..0000000 --- a/lib/openzeppelin-contracts-upgradeable +++ /dev/null @@ -1 +0,0 @@ -Subproject commit a40cb0bda838c2ef3dfc252c179f5c37c32e80c4 From 4d65cb2357784531da017440b7a5b406777384bb Mon Sep 17 00:00:00 2001 From: huyhuynh3103 Date: Tue, 16 Apr 2024 09:53:24 +0700 Subject: [PATCH 09/22] forge install: openzeppelin-contracts-upgradeable v4.9.5 --- .gitmodules | 3 +++ lib/openzeppelin-contracts-upgradeable | 1 + 2 files changed, 4 insertions(+) create mode 160000 lib/openzeppelin-contracts-upgradeable diff --git a/.gitmodules b/.gitmodules index e3d8d16..3183c85 100644 --- a/.gitmodules +++ b/.gitmodules @@ -6,3 +6,6 @@ path = lib/openzeppelin-contracts url = https://github.com/openzeppelin/openzeppelin-contracts branch = v4.8.2 +[submodule "lib/openzeppelin-contracts-upgradeable"] + path = lib/openzeppelin-contracts-upgradeable + url = https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable diff --git a/lib/openzeppelin-contracts-upgradeable b/lib/openzeppelin-contracts-upgradeable new file mode 160000 index 0000000..a40cb0b --- /dev/null +++ b/lib/openzeppelin-contracts-upgradeable @@ -0,0 +1 @@ +Subproject commit a40cb0bda838c2ef3dfc252c179f5c37c32e80c4 From 351dab422b192b82d730a30ff259315d37010f9d Mon Sep 17 00:00:00 2001 From: huyhuynh3103 Date: Tue, 16 Apr 2024 09:54:57 +0700 Subject: [PATCH 10/22] chore: add version in submodule --- .gitmodules | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitmodules b/.gitmodules index 3183c85..1674f48 100644 --- a/.gitmodules +++ b/.gitmodules @@ -9,3 +9,4 @@ [submodule "lib/openzeppelin-contracts-upgradeable"] path = lib/openzeppelin-contracts-upgradeable url = https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable + branch = v4.9.5 From 817617e0489d98a5cd0c701a97a699ed8e6ea300 Mon Sep 17 00:00:00 2001 From: huyhuynh3103 Date: Tue, 16 Apr 2024 10:08:06 +0700 Subject: [PATCH 11/22] chore: add ci script --- .DS_Store | Bin 0 -> 6148 bytes .github/template/create-pull-request.md | 2 + .../workflows/create-PR-deploy-to-release.yml | 64 +++++++++++++ .../create-PR-implement-to-feature.yml | 50 +++++++++++ .../create-PR-release-to-feature.yml | 84 ++++++++++++++++++ .../create-PR-release-to-network.yml | 47 ++++++++++ .github/workflows/create-release-tag.yml | 64 +++++++++++++ .github/workflows/test.yml | 54 +++++++++++ .husky/generate-layout.sh | 16 ++++ .husky/pre-commit | 10 +-- .husky/pre-push | 26 ++++++ .husky/storage-logger.js | 60 +++++++++++++ 12 files changed, 471 insertions(+), 6 deletions(-) create mode 100644 .DS_Store create mode 100644 .github/template/create-pull-request.md create mode 100644 .github/workflows/create-PR-deploy-to-release.yml create mode 100644 .github/workflows/create-PR-implement-to-feature.yml create mode 100644 .github/workflows/create-PR-release-to-feature.yml create mode 100644 .github/workflows/create-PR-release-to-network.yml create mode 100644 .github/workflows/create-release-tag.yml create mode 100644 .github/workflows/test.yml create mode 100755 .husky/generate-layout.sh create mode 100755 .husky/pre-push create mode 100644 .husky/storage-logger.js diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..8a7670fb140235cdc57659293e306986a1f3e06a GIT binary patch literal 6148 zcmeHKI|@QE5ZqM}!N$@uClI_r5Iunx5Va5#EX2a@Ri4YEIr}M;r=1qcENmv(>?CB0 zw{Jy6XXouyWF#U3xS?EaXq)Yux2%&91;TO0UM}0y=CD2<53TIi0ps>%B0D+D>5*?6 zG%7#^r~nn90#xAR3S@~L3_pG{52ONA;MWzf??Ztb*2E^zKOGpn1pxLCcEj9z31G1R zuqHNvh`=> $GITHUB_ENV + echo "VERSION=$(echo -n ${{ env.HEAD_BRANCH }} | sed 's/.*deploy\///' | cut -d'-' -f1)" >> $GITHUB_ENV + echo "NETWORK=$(echo -n ${{ env.HEAD_BRANCH }} | sed 's/.*deploy\/v[0-9\.]*-\(.*\)/\1/')" >> $GITHUB_ENV + - name: Checkout code + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + ref: 'release/${{ env.VERSION }}' + fetch-depth: 0 + fetch-tags: 'true' + + - name: Get Testnet Latest Tag + if: ${{ env.NETWORK == 'testnet' }} + run: | + echo "LATESTTAG=$(git describe --tags --match "*testnet*" --abbrev=0)" >> $GITHUB_ENV + + - name: Get Mainnet Latest Tag + if: ${{ env.NETWORK == 'mainnet' }} + run: | + echo "LATESTTAG=$(git describe --tags --match "*mainnet*" --abbrev=0)" >> $GITHUB_ENV + + - name: Reset promotion branch + run: | + git fetch origin ${HEAD_BRANCH}:${HEAD_BRANCH} + git reset --hard ${HEAD_BRANCH} + + - name: Generate Release note + id: template + run: | + echo "VERSION=${{ env.VERSION }} - SHA: ${{ github.sha }}" > CHANGELOG.md + + - name: Create Pull Request + id: cpr + uses: peter-evans/create-pull-request@v6.0.1 + with: + labels: automated PR + delete-branch: true + title: 'chore(`release/${{ env.VERSION }}`): merge from `${{ env.HEAD_BRANCH}}`' + body: ${{ steps.template.outputs.result }} + branch: ${{ env.PR_BRANCH }} \ No newline at end of file diff --git a/.github/workflows/create-PR-implement-to-feature.yml b/.github/workflows/create-PR-implement-to-feature.yml new file mode 100644 index 0000000..85cbbd6 --- /dev/null +++ b/.github/workflows/create-PR-implement-to-feature.yml @@ -0,0 +1,50 @@ +name: Create Pull Request From Implement To Feature +on: + push: + branches: + - 'implement-feature/**' + - 'implement-feature/**/**' + +concurrency: + group: ${{ github.workflow }}-${{ github.ref || github.run_id }} + cancel-in-progress: true + +env: + HEAD_BRANCH: ${{ github.head_ref || github.ref_name }} + +jobs: + createPullRequest: + runs-on: ubuntu-latest + steps: + - name: Set env + run: | + echo "FEATURE_NAME=$(echo ${HEAD_BRANCH} | cut -d'/' -f2)" >> $GITHUB_ENV + echo "FEATURE_BRANCH=feature/$(echo ${HEAD_BRANCH} | cut -d'/' -f2)" >> $GITHUB_ENV + echo "IMPLEMENT_NAME=$(echo ${HEAD_BRANCH} | cut -d'/' -f3)" >> $GITHUB_ENV + + - uses: actions/checkout@v3 + with: + ref: ${{env.FEATURE_BRANCH}} + + - name: Reset promotion branch + run: | + git fetch origin ${HEAD_BRANCH}:${HEAD_BRANCH} + git reset --hard ${HEAD_BRANCH} + + - name: Render template + id: template + uses: chuhlomin/render-template@v1.4 + with: + template: .github/template/create-pull-request.md + vars: | + fromBranch: ${{env.HEAD_BRANCH}} + toBranch: ${{ env.FEATURE_BRANCH }} + + - name: Create Pull Request + uses: peter-evans/create-pull-request@v6.0.1 + with: + branch: ${{ env.HEAD_BRANCH }} + base: ${{env.FEATURE_BRANCH}} + labels: automated PR + title: 'feat(${{env.FEATURE_NAME}}): implement `${{env.IMPLEMENT_NAME}}`' + body: ${{ steps.template.outputs.result }} \ No newline at end of file diff --git a/.github/workflows/create-PR-release-to-feature.yml b/.github/workflows/create-PR-release-to-feature.yml new file mode 100644 index 0000000..b9dec20 --- /dev/null +++ b/.github/workflows/create-PR-release-to-feature.yml @@ -0,0 +1,84 @@ +name: Create Pull Request From Release to Feature +on: + push: + branches: + - 'release/*' + - 'release*/*' + +concurrency: + group: ${{ github.workflow }}-${{ github.ref || github.run_id }} + cancel-in-progress: true + +env: + HEAD_BRANCH: ${{ github.head_ref || github.ref_name }} + +jobs: + fetchAllFeatureBranches: + runs-on: ubuntu-latest + + steps: + - id: step1 + name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - id: step2 + name: List all the remote feature branches + run: | + branches=$(git branch -r | grep -E '.*origin\/feature\/.*' | sed -e "s/.*origin\///" | tr "\n" " ") + JSON="[" + for branch in ${branches[@]}; do + echo $branch + JSONline="\"$branch\"," + # we don't need to iterate on the same branch over and over, so + # onnly include it when it wasn't included + if [[ "$JSON" != *"$JSONline"* ]]; then + JSON="$JSON$JSONline" + fi + done + # Remove last "," and add the closing bracket + if [[ $JSON == *, ]]; then + JSON="${JSON%?}" + fi + JSON="$JSON]" + echo $JSON + echo "BRANCHES={\"branch_name\": $( echo "$JSON" )}" >> "$GITHUB_OUTPUT" + outputs: + BRANCHES: ${{ steps.step2.outputs.BRANCHES }} + + mergeRelease2FeatureRepo: + runs-on: ubuntu-latest + needs: fetchAllFeatureBranches + strategy: + matrix: ${{ fromJSON(needs.fetchAllFeatureBranches.outputs.BRANCHES) }} + steps: + - name: Set env + run: | + echo "PR_BRANCH=merge/${HEAD_BRANCH}-${{matrix.branch_name}}" >> $GITHUB_ENV + echo "FEATURE_NAME=$(echo ${{matrix.branch_name}} | cut -d'/' -f2)" >> $GITHUB_ENV + - uses: actions/checkout@v3 + with: + ref: ${{matrix.branch_name}} + - name: Reset promotion branch + run: | + git fetch origin ${HEAD_BRANCH}:${HEAD_BRANCH} + git reset --hard ${HEAD_BRANCH} + + - name: Render template + id: template + uses: chuhlomin/render-template@v1.4 + with: + template: .github/template/create-pull-request.md + vars: | + fromBranch: ${{env.HEAD_BRANCH}} + toBranch: ${{matrix.branch_name}} + + - name: Create Pull Request + uses: peter-evans/create-pull-request@v6.0.1 + with: + labels: automated PR + delete-branch: true + title: 'chore(`${{env.FEATURE_NAME}}`): merge from `${{env.HEAD_BRANCH}}`' + body: ${{ steps.template.outputs.result }} + branch: ${{env.PR_BRANCH}} diff --git a/.github/workflows/create-PR-release-to-network.yml b/.github/workflows/create-PR-release-to-network.yml new file mode 100644 index 0000000..e291a52 --- /dev/null +++ b/.github/workflows/create-PR-release-to-network.yml @@ -0,0 +1,47 @@ +name: Create PR from release to network + +on: + pull_request: + branches: + - release/* + types: + - closed + +permissions: + contents: write + pull-requests: write + +env: + HEAD_BRANCH: ${{ github.head_ref || github.ref_name }} + RELEASE_BRANCH: ${{ github.event.pull_request.base.ref}} + +jobs: + merge-release-to-network: + runs-on: ubuntu-latest + if: ${{ (github.event.pull_request.merged == true) && (contains(github.head_ref, 'deploy') || contains(github.ref_name, 'deploy')) }} + steps: + - name: Set Env + run: | + echo "PR_BRANCH=merge/${HEAD_BRANCH}" >> $GITHUB_ENV + echo "VERSION=$(echo -n ${{ env.HEAD_BRANCH }} | sed 's/.*deploy\///' | cut -d'-' -f1)" >> $GITHUB_ENV + echo "NETWORK=$(echo -n ${{ env.HEAD_BRANCH }} | sed 's/.*deploy\/v[0-9\.]*-\(.*\)/\1/')" >> $GITHUB_ENV + + - name: Checkout code + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + ref: ${{ env.NETWORK }} + + - name: Reset promotion branch + run: | + git fetch origin ${RELEASE_BRANCH}:${RELEASE_BRANCH} + git reset --hard ${RELEASE_BRANCH} + + - name: Create Pull Request + id: cpr + uses: peter-evans/create-pull-request@v6.0.1 + with: + labels: automated PR + delete-branch: true + title: 'chore(`${{ env.NETWORK }}`): merge from `${{ env.HEAD_BRANCH}}`' + body: ${{ steps.template.outputs.result }} + branch: ${{env.PR_BRANCH}} diff --git a/.github/workflows/create-release-tag.yml b/.github/workflows/create-release-tag.yml new file mode 100644 index 0000000..d720027 --- /dev/null +++ b/.github/workflows/create-release-tag.yml @@ -0,0 +1,64 @@ +name: Create Release Tag + +on: + pull_request: + types: [closed] + branches: + - mainnet + - testnet + +env: + HEAD_BRANCH: ${{ github.head_ref || github.ref_name }} + +permissions: + contents: write + pull-requests: write + +jobs: + create-release-tag: + runs-on: ubuntu-latest + if: github.event.pull_request.merged == true + steps: + - name: Set Env + run: | + echo "VERSION=$(echo -n ${{ env.HEAD_BRANCH }} | sed 's/.*deploy\///' | cut -d'-' -f1)" >> $GITHUB_ENV + echo "NETWORK=$(echo -n ${{ env.HEAD_BRANCH }} | sed 's/.*deploy\/v[0-9\.]*-\(.*\)/\1/')" >> $GITHUB_ENV + + - name: Checkout code + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + ref: ${{ env.NETWORK }} + fetch-depth: 0 + fetch-tags: 'true' + + - name: Set Mainnet Tag + if: ${{ env.NETWORK == 'mainnet' }} + run: | + echo "TAG=${{ env.VERSION }}" >> $GITHUB_ENV + + - name: Set Testnet Tag + if: ${{ env.NETWORK == 'testnet' }} + run: | + echo "TAG=${{ env.VERSION }}-testnet" >> $GITHUB_ENV + + - name: Get Testnet Latest Tag + if: ${{ env.NETWORK == 'testnet' }} + run: | + echo "LATESTTAG=$(git describe --tags --match "*testnet*" --abbrev=0)" >> $GITHUB_ENV + + - name: Get Mainnet Latest Tag + if: ${{ env.NETWORK == 'mainnet' }} + run: | + echo "LATESTTAG=$(git describe --tags --match "*mainnet*" --abbrev=0)" >> $GITHUB_ENV + + - name: Create release + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + tag: ${{ env.TAG }} + run: | + gh release create "$tag" \ + --repo "$GITHUB_REPOSITORY" \ + --title "${{ env.NETWORK }} release ${{ env.VERSION }}" \ + --target "${{ env.NETWORK }}" \ + --notes-start-tag "${{ env.LATESTTAG }}" \ + --generate-notes diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..876b75f --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,54 @@ +name: test + +on: + push: + branches: + - mainnet + - testnet + - 'feature/*' + - 'features/*' + pull_request: + branches: + - mainnet + - testnet + - 'feature/*' + - 'features/*' + +env: + FOUNDRY_PROFILE: ci + +jobs: + check: + strategy: + fail-fast: true + + name: Foundry project + runs-on: [self-hosted, dockerize] + steps: + - id: 'gh-app' + name: 'Get Token' + uses: 'tibdex/github-app-token@3beb63f4bd073e61482598c45c71c1019b59b73a' #v1.7.0 + with: + app_id: ${{ secrets.GH_APP_ID }} + private_key: ${{ secrets.GH_PRIVATE_KEY }} + + - uses: actions/checkout@v4.1.1 + with: + submodules: recursive + token: ${{ steps.gh-app.outputs.token }} + + - name: Install Foundry + uses: foundry-rs/foundry-toolchain@v1 + with: + version: nightly + + - name: Run Forge build + run: | + forge --version + forge build --sizes + id: build + + - name: Run Forge tests + run: | + forge test -vvv + id: test diff --git a/.husky/generate-layout.sh b/.husky/generate-layout.sh new file mode 100755 index 0000000..0e66916 --- /dev/null +++ b/.husky/generate-layout.sh @@ -0,0 +1,16 @@ +#!/bin/sh + +rm -rf logs/storage/* +dirOutputs=$(ls out | grep '^[^.]*\.sol$') # assuming the out dir is at 'out' +while IFS= read -r contractDir; do + innerdirOutputs=$(ls out/"$contractDir") + + while IFS= read -r jsonFile; do + fileIn=out/"$contractDir"/$jsonFile + fileOut=logs/storage/"$contractDir":${jsonFile%.json}.log + node .husky/storage-logger.js "$fileIn" "$fileOut" & + done <<< "$innerdirOutputs" +done <<< "$dirOutputs" + +# Wait for all background jobs to finish +wait \ No newline at end of file diff --git a/.husky/pre-commit b/.husky/pre-commit index a77b1e6..259dc79 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,7 +1,5 @@ -#!/bin/sh -. "$(dirname "$0")/_/husky.sh" +#!/usr/bin/env sh +. "$(dirname -- "$0")/_/husky.sh" -set -ex - -yarn lint-staged -yarn compile +forge build +npx lint-staged diff --git a/.husky/pre-push b/.husky/pre-push new file mode 100755 index 0000000..6397927 --- /dev/null +++ b/.husky/pre-push @@ -0,0 +1,26 @@ +#!/bin/sh +. "$(dirname "$0")/_/husky.sh" + +set -ex + +# Workaround: git stash no changes doesn't cause failure but git stash pop cause +output=$(git stash) +stashed=true +if [[ $output == *"No local changes to save"* ]]; then + stashed=false +fi + +forge build --sizes 2>&1 | sed -n '/Contract/,$p' > logs/contract-code-sizes.log +.husky/generate-layout.sh + +git add logs + +output=$(git status -s) +line_count=$(echo "$output" | wc -l) +if [ "$line_count" -gt 1 ]; then + git commit -m "chore: storage layout" +fi + +if $stashed; then + git stash pop +fi \ No newline at end of file diff --git a/.husky/storage-logger.js b/.husky/storage-logger.js new file mode 100644 index 0000000..0ff423c --- /dev/null +++ b/.husky/storage-logger.js @@ -0,0 +1,60 @@ +const fs = require('fs'); +const fileIn = process.argv[2]; +const fileOut = process.argv[3]; + +if (!fileIn) { + console.error('Invalid input'); +} + +fs.readFile(fileIn, 'utf8', (err, data) => { + if (err) { + console.error('Error reading file:', err); + return; + } + + try { + const jsonData = JSON.parse(data); + + if (typeof jsonData.storageLayout == 'undefined') return; + if (jsonData.storageLayout.storage.length == 0) return; + + const hasAst = typeof jsonData.ast != 'undefined'; + + let storageLayout; + if (hasAst) { + const absolutePath = jsonData.ast.absolutePath; + if (typeof absolutePath == 'undefined') return; + if (!absolutePath.startsWith('src')) return; + storageLayout = jsonData.storageLayout.storage; + } else { + // filter only contracts in src/* + storageLayout = jsonData.storageLayout.storage.filter(({ contract }) => + contract.startsWith('src') + ); + } + + const outputData = storageLayout + .map(({ contract, label, offset, slot, type: typeId }) => { + const typeObj = jsonData.storageLayout.types[typeId]; + const typeLabel = typeObj.label; + const numberOfBytes = typeObj.numberOfBytes; + return `${contract}:${label} (storage_slot: ${slot}) (offset: ${offset}) (type: ${typeLabel}) (numberOfBytes: ${numberOfBytes})`; + }) + .join('\n'); + + if (outputData == '') return; + + if (!fileOut) { + console.log(outputData); + } else { + fs.writeFile(fileOut, outputData, 'utf-8', (err) => { + if (err) { + console.error('Error writing file:', err); + return; + } + }); + } + } catch (err) { + console.error('Error parsing JSON:', err); + } +}); From b5c9cfa7662cba9b463d640f78214873b736be5d Mon Sep 17 00:00:00 2001 From: huyhuynh3103 Date: Tue, 16 Apr 2024 10:10:22 +0700 Subject: [PATCH 12/22] chore: add ci script --- .DS_Store | Bin 6148 -> 6148 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/.DS_Store b/.DS_Store index 8a7670fb140235cdc57659293e306986a1f3e06a..cb6d06e5541cde63fb3630cd6b1db2ddaf11e863 100644 GIT binary patch delta 362 zcmZoMXfc=|#>B)qu~2NHo}wrV0|Nsi1A_nqLk2@BLsC+CaY0hf#*NDv>p?Q?40;Ud z44Dii$g=rKK$)FM1v#0;B?bo97@3$^SlQS)*g3d4VuLgC%Y#c2OG=BK5{sfiypa6- zoFo`KF)1uFwLD%x#5q5&Br!8DwFs;sGbI(MBqlsFFD1X+DZex?r8v4CNrr=ygEL-0 zvbx&H#N1Lx!N|~}R!5=Q(#SwZ!Nl0Cww9AaR9W9TC_XzUH!r^%=sF-^1o{dLc%d|m z>H#v){FPFioRb7}CrArSiXZCdvf!e;ocz4>jUDeCJzu~2NHo}wrt0|NsP3otNbGgPJ&C+8&P=jTi;RNpMk{Dx(70P_T< l&Fmcf96$}59htu~Pv#fV Date: Tue, 16 Apr 2024 10:12:54 +0700 Subject: [PATCH 13/22] chore: add code-size log --- logs/contract-code-sizes.log | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 logs/contract-code-sizes.log diff --git a/logs/contract-code-sizes.log b/logs/contract-code-sizes.log new file mode 100644 index 0000000..2fee138 --- /dev/null +++ b/logs/contract-code-sizes.log @@ -0,0 +1,32 @@ +| Contract | Size (kB) | Margin (kB) | +|-----------------------------------------------------|-----------|-------------| +| Address | 0.086 | 24.49 | +| AddressUpgradeable | 0.086 | 24.49 | +| Counters | 0.086 | 24.49 | +| CountersUpgradeable | 0.086 | 24.49 | +| ERC1967Proxy | 0.699 | 23.877 | +| ERC721 | 4.339 | 20.237 | +| ERC721PresetMinterPauserAutoIdCustomized | 9.984 | 14.592 | +| ERC721PresetMinterPauserAutoIdCustomizedUpgradeable | 10.727 | 13.849 | +| ERC721Upgradeable | 4.339 | 20.237 | +| EnumerableSet | 0.086 | 24.49 | +| EnumerableSetUpgradeable | 0.086 | 24.49 | +| Math | 0.086 | 24.49 | +| MathUpgradeable | 0.086 | 24.49 | +| SampleERC721 | 11.012 | 13.564 | +| SampleERC721Upgradeable | 11.734 | 12.842 | +| SignedMathUpgradeable | 0.086 | 24.49 | +| StdInvariant | 2.038 | 22.538 | +| StdStyle | 0.086 | 24.49 | +| StorageSlot | 0.086 | 24.49 | +| Strings | 0.086 | 24.49 | +| StringsUpgradeable | 0.086 | 24.49 | +| TransparentUpgradeableProxy | 2.096 | 22.48 | +| console | 0.086 | 24.49 | +| console2 | 0.086 | 24.49 | +| stdError | 0.591 | 23.985 | +| stdJson | 0.086 | 24.49 | +| stdMath | 0.086 | 24.49 | +| stdStorage | 0.086 | 24.49 | +| stdStorageSafe | 0.086 | 24.49 | + From 17f4efa570ba0e391c5ad6f2949ccc6e2a5461fc Mon Sep 17 00:00:00 2001 From: huyhuynh3103 Date: Tue, 16 Apr 2024 10:37:24 +0700 Subject: [PATCH 14/22] chore: add storage log --- .husky/.gitignore | 0 .husky/storage-logger.js | 75 ++++++++++--------- foundry.toml | 3 + .../storage/ERC721Common.sol:ERC721Common.log | 17 +++++ ...pgradeable.sol:ERC721CommonUpgradeable.log | 29 +++++++ logs/storage/ERC721Nonce.sol:ERC721Nonce.log | 8 ++ ...Upgradeable.sol:ERC721NonceUpgradeable.log | 13 ++++ ...C721PresetMinterPauserAutoIdCustomized.log | 15 ++++ ...interPauserAutoIdCustomizedUpgradeable.log | 27 +++++++ .../storage/SampleERC721.sol:SampleERC721.log | 17 +++++ ...pgradeable.sol:SampleERC721Upgradeable.log | 29 +++++++ 11 files changed, 196 insertions(+), 37 deletions(-) create mode 100644 .husky/.gitignore create mode 100644 logs/storage/ERC721Common.sol:ERC721Common.log create mode 100644 logs/storage/ERC721CommonUpgradeable.sol:ERC721CommonUpgradeable.log create mode 100644 logs/storage/ERC721Nonce.sol:ERC721Nonce.log create mode 100644 logs/storage/ERC721NonceUpgradeable.sol:ERC721NonceUpgradeable.log create mode 100644 logs/storage/ERC721PresetMinterPauserAutoIdCustomized.sol:ERC721PresetMinterPauserAutoIdCustomized.log create mode 100644 logs/storage/ERC721PresetMinterPauserAutoIdCustomizedUpgradeable.sol:ERC721PresetMinterPauserAutoIdCustomizedUpgradeable.log create mode 100644 logs/storage/SampleERC721.sol:SampleERC721.log create mode 100644 logs/storage/SampleERC721Upgradeable.sol:SampleERC721Upgradeable.log diff --git a/.husky/.gitignore b/.husky/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/.husky/storage-logger.js b/.husky/storage-logger.js index 0ff423c..fb8eba0 100644 --- a/.husky/storage-logger.js +++ b/.husky/storage-logger.js @@ -7,54 +7,55 @@ if (!fileIn) { } fs.readFile(fileIn, 'utf8', (err, data) => { - if (err) { - console.error('Error reading file:', err); + console.log("fileIn", fileIn) + if (err) { + console.error('Error reading file:', err); return; } - + try { - const jsonData = JSON.parse(data); - + const jsonData = JSON.parse(data); + + console.log("jsonData", jsonData.storageLayout); if (typeof jsonData.storageLayout == 'undefined') return; if (jsonData.storageLayout.storage.length == 0) return; - + const hasAst = typeof jsonData.ast != 'undefined'; - let storageLayout; if (hasAst) { - const absolutePath = jsonData.ast.absolutePath; + const absolutePath = jsonData.ast.absolutePath; if (typeof absolutePath == 'undefined') return; if (!absolutePath.startsWith('src')) return; storageLayout = jsonData.storageLayout.storage; } else { - // filter only contracts in src/* + // filter only contracts in src/* storageLayout = jsonData.storageLayout.storage.filter(({ contract }) => - contract.startsWith('src') - ); - } - - const outputData = storageLayout - .map(({ contract, label, offset, slot, type: typeId }) => { - const typeObj = jsonData.storageLayout.types[typeId]; - const typeLabel = typeObj.label; - const numberOfBytes = typeObj.numberOfBytes; - return `${contract}:${label} (storage_slot: ${slot}) (offset: ${offset}) (type: ${typeLabel}) (numberOfBytes: ${numberOfBytes})`; - }) - .join('\n'); - - if (outputData == '') return; - - if (!fileOut) { - console.log(outputData); - } else { - fs.writeFile(fileOut, outputData, 'utf-8', (err) => { - if (err) { - console.error('Error writing file:', err); - return; - } - }); - } - } catch (err) { - console.error('Error parsing JSON:', err); - } + contract.startsWith('src') + ); + } + + const outputData = storageLayout + .map(({ contract, label, offset, slot, type: typeId }) => { + const typeObj = jsonData.storageLayout.types[typeId]; + const typeLabel = typeObj.label; + const numberOfBytes = typeObj.numberOfBytes; + return `${contract}:${label} (storage_slot: ${slot}) (offset: ${offset}) (type: ${typeLabel}) (numberOfBytes: ${numberOfBytes})`; + }) + .join('\n'); + + if (outputData == '') return; + + if (!fileOut) { + console.log(outputData); + } else { + fs.writeFile(fileOut, outputData, 'utf-8', (err) => { + if (err) { + console.error('Error writing file:', err); + return; + } + }); + } +} catch (err) { + console.error('Error parsing JSON:', err); +} }); diff --git a/foundry.toml b/foundry.toml index 87fb94e..ff5e26c 100644 --- a/foundry.toml +++ b/foundry.toml @@ -8,6 +8,9 @@ solc = '0.8.17' evm_version = 'istanbul' cache_path = 'cache/foundry' +extra_output = ["devdoc", "userdoc", "storagelayout"] +fs_permissions = [{ access = "read-write", path = "./" }] + [fmt] line_length = 120 tab_width = 2 diff --git a/logs/storage/ERC721Common.sol:ERC721Common.log b/logs/storage/ERC721Common.sol:ERC721Common.log new file mode 100644 index 0000000..607257b --- /dev/null +++ b/logs/storage/ERC721Common.sol:ERC721Common.log @@ -0,0 +1,17 @@ +src/ERC721Common.sol:ERC721Common:_roles (storage_slot: 0) (offset: 0) (type: mapping(bytes32 => struct AccessControl.RoleData)) (numberOfBytes: 32) +src/ERC721Common.sol:ERC721Common:_roleMembers (storage_slot: 1) (offset: 0) (type: mapping(bytes32 => struct EnumerableSet.AddressSet)) (numberOfBytes: 32) +src/ERC721Common.sol:ERC721Common:_name (storage_slot: 2) (offset: 0) (type: string) (numberOfBytes: 32) +src/ERC721Common.sol:ERC721Common:_symbol (storage_slot: 3) (offset: 0) (type: string) (numberOfBytes: 32) +src/ERC721Common.sol:ERC721Common:_owners (storage_slot: 4) (offset: 0) (type: mapping(uint256 => address)) (numberOfBytes: 32) +src/ERC721Common.sol:ERC721Common:_balances (storage_slot: 5) (offset: 0) (type: mapping(address => uint256)) (numberOfBytes: 32) +src/ERC721Common.sol:ERC721Common:_tokenApprovals (storage_slot: 6) (offset: 0) (type: mapping(uint256 => address)) (numberOfBytes: 32) +src/ERC721Common.sol:ERC721Common:_operatorApprovals (storage_slot: 7) (offset: 0) (type: mapping(address => mapping(address => bool))) (numberOfBytes: 32) +src/ERC721Common.sol:ERC721Common:nonces (storage_slot: 8) (offset: 0) (type: mapping(uint256 => uint256)) (numberOfBytes: 32) +src/ERC721Common.sol:ERC721Common:______gap (storage_slot: 9) (offset: 0) (type: uint256[50]) (numberOfBytes: 1600) +src/ERC721Common.sol:ERC721Common:_ownedTokens (storage_slot: 59) (offset: 0) (type: mapping(address => mapping(uint256 => uint256))) (numberOfBytes: 32) +src/ERC721Common.sol:ERC721Common:_ownedTokensIndex (storage_slot: 60) (offset: 0) (type: mapping(uint256 => uint256)) (numberOfBytes: 32) +src/ERC721Common.sol:ERC721Common:_allTokens (storage_slot: 61) (offset: 0) (type: uint256[]) (numberOfBytes: 32) +src/ERC721Common.sol:ERC721Common:_allTokensIndex (storage_slot: 62) (offset: 0) (type: mapping(uint256 => uint256)) (numberOfBytes: 32) +src/ERC721Common.sol:ERC721Common:_paused (storage_slot: 63) (offset: 0) (type: bool) (numberOfBytes: 1) +src/ERC721Common.sol:ERC721Common:_tokenIdTracker (storage_slot: 64) (offset: 0) (type: struct Counters.Counter) (numberOfBytes: 32) +src/ERC721Common.sol:ERC721Common:_baseTokenURI (storage_slot: 65) (offset: 0) (type: string) (numberOfBytes: 32) \ No newline at end of file diff --git a/logs/storage/ERC721CommonUpgradeable.sol:ERC721CommonUpgradeable.log b/logs/storage/ERC721CommonUpgradeable.sol:ERC721CommonUpgradeable.log new file mode 100644 index 0000000..32b64ca --- /dev/null +++ b/logs/storage/ERC721CommonUpgradeable.sol:ERC721CommonUpgradeable.log @@ -0,0 +1,29 @@ +src/upgradeable/ERC721CommonUpgradeable.sol:ERC721CommonUpgradeable:_initialized (storage_slot: 0) (offset: 0) (type: uint8) (numberOfBytes: 1) +src/upgradeable/ERC721CommonUpgradeable.sol:ERC721CommonUpgradeable:_initializing (storage_slot: 0) (offset: 1) (type: bool) (numberOfBytes: 1) +src/upgradeable/ERC721CommonUpgradeable.sol:ERC721CommonUpgradeable:__gap (storage_slot: 1) (offset: 0) (type: uint256[50]) (numberOfBytes: 1600) +src/upgradeable/ERC721CommonUpgradeable.sol:ERC721CommonUpgradeable:__gap (storage_slot: 51) (offset: 0) (type: uint256[50]) (numberOfBytes: 1600) +src/upgradeable/ERC721CommonUpgradeable.sol:ERC721CommonUpgradeable:_roles (storage_slot: 101) (offset: 0) (type: mapping(bytes32 => struct AccessControlUpgradeable.RoleData)) (numberOfBytes: 32) +src/upgradeable/ERC721CommonUpgradeable.sol:ERC721CommonUpgradeable:__gap (storage_slot: 102) (offset: 0) (type: uint256[49]) (numberOfBytes: 1568) +src/upgradeable/ERC721CommonUpgradeable.sol:ERC721CommonUpgradeable:_roleMembers (storage_slot: 151) (offset: 0) (type: mapping(bytes32 => struct EnumerableSetUpgradeable.AddressSet)) (numberOfBytes: 32) +src/upgradeable/ERC721CommonUpgradeable.sol:ERC721CommonUpgradeable:__gap (storage_slot: 152) (offset: 0) (type: uint256[49]) (numberOfBytes: 1568) +src/upgradeable/ERC721CommonUpgradeable.sol:ERC721CommonUpgradeable:_name (storage_slot: 201) (offset: 0) (type: string) (numberOfBytes: 32) +src/upgradeable/ERC721CommonUpgradeable.sol:ERC721CommonUpgradeable:_symbol (storage_slot: 202) (offset: 0) (type: string) (numberOfBytes: 32) +src/upgradeable/ERC721CommonUpgradeable.sol:ERC721CommonUpgradeable:_owners (storage_slot: 203) (offset: 0) (type: mapping(uint256 => address)) (numberOfBytes: 32) +src/upgradeable/ERC721CommonUpgradeable.sol:ERC721CommonUpgradeable:_balances (storage_slot: 204) (offset: 0) (type: mapping(address => uint256)) (numberOfBytes: 32) +src/upgradeable/ERC721CommonUpgradeable.sol:ERC721CommonUpgradeable:_tokenApprovals (storage_slot: 205) (offset: 0) (type: mapping(uint256 => address)) (numberOfBytes: 32) +src/upgradeable/ERC721CommonUpgradeable.sol:ERC721CommonUpgradeable:_operatorApprovals (storage_slot: 206) (offset: 0) (type: mapping(address => mapping(address => bool))) (numberOfBytes: 32) +src/upgradeable/ERC721CommonUpgradeable.sol:ERC721CommonUpgradeable:__gap (storage_slot: 207) (offset: 0) (type: uint256[44]) (numberOfBytes: 1408) +src/upgradeable/ERC721CommonUpgradeable.sol:ERC721CommonUpgradeable:nonces (storage_slot: 251) (offset: 0) (type: mapping(uint256 => uint256)) (numberOfBytes: 32) +src/upgradeable/ERC721CommonUpgradeable.sol:ERC721CommonUpgradeable:______gap (storage_slot: 252) (offset: 0) (type: uint256[50]) (numberOfBytes: 1600) +src/upgradeable/ERC721CommonUpgradeable.sol:ERC721CommonUpgradeable:_ownedTokens (storage_slot: 302) (offset: 0) (type: mapping(address => mapping(uint256 => uint256))) (numberOfBytes: 32) +src/upgradeable/ERC721CommonUpgradeable.sol:ERC721CommonUpgradeable:_ownedTokensIndex (storage_slot: 303) (offset: 0) (type: mapping(uint256 => uint256)) (numberOfBytes: 32) +src/upgradeable/ERC721CommonUpgradeable.sol:ERC721CommonUpgradeable:_allTokens (storage_slot: 304) (offset: 0) (type: uint256[]) (numberOfBytes: 32) +src/upgradeable/ERC721CommonUpgradeable.sol:ERC721CommonUpgradeable:_allTokensIndex (storage_slot: 305) (offset: 0) (type: mapping(uint256 => uint256)) (numberOfBytes: 32) +src/upgradeable/ERC721CommonUpgradeable.sol:ERC721CommonUpgradeable:__gap (storage_slot: 306) (offset: 0) (type: uint256[46]) (numberOfBytes: 1472) +src/upgradeable/ERC721CommonUpgradeable.sol:ERC721CommonUpgradeable:__gap (storage_slot: 352) (offset: 0) (type: uint256[50]) (numberOfBytes: 1600) +src/upgradeable/ERC721CommonUpgradeable.sol:ERC721CommonUpgradeable:_paused (storage_slot: 402) (offset: 0) (type: bool) (numberOfBytes: 1) +src/upgradeable/ERC721CommonUpgradeable.sol:ERC721CommonUpgradeable:__gap (storage_slot: 403) (offset: 0) (type: uint256[49]) (numberOfBytes: 1568) +src/upgradeable/ERC721CommonUpgradeable.sol:ERC721CommonUpgradeable:__gap (storage_slot: 452) (offset: 0) (type: uint256[50]) (numberOfBytes: 1600) +src/upgradeable/ERC721CommonUpgradeable.sol:ERC721CommonUpgradeable:_tokenIdTracker (storage_slot: 502) (offset: 0) (type: struct CountersUpgradeable.Counter) (numberOfBytes: 32) +src/upgradeable/ERC721CommonUpgradeable.sol:ERC721CommonUpgradeable:_baseTokenURI (storage_slot: 503) (offset: 0) (type: string) (numberOfBytes: 32) +src/upgradeable/ERC721CommonUpgradeable.sol:ERC721CommonUpgradeable:__gap (storage_slot: 504) (offset: 0) (type: uint256[48]) (numberOfBytes: 1536) \ No newline at end of file diff --git a/logs/storage/ERC721Nonce.sol:ERC721Nonce.log b/logs/storage/ERC721Nonce.sol:ERC721Nonce.log new file mode 100644 index 0000000..449d7d2 --- /dev/null +++ b/logs/storage/ERC721Nonce.sol:ERC721Nonce.log @@ -0,0 +1,8 @@ +src/refs/ERC721Nonce.sol:ERC721Nonce:_name (storage_slot: 0) (offset: 0) (type: string) (numberOfBytes: 32) +src/refs/ERC721Nonce.sol:ERC721Nonce:_symbol (storage_slot: 1) (offset: 0) (type: string) (numberOfBytes: 32) +src/refs/ERC721Nonce.sol:ERC721Nonce:_owners (storage_slot: 2) (offset: 0) (type: mapping(uint256 => address)) (numberOfBytes: 32) +src/refs/ERC721Nonce.sol:ERC721Nonce:_balances (storage_slot: 3) (offset: 0) (type: mapping(address => uint256)) (numberOfBytes: 32) +src/refs/ERC721Nonce.sol:ERC721Nonce:_tokenApprovals (storage_slot: 4) (offset: 0) (type: mapping(uint256 => address)) (numberOfBytes: 32) +src/refs/ERC721Nonce.sol:ERC721Nonce:_operatorApprovals (storage_slot: 5) (offset: 0) (type: mapping(address => mapping(address => bool))) (numberOfBytes: 32) +src/refs/ERC721Nonce.sol:ERC721Nonce:nonces (storage_slot: 6) (offset: 0) (type: mapping(uint256 => uint256)) (numberOfBytes: 32) +src/refs/ERC721Nonce.sol:ERC721Nonce:______gap (storage_slot: 7) (offset: 0) (type: uint256[50]) (numberOfBytes: 1600) \ No newline at end of file diff --git a/logs/storage/ERC721NonceUpgradeable.sol:ERC721NonceUpgradeable.log b/logs/storage/ERC721NonceUpgradeable.sol:ERC721NonceUpgradeable.log new file mode 100644 index 0000000..3eb8f64 --- /dev/null +++ b/logs/storage/ERC721NonceUpgradeable.sol:ERC721NonceUpgradeable.log @@ -0,0 +1,13 @@ +src/upgradeable/refs/ERC721NonceUpgradeable.sol:ERC721NonceUpgradeable:_initialized (storage_slot: 0) (offset: 0) (type: uint8) (numberOfBytes: 1) +src/upgradeable/refs/ERC721NonceUpgradeable.sol:ERC721NonceUpgradeable:_initializing (storage_slot: 0) (offset: 1) (type: bool) (numberOfBytes: 1) +src/upgradeable/refs/ERC721NonceUpgradeable.sol:ERC721NonceUpgradeable:__gap (storage_slot: 1) (offset: 0) (type: uint256[50]) (numberOfBytes: 1600) +src/upgradeable/refs/ERC721NonceUpgradeable.sol:ERC721NonceUpgradeable:__gap (storage_slot: 51) (offset: 0) (type: uint256[50]) (numberOfBytes: 1600) +src/upgradeable/refs/ERC721NonceUpgradeable.sol:ERC721NonceUpgradeable:_name (storage_slot: 101) (offset: 0) (type: string) (numberOfBytes: 32) +src/upgradeable/refs/ERC721NonceUpgradeable.sol:ERC721NonceUpgradeable:_symbol (storage_slot: 102) (offset: 0) (type: string) (numberOfBytes: 32) +src/upgradeable/refs/ERC721NonceUpgradeable.sol:ERC721NonceUpgradeable:_owners (storage_slot: 103) (offset: 0) (type: mapping(uint256 => address)) (numberOfBytes: 32) +src/upgradeable/refs/ERC721NonceUpgradeable.sol:ERC721NonceUpgradeable:_balances (storage_slot: 104) (offset: 0) (type: mapping(address => uint256)) (numberOfBytes: 32) +src/upgradeable/refs/ERC721NonceUpgradeable.sol:ERC721NonceUpgradeable:_tokenApprovals (storage_slot: 105) (offset: 0) (type: mapping(uint256 => address)) (numberOfBytes: 32) +src/upgradeable/refs/ERC721NonceUpgradeable.sol:ERC721NonceUpgradeable:_operatorApprovals (storage_slot: 106) (offset: 0) (type: mapping(address => mapping(address => bool))) (numberOfBytes: 32) +src/upgradeable/refs/ERC721NonceUpgradeable.sol:ERC721NonceUpgradeable:__gap (storage_slot: 107) (offset: 0) (type: uint256[44]) (numberOfBytes: 1408) +src/upgradeable/refs/ERC721NonceUpgradeable.sol:ERC721NonceUpgradeable:nonces (storage_slot: 151) (offset: 0) (type: mapping(uint256 => uint256)) (numberOfBytes: 32) +src/upgradeable/refs/ERC721NonceUpgradeable.sol:ERC721NonceUpgradeable:______gap (storage_slot: 152) (offset: 0) (type: uint256[50]) (numberOfBytes: 1600) \ No newline at end of file diff --git a/logs/storage/ERC721PresetMinterPauserAutoIdCustomized.sol:ERC721PresetMinterPauserAutoIdCustomized.log b/logs/storage/ERC721PresetMinterPauserAutoIdCustomized.sol:ERC721PresetMinterPauserAutoIdCustomized.log new file mode 100644 index 0000000..ab746a5 --- /dev/null +++ b/logs/storage/ERC721PresetMinterPauserAutoIdCustomized.sol:ERC721PresetMinterPauserAutoIdCustomized.log @@ -0,0 +1,15 @@ +src/ERC721PresetMinterPauserAutoIdCustomized.sol:ERC721PresetMinterPauserAutoIdCustomized:_roles (storage_slot: 0) (offset: 0) (type: mapping(bytes32 => struct AccessControl.RoleData)) (numberOfBytes: 32) +src/ERC721PresetMinterPauserAutoIdCustomized.sol:ERC721PresetMinterPauserAutoIdCustomized:_roleMembers (storage_slot: 1) (offset: 0) (type: mapping(bytes32 => struct EnumerableSet.AddressSet)) (numberOfBytes: 32) +src/ERC721PresetMinterPauserAutoIdCustomized.sol:ERC721PresetMinterPauserAutoIdCustomized:_name (storage_slot: 2) (offset: 0) (type: string) (numberOfBytes: 32) +src/ERC721PresetMinterPauserAutoIdCustomized.sol:ERC721PresetMinterPauserAutoIdCustomized:_symbol (storage_slot: 3) (offset: 0) (type: string) (numberOfBytes: 32) +src/ERC721PresetMinterPauserAutoIdCustomized.sol:ERC721PresetMinterPauserAutoIdCustomized:_owners (storage_slot: 4) (offset: 0) (type: mapping(uint256 => address)) (numberOfBytes: 32) +src/ERC721PresetMinterPauserAutoIdCustomized.sol:ERC721PresetMinterPauserAutoIdCustomized:_balances (storage_slot: 5) (offset: 0) (type: mapping(address => uint256)) (numberOfBytes: 32) +src/ERC721PresetMinterPauserAutoIdCustomized.sol:ERC721PresetMinterPauserAutoIdCustomized:_tokenApprovals (storage_slot: 6) (offset: 0) (type: mapping(uint256 => address)) (numberOfBytes: 32) +src/ERC721PresetMinterPauserAutoIdCustomized.sol:ERC721PresetMinterPauserAutoIdCustomized:_operatorApprovals (storage_slot: 7) (offset: 0) (type: mapping(address => mapping(address => bool))) (numberOfBytes: 32) +src/ERC721PresetMinterPauserAutoIdCustomized.sol:ERC721PresetMinterPauserAutoIdCustomized:_ownedTokens (storage_slot: 8) (offset: 0) (type: mapping(address => mapping(uint256 => uint256))) (numberOfBytes: 32) +src/ERC721PresetMinterPauserAutoIdCustomized.sol:ERC721PresetMinterPauserAutoIdCustomized:_ownedTokensIndex (storage_slot: 9) (offset: 0) (type: mapping(uint256 => uint256)) (numberOfBytes: 32) +src/ERC721PresetMinterPauserAutoIdCustomized.sol:ERC721PresetMinterPauserAutoIdCustomized:_allTokens (storage_slot: 10) (offset: 0) (type: uint256[]) (numberOfBytes: 32) +src/ERC721PresetMinterPauserAutoIdCustomized.sol:ERC721PresetMinterPauserAutoIdCustomized:_allTokensIndex (storage_slot: 11) (offset: 0) (type: mapping(uint256 => uint256)) (numberOfBytes: 32) +src/ERC721PresetMinterPauserAutoIdCustomized.sol:ERC721PresetMinterPauserAutoIdCustomized:_paused (storage_slot: 12) (offset: 0) (type: bool) (numberOfBytes: 1) +src/ERC721PresetMinterPauserAutoIdCustomized.sol:ERC721PresetMinterPauserAutoIdCustomized:_tokenIdTracker (storage_slot: 13) (offset: 0) (type: struct Counters.Counter) (numberOfBytes: 32) +src/ERC721PresetMinterPauserAutoIdCustomized.sol:ERC721PresetMinterPauserAutoIdCustomized:_baseTokenURI (storage_slot: 14) (offset: 0) (type: string) (numberOfBytes: 32) \ No newline at end of file diff --git a/logs/storage/ERC721PresetMinterPauserAutoIdCustomizedUpgradeable.sol:ERC721PresetMinterPauserAutoIdCustomizedUpgradeable.log b/logs/storage/ERC721PresetMinterPauserAutoIdCustomizedUpgradeable.sol:ERC721PresetMinterPauserAutoIdCustomizedUpgradeable.log new file mode 100644 index 0000000..31caffd --- /dev/null +++ b/logs/storage/ERC721PresetMinterPauserAutoIdCustomizedUpgradeable.sol:ERC721PresetMinterPauserAutoIdCustomizedUpgradeable.log @@ -0,0 +1,27 @@ +src/upgradeable/ERC721PresetMinterPauserAutoIdCustomizedUpgradeable.sol:ERC721PresetMinterPauserAutoIdCustomizedUpgradeable:_initialized (storage_slot: 0) (offset: 0) (type: uint8) (numberOfBytes: 1) +src/upgradeable/ERC721PresetMinterPauserAutoIdCustomizedUpgradeable.sol:ERC721PresetMinterPauserAutoIdCustomizedUpgradeable:_initializing (storage_slot: 0) (offset: 1) (type: bool) (numberOfBytes: 1) +src/upgradeable/ERC721PresetMinterPauserAutoIdCustomizedUpgradeable.sol:ERC721PresetMinterPauserAutoIdCustomizedUpgradeable:__gap (storage_slot: 1) (offset: 0) (type: uint256[50]) (numberOfBytes: 1600) +src/upgradeable/ERC721PresetMinterPauserAutoIdCustomizedUpgradeable.sol:ERC721PresetMinterPauserAutoIdCustomizedUpgradeable:__gap (storage_slot: 51) (offset: 0) (type: uint256[50]) (numberOfBytes: 1600) +src/upgradeable/ERC721PresetMinterPauserAutoIdCustomizedUpgradeable.sol:ERC721PresetMinterPauserAutoIdCustomizedUpgradeable:_roles (storage_slot: 101) (offset: 0) (type: mapping(bytes32 => struct AccessControlUpgradeable.RoleData)) (numberOfBytes: 32) +src/upgradeable/ERC721PresetMinterPauserAutoIdCustomizedUpgradeable.sol:ERC721PresetMinterPauserAutoIdCustomizedUpgradeable:__gap (storage_slot: 102) (offset: 0) (type: uint256[49]) (numberOfBytes: 1568) +src/upgradeable/ERC721PresetMinterPauserAutoIdCustomizedUpgradeable.sol:ERC721PresetMinterPauserAutoIdCustomizedUpgradeable:_roleMembers (storage_slot: 151) (offset: 0) (type: mapping(bytes32 => struct EnumerableSetUpgradeable.AddressSet)) (numberOfBytes: 32) +src/upgradeable/ERC721PresetMinterPauserAutoIdCustomizedUpgradeable.sol:ERC721PresetMinterPauserAutoIdCustomizedUpgradeable:__gap (storage_slot: 152) (offset: 0) (type: uint256[49]) (numberOfBytes: 1568) +src/upgradeable/ERC721PresetMinterPauserAutoIdCustomizedUpgradeable.sol:ERC721PresetMinterPauserAutoIdCustomizedUpgradeable:_name (storage_slot: 201) (offset: 0) (type: string) (numberOfBytes: 32) +src/upgradeable/ERC721PresetMinterPauserAutoIdCustomizedUpgradeable.sol:ERC721PresetMinterPauserAutoIdCustomizedUpgradeable:_symbol (storage_slot: 202) (offset: 0) (type: string) (numberOfBytes: 32) +src/upgradeable/ERC721PresetMinterPauserAutoIdCustomizedUpgradeable.sol:ERC721PresetMinterPauserAutoIdCustomizedUpgradeable:_owners (storage_slot: 203) (offset: 0) (type: mapping(uint256 => address)) (numberOfBytes: 32) +src/upgradeable/ERC721PresetMinterPauserAutoIdCustomizedUpgradeable.sol:ERC721PresetMinterPauserAutoIdCustomizedUpgradeable:_balances (storage_slot: 204) (offset: 0) (type: mapping(address => uint256)) (numberOfBytes: 32) +src/upgradeable/ERC721PresetMinterPauserAutoIdCustomizedUpgradeable.sol:ERC721PresetMinterPauserAutoIdCustomizedUpgradeable:_tokenApprovals (storage_slot: 205) (offset: 0) (type: mapping(uint256 => address)) (numberOfBytes: 32) +src/upgradeable/ERC721PresetMinterPauserAutoIdCustomizedUpgradeable.sol:ERC721PresetMinterPauserAutoIdCustomizedUpgradeable:_operatorApprovals (storage_slot: 206) (offset: 0) (type: mapping(address => mapping(address => bool))) (numberOfBytes: 32) +src/upgradeable/ERC721PresetMinterPauserAutoIdCustomizedUpgradeable.sol:ERC721PresetMinterPauserAutoIdCustomizedUpgradeable:__gap (storage_slot: 207) (offset: 0) (type: uint256[44]) (numberOfBytes: 1408) +src/upgradeable/ERC721PresetMinterPauserAutoIdCustomizedUpgradeable.sol:ERC721PresetMinterPauserAutoIdCustomizedUpgradeable:_ownedTokens (storage_slot: 251) (offset: 0) (type: mapping(address => mapping(uint256 => uint256))) (numberOfBytes: 32) +src/upgradeable/ERC721PresetMinterPauserAutoIdCustomizedUpgradeable.sol:ERC721PresetMinterPauserAutoIdCustomizedUpgradeable:_ownedTokensIndex (storage_slot: 252) (offset: 0) (type: mapping(uint256 => uint256)) (numberOfBytes: 32) +src/upgradeable/ERC721PresetMinterPauserAutoIdCustomizedUpgradeable.sol:ERC721PresetMinterPauserAutoIdCustomizedUpgradeable:_allTokens (storage_slot: 253) (offset: 0) (type: uint256[]) (numberOfBytes: 32) +src/upgradeable/ERC721PresetMinterPauserAutoIdCustomizedUpgradeable.sol:ERC721PresetMinterPauserAutoIdCustomizedUpgradeable:_allTokensIndex (storage_slot: 254) (offset: 0) (type: mapping(uint256 => uint256)) (numberOfBytes: 32) +src/upgradeable/ERC721PresetMinterPauserAutoIdCustomizedUpgradeable.sol:ERC721PresetMinterPauserAutoIdCustomizedUpgradeable:__gap (storage_slot: 255) (offset: 0) (type: uint256[46]) (numberOfBytes: 1472) +src/upgradeable/ERC721PresetMinterPauserAutoIdCustomizedUpgradeable.sol:ERC721PresetMinterPauserAutoIdCustomizedUpgradeable:__gap (storage_slot: 301) (offset: 0) (type: uint256[50]) (numberOfBytes: 1600) +src/upgradeable/ERC721PresetMinterPauserAutoIdCustomizedUpgradeable.sol:ERC721PresetMinterPauserAutoIdCustomizedUpgradeable:_paused (storage_slot: 351) (offset: 0) (type: bool) (numberOfBytes: 1) +src/upgradeable/ERC721PresetMinterPauserAutoIdCustomizedUpgradeable.sol:ERC721PresetMinterPauserAutoIdCustomizedUpgradeable:__gap (storage_slot: 352) (offset: 0) (type: uint256[49]) (numberOfBytes: 1568) +src/upgradeable/ERC721PresetMinterPauserAutoIdCustomizedUpgradeable.sol:ERC721PresetMinterPauserAutoIdCustomizedUpgradeable:__gap (storage_slot: 401) (offset: 0) (type: uint256[50]) (numberOfBytes: 1600) +src/upgradeable/ERC721PresetMinterPauserAutoIdCustomizedUpgradeable.sol:ERC721PresetMinterPauserAutoIdCustomizedUpgradeable:_tokenIdTracker (storage_slot: 451) (offset: 0) (type: struct CountersUpgradeable.Counter) (numberOfBytes: 32) +src/upgradeable/ERC721PresetMinterPauserAutoIdCustomizedUpgradeable.sol:ERC721PresetMinterPauserAutoIdCustomizedUpgradeable:_baseTokenURI (storage_slot: 452) (offset: 0) (type: string) (numberOfBytes: 32) +src/upgradeable/ERC721PresetMinterPauserAutoIdCustomizedUpgradeable.sol:ERC721PresetMinterPauserAutoIdCustomizedUpgradeable:__gap (storage_slot: 453) (offset: 0) (type: uint256[48]) (numberOfBytes: 1536) \ No newline at end of file diff --git a/logs/storage/SampleERC721.sol:SampleERC721.log b/logs/storage/SampleERC721.sol:SampleERC721.log new file mode 100644 index 0000000..c7c5f97 --- /dev/null +++ b/logs/storage/SampleERC721.sol:SampleERC721.log @@ -0,0 +1,17 @@ +src/mock/SampleERC721.sol:SampleERC721:_roles (storage_slot: 0) (offset: 0) (type: mapping(bytes32 => struct AccessControl.RoleData)) (numberOfBytes: 32) +src/mock/SampleERC721.sol:SampleERC721:_roleMembers (storage_slot: 1) (offset: 0) (type: mapping(bytes32 => struct EnumerableSet.AddressSet)) (numberOfBytes: 32) +src/mock/SampleERC721.sol:SampleERC721:_name (storage_slot: 2) (offset: 0) (type: string) (numberOfBytes: 32) +src/mock/SampleERC721.sol:SampleERC721:_symbol (storage_slot: 3) (offset: 0) (type: string) (numberOfBytes: 32) +src/mock/SampleERC721.sol:SampleERC721:_owners (storage_slot: 4) (offset: 0) (type: mapping(uint256 => address)) (numberOfBytes: 32) +src/mock/SampleERC721.sol:SampleERC721:_balances (storage_slot: 5) (offset: 0) (type: mapping(address => uint256)) (numberOfBytes: 32) +src/mock/SampleERC721.sol:SampleERC721:_tokenApprovals (storage_slot: 6) (offset: 0) (type: mapping(uint256 => address)) (numberOfBytes: 32) +src/mock/SampleERC721.sol:SampleERC721:_operatorApprovals (storage_slot: 7) (offset: 0) (type: mapping(address => mapping(address => bool))) (numberOfBytes: 32) +src/mock/SampleERC721.sol:SampleERC721:nonces (storage_slot: 8) (offset: 0) (type: mapping(uint256 => uint256)) (numberOfBytes: 32) +src/mock/SampleERC721.sol:SampleERC721:______gap (storage_slot: 9) (offset: 0) (type: uint256[50]) (numberOfBytes: 1600) +src/mock/SampleERC721.sol:SampleERC721:_ownedTokens (storage_slot: 59) (offset: 0) (type: mapping(address => mapping(uint256 => uint256))) (numberOfBytes: 32) +src/mock/SampleERC721.sol:SampleERC721:_ownedTokensIndex (storage_slot: 60) (offset: 0) (type: mapping(uint256 => uint256)) (numberOfBytes: 32) +src/mock/SampleERC721.sol:SampleERC721:_allTokens (storage_slot: 61) (offset: 0) (type: uint256[]) (numberOfBytes: 32) +src/mock/SampleERC721.sol:SampleERC721:_allTokensIndex (storage_slot: 62) (offset: 0) (type: mapping(uint256 => uint256)) (numberOfBytes: 32) +src/mock/SampleERC721.sol:SampleERC721:_paused (storage_slot: 63) (offset: 0) (type: bool) (numberOfBytes: 1) +src/mock/SampleERC721.sol:SampleERC721:_tokenIdTracker (storage_slot: 64) (offset: 0) (type: struct Counters.Counter) (numberOfBytes: 32) +src/mock/SampleERC721.sol:SampleERC721:_baseTokenURI (storage_slot: 65) (offset: 0) (type: string) (numberOfBytes: 32) \ No newline at end of file diff --git a/logs/storage/SampleERC721Upgradeable.sol:SampleERC721Upgradeable.log b/logs/storage/SampleERC721Upgradeable.sol:SampleERC721Upgradeable.log new file mode 100644 index 0000000..1bd7fa3 --- /dev/null +++ b/logs/storage/SampleERC721Upgradeable.sol:SampleERC721Upgradeable.log @@ -0,0 +1,29 @@ +src/mock/SampleERC721Upgradeable.sol:SampleERC721Upgradeable:_initialized (storage_slot: 0) (offset: 0) (type: uint8) (numberOfBytes: 1) +src/mock/SampleERC721Upgradeable.sol:SampleERC721Upgradeable:_initializing (storage_slot: 0) (offset: 1) (type: bool) (numberOfBytes: 1) +src/mock/SampleERC721Upgradeable.sol:SampleERC721Upgradeable:__gap (storage_slot: 1) (offset: 0) (type: uint256[50]) (numberOfBytes: 1600) +src/mock/SampleERC721Upgradeable.sol:SampleERC721Upgradeable:__gap (storage_slot: 51) (offset: 0) (type: uint256[50]) (numberOfBytes: 1600) +src/mock/SampleERC721Upgradeable.sol:SampleERC721Upgradeable:_roles (storage_slot: 101) (offset: 0) (type: mapping(bytes32 => struct AccessControlUpgradeable.RoleData)) (numberOfBytes: 32) +src/mock/SampleERC721Upgradeable.sol:SampleERC721Upgradeable:__gap (storage_slot: 102) (offset: 0) (type: uint256[49]) (numberOfBytes: 1568) +src/mock/SampleERC721Upgradeable.sol:SampleERC721Upgradeable:_roleMembers (storage_slot: 151) (offset: 0) (type: mapping(bytes32 => struct EnumerableSetUpgradeable.AddressSet)) (numberOfBytes: 32) +src/mock/SampleERC721Upgradeable.sol:SampleERC721Upgradeable:__gap (storage_slot: 152) (offset: 0) (type: uint256[49]) (numberOfBytes: 1568) +src/mock/SampleERC721Upgradeable.sol:SampleERC721Upgradeable:_name (storage_slot: 201) (offset: 0) (type: string) (numberOfBytes: 32) +src/mock/SampleERC721Upgradeable.sol:SampleERC721Upgradeable:_symbol (storage_slot: 202) (offset: 0) (type: string) (numberOfBytes: 32) +src/mock/SampleERC721Upgradeable.sol:SampleERC721Upgradeable:_owners (storage_slot: 203) (offset: 0) (type: mapping(uint256 => address)) (numberOfBytes: 32) +src/mock/SampleERC721Upgradeable.sol:SampleERC721Upgradeable:_balances (storage_slot: 204) (offset: 0) (type: mapping(address => uint256)) (numberOfBytes: 32) +src/mock/SampleERC721Upgradeable.sol:SampleERC721Upgradeable:_tokenApprovals (storage_slot: 205) (offset: 0) (type: mapping(uint256 => address)) (numberOfBytes: 32) +src/mock/SampleERC721Upgradeable.sol:SampleERC721Upgradeable:_operatorApprovals (storage_slot: 206) (offset: 0) (type: mapping(address => mapping(address => bool))) (numberOfBytes: 32) +src/mock/SampleERC721Upgradeable.sol:SampleERC721Upgradeable:__gap (storage_slot: 207) (offset: 0) (type: uint256[44]) (numberOfBytes: 1408) +src/mock/SampleERC721Upgradeable.sol:SampleERC721Upgradeable:nonces (storage_slot: 251) (offset: 0) (type: mapping(uint256 => uint256)) (numberOfBytes: 32) +src/mock/SampleERC721Upgradeable.sol:SampleERC721Upgradeable:______gap (storage_slot: 252) (offset: 0) (type: uint256[50]) (numberOfBytes: 1600) +src/mock/SampleERC721Upgradeable.sol:SampleERC721Upgradeable:_ownedTokens (storage_slot: 302) (offset: 0) (type: mapping(address => mapping(uint256 => uint256))) (numberOfBytes: 32) +src/mock/SampleERC721Upgradeable.sol:SampleERC721Upgradeable:_ownedTokensIndex (storage_slot: 303) (offset: 0) (type: mapping(uint256 => uint256)) (numberOfBytes: 32) +src/mock/SampleERC721Upgradeable.sol:SampleERC721Upgradeable:_allTokens (storage_slot: 304) (offset: 0) (type: uint256[]) (numberOfBytes: 32) +src/mock/SampleERC721Upgradeable.sol:SampleERC721Upgradeable:_allTokensIndex (storage_slot: 305) (offset: 0) (type: mapping(uint256 => uint256)) (numberOfBytes: 32) +src/mock/SampleERC721Upgradeable.sol:SampleERC721Upgradeable:__gap (storage_slot: 306) (offset: 0) (type: uint256[46]) (numberOfBytes: 1472) +src/mock/SampleERC721Upgradeable.sol:SampleERC721Upgradeable:__gap (storage_slot: 352) (offset: 0) (type: uint256[50]) (numberOfBytes: 1600) +src/mock/SampleERC721Upgradeable.sol:SampleERC721Upgradeable:_paused (storage_slot: 402) (offset: 0) (type: bool) (numberOfBytes: 1) +src/mock/SampleERC721Upgradeable.sol:SampleERC721Upgradeable:__gap (storage_slot: 403) (offset: 0) (type: uint256[49]) (numberOfBytes: 1568) +src/mock/SampleERC721Upgradeable.sol:SampleERC721Upgradeable:__gap (storage_slot: 452) (offset: 0) (type: uint256[50]) (numberOfBytes: 1600) +src/mock/SampleERC721Upgradeable.sol:SampleERC721Upgradeable:_tokenIdTracker (storage_slot: 502) (offset: 0) (type: struct CountersUpgradeable.Counter) (numberOfBytes: 32) +src/mock/SampleERC721Upgradeable.sol:SampleERC721Upgradeable:_baseTokenURI (storage_slot: 503) (offset: 0) (type: string) (numberOfBytes: 32) +src/mock/SampleERC721Upgradeable.sol:SampleERC721Upgradeable:__gap (storage_slot: 504) (offset: 0) (type: uint256[48]) (numberOfBytes: 1536) \ No newline at end of file From 7b2f7326a8abc88abf5b6aae8db3b79883879d3d Mon Sep 17 00:00:00 2001 From: huyhuynh3103 Date: Tue, 16 Apr 2024 10:37:59 +0700 Subject: [PATCH 15/22] chore: fix gitignore --- .husky/.gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.husky/.gitignore b/.husky/.gitignore index e69de29..c9cdc63 100644 --- a/.husky/.gitignore +++ b/.husky/.gitignore @@ -0,0 +1 @@ +_ \ No newline at end of file From 5037dde85780b866f035600bb7328b152e7f74bf Mon Sep 17 00:00:00 2001 From: huyhuynh3103 Date: Tue, 16 Apr 2024 10:50:50 +0700 Subject: [PATCH 16/22] chore: use custom error instead --- src/upgradeable/ERC721CommonUpgradeable.sol | 11 +++++++---- ...esetMinterPauserAutoIdCustomizedUpgradeable.sol | 14 +++++++++++--- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/src/upgradeable/ERC721CommonUpgradeable.sol b/src/upgradeable/ERC721CommonUpgradeable.sol index 545f042..56e5690 100644 --- a/src/upgradeable/ERC721CommonUpgradeable.sol +++ b/src/upgradeable/ERC721CommonUpgradeable.sol @@ -10,6 +10,9 @@ abstract contract ERC721CommonUpgradeable is ERC721PresetMinterPauserAutoIdCustomizedUpgradeable, IERC721State { + error ErrInvalidArrayLength(); + error ErrNonExistentToken(); + constructor() { _disableInitializers(); } @@ -18,12 +21,12 @@ abstract contract ERC721CommonUpgradeable is * @inheritdoc IERC721State */ function stateOf(uint256 _tokenId) external view virtual override returns (bytes memory) { - require(_exists(_tokenId), "ERC721Common: query for non-existent token"); + if (!_exists(_tokenId)) revert ErrNonExistentToken(); return abi.encodePacked(ownerOf(_tokenId), nonces[_tokenId], _tokenId); } /** - * @dev Override `ERC721-_baseURI`. + * @dev Override `ERC721Upgradeable-_baseURI`. */ function _baseURI() internal @@ -49,7 +52,7 @@ abstract contract ERC721CommonUpgradeable is } /** - * @dev Override `ERC721PresetMinterPauserAutoIdCustomized-_beforeTokenTransfer`. + * @dev Override `ERC721PresetMinterPauserAutoIdCustomizedUpgradeable-_beforeTokenTransfer`. */ function _beforeTokenTransfer(address _from, address _to, uint256 _firstTokenId, uint256 _batchSize) internal @@ -76,7 +79,7 @@ abstract contract ERC721CommonUpgradeable is onlyRole(MINTER_ROLE) returns (uint256[] memory _tokenIds) { - require(_recipients.length > 0, "ERC721Common: invalid array lengths"); + if (_recipients.length == 0) revert ErrInvalidArrayLength(); _tokenIds = new uint256[](_recipients.length); for (uint256 _i = 0; _i < _recipients.length; _i++) { diff --git a/src/upgradeable/ERC721PresetMinterPauserAutoIdCustomizedUpgradeable.sol b/src/upgradeable/ERC721PresetMinterPauserAutoIdCustomizedUpgradeable.sol index 3087f07..7790e5f 100644 --- a/src/upgradeable/ERC721PresetMinterPauserAutoIdCustomizedUpgradeable.sol +++ b/src/upgradeable/ERC721PresetMinterPauserAutoIdCustomizedUpgradeable.sol @@ -37,6 +37,8 @@ contract ERC721PresetMinterPauserAutoIdCustomizedUpgradeable is ERC721BurnableUpgradeable, ERC721PausableUpgradeable { + error ErrUnauthorizedAccount(address account, bytes32 neededRole); + using CountersUpgradeable for CountersUpgradeable.Counter; bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); @@ -95,7 +97,9 @@ contract ERC721PresetMinterPauserAutoIdCustomizedUpgradeable is * - the caller must have the `MINTER_ROLE`. */ function mint(address to) public virtual returns (uint256 tokenId) { - require(hasRole(MINTER_ROLE, _msgSender()), "ERC721PresetMinterPauserAutoId: must have minter role to mint"); + address sender = _msgSender(); + if (!hasRole(MINTER_ROLE, sender)) revert ErrUnauthorizedAccount(sender, MINTER_ROLE); + tokenId = _mintFor(to); } @@ -109,7 +113,9 @@ contract ERC721PresetMinterPauserAutoIdCustomizedUpgradeable is * - the caller must have the `PAUSER_ROLE`. */ function pause() public virtual { - require(hasRole(PAUSER_ROLE, _msgSender()), "ERC721PresetMinterPauserAutoId: must have pauser role to pause"); + address sender = _msgSender(); + if (!hasRole(PAUSER_ROLE, sender)) revert ErrUnauthorizedAccount(sender, PAUSER_ROLE); + _pause(); } @@ -123,7 +129,9 @@ contract ERC721PresetMinterPauserAutoIdCustomizedUpgradeable is * - the caller must have the `PAUSER_ROLE`. */ function unpause() public virtual { - require(hasRole(PAUSER_ROLE, _msgSender()), "ERC721PresetMinterPauserAutoId: must have pauser role to unpause"); + address sender = _msgSender(); + if (!hasRole(PAUSER_ROLE, sender)) revert ErrUnauthorizedAccount(sender, PAUSER_ROLE); + _unpause(); } From f32a5413839c0f79e7a83d2bf3334b81e09f2133 Mon Sep 17 00:00:00 2001 From: huyhuynh3103 Date: Tue, 16 Apr 2024 10:52:39 +0700 Subject: [PATCH 17/22] feat: remove .DS_Store --- .DS_Store | Bin 6148 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 .DS_Store diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index cb6d06e5541cde63fb3630cd6b1db2ddaf11e863..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHK%}T>S5T0#on^J@x6!f;>wP;(#AH0NGU%-eSRBB_224l7~sYOa5cYPsW#OHBl zcPrKEO+?BJ%znE&^Cj6YVK)N+qBRT}0962R&d!tTuku_U>d-c2+mG4o^Dw(L=1Bjg|sGJ8jDrr|^QEFUty&o5;t< zB+8f2qc?~n72jfnqD9n$lt|zno@QwnV`Bwa0ajoU6tJ78Q(1(?@ETYFR^V3^p#4Fj z6S@{NgL>=0MwbAH^c$%S`&3I1M_P0(W(F~WCJYtPP=zfqgrVcSw0W+@%%Guzu*HY4 zcNVrn5&G_UeW}wyxCXgp1z3U43gpeOO6ULa&-MRj5|3B`R$!qN5QVnaZsC&b**dp4 wI%_5RH98sPWd=Ve*wIHZ=F(BThOQ0gC3O&8i3LE|3*Edw{Kz@IAc4)lUpCIA2c From 8c72ed8700697a5fdbcd322fee1d78c896ece615 Mon Sep 17 00:00:00 2001 From: huyhuynh3103 Date: Tue, 16 Apr 2024 10:55:53 +0700 Subject: [PATCH 18/22] chore: fix comments --- src/upgradeable/ERC721CommonUpgradeable.sol | 4 ++-- ...21PresetMinterPauserAutoIdCustomizedUpgradeable.sol | 10 +++++----- src/upgradeable/refs/ERC721NonceUpgradeable.sol | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/upgradeable/ERC721CommonUpgradeable.sol b/src/upgradeable/ERC721CommonUpgradeable.sol index 56e5690..f664fa6 100644 --- a/src/upgradeable/ERC721CommonUpgradeable.sol +++ b/src/upgradeable/ERC721CommonUpgradeable.sol @@ -64,10 +64,10 @@ abstract contract ERC721CommonUpgradeable is /** * @dev Bulk create new tokens for `_recipients`. Tokens ID will be automatically - * assigned (and available on the emitted {IERC721-Transfer} event), and the token + * assigned (and available on the emitted {IERC721Upgradeable-Transfer} event), and the token * URI autogenerated based on the base URI passed at construction. * - * See {ERC721-_mint}. + * See {ERC721Upgradeable-_mint}. * * Requirements: * diff --git a/src/upgradeable/ERC721PresetMinterPauserAutoIdCustomizedUpgradeable.sol b/src/upgradeable/ERC721PresetMinterPauserAutoIdCustomizedUpgradeable.sol index 7790e5f..afe0ed3 100644 --- a/src/upgradeable/ERC721PresetMinterPauserAutoIdCustomizedUpgradeable.sol +++ b/src/upgradeable/ERC721PresetMinterPauserAutoIdCustomizedUpgradeable.sol @@ -87,10 +87,10 @@ contract ERC721PresetMinterPauserAutoIdCustomizedUpgradeable is /** * @dev Creates a new token for `to`. Its token ID will be automatically - * assigned (and available on the emitted {IERC721-Transfer} event), and the token + * assigned (and available on the emitted {IERC721Upgradeable-Transfer} event), and the token * URI autogenerated based on the base URI passed at construction. * - * See {ERC721-_mint}. + * See {ERC721Upgradeable-_mint}. * * Requirements: * @@ -106,7 +106,7 @@ contract ERC721PresetMinterPauserAutoIdCustomizedUpgradeable is /** * @dev Pauses all token transfers. * - * See {ERC721Pausable} and {Pausable-_pause}. + * See {ERC721PausableUpgradeable} and {PausableUpgradeable-_pause}. * * Requirements: * @@ -122,7 +122,7 @@ contract ERC721PresetMinterPauserAutoIdCustomizedUpgradeable is /** * @dev Unpauses all token transfers. * - * See {ERC721Pausable} and {Pausable-_unpause}. + * See {ERC721PausableUpgradeable} and {PausableUpgradeable-_unpause}. * * Requirements: * @@ -159,7 +159,7 @@ contract ERC721PresetMinterPauserAutoIdCustomizedUpgradeable is /** * @dev Helper function to mint for address `to`. * - * See {ERC721-_mint}. + * See {ERC721Upgradeable-_mint}. * */ function _mintFor(address to) internal virtual returns (uint256 _tokenId) { diff --git a/src/upgradeable/refs/ERC721NonceUpgradeable.sol b/src/upgradeable/refs/ERC721NonceUpgradeable.sol index 14b7faa..6193a97 100644 --- a/src/upgradeable/refs/ERC721NonceUpgradeable.sol +++ b/src/upgradeable/refs/ERC721NonceUpgradeable.sol @@ -21,7 +21,7 @@ abstract contract ERC721NonceUpgradeable is ERC721Upgradeable { uint256[50] private ______gap; /** - * @dev Override `ERC721-_beforeTokenTransfer`. + * @dev Override `ERC721Upgradeable-_beforeTokenTransfer`. */ function _beforeTokenTransfer(address _from, address _to, uint256 _firstTokenId, uint256 _batchSize) internal From 78850b88679a2bfc995bd14ca003af10189b6a3e Mon Sep 17 00:00:00 2001 From: huyhuynh3103 Date: Tue, 16 Apr 2024 11:06:50 +0700 Subject: [PATCH 19/22] chore: fix linter --- .husky/storage-logger.js | 88 ++++++++++++++++++++-------------------- 1 file changed, 44 insertions(+), 44 deletions(-) diff --git a/.husky/storage-logger.js b/.husky/storage-logger.js index fb8eba0..840711b 100644 --- a/.husky/storage-logger.js +++ b/.husky/storage-logger.js @@ -3,59 +3,59 @@ const fileIn = process.argv[2]; const fileOut = process.argv[3]; if (!fileIn) { - console.error('Invalid input'); + console.error('Invalid input'); } fs.readFile(fileIn, 'utf8', (err, data) => { console.log("fileIn", fileIn) if (err) { console.error('Error reading file:', err); - return; - } - - try { + return; + } + + try { const jsonData = JSON.parse(data); - + console.log("jsonData", jsonData.storageLayout); - if (typeof jsonData.storageLayout == 'undefined') return; - if (jsonData.storageLayout.storage.length == 0) return; - - const hasAst = typeof jsonData.ast != 'undefined'; - let storageLayout; - if (hasAst) { + if (typeof jsonData.storageLayout == 'undefined') return; + if (jsonData.storageLayout.storage.length == 0) return; + + const hasAst = typeof jsonData.ast != 'undefined'; + let storageLayout; + if (hasAst) { const absolutePath = jsonData.ast.absolutePath; - if (typeof absolutePath == 'undefined') return; - if (!absolutePath.startsWith('src')) return; - storageLayout = jsonData.storageLayout.storage; - } else { + if (typeof absolutePath == 'undefined') return; + if (!absolutePath.startsWith('src')) return; + storageLayout = jsonData.storageLayout.storage; + } else { // filter only contracts in src/* - storageLayout = jsonData.storageLayout.storage.filter(({ contract }) => - contract.startsWith('src') - ); - } - - const outputData = storageLayout - .map(({ contract, label, offset, slot, type: typeId }) => { - const typeObj = jsonData.storageLayout.types[typeId]; - const typeLabel = typeObj.label; - const numberOfBytes = typeObj.numberOfBytes; - return `${contract}:${label} (storage_slot: ${slot}) (offset: ${offset}) (type: ${typeLabel}) (numberOfBytes: ${numberOfBytes})`; - }) - .join('\n'); - - if (outputData == '') return; - - if (!fileOut) { - console.log(outputData); - } else { - fs.writeFile(fileOut, outputData, 'utf-8', (err) => { - if (err) { - console.error('Error writing file:', err); - return; - } - }); + storageLayout = jsonData.storageLayout.storage.filter(({ contract }) => + contract.startsWith('src') + ); + } + + const outputData = storageLayout + .map(({ contract, label, offset, slot, type: typeId }) => { + const typeObj = jsonData.storageLayout.types[typeId]; + const typeLabel = typeObj.label; + const numberOfBytes = typeObj.numberOfBytes; + return `${contract}:${label} (storage_slot: ${slot}) (offset: ${offset}) (type: ${typeLabel}) (numberOfBytes: ${numberOfBytes})`; + }) + .join('\n'); + + if (outputData == '') return; + + if (!fileOut) { + console.log(outputData); + } else { + fs.writeFile(fileOut, outputData, 'utf-8', (err) => { + if (err) { + console.error('Error writing file:', err); + return; + } + }); + } + } catch (err) { + console.error('Error parsing JSON:', err); } -} catch (err) { - console.error('Error parsing JSON:', err); -} }); From dc16164f17348ce5b0f5d66add9cba9ab8c11f51 Mon Sep 17 00:00:00 2001 From: huyhuynh3103 Date: Tue, 16 Apr 2024 11:08:11 +0700 Subject: [PATCH 20/22] chore: linter storagelayout.js --- .husky/storage-logger.js | 105 +++++++++++++++++++-------------------- 1 file changed, 52 insertions(+), 53 deletions(-) diff --git a/.husky/storage-logger.js b/.husky/storage-logger.js index 840711b..ba8b3ee 100644 --- a/.husky/storage-logger.js +++ b/.husky/storage-logger.js @@ -3,59 +3,58 @@ const fileIn = process.argv[2]; const fileOut = process.argv[3]; if (!fileIn) { - console.error('Invalid input'); + console.error('Invalid input'); } fs.readFile(fileIn, 'utf8', (err, data) => { - console.log("fileIn", fileIn) - if (err) { - console.error('Error reading file:', err); - return; - } - - try { - const jsonData = JSON.parse(data); - - console.log("jsonData", jsonData.storageLayout); - if (typeof jsonData.storageLayout == 'undefined') return; - if (jsonData.storageLayout.storage.length == 0) return; - - const hasAst = typeof jsonData.ast != 'undefined'; - let storageLayout; - if (hasAst) { - const absolutePath = jsonData.ast.absolutePath; - if (typeof absolutePath == 'undefined') return; - if (!absolutePath.startsWith('src')) return; - storageLayout = jsonData.storageLayout.storage; - } else { - // filter only contracts in src/* - storageLayout = jsonData.storageLayout.storage.filter(({ contract }) => - contract.startsWith('src') - ); - } - - const outputData = storageLayout - .map(({ contract, label, offset, slot, type: typeId }) => { - const typeObj = jsonData.storageLayout.types[typeId]; - const typeLabel = typeObj.label; - const numberOfBytes = typeObj.numberOfBytes; - return `${contract}:${label} (storage_slot: ${slot}) (offset: ${offset}) (type: ${typeLabel}) (numberOfBytes: ${numberOfBytes})`; - }) - .join('\n'); - - if (outputData == '') return; - - if (!fileOut) { - console.log(outputData); - } else { - fs.writeFile(fileOut, outputData, 'utf-8', (err) => { - if (err) { - console.error('Error writing file:', err); - return; - } - }); - } - } catch (err) { - console.error('Error parsing JSON:', err); - } -}); + if (err) { + console.error('Error reading file:', err); + return; + } + + try { + const jsonData = JSON.parse(data); + + if (typeof jsonData.storageLayout == 'undefined') return; + if (jsonData.storageLayout.storage.length == 0) return; + + const hasAst = typeof jsonData.ast != 'undefined'; + + let storageLayout; + if (hasAst) { + const absolutePath = jsonData.ast.absolutePath; + if (typeof absolutePath == 'undefined') return; + if (!absolutePath.startsWith('src')) return; + storageLayout = jsonData.storageLayout.storage; + } else { + // filter only contracts in src/* + storageLayout = jsonData.storageLayout.storage.filter(({ contract }) => + contract.startsWith('src') + ); + } + + const outputData = storageLayout + .map(({ contract, label, offset, slot, type: typeId }) => { + const typeObj = jsonData.storageLayout.types[typeId]; + const typeLabel = typeObj.label; + const numberOfBytes = typeObj.numberOfBytes; + return `${contract}:${label} (storage_slot: ${slot}) (offset: ${offset}) (type: ${typeLabel}) (numberOfBytes: ${numberOfBytes})`; + }) + .join('\n'); + + if (outputData == '') return; + + if (!fileOut) { + console.log(outputData); + } else { + fs.writeFile(fileOut, outputData, 'utf-8', (err) => { + if (err) { + console.error('Error writing file:', err); + return; + } + }); + } + } catch (err) { + console.error('Error parsing JSON:', err); + } +}); \ No newline at end of file From c448189977b4623e09d327df8eced798fa806b99 Mon Sep 17 00:00:00 2001 From: huyhuynh3103 Date: Wed, 17 Apr 2024 10:25:42 +0700 Subject: [PATCH 21/22] feat: move ci into another files --- .gitmodules | 4 - lib/openzeppelin-contracts-upgradeable | 1 - .../deploy/logic/erc721-upgradeable-logic.sol | 16 -- scripts/deploy/proxy-admin.ts | 16 -- .../deploy/proxy/erc721-upgradeable-proxy.ts | 25 --- src/mock/SampleERC721Upgradeable.sol | 6 - src/upgradeable/ERC721CommonUpgradeable.sol | 89 --------- ...interPauserAutoIdCustomizedUpgradeable.sol | 179 ------------------ .../refs/ERC721NonceUpgradeable.sol | 36 ---- test/foundry/SampleERC721Upgradeable.t.sol | 101 ---------- 10 files changed, 473 deletions(-) delete mode 160000 lib/openzeppelin-contracts-upgradeable delete mode 100644 scripts/deploy/logic/erc721-upgradeable-logic.sol delete mode 100644 scripts/deploy/proxy-admin.ts delete mode 100644 scripts/deploy/proxy/erc721-upgradeable-proxy.ts delete mode 100644 src/mock/SampleERC721Upgradeable.sol delete mode 100644 src/upgradeable/ERC721CommonUpgradeable.sol delete mode 100644 src/upgradeable/ERC721PresetMinterPauserAutoIdCustomizedUpgradeable.sol delete mode 100644 src/upgradeable/refs/ERC721NonceUpgradeable.sol delete mode 100644 test/foundry/SampleERC721Upgradeable.t.sol diff --git a/.gitmodules b/.gitmodules index 1674f48..e3d8d16 100644 --- a/.gitmodules +++ b/.gitmodules @@ -6,7 +6,3 @@ path = lib/openzeppelin-contracts url = https://github.com/openzeppelin/openzeppelin-contracts branch = v4.8.2 -[submodule "lib/openzeppelin-contracts-upgradeable"] - path = lib/openzeppelin-contracts-upgradeable - url = https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable - branch = v4.9.5 diff --git a/lib/openzeppelin-contracts-upgradeable b/lib/openzeppelin-contracts-upgradeable deleted file mode 160000 index a40cb0b..0000000 --- a/lib/openzeppelin-contracts-upgradeable +++ /dev/null @@ -1 +0,0 @@ -Subproject commit a40cb0bda838c2ef3dfc252c179f5c37c32e80c4 diff --git a/scripts/deploy/logic/erc721-upgradeable-logic.sol b/scripts/deploy/logic/erc721-upgradeable-logic.sol deleted file mode 100644 index 63c45ab..0000000 --- a/scripts/deploy/logic/erc721-upgradeable-logic.sol +++ /dev/null @@ -1,16 +0,0 @@ -import { HardhatRuntimeEnvironment } from 'hardhat/types'; - -const deploy = async ({ getNamedAccounts, deployments, ethers }: HardhatRuntimeEnvironment) => { - const { deploy } = deployments; - const { deployer } = await getNamedAccounts(); - await deploy('SampleERC721CommonUpgradeableLogic', { - contract: 'ERC721CommonUpgradeable', - from: deployer, - log: true, - }); -}; - -deploy.tags = ['SampleERC721CommonUpgradeableLogic']; -deploy.dependencies = ['VerifyContracts']; - -export default deploy; diff --git a/scripts/deploy/proxy-admin.ts b/scripts/deploy/proxy-admin.ts deleted file mode 100644 index 6295715..0000000 --- a/scripts/deploy/proxy-admin.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { HardhatRuntimeEnvironment } from 'hardhat/types'; - -const deploy = async ({ getNamedAccounts, deployments, ethers }: HardhatRuntimeEnvironment) => { - const { deploy } = deployments; - const { deployer } = await getNamedAccounts(); - await deploy('ProxyAdmin', { - contract: 'ProxyAdmin', - from: deployer, - log: true, - }); -}; - -deploy.tags = ['ProxyAdmin']; -deploy.dependencies = ['VerifyContracts']; - -export default deploy; diff --git a/scripts/deploy/proxy/erc721-upgradeable-proxy.ts b/scripts/deploy/proxy/erc721-upgradeable-proxy.ts deleted file mode 100644 index b0f7b01..0000000 --- a/scripts/deploy/proxy/erc721-upgradeable-proxy.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ERC721CommonUpgradeable__factory } from '../../typechain-types'; -import { HardhatRuntimeEnvironment } from 'hardhat/types'; - -const erc721Interface = ERC721CommonUpgradeable__factory.createInterface(); - -const deploy = async ({ getNamedAccounts, deployments, network }: HardhatRuntimeEnvironment) => { - const { deploy } = deployments; - const { deployer } = await getNamedAccounts(); - const proxyAdmin = await deployments.get('ProxyAdmin'); - const logicContract = await deployments.get('SampleERC721CommonUpgradeableLogic'); - - const data = erc721Interface.encodeFunctionData('initialize', ['SampleERC721', 'NFT', 'http://example.com/']); - - await deploy('SampleERC721CommonUpgradeableProxy', { - contract: 'TransparentUpgradeableProxy', - from: deployer, - log: true, - args: [logicContract.address, proxyAdmin, data], - }); -}; - -deploy.tags = ['SampleERC721CommonUpgradeableProxy']; -deploy.dependencies = ['VerifyContracts', 'ProxyAdmin', 'SampleERC721CommonUpgradeableLogic']; - -export default deploy; diff --git a/src/mock/SampleERC721Upgradeable.sol b/src/mock/SampleERC721Upgradeable.sol deleted file mode 100644 index 32bdd04..0000000 --- a/src/mock/SampleERC721Upgradeable.sol +++ /dev/null @@ -1,6 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity ^0.8.0; - -import "../upgradeable/ERC721CommonUpgradeable.sol"; - -contract SampleERC721Upgradeable is ERC721CommonUpgradeable {} diff --git a/src/upgradeable/ERC721CommonUpgradeable.sol b/src/upgradeable/ERC721CommonUpgradeable.sol deleted file mode 100644 index f664fa6..0000000 --- a/src/upgradeable/ERC721CommonUpgradeable.sol +++ /dev/null @@ -1,89 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity ^0.8.0; - -import "../refs/IERC721State.sol"; -import "./refs/ERC721NonceUpgradeable.sol"; -import "./ERC721PresetMinterPauserAutoIdCustomizedUpgradeable.sol"; - -abstract contract ERC721CommonUpgradeable is - ERC721NonceUpgradeable, - ERC721PresetMinterPauserAutoIdCustomizedUpgradeable, - IERC721State -{ - error ErrInvalidArrayLength(); - error ErrNonExistentToken(); - - constructor() { - _disableInitializers(); - } - - /** - * @inheritdoc IERC721State - */ - function stateOf(uint256 _tokenId) external view virtual override returns (bytes memory) { - if (!_exists(_tokenId)) revert ErrNonExistentToken(); - return abi.encodePacked(ownerOf(_tokenId), nonces[_tokenId], _tokenId); - } - - /** - * @dev Override `ERC721Upgradeable-_baseURI`. - */ - function _baseURI() - internal - view - virtual - override(ERC721Upgradeable, ERC721PresetMinterPauserAutoIdCustomizedUpgradeable) - returns (string memory) - { - return super._baseURI(); - } - - /** - * @dev Override `IERC165-supportsInterface`. - */ - function supportsInterface(bytes4 interfaceId) - public - view - virtual - override(ERC721Upgradeable, ERC721PresetMinterPauserAutoIdCustomizedUpgradeable) - returns (bool) - { - return super.supportsInterface(interfaceId); - } - - /** - * @dev Override `ERC721PresetMinterPauserAutoIdCustomizedUpgradeable-_beforeTokenTransfer`. - */ - function _beforeTokenTransfer(address _from, address _to, uint256 _firstTokenId, uint256 _batchSize) - internal - virtual - override(ERC721NonceUpgradeable, ERC721PresetMinterPauserAutoIdCustomizedUpgradeable) - { - super._beforeTokenTransfer(_from, _to, _firstTokenId, _batchSize); - } - - /** - * @dev Bulk create new tokens for `_recipients`. Tokens ID will be automatically - * assigned (and available on the emitted {IERC721Upgradeable-Transfer} event), and the token - * URI autogenerated based on the base URI passed at construction. - * - * See {ERC721Upgradeable-_mint}. - * - * Requirements: - * - * - the caller must have the `MINTER_ROLE`. - */ - function bulkMint(address[] calldata _recipients) - external - virtual - onlyRole(MINTER_ROLE) - returns (uint256[] memory _tokenIds) - { - if (_recipients.length == 0) revert ErrInvalidArrayLength(); - _tokenIds = new uint256[](_recipients.length); - - for (uint256 _i = 0; _i < _recipients.length; _i++) { - _tokenIds[_i] = _mintFor(_recipients[_i]); - } - } -} diff --git a/src/upgradeable/ERC721PresetMinterPauserAutoIdCustomizedUpgradeable.sol b/src/upgradeable/ERC721PresetMinterPauserAutoIdCustomizedUpgradeable.sol deleted file mode 100644 index afe0ed3..0000000 --- a/src/upgradeable/ERC721PresetMinterPauserAutoIdCustomizedUpgradeable.sol +++ /dev/null @@ -1,179 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/presets/ERC721PresetMinterPauserAutoId.sol) - -pragma solidity ^0.8.0; - -import "../../lib/openzeppelin-contracts-upgradeable/contracts/token/ERC721/ERC721Upgradeable.sol"; -import "../../lib/openzeppelin-contracts-upgradeable/contracts/token/ERC721/extensions/ERC721EnumerableUpgradeable.sol"; -import "../../lib/openzeppelin-contracts-upgradeable/contracts/token/ERC721/extensions/ERC721BurnableUpgradeable.sol"; -import "../../lib/openzeppelin-contracts-upgradeable/contracts/token/ERC721/extensions/ERC721PausableUpgradeable.sol"; -import "../../lib/openzeppelin-contracts-upgradeable/contracts/access/AccessControlEnumerableUpgradeable.sol"; -import "../../lib/openzeppelin-contracts-upgradeable/contracts/utils/ContextUpgradeable.sol"; -import "../../lib/openzeppelin-contracts-upgradeable/contracts/utils/CountersUpgradeable.sol"; -import {Initializable} from "../../lib/openzeppelin-contracts-upgradeable/contracts/proxy/utils/Initializable.sol"; - -/** - * @dev {ERC721} token, including: - * - * - ability for holders to burn (destroy) their tokens - * - a minter role that allows for token minting (creation) - * - a pauser role that allows to stop all token transfers - * - token ID and URI autogeneration - * - * This contract uses {AccessControl} to lock permissioned functions using the - * different roles - head to its documentation for details. - * - * The account that deploys the contract will be granted the minter and pauser - * roles, as well as the default admin role, which will let it grant both minter - * and pauser roles to other accounts. - * - * _Deprecated in favor of https://wizard.openzeppelin.com/[Contracts Wizard]._ - */ -contract ERC721PresetMinterPauserAutoIdCustomizedUpgradeable is - Initializable, - ContextUpgradeable, - AccessControlEnumerableUpgradeable, - ERC721EnumerableUpgradeable, - ERC721BurnableUpgradeable, - ERC721PausableUpgradeable -{ - error ErrUnauthorizedAccount(address account, bytes32 neededRole); - - using CountersUpgradeable for CountersUpgradeable.Counter; - - bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); - bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE"); - - CountersUpgradeable.Counter private _tokenIdTracker; - - string private _baseTokenURI; - - function initialize(string memory name, string memory symbol, string memory baseTokenURI) public virtual initializer { - __ERC721PresetMinterPauserAutoId_init(name, symbol, baseTokenURI); - } - /** - * @dev Grants `DEFAULT_ADMIN_ROLE`, `MINTER_ROLE` and `PAUSER_ROLE` to the - * account that deploys the contract. - * - * Token URIs will be autogenerated based on `baseURI` and their token IDs. - * See {ERC721-tokenURI}. - */ - - function __ERC721PresetMinterPauserAutoId_init(string memory name, string memory symbol, string memory baseTokenURI) - internal - onlyInitializing - { - __ERC721_init_unchained(name, symbol); - __Pausable_init_unchained(); - __ERC721PresetMinterPauserAutoId_init_unchained(name, symbol, baseTokenURI); - _tokenIdTracker.increment(); - } - - function __ERC721PresetMinterPauserAutoId_init_unchained(string memory, string memory, string memory baseTokenURI) - internal - onlyInitializing - { - _baseTokenURI = baseTokenURI; - - _setupRole(DEFAULT_ADMIN_ROLE, _msgSender()); - - _setupRole(MINTER_ROLE, _msgSender()); - _setupRole(PAUSER_ROLE, _msgSender()); - } - - function _baseURI() internal view virtual override returns (string memory) { - return _baseTokenURI; - } - - /** - * @dev Creates a new token for `to`. Its token ID will be automatically - * assigned (and available on the emitted {IERC721Upgradeable-Transfer} event), and the token - * URI autogenerated based on the base URI passed at construction. - * - * See {ERC721Upgradeable-_mint}. - * - * Requirements: - * - * - the caller must have the `MINTER_ROLE`. - */ - function mint(address to) public virtual returns (uint256 tokenId) { - address sender = _msgSender(); - if (!hasRole(MINTER_ROLE, sender)) revert ErrUnauthorizedAccount(sender, MINTER_ROLE); - - tokenId = _mintFor(to); - } - - /** - * @dev Pauses all token transfers. - * - * See {ERC721PausableUpgradeable} and {PausableUpgradeable-_pause}. - * - * Requirements: - * - * - the caller must have the `PAUSER_ROLE`. - */ - function pause() public virtual { - address sender = _msgSender(); - if (!hasRole(PAUSER_ROLE, sender)) revert ErrUnauthorizedAccount(sender, PAUSER_ROLE); - - _pause(); - } - - /** - * @dev Unpauses all token transfers. - * - * See {ERC721PausableUpgradeable} and {PausableUpgradeable-_unpause}. - * - * Requirements: - * - * - the caller must have the `PAUSER_ROLE`. - */ - function unpause() public virtual { - address sender = _msgSender(); - if (!hasRole(PAUSER_ROLE, sender)) revert ErrUnauthorizedAccount(sender, PAUSER_ROLE); - - _unpause(); - } - - function _beforeTokenTransfer(address from, address to, uint256 firstTokenId, uint256 batchSize) - internal - virtual - override(ERC721Upgradeable, ERC721EnumerableUpgradeable, ERC721PausableUpgradeable) - { - super._beforeTokenTransfer(from, to, firstTokenId, batchSize); - } - - /** - * @dev See {IERC165-supportsInterface}. - */ - function supportsInterface(bytes4 interfaceId) - public - view - virtual - override(AccessControlEnumerableUpgradeable, ERC721Upgradeable, ERC721EnumerableUpgradeable) - returns (bool) - { - return super.supportsInterface(interfaceId); - } - - /** - * @dev Helper function to mint for address `to`. - * - * See {ERC721Upgradeable-_mint}. - * - */ - function _mintFor(address to) internal virtual returns (uint256 _tokenId) { - // We cannot just use balanceOf to create the new tokenId because tokens - // can be burned (destroyed), so we need a separate counter. - _tokenId = _tokenIdTracker.current(); - _mint(to, _tokenId); - _tokenIdTracker.increment(); - } - - /** - * @dev This empty reserved space is put in place to allow future versions to add new - * variables without shifting down storage in the inheritance chain. - * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps - */ - uint256[48] private __gap; -} diff --git a/src/upgradeable/refs/ERC721NonceUpgradeable.sol b/src/upgradeable/refs/ERC721NonceUpgradeable.sol deleted file mode 100644 index 6193a97..0000000 --- a/src/upgradeable/refs/ERC721NonceUpgradeable.sol +++ /dev/null @@ -1,36 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -import "../../../lib/openzeppelin-contracts-upgradeable/contracts/token/ERC721/ERC721Upgradeable.sol"; - -/** - * @title ERC721NonceUpgradeable - * @dev This contract provides a nonce that will be increased whenever the token is tranferred. - */ -abstract contract ERC721NonceUpgradeable is ERC721Upgradeable { - /// @dev Emitted when the token nonce is updated - event NonceUpdated(uint256 indexed _tokenId, uint256 indexed _nonce); - - /// @dev Mapping from token id => token nonce - mapping(uint256 => uint256) public nonces; - - /** - * @dev This empty reserved space is put in place to allow future versions to add new - * variables without shifting down storage in the inheritance chain. - */ - uint256[50] private ______gap; - - /** - * @dev Override `ERC721Upgradeable-_beforeTokenTransfer`. - */ - function _beforeTokenTransfer(address _from, address _to, uint256 _firstTokenId, uint256 _batchSize) - internal - virtual - override - { - for (uint256 _tokenId = _firstTokenId; _tokenId < _firstTokenId + _batchSize; _tokenId++) { - emit NonceUpdated(_tokenId, ++nonces[_tokenId]); - } - super._beforeTokenTransfer(_from, _to, _firstTokenId, _batchSize); - } -} diff --git a/test/foundry/SampleERC721Upgradeable.t.sol b/test/foundry/SampleERC721Upgradeable.t.sol deleted file mode 100644 index 679303b..0000000 --- a/test/foundry/SampleERC721Upgradeable.t.sol +++ /dev/null @@ -1,101 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity ^0.8.13; - -import "forge-std/Test.sol"; -import {ERC721NonceUpgradeable} from "src/upgradeable/refs/ERC721NonceUpgradeable.sol"; -import {Strings} from "../../lib/openzeppelin-contracts/contracts/utils/Strings.sol"; -import {TransparentUpgradeableProxy} from - "../../lib/openzeppelin-contracts/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; -import { - SampleERC721Upgradeable, - ERC721CommonUpgradeable, - ERC721PresetMinterPauserAutoIdCustomizedUpgradeable, - IERC721State -} from "src/mock/SampleERC721Upgradeable.sol"; - -contract SampleERC721Upgradeable_Test is Test { - using Strings for uint256; - - event NonceUpdated(uint256 indexed _tokenId, uint256 indexed _nonce); - - string public constant NAME = "SampleERC721"; - string public constant SYMBOL = "NFT"; - string public constant BASE_URI = "http://example.com/"; - - address _proxyAdmin; - - ERC721CommonUpgradeable internal _t; - - function setUp() public virtual { - _proxyAdmin = makeAddr("proxy-admin"); - - bytes memory initializeData = - abi.encodeCall(ERC721PresetMinterPauserAutoIdCustomizedUpgradeable.initialize, (NAME, SYMBOL, BASE_URI)); - TransparentUpgradeableProxy proxy = - new TransparentUpgradeableProxy(address(new SampleERC721Upgradeable()), _proxyAdmin, initializeData); - _t = SampleERC721Upgradeable(address(proxy)); - } - - function testName() public virtual { - assertEq(_token().name(), NAME); - } - - function testSymbol() public virtual { - assertEq(_token().symbol(), SYMBOL); - } - - function testFirstTokenId() public virtual { - (uint256 _tokenId,) = _mint(address(1)); - assertNotEq(_tokenId, 0); - } - - function testTokenURI(address _from) public virtual { - vm.assume(_from.code.length == 0 && _from != address(0)); - (uint256 _tokenId,) = _mint(_from); - assertEq(_token().tokenURI(_tokenId), string(abi.encodePacked(BASE_URI, _tokenId.toString()))); - } - - function testNonce(address _from, address _to, uint256 _transferTimes) public virtual { - vm.assume(_from.code.length == 0 && _to.code.length == 0 && _from != address(0) && _to != address(0)); - vm.assume(_transferTimes > 0 && _transferTimes < 10); - (uint256 _tokenId, uint256 _nonce) = _mint(_from); - - for (uint256 _i; _i < _transferTimes; _i++) { - vm.expectEmit(true, true, true, true, address(_token())); - emit NonceUpdated(_tokenId, ++_nonce); - _transferFrom(_from, _to, _tokenId); - - vm.expectEmit(true, true, true, true, address(_token())); - emit NonceUpdated(_tokenId, ++_nonce); - _transferFrom(_to, _from, _tokenId); - } - - assertEq(_nonce, _token().nonces(_tokenId)); - } - - function testState(address _from, address _to) public virtual { - vm.assume(_from.code.length == 0 && _to.code.length == 0 && _from != address(0) && _to != address(0)); - (uint256 _tokenId,) = _mint(_from); - - bytes32 _state0 = keccak256(_token().stateOf(_tokenId)); - _transferFrom(_from, _to, _tokenId); - _transferFrom(_to, _from, _tokenId); - bytes32 _state1 = keccak256(_token().stateOf(_tokenId)); - assertNotEq(_state0, _state1); - } - - function _mint(address _user) internal virtual returns (uint256 _tokenId, uint256 _nonce) { - _token().mint(_user); - uint256 _balance = _token().balanceOf(_user); - return (_token().tokenOfOwnerByIndex(_user, _balance - 1), 1); - } - - function _transferFrom(address _from, address _to, uint256 _tokenId) internal virtual { - vm.prank(_from); - _token().transferFrom(_from, _to, _tokenId); - } - - function _token() internal view virtual returns (ERC721CommonUpgradeable) { - return _t; - } -} From 0879fd460308a610d7d09aac97dcc82e867005ff Mon Sep 17 00:00:00 2001 From: huyhuynh3103 Date: Wed, 17 Apr 2024 10:27:50 +0700 Subject: [PATCH 22/22] feat: remove redundant ci --- .../workflows/create-PR-deploy-to-release.yml | 64 -------------- .../create-PR-release-to-feature.yml | 84 ------------------- .../create-PR-release-to-network.yml | 47 ----------- .github/workflows/create-release-tag.yml | 64 -------------- 4 files changed, 259 deletions(-) delete mode 100644 .github/workflows/create-PR-deploy-to-release.yml delete mode 100644 .github/workflows/create-PR-release-to-feature.yml delete mode 100644 .github/workflows/create-PR-release-to-network.yml delete mode 100644 .github/workflows/create-release-tag.yml diff --git a/.github/workflows/create-PR-deploy-to-release.yml b/.github/workflows/create-PR-deploy-to-release.yml deleted file mode 100644 index 56dd61c..0000000 --- a/.github/workflows/create-PR-deploy-to-release.yml +++ /dev/null @@ -1,64 +0,0 @@ -name: Create PR Deploy to Release - -on: - push: - branches: - - deploy/* - pull_request: - types: - - opened - branches: - - 'deploy/**' - -env: - HEAD_BRANCH: ${{ github.head_ref || github.ref_name }} - -permissions: - contents: write - pull-requests: write - -jobs: - build: - runs-on: ubuntu-latest - steps: - - name: Set Env - run: | - echo "PR_BRANCH=merge/${HEAD_BRANCH}" >> $GITHUB_ENV - echo "VERSION=$(echo -n ${{ env.HEAD_BRANCH }} | sed 's/.*deploy\///' | cut -d'-' -f1)" >> $GITHUB_ENV - echo "NETWORK=$(echo -n ${{ env.HEAD_BRANCH }} | sed 's/.*deploy\/v[0-9\.]*-\(.*\)/\1/')" >> $GITHUB_ENV - - name: Checkout code - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - with: - ref: 'release/${{ env.VERSION }}' - fetch-depth: 0 - fetch-tags: 'true' - - - name: Get Testnet Latest Tag - if: ${{ env.NETWORK == 'testnet' }} - run: | - echo "LATESTTAG=$(git describe --tags --match "*testnet*" --abbrev=0)" >> $GITHUB_ENV - - - name: Get Mainnet Latest Tag - if: ${{ env.NETWORK == 'mainnet' }} - run: | - echo "LATESTTAG=$(git describe --tags --match "*mainnet*" --abbrev=0)" >> $GITHUB_ENV - - - name: Reset promotion branch - run: | - git fetch origin ${HEAD_BRANCH}:${HEAD_BRANCH} - git reset --hard ${HEAD_BRANCH} - - - name: Generate Release note - id: template - run: | - echo "VERSION=${{ env.VERSION }} - SHA: ${{ github.sha }}" > CHANGELOG.md - - - name: Create Pull Request - id: cpr - uses: peter-evans/create-pull-request@v6.0.1 - with: - labels: automated PR - delete-branch: true - title: 'chore(`release/${{ env.VERSION }}`): merge from `${{ env.HEAD_BRANCH}}`' - body: ${{ steps.template.outputs.result }} - branch: ${{ env.PR_BRANCH }} \ No newline at end of file diff --git a/.github/workflows/create-PR-release-to-feature.yml b/.github/workflows/create-PR-release-to-feature.yml deleted file mode 100644 index b9dec20..0000000 --- a/.github/workflows/create-PR-release-to-feature.yml +++ /dev/null @@ -1,84 +0,0 @@ -name: Create Pull Request From Release to Feature -on: - push: - branches: - - 'release/*' - - 'release*/*' - -concurrency: - group: ${{ github.workflow }}-${{ github.ref || github.run_id }} - cancel-in-progress: true - -env: - HEAD_BRANCH: ${{ github.head_ref || github.ref_name }} - -jobs: - fetchAllFeatureBranches: - runs-on: ubuntu-latest - - steps: - - id: step1 - name: Checkout code - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - id: step2 - name: List all the remote feature branches - run: | - branches=$(git branch -r | grep -E '.*origin\/feature\/.*' | sed -e "s/.*origin\///" | tr "\n" " ") - JSON="[" - for branch in ${branches[@]}; do - echo $branch - JSONline="\"$branch\"," - # we don't need to iterate on the same branch over and over, so - # onnly include it when it wasn't included - if [[ "$JSON" != *"$JSONline"* ]]; then - JSON="$JSON$JSONline" - fi - done - # Remove last "," and add the closing bracket - if [[ $JSON == *, ]]; then - JSON="${JSON%?}" - fi - JSON="$JSON]" - echo $JSON - echo "BRANCHES={\"branch_name\": $( echo "$JSON" )}" >> "$GITHUB_OUTPUT" - outputs: - BRANCHES: ${{ steps.step2.outputs.BRANCHES }} - - mergeRelease2FeatureRepo: - runs-on: ubuntu-latest - needs: fetchAllFeatureBranches - strategy: - matrix: ${{ fromJSON(needs.fetchAllFeatureBranches.outputs.BRANCHES) }} - steps: - - name: Set env - run: | - echo "PR_BRANCH=merge/${HEAD_BRANCH}-${{matrix.branch_name}}" >> $GITHUB_ENV - echo "FEATURE_NAME=$(echo ${{matrix.branch_name}} | cut -d'/' -f2)" >> $GITHUB_ENV - - uses: actions/checkout@v3 - with: - ref: ${{matrix.branch_name}} - - name: Reset promotion branch - run: | - git fetch origin ${HEAD_BRANCH}:${HEAD_BRANCH} - git reset --hard ${HEAD_BRANCH} - - - name: Render template - id: template - uses: chuhlomin/render-template@v1.4 - with: - template: .github/template/create-pull-request.md - vars: | - fromBranch: ${{env.HEAD_BRANCH}} - toBranch: ${{matrix.branch_name}} - - - name: Create Pull Request - uses: peter-evans/create-pull-request@v6.0.1 - with: - labels: automated PR - delete-branch: true - title: 'chore(`${{env.FEATURE_NAME}}`): merge from `${{env.HEAD_BRANCH}}`' - body: ${{ steps.template.outputs.result }} - branch: ${{env.PR_BRANCH}} diff --git a/.github/workflows/create-PR-release-to-network.yml b/.github/workflows/create-PR-release-to-network.yml deleted file mode 100644 index e291a52..0000000 --- a/.github/workflows/create-PR-release-to-network.yml +++ /dev/null @@ -1,47 +0,0 @@ -name: Create PR from release to network - -on: - pull_request: - branches: - - release/* - types: - - closed - -permissions: - contents: write - pull-requests: write - -env: - HEAD_BRANCH: ${{ github.head_ref || github.ref_name }} - RELEASE_BRANCH: ${{ github.event.pull_request.base.ref}} - -jobs: - merge-release-to-network: - runs-on: ubuntu-latest - if: ${{ (github.event.pull_request.merged == true) && (contains(github.head_ref, 'deploy') || contains(github.ref_name, 'deploy')) }} - steps: - - name: Set Env - run: | - echo "PR_BRANCH=merge/${HEAD_BRANCH}" >> $GITHUB_ENV - echo "VERSION=$(echo -n ${{ env.HEAD_BRANCH }} | sed 's/.*deploy\///' | cut -d'-' -f1)" >> $GITHUB_ENV - echo "NETWORK=$(echo -n ${{ env.HEAD_BRANCH }} | sed 's/.*deploy\/v[0-9\.]*-\(.*\)/\1/')" >> $GITHUB_ENV - - - name: Checkout code - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - with: - ref: ${{ env.NETWORK }} - - - name: Reset promotion branch - run: | - git fetch origin ${RELEASE_BRANCH}:${RELEASE_BRANCH} - git reset --hard ${RELEASE_BRANCH} - - - name: Create Pull Request - id: cpr - uses: peter-evans/create-pull-request@v6.0.1 - with: - labels: automated PR - delete-branch: true - title: 'chore(`${{ env.NETWORK }}`): merge from `${{ env.HEAD_BRANCH}}`' - body: ${{ steps.template.outputs.result }} - branch: ${{env.PR_BRANCH}} diff --git a/.github/workflows/create-release-tag.yml b/.github/workflows/create-release-tag.yml deleted file mode 100644 index d720027..0000000 --- a/.github/workflows/create-release-tag.yml +++ /dev/null @@ -1,64 +0,0 @@ -name: Create Release Tag - -on: - pull_request: - types: [closed] - branches: - - mainnet - - testnet - -env: - HEAD_BRANCH: ${{ github.head_ref || github.ref_name }} - -permissions: - contents: write - pull-requests: write - -jobs: - create-release-tag: - runs-on: ubuntu-latest - if: github.event.pull_request.merged == true - steps: - - name: Set Env - run: | - echo "VERSION=$(echo -n ${{ env.HEAD_BRANCH }} | sed 's/.*deploy\///' | cut -d'-' -f1)" >> $GITHUB_ENV - echo "NETWORK=$(echo -n ${{ env.HEAD_BRANCH }} | sed 's/.*deploy\/v[0-9\.]*-\(.*\)/\1/')" >> $GITHUB_ENV - - - name: Checkout code - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - with: - ref: ${{ env.NETWORK }} - fetch-depth: 0 - fetch-tags: 'true' - - - name: Set Mainnet Tag - if: ${{ env.NETWORK == 'mainnet' }} - run: | - echo "TAG=${{ env.VERSION }}" >> $GITHUB_ENV - - - name: Set Testnet Tag - if: ${{ env.NETWORK == 'testnet' }} - run: | - echo "TAG=${{ env.VERSION }}-testnet" >> $GITHUB_ENV - - - name: Get Testnet Latest Tag - if: ${{ env.NETWORK == 'testnet' }} - run: | - echo "LATESTTAG=$(git describe --tags --match "*testnet*" --abbrev=0)" >> $GITHUB_ENV - - - name: Get Mainnet Latest Tag - if: ${{ env.NETWORK == 'mainnet' }} - run: | - echo "LATESTTAG=$(git describe --tags --match "*mainnet*" --abbrev=0)" >> $GITHUB_ENV - - - name: Create release - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - tag: ${{ env.TAG }} - run: | - gh release create "$tag" \ - --repo "$GITHUB_REPOSITORY" \ - --title "${{ env.NETWORK }} release ${{ env.VERSION }}" \ - --target "${{ env.NETWORK }}" \ - --notes-start-tag "${{ env.LATESTTAG }}" \ - --generate-notes