Skip to content

Commit

Permalink
Merge pull request #26 from axieinfinity/release/v0.2.0
Browse files Browse the repository at this point in the history
feat: add ERC1155Common, support launchpad/presale and adapt OZ v5.
huyhuynh3103 authored Dec 29, 2024
2 parents fa36abc + c8d186c commit 2027c61
Showing 34 changed files with 500 additions and 259 deletions.
7 changes: 6 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -7,12 +7,16 @@ on:
- dev
- "feature/*"
- "features/*"
- "feature/*"
- "features/*"
pull_request:
branches:
- main
- dev
- "feature/*"
- "features/*"
- "feature/*"
- "features/*"

env:
FOUNDRY_PROFILE: ci
@@ -24,6 +28,7 @@ jobs:

name: Foundry project
runs-on: ubuntu-latest
runs-on: ubuntu-latest
steps:
- uses: actions/[email protected]
with:
@@ -36,7 +41,7 @@ jobs:

- name: Install dependencies
run: |
forge install
forge soldeer update
id: install

- name: Run Forge build
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -13,3 +13,5 @@ artifacts/
typechain-types/
.idea
.env

dependencies
12 changes: 0 additions & 12 deletions .gitmodules

This file was deleted.

32 changes: 31 additions & 1 deletion foundry.toml
Original file line number Diff line number Diff line change
@@ -11,6 +11,36 @@ extra_output = ["devdoc", "userdoc", "storagelayout"]
fs_permissions = [{ access = "read-write", path = "./" }]

[fmt]
tab_width = 2
line_length = 120
tab_width = 2
bracket_spacing = true
multiline_func_header = 'params_first'
single_line_statement_blocks = 'single'
sort_imports = true
number_underscore = "thousands"
wrap_comments = true

[dependencies]
"openzeppelin" = { version = "5.0.2", url = "https://github.com/OpenZeppelin/openzeppelin-contracts/archive/refs/tags/v5.0.2.zip" }
"openzeppelin-upgradeable" = { version = "5.0.2", url = "https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/archive/refs/tags/v5.0.2.zip" }
forge-std = { version = "1.9.3", url = "https://github.com/foundry-rs/forge-std/archive/refs/tags/v1.9.3.zip" }

[soldeer]
# whether soldeer manages remappings
remappings_generate = false

# whether soldeer re-generates all remappings when installing, updating or uninstalling deps
remappings_regenerate = false

# whether to suffix the remapping with the version: `name-a.b.c`
remappings_version = true

# a prefix to add to the remappings ("@" would give `@name`)
remappings_prefix = "@"

# where to store the remappings ("txt" for `remappings.txt` or "config" for `foundry.toml`)
# ignored when `soldeer.toml` is used as config (uses `remappings.txt`)
remappings_location = "txt"

# whether to install sub-dependencies or not. If true this wil install the dependencies of dependencies 1 level down.
recursive_deps = true
1 change: 0 additions & 1 deletion lib/forge-std
Submodule forge-std deleted from fc560f
1 change: 0 additions & 1 deletion lib/openzeppelin-contracts
Submodule openzeppelin-contracts deleted from d00ace
1 change: 0 additions & 1 deletion lib/openzeppelin-contracts-upgradeable
Submodule openzeppelin-contracts-upgradeable deleted from a40cb0
7 changes: 3 additions & 4 deletions remappings.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
forge-std/=lib/forge-std/src/
ds-test/=lib/forge-std/lib/ds-test/src/
@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/
@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts
forge-std/=dependencies/forge-std-1.9.3/src/
@openzeppelin/contracts/=dependencies/openzeppelin-5.0.2/contracts/
@openzeppelin/contracts-upgradeable/=dependencies/openzeppelin-upgradeable-5.0.2/contracts/
27 changes: 27 additions & 0 deletions soldeer.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
[[dependencies]]
name = "contract-template"
version = "0.1.0"
source = "https://github.com/axieinfinity/contract-template/archive/refs/tags/release-v0.1.0.zip"
checksum = "56676e92b8825974abab8e381a98d0cc55da7057a18b3d325a13def760fa69d3"
integrity = "9fda9db2e8c24bb37378b1a14f41e1338967d101282bcdc0df9e98d7cf0edcda"

[[dependencies]]
name = "forge-std"
version = "1.9.3"
source = "https://github.com/foundry-rs/forge-std/archive/refs/tags/v1.9.3.zip"
checksum = "cc61148ae1a47f2415956a95ada670501b10ebd7f65cc00eda6ea7025770f42b"
integrity = "d53734fbd7201cd9e44de730ae045ed8958dd2c7b9493c30b322f6e6c21ca8b2"

[[dependencies]]
name = "openzeppelin"
version = "5.0.2"
source = "https://github.com/OpenZeppelin/openzeppelin-contracts/archive/refs/tags/v5.0.2.zip"
checksum = "ca49e0776066328da0087977864dfaef0d5e54a0ea9859236a7cd9ad02abb9e5"
integrity = "6f8fc028520b958667ef1e96460c64140f42fef60ff02bc63110780c557b7c7e"

[[dependencies]]
name = "openzeppelin-upgradeable"
version = "5.0.2"
source = "https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/archive/refs/tags/v5.0.2.zip"
checksum = "4790d4f592cb46c868916ea50613997df1e28fd42b4d32e0999f0a4b9d1a7cf8"
integrity = "085dfc37ec3b96f0ea95ae99d8c044b0b407eab88a78d7cb552284bccf1130ba"
56 changes: 28 additions & 28 deletions src/ERC1155Common.sol
Original file line number Diff line number Diff line change
@@ -2,15 +2,15 @@
// 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 { AccessControlEnumerable } from "@openzeppelin/contracts/access/AccessControlEnumerable.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";
import { IERC1155Common } from "./interfaces/IERC1155Common.sol";

contract ERC1155Common is
ERC1155,
@@ -44,7 +44,9 @@ contract ERC1155Common is
* Requirements:
* - the caller must have the `URI_SETTER_ROLE`.
*/
function setURI(string memory newURI) external onlyRole(URI_SETTER_ROLE) {
function setURI(
string memory newURI
) external onlyRole(URI_SETTER_ROLE) {
_setURI(newURI);
}

@@ -72,11 +74,12 @@ contract ERC1155Common is
}

/// @inheritdoc IERC1155Common
function mintBatch(address to, uint256[] calldata ids, uint256[] calldata amounts, bytes calldata data)
public
virtual
onlyRole(MINTER_ROLE)
{
function mintBatch(
address to,
uint256[] calldata ids,
uint256[] calldata amounts,
bytes calldata data
) public virtual onlyRole(MINTER_ROLE) {
_mintBatch(to, ids, amounts, data);
}

@@ -85,11 +88,12 @@ contract ERC1155Common is
* 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)
{
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");

@@ -101,7 +105,9 @@ contract ERC1155Common is
/**
* @dev See {ERC1155-uri}.
*/
function uri(uint256 tokenId) public view virtual override returns (string memory) {
function uri(
uint256 tokenId
) public view virtual override returns (string memory) {
string memory uri_ = super.uri(tokenId);
return string.concat(uri_, tokenId.toString());
}
@@ -119,27 +125,21 @@ contract ERC1155Common is
/**
* @dev See {ERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId)
public
view
virtual
override(IERC165, ERC1155, AccessControlEnumerable)
returns (bool)
{
function supportsInterface(
bytes4 interfaceId
) public view virtual override(IERC165, ERC1155, AccessControlEnumerable) returns (bool) {
return interfaceId == type(IERC1155Common).interfaceId || super.supportsInterface(interfaceId);
}

/**
* @dev See {ERC1155-_beforeTokenTransfer}.
* @dev See {ERC1155-_update}.
*/
function _beforeTokenTransfer(
address operator,
function _update(
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) internal virtual override(ERC1155, ERC1155Pausable, ERC1155Supply) {
super._beforeTokenTransfer(operator, from, to, ids, amounts, data);
uint256[] memory values
) internal virtual override(ERC1155, ERC1155Supply, ERC1155Pausable) {
super._update(from, to, ids, values);
}
}
75 changes: 41 additions & 34 deletions src/ERC721Common.sol
Original file line number Diff line number Diff line change
@@ -1,20 +1,24 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

import "./interfaces/IERC721State.sol";
import "./interfaces/IERC721Common.sol";
import "./refs/ERC721Nonce.sol";
import "./ERC721PresetMinterPauserAutoIdCustomized.sol";
import { ERC721PresetMinterPauserAutoIdCustomized } from "./ERC721PresetMinterPauserAutoIdCustomized.sol";
import { IERC721Common } from "./interfaces/IERC721Common.sol";
import { IERC721State } from "./interfaces/IERC721State.sol";
import { ERC721Nonce } from "./refs/ERC721Nonce.sol";
import { ERC721 } from "@openzeppelin/contracts/token/ERC721/ERC721.sol";

contract ERC721Common is ERC721Nonce, ERC721PresetMinterPauserAutoIdCustomized, IERC721State, IERC721Common {
constructor(string memory name, string memory symbol, string memory baseTokenURI)
ERC721PresetMinterPauserAutoIdCustomized(name, symbol, baseTokenURI)
{ }
constructor(
string memory name,
string memory symbol,
string memory baseTokenURI
) ERC721PresetMinterPauserAutoIdCustomized(name, symbol, baseTokenURI) { }

/// @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);
function stateOf(
uint256 tokenId
) external view virtual override returns (bytes memory) {
return abi.encodePacked(ownerOf(tokenId), nonces[tokenId], tokenId);
}

/**
@@ -33,26 +37,32 @@ contract ERC721Common is ERC721Nonce, ERC721PresetMinterPauserAutoIdCustomized,
/**
* @dev Override `IERC165-supportsInterface`.
*/
function supportsInterface(bytes4 interfaceId)
public
view
virtual
override(ERC721, ERC721PresetMinterPauserAutoIdCustomized)
returns (bool)
{
function supportsInterface(
bytes4 interfaceId
) public view virtual override(ERC721, ERC721PresetMinterPauserAutoIdCustomized) returns (bool) {
return interfaceId == type(IERC721Common).interfaceId || interfaceId == type(IERC721State).interfaceId
|| super.supportsInterface(interfaceId);
}

/**
* @dev Override `ERC721PresetMinterPauserAutoIdCustomized-_beforeTokenTransfer`.
* @dev Override `ERC721PresetMinterPauserAutoIdCustomized-_update`.
*/
function _beforeTokenTransfer(address _from, address _to, uint256 _firstTokenId, uint256 _batchSize)
internal
virtual
override(ERC721Nonce, ERC721PresetMinterPauserAutoIdCustomized)
{
super._beforeTokenTransfer(_from, _to, _firstTokenId, _batchSize);
function _update(
address to,
uint256 tokenId,
address auth
) internal virtual override(ERC721Nonce, ERC721PresetMinterPauserAutoIdCustomized) returns (address from) {
return super._update(to, tokenId, auth);
}

/**
* @dev See {ERC721-_increaseBalance}.
*/
function _increaseBalance(
address account,
uint128 amount
) internal virtual override(ERC721, ERC721PresetMinterPauserAutoIdCustomized) {
super._increaseBalance(account, amount);
}

/**
@@ -66,17 +76,14 @@ contract ERC721Common is ERC721Nonce, ERC721PresetMinterPauserAutoIdCustomized,
*
* - 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);
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]);
for (uint256 i; i < recipients.length; i++) {
tokenIds[i] = _mintFor(recipients[i]);
}
}
}
72 changes: 39 additions & 33 deletions src/ERC721PresetMinterPauserAutoIdCustomized.sol
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Burnable.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Pausable.sol";
import "@openzeppelin/contracts/access/AccessControlEnumerable.sol";
import "@openzeppelin/contracts/utils/Context.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
import "./interfaces/IERC721PresetMinterPauserAutoIdCustomized.sol";
import { IERC721PresetMinterPauserAutoIdCustomized } from "./interfaces/IERC721PresetMinterPauserAutoIdCustomized.sol";
import { AccessControlEnumerable } from "@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol";
import { ERC721 } from "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import { ERC721Burnable } from "@openzeppelin/contracts/token/ERC721/extensions/ERC721Burnable.sol";
import { ERC721Enumerable } from "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
import { ERC721Pausable } from "@openzeppelin/contracts/token/ERC721/extensions/ERC721Pausable.sol";
import { Context } from "@openzeppelin/contracts/utils/Context.sol";

/**
* @dev ERC721PresetMinterPauserAutoId is a customized version of
@@ -22,12 +21,10 @@ contract ERC721PresetMinterPauserAutoIdCustomized is
ERC721Burnable,
ERC721Pausable
{
using Counters for Counters.Counter;

bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE");

Counters.Counter internal _tokenIdTracker;
uint256 internal _tokenIdTracker;

string internal _baseTokenURI;

@@ -41,15 +38,17 @@ contract ERC721PresetMinterPauserAutoIdCustomized is
constructor(string memory name, string memory symbol, string memory baseTokenURI) ERC721(name, symbol) {
_baseTokenURI = baseTokenURI;

_setupRole(DEFAULT_ADMIN_ROLE, _msgSender());
_setupRole(MINTER_ROLE, _msgSender());
_setupRole(PAUSER_ROLE, _msgSender());
_grantRole(DEFAULT_ADMIN_ROLE, _msgSender());
_grantRole(MINTER_ROLE, _msgSender());
_grantRole(PAUSER_ROLE, _msgSender());

// Token id should start from 1.
_tokenIdTracker.increment();
++_tokenIdTracker;
}

function setBaseURI(string memory baseTokenURI) external onlyRole(DEFAULT_ADMIN_ROLE) {
function setBaseURI(
string memory baseTokenURI
) external onlyRole(DEFAULT_ADMIN_ROLE) {
_baseTokenURI = baseTokenURI;
}

@@ -68,7 +67,9 @@ contract ERC721PresetMinterPauserAutoIdCustomized is
*
* - the caller must have the `MINTER_ROLE`.
*/
function mint(address to) public virtual returns (uint256 _tokenId) {
function mint(
address to
) public virtual returns (uint256 _tokenId) {
require(hasRole(MINTER_ROLE, _msgSender()), "ERC721PresetMinterPauserAutoId: must have minter role to mint");
return _mintFor(to);
}
@@ -101,24 +102,27 @@ contract ERC721PresetMinterPauserAutoIdCustomized is
_unpause();
}

function _beforeTokenTransfer(address from, address to, uint256 firstTokenId, uint256 batchSize)
internal
virtual
override(ERC721, ERC721Enumerable, ERC721Pausable)
{
super._beforeTokenTransfer(from, to, firstTokenId, batchSize);
function _update(
address to,
uint256 tokenId,
address auth
) internal virtual override(ERC721, ERC721Pausable, ERC721Enumerable) returns (address from) {
return super._update(to, tokenId, auth);
}

/**
* @dev See {ERC721-_increaseBalance}.
*/
function _increaseBalance(address account, uint128 amount) internal virtual override(ERC721, ERC721Enumerable) {
super._increaseBalance(account, amount);
}

/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId)
public
view
virtual
override(AccessControlEnumerable, ERC721, ERC721Enumerable)
returns (bool)
{
function supportsInterface(
bytes4 interfaceId
) public view virtual override(AccessControlEnumerable, ERC721, ERC721Enumerable) returns (bool) {
return
interfaceId == type(IERC721PresetMinterPauserAutoIdCustomized).interfaceId || super.supportsInterface(interfaceId);
}
@@ -129,11 +133,13 @@ contract ERC721PresetMinterPauserAutoIdCustomized is
* See {ERC721-_mint}.
*
*/
function _mintFor(address to) internal virtual returns (uint256 _tokenId) {
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();
_tokenId = _tokenIdTracker;
_mint(to, _tokenId);
_tokenIdTracker.increment();
++_tokenIdTracker;
}
}
2 changes: 1 addition & 1 deletion src/interfaces/IERC1155Common.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

import { IAccessControlEnumerable } from "@openzeppelin/contracts/access/IAccessControlEnumerable.sol";
import { IAccessControlEnumerable } from "@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol";
import { IERC1155 } from "@openzeppelin/contracts/token/ERC1155/IERC1155.sol";

interface IERC1155Common is IAccessControlEnumerable, IERC1155 {
4 changes: 3 additions & 1 deletion src/interfaces/IERC721Common.sol
Original file line number Diff line number Diff line change
@@ -13,5 +13,7 @@ interface IERC721Common {
*
* - the caller must have the `MINTER_ROLE`.
*/
function bulkMint(address[] calldata recipients) external returns (uint256[] memory tokenIds);
function bulkMint(
address[] calldata recipients
) external returns (uint256[] memory tokenIds);
}
4 changes: 3 additions & 1 deletion src/interfaces/IERC721PresetMinterPauserAutoIdCustomized.sol
Original file line number Diff line number Diff line change
@@ -13,7 +13,9 @@ interface IERC721PresetMinterPauserAutoIdCustomized {
*
* - the caller must have the `MINTER_ROLE`.
*/
function mint(address to) external returns (uint256 tokenId);
function mint(
address to
) external returns (uint256 tokenId);

/**
* @dev Pauses all token transfers.
9 changes: 6 additions & 3 deletions src/interfaces/IERC721State.sol
Original file line number Diff line number Diff line change
@@ -10,7 +10,8 @@ interface IERC721State {
* - The token exists.
*
* @notice The token state presents the properties of a token at a certain point in time, it should be unique.
* The token state helps other contracts can verify the token properties without getting and selecting properties from the base contract.
* The token state helps other contracts can verify the token properties without getting and selecting properties from
* the base contract.
*
* For example:
*
@@ -22,10 +23,12 @@ interface IERC721State {
* }
*
* interface Exchange {
* // Buy NFT with the specificed state of `_tokenId`.
* // Buy NFT with the specified state of `_tokenId`.
* function buy(uint256 _tokenId, uint256 _price, bytes calldata _kittyState) external;
* }
* ```
*/
function stateOf(uint256 _tokenId) external view returns (bytes memory);
function stateOf(
uint256 _tokenId
) external view returns (bytes memory);
}
8 changes: 5 additions & 3 deletions src/interfaces/launchpad/INFTLaunchpad.sol
Original file line number Diff line number Diff line change
@@ -24,7 +24,9 @@ interface INFTLaunchpad {
* @return mintedTokenIds The token IDs of the minted NFTs.
* @return mintedAmounts The minted amounts according to the `mintedTokenIds`.
*/
function mintLaunchpad(address to, uint256 quantity, bytes calldata extraData)
external
returns (uint256[] memory mintedTokenIds, uint256[] memory mintedAmounts);
function mintLaunchpad(
address to,
uint256 quantity,
bytes calldata extraData
) external returns (uint256[] memory mintedTokenIds, uint256[] memory mintedAmounts);
}
10 changes: 6 additions & 4 deletions src/mock/SampleERC721.sol
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

import "../ERC721Common.sol";
import { ERC721Common } from "../ERC721Common.sol";

contract SampleERC721 is ERC721Common {
constructor(string memory name, string memory symbol, string memory baseTokenURI)
ERC721Common(name, symbol, baseTokenURI)
{ }
constructor(
string memory name_,
string memory symbol_,
string memory baseTokenURI
) ERC721Common(name_, symbol_, baseTokenURI) { }
}
2 changes: 1 addition & 1 deletion src/mock/SampleERC721Upgradeable.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

import "../upgradeable/ERC721CommonUpgradeable.sol";
import { ERC721CommonUpgradeable } from "../upgradeable/ERC721CommonUpgradeable.sol";

contract SampleERC721Upgradeable is ERC721CommonUpgradeable { }
Original file line number Diff line number Diff line change
@@ -4,17 +4,17 @@ pragma solidity ^0.8.19;
import { NFTLaunchpadCommon } from "../../launchpad/NFTLaunchpadCommon.sol";
import { SampleERC1155, ERC1155Common } from "../SampleERC1155.sol";

contract SampleNFT1155Launchpad is SampleERC1155, NFTLaunchpadCommon {
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)
{
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, "");

38 changes: 38 additions & 0 deletions src/mock/launchpad/SampleERC1155Presale.sol
Original file line number Diff line number Diff line change
@@ -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);
}
}
Original file line number Diff line number Diff line change
@@ -3,19 +3,19 @@ pragma solidity ^0.8.19;

import { SampleERC721 } from "../SampleERC721.sol";

import { SampleERC721 } from "../SampleERC721.sol";
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.
function mintLaunchpad(address to, uint256 quantity, bytes calldata /* extraData */ )
external
onlyRole(MINTER_ROLE)
returns (uint256[] memory tokenIds, uint256[] memory amounts)
{
function mintLaunchpad(
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) {
32 changes: 32 additions & 0 deletions src/mock/launchpad/SampleERC721Presale.sol
Original file line number Diff line number Diff line change
@@ -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);
}
}
18 changes: 6 additions & 12 deletions src/refs/ERC721Nonce.sol
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import { ERC721 } from "@openzeppelin/contracts/token/ERC721/ERC721.sol";

/**
* @title ERC721Nonce
* @dev This contract provides a nonce that will be increased whenever the token is tranferred.
* @dev This contract provides a nonce that will be increased whenever the token is transferred.
*/
abstract contract ERC721Nonce is ERC721 {
/// @dev Emitted when the token nonce is updated
@@ -21,16 +21,10 @@ abstract contract ERC721Nonce is ERC721 {
uint256[50] private ______gap;

/**
* @dev Override `ERC721-_beforeTokenTransfer`.
* @dev Override `ERC721-_update`.
*/
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);
function _update(address to, uint256 tokenId, address auth) internal virtual override returns (address) {
emit NonceUpdated(tokenId, ++nonces[tokenId]);
return super._update(to, tokenId, auth);
}
}
53 changes: 32 additions & 21 deletions src/upgradeable/ERC721CommonUpgradeable.sol
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.19;

import { ERC721Upgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol";
import { IERC721State } from "../interfaces/IERC721State.sol";
import { IERC721Common } from "../interfaces/IERC721Common.sol";
import { ERC721NonceUpgradeable } from "./refs/ERC721NonceUpgradeable.sol";
import { IERC721State } from "../interfaces/IERC721State.sol";

import { ERC721PresetMinterPauserAutoIdCustomizedUpgradeable } from
"./ERC721PresetMinterPauserAutoIdCustomizedUpgradeable.sol";
import { ERC721NonceUpgradeable } from "./refs/ERC721NonceUpgradeable.sol";
import { ERC721Upgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol";

abstract contract ERC721CommonUpgradeable is
ERC721NonceUpgradeable,
@@ -29,18 +30,17 @@ abstract contract ERC721CommonUpgradeable is
}

/// @inheritdoc IERC721State
function stateOf(uint256 tokenId) external view virtual override returns (bytes memory) {
if (!_exists(tokenId)) revert ErrNonExistentToken();
function stateOf(
uint256 tokenId
) external view virtual override returns (bytes memory) {
_requireOwned(tokenId);
return abi.encodePacked(ownerOf(tokenId), nonces(tokenId), tokenId);
}

/// @inheritdoc IERC721Common
function bulkMint(address[] calldata recipients)
external
virtual
onlyRole(MINTER_ROLE)
returns (uint256[] memory tokenIds)
{
function bulkMint(
address[] calldata recipients
) external virtual onlyRole(MINTER_ROLE) returns (uint256[] memory tokenIds) {
uint256 length = recipients.length;
if (length == 0) revert ErrInvalidArrayLength();
tokenIds = new uint256[](length);
@@ -53,13 +53,9 @@ abstract contract ERC721CommonUpgradeable is
/**
* @dev Override `IERC165-supportsInterface`.
*/
function supportsInterface(bytes4 interfaceId)
public
view
virtual
override(ERC721Upgradeable, ERC721PresetMinterPauserAutoIdCustomizedUpgradeable)
returns (bool)
{
function supportsInterface(
bytes4 interfaceId
) public view virtual override(ERC721Upgradeable, ERC721PresetMinterPauserAutoIdCustomizedUpgradeable) returns (bool) {
return interfaceId == type(IERC721State).interfaceId || interfaceId == type(IERC721Common).interfaceId
|| super.supportsInterface(interfaceId);
}
@@ -78,13 +74,28 @@ abstract contract ERC721CommonUpgradeable is
}

/**
* @dev Override `ERC721PresetMinterPauserAutoIdCustomizedUpgradeable-_beforeTokenTransfer`.
* @dev Override `ERC721PresetMinterPauserAutoIdCustomizedUpgradeable-_update`.
*/
function _beforeTokenTransfer(address from, address to, uint256 firstTokenId, uint256 batchSize)
function _update(
address to,
uint256 tokenId,
address auth
)
internal
virtual
override(ERC721NonceUpgradeable, ERC721PresetMinterPauserAutoIdCustomizedUpgradeable)
returns (address from)
{
super._beforeTokenTransfer(from, to, firstTokenId, batchSize);
return super._update(to, tokenId, auth);
}

/**
* @dev See {ERC721Upgradeable-_increaseBalance}.
*/
function _increaseBalance(
address account,
uint128 amount
) internal virtual override(ERC721Upgradeable, ERC721PresetMinterPauserAutoIdCustomizedUpgradeable) {
super._increaseBalance(account, amount);
}
}
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import { IERC721PresetMinterPauserAutoIdCustomized } from "../interfaces/IERC721PresetMinterPauserAutoIdCustomized.sol";
import { AccessControlEnumerableUpgradeable } from
"@openzeppelin/contracts-upgradeable/access/extensions/AccessControlEnumerableUpgradeable.sol";
import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import { ERC721Upgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol";
import { ERC721EnumerableUpgradeable } from
"@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721EnumerableUpgradeable.sol";
import { ERC721BurnableUpgradeable } from
"@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721BurnableUpgradeable.sol";
import { ERC721EnumerableUpgradeable } from
"@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721EnumerableUpgradeable.sol";
import { ERC721PausableUpgradeable } from
"@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721PausableUpgradeable.sol";
import { AccessControlEnumerableUpgradeable } from
"@openzeppelin/contracts-upgradeable/access/AccessControlEnumerableUpgradeable.sol";
import { ContextUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol";
import { CountersUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/CountersUpgradeable.sol";
import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import { IERC721PresetMinterPauserAutoIdCustomized } from "../interfaces/IERC721PresetMinterPauserAutoIdCustomized.sol";

/**
* @dev ERC721PresetMinterPauserAutoIdCustomizedUpgradeable is a customized version of
* openzeppelin-contracts-upgradeable/contracts/token/ERC721/presets/ERC721PresetMinterPauserAutoIdUpgradeable.sol to change the private counter and
* openzeppelin-contracts-upgradeable/contracts/token/ERC721/presets/ERC721PresetMinterPauserAutoIdUpgradeable.sol to
* change the private counter and
* base token URI into internal, mainly to support the inherited contracts.
*/
contract ERC721PresetMinterPauserAutoIdCustomizedUpgradeable is
@@ -31,12 +31,10 @@ contract ERC721PresetMinterPauserAutoIdCustomizedUpgradeable is
{
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;
uint256 private _tokenIdTracker;

string private _baseTokenURI;

@@ -57,31 +55,35 @@ contract ERC721PresetMinterPauserAutoIdCustomizedUpgradeable is
* 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
{
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
{
function __ERC721PresetMinterPauserAutoId_init_unchained(
string memory,
string memory,
string memory baseTokenURI
) internal onlyInitializing {
_baseTokenURI = baseTokenURI;

_setupRole(DEFAULT_ADMIN_ROLE, _msgSender());
_grantRole(DEFAULT_ADMIN_ROLE, _msgSender());

_setupRole(MINTER_ROLE, _msgSender());
_setupRole(PAUSER_ROLE, _msgSender());
_grantRole(MINTER_ROLE, _msgSender());
_grantRole(PAUSER_ROLE, _msgSender());

_tokenIdTracker.increment();
++_tokenIdTracker;
}

/// @inheritdoc IERC721PresetMinterPauserAutoIdCustomized
function mint(address to) public virtual returns (uint256 tokenId) {
function mint(
address to
) public virtual returns (uint256 tokenId) {
address sender = _msgSender();
if (!hasRole(MINTER_ROLE, sender)) revert ErrUnauthorizedAccount(sender, MINTER_ROLE);

@@ -107,7 +109,9 @@ contract ERC721PresetMinterPauserAutoIdCustomizedUpgradeable is
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId)
function supportsInterface(
bytes4 interfaceId
)
public
view
virtual
@@ -124,12 +128,14 @@ contract ERC721PresetMinterPauserAutoIdCustomizedUpgradeable is
* See {ERC721Upgradeable-_mint}.
*
*/
function _mintFor(address to) internal virtual returns (uint256 _tokenId) {
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();
tokenId = _tokenIdTracker;
_mint(to, tokenId);
++_tokenIdTracker;
}

/**
@@ -142,11 +148,29 @@ contract ERC721PresetMinterPauserAutoIdCustomizedUpgradeable is
return _baseTokenURI;
}

function _beforeTokenTransfer(address from, address to, uint256 firstTokenId, uint256 batchSize)
/**
* @dev See {ERC721Upgradeable-_update}.
*/
function _update(
address to,
uint256 tokenId,
address auth
)
internal
virtual
override(ERC721Upgradeable, ERC721EnumerableUpgradeable, ERC721PausableUpgradeable)
returns (address from)
{
super._beforeTokenTransfer(from, to, firstTokenId, batchSize);
return super._update(to, tokenId, auth);
}

/**
* @dev See {ERC721Upgradeable-_increaseBalance}.
*/
function _increaseBalance(
address account,
uint128 amount
) internal virtual override(ERC721Upgradeable, ERC721EnumerableUpgradeable) {
super._increaseBalance(account, amount);
}
}
22 changes: 8 additions & 14 deletions src/upgradeable/refs/ERC721NonceUpgradeable.sol
Original file line number Diff line number Diff line change
@@ -5,7 +5,7 @@ import { ERC721Upgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC

/**
* @title ERC721NonceUpgradeable
* @dev This contract provides a nonce that will be increased whenever the token is tranferred.
* @dev This contract provides a nonce that will be increased whenever the token is transferred.
*/
abstract contract ERC721NonceUpgradeable is ERC721Upgradeable {
/// @dev Emitted when the token nonce is updated
@@ -20,25 +20,19 @@ abstract contract ERC721NonceUpgradeable is ERC721Upgradeable {
*/
uint256[50] private __gap;

function nonces(uint256 tokenId) public view returns (uint256) {
function nonces(
uint256 tokenId
) public view returns (uint256) {
return _nonceOf[tokenId];
}

/**
* @dev Override `ERC721Upgradeable-_beforeTokenTransfer`.
* @dev Override `ERC721Upgradeable-_update`.
*/
function _beforeTokenTransfer(address from, address to, uint256 firstTokenId, uint256 batchSize)
internal
virtual
override
{
uint256 length = firstTokenId + batchSize;
function _update(address to, uint256 tokenId, address auth) internal virtual override returns (address from) {
unchecked {
for (uint256 tokenId = firstTokenId; tokenId < length; ++tokenId) {
emit NonceUpdated(tokenId, ++_nonceOf[tokenId]);
}

super._beforeTokenTransfer(from, to, firstTokenId, batchSize);
emit NonceUpdated(tokenId, ++_nonceOf[tokenId]);
return super._update(to, tokenId, auth);
}
}
}
2 changes: 1 addition & 1 deletion test/foundry/SampleERC1155.t.sol
Original file line number Diff line number Diff line change
@@ -6,7 +6,7 @@ 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/IAccessControlEnumerable.sol";
import { IAccessControlEnumerable } from "@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol";
import { IERC1155Common } from "src/interfaces/IERC1155Common.sol";

contract SampleERC1155Test is Test {
Original file line number Diff line number Diff line change
@@ -3,7 +3,7 @@ pragma solidity ^0.8.13;

import "forge-std/Test.sol";
import { Strings } from "@openzeppelin/contracts/utils/Strings.sol";
import { SampleNFT1155Launchpad, SampleERC1155 } from "../../src/mock/launchpad/SampleNFT1155Launchpad.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";

@@ -15,20 +15,20 @@ contract SampleERC1155LaunchpadTest is Test {
string public constant SYMBOL = "NFT";
string public constant BASE_URI = "http://example.com/";

SampleNFT1155Launchpad internal _t;
SampleERC1155Launchpad internal _t;

function setUp() public virtual {
_t = new SampleNFT1155Launchpad(admin, NAME, SYMBOL, BASE_URI);
_t = new SampleERC1155Launchpad(admin, NAME, SYMBOL, BASE_URI);
}

function testSupportsInterface() public {
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 (SampleNFT1155Launchpad) {
function _token() internal view virtual returns (SampleERC1155Launchpad) {
return _t;
}
}
35 changes: 35 additions & 0 deletions test/foundry/SampleERC1155Presale.t.sol
Original file line number Diff line number Diff line change
@@ -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;
}
}
15 changes: 10 additions & 5 deletions test/foundry/SampleERC721.t.sol
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

import "forge-std/Test.sol";
import { ERC721Common, SampleERC721 } from "../../src/mock/SampleERC721.sol";
import { ERC721Nonce } from "../../src/refs/ERC721Nonce.sol";
import { Strings } from "@openzeppelin/contracts/utils/Strings.sol";
import { SampleERC721, ERC721Common } from "../../src/mock/SampleERC721.sol";
import "forge-std/Test.sol";

import { IERC721Common } from "src/interfaces/IERC721Common.sol";
import { IERC721PresetMinterPauserAutoIdCustomized } from "src/interfaces/IERC721PresetMinterPauserAutoIdCustomized.sol";
import { IERC721State } from "src/interfaces/IERC721State.sol";
@@ -37,7 +38,9 @@ contract SampleERC721Test is Test {
assertNotEq(_tokenId, 0);
}

function testTokenURI(address _from) public virtual {
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())));
@@ -72,13 +75,15 @@ contract SampleERC721Test is Test {
assertNotEq(_state0, _state1);
}

function testSupportInterface() public {
function testSupportInterface() public view {
assertEq(_token().supportsInterface(type(IERC721State).interfaceId), true);
assertEq(_token().supportsInterface(type(IERC721PresetMinterPauserAutoIdCustomized).interfaceId), true);
assertEq(_token().supportsInterface(type(IERC721Common).interfaceId), true);
}

function _mint(address _user) internal virtual returns (uint256 _tokenId, uint256 _nonce) {
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);
Original file line number Diff line number Diff line change
@@ -3,29 +3,29 @@ pragma solidity ^0.8.13;

import "forge-std/Test.sol";
import { Strings } from "@openzeppelin/contracts/utils/Strings.sol";
import { SampleNFT721Launchpad } from "../../src/mock/launchpad/SampleNFT721Launchpad.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 SampleNFT721LaunchpadTest is Test {
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/";

SampleNFT721Launchpad internal _t;
SampleERC721Launchpad internal _t;

function setUp() public virtual {
_t = new SampleNFT721Launchpad(NAME, SYMBOL, BASE_URI);
_t = new SampleERC721Launchpad(NAME, SYMBOL, BASE_URI);
}

function testSupportInterface() public {
function testSupportInterface() public view {
assertEq(_token().supportsInterface(type(INFTLaunchpad).interfaceId), true);
assertEq(_token().supportsInterface(type(IERC721Common).interfaceId), true);
}

function _token() internal view virtual returns (SampleNFT721Launchpad) {
function _token() internal view virtual returns (SampleERC721Launchpad) {
return _t;
}
}
32 changes: 32 additions & 0 deletions test/foundry/SampleERC721Presale.t.sol
Original file line number Diff line number Diff line change
@@ -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;
}
}
46 changes: 25 additions & 21 deletions test/foundry/SampleERC721Upgradeable.t.sol
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
// 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 "@openzeppelin/contracts/utils/Strings.sol";
import { TransparentUpgradeableProxy } from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
import { IAccessControlEnumerable } from "@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol";

import { ProxyAdmin } from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol";
import { IERC721Upgradeable } from "@openzeppelin/contracts-upgradeable/interfaces/IERC721Upgradeable.sol";
import { IAccessControlEnumerableUpgradeable } from
"@openzeppelin/contracts-upgradeable/access/IAccessControlEnumerableUpgradeable.sol";
import { IERC721EnumerableUpgradeable } from
"@openzeppelin/contracts-upgradeable/interfaces/IERC721EnumerableUpgradeable.sol";
import {
SampleERC721Upgradeable,
ERC721CommonUpgradeable,
ERC721PresetMinterPauserAutoIdCustomizedUpgradeable
} from "src/mock/SampleERC721Upgradeable.sol";
import { TransparentUpgradeableProxy } from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
import { IERC721 } from "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import { IERC721Enumerable } from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol";

import { Strings } from "@openzeppelin/contracts/utils/Strings.sol";
import "forge-std/Test.sol";

import { IERC721Common } from "src/interfaces/IERC721Common.sol";
import { IERC721PresetMinterPauserAutoIdCustomized } from "src/interfaces/IERC721PresetMinterPauserAutoIdCustomized.sol";
import { IERC721State } from "src/interfaces/IERC721State.sol";
import { ERC721CommonUpgradeable, SampleERC721Upgradeable } from "src/mock/SampleERC721Upgradeable.sol";

import { ERC721PresetMinterPauserAutoIdCustomizedUpgradeable } from
"src/upgradeable/ERC721PresetMinterPauserAutoIdCustomizedUpgradeable.sol";
import { ERC721NonceUpgradeable } from "src/upgradeable/refs/ERC721NonceUpgradeable.sol";

contract SampleERC721Upgradeable_Test is Test {
using Strings for uint256;
@@ -34,7 +34,7 @@ contract SampleERC721Upgradeable_Test is Test {
ERC721CommonUpgradeable internal _testToken;

function setUp() public virtual {
_proxyAdmin = address(new ProxyAdmin());
_proxyAdmin = address(new ProxyAdmin(address(this)));

bytes memory initializeData =
abi.encodeCall(ERC721PresetMinterPauserAutoIdCustomizedUpgradeable.initialize, (NAME, SYMBOL, BASE_URI));
@@ -56,7 +56,9 @@ contract SampleERC721Upgradeable_Test is Test {
assertNotEq(tokenId, 0);
}

function testTokenURI(address from) public virtual {
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())));
@@ -91,16 +93,18 @@ contract SampleERC721Upgradeable_Test is Test {
assertNotEq(_state0, _state1);
}

function testSupportInterface() public {
assertEq(_token().supportsInterface(type(IERC721Upgradeable).interfaceId), true);
assertEq(_token().supportsInterface(type(IAccessControlEnumerableUpgradeable).interfaceId), true);
assertEq(_token().supportsInterface(type(IERC721EnumerableUpgradeable).interfaceId), true);
function testSupportInterface() public view {
assertEq(_token().supportsInterface(type(IERC721).interfaceId), true);
assertEq(_token().supportsInterface(type(IAccessControlEnumerable).interfaceId), true);
assertEq(_token().supportsInterface(type(IERC721Enumerable).interfaceId), true);
assertEq(_token().supportsInterface(type(IERC721State).interfaceId), true);
assertEq(_token().supportsInterface(type(IERC721PresetMinterPauserAutoIdCustomized).interfaceId), true);
assertEq(_token().supportsInterface(type(IERC721Common).interfaceId), true);
}

function _mint(address _user) internal virtual returns (uint256 tokenId, uint256 nonce) {
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);

0 comments on commit 2027c61

Please sign in to comment.