// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @title ERC1155 Token
* @author 0xSumo <@PBADAO>
*/
interface ERC1155TokenReceiver {
function onERC1155Received(address operator_, address from_, uint256 id_, uint256 amount_, bytes calldata data_) external returns (bytes4);
function onERC1155BatchReceived(address operator_, address from_, uint256[] calldata ids_, uint256[] calldata amounts_, bytes calldata data_) external returns (bytes4);
}
abstract contract ERC1155Enumerable {
string public name;
string public symbol;
constructor(string memory name_, string memory symbol_) {
name = name_;
symbol = symbol_;
}
event TransferSingle(address indexed operator_, address indexed from_, address indexed to_, uint256 id_, uint256 amount_);
event TransferBatch(address indexed operator_, address indexed from_, address indexed to_, uint256[] ids_, uint256[] amounts_);
event ApprovalForAll(address indexed owner_, address indexed operator_, bool approved_);
event URI(string value_, uint256 indexed id_);
mapping(address => mapping(uint256 => uint256)) public balanceOf;
mapping(address => mapping(address => bool)) public isApprovedForAll;
mapping(uint256 => address[]) public tokenToOwners;
mapping(uint256 => mapping(address => uint256)) public tokenToOwnersToIndex;
struct TokenBalances {
address owner;
uint256 balance;
}
function _addEnumerableData(address address_, uint256 id_) internal {
if (balanceOf[address_][id_] == 0) {
uint256 _nextIndex = tokenToOwners[id_].length;
tokenToOwners[id_].push(address_);
tokenToOwnersToIndex[id_][address_] = _nextIndex;
}
}
function _removeEnumerableData(address address_, uint256 id_) internal {
if (balanceOf[address_][id_] == 0) {
uint256 _userIndex = tokenToOwnersToIndex[id_][address_];
uint256 _lastIndex = tokenToOwners[id_].length - 1;
if (_userIndex != _lastIndex) {
address _userAtLastIndex = tokenToOwners[id_][_lastIndex];
tokenToOwners[id_][_userIndex] = _userAtLastIndex;
tokenToOwnersToIndex[id_][_userAtLastIndex] = _userIndex;
}
tokenToOwners[id_].pop();
delete tokenToOwnersToIndex[id_][address_];
}
}
function getOwnersOfTokenId(uint256 id_) public view returns (address[] memory) {
return tokenToOwners[id_];
}
function getOwnersOfTokenIdAndBalance(uint256 id_) public view returns (TokenBalances[] memory) {
address[] memory _owners = getOwnersOfTokenId(id_);
uint256 _ownersLength = _owners.length;
TokenBalances[] memory _TokenBalancesAll = new TokenBalances[] (_ownersLength);
for (uint256 i = 0; i < _ownersLength; i++) {
address _currentOwner = _owners[i];
_TokenBalancesAll[i] = TokenBalances(
_currentOwner,
balanceOf[_currentOwner][id_]
);
}
return _TokenBalancesAll;
}
function getTotalSupplyOfIds(uint256[] calldata ids_) public view returns (uint256) {
uint256 _tokens;
for (uint256 i = 0; i < ids_.length; i++) {
_tokens += getOwnersOfTokenId(ids_[i]).length;
}
return _tokens;
}
function uri(uint256 id) public view virtual returns (string memory);
function _isSameLength(uint256 a, uint256 b) internal pure returns (bool) {
return a == b;
}
function _isApprovedOrOwner(address from_) internal view returns (bool) {
return msg.sender == from_ || isApprovedForAll[from_][msg.sender];
}
function _ERC1155Supported(address from_, address to_, uint256 id_, uint256 amount_, bytes memory data_) internal {
require(to_.code.length == 0 ? to_ != address(0) :
ERC1155TokenReceiver(to_).onERC1155Received(
msg.sender, from_, id_, amount_, data_) ==
ERC1155TokenReceiver.onERC1155Received.selector,
"_ERC1155Supported(): Unsupported Recipient!"
);
}
function _ERC1155BatchSupported(address from_, address to_, uint256[] memory ids_, uint256[] memory amounts_, bytes memory data_) internal {
require(to_.code.length == 0 ? to_ != address(0) :
ERC1155TokenReceiver(to_).onERC1155BatchReceived(
msg.sender, from_, ids_, amounts_, data_) ==
ERC1155TokenReceiver.onERC1155BatchReceived.selector,
"_ERC1155BatchSupported(): Unsupported Recipient!"
);
}
function setApprovalForAll(address operator_, bool approved_) public virtual {
isApprovedForAll[msg.sender][operator_] = approved_;
emit ApprovalForAll(msg.sender, operator_, approved_);
}
function _transfer(address from_, address to_, uint256 id_, uint256 amount_) internal {
_addEnumerableData(to_, id_);
balanceOf[to_][id_] += amount_;
balanceOf[from_][id_] -= amount_;
_removeEnumerableData(from_, id_);
}
function safeTransferFrom(address from_, address to_, uint256 id_, uint256 amount_, bytes memory data_) public virtual {
require(_isApprovedOrOwner(from_));
_transfer(from_, to_, id_, amount_);
emit TransferSingle(msg.sender, from_, to_, id_, amount_);
_ERC1155Supported(from_, to_, id_, amount_, data_);
}
function safeBatchTransferFrom(address from_, address to_, uint256[] memory ids_, uint256[] memory amounts_, bytes memory data_) public virtual {
require(_isSameLength(ids_.length, amounts_.length));
require(_isApprovedOrOwner(from_));
for (uint256 i = 0; i < ids_.length; i++) {
_transfer(from_, to_, ids_[i], amounts_[i]);
}
emit TransferBatch(msg.sender, from_, to_, ids_, amounts_);
_ERC1155BatchSupported(from_, to_, ids_, amounts_, data_);
}
function _mintInternal(address to_, uint256 id_, uint256 amount_) internal {
_addEnumerableData(to_, id_);
balanceOf[to_][id_] += amount_;
}
function _mint(address to_, uint256 id_, uint256 amount_, bytes memory data_) internal {
_mintInternal(to_, id_, amount_);
emit TransferSingle(msg.sender, address(0), to_, id_, amount_);
_ERC1155Supported(address(0), to_, id_, amount_, data_);
}
function _batchMint(address to_, uint256[] memory ids_, uint256[] memory amounts_, bytes memory data_) internal {
require(_isSameLength(ids_.length, amounts_.length));
for (uint256 i = 0; i < ids_.length; i++) {
_mintInternal(to_, ids_[i], amounts_[i]);
}
emit TransferBatch(msg.sender, address(0), to_, ids_, amounts_);
_ERC1155BatchSupported(address(0), to_, ids_, amounts_, data_);
}
function _burnInternal(address from_, uint256 id_, uint256 amount_) internal {
balanceOf[from_][id_] -= amount_;
_removeEnumerableData(from_, id_);
}
function _burn(address from_, uint256 id_, uint256 amount_) internal {
_burnInternal(from_, id_, amount_);
emit TransferSingle(msg.sender, from_, address(0), id_, amount_);
}
function _batchBurn(address from_, uint256[] memory ids_, uint256[] memory amounts_) internal {
require(_isSameLength(ids_.length, amounts_.length));
for (uint256 i = 0; i < ids_.length; i++) {
_burnInternal(from_, ids_[i], amounts_[i]);
}
emit TransferBatch(msg.sender, from_, address(0), ids_, amounts_);
}
function supportsInterface(bytes4 interfaceId_) public pure virtual returns (bool) {
return interfaceId_ == 0x01ffc9a7 || interfaceId_ == 0xd9b67a26 || interfaceId_ == 0x0e89341c;
}
function balanceOfBatch(address[] memory owners_, uint256[] memory ids_) public view virtual returns (uint256[] memory) {
require(_isSameLength(owners_.length, ids_.length));
uint256[] memory _balances = new uint256[](owners_.length);
for (uint256 i = 0; i < owners_.length; i++) {
_balances[i] = balanceOf[owners_[i]][ids_[i]];
}
return _balances;
}
}
abstract contract ERC721URIPerToken {
mapping(uint256 => string) public tokenToURI;
function _setTokenToURI(uint256 tokenId_, string memory uri_) internal virtual {
tokenToURI[tokenId_] = uri_;
}
}
abstract contract OwnWithAuth {
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
event AdminSet(bytes32 indexed controllerType, bytes32 indexed controllerSlot, address indexed controller, bool status);
address public owner;
mapping(bytes32 => mapping(address => bool)) internal admin;
constructor() { owner = msg.sender; }
modifier onlyOwner() { require(owner == msg.sender, "only owner");_; }
modifier onlyAdmin(string memory type_) { require(isAdmin(type_, msg.sender), "only admin");_; }
function transferOwnership(address newOwner) external onlyOwner {
emit OwnershipTransferred(owner, newOwner); owner = newOwner;
}
function _setAdmin(string memory type_, address controller, bool status) internal {
bytes32 typeHash = keccak256(abi.encodePacked(type_));
admin[typeHash][controller] = status;
emit AdminSet(typeHash, typeHash, controller, status);
}
function setAdmin(string memory type_, address controller, bool status) external onlyOwner {
_setAdmin(type_, controller, status);
}
function isAdmin(string memory type_, address controller) public view returns (bool) {
bytes32 typeHash = keccak256(abi.encodePacked(type_));
return admin[typeHash][controller];
}
}
contract ERC1155 is ERC1155Enumerable, ERC721URIPerToken, OwnWithAuth {
uint8 public immutable mintId = 1;
uint16 public maxTokens = 5000;
uint256 public totalMintOut;
uint256 public mintPrice = 0.01 ether;
bool public mintState;
modifier onlySender {
require(msg.sender == tx.origin, "No smart contracts!");
_;
}
constructor() ERC1155Enumerable("8CH1 Online Event Collection", "8OEC") {
_setAdmin("MINTER", msg.sender, true);
_setAdmin("BURNER", msg.sender, true);
_setAdmin("ADMIN", msg.sender, true);
_setTokenToURI(1, "ipfs://QmRh9KmQVG4LQtsvTPknhTnmo1Yf9q28DNUV5EoC5GGZd9");
_setTokenToURI(2, "ipfs://QmaMc13k99ku3aNrZQE1vaQbF38Js58To2yXcjQHxo64AU");
}
function mint8CH1(address to_, uint256 amount_, bytes memory data_) external payable onlySender {
require(mintState, "Not active");
require(maxTokens >= totalMintOut + amount_, "No mints remaining");
require(msg.value == mintPrice * amount_, "Invalid value sent");
_mint(to_, mintId, amount_, data_);
totalMintOut += amount_;
}
function mint(address to_, uint256 id_, uint256 amount_, bytes memory data_) external onlyAdmin("MINTER") {
_mint(to_, id_, amount_, data_);
}
function burn(address from_, uint256 id_, uint256 amount_) external onlyAdmin("BURNER") {
_burn(from_, id_, amount_);
}
function setMintState(bool state_) external onlyAdmin("ADMIN") {
mintState = state_;
}
function setMaxTokens(uint16 amount_) external onlyAdmin("ADMIN") {
maxTokens = amount_;
}
function setMintPrice(uint256 price_) external onlyAdmin("ADMIN") {
mintPrice = price_;
}
function setTokenToURI(uint256 tokenId_, string calldata uri_) external onlyAdmin("ADMIN") {
_setTokenToURI(tokenId_, uri_);
}
function uri(uint256 id) public view override returns (string memory) {
return tokenToURI[id];
}
function withdraw() external onlyOwner {
uint256 balance = address(this).balance;
(bool transferTx, ) = msg.sender.call{value: balance}("");
require(transferTx, "Transfer failed.");
}
}
{
"compilationTarget": {
"ERC1155.sol": "ERC1155"
},
"evmVersion": "shanghai",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"controllerType","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"controllerSlot","type":"bytes32"},{"indexed":true,"internalType":"address","name":"controller","type":"address"},{"indexed":false,"internalType":"bool","name":"status","type":"bool"}],"name":"AdminSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner_","type":"address"},{"indexed":true,"internalType":"address","name":"operator_","type":"address"},{"indexed":false,"internalType":"bool","name":"approved_","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator_","type":"address"},{"indexed":true,"internalType":"address","name":"from_","type":"address"},{"indexed":true,"internalType":"address","name":"to_","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"ids_","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"amounts_","type":"uint256[]"}],"name":"TransferBatch","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator_","type":"address"},{"indexed":true,"internalType":"address","name":"from_","type":"address"},{"indexed":true,"internalType":"address","name":"to_","type":"address"},{"indexed":false,"internalType":"uint256","name":"id_","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount_","type":"uint256"}],"name":"TransferSingle","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"value_","type":"string"},{"indexed":true,"internalType":"uint256","name":"id_","type":"uint256"}],"name":"URI","type":"event"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"owners_","type":"address[]"},{"internalType":"uint256[]","name":"ids_","type":"uint256[]"}],"name":"balanceOfBatch","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from_","type":"address"},{"internalType":"uint256","name":"id_","type":"uint256"},{"internalType":"uint256","name":"amount_","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id_","type":"uint256"}],"name":"getOwnersOfTokenId","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id_","type":"uint256"}],"name":"getOwnersOfTokenIdAndBalance","outputs":[{"components":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"balance","type":"uint256"}],"internalType":"struct ERC1155Enumerable.TokenBalances[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"ids_","type":"uint256[]"}],"name":"getTotalSupplyOfIds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"type_","type":"string"},{"internalType":"address","name":"controller","type":"address"}],"name":"isAdmin","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxTokens","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to_","type":"address"},{"internalType":"uint256","name":"id_","type":"uint256"},{"internalType":"uint256","name":"amount_","type":"uint256"},{"internalType":"bytes","name":"data_","type":"bytes"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to_","type":"address"},{"internalType":"uint256","name":"amount_","type":"uint256"},{"internalType":"bytes","name":"data_","type":"bytes"}],"name":"mint8CH1","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"mintId","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mintPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mintState","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from_","type":"address"},{"internalType":"address","name":"to_","type":"address"},{"internalType":"uint256[]","name":"ids_","type":"uint256[]"},{"internalType":"uint256[]","name":"amounts_","type":"uint256[]"},{"internalType":"bytes","name":"data_","type":"bytes"}],"name":"safeBatchTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from_","type":"address"},{"internalType":"address","name":"to_","type":"address"},{"internalType":"uint256","name":"id_","type":"uint256"},{"internalType":"uint256","name":"amount_","type":"uint256"},{"internalType":"bytes","name":"data_","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"type_","type":"string"},{"internalType":"address","name":"controller","type":"address"},{"internalType":"bool","name":"status","type":"bool"}],"name":"setAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator_","type":"address"},{"internalType":"bool","name":"approved_","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"amount_","type":"uint16"}],"name":"setMaxTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"price_","type":"uint256"}],"name":"setMintPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"state_","type":"bool"}],"name":"setMintState","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId_","type":"uint256"},{"internalType":"string","name":"uri_","type":"string"}],"name":"setTokenToURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId_","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"tokenToOwners","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"}],"name":"tokenToOwnersToIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"tokenToURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalMintOut","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"uri","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]