Skip to content

Commit

Permalink
feat: standardlize ERC1155Common contract, inspired by contract-template
Browse files Browse the repository at this point in the history
  • Loading branch information
huyhuynh3103 committed Nov 14, 2024
1 parent 345c4b9 commit 8935566
Show file tree
Hide file tree
Showing 4 changed files with 129 additions and 46 deletions.
133 changes: 97 additions & 36 deletions src/ERC1155Common.sol
Original file line number Diff line number Diff line change
@@ -1,80 +1,141 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
// SPDX-License-Identifier: MIT
// Compatible with OpenZeppelin Contracts ^5.0.0
pragma solidity ^0.8.20;

import { AccessControlEnumerable } from "@openzeppelin/contracts/access/AccessControlEnumerable.sol";
import { ERC1155 } from "@openzeppelin/contracts/token/ERC1155/ERC1155.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 { AccessControlEnumerable } from "@openzeppelin/contracts/access/AccessControlEnumerable.sol";
import { Strings } from "@openzeppelin/contracts/utils/Strings.sol";
import { IERC1155Common } from "./interfaces/IERC1155Common.sol";

contract ERC1155Common is AccessControlEnumerable, ERC1155, ERC1155Supply, IERC1155Common {
abstract 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(string memory name_, string memory symbol_, string memory baseTokenURI, address[] memory minters)
payable
ERC1155(baseTokenURI)
{
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_;
_grantRole(DEFAULT_ADMIN_ROLE, _msgSender());
bytes32 minterRole = MINTER_ROLE;

uint256 length = minters.length;
for (uint256 i; i < length;) {
_grantRole(minterRole, minters[i]);
unchecked {
++i;
}
}
}

function uri(uint256 tokenId) public view override returns (string memory) {
string memory _uri = super.uri(tokenId);
return string(abi.encodePacked(_uri, tokenId.toString()));
}

function name() external view returns (string memory) {
return _name;
/**
* @dev Set the URI for all token types.
* Requirements:
* - the caller must have the `URI_SETTER_ROLE`.
*/
function setURI(string memory newURI) public onlyRole(URI_SETTER_ROLE) {
_setURI(newURI);
}

function symbol() external view returns (string memory) {
return _symbol;
/**
* @dev Pauses all token transfers.
* Requirements:
* - the caller must have the `PAUSER_ROLE`.
*/
function pause() public onlyRole(PAUSER_ROLE) {
_pause();
}

/**
* @dev Sets the base URI for metadata of ERC1155 tokens.
* @param uri_ The new base URI.
* @dev Unpauses all token transfers.
* Requirements:
* - the caller must have the `PAUSER_ROLE`.
*/
function setURI(string calldata uri_) external onlyRole(DEFAULT_ADMIN_ROLE) {
_setURI(uri_);
function unpause() public onlyRole(PAUSER_ROLE) {
_unpause();
}

/// @inheritdoc IERC1155Common
function mint(address to, uint256 id, uint256 amount) external onlyRole(MINTER_ROLE) {
_mint(to, id, amount, "");
function mint(address account, uint256 id, uint256 amount, bytes calldata data) public onlyRole(MINTER_ROLE) {
_mint(account, id, amount, data);
}

/// @inheritdoc IERC1155Common
function batchMint(address to, uint256[] calldata ids, uint256[] calldata amounts) external onlyRole(MINTER_ROLE) {
_mintBatch(to, ids, amounts, "");
function mintBatch(address to, uint256[] calldata ids, uint256[] calldata amounts, bytes calldata data)
public
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)
external
onlyRole(MINTER_ROLE)
{
uint256 length = tos.length;
require(length == amounts.length, "ERC1155: invalid array lengths");
require(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 override returns (string memory) {
string memory uri_ = super.uri(tokenId);
return string.concat(uri_, tokenId.toString());
}

/**
* @dev Collection name.
*/
function name() public view returns (string memory) {
return _name;
}

/**
* @dev Collection symbol.
*/
function symbol() public view returns (string memory) {
return _symbol;
}

/**
* @dev See {ERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view override(ERC1155, AccessControlEnumerable) returns (bool) {
return interfaceId == type(IERC1155Common).interfaceId || super.supportsInterface(interfaceId);
}

/**
* @dev See {ERC1155-_beforeTokenTransfer}.
*/
function _beforeTokenTransfer(
address operator,
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) internal virtual override(ERC1155, ERC1155Supply) {
) internal override(ERC1155, ERC1155Pausable, ERC1155Supply) {
super._beforeTokenTransfer(operator, from, to, ids, amounts, data);
}
}
26 changes: 24 additions & 2 deletions src/interfaces/IERC1155Common.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,39 @@ pragma solidity ^0.8.0;
interface IERC1155Common {
/**
* @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) external;
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 batchMint(address to, uint256[] calldata ids, uint256[] calldata amounts) external;
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;
}
6 changes: 3 additions & 3 deletions src/mock/SampleERC1155.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ pragma solidity ^0.8.0;
import "../ERC1155Common.sol";

contract SampleERC1155 is ERC1155Common {
constructor(string memory name, string memory symbol, string memory baseTokenURI, address[] memory minters)
ERC1155Common(name, symbol, baseTokenURI, minters)
{}
constructor(address admin, string memory name, string memory symbol, string memory uri)
ERC1155Common(admin, name, symbol, uri)
{ }
}
10 changes: 5 additions & 5 deletions test/foundry/SampleERC1155.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@ contract SampleERC1155Test is Test {
string public constant NAME = "SampleERC1155";
string public constant SYMBOL = "NFT1155";
string public constant BASE_URI = "http://example.com/";
address[] public minters = [address(1)];
address admin = makeAddr("admin");

ERC1155Common internal _t;

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

function testName() public virtual {
Expand All @@ -36,12 +36,12 @@ contract SampleERC1155Test is Test {
}

function testMint() public virtual {
vm.startPrank(address(1));
_token().mint(address(15), 15, 15);
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);
_token().mint(address(20), 15, 15, "");
assertEq(_token().totalSupply(15), 30);
assertEq(_token().balanceOf(address(20), 15), 15);
vm.stopPrank();
Expand Down

0 comments on commit 8935566

Please sign in to comment.