From 388b294b587ebbfa9245487e4ef462bfc0302514 Mon Sep 17 00:00:00 2001 From: owen05 Date: Wed, 14 Apr 2021 13:51:21 +0800 Subject: [PATCH] arrange erc721 && erc1155 --- .../DODOMysteryBox.sol | 0 contracts/DODOMysteryBox/MysteryBox1.sol | 115 ++++++ contracts/external/ERC1155/ERC1155.sol | 179 +++++++-- contracts/external/ERC721/ERC721.sol | 369 ++++++++++++++++++ .../external/ERC721/InitializableERC721.sol | 220 +---------- contracts/{lib => external/utils}/Address.sol | 0 contracts/external/utils/Context.sol | 25 ++ contracts/external/utils/ERC165.sol | 29 ++ .../{intf => external/utils}/IERC165.sol | 0 contracts/{lib => external/utils}/Strings.sol | 0 10 files changed, 695 insertions(+), 242 deletions(-) rename contracts/{DODOToken => DODOMysteryBox}/DODOMysteryBox.sol (100%) create mode 100644 contracts/DODOMysteryBox/MysteryBox1.sol create mode 100644 contracts/external/ERC721/ERC721.sol rename contracts/{lib => external/utils}/Address.sol (100%) create mode 100644 contracts/external/utils/Context.sol create mode 100644 contracts/external/utils/ERC165.sol rename contracts/{intf => external/utils}/IERC165.sol (100%) rename contracts/{lib => external/utils}/Strings.sol (100%) diff --git a/contracts/DODOToken/DODOMysteryBox.sol b/contracts/DODOMysteryBox/DODOMysteryBox.sol similarity index 100% rename from contracts/DODOToken/DODOMysteryBox.sol rename to contracts/DODOMysteryBox/DODOMysteryBox.sol diff --git a/contracts/DODOMysteryBox/MysteryBox1.sol b/contracts/DODOMysteryBox/MysteryBox1.sol new file mode 100644 index 0000000..a71085c --- /dev/null +++ b/contracts/DODOMysteryBox/MysteryBox1.sol @@ -0,0 +1,115 @@ +/* + Copyright 2020 DODO ZOO. + SPDX-License-Identifier: Apache-2.0 +*/ +pragma solidity 0.6.9; +pragma experimental ABIEncoderV2; + +import {IERC20} from "../intf/IERC20.sol"; +import {SafeERC20} from "../lib/SafeERC20.sol"; +import {SafeMath} from "../lib/SafeMath.sol"; +import {IRandomGenerator} from "../lib/RandomGenerator.sol"; +import {InitializableOwnable} from "../lib/InitializableOwnable.sol"; +import {Address} from "../external/utils/Address.sol"; +import {ERC721} from "../external/ERC721/ERC721.sol"; + +contract MysteryBox1 is ERC721, InitializableOwnable { + using SafeMath for uint256; + using SafeERC20 for IERC20; + using Address for address; + + // ============ Storage ============ + + mapping(address => uint256) _USER_TICKETS_; + + uint256 public _TOTAL_TICKETS_; + uint256 public _CUR_SELLING_TICKETS_; + uint256 public _CUR_PRCIE_; + uint256 public _TICKET_UNIT_ = 1; // ticket consumed in a single lottery + + + mapping(uint256 => bool) _TOKEN_ID_FLAG_; + + address public _RANDOM_GENERATOR_; + + uint256 constant _TOTAL_NFTs_ = 3000; + + // ============ Event ============= + event ChangeRandomGenerator(address randomGenerator); + event ChangeTicketUnit(uint256 newTicketUnit); + event ChangeSellingInfo(uint256 curSellingTickets, uint256 curPrice); + event Withdraw(address account, uint256 amount); + + fallback() external payable {} + + receive() external payable {} + + function init( + address owner, + string memory baseUri, + address randomGenerator + ) public { + initOwner(owner); + _setURI(baseUri); + _RANDOM_GENERATOR_ = randomGenerator; + } + + function buyTicket() payable external { + require(msg.value >= _CUR_PRCIE_, "BNB_NOT_ENOUGH"); + + } + + function redeemPrize(address to) external { + + // uint256 ticketNum = ticketInput.div(_TICKET_UNIT_); + // require(ticketNum >= 1, "DODOMysteryBox: TICKET_NOT_ENOUGH"); + // for (uint256 i = 0; i < ticketNum; i++) { + // _redeemSinglePrize(to); + // } + // emit RedeemPrize(to, ticketInput, ticketNum); + } + + // =============== View ================ + + // =============== Internal ================ + + function _redeemSinglePrize(address to) internal { + // uint256 range = _PROB_INTERVAL_[_PROB_INTERVAL_.length - 1]; + // uint256 random = IRandomGenerator(_RANDOM_GENERATOR_).random(gasleft()) % range; + // uint256 i; + // for (i = 0; i < _PROB_INTERVAL_.length; i++) { + // if (random <= _PROB_INTERVAL_[i]) { + // break; + // } + // } + // require(_PRIZE_SET_[i].length > 0, "EMPTY_PRIZE_SET"); + // uint256 prize = _PRIZE_SET_[i][random % _PRIZE_SET_[i].length]; + // _mint(to, prize, 1, ""); + } + + // ================= Owner =================== + + function updateRandomGenerator(address newRandomGenerator) external onlyOwner { + require(newRandomGenerator != address(0)); + _RANDOM_GENERATOR_ = newRandomGenerator; + emit ChangeRandomGenerator(newRandomGenerator); + } + + function updateSellingInfo(uint256 newSellingTickets, uint256 newPrice) external onlyOwner { + _CUR_SELLING_TICKETS_ = newSellingTickets; + _CUR_PRCIE_ = newPrice; + emit ChangeSellingInfo(newSellingTickets, newPrice); + } + + function updateTicketUnit(uint256 newTicketUnit) external onlyOwner { + require(newTicketUnit != 0); + _TICKET_UNIT_ = newTicketUnit; + emit ChangeTicketUnit(newTicketUnit); + } + + function withdraw() external onlyOwner { + uint256 amount = address(this).balance; + msg.sender.transfer(amount); + emit Withdraw(msg.sender, amount); + } +} diff --git a/contracts/external/ERC1155/ERC1155.sol b/contracts/external/ERC1155/ERC1155.sol index daddffe..ecd92f2 100644 --- a/contracts/external/ERC1155/ERC1155.sol +++ b/contracts/external/ERC1155/ERC1155.sol @@ -1,43 +1,85 @@ -/* - - Copyright 2020 DODO ZOO. - SPDX-License-Identifier: Apache-2.0 - -*/ +// This is a file copied from https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC1155/ERC1155.sol +// SPDX-License-Identifier: MIT 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"; +import {ERC165} from "../utils/ERC165.sol"; +import {Strings} from "../utils/Strings.sol"; +import {Address} from "../utils/Address.sol"; +import {Context} from "../utils/Context.sol"; - -contract ERC1155 is IERC165, IERC1155, IERC1155MetadataURI { +/** + * + * @dev Implementation of the basic standard multi-token. + * See https://eips.ethereum.org/EIPS/eip-1155 + * Originally based on code by Enjin: https://github.com/enjin/erc-1155 + * + * _Available since v3.1._ + */ +contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI { using Address for address; + // Mapping from token ID to account balances mapping (uint256 => mapping(address => uint256)) private _balances; + // Mapping from account to operator approvals mapping (address => mapping(address => bool)) private _operatorApprovals; + // Used as the URI for all token types by relying on ID substitution, e.g. https://token-cdn-domain/{id}.json string private _uri; - function supportsInterface(bytes4 interfaceId) public view override returns (bool) { - return interfaceId == type(IERC1155).interfaceId - || interfaceId == type(IERC1155MetadataURI).interfaceId; + /** + * @dev See {_setURI}. + */ + constructor (string memory uri_) { + _setURI(uri_); } + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { + return interfaceId == type(IERC1155).interfaceId + || interfaceId == type(IERC1155MetadataURI).interfaceId + || super.supportsInterface(interfaceId); + } + + /** + * @dev See {IERC1155MetadataURI-uri}. + * + * This implementation returns the same URI for *all* token types. It relies + * on the token type ID substitution mechanism + * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP]. + * + * Clients calling this function must replace the `\{id\}` substring with the + * actual token type ID. + */ function uri(uint256) public view virtual override returns (string memory) { return _uri; } + /** + * @dev See {IERC1155-balanceOf}. + * + * Requirements: + * + * - `account` cannot be the zero address. + */ 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]; } + /** + * @dev See {IERC1155-balanceOfBatch}. + * + * Requirements: + * + * - `accounts` and `ids` must have the same length. + */ function balanceOfBatch( address[] memory accounts, uint256[] memory ids @@ -59,17 +101,26 @@ contract ERC1155 is IERC165, IERC1155, IERC1155MetadataURI { return batchBalances; } + /** + * @dev See {IERC1155-setApprovalForAll}. + */ function setApprovalForAll(address operator, bool approved) public virtual override { - require(msg.sender != operator, "ERC1155: setting approval status for self"); + require(_msgSender() != operator, "ERC1155: setting approval status for self"); - _operatorApprovals[msg.sender][operator] = approved; - emit ApprovalForAll(msg.sender, operator, approved); + _operatorApprovals[_msgSender()][operator] = approved; + emit ApprovalForAll(_msgSender(), operator, approved); } + /** + * @dev See {IERC1155-isApprovedForAll}. + */ function isApprovedForAll(address account, address operator) public view virtual override returns (bool) { return _operatorApprovals[account][operator]; } + /** + * @dev See {IERC1155-safeTransferFrom}. + */ function safeTransferFrom( address from, address to, @@ -83,11 +134,11 @@ contract ERC1155 is IERC165, IERC1155, IERC1155MetadataURI { { require(to != address(0), "ERC1155: transfer to the zero address"); require( - from == msg.sender || isApprovedForAll(from, msg.sender), + from == _msgSender() || isApprovedForAll(from, _msgSender()), "ERC1155: caller is not owner nor approved" ); - address operator = msg.sender; + address operator = _msgSender(); _beforeTokenTransfer(operator, from, to, _asSingletonArray(id), _asSingletonArray(amount), data); @@ -101,6 +152,9 @@ contract ERC1155 is IERC165, IERC1155, IERC1155MetadataURI { _doSafeTransferAcceptanceCheck(operator, from, to, id, amount, data); } + /** + * @dev See {IERC1155-safeBatchTransferFrom}. + */ function safeBatchTransferFrom( address from, address to, @@ -115,11 +169,11 @@ contract ERC1155 is IERC165, IERC1155, IERC1155MetadataURI { 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), + from == _msgSender() || isApprovedForAll(from, _msgSender()), "ERC1155: transfer caller is not owner nor approved" ); - address operator = msg.sender; + address operator = _msgSender(); _beforeTokenTransfer(operator, from, to, ids, amounts, data); @@ -138,14 +192,44 @@ contract ERC1155 is IERC165, IERC1155, IERC1155MetadataURI { _doSafeBatchTransferAcceptanceCheck(operator, from, to, ids, amounts, data); } + /** + * @dev Sets a new URI for all token types, by relying on the token type ID + * substitution mechanism + * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP]. + * + * By this mechanism, any occurrence of the `\{id\}` substring in either the + * URI or any of the amounts in the JSON file at said URI will be replaced by + * clients with the token type ID. + * + * For example, the `https://token-cdn-domain/\{id\}.json` URI would be + * interpreted by clients as + * `https://token-cdn-domain/000000000000000000000000000000000000000000000000000000000004cce0.json` + * for token type ID 0x4cce0. + * + * See {uri}. + * + * Because these URIs cannot be meaningfully represented by the {URI} event, + * this function emits no events. + */ function _setURI(string memory newuri) internal virtual { _uri = newuri; } + /** + * @dev Creates `amount` tokens of token type `id`, and assigns them to `account`. + * + * Emits a {TransferSingle} event. + * + * Requirements: + * + * - `account` cannot be the zero address. + * - If `account` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the + * acceptance magic value. + */ 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; + address operator = _msgSender(); _beforeTokenTransfer(operator, address(0), account, _asSingletonArray(id), _asSingletonArray(amount), data); @@ -155,11 +239,20 @@ contract ERC1155 is IERC165, IERC1155, IERC1155MetadataURI { _doSafeTransferAcceptanceCheck(operator, address(0), account, id, amount, data); } + /** + * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_mint}. + * + * Requirements: + * + * - `ids` and `amounts` must have the same length. + * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the + * acceptance magic value. + */ 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; + address operator = _msgSender(); _beforeTokenTransfer(operator, address(0), to, ids, amounts, data); @@ -172,10 +265,18 @@ contract ERC1155 is IERC165, IERC1155, IERC1155MetadataURI { _doSafeBatchTransferAcceptanceCheck(operator, address(0), to, ids, amounts, data); } + /** + * @dev Destroys `amount` tokens of token type `id` from `account` + * + * Requirements: + * + * - `account` cannot be the zero address. + * - `account` must have at least `amount` tokens of token type `id`. + */ function _burn(address account, uint256 id, uint256 amount) internal virtual { require(account != address(0), "ERC1155: burn from the zero address"); - address operator = msg.sender; + address operator = _msgSender(); _beforeTokenTransfer(operator, account, address(0), _asSingletonArray(id), _asSingletonArray(amount), ""); @@ -186,11 +287,18 @@ contract ERC1155 is IERC165, IERC1155, IERC1155MetadataURI { emit TransferSingle(operator, account, address(0), id, amount); } + /** + * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_burn}. + * + * Requirements: + * + * - `ids` and `amounts` must have the same length. + */ 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; + address operator = _msgSender(); _beforeTokenTransfer(operator, account, address(0), ids, amounts, ""); @@ -206,6 +314,26 @@ contract ERC1155 is IERC165, IERC1155, IERC1155MetadataURI { emit TransferBatch(operator, account, address(0), ids, amounts); } + /** + * @dev Hook that is called before any token transfer. This includes minting + * and burning, as well as batched variants. + * + * The same hook is called on both single and batched variants. For single + * transfers, the length of the `id` and `amount` arrays will be 1. + * + * Calling conditions (for each `id` and `amount` pair): + * + * - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens + * of token type `id` will be transferred to `to`. + * - When `from` is zero, `amount` tokens of token type `id` will be minted + * for `to`. + * - when `to` is zero, `amount` of ``from``'s tokens of token type `id` + * will be burned. + * - `from` and `to` are never both zero. + * - `ids` and `amounts` have the same, non-zero length. + * + * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. + */ function _beforeTokenTransfer( address operator, address from, @@ -271,3 +399,4 @@ contract ERC1155 is IERC165, IERC1155, IERC1155MetadataURI { return array; } } + diff --git a/contracts/external/ERC721/ERC721.sol b/contracts/external/ERC721/ERC721.sol new file mode 100644 index 0000000..df59ec2 --- /dev/null +++ b/contracts/external/ERC721/ERC721.sol @@ -0,0 +1,369 @@ +// This is a file copied from https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC721/ERC721.sol +// SPDX-License-Identifier: MIT + +pragma solidity 0.6.9; + +import {IERC721} from "../../intf/IERC721.sol"; +import {IERC721Receiver} from "../../intf/IERC721Receiver.sol"; +import {IERC721Metadata} from "../../intf/IERC721Metadata.sol"; +import {ERC165} from "../utils/ERC165.sol"; +import {Strings} from "../utils/Strings.sol"; +import {Address} from "../utils/Address.sol"; +import {Context} from "../utils/Context.sol"; + +/** + * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including + * the Metadata extension, but not including the Enumerable extension, which is available separately as + * {ERC721Enumerable}. + */ +contract ERC721 is Context, ERC165, IERC721, IERC721Metadata { + using Address for address; + using Strings for uint256; + + // Token name + string private _name; + + // Token symbol + string private _symbol; + + // Mapping from token ID to owner address + mapping (uint256 => address) private _owners; + + // Mapping owner address to token count + mapping (address => uint256) private _balances; + + // Mapping from token ID to approved address + mapping (uint256 => address) private _tokenApprovals; + + // Mapping from owner to operator approvals + mapping (address => mapping (address => bool)) private _operatorApprovals; + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { + return interfaceId == type(IERC721).interfaceId + || interfaceId == type(IERC721Metadata).interfaceId + || super.supportsInterface(interfaceId); + } + + /** + * @dev See {IERC721-balanceOf}. + */ + function balanceOf(address owner) public view virtual override returns (uint256) { + require(owner != address(0), "ERC721: balance query for the zero address"); + return _balances[owner]; + } + + /** + * @dev See {IERC721-ownerOf}. + */ + function ownerOf(uint256 tokenId) public view virtual override returns (address) { + address owner = _owners[tokenId]; + require(owner != address(0), "ERC721: owner query for nonexistent token"); + return owner; + } + + /** + * @dev See {IERC721Metadata-name}. + */ + function name() public view virtual override returns (string memory) { + return _name; + } + + /** + * @dev See {IERC721Metadata-symbol}. + */ + function symbol() public view virtual override returns (string memory) { + return _symbol; + } + + /** + * @dev See {IERC721Metadata-tokenURI}. + */ + function tokenURI(uint256 tokenId) public view virtual override returns (string memory) { + require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token"); + + string memory baseURI = _baseURI(); + return bytes(baseURI).length > 0 + ? string(abi.encodePacked(baseURI, tokenId.toString())) + : ''; + } + + /** + * @dev Base URI for computing {tokenURI}. Empty by default, can be overriden + * in child contracts. + */ + function _baseURI() internal view virtual returns (string memory) { + return ""; + } + + /** + * @dev See {IERC721-approve}. + */ + function approve(address to, uint256 tokenId) public virtual override { + address owner = ERC721.ownerOf(tokenId); + require(to != owner, "ERC721: approval to current owner"); + + require(_msgSender() == owner || isApprovedForAll(owner, _msgSender()), + "ERC721: approve caller is not owner nor approved for all" + ); + + _approve(to, tokenId); + } + + /** + * @dev See {IERC721-getApproved}. + */ + function getApproved(uint256 tokenId) public view virtual override returns (address) { + require(_exists(tokenId), "ERC721: approved query for nonexistent token"); + + return _tokenApprovals[tokenId]; + } + + /** + * @dev See {IERC721-setApprovalForAll}. + */ + function setApprovalForAll(address operator, bool approved) public virtual override { + require(operator != _msgSender(), "ERC721: approve to caller"); + + _operatorApprovals[_msgSender()][operator] = approved; + emit ApprovalForAll(_msgSender(), operator, approved); + } + + /** + * @dev See {IERC721-isApprovedForAll}. + */ + function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) { + return _operatorApprovals[owner][operator]; + } + + /** + * @dev See {IERC721-transferFrom}. + */ + function transferFrom(address from, address to, uint256 tokenId) public virtual override { + //solhint-disable-next-line max-line-length + require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved"); + + _transfer(from, to, tokenId); + } + + /** + * @dev See {IERC721-safeTransferFrom}. + */ + function safeTransferFrom(address from, address to, uint256 tokenId) public virtual override { + safeTransferFrom(from, to, tokenId, ""); + } + + /** + * @dev See {IERC721-safeTransferFrom}. + */ + function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory _data) public virtual override { + require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved"); + _safeTransfer(from, to, tokenId, _data); + } + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients + * are aware of the ERC721 protocol to prevent tokens from being forever locked. + * + * `_data` is additional data, it has no specified format and it is sent in call to `to`. + * + * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g. + * implement alternative mechanisms to perform token transfer, such as signature-based. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function _safeTransfer(address from, address to, uint256 tokenId, bytes memory _data) internal virtual { + _transfer(from, to, tokenId); + require(_checkOnERC721Received(from, to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer"); + } + + /** + * @dev Returns whether `tokenId` exists. + * + * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}. + * + * Tokens start existing when they are minted (`_mint`), + * and stop existing when they are burned (`_burn`). + */ + function _exists(uint256 tokenId) internal view virtual returns (bool) { + return _owners[tokenId] != address(0); + } + + /** + * @dev Returns whether `spender` is allowed to manage `tokenId`. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) { + require(_exists(tokenId), "ERC721: operator query for nonexistent token"); + address owner = ERC721.ownerOf(tokenId); + return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender)); + } + + /** + * @dev Safely mints `tokenId` and transfers it to `to`. + * + * Requirements: + * + * - `tokenId` must not exist. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function _safeMint(address to, uint256 tokenId) internal virtual { + _safeMint(to, tokenId, ""); + } + + /** + * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is + * forwarded in {IERC721Receiver-onERC721Received} to contract recipients. + */ + function _safeMint(address to, uint256 tokenId, bytes memory _data) internal virtual { + _mint(to, tokenId); + require(_checkOnERC721Received(address(0), to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer"); + } + + /** + * @dev Mints `tokenId` and transfers it to `to`. + * + * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible + * + * Requirements: + * + * - `tokenId` must not exist. + * - `to` cannot be the zero address. + * + * Emits a {Transfer} event. + */ + function _mint(address to, uint256 tokenId) internal virtual { + require(to != address(0), "ERC721: mint to the zero address"); + require(!_exists(tokenId), "ERC721: token already minted"); + + _beforeTokenTransfer(address(0), to, tokenId); + + _balances[to] += 1; + _owners[tokenId] = to; + + emit Transfer(address(0), to, tokenId); + } + + /** + * @dev Destroys `tokenId`. + * The approval is cleared when the token is burned. + * + * Requirements: + * + * - `tokenId` must exist. + * + * Emits a {Transfer} event. + */ + function _burn(uint256 tokenId) internal virtual { + address owner = ERC721.ownerOf(tokenId); + + _beforeTokenTransfer(owner, address(0), tokenId); + + // Clear approvals + _approve(address(0), tokenId); + + _balances[owner] -= 1; + delete _owners[tokenId]; + + emit Transfer(owner, address(0), tokenId); + } + + /** + * @dev Transfers `tokenId` from `from` to `to`. + * As opposed to {transferFrom}, this imposes no restrictions on msg.sender. + * + * Requirements: + * + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * + * Emits a {Transfer} event. + */ + function _transfer(address from, address to, uint256 tokenId) internal virtual { + require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer of token that is not own"); + require(to != address(0), "ERC721: transfer to the zero address"); + + _beforeTokenTransfer(from, to, tokenId); + + // Clear approvals from the previous owner + _approve(address(0), tokenId); + + _balances[from] -= 1; + _balances[to] += 1; + _owners[tokenId] = to; + + emit Transfer(from, to, tokenId); + } + + /** + * @dev Approve `to` to operate on `tokenId` + * + * Emits a {Approval} event. + */ + function _approve(address to, uint256 tokenId) internal virtual { + _tokenApprovals[tokenId] = to; + emit Approval(ERC721.ownerOf(tokenId), to, tokenId); + } + + /** + * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address. + * The call is not executed if the target address is not a contract. + * + * @param from address representing the previous owner of the given token ID + * @param to target address that will receive the tokens + * @param tokenId uint256 ID of the token to be transferred + * @param _data bytes optional data to send along with the call + * @return bool whether the call correctly returned the expected magic value + */ + function _checkOnERC721Received(address from, address to, uint256 tokenId, bytes memory _data) + private returns (bool) + { + if (to.isContract()) { + try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, _data) returns (bytes4 retval) { + return retval == IERC721Receiver(to).onERC721Received.selector; + } catch (bytes memory reason) { + if (reason.length == 0) { + revert("ERC721: transfer to non ERC721Receiver implementer"); + } else { + // solhint-disable-next-line no-inline-assembly + assembly { + revert(add(32, reason), mload(reason)) + } + } + } + } else { + return true; + } + } + + /** + * @dev Hook that is called before any token transfer. This includes minting + * and burning. + * + * Calling conditions: + * + * - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be + * transferred to `to`. + * - When `from` is zero, `tokenId` will be minted for `to`. + * - When `to` is zero, ``from``'s `tokenId` will be burned. + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * + * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. + */ + function _beforeTokenTransfer(address from, address to, uint256 tokenId) internal virtual { } +} \ No newline at end of file diff --git a/contracts/external/ERC721/InitializableERC721.sol b/contracts/external/ERC721/InitializableERC721.sol index 2a7700c..058f0a6 100644 --- a/contracts/external/ERC721/InitializableERC721.sol +++ b/contracts/external/ERC721/InitializableERC721.sol @@ -7,41 +7,9 @@ pragma solidity 0.6.9; -import {IERC721} from "../../intf/IERC721.sol"; -import {IERC721Receiver} from "../../intf/IERC721Receiver.sol"; -import {IERC721Metadata} from "../../intf/IERC721Metadata.sol"; -import {IERC165} from "../../intf/IERC165.sol"; -import {Strings} from "../../lib/Strings.sol"; -import {Address} from "../../lib/Address.sol"; - - -contract InitializableERC721 is IERC165, IERC721, IERC721Metadata { - - using Address for address; - using Strings for uint256; - - // Token name - string private _name; - - // Token symbol - string private _symbol; - - // Base URI - string private _baseURI; - - // Mapping from token ID to owner address - mapping (uint256 => address) private _owners; - - // Mapping owner address to token count - mapping (address => uint256) private _balances; - - // Mapping from token ID to approved address - mapping (uint256 => address) private _tokenApprovals; - - // Mapping from owner to operator approvals - mapping (address => mapping (address => bool)) private _operatorApprovals; - +import {ERC721} from "./ERC721.sol"; +contract InitializableERC1155 is ERC721 { function init( address creator, string memory name, @@ -53,186 +21,4 @@ contract InitializableERC721 is IERC165, IERC721, IERC721Metadata { _baseURI = baseUrI; _mint(creator, 0); } - - - function tokenURI(uint256 tokenId) public view override returns (string memory) { - require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token"); - - string memory baseURI = _baseURI; - return bytes(baseURI).length > 0 - ? string(abi.encodePacked(baseURI, tokenId.toString())) - : ''; - } - - - function supportsInterface(bytes4 interfaceId) public view override returns (bool) { - return interfaceId == type(IERC721).interfaceId - || interfaceId == type(IERC721Metadata).interfaceId; - } - - - function balanceOf(address owner) public view virtual override returns (uint256) { - require(owner != address(0), "ERC721: balance query for the zero address"); - return _balances[owner]; - } - - function ownerOf(uint256 tokenId) public view virtual override returns (address) { - address owner = _owners[tokenId]; - require(owner != address(0), "ERC721: owner query for nonexistent token"); - return owner; - } - - - function name() public view virtual override returns (string memory) { - return _name; - } - - - function symbol() public view virtual override returns (string memory) { - return _symbol; - } - - - function approve(address to, uint256 tokenId) public virtual override { - address owner = ownerOf(tokenId); - require(to != owner, "ERC721: approval to current owner"); - - require(msg.sender == owner || isApprovedForAll(owner, msg.sender), - "ERC721: approve caller is not owner nor approved for all" - ); - - _approve(to, tokenId); - } - - function getApproved(uint256 tokenId) public view virtual override returns (address) { - require(_exists(tokenId), "ERC721: approved query for nonexistent token"); - - return _tokenApprovals[tokenId]; - } - - - function setApprovalForAll(address operator, bool approved) public virtual override { - require(operator != msg.sender, "ERC721: approve to caller"); - - _operatorApprovals[msg.sender][operator] = approved; - emit ApprovalForAll(msg.sender, operator, approved); - } - - function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) { - return _operatorApprovals[owner][operator]; - } - - - function transferFrom(address from, address to, uint256 tokenId) public virtual override { - //solhint-disable-next-line max-line-length - require(_isApprovedOrOwner(msg.sender, tokenId), "ERC721: transfer caller is not owner nor approved"); - - _transfer(from, to, tokenId); - } - - function safeTransferFrom(address from, address to, uint256 tokenId) public virtual override { - safeTransferFrom(from, to, tokenId, ""); - } - - function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory _data) public virtual override { - require(_isApprovedOrOwner(msg.sender, tokenId), "ERC721: transfer caller is not owner nor approved"); - _safeTransfer(from, to, tokenId, _data); - } - - - // =========== internal ================== - - function _safeTransfer(address from, address to, uint256 tokenId, bytes memory _data) internal virtual { - _transfer(from, to, tokenId); - require(_checkOnERC721Received(from, to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer"); - } - - function _exists(uint256 tokenId) internal view virtual returns (bool) { - return _owners[tokenId] != address(0); - } - - function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) { - require(_exists(tokenId), "ERC721: operator query for nonexistent token"); - address owner = ownerOf(tokenId); - return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender)); - } - - function _safeMint(address to, uint256 tokenId) internal virtual { - _safeMint(to, tokenId, ""); - } - - function _safeMint(address to, uint256 tokenId, bytes memory _data) internal virtual { - _mint(to, tokenId); - require(_checkOnERC721Received(address(0), to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer"); - } - - function _mint(address to, uint256 tokenId) internal virtual { - require(to != address(0), "ERC721: mint to the zero address"); - require(!_exists(tokenId), "ERC721: token already minted"); - - _beforeTokenTransfer(address(0), to, tokenId); - - _balances[to] += 1; - _owners[tokenId] = to; - - emit Transfer(address(0), to, tokenId); - } - - function _burn(uint256 tokenId) internal virtual { - address owner = ownerOf(tokenId); - - _beforeTokenTransfer(owner, address(0), tokenId); - - // Clear approvals - _approve(address(0), tokenId); - - _balances[owner] -= 1; - delete _owners[tokenId]; - - emit Transfer(owner, address(0), tokenId); - } - - function _transfer(address from, address to, uint256 tokenId) internal virtual { - require(ownerOf(tokenId) == from, "ERC721: transfer of token that is not own"); - require(to != address(0), "ERC721: transfer to the zero address"); - - _beforeTokenTransfer(from, to, tokenId); - - // Clear approvals from the previous owner - _approve(address(0), tokenId); - - _balances[from] -= 1; - _balances[to] += 1; - _owners[tokenId] = to; - - emit Transfer(from, to, tokenId); - } - - function _approve(address to, uint256 tokenId) internal virtual { - _tokenApprovals[tokenId] = to; - emit Approval(ownerOf(tokenId), to, tokenId); - } - - function _checkOnERC721Received(address from, address to, uint256 tokenId, bytes memory _data) - private returns (bool) - { - if (to.isContract()) { - try IERC721Receiver(to).onERC721Received(msg.sender, from, tokenId, _data) returns (bytes4 retval) { - return retval == IERC721Receiver(to).onERC721Received.selector; - } catch (bytes memory reason) { - if (reason.length == 0) { - revert("ERC721: transfer to non ERC721Receiver implementer"); - } else { - // solhint-disable-next-line no-inline-assembly - assembly { - revert(add(32, reason), mload(reason)) - } - } - } - } else { - return true; - } - } - - function _beforeTokenTransfer(address from, address to, uint256 tokenId) internal virtual { } -} +} \ No newline at end of file diff --git a/contracts/lib/Address.sol b/contracts/external/utils/Address.sol similarity index 100% rename from contracts/lib/Address.sol rename to contracts/external/utils/Address.sol diff --git a/contracts/external/utils/Context.sol b/contracts/external/utils/Context.sol new file mode 100644 index 0000000..3b43ce8 --- /dev/null +++ b/contracts/external/utils/Context.sol @@ -0,0 +1,25 @@ +// This is a file copied from https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/Context.sol +// SPDX-License-Identifier: MIT + +pragma solidity 0.6.9; + +/* + * @dev Provides information about the current execution context, including the + * sender of the transaction and its data. While these are generally available + * via msg.sender and msg.data, they should not be accessed in such a direct + * manner, since when dealing with meta-transactions the account sending and + * paying for execution may not be the actual sender (as far as an application + * is concerned). + * + * This contract is only required for intermediate, library-like contracts. + */ +abstract contract Context { + function _msgSender() internal view virtual returns (address) { + return msg.sender; + } + + function _msgData() internal view virtual returns (bytes calldata) { + this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 + return msg.data; + } +} \ No newline at end of file diff --git a/contracts/external/utils/ERC165.sol b/contracts/external/utils/ERC165.sol new file mode 100644 index 0000000..45b8bff --- /dev/null +++ b/contracts/external/utils/ERC165.sol @@ -0,0 +1,29 @@ +// This is a file copied from https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/introspection/ERC165.sol +// SPDX-License-Identifier: MIT + +pragma solidity 0.6.9; + +import "./IERC165.sol"; + +/** + * @dev Implementation of the {IERC165} interface. + * + * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check + * for the additional interface id that will be supported. For example: + * + * ```solidity + * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); + * } + * ``` + * + * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. + */ +abstract contract ERC165 is IERC165 { + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + return interfaceId == type(IERC165).interfaceId; + } +} \ No newline at end of file diff --git a/contracts/intf/IERC165.sol b/contracts/external/utils/IERC165.sol similarity index 100% rename from contracts/intf/IERC165.sol rename to contracts/external/utils/IERC165.sol diff --git a/contracts/lib/Strings.sol b/contracts/external/utils/Strings.sol similarity index 100% rename from contracts/lib/Strings.sol rename to contracts/external/utils/Strings.sol