/* Copyright 2020 DODO ZOO. SPDX-License-Identifier: Apache-2.0 */ pragma solidity 0.6.9; import {IERC1155} from "../../intf/IERC1155.sol"; import {IERC1155Receiver} from "../../intf/IERC1155Receiver.sol"; import {IERC1155MetadataURI} from "../../intf/IERC1155MetadataURI.sol"; import {IERC165} from "../../intf/IERC165.sol"; import {Strings} from "../../lib/Strings.sol"; import {Address} from "../../lib/Address.sol"; contract InitializableERC1155 is IERC165, IERC1155, IERC1155MetadataURI { using Address for address; mapping (uint256 => mapping(address => uint256)) private _balances; mapping (address => mapping(address => bool)) private _operatorApprovals; string private _uri; function init( uint256 amount, string memory baseUrI ) public { _setURI(baseUrI); _mint(msg.sender, 0, amount ,""); } function supportsInterface(bytes4 interfaceId) public view override returns (bool) { return interfaceId == type(IERC1155).interfaceId || interfaceId == type(IERC1155MetadataURI).interfaceId; } function uri(uint256) public view virtual override returns (string memory) { return _uri; } function balanceOf(address account, uint256 id) public view virtual override returns (uint256) { require(account != address(0), "ERC1155: balance query for the zero address"); return _balances[id][account]; } function balanceOfBatch( address[] memory accounts, uint256[] memory ids ) public view virtual override returns (uint256[] memory) { require(accounts.length == ids.length, "ERC1155: accounts and ids length mismatch"); uint256[] memory batchBalances = new uint256[](accounts.length); for (uint256 i = 0; i < accounts.length; ++i) { batchBalances[i] = balanceOf(accounts[i], ids[i]); } return batchBalances; } function setApprovalForAll(address operator, bool approved) public virtual override { require(msg.sender != operator, "ERC1155: setting approval status for self"); _operatorApprovals[msg.sender][operator] = approved; emit ApprovalForAll(msg.sender, operator, approved); } function isApprovedForAll(address account, address operator) public view virtual override returns (bool) { return _operatorApprovals[account][operator]; } function safeTransferFrom( address from, address to, uint256 id, uint256 amount, bytes memory data ) public virtual override { require(to != address(0), "ERC1155: transfer to the zero address"); require( from == msg.sender || isApprovedForAll(from, msg.sender), "ERC1155: caller is not owner nor approved" ); address operator = msg.sender; _beforeTokenTransfer(operator, from, to, _asSingletonArray(id), _asSingletonArray(amount), data); uint256 fromBalance = _balances[id][from]; require(fromBalance >= amount, "ERC1155: insufficient balance for transfer"); _balances[id][from] = fromBalance - amount; _balances[id][to] += amount; emit TransferSingle(operator, from, to, id, amount); _doSafeTransferAcceptanceCheck(operator, from, to, id, amount, data); } function safeBatchTransferFrom( address from, address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data ) public virtual override { require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch"); require(to != address(0), "ERC1155: transfer to the zero address"); require( from == msg.sender || isApprovedForAll(from, msg.sender), "ERC1155: transfer caller is not owner nor approved" ); address operator = msg.sender; _beforeTokenTransfer(operator, from, to, ids, amounts, data); for (uint256 i = 0; i < ids.length; ++i) { uint256 id = ids[i]; uint256 amount = amounts[i]; uint256 fromBalance = _balances[id][from]; require(fromBalance >= amount, "ERC1155: insufficient balance for transfer"); _balances[id][from] = fromBalance - amount; _balances[id][to] += amount; } emit TransferBatch(operator, from, to, ids, amounts); _doSafeBatchTransferAcceptanceCheck(operator, from, to, ids, amounts, data); } function _setURI(string memory newuri) internal virtual { _uri = newuri; } function _mint(address account, uint256 id, uint256 amount, bytes memory data) internal virtual { require(account != address(0), "ERC1155: mint to the zero address"); address operator = msg.sender; _beforeTokenTransfer(operator, address(0), account, _asSingletonArray(id), _asSingletonArray(amount), data); _balances[id][account] += amount; emit TransferSingle(operator, address(0), account, id, amount); _doSafeTransferAcceptanceCheck(operator, address(0), account, id, amount, data); } function _mintBatch(address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data) internal virtual { require(to != address(0), "ERC1155: mint to the zero address"); require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch"); address operator = msg.sender; _beforeTokenTransfer(operator, address(0), to, ids, amounts, data); for (uint i = 0; i < ids.length; i++) { _balances[ids[i]][to] += amounts[i]; } emit TransferBatch(operator, address(0), to, ids, amounts); _doSafeBatchTransferAcceptanceCheck(operator, address(0), to, ids, amounts, data); } function _burn(address account, uint256 id, uint256 amount) internal virtual { require(account != address(0), "ERC1155: burn from the zero address"); address operator = msg.sender; _beforeTokenTransfer(operator, account, address(0), _asSingletonArray(id), _asSingletonArray(amount), ""); uint256 accountBalance = _balances[id][account]; require(accountBalance >= amount, "ERC1155: burn amount exceeds balance"); _balances[id][account] = accountBalance - amount; emit TransferSingle(operator, account, address(0), id, amount); } function _burnBatch(address account, uint256[] memory ids, uint256[] memory amounts) internal virtual { require(account != address(0), "ERC1155: burn from the zero address"); require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch"); address operator = msg.sender; _beforeTokenTransfer(operator, account, address(0), ids, amounts, ""); for (uint i = 0; i < ids.length; i++) { uint256 id = ids[i]; uint256 amount = amounts[i]; uint256 accountBalance = _balances[id][account]; require(accountBalance >= amount, "ERC1155: burn amount exceeds balance"); _balances[id][account] = accountBalance - amount; } emit TransferBatch(operator, account, address(0), ids, amounts); } function _beforeTokenTransfer( address operator, address from, address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data ) internal virtual { } function _doSafeTransferAcceptanceCheck( address operator, address from, address to, uint256 id, uint256 amount, bytes memory data ) private { if (to.isContract()) { try IERC1155Receiver(to).onERC1155Received(operator, from, id, amount, data) returns (bytes4 response) { if (response != IERC1155Receiver(to).onERC1155Received.selector) { revert("ERC1155: ERC1155Receiver rejected tokens"); } } catch Error(string memory reason) { revert(reason); } catch { revert("ERC1155: transfer to non ERC1155Receiver implementer"); } } } function _doSafeBatchTransferAcceptanceCheck( address operator, address from, address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data ) private { if (to.isContract()) { try IERC1155Receiver(to).onERC1155BatchReceived(operator, from, ids, amounts, data) returns (bytes4 response) { if (response != IERC1155Receiver(to).onERC1155BatchReceived.selector) { revert("ERC1155: ERC1155Receiver rejected tokens"); } } catch Error(string memory reason) { revert(reason); } catch { revert("ERC1155: transfer to non ERC1155Receiver implementer"); } } } function _asSingletonArray(uint256 element) private pure returns (uint256[] memory) { uint256[] memory array = new uint256[](1); array[0] = element; return array; } }