diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e230f90..b828d48 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -5,14 +5,14 @@ on: branches: - main - dev - - 'feature/*' - - 'features/*' + - "feature/*" + - "features/*" pull_request: branches: - main - dev - - 'feature/*' - - 'features/*' + - "feature/*" + - "features/*" env: FOUNDRY_PROFILE: ci @@ -23,24 +23,21 @@ jobs: fail-fast: true name: Foundry project - runs-on: [self-hosted, dockerize] + runs-on: ubuntu-latest 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: Install dependencies + run: | + forge soldeer update + id: install - name: Run Forge build run: | diff --git a/src/ERC1155Common.sol b/src/ERC1155Common.sol new file mode 100644 index 0000000..f8e8c41 --- /dev/null +++ b/src/ERC1155Common.sol @@ -0,0 +1,145 @@ +// SPDX-License-Identifier: MIT +// Compatible with OpenZeppelin Contracts ^5.0.0 +pragma solidity ^0.8.20; + +import { AccessControlEnumerable } from "@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol"; +import { IERC165 } from "@openzeppelin/contracts/interfaces/IERC165.sol"; +import { ERC1155 } from "@openzeppelin/contracts/token/ERC1155/ERC1155.sol"; + +import { IERC1155Common } from "./interfaces/IERC1155Common.sol"; +import { ERC1155Burnable } from "@openzeppelin/contracts/token/ERC1155/extensions/ERC1155Burnable.sol"; +import { ERC1155Pausable } from "@openzeppelin/contracts/token/ERC1155/extensions/ERC1155Pausable.sol"; +import { ERC1155Supply } from "@openzeppelin/contracts/token/ERC1155/extensions/ERC1155Supply.sol"; +import { Strings } from "@openzeppelin/contracts/utils/Strings.sol"; + +contract ERC1155Common is + ERC1155, + AccessControlEnumerable, + ERC1155Pausable, + ERC1155Burnable, + ERC1155Supply, + IERC1155Common +{ + using Strings for uint256; + + bytes32 public constant URI_SETTER_ROLE = keccak256("URI_SETTER_ROLE"); + bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE"); + bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); + + string private _name; + string private _symbol; + + constructor(address admin, string memory name_, string memory symbol_, string memory uri_) ERC1155(uri_) { + _grantRole(DEFAULT_ADMIN_ROLE, admin); + _grantRole(PAUSER_ROLE, admin); + _grantRole(MINTER_ROLE, admin); + _grantRole(URI_SETTER_ROLE, admin); + + _name = name_; + _symbol = symbol_; + } + + /** + * @dev Set the URI for all token types. + * Requirements: + * - the caller must have the `URI_SETTER_ROLE`. + */ + function setURI( + string memory newURI + ) external onlyRole(URI_SETTER_ROLE) { + _setURI(newURI); + } + + /** + * @dev Pauses all token transfers. + * Requirements: + * - the caller must have the `PAUSER_ROLE`. + */ + function pause() external onlyRole(PAUSER_ROLE) { + _pause(); + } + + /** + * @dev Unpauses all token transfers. + * Requirements: + * - the caller must have the `PAUSER_ROLE`. + */ + function unpause() external onlyRole(PAUSER_ROLE) { + _unpause(); + } + + /// @inheritdoc IERC1155Common + function mint(address account, uint256 id, uint256 amount, bytes calldata data) public virtual onlyRole(MINTER_ROLE) { + _mint(account, id, amount, data); + } + + /// @inheritdoc IERC1155Common + function mintBatch( + address to, + uint256[] calldata ids, + uint256[] calldata amounts, + bytes calldata data + ) public virtual onlyRole(MINTER_ROLE) { + _mintBatch(to, ids, amounts, data); + } + + /** + * @dev Mint single token to multiple addresses. + * Requirements: + * - the caller must have the `MINTER_ROLE`. + */ + function bulkMint( + uint256 id, + address[] calldata tos, + uint256[] calldata amounts, + bytes[] calldata datas + ) public virtual onlyRole(MINTER_ROLE) { + uint256 length = tos.length; + require(length != 0 && length == amounts.length && length == datas.length, "ERC1155: invalid array lengths"); + + for (uint256 i; i < length; ++i) { + _mint(tos[i], id, amounts[i], datas[i]); + } + } + + /** + * @dev See {ERC1155-uri}. + */ + function uri( + uint256 tokenId + ) public view virtual override returns (string memory) { + string memory uri_ = super.uri(tokenId); + return string.concat(uri_, tokenId.toString()); + } + + /// @inheritdoc IERC1155Common + function name() public view virtual returns (string memory) { + return _name; + } + + /// @inheritdoc IERC1155Common + function symbol() public view virtual returns (string memory) { + return _symbol; + } + + /** + * @dev See {ERC165-supportsInterface}. + */ + function supportsInterface( + bytes4 interfaceId + ) public view virtual override(IERC165, ERC1155, AccessControlEnumerable) returns (bool) { + return interfaceId == type(IERC1155Common).interfaceId || super.supportsInterface(interfaceId); + } + + /** + * @dev See {ERC1155-_update}. + */ + function _update( + address from, + address to, + uint256[] memory ids, + uint256[] memory values + ) internal virtual override(ERC1155, ERC1155Supply, ERC1155Pausable) { + super._update(from, to, ids, values); + } +} diff --git a/src/ERC721Common.sol b/src/ERC721Common.sol index 1851c53..8cf5abb 100644 --- a/src/ERC721Common.sol +++ b/src/ERC721Common.sol @@ -7,12 +7,10 @@ import { IERC721State } from "./interfaces/IERC721State.sol"; import { ERC721Nonce } from "./refs/ERC721Nonce.sol"; import { ERC721 } from "@openzeppelin/contracts/token/ERC721/ERC721.sol"; -abstract contract ERC721Common is ERC721Nonce, ERC721PresetMinterPauserAutoIdCustomized, IERC721State, IERC721Common { - constructor( - string memory name_, - string memory symbol_, - string memory baseTokenURI - ) ERC721PresetMinterPauserAutoIdCustomized(name_, symbol_, baseTokenURI) { } +contract ERC721Common is ERC721Nonce, ERC721PresetMinterPauserAutoIdCustomized, IERC721State, IERC721Common { + constructor(string memory name, string memory symbol, string memory baseTokenURI) + ERC721PresetMinterPauserAutoIdCustomized(name, symbol, baseTokenURI) + { } /// @inheritdoc IERC721State function stateOf( diff --git a/src/interfaces/IERC1155Common.sol b/src/interfaces/IERC1155Common.sol new file mode 100644 index 0000000..1531282 --- /dev/null +++ b/src/interfaces/IERC1155Common.sol @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.0; + +import { IAccessControlEnumerable } from "@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol"; +import { IERC1155 } from "@openzeppelin/contracts/token/ERC1155/IERC1155.sol"; + +interface IERC1155Common is IAccessControlEnumerable, IERC1155 { + /// @dev Return the name of the collection. + function name() external view returns (string memory); + + /// @dev Return the symbol of the collection. + function symbol() external view returns (string memory); + + /** + * @dev Mints a single ERC1155 token and assigns it to the specified address. + * + * Requirements: + * - the caller must have the `MINTER_ROLE`. + * + * @param to The address to which the minted token will be assigned. + * @param id The ID of the token to mint. + * @param amount The amount of tokens to mint. + * @param data Additional data with no specified format. + */ + function mint(address to, uint256 id, uint256 amount, bytes calldata data) external; + + /** + * @dev Mints multiple ERC1155 tokens and assigns them to the specified address. + * + * Requirements: + * - the caller must have the `MINTER_ROLE`. + * + * @param to The address to which the minted tokens will be assigned. + * @param ids The IDs of the tokens to mint. + * @param amounts The amounts of tokens to mint. + * @param data Additional data with no specified format. + */ + function mintBatch(address to, uint256[] calldata ids, uint256[] calldata amounts, bytes calldata data) external; + + /** + * @dev Mint single token to multiple addresses. + * Requirements: + * - the caller must have the `MINTER_ROLE`. + * + * @param id The ID of the token to mint. + * @param tos The addresses to which the minted tokens will be assigned. + * @param amounts The amounts of tokens to mint. + * @param datas Additional data with no specified format. + */ + function bulkMint(uint256 id, address[] calldata tos, uint256[] calldata amounts, bytes[] calldata datas) external; +} diff --git a/src/interfaces/launchpad/INFTPresale.sol b/src/interfaces/launchpad/INFTPresale.sol new file mode 100644 index 0000000..d739042 --- /dev/null +++ b/src/interfaces/launchpad/INFTPresale.sol @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +/// @dev Interface for the NFT contract that compatible with the contract MavisPresale. +/// MUST be included ERC165 interface to support the detection of the contract's capabilities. +interface INFTPresale { + /** + * @dev Mint NFTs for the presale. + * + * Requirements: + * - The mintedTokenIds and mintedAmounts should have the same length. + * - The mintedTokenIds array should be unique. + * - For ERC721 NFTs, each minted token's quantity should always be 1. + * - For ERC1155 NFTs, each minted token's quantity should be actual minted amounts. + * - The total of minted amounts can be different from the input `quantity`. + * + * Examples: + * - ERC1155: If mintedTokenIds = [1, 2], then mintedAmounts = [10, 20] + * - ERC721: If mintedTokenIds = [1, 2], then mintedAmounts = [1, 1] + * + * @param to The address to mint the NFTs to. + * @param quantity The quantity of NFTs to mint. + * @param extraData The extra data for further customization. + * @return mintedTokenIds The token IDs of the minted NFTs. + * @return mintedAmounts The minted amounts according to the `mintedTokenIds`. + */ + function mintPresale(address to, uint256 quantity, bytes calldata extraData) + external + returns (uint256[] memory mintedTokenIds, uint256[] memory mintedAmounts); +} diff --git a/src/launchpad/NFTLaunchpadCommon.sol b/src/launchpad/NFTLaunchpadCommon.sol index e9458f1..08a0d73 100644 --- a/src/launchpad/NFTLaunchpadCommon.sol +++ b/src/launchpad/NFTLaunchpadCommon.sol @@ -7,9 +7,7 @@ import { INFTLaunchpad } from "../interfaces/launchpad/INFTLaunchpad.sol"; abstract contract NFTLaunchpadCommon is IERC165, INFTLaunchpad { /// @dev Returns whether the contract supports the NFT launchpad interface. - function supportsInterface( - bytes4 interfaceId - ) public view virtual returns (bool) { - return interfaceId == type(INFTLaunchpad).interfaceId; + function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) { + return interfaceId == type(INFTLaunchpad).interfaceId || interfaceId == type(IERC165).interfaceId; } } diff --git a/src/launchpad/NFTPresaleCommon.sol b/src/launchpad/NFTPresaleCommon.sol new file mode 100644 index 0000000..16ca8f2 --- /dev/null +++ b/src/launchpad/NFTPresaleCommon.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.22; + +import { IERC165 } from "@openzeppelin/contracts/interfaces/IERC165.sol"; + +import { INFTPresale } from "../interfaces/launchpad/INFTPresale.sol"; + +abstract contract NFTPresaleCommon is IERC165, INFTPresale { + /// @dev Returns whether the contract supports the NFT presale interface. + function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) { + return interfaceId == type(INFTPresale).interfaceId || interfaceId == type(IERC165).interfaceId; + } +} diff --git a/src/mock/SampleERC1155.sol b/src/mock/SampleERC1155.sol new file mode 100644 index 0000000..e919819 --- /dev/null +++ b/src/mock/SampleERC1155.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.0; + +import "../ERC1155Common.sol"; + +contract SampleERC1155 is ERC1155Common { + constructor(address admin, string memory name, string memory symbol, string memory uri) + ERC1155Common(admin, name, symbol, uri) + { } +} diff --git a/src/mock/launchpad/SampleERC1155Launchpad.sol b/src/mock/launchpad/SampleERC1155Launchpad.sol new file mode 100644 index 0000000..77d7106 --- /dev/null +++ b/src/mock/launchpad/SampleERC1155Launchpad.sol @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import { NFTLaunchpadCommon } from "../../launchpad/NFTLaunchpadCommon.sol"; +import { SampleERC1155, ERC1155Common } from "../SampleERC1155.sol"; + +contract SampleERC1155Launchpad is SampleERC1155, NFTLaunchpadCommon { + constructor(address admin, string memory name, string memory symbol, string memory uri) + SampleERC1155(admin, name, symbol, uri) + { } + + /// @dev Mint NFTs for the launchpad. + function mintLaunchpad( + address to, + uint256 quantity, + bytes calldata /* extraData */ + ) external onlyRole(MINTER_ROLE) returns (uint256[] memory tokenIds, uint256[] memory amounts) { + _mint(to, 3, quantity, ""); + _mint(to, 4, 1, ""); + + tokenIds = new uint256[](2); + amounts = new uint256[](2); + tokenIds[0] = 3; + tokenIds[1] = 4; + + amounts[0] = quantity; + amounts[1] = 1; + } + + function supportsInterface(bytes4 interfaceId) + public + view + virtual + override(ERC1155Common, NFTLaunchpadCommon) + returns (bool) + { + return ERC1155Common.supportsInterface(interfaceId) || NFTLaunchpadCommon.supportsInterface(interfaceId); + } +} diff --git a/src/mock/launchpad/SampleERC1155Presale.sol b/src/mock/launchpad/SampleERC1155Presale.sol new file mode 100644 index 0000000..f7a9e19 --- /dev/null +++ b/src/mock/launchpad/SampleERC1155Presale.sol @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import { NFTPresaleCommon } from "../../launchpad/NFTPresaleCommon.sol"; +import { ERC1155Common, SampleERC1155 } from "../SampleERC1155.sol"; + +contract SampleERC1155Presale is SampleERC1155, NFTPresaleCommon { + constructor( + address admin, + string memory name, + string memory symbol, + string memory uri + ) SampleERC1155(admin, name, symbol, uri) { } + + /// @dev Mint NFTs for the launchpad. + function mintPresale( + address to, + uint256 quantity, + bytes calldata /* extraData */ + ) external onlyRole(MINTER_ROLE) returns (uint256[] memory tokenIds, uint256[] memory amounts) { + _mint(to, 3, quantity, ""); + _mint(to, 4, 1, ""); + + tokenIds = new uint256[](2); + amounts = new uint256[](2); + tokenIds[0] = 3; + tokenIds[1] = 4; + + amounts[0] = quantity; + amounts[1] = 1; + } + + function supportsInterface( + bytes4 interfaceId + ) public view virtual override(ERC1155Common, NFTPresaleCommon) returns (bool) { + return ERC1155Common.supportsInterface(interfaceId) || NFTPresaleCommon.supportsInterface(interfaceId); + } +} diff --git a/src/mock/launchpad/SampleNFT721Launchpad.sol b/src/mock/launchpad/SampleERC721Launchpad.sol similarity index 72% rename from src/mock/launchpad/SampleNFT721Launchpad.sol rename to src/mock/launchpad/SampleERC721Launchpad.sol index 2d67a64..46a69d7 100644 --- a/src/mock/launchpad/SampleNFT721Launchpad.sol +++ b/src/mock/launchpad/SampleERC721Launchpad.sol @@ -7,7 +7,7 @@ import { ERC721Common } from "../../ERC721Common.sol"; import { NFTLaunchpadCommon } from "../../launchpad/NFTLaunchpadCommon.sol"; import { SampleERC721 } from "../SampleERC721.sol"; -contract SampleNFT721Launchpad is SampleERC721, NFTLaunchpadCommon { +contract SampleERC721Launchpad is SampleERC721, NFTLaunchpadCommon { constructor(string memory name_, string memory symbol_, string memory uri_) SampleERC721(name_, symbol_, uri_) { } /// @dev Mint NFTs for the launchpad. @@ -24,9 +24,13 @@ contract SampleNFT721Launchpad is SampleERC721, NFTLaunchpadCommon { } } - function supportsInterface( - bytes4 interfaceId - ) public view virtual override(ERC721Common, NFTLaunchpadCommon) returns (bool) { - return super.supportsInterface(interfaceId); + function supportsInterface(bytes4 interfaceId) + public + view + virtual + override(ERC721Common, NFTLaunchpadCommon) + returns (bool) + { + return ERC721Common.supportsInterface(interfaceId) || NFTLaunchpadCommon.supportsInterface(interfaceId); } } diff --git a/src/mock/launchpad/SampleERC721Presale.sol b/src/mock/launchpad/SampleERC721Presale.sol new file mode 100644 index 0000000..9f59869 --- /dev/null +++ b/src/mock/launchpad/SampleERC721Presale.sol @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import { SampleERC721 } from "../SampleERC721.sol"; + +import { ERC721Common } from "../../ERC721Common.sol"; +import { NFTPresaleCommon } from "../../launchpad/NFTPresaleCommon.sol"; +import { SampleERC721 } from "../SampleERC721.sol"; + +contract SampleERC721Presale is SampleERC721, NFTPresaleCommon { + constructor(string memory name_, string memory symbol_, string memory uri_) SampleERC721(name_, symbol_, uri_) { } + + /// @dev Mint NFTs for the presale. + function mintPresale( + address to, + uint256 quantity, + bytes calldata /* extraData */ + ) external onlyRole(MINTER_ROLE) returns (uint256[] memory tokenIds, uint256[] memory amounts) { + tokenIds = new uint256[](quantity); + amounts = new uint256[](quantity); + for (uint256 i; i < quantity; ++i) { + tokenIds[i] = _mintFor(to); + amounts[i] = 1; + } + } + + function supportsInterface( + bytes4 interfaceId + ) public view virtual override(ERC721Common, NFTPresaleCommon) returns (bool) { + return ERC721Common.supportsInterface(interfaceId) || NFTPresaleCommon.supportsInterface(interfaceId); + } +} diff --git a/src/mock/launchpad/SampleNFT1155Launchpad.sol b/src/mock/launchpad/SampleNFT1155Launchpad.sol deleted file mode 100644 index d62eb2a..0000000 --- a/src/mock/launchpad/SampleNFT1155Launchpad.sol +++ /dev/null @@ -1,39 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.19; - -import { NFTLaunchpadCommon } from "../../launchpad/NFTLaunchpadCommon.sol"; -import { AccessControl } from "@openzeppelin/contracts/access/AccessControl.sol"; -import { ERC1155 } from "@openzeppelin/contracts/token/ERC1155/ERC1155.sol"; - -contract SampleNFT1155Launchpad is ERC1155, AccessControl, NFTLaunchpadCommon { - bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); - - constructor(address admin, address minter, string memory uri_) ERC1155(uri_) { - _grantRole(DEFAULT_ADMIN_ROLE, admin); - _grantRole(MINTER_ROLE, minter); - } - - /// @dev Mint NFTs for the launchpad. - function mintLaunchpad( - address to, - uint256 quantity, - bytes calldata /* extraData */ - ) external onlyRole(MINTER_ROLE) returns (uint256[] memory tokenIds, uint256[] memory amounts) { - _mint(to, 3, quantity, ""); - _mint(to, 4, 1, ""); - - tokenIds = new uint256[](2); - amounts = new uint256[](2); - tokenIds[0] = 3; - tokenIds[1] = 4; - - amounts[0] = quantity; - amounts[1] = 1; - } - - function supportsInterface( - bytes4 interfaceId - ) public view virtual override(ERC1155, AccessControl, NFTLaunchpadCommon) returns (bool) { - return super.supportsInterface(interfaceId); - } -} diff --git a/test/foundry/SampleERC1155.t.sol b/test/foundry/SampleERC1155.t.sol new file mode 100644 index 0000000..e6a8564 --- /dev/null +++ b/test/foundry/SampleERC1155.t.sol @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.13; + +import "forge-std/Test.sol"; +import { Strings } from "@openzeppelin/contracts/utils/Strings.sol"; +import { SampleERC1155, ERC1155Common } from "../../src/mock/SampleERC1155.sol"; +import { IERC165 } from "@openzeppelin/contracts/interfaces/IERC165.sol"; +import { IERC1155 } from "@openzeppelin/contracts/interfaces/IERC1155.sol"; +import { IAccessControlEnumerable } from "@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol"; +import { IERC1155Common } from "src/interfaces/IERC1155Common.sol"; + +contract SampleERC1155Test is Test { + using Strings for uint256; + + string public constant NAME = "SampleERC1155"; + string public constant SYMBOL = "NFT1155"; + string public constant BASE_URI = "http://example.com/"; + address admin = makeAddr("admin"); + + ERC1155Common internal _t; + + function setUp() public virtual { + _t = new SampleERC1155(admin, NAME, SYMBOL, BASE_URI); + } + + function testName() public virtual { + assertEq(_token().name(), NAME); + } + + function testSymbol() public virtual { + assertEq(_token().symbol(), SYMBOL); + } + + function testURI(address _from) public virtual { + vm.assume(_from.code.length == 0 && _from != address(0)); + assertEq(_token().uri(uint256(50)), string(abi.encodePacked(BASE_URI, uint256(50).toString()))); + } + + function testMint() public virtual { + vm.startPrank(admin); + _token().mint(address(15), 15, 15, ""); + assertEq(_token().totalSupply(15), 15); + assertEq(_token().balanceOf(address(15), 15), 15); + + _token().mint(address(20), 15, 15, ""); + assertEq(_token().totalSupply(15), 30); + assertEq(_token().balanceOf(address(20), 15), 15); + vm.stopPrank(); + } + + function testSupportsInterface() public virtual { + assertEq(_token().supportsInterface(type(IERC1155).interfaceId), true); + assertEq(_token().supportsInterface(type(IAccessControlEnumerable).interfaceId), true); + assertEq(_token().supportsInterface(type(IERC1155Common).interfaceId), true); + assertEq(_token().supportsInterface(type(IERC165).interfaceId), true); + } + + function _token() internal view virtual returns (ERC1155Common) { + return _t; + } +} diff --git a/test/foundry/SampleERC1155Launchpad.t.sol b/test/foundry/SampleERC1155Launchpad.t.sol new file mode 100644 index 0000000..2f68425 --- /dev/null +++ b/test/foundry/SampleERC1155Launchpad.t.sol @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.13; + +import "forge-std/Test.sol"; +import { Strings } from "@openzeppelin/contracts/utils/Strings.sol"; +import { SampleERC1155Launchpad, SampleERC1155 } from "../../src/mock/launchpad/SampleERC1155Launchpad.sol"; +import { INFTLaunchpad } from "src/interfaces/launchpad/INFTLaunchpad.sol"; +import { IERC1155Common, IAccessControlEnumerable, IERC1155 } from "src/interfaces/IERC1155Common.sol"; + +contract SampleERC1155LaunchpadTest is Test { + using Strings for uint256; + + address admin = makeAddr("admin"); + string public constant NAME = "SampleERC721"; + string public constant SYMBOL = "NFT"; + string public constant BASE_URI = "http://example.com/"; + + SampleERC1155Launchpad internal _t; + + function setUp() public virtual { + _t = new SampleERC1155Launchpad(admin, NAME, SYMBOL, BASE_URI); + } + + function testSupportsInterface() public view { + assertEq(_token().supportsInterface(type(INFTLaunchpad).interfaceId), true); + assertEq(_token().supportsInterface(type(IERC1155Common).interfaceId), true); + assertEq(_token().supportsInterface(type(IAccessControlEnumerable).interfaceId), true); + assertEq(_token().supportsInterface(type(IERC1155).interfaceId), true); + } + + function _token() internal view virtual returns (SampleERC1155Launchpad) { + return _t; + } +} diff --git a/test/foundry/SampleERC1155Presale.t.sol b/test/foundry/SampleERC1155Presale.t.sol new file mode 100644 index 0000000..866febc --- /dev/null +++ b/test/foundry/SampleERC1155Presale.t.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.13; + +import { SampleERC1155, SampleERC1155Presale } from "../../src/mock/launchpad/SampleERC1155Presale.sol"; +import { Strings } from "@openzeppelin/contracts/utils/Strings.sol"; +import "forge-std/Test.sol"; + +import { IAccessControlEnumerable, IERC1155, IERC1155Common } from "src/interfaces/IERC1155Common.sol"; +import { INFTPresale } from "src/interfaces/launchpad/INFTPresale.sol"; + +contract SampleERC1155PresaleTest is Test { + using Strings for uint256; + + address admin = makeAddr("admin"); + string public constant NAME = "SampleERC721"; + string public constant SYMBOL = "NFT"; + string public constant BASE_URI = "http://example.com/"; + + SampleERC1155Presale internal _t; + + function setUp() public virtual { + _t = new SampleERC1155Presale(admin, NAME, SYMBOL, BASE_URI); + } + + function testSupportsInterface() public view { + assertEq(_token().supportsInterface(type(INFTPresale).interfaceId), true); + assertEq(_token().supportsInterface(type(IERC1155Common).interfaceId), true); + assertEq(_token().supportsInterface(type(IAccessControlEnumerable).interfaceId), true); + assertEq(_token().supportsInterface(type(IERC1155).interfaceId), true); + } + + function _token() internal view virtual returns (SampleERC1155Presale) { + return _t; + } +} diff --git a/test/foundry/SampleERC721Launchpad.t.sol b/test/foundry/SampleERC721Launchpad.t.sol new file mode 100644 index 0000000..7ed3cc4 --- /dev/null +++ b/test/foundry/SampleERC721Launchpad.t.sol @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.13; + +import "forge-std/Test.sol"; +import { Strings } from "@openzeppelin/contracts/utils/Strings.sol"; +import { SampleERC721Launchpad } from "../../src/mock/launchpad/SampleERC721Launchpad.sol"; +import { INFTLaunchpad } from "src/interfaces/launchpad/INFTLaunchpad.sol"; +import { IERC721Common } from "src/interfaces/IERC721Common.sol"; + +contract SampleERC721LaunchpadTest is Test { + using Strings for uint256; + + string public constant NAME = "SampleERC721"; + string public constant SYMBOL = "NFT"; + string public constant BASE_URI = "http://example.com/"; + + SampleERC721Launchpad internal _t; + + function setUp() public virtual { + _t = new SampleERC721Launchpad(NAME, SYMBOL, BASE_URI); + } + + function testSupportInterface() public view { + assertEq(_token().supportsInterface(type(INFTLaunchpad).interfaceId), true); + assertEq(_token().supportsInterface(type(IERC721Common).interfaceId), true); + } + + function _token() internal view virtual returns (SampleERC721Launchpad) { + return _t; + } +} diff --git a/test/foundry/SampleERC721Presale.t.sol b/test/foundry/SampleERC721Presale.t.sol new file mode 100644 index 0000000..9ab4961 --- /dev/null +++ b/test/foundry/SampleERC721Presale.t.sol @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.13; + +import { SampleERC721Presale } from "../../src/mock/launchpad/SampleERC721Presale.sol"; +import { Strings } from "@openzeppelin/contracts/utils/Strings.sol"; +import "forge-std/Test.sol"; + +import { IERC721Common } from "src/interfaces/IERC721Common.sol"; +import { INFTPresale } from "src/interfaces/launchpad/INFTPresale.sol"; + +contract SampleERC721PresaleTest is Test { + using Strings for uint256; + + string public constant NAME = "SampleERC721"; + string public constant SYMBOL = "NFT"; + string public constant BASE_URI = "http://example.com/"; + + SampleERC721Presale internal _t; + + function setUp() public virtual { + _t = new SampleERC721Presale(NAME, SYMBOL, BASE_URI); + } + + function testSupportInterface() public view { + assertEq(_token().supportsInterface(type(INFTPresale).interfaceId), true); + assertEq(_token().supportsInterface(type(IERC721Common).interfaceId), true); + } + + function _token() internal view virtual returns (SampleERC721Presale) { + return _t; + } +}