diff --git a/README.md b/README.md index cb86e3c..2e39a12 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # anotherblock anotherblock platform contracts -## collaboration workflow +## contribution workflow ### branches @@ -160,3 +160,23 @@ deploy standalone royalty contract for specific publisher ```sh forge script script/base/deploy-royalty.s.sol:DeployRoyalty --rpc-url base --sig "run(address)" --broadcast --verify ``` + +## contribute + +### creating new NFT minting mechanism + +in order for anyone to create new minting mechanism NFT contract compatible with anotherblock self-service platform, the contract must comply with below requirements : + +1. the new contract shall inherit the abstract contract [ERC721AB](src/token/ERC721/ERC721AB.sol) + +2. the new contract state shall include two constants, `IMPLEMENTATION_VERSION` & `IMPLEMENTATION_TYPE` + +3. the new contract shall include a function `initDrop` calling the internal function `_initDrop` and contain a minimum set of parameters : + + - amount of share per token + - amount of genesis token to be minted + - recipient address of the genesis token(s) + - currency used to pay-out royalties + - base URI + +4. the new contract shall include a custom mint function (see [ERC721ABLE](src/token//ERC721/ERC721ABLE.sol) for reference) diff --git a/forge-cache/solidity-files-cache.json b/forge-cache/solidity-files-cache.json index dc67c76..81a3e4f 100644 --- a/forge-cache/solidity-files-cache.json +++ b/forge-cache/solidity-files-cache.json @@ -4494,8 +4494,8 @@ } }, "script/base/deploy-implementations.s.sol": { - "lastModificationDate": 1693465366216, - "contentHash": "2b1d8c6802609a4d7e19ad28b5a22365", + "lastModificationDate": 1695887535699, + "contentHash": "7b91a7e4dd208eed116e3d6df13ec06b", "sourceName": "script/base/deploy-implementations.s.sol", "solcConfig": { "settings": { @@ -4584,6 +4584,7 @@ "src/royalty/IABRoyalty.sol", "src/token/ERC1155/ERC1155AB.sol", "src/token/ERC721/ERC721AB.sol", + "src/token/ERC721/ERC721ABLE.sol", "src/utils/IABDataRegistry.sol", "src/utils/IABVerifier.sol" ], @@ -4595,8 +4596,8 @@ } }, "script/base/deploy-platform.s.sol": { - "lastModificationDate": 1693465366216, - "contentHash": "bb0b1272e7bc230429fb4c45d19a3631", + "lastModificationDate": 1695887542037, + "contentHash": "b249659654ea2b392c4629c74cc3f49e", "sourceName": "script/base/deploy-platform.s.sol", "solcConfig": { "settings": { @@ -4697,6 +4698,7 @@ "src/royalty/IABRoyalty.sol", "src/token/ERC1155/ERC1155AB.sol", "src/token/ERC721/ERC721AB.sol", + "src/token/ERC721/ERC721ABLE.sol", "src/utils/ABDataRegistry.sol", "src/utils/ABVerifier.sol", "src/utils/IABDataRegistry.sol", @@ -4803,7 +4805,7 @@ } }, "script/base-goerli/create-publisher.s.sol": { - "lastModificationDate": 1693465366216, + "lastModificationDate": 1695374870137, "contentHash": "e2267180499cb7133e1684156d386c07", "sourceName": "script/base-goerli/create-publisher.s.sol", "solcConfig": { @@ -4987,8 +4989,8 @@ } }, "script/base-goerli/deploy-implementations.s.sol": { - "lastModificationDate": 1695108294170, - "contentHash": "a0f0f13c25577dc69475a662870251bd", + "lastModificationDate": 1695887525422, + "contentHash": "05dbd9c58bd38f549b31bb572d64d339", "sourceName": "script/base-goerli/deploy-implementations.s.sol", "solcConfig": { "settings": { @@ -5077,6 +5079,7 @@ "src/royalty/IABRoyalty.sol", "src/token/ERC1155/ERC1155AB.sol", "src/token/ERC721/ERC721AB.sol", + "src/token/ERC721/ERC721ABLE.sol", "src/utils/IABDataRegistry.sol", "src/utils/IABVerifier.sol" ], @@ -5088,8 +5091,8 @@ } }, "script/base-goerli/deploy-platform.s.sol": { - "lastModificationDate": 1693465366216, - "contentHash": "362038700fdab1493800300d36faf139", + "lastModificationDate": 1695887530527, + "contentHash": "bbc66cfe0dd45bbb847a00b608e770df", "sourceName": "script/base-goerli/deploy-platform.s.sol", "solcConfig": { "settings": { @@ -5190,6 +5193,7 @@ "src/royalty/IABRoyalty.sol", "src/token/ERC1155/ERC1155AB.sol", "src/token/ERC721/ERC721AB.sol", + "src/token/ERC721/ERC721ABLE.sol", "src/utils/ABDataRegistry.sol", "src/utils/ABVerifier.sol", "src/utils/IABDataRegistry.sol", @@ -5379,8 +5383,8 @@ } }, "script/op/deploy-platform.s.sol": { - "lastModificationDate": 1693465366217, - "contentHash": "bf5977017d6fc6e7fb50592a34bee58d", + "lastModificationDate": 1695887548109, + "contentHash": "bd1558a2a1b08abdadcab46e1dc68d55", "sourceName": "script/op/deploy-platform.s.sol", "solcConfig": { "settings": { @@ -5481,6 +5485,7 @@ "src/royalty/IABRoyalty.sol", "src/token/ERC1155/ERC1155AB.sol", "src/token/ERC721/ERC721AB.sol", + "src/token/ERC721/ERC721ABLE.sol", "src/utils/ABDataRegistry.sol", "src/utils/ABVerifier.sol", "src/utils/IABDataRegistry.sol", @@ -5966,8 +5971,8 @@ } }, "src/token/ERC721/ERC721AB.sol": { - "lastModificationDate": 1695284209908, - "contentHash": "e45756e7e86d105658039ee09472863a", + "lastModificationDate": 1695988116327, + "contentHash": "bcd226b30367a6e00094a07dca959719", "sourceName": "src/token/ERC721/ERC721AB.sol", "solcConfig": { "settings": { @@ -6024,6 +6029,66 @@ } } }, + "src/token/ERC721/ERC721ABLE.sol": { + "lastModificationDate": 1695988127296, + "contentHash": "53ccb4f12581345ed405955c2c70231c", + "sourceName": "src/token/ERC721/ERC721ABLE.sol", + "solcConfig": { + "settings": { + "optimizer": { + "enabled": true, + "runs": 200 + }, + "metadata": { + "useLiteralContent": false, + "bytecodeHash": "ipfs", + "appendCBOR": true + }, + "outputSelection": { + "*": { + "": [ + "ast" + ], + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata" + ] + } + }, + "evmVersion": "paris", + "libraries": {} + } + }, + "imports": [ + "lib/ERC721A-Upgradeable/contracts/ERC721AStorage.sol", + "lib/ERC721A-Upgradeable/contracts/ERC721AUpgradeable.sol", + "lib/ERC721A-Upgradeable/contracts/ERC721A__Initializable.sol", + "lib/ERC721A-Upgradeable/contracts/ERC721A__InitializableStorage.sol", + "lib/ERC721A-Upgradeable/contracts/IERC721AUpgradeable.sol", + "lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol", + "lib/openzeppelin-contracts/contracts/utils/Strings.sol", + "lib/openzeppelin-contracts/contracts/utils/math/Math.sol", + "lib/openzeppelin-contracts-upgradeable/contracts/access/OwnableUpgradeable.sol", + "lib/openzeppelin-contracts-upgradeable/contracts/proxy/utils/Initializable.sol", + "lib/openzeppelin-contracts-upgradeable/contracts/utils/AddressUpgradeable.sol", + "lib/openzeppelin-contracts-upgradeable/contracts/utils/ContextUpgradeable.sol", + "src/libraries/ABDataTypes.sol", + "src/libraries/ABErrors.sol", + "src/libraries/ABEvents.sol", + "src/token/ERC721/ERC721AB.sol", + "src/utils/IABDataRegistry.sol", + "src/utils/IABVerifier.sol" + ], + "versionRequirement": "^0.8.18", + "artifacts": { + "ERC721ABLE": { + "0.8.19+commit.7dd6d404.Darwin.appleclang": "ERC721ABLE.sol/ERC721ABLE.json" + } + } + }, "src/utils/ABDataRegistry.sol": { "lastModificationDate": 1695289811280, "contentHash": "01daae19991c3d298a84da11cea6a548", @@ -6600,10 +6665,10 @@ } } }, - "test/_testdata/ERC721AB.td.sol": { - "lastModificationDate": 1695290085213, + "test/_testdata/ERC721ABLE.td.sol": { + "lastModificationDate": 1695886290527, "contentHash": "18e471e2024322ed2364a9b96590a5d4", - "sourceName": "test/_testdata/ERC721AB.td.sol", + "sourceName": "test/_testdata/ERC721ABLE.td.sol", "solcConfig": { "settings": { "optimizer": { @@ -6637,13 +6702,13 @@ "versionRequirement": "^0.8.18", "artifacts": { "ERC721ABTestData": { - "0.8.19+commit.7dd6d404.Darwin.appleclang": "ERC721AB.td.sol/ERC721ABTestData.json" + "0.8.19+commit.7dd6d404.Darwin.appleclang": "ERC721ABLE.td.sol/ERC721ABTestData.json" } } }, "test/factory/AnotherCloneFactory.t.sol": { - "lastModificationDate": 1695290503763, - "contentHash": "837c4a0d860805d2c6f551900ce4e690", + "lastModificationDate": 1695887552259, + "contentHash": "28aa74940b4b4cac784b2cc9b9a6d370", "sourceName": "test/factory/AnotherCloneFactory.t.sol", "solcConfig": { "settings": { @@ -6749,6 +6814,7 @@ "src/royalty/IABRoyalty.sol", "src/token/ERC1155/ERC1155AB.sol", "src/token/ERC721/ERC721AB.sol", + "src/token/ERC721/ERC721ABLE.sol", "src/utils/ABDataRegistry.sol", "src/utils/ABVerifier.sol", "src/utils/IABDataRegistry.sol", @@ -6763,8 +6829,8 @@ } }, "test/royalty/ABRoyalty.t.sol": { - "lastModificationDate": 1695290509827, - "contentHash": "ab55e9210a3309ea998d5d5d611704df", + "lastModificationDate": 1695887559758, + "contentHash": "1709c4b58e65fec2eb5d4f2a98d2dab4", "sourceName": "test/royalty/ABRoyalty.t.sol", "solcConfig": { "settings": { @@ -6885,6 +6951,7 @@ "src/royalty/IABRoyalty.sol", "src/token/ERC1155/ERC1155AB.sol", "src/token/ERC721/ERC721AB.sol", + "src/token/ERC721/ERC721ABLE.sol", "src/utils/ABDataRegistry.sol", "src/utils/ABVerifier.sol", "src/utils/IABDataRegistry.sol", @@ -6900,8 +6967,8 @@ } }, "test/token/ERC1155/ERC1155AB.t.sol": { - "lastModificationDate": 1695290521135, - "contentHash": "47731f8ad74d6ba0571cca1040fe7ffa", + "lastModificationDate": 1695887569562, + "contentHash": "7e601132d94c61b0b8aea76a591768ba", "sourceName": "test/token/ERC1155/ERC1155AB.t.sol", "solcConfig": { "settings": { @@ -7029,6 +7096,7 @@ "src/royalty/IABRoyalty.sol", "src/token/ERC1155/ERC1155AB.sol", "src/token/ERC721/ERC721AB.sol", + "src/token/ERC721/ERC721ABLE.sol", "src/utils/ABDataRegistry.sol", "src/utils/ABVerifier.sol", "src/utils/IABDataRegistry.sol", @@ -7044,10 +7112,10 @@ } } }, - "test/token/ERC721/ERC721AB.t.sol": { - "lastModificationDate": 1695290918446, - "contentHash": "01aa01f3a6c3f8c6f82d27d5e28044b5", - "sourceName": "test/token/ERC721/ERC721AB.t.sol", + "test/token/ERC721/ERC721ABLE.t.sol": { + "lastModificationDate": 1695887446720, + "contentHash": "c3871a4701ce436512f1844c328b512f", + "sourceName": "test/token/ERC721/ERC721ABLE.t.sol", "solcConfig": { "settings": { "optimizer": { @@ -7169,18 +7237,19 @@ "src/royalty/IABRoyalty.sol", "src/token/ERC1155/ERC1155AB.sol", "src/token/ERC721/ERC721AB.sol", + "src/token/ERC721/ERC721ABLE.sol", "src/utils/ABDataRegistry.sol", "src/utils/ABVerifier.sol", "src/utils/IABDataRegistry.sol", "src/utils/IABVerifier.sol", "test/_mocks/ABSuperToken.sol", "test/_mocks/MockToken.sol", - "test/_testdata/ERC721AB.td.sol" + "test/_testdata/ERC721ABLE.td.sol" ], "versionRequirement": "^0.8.18", "artifacts": { "ERC721ABTest": { - "0.8.19+commit.7dd6d404.Darwin.appleclang": "ERC721AB.t.sol/ERC721ABTest.json" + "0.8.19+commit.7dd6d404.Darwin.appleclang": "ERC721ABLE.t.sol/ERC721ABTest.json" } } }, diff --git a/script/base-goerli/deploy-implementations.s.sol b/script/base-goerli/deploy-implementations.s.sol index 371a5eb..3919796 100644 --- a/script/base-goerli/deploy-implementations.s.sol +++ b/script/base-goerli/deploy-implementations.s.sol @@ -9,11 +9,11 @@ pragma solidity ^0.8.18; import "forge-std/Script.sol"; import {ERC1155AB} from "src/token/ERC1155/ERC1155AB.sol"; -import {ERC721AB} from "src/token/ERC721/ERC721AB.sol"; +import {ERC721ABLE} from "src/token/ERC721/ERC721ABLE.sol"; import {AnotherCloneFactory} from "src/factory/AnotherCloneFactory.sol"; contract DeployImplementation is Script { - ERC721AB public erc721Impl; + ERC721ABLE public erc721Impl; ERC1155AB public erc1155Impl; function run() external { @@ -24,7 +24,7 @@ contract DeployImplementation is Script { vm.startBroadcast(deployerPrivateKey); // Deploy Implementation Contracts - erc721Impl = new ERC721AB(); + erc721Impl = new ERC721ABLE(); erc1155Impl = new ERC1155AB(); // Set new implementation contracts addresses in AnotherCloneFactory diff --git a/script/base-goerli/deploy-platform.s.sol b/script/base-goerli/deploy-platform.s.sol index cb5d84a..890ceb7 100644 --- a/script/base-goerli/deploy-platform.s.sol +++ b/script/base-goerli/deploy-platform.s.sol @@ -11,7 +11,7 @@ import {ABRoyalty} from "src/royalty/ABRoyalty.sol"; import {ABVerifier} from "src/utils/ABVerifier.sol"; import {AnotherCloneFactory} from "src/factory/AnotherCloneFactory.sol"; import {ERC1155AB} from "src/token/ERC1155/ERC1155AB.sol"; -import {ERC721AB} from "src/token/ERC721/ERC721AB.sol"; +import {ERC721ABLE} from "src/token/ERC721/ERC721ABLE.sol"; contract DeployPlatform is Script { uint256 public constant DROP_ID_OFFSET = 20_000; @@ -21,7 +21,7 @@ contract DeployPlatform is Script { string public constant FACTORY_PATH = "deployment/84531/AnotherCloneFactory/address"; string public constant PROXY_ADMIN_PATH = "deployment/84531/ProxyAdmin/address"; - ERC721AB public erc721Impl; + ERC721ABLE public erc721Impl; ERC1155AB public erc1155Impl; ABRoyalty public royaltyImpl; ProxyAdmin public proxyAdmin; @@ -42,7 +42,7 @@ contract DeployPlatform is Script { vm.startBroadcast(deployerPrivateKey); // Deploy Implementation Contracts - erc721Impl = new ERC721AB(); + erc721Impl = new ERC721ABLE(); erc1155Impl = new ERC1155AB(); royaltyImpl = new ABRoyalty(); diff --git a/script/base/deploy-implementations.s.sol b/script/base/deploy-implementations.s.sol index c5e364f..e32941a 100644 --- a/script/base/deploy-implementations.s.sol +++ b/script/base/deploy-implementations.s.sol @@ -9,11 +9,11 @@ pragma solidity ^0.8.18; import "forge-std/Script.sol"; import {ERC1155AB} from "src/token/ERC1155/ERC1155AB.sol"; -import {ERC721AB} from "src/token/ERC721/ERC721AB.sol"; +import {ERC721ABLE} from "src/token/ERC721/ERC721ABLE.sol"; import {AnotherCloneFactory} from "src/factory/AnotherCloneFactory.sol"; contract DeployImplementation is Script { - ERC721AB public erc721Impl; + ERC721ABLE public erc721Impl; ERC1155AB public erc1155Impl; address public anotherCloneFactory = 0x137d7d27af9B4d7b467Ac008AFdcDb8C9Ac4ddd9; @@ -25,7 +25,7 @@ contract DeployImplementation is Script { vm.startBroadcast(deployerPrivateKey); // Deploy Implementation Contracts - erc721Impl = new ERC721AB(); + erc721Impl = new ERC721ABLE(); erc1155Impl = new ERC1155AB(); // Set new implementation contracts addresses in AnotherCloneFactory diff --git a/script/base/deploy-platform.s.sol b/script/base/deploy-platform.s.sol index 85676fe..404ffaf 100644 --- a/script/base/deploy-platform.s.sol +++ b/script/base/deploy-platform.s.sol @@ -11,7 +11,7 @@ import {ABRoyalty} from "src/royalty/ABRoyalty.sol"; import {ABVerifier} from "src/utils/ABVerifier.sol"; import {AnotherCloneFactory} from "src/factory/AnotherCloneFactory.sol"; import {ERC1155AB} from "src/token/ERC1155/ERC1155AB.sol"; -import {ERC721AB} from "src/token/ERC721/ERC721AB.sol"; +import {ERC721ABLE} from "src/token/ERC721/ERC721ABLE.sol"; contract DeployPlatform is Script { uint256 public constant DROP_ID_OFFSET = 10_000; @@ -25,7 +25,7 @@ contract DeployPlatform is Script { string public constant FACTORY_PATH = "deployment/8453/AnotherCloneFactory/address"; string public constant PROXY_ADMIN_PATH = "deployment/8453/ProxyAdmin/address"; - ERC721AB public erc721Impl; + ERC721ABLE public erc721Impl; ERC1155AB public erc1155Impl; ABRoyalty public royaltyImpl; ProxyAdmin public proxyAdmin; @@ -42,7 +42,7 @@ contract DeployPlatform is Script { vm.startBroadcast(deployerPrivateKey); // Deploy Implementation Contracts - erc721Impl = new ERC721AB(); + erc721Impl = new ERC721ABLE(); erc1155Impl = new ERC1155AB(); royaltyImpl = new ABRoyalty(); diff --git a/script/op/deploy-platform.s.sol b/script/op/deploy-platform.s.sol index e9a84c7..436c8f2 100644 --- a/script/op/deploy-platform.s.sol +++ b/script/op/deploy-platform.s.sol @@ -11,7 +11,7 @@ import {ABRoyalty} from "src/royalty/ABRoyalty.sol"; import {ABVerifier} from "src/utils/ABVerifier.sol"; import {AnotherCloneFactory} from "src/factory/AnotherCloneFactory.sol"; import {ERC1155AB} from "src/token/ERC1155/ERC1155AB.sol"; -import {ERC721AB} from "src/token/ERC721/ERC721AB.sol"; +import {ERC721ABLE} from "src/token/ERC721/ERC721ABLE.sol"; contract DeployPlatform is Script { uint256 public constant DROP_ID_OFFSET = 10_000; @@ -21,7 +21,7 @@ contract DeployPlatform is Script { string public constant FACTORY_PATH = "deployment/420/AnotherCloneFactory/address"; string public constant PROXY_ADMIN_PATH = "deployment/420/ProxyAdmin/address"; - ERC721AB public erc721Impl; + ERC721ABLE public erc721Impl; ERC1155AB public erc1155Impl; ABRoyalty public royaltyImpl; ProxyAdmin public proxyAdmin; @@ -39,7 +39,7 @@ contract DeployPlatform is Script { vm.startBroadcast(deployerPrivateKey); // Deploy Implementation Contracts - erc721Impl = new ERC721AB(); + erc721Impl = new ERC721ABLE(); erc1155Impl = new ERC1155AB(); royaltyImpl = new ABRoyalty(); diff --git a/src/token/ERC721/ERC721AB.sol b/src/token/ERC721/ERC721AB.sol index 1acb193..83e26f9 100644 --- a/src/token/ERC721/ERC721AB.sol +++ b/src/token/ERC721/ERC721AB.sol @@ -52,7 +52,7 @@ import {ABEvents} from "src/libraries/ABEvents.sol"; import {IABVerifier} from "src/utils/IABVerifier.sol"; import {IABDataRegistry} from "src/utils/IABDataRegistry.sol"; -contract ERC721AB is ERC721AUpgradeable, OwnableUpgradeable { +abstract contract ERC721AB is ERC721AUpgradeable, OwnableUpgradeable { // _____ __ __ // / ___// /_____ _/ /____ _____ // \__ \/ __/ __ `/ __/ _ \/ ___/ @@ -71,9 +71,6 @@ contract ERC721AB is ERC721AUpgradeable, OwnableUpgradeable { /// @dev Drop Identifier uint256 public dropId; - /// @dev Supply cap for this collection - uint256 public maxSupply; - /// @dev Percentage ownership of the full master right for one token (to be divided by 1e6) uint256 public sharePerToken; @@ -86,24 +83,6 @@ contract ERC721AB is ERC721AUpgradeable, OwnableUpgradeable { /// @dev Mapping storing the amount minted per wallet and per phase mapping(address user => mapping(uint256 phaseId => uint256 minted)) public mintedPerPhase; - /// @dev ERC721AB implementation version - uint8 public constant IMPLEMENTATION_VERSION = 1; - - // ______ __ __ - // / ____/___ ____ _____/ /________ _______/ /_____ _____ - // / / / __ \/ __ \/ ___/ __/ ___/ / / / ___/ __/ __ \/ ___/ - // / /___/ /_/ / / / (__ ) /_/ / / /_/ / /__/ /_/ /_/ / / - // \____/\____/_/ /_/____/\__/_/ \__,_/\___/\__/\____/_/ - - /** - * @notice - * Contract Constructor - */ - /// @custom:oz-upgrades-unsafe-allow constructor - constructor() { - _disableInitializers(); - } - /** * @notice * Contract Initializer (Minimal Proxy Contract) @@ -137,54 +116,6 @@ contract ERC721AB is ERC721AUpgradeable, OwnableUpgradeable { publisher = _publisher; } - // ______ __ __ ______ __ _ - // / ____/ __/ /____ _________ ____ _/ / / ____/_ ______ _____/ /_(_)___ ____ _____ - // / __/ | |/_/ __/ _ \/ ___/ __ \/ __ `/ / / /_ / / / / __ \/ ___/ __/ / __ \/ __ \/ ___/ - // / /____> maxSupply) { - revert ABErrors.NOT_ENOUGH_TOKEN_AVAILABLE(); - } - - // Check if the current phase is private - if (!phase.isPublic) { - // Check that the user is included in the allowlist - if (!abVerifier.verifySignature721(_to, address(this), _phaseId, _signature)) { - revert ABErrors.NOT_ELIGIBLE(); - } - } - - // Check that user did not mint / is not asking to mint more than the max mint per address for the current phase - if (mintedPerPhase[_to][_phaseId] + _quantity > phase.maxMint) revert ABErrors.MAX_MINT_PER_ADDRESS(); - - // Check that user is sending the correct amount of ETH (will revert if user send too much or not enough) - if (msg.value != phase.price * _quantity) revert ABErrors.INCORRECT_ETH_SENT(); - - // Set quantity minted for `_to` during the current phase - mintedPerPhase[_to][_phaseId] += _quantity; - - // Mint `_quantity` amount to `_to` address - _mint(_to, _quantity); - } - // ____ __ ___ __ _ // / __ \____ / /_ __ / | ____/ /___ ___ (_)___ // / / / / __ \/ / / / / / /| |/ __ / __ `__ \/ / __ \ @@ -192,54 +123,6 @@ contract ERC721AB is ERC721AUpgradeable, OwnableUpgradeable { // \____/_/ /_/_/\__, / /_/ |_\__,_/_/ /_/ /_/_/_/ /_/ // /____/ - /** - * @notice - * Initialize the Drop parameters - * Only the contract owner can perform this operation - * - * @param _maxSupply supply cap for this drop - * @param _sharePerToken percentage ownership of the full master right for one token (to be divided by 1e6) - * @param _mintGenesis amount of genesis tokens to be minted - * @param _genesisRecipient recipient address of genesis tokens - * @param _royaltyCurrency royalty currency contract address - * @param _baseUri base URI for this drop - */ - function initDrop( - uint256 _maxSupply, - uint256 _sharePerToken, - uint256 _mintGenesis, - address _genesisRecipient, - address _royaltyCurrency, - string calldata _baseUri - ) external virtual onlyOwner { - // Check that the drop hasn't been already initialized - if (dropId != 0) revert ABErrors.DROP_ALREADY_INITIALIZED(); - - // Check that share per token & royalty currency are consistent - if ( - (_sharePerToken == 0 && _royaltyCurrency != address(0)) - || (_royaltyCurrency == address(0) && _sharePerToken != 0) - ) revert ABErrors.INVALID_PARAMETER(); - - // Register Drop within ABDropRegistry - dropId = abDataRegistry.registerDrop(publisher, _royaltyCurrency, 0); - - // Set supply cap - maxSupply = _maxSupply; - - // Set the royalty share - sharePerToken = _sharePerToken; - - // Set base URI - baseTokenURI = _baseUri; - - // Mint Genesis tokens to `_genesisRecipient` address - if (_mintGenesis > 0) { - if (_mintGenesis > _maxSupply) revert ABErrors.INVALID_PARAMETER(); - _mint(_genesisRecipient, _mintGenesis); - } - } - /** * @notice * Update the Base URI @@ -334,18 +217,6 @@ contract ERC721AB is ERC721AUpgradeable, OwnableUpgradeable { IERC20(_token).transfer(msg.sender, _amount); } - /** - * @notice - * Set the maximum supply - * Only the contract owner can perform this operation - * - * @param _maxSupply new maximum supply to be set - */ - function setMaxSupply(uint256 _maxSupply) external onlyOwner { - if (_maxSupply < _totalMinted()) revert ABErrors.INVALID_PARAMETER(); - maxSupply = _maxSupply; - } - // _ ___ ______ __ _ // | | / (_)__ _ __ / ____/_ ______ _____/ /_(_)___ ____ _____ // | | / / / _ \ | /| / / / /_ / / / / __ \/ ___/ __/ / __ \/ __ \/ ___/ @@ -403,6 +274,48 @@ contract ERC721AB is ERC721AUpgradeable, OwnableUpgradeable { // _/ // / / / /_/ __/ / / / / / /_/ / / / __/ / /_/ / / / / /__/ /_/ / /_/ / / / (__ ) // /___/_/ /_/\__/\___/_/ /_/ /_/\__,_/_/ /_/ \__,_/_/ /_/\___/\__/_/\____/_/ /_/____/ + /** + * @notice + * Initialize the Drop parameters + * Only the contract owner can perform this operation + * + * @param _sharePerToken percentage ownership of the full master right for one token (to be divided by 1e6) + * @param _mintGenesis amount of genesis tokens to be minted + * @param _genesisRecipient recipient address of genesis tokens + * @param _royaltyCurrency royalty currency contract address + * @param _baseUri base URI for this drop + */ + function _initDrop( + uint256 _sharePerToken, + uint256 _mintGenesis, + address _genesisRecipient, + address _royaltyCurrency, + string calldata _baseUri + ) internal { + // Check that the drop hasn't been already initialized + if (dropId != 0) revert ABErrors.DROP_ALREADY_INITIALIZED(); + + // Check that share per token & royalty currency are consistent + if ( + (_sharePerToken == 0 && _royaltyCurrency != address(0)) + || (_royaltyCurrency == address(0) && _sharePerToken != 0) + ) revert ABErrors.INVALID_PARAMETER(); + + // Register Drop within ABDropRegistry + dropId = abDataRegistry.registerDrop(publisher, _royaltyCurrency, 0); + + // Set the royalty share + sharePerToken = _sharePerToken; + + // Set base URI + baseTokenURI = _baseUri; + + // Mint Genesis tokens to `_genesisRecipient` address + if (_mintGenesis > 0) { + _mint(_genesisRecipient, _mintGenesis); + } + } + /** * @notice * Returns true if the passed phase ID is active diff --git a/src/token/ERC721/ERC721ABLE.sol b/src/token/ERC721/ERC721ABLE.sol new file mode 100644 index 0000000..6976a21 --- /dev/null +++ b/src/token/ERC721/ERC721ABLE.sol @@ -0,0 +1,169 @@ +// ██████████████████████████████████ +// ██████████████████████████████████ +// ██████████████████████████████████ +// ██████████████████████████████████ +// ██████████████████████████████████ +// ██████████████████████████████████ +// ██████████████████████████████████ +// ██████████████████████████████████ +// ██████████████████████████████████ +// ████████████████████████ ██████████ +// ████████████████████████ ██████████ +// ████████████████████████ ██████████ +// ████████████████████████ ██████████ +// ████████████████████ +// ████████████████████ +// ████████████████████ +// ████████████████████ +// +// +// █████╗ ███╗ ██╗ ██████╗ ████████╗██╗ ██╗███████╗██████╗ ██████╗ ██╗ ██████╗ ██████╗██╗ ██╗ +// ██╔══██╗████╗ ██║██╔═══██╗╚══██╔══╝██║ ██║██╔════╝██╔══██╗██╔══██╗██║ ██╔═══██╗██╔════╝██║ ██╔╝ +// ███████║██╔██╗ ██║██║ ██║ ██║ ███████║█████╗ ██████╔╝██████╔╝██║ ██║ ██║██║ █████╔╝ +// ██╔══██║██║╚██╗██║██║ ██║ ██║ ██╔══██║██╔══╝ ██╔══██╗██╔══██╗██║ ██║ ██║██║ ██╔═██╗ +// ██║ ██║██║ ╚████║╚██████╔╝ ██║ ██║ ██║███████╗██║ ██║██████╔╝███████╗╚██████╔╝╚██████╗██║ ██╗ +// ╚═╝ ╚═╝╚═╝ ╚═══╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝╚═════╝ ╚══════╝ ╚═════╝ ╚═════╝╚═╝ ╚═╝ +// + +/** + * @title ERC721ABLE + * @author anotherblock Technical Team + * @notice anotherblock ERC721 contract used for regular mint mechanism & limited edition + * + */ + +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.18; + +/* anotherblock Contract */ +import {ERC721AB} from "src/token/ERC721/ERC721AB.sol"; + +/* anotherblock Libraries */ +import {ABDataTypes} from "src/libraries/ABDataTypes.sol"; +import {ABErrors} from "src/libraries/ABErrors.sol"; + +contract ERC721ABLE is ERC721AB { + // _____ __ __ + // / ___// /_____ _/ /____ _____ + // \__ \/ __/ __ `/ __/ _ \/ ___/ + // ___/ / /_/ /_/ / /_/ __(__ ) + // /____/\__/\__,_/\__/\___/____/ + + /// @dev Supply cap for this collection + uint256 public maxSupply; + + /// @dev Implementation Type + bytes32 public constant IMPLEMENTATION_TYPE = keccak256("LIMITED_EDITION"); + + /// @dev ERC721AB implementation version + uint8 public constant IMPLEMENTATION_VERSION = 1; + + // ______ __ __ + // / ____/___ ____ _____/ /________ _______/ /_____ _____ + // / / / __ \/ __ \/ ___/ __/ ___/ / / / ___/ __/ __ \/ ___/ + // / /___/ /_/ / / / (__ ) /_/ / / /_/ / /__/ /_/ /_/ / / + // \____/\____/_/ /_/____/\__/_/ \__,_/\___/\__/\____/_/ + + /** + * @notice + * Contract Constructor + */ + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + // ______ __ __ ______ __ _ + // / ____/ __/ /____ _________ ____ _/ / / ____/_ ______ _____/ /_(_)___ ____ _____ + // / __/ | |/_/ __/ _ \/ ___/ __ \/ __ `/ / / /_ / / / / __ \/ ___/ __/ / __ \/ __ \/ ___/ + // / /____> maxSupply) { + revert ABErrors.NOT_ENOUGH_TOKEN_AVAILABLE(); + } + + // Check if the current phase is private + if (!phase.isPublic) { + // Check that the user is included in the allowlist + if (!abVerifier.verifySignature721(_to, address(this), _phaseId, _signature)) { + revert ABErrors.NOT_ELIGIBLE(); + } + } + + // Check that user did not mint / is not asking to mint more than the max mint per address for the current phase + if (mintedPerPhase[_to][_phaseId] + _quantity > phase.maxMint) revert ABErrors.MAX_MINT_PER_ADDRESS(); + + // Check that user is sending the correct amount of ETH (will revert if user send too much or not enough) + if (msg.value != phase.price * _quantity) revert ABErrors.INCORRECT_ETH_SENT(); + + // Set quantity minted for `_to` during the current phase + mintedPerPhase[_to][_phaseId] += _quantity; + + // Mint `_quantity` amount to `_to` address + _mint(_to, _quantity); + } + + // ____ __ ___ __ _ + // / __ \____ / /_ __ / | ____/ /___ ___ (_)___ + // / / / / __ \/ / / / / / /| |/ __ / __ `__ \/ / __ \ + // / /_/ / / / / / /_/ / / ___ / /_/ / / / / / / / / / / + // \____/_/ /_/_/\__, / /_/ |_\__,_/_/ /_/ /_/_/_/ /_/ + // /____/ + + /** + * @notice + * Initialize the Drop parameters + * Only the contract owner can perform this operation + * + * @param _maxSupply supply cap for this drop + * @param _sharePerToken percentage ownership of the full master right for one token (to be divided by 1e6) + * @param _mintGenesis amount of genesis tokens to be minted + * @param _genesisRecipient recipient address of genesis tokens + * @param _royaltyCurrency royalty currency contract address + * @param _baseUri base URI for this drop + */ + function initDrop( + uint256 _maxSupply, + uint256 _sharePerToken, + uint256 _mintGenesis, + address _genesisRecipient, + address _royaltyCurrency, + string calldata _baseUri + ) external onlyOwner { + // Set supply cap + maxSupply = _maxSupply; + if (_mintGenesis > _maxSupply) revert ABErrors.INVALID_PARAMETER(); + + _initDrop(_sharePerToken, _mintGenesis, _genesisRecipient, _royaltyCurrency, _baseUri); + } + + /** + * @notice + * Set the maximum supply + * Only the contract owner can perform this operation + * + * @param _maxSupply new maximum supply to be set + */ + function setMaxSupply(uint256 _maxSupply) external onlyOwner { + if (_maxSupply < _totalMinted()) revert ABErrors.INVALID_PARAMETER(); + maxSupply = _maxSupply; + } +} diff --git a/test/_testdata/ERC721AB.td.sol b/test/_testdata/ERC721ABLE.td.sol similarity index 100% rename from test/_testdata/ERC721AB.td.sol rename to test/_testdata/ERC721ABLE.td.sol diff --git a/test/factory/AnotherCloneFactory.t.sol b/test/factory/AnotherCloneFactory.t.sol index 765188a..f1c3594 100644 --- a/test/factory/AnotherCloneFactory.t.sol +++ b/test/factory/AnotherCloneFactory.t.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.18; import "forge-std/Test.sol"; -import {ERC721AB} from "src/token/ERC721/ERC721AB.sol"; +import {ERC721ABLE} from "src/token/ERC721/ERC721ABLE.sol"; import {ERC1155AB} from "src/token/ERC1155/ERC1155AB.sol"; import {ABDataRegistry} from "src/utils/ABDataRegistry.sol"; import {AnotherCloneFactory} from "src/factory/AnotherCloneFactory.sol"; @@ -24,7 +24,7 @@ contract AnotherCloneFactoryTest is Test, AnotherCloneFactoryTestData { AnotherCloneFactory public anotherCloneFactory; ABRoyalty public royaltyImplementation; ERC1155AB public erc1155Implementation; - ERC721AB public erc721Implementation; + ERC721ABLE public erc721Implementation; ProxyAdmin public proxyAdmin; TransparentUpgradeableProxy public anotherCloneFactoryProxy; @@ -52,7 +52,7 @@ contract AnotherCloneFactoryTest is Test, AnotherCloneFactoryTestData { erc1155Implementation = new ERC1155AB(); vm.label(address(erc1155Implementation), "erc1155Implementation"); - erc721Implementation = new ERC721AB(); + erc721Implementation = new ERC721ABLE(); vm.label(address(erc721Implementation), "erc721Implementation"); royaltyImplementation = new ABRoyalty(); @@ -219,7 +219,7 @@ contract AnotherCloneFactoryTest is Test, AnotherCloneFactoryTestData { anotherCloneFactory.createCollection721(NAME, SALT); (address nft, address publisher) = anotherCloneFactory.collections(0); - assertEq(ERC721AB(nft).owner(), _publisher); + assertEq(ERC721ABLE(nft).owner(), _publisher); assertEq(publisher, _publisher); vm.stopPrank(); @@ -246,7 +246,7 @@ contract AnotherCloneFactoryTest is Test, AnotherCloneFactoryTestData { anotherCloneFactory.createCollection721FromImplementation(address(erc721Implementation), _publisher, NAME, SALT); (address nft, address publisher) = anotherCloneFactory.collections(0); - assertEq(ERC721AB(nft).owner(), _publisher); + assertEq(ERC721ABLE(nft).owner(), _publisher); assertEq(publisher, _publisher); vm.stopPrank(); @@ -306,7 +306,7 @@ contract AnotherCloneFactoryTest is Test, AnotherCloneFactoryTestData { } function test_setERC721Implementation_admin() public { - ERC721AB newErc721Implementation = new ERC721AB(); + ERC721ABLE newErc721Implementation = new ERC721ABLE(); assertEq(anotherCloneFactory.erc721Impl(), address(erc721Implementation)); @@ -318,7 +318,7 @@ contract AnotherCloneFactoryTest is Test, AnotherCloneFactoryTestData { function test_setERC721Implementation_nonAdmin(address _nonAdmin) public { vm.assume(_nonAdmin != address(this)); - ERC721AB newErc721Implementation = new ERC721AB(); + ERC721ABLE newErc721Implementation = new ERC721ABLE(); vm.prank(_nonAdmin); diff --git a/test/royalty/ABRoyalty.t.sol b/test/royalty/ABRoyalty.t.sol index c734e9f..82b7efe 100644 --- a/test/royalty/ABRoyalty.t.sol +++ b/test/royalty/ABRoyalty.t.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.18; import "forge-std/Test.sol"; -import {ERC721AB} from "src/token/ERC721/ERC721AB.sol"; +import {ERC721ABLE} from "src/token/ERC721/ERC721ABLE.sol"; import {ERC1155AB} from "src/token/ERC1155/ERC1155AB.sol"; import {ABDataRegistry} from "src/utils/ABDataRegistry.sol"; import {AnotherCloneFactory} from "src/factory/AnotherCloneFactory.sol"; @@ -35,7 +35,7 @@ contract ABRoyaltyTest is Test, ABRoyaltyTestData { ABVerifier public abVerifier; ABDataRegistry public abDataRegistry; AnotherCloneFactory public anotherCloneFactory; - ERC721AB public erc721Impl; + ERC721ABLE public erc721Impl; ERC1155AB public erc1155Impl; ProxyAdmin public proxyAdmin; TransparentUpgradeableProxy public anotherCloneFactoryProxy; @@ -80,7 +80,7 @@ contract ABRoyaltyTest is Test, ABRoyaltyTestData { erc1155Impl = new ERC1155AB(); vm.label(address(erc1155Impl), "erc1155Impl"); - erc721Impl = new ERC721AB(); + erc721Impl = new ERC721ABLE(); vm.label(address(erc721Impl), "erc721Impl"); abRoyaltyImpl = new ABRoyalty(); diff --git a/test/token/ERC1155/ERC1155AB.t.sol b/test/token/ERC1155/ERC1155AB.t.sol index e7b43d9..2251110 100644 --- a/test/token/ERC1155/ERC1155AB.t.sol +++ b/test/token/ERC1155/ERC1155AB.t.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.18; import "forge-std/Test.sol"; -import {ERC721AB} from "src/token/ERC721/ERC721AB.sol"; +import {ERC721ABLE} from "src/token/ERC721/ERC721ABLE.sol"; import {ERC1155AB} from "src/token/ERC1155/ERC1155AB.sol"; import {ABDataRegistry} from "src/utils/ABDataRegistry.sol"; import {AnotherCloneFactory} from "src/factory/AnotherCloneFactory.sol"; @@ -45,7 +45,7 @@ contract ERC1155ABTest is Test, ERC1155ABTestData, ERC1155Holder { ABDataRegistry public abDataRegistry; AnotherCloneFactory public anotherCloneFactory; ABRoyalty public royaltyImpl; - ERC721AB public erc721Impl; + ERC721ABLE public erc721Impl; ERC1155AB public erc1155Impl; ProxyAdmin public proxyAdmin; TransparentUpgradeableProxy public anotherCloneFactoryProxy; @@ -109,7 +109,7 @@ contract ERC1155ABTest is Test, ERC1155ABTestData, ERC1155Holder { erc1155Impl = new ERC1155AB(); vm.label(address(erc1155Impl), "erc1155Impl"); - erc721Impl = new ERC721AB(); + erc721Impl = new ERC721ABLE(); vm.label(address(erc721Impl), "erc721Impl"); royaltyImpl = new ABRoyalty(); diff --git a/test/token/ERC721/ERC721AB.t.sol b/test/token/ERC721/ERC721ABLE.t.sol similarity index 99% rename from test/token/ERC721/ERC721AB.t.sol rename to test/token/ERC721/ERC721ABLE.t.sol index d25b9a6..e6df19d 100644 --- a/test/token/ERC721/ERC721AB.t.sol +++ b/test/token/ERC721/ERC721ABLE.t.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.18; import "forge-std/Test.sol"; -import {ERC721AB} from "src/token/ERC721/ERC721AB.sol"; +import {ERC721ABLE} from "src/token/ERC721/ERC721ABLE.sol"; import {ERC1155AB} from "src/token/ERC1155/ERC1155AB.sol"; import {ABDataRegistry} from "src/utils/ABDataRegistry.sol"; import {AnotherCloneFactory} from "src/factory/AnotherCloneFactory.sol"; @@ -14,7 +14,7 @@ import {ABErrors} from "src/libraries/ABErrors.sol"; import {ABSuperToken} from "test/_mocks/ABSuperToken.sol"; import {MockToken} from "test/_mocks/MockToken.sol"; -import {ERC721ABTestData} from "test/_testdata/ERC721AB.td.sol"; +import {ERC721ABTestData} from "test/_testdata/ERC721ABLE.td.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; @@ -45,14 +45,14 @@ contract ERC721ABTest is Test, ERC721ABTestData { ABDataRegistry public abDataRegistry; AnotherCloneFactory public anotherCloneFactory; ABRoyalty public royaltyImpl; - ERC721AB public erc721Impl; + ERC721ABLE public erc721Impl; ERC1155AB public erc1155Impl; ProxyAdmin public proxyAdmin; TransparentUpgradeableProxy public anotherCloneFactoryProxy; TransparentUpgradeableProxy public abDataRegistryProxy; TransparentUpgradeableProxy public abVerifierProxy; - ERC721AB public nft; + ERC721ABLE public nft; uint256 public constant DROP_ID_OFFSET = 10_000; @@ -109,7 +109,7 @@ contract ERC721ABTest is Test, ERC721ABTestData { erc1155Impl = new ERC1155AB(); vm.label(address(erc1155Impl), "erc1155Impl"); - erc721Impl = new ERC721AB(); + erc721Impl = new ERC721ABLE(); vm.label(address(erc721Impl), "erc721Impl"); royaltyImpl = new ABRoyalty(); @@ -153,17 +153,17 @@ contract ERC721ABTest is Test, ERC721ABTestData { (address nftAddr,) = anotherCloneFactory.collections(0); - nft = ERC721AB(nftAddr); + nft = ERC721ABLE(nftAddr); } function test_initialize() public { TransparentUpgradeableProxy erc721proxy = new TransparentUpgradeableProxy( - address(new ERC721AB()), + address(new ERC721ABLE()), address(proxyAdmin), "" ); - nft = ERC721AB(address(erc721proxy)); + nft = ERC721ABLE(address(erc721proxy)); nft.initialize(publisher, address(abDataRegistry), address(abVerifier), NAME); assertEq(address(nft.abDataRegistry()), address(abDataRegistry));