diff --git a/ABI.json b/ABI.json old mode 100644 new mode 100755 diff --git a/ERC20/EIP-20.md b/ERC20/EIP-20.md old mode 100644 new mode 100755 diff --git a/ERC20/EtdToken.sol b/ERC20/EtdToken.sol old mode 100644 new mode 100755 diff --git a/ERC20/IERC20.sol b/ERC20/IERC20.sol old mode 100644 new mode 100755 diff --git a/ERC721/eip-721.md b/ERC721/eip-721.md old mode 100644 new mode 100755 diff --git a/ERCTOKEN.md b/ERCTOKEN.md old mode 100644 new mode 100755 diff --git a/ETD_faucet.sol b/ETD_faucet.sol old mode 100644 new mode 100755 diff --git a/History.md b/History.md old mode 100644 new mode 100755 diff --git a/Lock.sol b/Lock.sol old mode 100644 new mode 100755 diff --git a/NFT/1_Storage.sol b/NFT/1_Storage.sol new file mode 100755 index 0000000..2958b79 --- /dev/null +++ b/NFT/1_Storage.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity >=0.7.0 <0.9.0; + +/** + * @title Storage + * @dev Store & retrieve value in a variable + */ +contract Storage { + + uint256 number; + + /** + * @dev Store value in variable + * @param num value to store + */ + function store(uint256 num) public { + number = num; + } + + /** + * @dev Return value + * @return value of 'number' + */ + function retrieve() public view returns (uint256){ + return number; + } +} \ No newline at end of file diff --git a/NFT/2_Owner.sol b/NFT/2_Owner.sol new file mode 100755 index 0000000..601ee32 --- /dev/null +++ b/NFT/2_Owner.sol @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity >=0.7.0 <0.9.0; + +/** + * @title Owner + * @dev Set & change owner + */ +contract Owner { + + address private owner; + + // event for EVM logging + event OwnerSet(address indexed oldOwner, address indexed newOwner); + + // modifier to check if caller is owner + modifier isOwner() { + // If the first argument of 'require' evaluates to 'false', execution terminates and all + // changes to the state and to Ether balances are reverted. + // This used to consume all gas in old EVM versions, but not anymore. + // It is often a good idea to use 'require' to check if functions are called correctly. + // As a second argument, you can also provide an explanation about what went wrong. + require(msg.sender == owner, "Caller is not owner"); + _; + } + + /** + * @dev Set contract deployer as owner + */ + constructor() { + owner = msg.sender; // 'msg.sender' is sender of current call, contract deployer for a constructor + emit OwnerSet(address(0), owner); + } + + /** + * @dev Change owner + * @param newOwner address of new owner + */ + function changeOwner(address newOwner) public isOwner { + emit OwnerSet(owner, newOwner); + owner = newOwner; + } + + /** + * @dev Return owner address + * @return address of owner + */ + function getOwner() external view returns (address) { + return owner; + } +} \ No newline at end of file diff --git a/NFT/3_Ballot.sol b/NFT/3_Ballot.sol new file mode 100755 index 0000000..c47be92 --- /dev/null +++ b/NFT/3_Ballot.sol @@ -0,0 +1,138 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity >=0.7.0 <0.9.0; + +/** + * @title Ballot + * @dev Implements voting process along with vote delegation + */ +contract Ballot { + + struct Voter { + uint weight; // weight is accumulated by delegation + bool voted; // if true, that person already voted + address delegate; // person delegated to + uint vote; // index of the voted proposal + } + + struct Proposal { + // If you can limit the length to a certain number of bytes, + // always use one of bytes1 to bytes32 because they are much cheaper + bytes32 name; // short name (up to 32 bytes) + uint voteCount; // number of accumulated votes + } + + address public chairperson; + + mapping(address => Voter) public voters; + + Proposal[] public proposals; + + /** + * @dev Create a new ballot to choose one of 'proposalNames'. + * @param proposalNames names of proposals + */ + constructor(bytes32[] memory proposalNames) { + chairperson = msg.sender; + voters[chairperson].weight = 1; + + for (uint i = 0; i < proposalNames.length; i++) { + // 'Proposal({...})' creates a temporary + // Proposal object and 'proposals.push(...)' + // appends it to the end of 'proposals'. + proposals.push(Proposal({ + name: proposalNames[i], + voteCount: 0 + })); + } + } + + /** + * @dev Give 'voter' the right to vote on this ballot. May only be called by 'chairperson'. + * @param voter address of voter + */ + function giveRightToVote(address voter) public { + require( + msg.sender == chairperson, + "Only chairperson can give right to vote." + ); + require( + !voters[voter].voted, + "The voter already voted." + ); + require(voters[voter].weight == 0); + voters[voter].weight = 1; + } + + /** + * @dev Delegate your vote to the voter 'to'. + * @param to address to which vote is delegated + */ + function delegate(address to) public { + Voter storage sender = voters[msg.sender]; + require(!sender.voted, "You already voted."); + require(to != msg.sender, "Self-delegation is disallowed."); + + while (voters[to].delegate != address(0)) { + to = voters[to].delegate; + + // We found a loop in the delegation, not allowed. + require(to != msg.sender, "Found loop in delegation."); + } + sender.voted = true; + sender.delegate = to; + Voter storage delegate_ = voters[to]; + if (delegate_.voted) { + // If the delegate already voted, + // directly add to the number of votes + proposals[delegate_.vote].voteCount += sender.weight; + } else { + // If the delegate did not vote yet, + // add to her weight. + delegate_.weight += sender.weight; + } + } + + /** + * @dev Give your vote (including votes delegated to you) to proposal 'proposals[proposal].name'. + * @param proposal index of proposal in the proposals array + */ + function vote(uint proposal) public { + Voter storage sender = voters[msg.sender]; + require(sender.weight != 0, "Has no right to vote"); + require(!sender.voted, "Already voted."); + sender.voted = true; + sender.vote = proposal; + + // If 'proposal' is out of the range of the array, + // this will throw automatically and revert all + // changes. + proposals[proposal].voteCount += sender.weight; + } + + /** + * @dev Computes the winning proposal taking all previous votes into account. + * @return winningProposal_ index of winning proposal in the proposals array + */ + function winningProposal() public view + returns (uint winningProposal_) + { + uint winningVoteCount = 0; + for (uint p = 0; p < proposals.length; p++) { + if (proposals[p].voteCount > winningVoteCount) { + winningVoteCount = proposals[p].voteCount; + winningProposal_ = p; + } + } + } + + /** + * @dev Calls winningProposal() function to get the index of the winner contained in the proposals array and then + * @return winnerName_ the name of the winner + */ + function winnerName() public view + returns (bytes32 winnerName_) + { + winnerName_ = proposals[winningProposal()].name; + } +} diff --git a/NFT/721token.sol b/NFT/721token.sol new file mode 100755 index 0000000..b442429 --- /dev/null +++ b/NFT/721token.sol @@ -0,0 +1,1021 @@ +/** + *Submitted for verification at Etherscan.io on 2018-11-09 +*/ + +pragma solidity ^0.4.24; + +// File: openzeppelin-solidity/contracts/introspection/ERC165.sol + +/** + * @title ERC165 + * @dev https://github.com/ethereum/EIPs/blob/master/EIPS/eip-165.md + */ +interface ERC165 { + + /** + * @notice Query if a contract implements an interface + * @param _interfaceId The interface identifier, as specified in ERC-165 + * @dev Interface identification is specified in ERC-165. This function + * uses less than 30,000 gas. + */ + function supportsInterface(bytes4 _interfaceId) + external + view + returns (bool); +} + +// File: openzeppelin-solidity/contracts/token/ERC721/ERC721Basic.sol + +/** + * @title ERC721 Non-Fungible Token Standard basic interface + * @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md + */ +contract ERC721Basic is ERC165 { + + bytes4 internal constant InterfaceId_ERC721 = 0x80ac58cd; + /* + * 0x80ac58cd === + * bytes4(keccak256('balanceOf(address)')) ^ + * bytes4(keccak256('ownerOf(uint256)')) ^ + * bytes4(keccak256('approve(address,uint256)')) ^ + * bytes4(keccak256('getApproved(uint256)')) ^ + * bytes4(keccak256('setApprovalForAll(address,bool)')) ^ + * bytes4(keccak256('isApprovedForAll(address,address)')) ^ + * bytes4(keccak256('transferFrom(address,address,uint256)')) ^ + * bytes4(keccak256('safeTransferFrom(address,address,uint256)')) ^ + * bytes4(keccak256('safeTransferFrom(address,address,uint256,bytes)')) + */ + + bytes4 internal constant InterfaceId_ERC721Exists = 0x4f558e79; + /* + * 0x4f558e79 === + * bytes4(keccak256('exists(uint256)')) + */ + + bytes4 internal constant InterfaceId_ERC721Enumerable = 0x780e9d63; + /** + * 0x780e9d63 === + * bytes4(keccak256('totalSupply()')) ^ + * bytes4(keccak256('tokenOfOwnerByIndex(address,uint256)')) ^ + * bytes4(keccak256('tokenByIndex(uint256)')) + */ + + bytes4 internal constant InterfaceId_ERC721Metadata = 0x5b5e139f; + /** + * 0x5b5e139f === + * bytes4(keccak256('name()')) ^ + * bytes4(keccak256('symbol()')) ^ + * bytes4(keccak256('tokenURI(uint256)')) + */ + + event Transfer( + address indexed _from, + address indexed _to, + uint256 indexed _tokenId + ); + event Approval( + address indexed _owner, + address indexed _approved, + uint256 indexed _tokenId + ); + event ApprovalForAll( + address indexed _owner, + address indexed _operator, + bool _approved + ); + + function balanceOf(address _owner) public view returns (uint256 _balance); + function ownerOf(uint256 _tokenId) public view returns (address _owner); + function exists(uint256 _tokenId) public view returns (bool _exists); + + function approve(address _to, uint256 _tokenId) public; + function getApproved(uint256 _tokenId) + public view returns (address _operator); + + function setApprovalForAll(address _operator, bool _approved) public; + function isApprovedForAll(address _owner, address _operator) + public view returns (bool); + + function transferFrom(address _from, address _to, uint256 _tokenId) public; + function safeTransferFrom(address _from, address _to, uint256 _tokenId) + public; + + function safeTransferFrom( + address _from, + address _to, + uint256 _tokenId, + bytes _data + ) + public; +} + +// File: openzeppelin-solidity/contracts/token/ERC721/ERC721.sol + +/** + * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension + * @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md + */ +contract ERC721Enumerable is ERC721Basic { + function totalSupply() public view returns (uint256); + function tokenOfOwnerByIndex( + address _owner, + uint256 _index + ) + public + view + returns (uint256 _tokenId); + + function tokenByIndex(uint256 _index) public view returns (uint256); +} + + +/** + * @title ERC-721 Non-Fungible Token Standard, optional metadata extension + * @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md + */ +contract ERC721Metadata is ERC721Basic { + function name() external view returns (string _name); + function symbol() external view returns (string _symbol); + function tokenURI(uint256 _tokenId) public view returns (string); +} + + +/** + * @title ERC-721 Non-Fungible Token Standard, full implementation interface + * @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md + */ +contract ERC721 is ERC721Basic, ERC721Enumerable, ERC721Metadata { +} + +// File: openzeppelin-solidity/contracts/token/ERC721/ERC721Receiver.sol + +/** + * @title ERC721 token receiver interface + * @dev Interface for any contract that wants to support safeTransfers + * from ERC721 asset contracts. + */ +contract ERC721Receiver { + /** + * @dev Magic value to be returned upon successful reception of an NFT + * Equals to `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`, + * which can be also obtained as `ERC721Receiver(0).onERC721Received.selector` + */ + bytes4 internal constant ERC721_RECEIVED = 0x150b7a02; + + /** + * @notice Handle the receipt of an NFT + * @dev The ERC721 smart contract calls this function on the recipient + * after a `safetransfer`. This function MAY throw to revert and reject the + * transfer. Return of other than the magic value MUST result in the + * transaction being reverted. + * Note: the contract address is always the message sender. + * @param _operator The address which called `safeTransferFrom` function + * @param _from The address which previously owned the token + * @param _tokenId The NFT identifier which is being transferred + * @param _data Additional data with no specified format + * @return `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))` + */ + function onERC721Received( + address _operator, + address _from, + uint256 _tokenId, + bytes _data + ) + public + returns(bytes4); +} + +// File: openzeppelin-solidity/contracts/math/SafeMath.sol + +/** + * @title SafeMath + * @dev Math operations with safety checks that throw on error + */ +library SafeMath { + + /** + * @dev Multiplies two numbers, throws on overflow. + */ + function mul(uint256 _a, uint256 _b) internal pure returns (uint256 c) { + // Gas optimization: this is cheaper than asserting 'a' not being zero, but the + // benefit is lost if 'b' is also tested. + // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522 + if (_a == 0) { + return 0; + } + + c = _a * _b; + assert(c / _a == _b); + return c; + } + + /** + * @dev Integer division of two numbers, truncating the quotient. + */ + function div(uint256 _a, uint256 _b) internal pure returns (uint256) { + // assert(_b > 0); // Solidity automatically throws when dividing by 0 + // uint256 c = _a / _b; + // assert(_a == _b * c + _a % _b); // There is no case in which this doesn't hold + return _a / _b; + } + + /** + * @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend). + */ + function sub(uint256 _a, uint256 _b) internal pure returns (uint256) { + assert(_b <= _a); + return _a - _b; + } + + /** + * @dev Adds two numbers, throws on overflow. + */ + function add(uint256 _a, uint256 _b) internal pure returns (uint256 c) { + c = _a + _b; + assert(c >= _a); + return c; + } +} + +// File: openzeppelin-solidity/contracts/AddressUtils.sol + +/** + * Utility library of inline functions on addresses + */ +library AddressUtils { + + /** + * Returns whether the target address is a contract + * @dev This function will return false if invoked during the constructor of a contract, + * as the code is not actually created until after the constructor finishes. + * @param _addr address to check + * @return whether the target address is a contract + */ + function isContract(address _addr) internal view returns (bool) { + uint256 size; + // XXX Currently there is no better way to check if there is a contract in an address + // than to check the size of the code at that address. + // See https://ethereum.stackexchange.com/a/14016/36603 + // for more details about how this works. + // TODO Check this again before the Serenity release, because all addresses will be + // contracts then. + // solium-disable-next-line security/no-inline-assembly + assembly { size := extcodesize(_addr) } + return size > 0; + } + +} + +// File: openzeppelin-solidity/contracts/introspection/SupportsInterfaceWithLookup.sol + +/** + * @title SupportsInterfaceWithLookup + * @author Matt Condon (@shrugs) + * @dev Implements ERC165 using a lookup table. + */ +contract SupportsInterfaceWithLookup is ERC165 { + + bytes4 public constant InterfaceId_ERC165 = 0x01ffc9a7; + /** + * 0x01ffc9a7 === + * bytes4(keccak256('supportsInterface(bytes4)')) + */ + + /** + * @dev a mapping of interface id to whether or not it's supported + */ + mapping(bytes4 => bool) internal supportedInterfaces; + + /** + * @dev A contract implementing SupportsInterfaceWithLookup + * implement ERC165 itself + */ + constructor() + public + { + _registerInterface(InterfaceId_ERC165); + } + + /** + * @dev implement supportsInterface(bytes4) using a lookup table + */ + function supportsInterface(bytes4 _interfaceId) + external + view + returns (bool) + { + return supportedInterfaces[_interfaceId]; + } + + /** + * @dev private method for registering an interface + */ + function _registerInterface(bytes4 _interfaceId) + internal + { + require(_interfaceId != 0xffffffff); + supportedInterfaces[_interfaceId] = true; + } +} + +// File: openzeppelin-solidity/contracts/token/ERC721/ERC721BasicToken.sol + +/** + * @title ERC721 Non-Fungible Token Standard basic implementation + * @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md + */ +contract ERC721BasicToken is SupportsInterfaceWithLookup, ERC721Basic { + + using SafeMath for uint256; + using AddressUtils for address; + + // Equals to `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))` + // which can be also obtained as `ERC721Receiver(0).onERC721Received.selector` + bytes4 private constant ERC721_RECEIVED = 0x150b7a02; + + // Mapping from token ID to owner + mapping (uint256 => address) internal tokenOwner; + + // Mapping from token ID to approved address + mapping (uint256 => address) internal tokenApprovals; + + // Mapping from owner to number of owned token + mapping (address => uint256) internal ownedTokensCount; + + // Mapping from owner to operator approvals + mapping (address => mapping (address => bool)) internal operatorApprovals; + + constructor() + public + { + // register the supported interfaces to conform to ERC721 via ERC165 + _registerInterface(InterfaceId_ERC721); + _registerInterface(InterfaceId_ERC721Exists); + } + + /** + * @dev Gets the balance of the specified address + * @param _owner address to query the balance of + * @return uint256 representing the amount owned by the passed address + */ + function balanceOf(address _owner) public view returns (uint256) { + require(_owner != address(0)); + return ownedTokensCount[_owner]; + } + + /** + * @dev Gets the owner of the specified token ID + * @param _tokenId uint256 ID of the token to query the owner of + * @return owner address currently marked as the owner of the given token ID + */ + function ownerOf(uint256 _tokenId) public view returns (address) { + address owner = tokenOwner[_tokenId]; + require(owner != address(0)); + return owner; + } + + /** + * @dev Returns whether the specified token exists + * @param _tokenId uint256 ID of the token to query the existence of + * @return whether the token exists + */ + function exists(uint256 _tokenId) public view returns (bool) { + address owner = tokenOwner[_tokenId]; + return owner != address(0); + } + + /** + * @dev Approves another address to transfer the given token ID + * The zero address indicates there is no approved address. + * There can only be one approved address per token at a given time. + * Can only be called by the token owner or an approved operator. + * @param _to address to be approved for the given token ID + * @param _tokenId uint256 ID of the token to be approved + */ + function approve(address _to, uint256 _tokenId) public { + address owner = ownerOf(_tokenId); + require(_to != owner); + require(msg.sender == owner || isApprovedForAll(owner, msg.sender)); + + tokenApprovals[_tokenId] = _to; + emit Approval(owner, _to, _tokenId); + } + + /** + * @dev Gets the approved address for a token ID, or zero if no address set + * @param _tokenId uint256 ID of the token to query the approval of + * @return address currently approved for the given token ID + */ + function getApproved(uint256 _tokenId) public view returns (address) { + return tokenApprovals[_tokenId]; + } + + /** + * @dev Sets or unsets the approval of a given operator + * An operator is allowed to transfer all tokens of the sender on their behalf + * @param _to operator address to set the approval + * @param _approved representing the status of the approval to be set + */ + function setApprovalForAll(address _to, bool _approved) public { + require(_to != msg.sender); + operatorApprovals[msg.sender][_to] = _approved; + emit ApprovalForAll(msg.sender, _to, _approved); + } + + /** + * @dev Tells whether an operator is approved by a given owner + * @param _owner owner address which you want to query the approval of + * @param _operator operator address which you want to query the approval of + * @return bool whether the given operator is approved by the given owner + */ + function isApprovedForAll( + address _owner, + address _operator + ) + public + view + returns (bool) + { + return operatorApprovals[_owner][_operator]; + } + + /** + * @dev Transfers the ownership of a given token ID to another address + * Usage of this method is discouraged, use `safeTransferFrom` whenever possible + * Requires the msg sender to be the owner, approved, or operator + * @param _from current owner of the token + * @param _to address to receive the ownership of the given token ID + * @param _tokenId uint256 ID of the token to be transferred + */ + function transferFrom( + address _from, + address _to, + uint256 _tokenId + ) + public + { + require(isApprovedOrOwner(msg.sender, _tokenId)); + require(_from != address(0)); + require(_to != address(0)); + + clearApproval(_from, _tokenId); + removeTokenFrom(_from, _tokenId); + addTokenTo(_to, _tokenId); + + emit Transfer(_from, _to, _tokenId); + } + + /** + * @dev Safely transfers the ownership of a given token ID to another address + * If the target address is a contract, it must implement `onERC721Received`, + * which is called upon a safe transfer, and return the magic value + * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise, + * the transfer is reverted. + * + * Requires the msg sender to be the owner, approved, or operator + * @param _from current owner of the token + * @param _to address to receive the ownership of the given token ID + * @param _tokenId uint256 ID of the token to be transferred + */ + function safeTransferFrom( + address _from, + address _to, + uint256 _tokenId + ) + public + { + // solium-disable-next-line arg-overflow + safeTransferFrom(_from, _to, _tokenId, ""); + } + + /** + * @dev Safely transfers the ownership of a given token ID to another address + * If the target address is a contract, it must implement `onERC721Received`, + * which is called upon a safe transfer, and return the magic value + * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise, + * the transfer is reverted. + * Requires the msg sender to be the owner, approved, or operator + * @param _from current owner of the token + * @param _to address to receive the ownership of the given token ID + * @param _tokenId uint256 ID of the token to be transferred + * @param _data bytes data to send along with a safe transfer check + */ + function safeTransferFrom( + address _from, + address _to, + uint256 _tokenId, + bytes _data + ) + public + { + transferFrom(_from, _to, _tokenId); + // solium-disable-next-line arg-overflow + require(checkAndCallSafeTransfer(_from, _to, _tokenId, _data)); + } + + /** + * @dev Returns whether the given spender can transfer a given token ID + * @param _spender address of the spender to query + * @param _tokenId uint256 ID of the token to be transferred + * @return bool whether the msg.sender is approved for the given token ID, + * is an operator of the owner, or is the owner of the token + */ + function isApprovedOrOwner( + address _spender, + uint256 _tokenId + ) + internal + view + returns (bool) + { + address owner = ownerOf(_tokenId); + // Disable solium check because of + // https://github.com/duaraghav8/Solium/issues/175 + // solium-disable-next-line operator-whitespace + return ( + _spender == owner || + getApproved(_tokenId) == _spender || + isApprovedForAll(owner, _spender) + ); + } + + /** + * @dev Internal function to mint a new token + * Reverts if the given token ID already exists + * @param _to The address that will own the minted token + * @param _tokenId uint256 ID of the token to be minted by the msg.sender + */ + function _mint(address _to, uint256 _tokenId) internal { + require(_to != address(0)); + addTokenTo(_to, _tokenId); + emit Transfer(address(0), _to, _tokenId); + } + + /** + * @dev Internal function to burn a specific token + * Reverts if the token does not exist + * @param _tokenId uint256 ID of the token being burned by the msg.sender + */ + function _burn(address _owner, uint256 _tokenId) internal { + clearApproval(_owner, _tokenId); + removeTokenFrom(_owner, _tokenId); + emit Transfer(_owner, address(0), _tokenId); + } + + /** + * @dev Internal function to clear current approval of a given token ID + * Reverts if the given address is not indeed the owner of the token + * @param _owner owner of the token + * @param _tokenId uint256 ID of the token to be transferred + */ + function clearApproval(address _owner, uint256 _tokenId) internal { + require(ownerOf(_tokenId) == _owner); + if (tokenApprovals[_tokenId] != address(0)) { + tokenApprovals[_tokenId] = address(0); + } + } + + /** + * @dev Internal function to add a token ID to the list of a given address + * @param _to address representing the new owner of the given token ID + * @param _tokenId uint256 ID of the token to be added to the tokens list of the given address + */ + function addTokenTo(address _to, uint256 _tokenId) internal { + require(tokenOwner[_tokenId] == address(0)); + tokenOwner[_tokenId] = _to; + ownedTokensCount[_to] = ownedTokensCount[_to].add(1); + } + + /** + * @dev Internal function to remove a token ID from the list of a given address + * @param _from address representing the previous owner of the given token ID + * @param _tokenId uint256 ID of the token to be removed from the tokens list of the given address + */ + function removeTokenFrom(address _from, uint256 _tokenId) internal { + require(ownerOf(_tokenId) == _from); + ownedTokensCount[_from] = ownedTokensCount[_from].sub(1); + tokenOwner[_tokenId] = address(0); + } + + /** + * @dev Internal function to invoke `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 whether the call correctly returned the expected magic value + */ + function checkAndCallSafeTransfer( + address _from, + address _to, + uint256 _tokenId, + bytes _data + ) + internal + returns (bool) + { + if (!_to.isContract()) { + return true; + } + bytes4 retval = ERC721Receiver(_to).onERC721Received( + msg.sender, _from, _tokenId, _data); + return (retval == ERC721_RECEIVED); + } +} + +// File: openzeppelin-solidity/contracts/token/ERC721/ERC721Token.sol + +/** + * @title Full ERC721 Token + * This implementation includes all the required and some optional functionality of the ERC721 standard + * Moreover, it includes approve all functionality using operator terminology + * @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md + */ +contract ERC721Token is SupportsInterfaceWithLookup, ERC721BasicToken, ERC721 { + + // Token name + string internal name_; + + // Token symbol + string internal symbol_; + + // Mapping from owner to list of owned token IDs + mapping(address => uint256[]) internal ownedTokens; + + // Mapping from token ID to index of the owner tokens list + mapping(uint256 => uint256) internal ownedTokensIndex; + + // Array with all token ids, used for enumeration + uint256[] internal allTokens; + + // Mapping from token id to position in the allTokens array + mapping(uint256 => uint256) internal allTokensIndex; + + // Optional mapping for token URIs + mapping(uint256 => string) internal tokenURIs; + + /** + * @dev Constructor function + */ + constructor(string _name, string _symbol) public { + name_ = _name; + symbol_ = _symbol; + + // register the supported interfaces to conform to ERC721 via ERC165 + _registerInterface(InterfaceId_ERC721Enumerable); + _registerInterface(InterfaceId_ERC721Metadata); + } + + /** + * @dev Gets the token name + * @return string representing the token name + */ + function name() external view returns (string) { + return name_; + } + + /** + * @dev Gets the token symbol + * @return string representing the token symbol + */ + function symbol() external view returns (string) { + return symbol_; + } + + /** + * @dev Returns an URI for a given token ID + * Throws if the token ID does not exist. May return an empty string. + * @param _tokenId uint256 ID of the token to query + */ + function tokenURI(uint256 _tokenId) public view returns (string) { + require(exists(_tokenId)); + return tokenURIs[_tokenId]; + } + + /** + * @dev Gets the token ID at a given index of the tokens list of the requested owner + * @param _owner address owning the tokens list to be accessed + * @param _index uint256 representing the index to be accessed of the requested tokens list + * @return uint256 token ID at the given index of the tokens list owned by the requested address + */ + function tokenOfOwnerByIndex( + address _owner, + uint256 _index + ) + public + view + returns (uint256) + { + require(_index < balanceOf(_owner)); + return ownedTokens[_owner][_index]; + } + + /** + * @dev Gets the total amount of tokens stored by the contract + * @return uint256 representing the total amount of tokens + */ + function totalSupply() public view returns (uint256) { + return allTokens.length; + } + + /** + * @dev Gets the token ID at a given index of all the tokens in this contract + * Reverts if the index is greater or equal to the total number of tokens + * @param _index uint256 representing the index to be accessed of the tokens list + * @return uint256 token ID at the given index of the tokens list + */ + function tokenByIndex(uint256 _index) public view returns (uint256) { + require(_index < totalSupply()); + return allTokens[_index]; + } + + /** + * @dev Internal function to set the token URI for a given token + * Reverts if the token ID does not exist + * @param _tokenId uint256 ID of the token to set its URI + * @param _uri string URI to assign + */ + function _setTokenURI(uint256 _tokenId, string _uri) internal { + require(exists(_tokenId)); + tokenURIs[_tokenId] = _uri; + } + + /** + * @dev Internal function to add a token ID to the list of a given address + * @param _to address representing the new owner of the given token ID + * @param _tokenId uint256 ID of the token to be added to the tokens list of the given address + */ + function addTokenTo(address _to, uint256 _tokenId) internal { + super.addTokenTo(_to, _tokenId); + uint256 length = ownedTokens[_to].length; + ownedTokens[_to].push(_tokenId); + ownedTokensIndex[_tokenId] = length; + } + + /** + * @dev Internal function to remove a token ID from the list of a given address + * @param _from address representing the previous owner of the given token ID + * @param _tokenId uint256 ID of the token to be removed from the tokens list of the given address + */ + function removeTokenFrom(address _from, uint256 _tokenId) internal { + super.removeTokenFrom(_from, _tokenId); + + // To prevent a gap in the array, we store the last token in the index of the token to delete, and + // then delete the last slot. + uint256 tokenIndex = ownedTokensIndex[_tokenId]; + uint256 lastTokenIndex = ownedTokens[_from].length.sub(1); + uint256 lastToken = ownedTokens[_from][lastTokenIndex]; + + ownedTokens[_from][tokenIndex] = lastToken; + // This also deletes the contents at the last position of the array + ownedTokens[_from].length--; + + // Note that this will handle single-element arrays. In that case, both tokenIndex and lastTokenIndex are going to + // be zero. Then we can make sure that we will remove _tokenId from the ownedTokens list since we are first swapping + // the lastToken to the first position, and then dropping the element placed in the last position of the list + + ownedTokensIndex[_tokenId] = 0; + ownedTokensIndex[lastToken] = tokenIndex; + } + + /** + * @dev Internal function to mint a new token + * Reverts if the given token ID already exists + * @param _to address the beneficiary that will own the minted token + * @param _tokenId uint256 ID of the token to be minted by the msg.sender + */ + function _mint(address _to, uint256 _tokenId) internal { + super._mint(_to, _tokenId); + + allTokensIndex[_tokenId] = allTokens.length; + allTokens.push(_tokenId); + } + + /** + * @dev Internal function to burn a specific token + * Reverts if the token does not exist + * @param _owner owner of the token to burn + * @param _tokenId uint256 ID of the token being burned by the msg.sender + */ + function _burn(address _owner, uint256 _tokenId) internal { + super._burn(_owner, _tokenId); + + // Clear metadata (if any) + if (bytes(tokenURIs[_tokenId]).length != 0) { + delete tokenURIs[_tokenId]; + } + + // Reorg all tokens array + uint256 tokenIndex = allTokensIndex[_tokenId]; + uint256 lastTokenIndex = allTokens.length.sub(1); + uint256 lastToken = allTokens[lastTokenIndex]; + + allTokens[tokenIndex] = lastToken; + allTokens[lastTokenIndex] = 0; + + allTokens.length--; + allTokensIndex[_tokenId] = 0; + allTokensIndex[lastToken] = tokenIndex; + } + +} + +// File: openzeppelin-solidity/contracts/ownership/Ownable.sol + +/** + * @title Ownable + * @dev The Ownable contract has an owner address, and provides basic authorization control + * functions, this simplifies the implementation of "user permissions". + */ +contract Ownable { + address public owner; + + + event OwnershipRenounced(address indexed previousOwner); + event OwnershipTransferred( + address indexed previousOwner, + address indexed newOwner + ); + + + /** + * @dev The Ownable constructor sets the original `owner` of the contract to the sender + * account. + */ + constructor() public { + owner = msg.sender; + } + + /** + * @dev Throws if called by any account other than the owner. + */ + modifier onlyOwner() { + require(msg.sender == owner); + _; + } + + /** + * @dev Allows the current owner to relinquish control of the contract. + * @notice Renouncing to ownership will leave the contract without an owner. + * It will not be possible to call the functions with the `onlyOwner` + * modifier anymore. + */ + function renounceOwnership() public onlyOwner { + emit OwnershipRenounced(owner); + owner = address(0); + } + + /** + * @dev Allows the current owner to transfer control of the contract to a newOwner. + * @param _newOwner The address to transfer ownership to. + */ + function transferOwnership(address _newOwner) public onlyOwner { + _transferOwnership(_newOwner); + } + + /** + * @dev Transfers control of the contract to a newOwner. + * @param _newOwner The address to transfer ownership to. + */ + function _transferOwnership(address _newOwner) internal { + require(_newOwner != address(0)); + emit OwnershipTransferred(owner, _newOwner); + owner = _newOwner; + } +} + +// File: contracts/Strings.sol + +library Strings { + // via https://github.com/oraclize/ethereum-api/blob/master/oraclizeAPI_0.5.sol + function strConcat(string _a, string _b, string _c, string _d, string _e) internal pure returns (string) { + bytes memory _ba = bytes(_a); + bytes memory _bb = bytes(_b); + bytes memory _bc = bytes(_c); + bytes memory _bd = bytes(_d); + bytes memory _be = bytes(_e); + string memory abcde = new string(_ba.length + _bb.length + _bc.length + _bd.length + _be.length); + bytes memory babcde = bytes(abcde); + uint k = 0; + for (uint i = 0; i < _ba.length; i++) babcde[k++] = _ba[i]; + for (i = 0; i < _bb.length; i++) babcde[k++] = _bb[i]; + for (i = 0; i < _bc.length; i++) babcde[k++] = _bc[i]; + for (i = 0; i < _bd.length; i++) babcde[k++] = _bd[i]; + for (i = 0; i < _be.length; i++) babcde[k++] = _be[i]; + return string(babcde); + } + + function strConcat(string _a, string _b, string _c, string _d) internal pure returns (string) { + return strConcat(_a, _b, _c, _d, ""); + } + + function strConcat(string _a, string _b, string _c) internal pure returns (string) { + return strConcat(_a, _b, _c, "", ""); + } + + function strConcat(string _a, string _b) internal pure returns (string) { + return strConcat(_a, _b, "", "", ""); + } + + function uint2str(uint i) internal pure returns (string) { + if (i == 0) return "0"; + uint j = i; + uint len; + while (j != 0){ + len++; + j /= 10; + } + bytes memory bstr = new bytes(len); + uint k = len - 1; + while (i != 0){ + bstr[k--] = byte(48 + i % 10); + i /= 10; + } + return string(bstr); + } +} + +// File: contracts/TradeableERC721Token.sol + +contract OwnableDelegateProxy { } + +contract ProxyRegistry { + mapping(address => OwnableDelegateProxy) public proxies; +} + +/** + * @title TradeableERC721Token + * TradeableERC721Token - ERC721 contract that whitelists a trading address, and has minting functionality. + */ +contract TradeableERC721Token is ERC721Token, Ownable { + using Strings for string; + + address proxyRegistryAddress; + + constructor(string _name, string _symbol, address _proxyRegistryAddress) ERC721Token(_name, _symbol) public { + proxyRegistryAddress = _proxyRegistryAddress; + } + + /** + * @dev Mints a token to an address with a tokenURI. + * @param _to address of the future owner of the token + */ + function mintTo(address _to) public onlyOwner { + uint256 newTokenId = _getNextTokenId(); + _mint(_to, newTokenId); + } + + /** + * @dev calculates the next token ID based on totalSupply + * @return uint256 for the next token ID + */ + function _getNextTokenId() private view returns (uint256) { + return totalSupply().add(1); + } + + function baseTokenURI() public pure returns (string) { + return ""; + } + + function tokenURI(uint256 _tokenId) public view returns (string) { + return Strings.strConcat( + baseTokenURI(), + Strings.uint2str(_tokenId) + ); + } + + /** + * Override isApprovedForAll to whitelist user's OpenSea proxy accounts to enable gas-less listings. + */ + function isApprovedForAll( + address owner, + address operator + ) + public + view + returns (bool) + { + // Whitelist OpenSea proxy contract for easy trading. + ProxyRegistry proxyRegistry = ProxyRegistry(proxyRegistryAddress); + if (proxyRegistry.proxies(owner) == operator) { + return true; + } + + return super.isApprovedForAll(owner, operator); + } +} + +// File: contracts/Creature.sol + +/** + * @title Creature + * Creature - a contract for my non-fungible creatures. + */ +contract Creature is TradeableERC721Token { + constructor(address _proxyRegistryAddress) TradeableERC721Token("Creature", "OSC", _proxyRegistryAddress) public { } + + function baseTokenURI() public pure returns (string) { + return "1/"; + } +} \ No newline at end of file diff --git a/NFT/Address.sol b/NFT/Address.sol new file mode 100755 index 0000000..9f4777c --- /dev/null +++ b/NFT/Address.sol @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + + +/** + * Utility library of inline functions on addresses + */ +library Address { + + /** + * Returns whether the target address is a contract + * @dev This function will return false if invoked during the constructor of a contract, + * as the code is not actually created until after the constructor finishes. + * @param account address of the account to check + * @return whether the target address is a contract + */ + function isContract(address account) internal view returns (bool) { + uint256 size; + // XXX Currently there is no better way to check if there is a contract in an address + // than to check the size of the code at that address. + // See https://ethereum.stackexchange.com/a/14016/36603 + // for more details about how this works. + // TODO Check this again before the Serenity release, because all addresses will be + // contracts then. + // solium-disable-next-line security/no-inline-assembly + assembly { size := extcodesize(account) } + return size > 0; + } + +} \ No newline at end of file diff --git a/NFT/Common.sol b/NFT/Common.sol new file mode 100755 index 0000000..8cb610b --- /dev/null +++ b/NFT/Common.sol @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +/** + Note: Simple contract to use as base for const vals +*/ +contract CommonConstants { + + bytes4 constant internal ERC1155_ACCEPTED = 0xf23a6e61; // bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)")) + bytes4 constant internal ERC1155_BATCH_ACCEPTED = 0xbc197c81; // bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)")) +} \ No newline at end of file diff --git a/NFT/ERC1155.sol b/NFT/ERC1155.sol new file mode 100755 index 0000000..3db0f01 --- /dev/null +++ b/NFT/ERC1155.sol @@ -0,0 +1,234 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "./SafeMath.sol"; +import "./Address.sol"; +import "./Common.sol"; +import "./IERC1155TokenReceiver.sol"; +import "./IERC1155.sol"; +import "./ERC165.sol"; +import "./IERC1155Metadata.sol"; + +// A sample implementation of core ERC1155 function. +contract ERC1155 is IERC1155, ERC165, CommonConstants +{ + using SafeMath for uint256; + using Address for address; + + // id => (owner => balance) + mapping (uint256 => mapping(address => uint256)) internal balances; + + // owner => (operator => approved) + mapping (address => mapping(address => bool)) internal operatorApproval; + +/////////////////////////////////////////// ERC165 ////////////////////////////////////////////// + + /* + bytes4(keccak256('supportsInterface(bytes4)')); + */ + bytes4 constant private INTERFACE_SIGNATURE_ERC165 = 0x01ffc9a7; + + /* + bytes4(keccak256("safeTransferFrom(address,address,uint256,uint256,bytes)")) ^ + bytes4(keccak256("safeBatchTransferFrom(address,address,uint256[],uint256[],bytes)")) ^ + bytes4(keccak256("balanceOf(address,uint256)")) ^ + bytes4(keccak256("balanceOfBatch(address[],uint256[])")) ^ + bytes4(keccak256("setApprovalForAll(address,bool)")) ^ + bytes4(keccak256("isApprovedForAll(address,address)")); + */ + bytes4 constant private INTERFACE_SIGNATURE_ERC1155 = 0xd9b67a26; + + function supportsInterface(bytes4 _interfaceId) external pure returns (bool) { + if (_interfaceId == INTERFACE_SIGNATURE_ERC165 || + _interfaceId == INTERFACE_SIGNATURE_ERC1155) { + return true; + } + + return false; + } + +/////////////////////////////////////////// ERC1155 ////////////////////////////////////////////// + + /** + @notice Transfers `_value` amount of an `_id` from the `_from` address to the `_to` address specified (with safety call). + @dev Caller must be approved to manage the tokens being transferred out of the `_from` account (see "Approval" section of the standard). + MUST revert if `_to` is the zero address. + MUST revert if balance of holder for token `_id` is lower than the `_value` sent. + MUST revert on any other error. + MUST emit the `TransferSingle` event to reflect the balance change (see "Safe Transfer Rules" section of the standard). + After the above conditions are met, this function MUST check if `_to` is a smart contract (e.g. code size > 0). If so, it MUST call `onERC1155Received` on `_to` and act appropriately (see "Safe Transfer Rules" section of the standard). + @param _from Source address + @param _to Target address + @param _id ID of the token type + @param _value Transfer amount + @param _data Additional data with no specified format, MUST be sent unaltered in call to `onERC1155Received` on `_to` + */ + function safeTransferFrom(address _from, address _to, uint256 _id, uint256 _value, bytes calldata _data) external { + + require(_to != address(0x0), "_to must be non-zero."); + require(_from == msg.sender || operatorApproval[_from][msg.sender] == true, "Need operator approval for 3rd party transfers."); + + // SafeMath will throw with insuficient funds _from + // or if _id is not valid (balance will be 0) + balances[_id][_from] = balances[_id][_from].sub(_value); + balances[_id][_to] = _value.add(balances[_id][_to]); + + // MUST emit event + emit TransferSingle(msg.sender, _from, _to, _id, _value); + + // Now that the balance is updated and the event was emitted, + // call onERC1155Received if the destination is a contract. + if (_to.isContract()) { + _doSafeTransferAcceptanceCheck(msg.sender, _from, _to, _id, _value, _data); + } + } + + /** + @notice Transfers `_values` amount(s) of `_ids` from the `_from` address to the `_to` address specified (with safety call). + @dev Caller must be approved to manage the tokens being transferred out of the `_from` account (see "Approval" section of the standard). + MUST revert if `_to` is the zero address. + MUST revert if length of `_ids` is not the same as length of `_values`. + MUST revert if any of the balance(s) of the holder(s) for token(s) in `_ids` is lower than the respective amount(s) in `_values` sent to the recipient. + MUST revert on any other error. + MUST emit `TransferSingle` or `TransferBatch` event(s) such that all the balance changes are reflected (see "Safe Transfer Rules" section of the standard). + Balance changes and events MUST follow the ordering of the arrays (_ids[0]/_values[0] before _ids[1]/_values[1], etc). + After the above conditions for the transfer(s) in the batch are met, this function MUST check if `_to` is a smart contract (e.g. code size > 0). If so, it MUST call the relevant `ERC1155TokenReceiver` hook(s) on `_to` and act appropriately (see "Safe Transfer Rules" section of the standard). + @param _from Source address + @param _to Target address + @param _ids IDs of each token type (order and length must match _values array) + @param _values Transfer amounts per token type (order and length must match _ids array) + @param _data Additional data with no specified format, MUST be sent unaltered in call to the `ERC1155TokenReceiver` hook(s) on `_to` + */ + function safeBatchTransferFrom(address _from, address _to, uint256[] calldata _ids, uint256[] calldata _values, bytes calldata _data) external { + + // MUST Throw on errors + require(_to != address(0x0), "destination address must be non-zero."); + require(_ids.length == _values.length, "_ids and _values array length must match."); + require(_from == msg.sender || operatorApproval[_from][msg.sender] == true, "Need operator approval for 3rd party transfers."); + + for (uint256 i = 0; i < _ids.length; ++i) { + uint256 id = _ids[i]; + uint256 value = _values[i]; + + // SafeMath will throw with insuficient funds _from + // or if _id is not valid (balance will be 0) + balances[id][_from] = balances[id][_from].sub(value); + balances[id][_to] = value.add(balances[id][_to]); + } + + // Note: instead of the below batch versions of event and acceptance check you MAY have emitted a TransferSingle + // event and a subsequent call to _doSafeTransferAcceptanceCheck in above loop for each balance change instead. + // Or emitted a TransferSingle event for each in the loop and then the single _doSafeBatchTransferAcceptanceCheck below. + // However it is implemented the balance changes and events MUST match when a check (i.e. calling an external contract) is done. + + // MUST emit event + emit TransferBatch(msg.sender, _from, _to, _ids, _values); + + // Now that the balances are updated and the events are emitted, + // call onERC1155BatchReceived if the destination is a contract. + if (_to.isContract()) { + _doSafeBatchTransferAcceptanceCheck(msg.sender, _from, _to, _ids, _values, _data); + } + } + + /** + @notice Get the balance of an account's Tokens. + @param _owner The address of the token holder + @param _id ID of the Token + @return The _owner's balance of the Token type requested + */ + function balanceOf(address _owner, uint256 _id) external view returns (uint256) { + // The balance of any account can be calculated from the Transfer events history. + // However, since we need to keep the balances to validate transfer request, + // there is no extra cost to also privide a querry function. + return balances[_id][_owner]; + } + + + /** + @notice Get the balance of multiple account/token pairs + @param _owners The addresses of the token holders + @param _ids ID of the Tokens + @return The _owner's balance of the Token types requested (i.e. balance for each (owner, id) pair) + */ + function balanceOfBatch(address[] calldata _owners, uint256[] calldata _ids) external view returns (uint256[] memory) { + + require(_owners.length == _ids.length); + + uint256[] memory balances_ = new uint256[](_owners.length); + + for (uint256 i = 0; i < _owners.length; ++i) { + balances_[i] = balances[_ids[i]][_owners[i]]; + } + + return balances_; + } + + /** + @notice Enable or disable approval for a third party ("operator") to manage all of the caller's tokens. + @dev MUST emit the ApprovalForAll event on success. + @param _operator Address to add to the set of authorized operators + @param _approved True if the operator is approved, false to revoke approval + */ + function setApprovalForAll(address _operator, bool _approved) external { + operatorApproval[tx.origin][_operator] = _approved; + emit ApprovalForAll(tx.origin, _operator, _approved); + } + + /** + @notice Queries the approval status of an operator for a given owner. + @param _owner The owner of the Tokens + @param _operator Address of authorized operator + @return True if the operator is approved, false if not + */ + function isApprovedForAll(address _owner, address _operator) external view returns (bool) { + return operatorApproval[_owner][_operator]; + } + +/////////////////////////////////////////// Internal ////////////////////////////////////////////// + + function _doSafeTransferAcceptanceCheck(address _operator, address _from, address _to, uint256 _id, uint256 _value, bytes memory _data) internal { + + // If this was a hybrid standards solution you would have to check ERC165(_to).supportsInterface(0x4e2312e0) here but as this is a pure implementation of an ERC-1155 token set as recommended by + // the standard, it is not necessary. The below should revert in all failure cases i.e. _to isn't a receiver, or it is and either returns an unknown value or it reverts in the call to indicate non-acceptance. + + + // Note: if the below reverts in the onERC1155Received function of the _to address you will have an undefined revert reason returned rather than the one in the require test. + // If you want predictable revert reasons consider using low level _to.call() style instead so the revert does not bubble up and you can revert yourself on the ERC1155_ACCEPTED test. + require(ERC1155TokenReceiver(_to).onERC1155Received(_operator, _from, _id, _value, _data) == ERC1155_ACCEPTED, "contract returned an unknown value from onERC1155Received"); + } + + function _doSafeBatchTransferAcceptanceCheck(address _operator, address _from, address _to, uint256[] memory _ids, uint256[] memory _values, bytes memory _data) internal { + + // If this was a hybrid standards solution you would have to check ERC165(_to).supportsInterface(0x4e2312e0) here but as this is a pure implementation of an ERC-1155 token set as recommended by + // the standard, it is not necessary. The below should revert in all failure cases i.e. _to isn't a receiver, or it is and either returns an unknown value or it reverts in the call to indicate non-acceptance. + + // Note: if the below reverts in the onERC1155BatchReceived function of the _to address you will have an undefined revert reason returned rather than the one in the require test. + // If you want predictable revert reasons consider using low level _to.call() style instead so the revert does not bubble up and you can revert yourself on the ERC1155_BATCH_ACCEPTED test. + require(ERC1155TokenReceiver(_to).onERC1155BatchReceived(_operator, _from, _ids, _values, _data) == ERC1155_BATCH_ACCEPTED, "contract returned an unknown value from onERC1155BatchReceived"); + } + + function _mint(address to,uint256 id,uint256 amount,bytes memory data) internal { + require(to != address(0), "ERC1155: mint to the zero address"); + address operator = msg.sender; + balances[id][to] +=amount;// amount.add(balances[id][to]); + emit TransferSingle(operator, address(0), to, id, amount); + if (to.isContract()) { + _doSafeTransferAcceptanceCheck(operator, address(0), to, id, amount, data); + } + } + + function _mintBatch(address to,uint256[] memory ids,uint256[] memory amounts,bytes memory data) internal { + 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; + + for (uint256 i = 0; i < ids.length; i++) { + balances[ids[i]][to] = amounts[i].add(balances[ids[i]][to]); + } + emit TransferBatch(operator, address(0), to, ids, amounts); + if (to.isContract()) { + _doSafeBatchTransferAcceptanceCheck(operator, address(0), to, ids, amounts, data); + } + } +} \ No newline at end of file diff --git a/NFT/ERC165.sol b/NFT/ERC165.sol new file mode 100755 index 0000000..de7e776 --- /dev/null +++ b/NFT/ERC165.sol @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + + +/** + * @title ERC165 + * @dev https://github.com/ethereum/EIPs/blob/master/EIPS/eip-165.md + */ +interface ERC165 { + + /** + * @notice Query if a contract implements an interface + * @param _interfaceId The interface identifier, as specified in ERC-165 + * @dev Interface identification is specified in ERC-165. This function + * uses less than 30,000 gas. + */ + function supportsInterface(bytes4 _interfaceId) + external + pure + returns (bool); +} \ No newline at end of file diff --git a/NFT/ERC721.sol b/NFT/ERC721.sol new file mode 100755 index 0000000..55d143a --- /dev/null +++ b/NFT/ERC721.sol @@ -0,0 +1,117 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +interface ERC721basic { + /// @dev 当任何NFT的所有权更改时(不管哪种方式),就会触发此事件。 + /// 包括在创建时(`from` == 0)和销毁时(`to` == 0), 合约创建时除外。 + event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId); + + /// @dev 当更改或确认NFT的授权地址时触发。 + /// 零地址表示没有授权的地址。 + /// 发生 `Transfer` 事件时,同样表示该NFT的授权地址(如果有)被重置为“无”(零地址)。 + event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId); + + /// @dev 所有者启用或禁用操作员时触发。(操作员可管理所有者所持有的NFTs) + event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved); + + /// @notice 统计所持有的NFTs数量 + /// @dev NFT 不能分配给零地址,查询零地址同样会异常 + /// @param _owner : 待查地址 + /// @return 返回数量,也许是0 + function balanceOf(address _owner) external view returns (uint256); + + /// @notice 返回所有者 + /// @dev NFT 不能分配给零地址,查询零地址抛出异常 + /// @param _tokenId NFT 的id + /// @return 返回所有者地址 + function ownerOf(uint256 _tokenId) external view returns (address); + + /// @notice 将NFT的所有权从一个地址转移到另一个地址 + /// @dev 如果`msg.sender` 不是当前的所有者(或授权者)抛出异常 + /// 如果 `_from` 不是所有者、`_to` 是零地址、`_tokenId` 不是有效id 均抛出异常。 + /// 当转移完成时,函数检查 `_to` 是否是合约,如果是,调用 `_to`的 `onERC721Received` 并且检查返回值是否是 `0x150b7a02` (即:`bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`) 如果不是抛出异常。 + /// @param _from :当前的所有者 + /// @param _to :新的所有者 + /// @param _tokenId :要转移的token id. + /// @param data : 附加额外的参数(没有指定格式),传递给接收者。 + function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes calldata data) external payable; + + /// @notice 将NFT的所有权从一个地址转移到另一个地址,功能同上,不带data参数。 + function safeTransferFrom(address _from, address _to, uint256 _tokenId) external payable; + + /// @notice 转移所有权 -- 调用者负责确认`_to`是否有能力接收NFTs,否则可能永久丢失。 + /// @dev 如果`msg.sender` 不是当前的所有者(或授权者、操作员)抛出异常 + /// 如果 `_from` 不是所有者、`_to` 是零地址、`_tokenId` 不是有效id 均抛出异常。 + function transferFrom(address _from, address _to, uint256 _tokenId) external payable; + + /// @notice 更改或确认NFT的授权地址 + /// @dev 零地址表示没有授权的地址。 + /// 如果`msg.sender` 不是当前的所有者或操作员 + /// @param _approved 新授权的控制者 + /// @param _tokenId : token id + function approve(address _approved, uint256 _tokenId) external payable; + + /// @notice 启用或禁用第三方(操作员)管理 `msg.sender` 所有资产 + /// @dev 触发 ApprovalForAll 事件,合约必须允许每个所有者可以有多个操作员。 + /// @param _operator 要添加到授权操作员列表中的地址 + /// @param _approved True 表示授权, false 表示撤销 + function setApprovalForAll(address _operator, bool _approved) external; + + /// @notice 获取单个NFT的授权地址 + /// @dev 如果 `_tokenId` 无效,抛出异常。 + /// @param _tokenId : token id + /// @return 返回授权地址, 零地址表示没有。 + function getApproved(uint256 _tokenId) external view returns (address); + + /// @notice 查询一个地址是否是另一个地址的授权操作员 + /// @param _owner 所有者 + /// @param _operator 代表所有者的授权操作员 + function isApprovedForAll(address _owner, address _operator) external view returns (bool); +} + +interface ERC721TokenReceiver { + /// @notice 处理接收NFT + /// @dev ERC721智能合约在`transfer`完成后,在接收这地址上调用这个函数。 + /// 函数可以通过revert 拒绝接收。返回非`0x150b7a02` 也同样是拒绝接收。 + /// 注意: 调用这个函数的 msg.sender是ERC721的合约地址 + /// @param _operator :调用 `safeTransferFrom` 函数的地址。 + /// @param _from :之前的NFT拥有者 + /// @param _tokenId : NFT token id + /// @param _data : 附加信息 + /// @return 正确处理时返回 `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))` + function onERC721Received(address _operator, address _from, uint256 _tokenId, bytes calldata _data) external returns(bytes4); +} + +interface ERC721Enumerable { + /// @notice NFTs 计数 + /// @return 返回合约有效跟踪(所有者不为零地址)的 NFT数量 + function totalSupply() external view returns (uint256); + + /// @notice 枚举索引NFT + /// @dev 如果 `_index` >= `totalSupply()` 则抛出异常 + /// @param _index 小于 `totalSupply()`的索引号 + /// @return 对应的token id(标准不指定排序方式) + function tokenByIndex(uint256 _index) external view returns (uint256); + + /// @notice 枚举索引某个所有者的 NFTs + /// @dev 如果 `_index` >= `balanceOf(_owner)` 或 `_owner` 是零地址,抛出异常 + /// @param _owner 查询的所有者地址 + /// @param _index 小于 `balanceOf(_owner)` 的索引号 + /// @return 对应的token id (标准不指定排序方式) + function tokenOfOwnerByIndex(address _owner, uint256 _index) external view returns (uint256); +} + +interface ERC721Metadata { + /// @notice NFTs 集合的名字 + function name() external view returns (string calldata _name); + + /// @notice NFTs 缩写代号 + function symbol() external view returns (string calldata _symbol); + + /// @notice 一个给定资产的唯一的统一资源标识符(URI) + /// @dev 如果 `_tokenId` 无效,抛出异常. URIs在 RFC 3986 定义, + /// URI 也许指向一个 符合 "ERC721 元数据 JSON Schema" 的 JSON 文件 + function tokenURI(uint256 _tokenId) external view returns (string calldata); +} + + diff --git a/NFT/IERC1155.sol b/NFT/IERC1155.sol new file mode 100755 index 0000000..dcbe480 --- /dev/null +++ b/NFT/IERC1155.sol @@ -0,0 +1,114 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "./ERC165.sol"; + +/** + @title ERC-1155 Multi Token Standard + @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1155.md + Note: The ERC-165 identifier for this interface is 0xd9b67a26. + */ +interface IERC1155 /* is ERC165 */ { + /** + @dev Either `TransferSingle` or `TransferBatch` MUST emit when tokens are transferred, including zero value transfers as well as minting or burning (see "Safe Transfer Rules" section of the standard). + The `_operator` argument MUST be msg.sender. + The `_from` argument MUST be the address of the holder whose balance is decreased. + The `_to` argument MUST be the address of the recipient whose balance is increased. + The `_id` argument MUST be the token type being transferred. + The `_value` argument MUST be the number of tokens the holder balance is decreased by and match what the recipient balance is increased by. + When minting/creating tokens, the `_from` argument MUST be set to `0x0` (i.e. zero address). + When burning/destroying tokens, the `_to` argument MUST be set to `0x0` (i.e. zero address). + */ + event TransferSingle(address indexed _operator, address indexed _from, address indexed _to, uint256 _id, uint256 _value); + + /** + @dev Either `TransferSingle` or `TransferBatch` MUST emit when tokens are transferred, including zero value transfers as well as minting or burning (see "Safe Transfer Rules" section of the standard). + The `_operator` argument MUST be msg.sender. + The `_from` argument MUST be the address of the holder whose balance is decreased. + The `_to` argument MUST be the address of the recipient whose balance is increased. + The `_ids` argument MUST be the list of tokens being transferred. + The `_values` argument MUST be the list of number of tokens (matching the list and order of tokens specified in _ids) the holder balance is decreased by and match what the recipient balance is increased by. + When minting/creating tokens, the `_from` argument MUST be set to `0x0` (i.e. zero address). + When burning/destroying tokens, the `_to` argument MUST be set to `0x0` (i.e. zero address). + */ + event TransferBatch(address indexed _operator, address indexed _from, address indexed _to, uint256[] _ids, uint256[] _values); + + /** + @dev MUST emit when approval for a second party/operator address to manage all tokens for an owner address is enabled or disabled (absense of an event assumes disabled). + */ + event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved); + + /** + @dev MUST emit when the URI is updated for a token ID. + URIs are defined in RFC 3986. + The URI MUST point a JSON file that conforms to the "ERC-1155 Metadata URI JSON Schema". + */ + event URI(string _value, uint256 indexed _id); + + /** + @notice Transfers `_value` amount of an `_id` from the `_from` address to the `_to` address specified (with safety call). + @dev Caller must be approved to manage the tokens being transferred out of the `_from` account (see "Approval" section of the standard). + MUST revert if `_to` is the zero address. + MUST revert if balance of holder for token `_id` is lower than the `_value` sent. + MUST revert on any other error. + MUST emit the `TransferSingle` event to reflect the balance change (see "Safe Transfer Rules" section of the standard). + After the above conditions are met, this function MUST check if `_to` is a smart contract (e.g. code size > 0). If so, it MUST call `onERC1155Received` on `_to` and act appropriately (see "Safe Transfer Rules" section of the standard). + @param _from Source address + @param _to Target address + @param _id ID of the token type + @param _value Transfer amount + @param _data Additional data with no specified format, MUST be sent unaltered in call to `onERC1155Received` on `_to` + */ + function safeTransferFrom(address _from, address _to, uint256 _id, uint256 _value, bytes calldata _data) external; + + /** + @notice Transfers `_values` amount(s) of `_ids` from the `_from` address to the `_to` address specified (with safety call). + @dev Caller must be approved to manage the tokens being transferred out of the `_from` account (see "Approval" section of the standard). + MUST revert if `_to` is the zero address. + MUST revert if length of `_ids` is not the same as length of `_values`. + MUST revert if any of the balance(s) of the holder(s) for token(s) in `_ids` is lower than the respective amount(s) in `_values` sent to the recipient. + MUST revert on any other error. + MUST emit `TransferSingle` or `TransferBatch` event(s) such that all the balance changes are reflected (see "Safe Transfer Rules" section of the standard). + Balance changes and events MUST follow the ordering of the arrays (_ids[0]/_values[0] before _ids[1]/_values[1], etc). + After the above conditions for the transfer(s) in the batch are met, this function MUST check if `_to` is a smart contract (e.g. code size > 0). If so, it MUST call the relevant `ERC1155TokenReceiver` hook(s) on `_to` and act appropriately (see "Safe Transfer Rules" section of the standard). + @param _from Source address + @param _to Target address + @param _ids IDs of each token type (order and length must match _values array) + @param _values Transfer amounts per token type (order and length must match _ids array) + @param _data Additional data with no specified format, MUST be sent unaltered in call to the `ERC1155TokenReceiver` hook(s) on `_to` + */ + function safeBatchTransferFrom(address _from, address _to, uint256[] calldata _ids, uint256[] calldata _values, bytes calldata _data) external; + + /** + @notice Get the balance of an account's Tokens. + @param _owner The address of the token holder + @param _id ID of the Token + @return The _owner's balance of the Token type requested + */ + function balanceOf(address _owner, uint256 _id) external view returns (uint256); + + /** + @notice Get the balance of multiple account/token pairs + @param _owners The addresses of the token holders + @param _ids ID of the Tokens + @return The _owner's balance of the Token types requested (i.e. balance for each (owner, id) pair) + */ + function balanceOfBatch(address[] calldata _owners, uint256[] calldata _ids) external view returns (uint256[] memory); + + /** + @notice Enable or disable approval for a third party ("operator") to manage all of the caller's tokens. + @dev MUST emit the ApprovalForAll event on success. + @param _operator Address to add to the set of authorized operators + @param _approved True if the operator is approved, false to revoke approval + */ + function setApprovalForAll(address _operator, bool _approved) external; + + /** + @notice Queries the approval status of an operator for a given owner. + @param _owner The owner of the Tokens + @param _operator Address of authorized operator + @return True if the operator is approved, false if not + */ + function isApprovedForAll(address _owner, address _operator) external view returns (bool); + +} \ No newline at end of file diff --git a/NFT/IERC1155Metadata.sol b/NFT/IERC1155Metadata.sol new file mode 100755 index 0000000..01c272d --- /dev/null +++ b/NFT/IERC1155Metadata.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +/** + Note: The ERC-165 identifier for this interface is 0x0e89341c. +*/ +interface ERC1155Metadata_URI { + /* + @notice A distinct Uniform Resource Identifier (URI) for a given token. + @dev URIs are defined in RFC 3986. + The URI may point to a JSON file that conforms to the "ERC-1155 Metadata URI JSON Schema". + @return URI string + */ + function name(uint256 _id) external view returns (string memory); + function symbol(uint256 _id) external view returns (string memory); + function uri(uint256 _id) external view returns (string memory); +} \ No newline at end of file diff --git a/NFT/IERC1155TokenReceiver.sol b/NFT/IERC1155TokenReceiver.sol new file mode 100755 index 0000000..eacbe24 --- /dev/null +++ b/NFT/IERC1155TokenReceiver.sol @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +/** + Note: The ERC-165 identifier for this interface is 0x4e2312e0. +*/ +interface ERC1155TokenReceiver { + /** + @notice Handle the receipt of a single ERC1155 token type. + @dev An ERC1155-compliant smart contract MUST call this function on the token recipient contract, at the end of a `safeTransferFrom` after the balance has been updated. + This function MUST return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` (i.e. 0xf23a6e61) if it accepts the transfer. + This function MUST revert if it rejects the transfer. + Return of any other value than the prescribed keccak256 generated value MUST result in the transaction being reverted by the caller. + @param _operator The address which initiated the transfer (i.e. msg.sender) + @param _from The address which previously owned the token + @param _id The ID of the token being transferred + @param _value The amount of tokens being transferred + @param _data Additional data with no specified format + @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` + */ + function onERC1155Received(address _operator, address _from, uint256 _id, uint256 _value, bytes calldata _data) external returns(bytes4); + + /** + @notice Handle the receipt of multiple ERC1155 token types. + @dev An ERC1155-compliant smart contract MUST call this function on the token recipient contract, at the end of a `safeBatchTransferFrom` after the balances have been updated. + This function MUST return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` (i.e. 0xbc197c81) if it accepts the transfer(s). + This function MUST revert if it rejects the transfer(s). + Return of any other value than the prescribed keccak256 generated value MUST result in the transaction being reverted by the caller. + @param _operator The address which initiated the batch transfer (i.e. msg.sender) + @param _from The address which previously owned the token + @param _ids An array containing ids of each token being transferred (order and length must match _values array) + @param _values An array containing amounts of each token being transferred (order and length must match _ids array) + @param _data Additional data with no specified format + @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` + */ + function onERC1155BatchReceived(address _operator, address _from, uint256[] calldata _ids, uint256[] calldata _values, bytes calldata _data) external returns(bytes4); +} \ No newline at end of file diff --git a/NFT/IERC20.sol b/NFT/IERC20.sol new file mode 100755 index 0000000..d75426d --- /dev/null +++ b/NFT/IERC20.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +interface IERC20 { + function totalSupply() external view returns (uint256); + function _balanceOf(address who) external view returns (uint256); + function allowance(address owner, address spender) external view returns (uint256); + function transfer(address to, uint256 value) external returns (bool); + function approve(address spender, uint256 value) external returns (bool); + function transferFrom(address from, address to, uint256 value) external returns (bool); + event Transfer(address indexed from, address indexed to, uint256 value); + event Approval(address indexed owner, address indexed spender, uint256 value); +} \ No newline at end of file diff --git a/NFT/INFTToken.sol b/NFT/INFTToken.sol new file mode 100755 index 0000000..7dce6d4 --- /dev/null +++ b/NFT/INFTToken.sol @@ -0,0 +1,4 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "./ERC.sol"; \ No newline at end of file diff --git a/NFT/NFTToken.sol b/NFT/NFTToken.sol new file mode 100755 index 0000000..27918e0 --- /dev/null +++ b/NFT/NFTToken.sol @@ -0,0 +1,554 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "./SafeMath.sol"; +import "./Address.sol"; +import "./Common.sol"; +import "./IERC1155TokenReceiver.sol"; +import "./IERC1155.sol"; +import "./ERC165.sol"; +import "./IERC1155Metadata.sol"; + +// A sample implementation of core ERC1155 function. +contract ERC1155 is IERC1155, ERC165, CommonConstants, ERC1155Metadata_URI +{ + using SafeMath for uint256; + using Address for address; + + // id => (owner => balance) + mapping (uint256 => mapping(address => uint256)) internal balances; + + // owner => (operator => approved) + mapping (address => mapping(address => bool)) internal operatorApproval; + +/////////////////////////////////////////// ERC165 ////////////////////////////////////////////// + + /* + bytes4(keccak256('supportsInterface(bytes4)')); + */ + bytes4 constant private INTERFACE_SIGNATURE_ERC165 = 0x01ffc9a7; + + /* + bytes4(keccak256("safeTransferFrom(address,address,uint256,uint256,bytes)")) ^ + bytes4(keccak256("safeBatchTransferFrom(address,address,uint256[],uint256[],bytes)")) ^ + bytes4(keccak256("balanceOf(address,uint256)")) ^ + bytes4(keccak256("balanceOfBatch(address[],uint256[])")) ^ + bytes4(keccak256("setApprovalForAll(address,bool)")) ^ + bytes4(keccak256("isApprovedForAll(address,address)")); + */ + bytes4 constant private INTERFACE_SIGNATURE_ERC1155 = 0xd9b67a26; + + function supportsInterface(bytes4 _interfaceId) external pure returns (bool) { + if (_interfaceId == INTERFACE_SIGNATURE_ERC165 || + _interfaceId == INTERFACE_SIGNATURE_ERC1155) { + return true; + } + + return false; + } +/////////////////////////////////////////// ERC1155 ////////////////////////////////////////////// + + /** + @notice Transfers `_value` amount of an `_id` from the `_from` address to the `_to` address specified (with safety call). + @dev Caller must be approved to manage the tokens being transferred out of the `_from` account (see "Approval" section of the standard). + MUST revert if `_to` is the zero address. + MUST revert if balance of holder for token `_id` is lower than the `_value` sent. + MUST revert on any other error. + MUST emit the `TransferSingle` event to reflect the balance change (see "Safe Transfer Rules" section of the standard). + After the above conditions are met, this function MUST check if `_to` is a smart contract (e.g. code size > 0). If so, it MUST call `onERC1155Received` on `_to` and act appropriately (see "Safe Transfer Rules" section of the standard). + @param _from Source address + @param _to Target address + @param _id ID of the token type + @param _value Transfer amount + @param _data Additional data with no specified format, MUST be sent unaltered in call to `onERC1155Received` on `_to` + */ + + function safeTransferFrom(address _from, address _to, uint256 _id, uint256 _value, bytes calldata _data) external { + + require(_to != address(0x0), "_to must be non-zero."); + require(_from == msg.sender || operatorApproval[_from][msg.sender] == true, "Need operator approval for 3rd party transfers."); + if (allTokens[tokenFromCollection[_id]][allTokensindex[_id]].status != Tokenstatus.pending && msg.sender == _from){ + revert("The Token is locked!"); + } + // SafeMath will throw with insuficient funds _from + // or if _id is not valid (balance will be 0) + balances[_id][_from] = balances[_id][_from].sub(_value); + balances[_id][_to] = _value.add(balances[_id][_to]); + tokenOwners[_id] = _to; + // MUST emit event + emit TransferSingle(msg.sender, _from, _to, _id, _value); + + // Now that the balance is updated and the event was emitted, + // call onERC1155Received if the destination is a contract. + if (_to.isContract()) { + _doSafeTransferAcceptanceCheck(msg.sender, _from, _to, _id, _value, _data); + } + } + + /** + @notice Transfers `_values` amount(s) of `_ids` from the `_from` address to the `_to` address specified (with safety call). + @dev Caller must be approved to manage the tokens being transferred out of the `_from` account (see "Approval" section of the standard). + MUST revert if `_to` is the zero address. + MUST revert if length of `_ids` is not the same as length of `_values`. + MUST revert if any of the balance(s) of the holder(s) for token(s) in `_ids` is lower than the respective amount(s) in `_values` sent to the recipient. + MUST revert on any other error. + MUST emit `TransferSingle` or `TransferBatch` event(s) such that all the balance changes are reflected (see "Safe Transfer Rules" section of the standard). + Balance changes and events MUST follow the ordering of the arrays (_ids[0]/_values[0] before _ids[1]/_values[1], etc). + After the above conditions for the transfer(s) in the batch are met, this function MUST check if `_to` is a smart contract (e.g. code size > 0). If so, it MUST call the relevant `ERC1155TokenReceiver` hook(s) on `_to` and act appropriately (see "Safe Transfer Rules" section of the standard). + @param _from Source address + @param _to Target address + @param _ids IDs of each token type (order and length must match _values array) + @param _values Transfer amounts per token type (order and length must match _ids array) + @param _data Additional data with no specified format, MUST be sent unaltered in call to the `ERC1155TokenReceiver` hook(s) on `_to` + */ + function safeBatchTransferFrom(address _from, address _to, uint256[] calldata _ids, uint256[] calldata _values, bytes calldata _data) external { + + // MUST Throw on errors + require(_to != address(0x0), "destination address must be non-zero."); + require(_ids.length == _values.length, "_ids and _values array length must match."); + require(_from == msg.sender || operatorApproval[_from][msg.sender] == true, "Need operator approval for 3rd party transfers."); + for (uint256 i = 0; i < _ids.length; ++i) { + uint256 id = _ids[i]; + uint256 value = _values[i]; + if (allTokens[tokenFromCollection[id]][allTokensindex[id]].status != Tokenstatus.pending && msg.sender == _from){ + revert("The Token is locked!"); + } + // SafeMath will throw with insuficient funds _from + // or if _id is not valid (balance will be 0) + balances[id][_from] = balances[id][_from].sub(value); + balances[id][_to] = value.add(balances[id][_to]); + tokenOwners[id] = _to; + } + + // Note: instead of the below batch versions of event and acceptance check you MAY have emitted a TransferSingle + // event and a subsequent call to _doSafeTransferAcceptanceCheck in above loop for each balance change instead. + // Or emitted a TransferSingle event for each in the loop and then the single _doSafeBatchTransferAcceptanceCheck below. + // However it is implemented the balance changes and events MUST match when a check (i.e. calling an external contract) is done. + + // MUST emit event + emit TransferBatch(msg.sender, _from, _to, _ids, _values); + + // Now that the balances are updated and the events are emitted, + // call onERC1155BatchReceived if the destination is a contract. + if (_to.isContract()) { + _doSafeBatchTransferAcceptanceCheck(msg.sender, _from, _to, _ids, _values, _data); + } + } + + /** + @notice Get the balance of an account's Tokens. + @param _owner The address of the token holder + @param _id ID of the Token + @return The _owner's balance of the Token type requested + */ + function balanceOf(address _owner, uint256 _id) external view returns (uint256) { + // The balance of any account can be calculated from the Transfer events history. + // However, since we need to keep the balances to validate transfer request, + // there is no extra cost to also privide a querry function. + return balances[_id][_owner]; + } + + + /** + @notice Get the balance of multiple account/token pairs + @param _owners The addresses of the token holders + @param _ids ID of the Tokens + @return The _owner's balance of the Token types requested (i.e. balance for each (owner, id) pair) + */ + function balanceOfBatch(address[] calldata _owners, uint256[] calldata _ids) external view returns (uint256[] memory) { + + require(_owners.length == _ids.length); + + uint256[] memory balances_ = new uint256[](_owners.length); + + for (uint256 i = 0; i < _owners.length; ++i) { + balances_[i] = balances[_ids[i]][_owners[i]]; + } + + return balances_; + } + + /** + @notice Enable or disable approval for a third party ("operator") to manage all of the caller's tokens. + @dev MUST emit the ApprovalForAll event on success. + @param _operator Address to add to the set of authorized operators + @param _approved True if the operator is approved, false to revoke approval + */ + function setApprovalForAll(address _operator, bool _approved) external { + operatorApproval[tx.origin][_operator] = _approved; + emit ApprovalForAll(tx.origin, _operator, _approved); + } + + /** + @notice Queries the approval status of an operator for a given owner. + @param _owner The owner of the Tokens + @param _operator Address of authorized operator + @return True if the operator is approved, false if not + */ + function isApprovedForAll(address _owner, address _operator) external view returns (bool) { + return operatorApproval[_owner][_operator]; + } + +/////////////////////////////////////////// Internal ////////////////////////////////////////////// + + function _doSafeTransferAcceptanceCheck(address _operator, address _from, address _to, uint256 _id, uint256 _value, bytes memory _data) internal { + + // If this was a hybrid standards solution you would have to check ERC165(_to).supportsInterface(0x4e2312e0) here but as this is a pure implementation of an ERC-1155 token set as recommended by + // the standard, it is not necessary. The below should revert in all failure cases i.e. _to isn't a receiver, or it is and either returns an unknown value or it reverts in the call to indicate non-acceptance. + + + // Note: if the below reverts in the onERC1155Received function of the _to address you will have an undefined revert reason returned rather than the one in the require test. + // If you want predictable revert reasons consider using low level _to.call() style instead so the revert does not bubble up and you can revert yourself on the ERC1155_ACCEPTED test. + require(ERC1155TokenReceiver(_to).onERC1155Received(_operator, _from, _id, _value, _data) == ERC1155_ACCEPTED, "contract returned an unknown value from onERC1155Received"); + } + + function _doSafeBatchTransferAcceptanceCheck(address _operator, address _from, address _to, uint256[] memory _ids, uint256[] memory _values, bytes memory _data) internal { + + // If this was a hybrid standards solution you would have to check ERC165(_to).supportsInterface(0x4e2312e0) here but as this is a pure implementation of an ERC-1155 token set as recommended by + // the standard, it is not necessary. The below should revert in all failure cases i.e. _to isn't a receiver, or it is and either returns an unknown value or it reverts in the call to indicate non-acceptance. + + // Note: if the below reverts in the onERC1155BatchReceived function of the _to address you will have an undefined revert reason returned rather than the one in the require test. + // If you want predictable revert reasons consider using low level _to.call() style instead so the revert does not bubble up and you can revert yourself on the ERC1155_BATCH_ACCEPTED test. + require(ERC1155TokenReceiver(_to).onERC1155BatchReceived(_operator, _from, _ids, _values, _data) == ERC1155_BATCH_ACCEPTED, "contract returned an unknown value from onERC1155BatchReceived"); + } + + function _mint(address to,uint256 id,uint256 amount,bytes memory data) internal { + require(to != address(0), "ERC1155: mint to the zero address"); + address operator = msg.sender; + balances[id][to] += amount.add(balances[id][to]); + emit TransferSingle(operator, address(0), to, id, amount); + if (to.isContract()) { + _doSafeTransferAcceptanceCheck(operator, address(0), to, id, amount, data); + } + } + + function _mintBatch(address to,uint256[] memory ids,uint256[] memory amounts,bytes memory data) internal { + 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; + + for (uint256 i = 0; i < ids.length; i++) { + balances[ids[i]][to] = amounts[i].add(balances[ids[i]][to]); + } + emit TransferBatch(operator, address(0), to, ids, amounts); + if (to.isContract()) { + _doSafeBatchTransferAcceptanceCheck(operator, address(0), to, ids, amounts, data); + } + } + +/////////////////////////////////////////// Token ///////////////////////////////////////////////////////////////////////// + using SafeMath for uint256; + + struct Collection { + address owner; + uint256[] allTokens; + string uri; + string name; + } + mapping(uint256 => uint256) tokenFromCollection; + uint256[] public allCollection; + mapping(uint256 => Collection) Collections; + //collection的信息 + + struct BidInfo {//竞标信息 + address buyer; + uint256 value; + } + + + mapping(uint256 => uint256) imagePrice; + struct auctionData { + uint256 price; + uint256 time; + BidInfo HighestBid; + } + mapping(uint256 => auctionData) tokenAuction; + //拍卖NFT信息 + + enum Tokenstatus{ pending, onsell, onauction } + struct allTokenstatus { + Tokenstatus status; + uint256 tokenId; + } + mapping(uint256 => allTokenstatus[]) allTokens; + mapping(uint256 => uint256) allTokensindex; + //所有Token的信息 + +/* + struct TokenStatus { + bool isOnSale; + uint256 index; + } + + mapping(uint256 => uint256[]) public SaleTokens; + mapping(uint256 => uint256[]) public AucTokens; + mapping(uint256 => uint256[]) public pendingTokens; + mapping(uint256 => TokenStatus) _listedForAuction; + mapping(uint256 => TokenStatus) _listedForSale; + mapping(uint256 => uint256) _indexForPending; + //出售的NFT,拍卖的NFT,以及无状态的NFT的信息 + */ + + mapping(uint256 => string) internal _name; + mapping(uint256 => string) internal _symbol; + + + mapping(uint256 => string) internal tokenURIs; + mapping(uint256 => address) internal tokenOwners; + + address admin; + constructor(address Admin){admin = Admin;} + + function name(uint256 _id) external view returns (string memory){ + return _name[_id]; + } + function symbol(uint256 _id) external view returns(string memory){ + return _symbol[_id]; + } + function uri(uint256 _id) external view returns (string memory) { + // require(exists(_id)); + return tokenURIs[_id]; + } + + function Addcollection(string memory name_, uint256 collectionId, string memory _uri) public { + require(msg.sender == admin,"You are not allowed to use this API"); + Collections[collectionId].owner = tx.origin; + Collections[collectionId].name = name_; + Collections[collectionId].uri = _uri; + allCollection.push(collectionId); + //SaleTokens[collectionId].push(0); + //AucTokens[collectionId].push(0); + //pendingTokens[collectionId].push(0); + } + + + function AddToken(string memory name_, string memory symbol_, uint256 _tokenId,bytes memory data,string memory _uri, uint256 collectionId) public { + require(msg.sender == admin,"You are not allowed to use this API"); + _mint(tx.origin,_tokenId,1,data); + _name[_tokenId] = name_; + _symbol[_tokenId] = symbol_; + tokenOwners[_tokenId] = tx.origin; + _setURI(_tokenId,_uri); + allTokenstatus memory x; + x.status = Tokenstatus.pending; + x.tokenId = _tokenId; + allTokens[collectionId].push(x); + allTokensindex[_tokenId] = allTokens[collectionId].length - 1; + //pendingTokens[collectionId].push(_tokenId); + //_indexForPending[_tokenId] = pendingTokens[collectionId].length - 1; + //pendingTokens[collectionId][0]++; + Collections[collectionId].allTokens.push(_tokenId); + tokenFromCollection[_tokenId] = collectionId; + } + + function _setURI(uint256 _id,string memory _uri) internal { + tokenURIs[_id] = _uri; + } + + /* + function _setOwner(uint256 _id,address _owner) external { + require (tokenOwners[_id] == msg.sender || operatorApproval[tokenOwners[_id]][msg.sender] == true,"Is not owner!"); + tokenOwners[_id] = _owner; + } +*/ + function _getOwner(uint256 _id) public view returns (address){ + return tokenOwners[_id]; + } + + function setNFTPrice(uint256 _id, uint256 _price) external { + require(_getOwner(_id) == tx.origin,"not owner!"); + require(allTokens[tokenFromCollection[_id]][allTokensindex[_id]].status != Tokenstatus.onauction,"the product is auction"); + imagePrice[_id] = _price; + } + + function getNFTPrice(uint256 _id) external view returns (uint256){ + return imagePrice[_id]; + } + + function setSaleState(uint256 _id, bool isSale) external { + require(_getOwner(_id) == tx.origin,"not owner!"); + uint256 collectionId = tokenFromCollection[_id]; + if (isSale == true){ + allTokens[collectionId][allTokensindex[_id]].status = Tokenstatus.onsell; + /* + if (_listedForSale[_id].index == 0){ + SaleTokens[collectionId].push(_id); + _listedForSale[_id].index = SaleTokens[collectionId].length-1; + } + else{ + SaleTokens[collectionId][_listedForSale[_id].index] = _id; + } + SaleTokens[collectionId][0]=SaleTokens[collectionId][0].add(1); pendingTokens[collectionId][0]=pendingTokens[collectionId][0].sub(1); + delete pendingTokens[collectionId][_indexForPending[_id]]; + */ + } + else { + allTokens[collectionId][allTokensindex[_id]].status = Tokenstatus.pending; + /* + pendingTokens[collectionId][_indexForPending[_id]] = _id; + pendingTokens[collectionId][0]=pendingTokens[collectionId][0].add(1); SaleTokens[collectionId][0]=SaleTokens[collectionId][0].sub(1); + delete SaleTokens[collectionId][_listedForSale[_id].index]; + */ + } + // _listedForSale[_id].isOnSale = isSale; + } + + function getSaleState(uint256 _id) external view returns (bool){ + if (allTokens[tokenFromCollection[_id]][allTokensindex[_id]].status == Tokenstatus.onsell) + return true; + else + return false; + //return _listedForSale[_id].isOnSale; + } + + function setAuctionState(uint256 _id, bool isAuction) external { + require(_getOwner(_id) == tx.origin,"not owner!"); + uint256 collectionId = tokenFromCollection[_id]; + if (isAuction == true){ + allTokens[collectionId][allTokensindex[_id]].status = Tokenstatus.onauction; + /* + if (_listedForAuction[_id].index == 0){ + AucTokens[collectionId].push(_id); + _listedForAuction[_id].index = AucTokens[collectionId].length-1; + } + else{ + AucTokens[collectionId][_listedForAuction[_id].index] = _id; + } + AucTokens[collectionId][0]=AucTokens[collectionId][0].add(1); pendingTokens[collectionId][0]=pendingTokens[collectionId][0].sub(1); + delete pendingTokens[collectionId][_indexForPending[_id]]; + */ + } + else { + allTokens[collectionId][allTokensindex[_id]].status = Tokenstatus.pending; + /* + pendingTokens[collectionId][_indexForPending[_id]] = _id; + pendingTokens[collectionId][0]=pendingTokens[collectionId][0].add(1); AucTokens[collectionId][0]=AucTokens[collectionId][0].sub(1); + delete AucTokens[collectionId][_listedForAuction[_id].index]; + */ + } + // _listedForAuction[_id].isOnSale = isAuction; + } + + function getAuctionState(uint256 _id) external view returns (bool) { + if (allTokens[tokenFromCollection[_id]][allTokensindex[_id]].status == Tokenstatus.onauction) + return true; + else + return false; + //return _listedForAuction[_id].isOnSale; + } + + function setAuctionInfo(uint256 _id, uint256 _price, uint256 _time) external{ + require(msg.sender == admin,"You are not allowed to use this API"); + require(_getOwner(_id) == tx.origin ,"not owner!"); + tokenAuction[_id].price = _price; + tokenAuction[_id].time = _time; + delete tokenAuction[_id].HighestBid; + } + + function getAuctionPrice(uint256 _id) external view returns (uint256){ + return tokenAuction[_id].price; + } + + function getAuctionTime(uint256 _id) external view returns (uint256){ + return tokenAuction[_id].time; + } + + function getOnSaleList(uint256 collectionId) external view returns (uint256[] memory){ + //return SaleTokens; + uint256 sum = 0; + for (uint i =0; i mapping(uint256 => uint256)) imagePrice; + struct auctionData { + uint256 price; + uint256 time; + BidInfo HighestBid; + } + mapping(uint256 => mapping(uint256 => auctionData)) tokenAuction; + //拍卖NFT信息 + + enum Tokenstatus{ pending, onsell, onauction} + struct allTokenstatus { + uint256 tokenId; + // mapping(uint256 => Tokenstatus) status; + uint256 totalSupply; + + address originOwner; + + } + + allTokenstatus[] allTokens; + mapping(uint256 => uint256) allTokensindex; + mapping(uint256 => mapping (uint256 => Tokenstatus)) status; + //所有Token的信息 + + struct TokenInfo{ + string name; + string symbol; + string tokenURI; + address originOwner; + uint256 totalSupply; + } + + + mapping(uint256 => string) internal _name; + mapping(uint256 => string) internal _symbol; + mapping(uint256 => string) internal tokenURIs; + //Metadata + + mapping(uint256 => mapping(uint256 => address)) internal tokenOwners; + + address admin; + constructor(address Admin){admin = Admin;} + + function name(uint256 _id) external view returns (string memory){ + return _name[_id]; + } + function symbol(uint256 _id) external view returns(string memory){ + return _symbol[_id]; + } + function uri(uint256 _id) external view returns (string memory) { + // require(exists(_id)); + return tokenURIs[_id]; + } + + + function AddToken(string memory name_, string memory symbol_, uint256 _tokenId, uint256 _amount, bytes memory data,string memory _uri) public { + _mint(msg.sender,_tokenId,_amount,data); + _name[_tokenId] = name_; + _symbol[_tokenId] = symbol_; + _setURI(_tokenId,_uri); + allTokenstatus memory x; + x.originOwner = msg.sender; + x.tokenId = _tokenId; + x.totalSupply = _amount; + allTokens.push(x); + allTokensindex[_tokenId] = allTokens.length - 1; + } + + function _setURI(uint256 _id,string memory _uri) internal { + tokenURIs[_id] = _uri; + } + + function _setOwner(uint256 _id, uint256 _order, address _owner) internal { + require (_getOwner(_id,_order) == msg.sender || operatorApproval[_getOwner(_id,_order)][msg.sender] == true,"Is not owner!"); + tokenOwners[_id][_order] = _owner; + } + + function TransferToken(address _from, address _to, uint256 _id, uint256[] calldata _order, bytes calldata data) external { + for (uint i=0; i<_order.length; i++){ + if (msg.sender == _from && status[_id][_order[i]] != Tokenstatus.pending){ + revert("The token is locked!"); + } + _setOwner(_id, _order[i], _to); + } + safeTransferFrom(_from, _to, _id, _order.length, data); + } + + function _getOwner(uint256 _id, uint256 _order) public view returns (address){ + require(allTokens[allTokensindex[_id]].originOwner != address(0), "No NFT!"); + if (tokenOwners[_id][_order] == address(0)) return allTokens[allTokensindex[_id]].originOwner; + else return tokenOwners[_id][_order]; + } + + function setNFTPrice(uint256 _id, uint256 _order, uint256 _price) internal { + require(_getOwner(_id, _order) == msg.sender ,"not owner!"); + imagePrice[_id][_order] = _price; + } + + function getNFTPrice(uint256 _id, uint256 _order) public view returns (uint256){ + return imagePrice[_id][_order]; + } + + function setSaleState(uint256 _id, uint256 _order, bool isSale) internal{ + require(_getOwner(_id,_order) == msg.sender || operatorApproval[_getOwner(_id,_order)][msg.sender] == true,"not owner!"); + if (isSale == true){ + status[_id][_order] = Tokenstatus.onsell; + /* + if (_listedForSale[_id][_order] == 0){ + SaleTokens[_id].push(_order); + _listedForSale[_id][_order] = SaleTokens[_id].length-1; + } + else{ + SaleTokens[_id][_listedForSale[_id][_order]] = _order; + } + SaleTokens[_id][0]=SaleTokens[_id][0].add(1); pendingTokens[_id][0]=pendingTokens[_id][0].sub(1); + delete pendingTokens[_id][_indexForPending[_id][_order]]; + */ + } + else { + status[_id][_order] = Tokenstatus.pending; + /* + pendingTokens[_id][_indexForPending[_id][_order]] = _order; + pendingTokens[_id][0]=pendingTokens[_id][0].add(1); SaleTokens[_id][0]=SaleTokens[_id][0].sub(1); + delete SaleTokens[_id][_listedForSale[_id][_order]]; + */ + } + } + + function updatePrice(uint _id, uint256 _order, uint _price) public returns (bool){ + require(_getOwner(_id,_order) == msg.sender,"not owner!"); + require(getSaleState(_id, _order) == Tokenstatus.onsell,"the product is pending or at auction"); + setNFTPrice(_id, _order, _price); + return true; + } + + function approveForSale(uint256 _tokenId, uint256 _order, uint _price) public { + require(_getOwner(_tokenId,_order) == msg.sender,"not owner!"); + require(getSaleState(_tokenId,_order) == Tokenstatus.pending,"the product is not pending"); + setSaleState(_tokenId, _order, true); + updatePrice(_tokenId, _order, _price); + operatorApproval[msg.sender][admin] = true; + emit ApprovalForAll(msg.sender, admin, true); + } + + function approveForAuction(uint _tokenId, uint _order, uint _price, uint _time) public { + require(_getOwner(_tokenId, _order) == msg.sender,"not owner!"); + require(getSaleState(_tokenId, _order) == Tokenstatus.pending,"the product is not pending"); + setAuctionState(_tokenId, _order, true); + setAuctionInfo(_tokenId, _order, _price, block.timestamp + _time); + operatorApproval[msg.sender][admin] = true; + emit ApprovalForAll(msg.sender, admin, true); + } + + function withDrawToken(uint _tokenId, uint _order) public { + require(_getOwner(_tokenId, _order) == msg.sender,"not owner!"); + require(getSaleState(_tokenId, _order) != Tokenstatus.pending,"the product is pending"); + operatorApproval[msg.sender][admin] = false; + if (getSaleState(_tokenId, _order) == Tokenstatus.onauction){ + uint256 highestbidvalue; + address highestbidbuyer; + (highestbidvalue, highestbidbuyer) = getHighestBidInfo(_tokenId, _order); + payable(highestbidbuyer).transfer(highestbidvalue); + } + status[_tokenId][_order] = Tokenstatus.pending; + } + + function getSaleState(uint256 _id, uint256 _order) public view returns (Tokenstatus){ + return status[_id][_order]; + } + + function nftSold(uint _tokenId, uint _order) internal { + if (getSaleState(_tokenId, _order) == Tokenstatus.onsell){ + setSaleState(_tokenId, _order, false); + } + if (getSaleState(_tokenId, _order) == Tokenstatus.onauction){ + setAuctionState(_tokenId, _order, false); + } + } + + + function buyToken1155(uint256 _tokenId, uint256 _order) public payable { + uint256 _price = imagePrice[_tokenId][_order]; + require(getSaleState(_tokenId, _order) == Tokenstatus.onsell,"The product is not available"); + require(msg.value >= _price,"too less etd"); + payable(msg.sender).transfer(msg.value - _price); + + address _owner= _getOwner(_tokenId,_order); + payable(_owner).transfer(_price); + //safeTransferFrom(_owner,msg.sender,_tokenId,1,""); + //_setOwner(_tokenId, _order, msg.sender); + + status[_tokenId][_order] = Tokenstatus.pending; + + /* + pendingTokens[_tokenId][_indexForPending[_tokenId][_order]] = _order; + pendingTokens[_tokenId][0]=pendingTokens[_tokenId][0].add(1); SaleTokens[_tokenId][0]=SaleTokens[_tokenId][0].sub(1); + delete SaleTokens[_tokenId][_listedForSale[_tokenId][_order]]; + */ + + + emit BoughtNFT(_tokenId, msg.sender, _price); + + } + + function setAuctionState(uint256 _id, uint256 _order, bool isAuction) internal { + require(_getOwner(_id, _order) == msg.sender || operatorApproval[tokenOwners[_id][_order]][msg.sender] == true,"not owner!"); + if (isAuction == true){ + status[_id][_order] = Tokenstatus.onauction; + /* + if (_listedForAuction[_id][_order] == 0){ + AucTokens[_id].push(_id); + _listedForAuction[_id][_order] = AucTokens[_id].length-1; + } + else{ + AucTokens[_id][_listedForAuction[_id][_order]] = _order; + } + AucTokens[_id][0]=AucTokens[_id][0].add(1); pendingTokens[_id][0]=pendingTokens[_id][0].sub(1); + delete pendingTokens[_id][_indexForPending[_id][_order]]; + */ + } + else { + status[_id][_order] = Tokenstatus.pending; + /* + pendingTokens[_id][_indexForPending[_id][_order]] = _order; + pendingTokens[_id][0]=pendingTokens[_id][0].add(1); AucTokens[_id][0]=AucTokens[_id][0].sub(1); + delete AucTokens[_id][_listedForAuction[_id][_order]]; + */ + } + } + + function setAuctionInfo(uint256 _id, uint256 _order, uint256 _price, uint256 _time) internal{ + require(_getOwner(_id, _order) == tx.origin ,"not owner!"); + tokenAuction[_id][_order].price = _price; + tokenAuction[_id][_order].time = _time; + delete tokenAuction[_id][_order].HighestBid; + } + + function getAuctionPrice(uint256 _id, uint256 _order) public view returns (uint256){ + return tokenAuction[_id][_order].price; + } + + function getAuctionTime(uint256 _id, uint256 _order) public view returns (uint256){ + return tokenAuction[_id][_order].time; + } + + function AuctionToken1155(uint256 _tokenId, uint256 _order) public payable { + uint256 _TIME = getAuctionTime(_tokenId, _order); + uint256 _PRICE =getAuctionPrice(_tokenId, _order); + uint256 highestbidvalue; + address highestbidbuyer; + (highestbidvalue, highestbidbuyer) = getHighestBidInfo(_tokenId, _order); + require(getSaleState(_tokenId, _order) == Tokenstatus.onauction,"The product is not available"); + require(block.timestamp <= _TIME,"The auction is finished"); + require(msg.value >= _PRICE,"balance is not adequate"); + require(msg.value > highestbidvalue,"require more etd to acquire the product"); + payable(highestbidbuyer).transfer(highestbidvalue); + setHighestBidInfo(_tokenId, _order, msg.value, msg.sender); + emit AuctionNFT(_tokenId, msg.sender, msg.value); + } + + function revealAuction(uint256 _tokenId, uint256 _order) payable public returns(uint256,address){ + // Bid opening function When the time is up, the bid can be opened + require(getSaleState(_tokenId, _order) == Tokenstatus.onauction,"The product is not available"); + uint256 _TIME = getAuctionTime(_tokenId, _order); + require(block.timestamp > _TIME,"THE AUCTION IS NOT FINISHED");//the auction time is not due; + address _owner= _getOwner(_tokenId, _order); + uint256 highestbidvalue; + address highestbidbuyer; + (highestbidvalue, highestbidbuyer) = getHighestBidInfo(_tokenId, _order); + require(highestbidbuyer != address(0),"ERROR ADDRESS"); + + status[_tokenId][_order] = Tokenstatus.pending; + /* + pendingTokens[_tokenId][_indexForPending[_tokenId][_order]] = _order; + pendingTokens[_tokenId][0]=pendingTokens[_tokenId][0].add(1); AucTokens[_tokenId][0]=AucTokens[_tokenId][0].sub(1); + delete AucTokens[_tokenId][_listedForAuction[_tokenId][_order]]; + */ + + payable(_owner).transfer(highestbidvalue); + //safeTransferFrom(_owner,highestbidbuyer,_tokenId,1,""); + //_setOwner(_tokenId, _order, highestbidbuyer); + return (highestbidvalue, highestbidbuyer); + } + + function getOnSaleList(uint256 _id) external view returns (uint256, uint256[] memory){ + uint256 sum=0;uint256 j=0; + for (uint i =1; i<=allTokens[allTokensindex[_id]].totalSupply; i++){ + if (status[_id][i] == Tokenstatus.onsell)sum++; + } + uint256[] memory tokens = new uint256[](sum); + for (uint i =1; i<=allTokens[allTokensindex[_id]].totalSupply; i++){ + if (status[_id][i] == Tokenstatus.onsell)tokens[j++] = i; + } + return (sum, tokens); + } + + function getAuctionList(uint256 _id) external view returns (uint256, uint256[] memory){ + uint256 sum=0;uint256 j=0; + for (uint i =1; i<=allTokens[allTokensindex[_id]].totalSupply; i++){ + if (status[_id][i] == Tokenstatus.onauction)sum++; + } + uint256[] memory tokens = new uint256[](sum); + for (uint i =1; i<=allTokens[allTokensindex[_id]].totalSupply; i++){ + if (status[_id][i] == Tokenstatus.onauction)tokens[j++] = i; + } + return (sum, tokens); + } + + function getHighestBidInfo(uint256 _id, uint256 _order) public view returns (uint256, address){ + return (tokenAuction[_id][_order].HighestBid.value, tokenAuction[_id][_order].HighestBid.buyer); + } + + function setHighestBidInfo(uint256 _id, uint256 _order, uint256 _value, address _buyer) private { + //require(_getOwner(_id, _order) == tx.origin || operatorApproval[tokenOwners[_id][_order]][msg.sender] == true,"not owner!"); + tokenAuction[_id][_order].HighestBid.value = _value; + tokenAuction[_id][_order].HighestBid.buyer = _buyer; + } + + function getAllTokens() public view returns(allTokenstatus[] memory){ + return allTokens; + } + + function getTokenInfo(uint256 _tokenId) external view returns(TokenInfo memory){ + TokenInfo memory x; + x.totalSupply = allTokens[allTokensindex[_tokenId]].totalSupply; + x.originOwner = allTokens[allTokensindex[_tokenId]].originOwner; + x.name = _name[_tokenId]; + x.symbol = _symbol[_tokenId]; + x.tokenURI = tokenURIs[_tokenId]; + return x; + } + + function getPendingList(uint256 _id) external view returns (uint256,uint256[] memory){ + uint256 sum=0;uint256 j=0; + for (uint i =1; i<=allTokens[allTokensindex[_id]].totalSupply; i++){ + if (status[_id][i] == Tokenstatus.pending)sum++; + } + uint256[] memory tokens = new uint256[](sum); + for (uint i =1; i<=allTokens[allTokensindex[_id]].totalSupply; i++){ + if (status[_id][i] == Tokenstatus.pending)tokens[j++] = i; + } + return (sum, tokens); + } + + function getBalance(address owner) external view returns(uint256,uint256[] memory){ + uint256 sum=0; + for (uint i =0;i 0)sum++; + } + uint256[] memory tokens = new uint256[](sum); + uint j=0; + for (uint i =0;i 0){ + tokens[j++] = allTokens[i].tokenId; + } + } + return (sum, tokens); + } + + function getBalanceOfToken(address owner, uint256 _tokenId) external view returns(uint256,uint256[] memory){ + uint256 sum=0; + for (uint i =1;i<=allTokens[allTokensindex[_tokenId]].totalSupply;i++){ + if (_getOwner(_tokenId, i) == owner)sum++; + } + uint256[] memory tokens = new uint256[](sum); + uint j=0; + for (uint i =1;i<=allTokens[allTokensindex[_tokenId]].totalSupply;i++){ + if (_getOwner(_tokenId, i) == owner){ + tokens[j++] = i; + } + } + return (sum,tokens); + } +} + diff --git a/NFT/NFT_market.sol b/NFT/NFT_market.sol new file mode 100755 index 0000000..23193ca --- /dev/null +++ b/NFT/NFT_market.sol @@ -0,0 +1,371 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "./ERC1155.sol"; +import "./SafeMath.sol"; +import "./ERC165.sol"; +import "./ERC721.sol"; + +contract ImageContract{ + mapping(address => uint256[]) OwnersCollections; + mapping(uint256 => address) TokensFromContract; + mapping(uint256 => address) CollectionFromContract; + /* + mapping(address => uint256[]) OwnersTokens; + mapping(address => uint256) OwnersTokensNum; + mapping(uint256 => uint256) TokensIndex; +*/ + address[] allContract; + + struct TokenInfo { + bool _isSell; + bool _isAuction; + uint256 _price; + address _owner; + uint256 _tokenId; + string _name; + string _symbol; + string _uri; + uint256 _aucPrice; + uint256 _aucTime; + uint256 _collectionnId; + } + + //NFT_MINT NFTTOKEN; + address public admin; + address public owner; + + event BoughtNFT(uint256 _tokenId, address _buyer, uint256 _price); + event AuctionNFT(uint256 _tokenId, address _buyer, uint256 _price); + + uint256[50] public recentTokens; + uint256 recent_point; + + modifier onlyAdmin() { + require( + msg.sender == admin, + "Only admin can call this." + ); + _; + } + + modifier onlyOwner() { + require( + msg.sender == owner, + "Only owner can call this." + ); + _; + } + + constructor(){ + owner = msg.sender; + admin = address(this); + } + + function AddCollection(string memory name_, uint256 collectionId, string memory _uri) public { + if (allContract.length == 0){ + ERC1155 A = new ERC1155(admin); + allContract.push(address(A)); + } + ERC1155 NFTTOKEN = ERC1155(allContract[allContract.length-1]); + if (NFTTOKEN.getCollectionsNum()>=1000){ + ERC1155 A = new ERC1155(admin); + allContract.push(address(A)); + } + NFTTOKEN = ERC1155(allContract[allContract.length-1]); + NFTTOKEN.Addcollection(name_,collectionId,_uri); + OwnersCollections[msg.sender].push(collectionId); + CollectionFromContract[collectionId] = address(NFTTOKEN); + } + +/* + function isNeedChangeContract() external returns (bool){ + if (allContract.length == 0){ + ERC1155 A = new ERC1155(admin); + allContract.push(address(A)); + return true; + } + ERC1155 NFTTOKEN = ERC1155(allContract[allContract.length-1]); + if (NFTTOKEN.getCollectionsNum() <1000) return false; + else { + ERC1155 A = new ERC1155(admin); + allContract.push(address(A)); + return true; + } + } +*/ + function addToken(string memory name_, string memory symbol_, uint256 _tokenId,bytes memory data,string memory _uri, uint256 collectionId) public { + require(TokensFromContract[_tokenId] == address(0), "The Token is exist"); + require(CollectionFromContract[collectionId] != address(0), "The Collection is not exist!"); + ERC1155 NFTTOKEN = ERC1155(CollectionFromContract[collectionId]); + NFTTOKEN.AddToken(name_, symbol_, _tokenId, data, _uri, collectionId); + if (recent_point < 50){ + recentTokens[recent_point++] = _tokenId; + } + else{ + for (uint i=0; i<49; i++){ + recentTokens[i]=recentTokens[i+1]; + } + recentTokens[49] = _tokenId; + } + TokensFromContract[_tokenId] = address(NFTTOKEN); + + /* + OwnersTokensNum[msg.sender]++; + TokensIndex[_tokenId] = OwnersTokens[msg.sender].length; + OwnersTokens[msg.sender].push(_tokenId); + */ + } + + + + function updatePrice(uint _id, uint _price) public returns (bool){ + ERC1155 NFTTOKEN = ERC1155(TokensFromContract[_id]); + require(NFTTOKEN._getOwner(_id) == msg.sender,"not owner!"); + require(NFTTOKEN.getAuctionState(_id) == false,"the product is auction"); + NFTTOKEN.setNFTPrice(_id,_price); + return true; + } + + function approveForSale(uint _tokenId, uint _price) public { + ERC1155 NFTTOKEN = ERC1155(TokensFromContract[_tokenId]); + require(NFTTOKEN._getOwner(_tokenId) == msg.sender,"not owner"); + require(NFTTOKEN.getAuctionState(_tokenId) == false,"the product is auction"); + require(NFTTOKEN.getSaleState(_tokenId) == false,"the product is selling"); + NFTTOKEN.setSaleState(_tokenId, true); + updatePrice(_tokenId,_price); + NFTTOKEN.setApprovalForAll(admin, true); + } + + function approveForAuction(uint _tokenId, uint _price, uint _time) public { + ERC1155 NFTTOKEN = ERC1155(TokensFromContract[_tokenId]); + require(NFTTOKEN._getOwner(_tokenId) == msg.sender,"not owner!"); + require(NFTTOKEN.getSaleState(_tokenId) == false,"the product is selling"); + require(NFTTOKEN.getAuctionState(_tokenId) == false,"the product is auction"); + NFTTOKEN.setAuctionState(_tokenId, true); + NFTTOKEN.setAuctionInfo(_tokenId, _price, block.timestamp + _time); + NFTTOKEN.setApprovalForAll(admin, true); + //approveNFT(admin,true); + } + + function nftSold(uint _tokenId) internal { + ERC1155 NFTTOKEN = ERC1155(TokensFromContract[_tokenId]); + if (NFTTOKEN.getSaleState(_tokenId) == true){ + NFTTOKEN.setSaleState(_tokenId, false); + } + if (NFTTOKEN.getAuctionState(_tokenId) == true){ + NFTTOKEN.setAuctionState(_tokenId, false); + } + } + + function buyImage(uint256 _tokenId) public payable { + ERC1155 NFTTOKEN = ERC1155(TokensFromContract[_tokenId]); + uint256 _price = NFTTOKEN.getNFTPrice(_tokenId); + require(NFTTOKEN.getSaleState(_tokenId) == true,"The product is not available"); + require(msg.value >= _price,"too less etd"); + payable(msg.sender).transfer(msg.value - _price); + + address _owner= NFTTOKEN._getOwner(_tokenId); + payable(_owner).transfer(_price); + NFTTOKEN.safeTransferFrom(_owner,msg.sender,_tokenId,1,""); + //NFTTOKEN._setOwner(_tokenId,msg.sender); + nftSold(_tokenId); + + /* + delete(OwnersTokens[_owner][TokensIndex[_tokenId]]); + OwnersTokensNum[_owner]--; + OwnersTokensNum[msg.sender]++; + OwnersTokens[msg.sender].push(_tokenId); + TokensIndex[_tokenId] = OwnersTokens[msg.sender].length-1; + */ + + emit BoughtNFT(_tokenId, msg.sender, _price); + } + +/* + function getWetd(uint256 _value) payable public { + require(msg.sender.value >= _value,"etd is not adequate"); + WTED.transfer(msg.sender,_value); + msg.sender.transfer(msg.sender - _value); + } + + function getWetdBalances() payable public returns(uint256){ + return WETD._balanceOf(msg.sender); + } + + function AuctionImage(uint256 _tokenId, uint256 _value) public payable { + require(_listedForAuction[_tokenId] == false,"The product is not available"); + require(getWetdBalances() >= _value,"balance is not adequate"); + + emit AuctionNFT(_tokenId,msg.sender,_value); + } + */ + + function AuctionImage(uint256 _tokenId) public payable { + ERC1155 NFTTOKEN = ERC1155(TokensFromContract[_tokenId]); + uint256 _TIME = NFTTOKEN.getAuctionTime(_tokenId); + uint256 _PRICE = NFTTOKEN.getAuctionPrice(_tokenId); + uint256 highestbidvalue; + address highestbidbuyer; + (highestbidvalue, highestbidbuyer) = NFTTOKEN.getHighestBidInfo(_tokenId); + require(NFTTOKEN.getAuctionState(_tokenId) == true,"The product is not available"); + require(block.timestamp <= _TIME,"The auction is finished"); + require(msg.value >= _PRICE,"balance is not adequate"); + require(msg.value > highestbidvalue,"require more etd to acquire the product"); + payable(highestbidbuyer).transfer(highestbidvalue); + NFTTOKEN.setHighestBidInfo(_tokenId, msg.value, msg.sender); + emit AuctionNFT(_tokenId, msg.sender, msg.value); + } + + function revealAuction(uint256 _tokenId) payable public{ + ERC1155 NFTTOKEN = ERC1155(TokensFromContract[_tokenId]); + // Bid opening function When the time is up, the bid can be opened + require(NFTTOKEN.getAuctionState(_tokenId) == true,"The product is not available"); + uint256 _TIME = NFTTOKEN.getAuctionTime(_tokenId); + require(block.timestamp > _TIME,"THE AUCTION IS NOT FINISHED");//the auction time is not due; + address _owner= NFTTOKEN._getOwner(_tokenId); + uint256 highestbidvalue; + address highestbidbuyer; + (highestbidvalue, highestbidbuyer) = NFTTOKEN.getHighestBidInfo(_tokenId); + nftSold(_tokenId); + require(highestbidbuyer != address(0),"ERROR ADDRESS"); + payable(_owner).transfer(highestbidvalue); + NFTTOKEN.safeTransferFrom(_owner,highestbidbuyer,_tokenId,1,""); + //NFTTOKEN._setOwner(_tokenId,highestbidbuyer); + + /* + delete(OwnersTokens[ _owner][TokensIndex[_tokenId]]); + OwnersTokensNum[ _owner]--; + OwnersTokensNum[highestbidbuyer]++; + OwnersTokens[highestbidbuyer].push(_tokenId); + TokensIndex[_tokenId] = OwnersTokens[highestbidbuyer].length-1; + */ + } + + + function getTokenInfo(uint256 tokenId) public view returns (TokenInfo memory){ + require(TokensFromContract[tokenId] != address(0),"The Token is not exist!"); + ERC1155 NFTTOKEN = ERC1155(TokensFromContract[tokenId]); + require(NFTTOKEN._getOwner(tokenId) != address(0),"The Token is not exist!"); + TokenInfo memory tokeninfo; + tokeninfo._isSell = NFTTOKEN.getSaleState(tokenId); + tokeninfo._isAuction = NFTTOKEN.getAuctionState(tokenId); + tokeninfo._price = NFTTOKEN.getNFTPrice(tokenId); + tokeninfo._tokenId = tokenId; + tokeninfo._name = NFTTOKEN.name(tokenId); + tokeninfo._symbol = NFTTOKEN.symbol(tokenId); + tokeninfo._uri = NFTTOKEN.uri(tokenId); + tokeninfo._owner = NFTTOKEN._getOwner(tokenId); + tokeninfo._aucPrice = NFTTOKEN.getAuctionPrice(tokenId); + tokeninfo._aucTime = NFTTOKEN.getAuctionTime(tokenId); + tokeninfo._collectionnId = NFTTOKEN.getCollectionId(tokenId); + return tokeninfo; + } + /* + function getNftAddress() view public onlyOwner returns(address){ + return address(NFTTOKEN); + } + */ + function getRecentTokens() view public returns(uint256[50] memory){ + return recentTokens; + } + function getTokensFrom(uint256 tokenId) view public returns(address){ + require(TokensFromContract[tokenId] != address(0)); + return TokensFromContract[tokenId]; + } + function getCollectionsFrom(uint256 collectionId) view public returns(address){ + require(CollectionFromContract[collectionId]!= address(0)); + return CollectionFromContract[collectionId]; + } + + function getOwnersTokens(address Owner) view public returns(uint256,uint256[] memory){ + //return (OwnersTokensNum[Owner],OwnersTokens[Owner]); + } + + +} + +contract ImplementContract is ImageContract{ + + address[] Contract721; + // mapping TokensPrice; + struct Token721Info{ + uint256 _id; + address owner; + string URI; + } + constructor(){ + } + bytes4 internal constant INTERFACE_SIGNATURE_ERC165 = 0x01ffc9a7; + bytes4 internal constant INTERFACE_SIGNATURE_ERC1155 = 0xd9b67a26; + bytes4 internal constant INTERFACE_SIGNATURE_ERC721 = 0x80ac58cd; + bytes4 internal constant InterfaceId_ERC721Enumerable = 0x780e9d63; + bytes4 internal constant InterfaceId_ERC721Metadata = 0x5b5e139f; + bytes4 private constant InterfaceId_Invalid = 0xffffffff; + + function doesContractImplementInterface(address _contract, bytes4 _interfaceId) internal view returns (bool) { + uint256 success; + uint256 result; + + (success, result) = noThrowCall(_contract, INTERFACE_SIGNATURE_ERC165); + if ((success==0)||(result==0)) { + return false; + } + + (success, result) = noThrowCall(_contract, InterfaceId_Invalid); + if ((success==0)||(result!=0)) { + return false; + } + + (success, result) = noThrowCall(_contract, _interfaceId); + if ((success==1)&&(result==1)) { + return true; + } + return false; + } + + function noThrowCall(address _contract, bytes4 _interfaceId) internal view returns (uint256 success, uint256 result) { + bytes4 erc165ID = INTERFACE_SIGNATURE_ERC165; + + assembly { + let x := mload(0x40) // Find empty storage location using "free memory pointer" + mstore(x, erc165ID) // Place signature at beginning of empty storage + mstore(add(x, 0x04), _interfaceId) // Place first argument directly next to signature + + success := staticcall( + 30000, // 30k gas + _contract, // To addr + x, // Inputs are stored at location x + 0x24, // Inputs are 36 bytes long + x, // Store output over input (saves space) + 0x20) // Outputs are 32 bytes long + + result := mload(x) // Load the result + } + } + + function Implementation721(address Contract) external returns(uint256,Token721Info[] memory){ + require(doesContractImplementInterface(Contract,INTERFACE_SIGNATURE_ERC165), "Does not support 165"); + require(doesContractImplementInterface(Contract,INTERFACE_SIGNATURE_ERC721) + &&doesContractImplementInterface(Contract,InterfaceId_ERC721Enumerable), "Does not support 721"); + Contract721.push(Contract); + Token721Info[] memory all721Token; + ERC721Enumerable erc721Enumerable = ERC721Enumerable(Contract); + ERC721basic erc721basic = ERC721basic(Contract); + ERC721Metadata erc721Metadata = ERC721Metadata(Contract); + uint256 TokenSum = erc721Enumerable.totalSupply(); + for (uint i=0; i=price,"Too less ETD"); + + // } +} \ No newline at end of file diff --git a/NFT/NFTtoken.sol b/NFT/NFTtoken.sol new file mode 100755 index 0000000..f7f0143 --- /dev/null +++ b/NFT/NFTtoken.sol @@ -0,0 +1,252 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "./ERC1155.sol"; +import "./SafeMath.sol"; + +contract NFT_MINT is ERC1155,ERC1155Metadata_URI{ + using SafeMath for uint256; + + struct Collection { + address owner; + uint256[] allTokens; + string uri; + string name; + } + mapping(uint256 => uint256) tokenFromCollection; + uint256[] public allCollection; + mapping(uint256 => Collection) Collections; + //collection的信息 + + struct BidInfo {//竞标信息 + address buyer; + uint256 value; + } + + + mapping(uint256 => uint256) imagePrice; + struct auctionData { + uint256 price; + uint256 time; + BidInfo HighestBid; + } + mapping(uint256 => auctionData) tokenAuction; + //拍卖NFT信息 + + enum Tokenstatus{ pending, onsell, onauction } + struct allTokenstatus { + Tokenstatus status; + uint256 tokenId; + } + mapping(uint256 => allTokenstatus[]) allTokens; + mapping(uint256 => uint256) allTokensindex; + //所有Token的信息 + + struct TokenStatus { + bool isOnSale; + uint256 index; + } + mapping(uint256 => uint256[]) public SaleTokens; + mapping(uint256 => uint256[]) public AucTokens; + mapping(uint256 => uint256[]) public pendingTokens; + mapping(uint256 => TokenStatus) _listedForAuction; + mapping(uint256 => TokenStatus) _listedForSale; + mapping(uint256 => uint256) _indexForPending; + //出售的NFT,拍卖的NFT,以及无状态的NFT的信息 + + mapping(uint256 => string) internal _name; + mapping(uint256 => string) internal _symbol; + + + mapping(uint256 => string) internal tokenURIs; + mapping(uint256 => address) internal tokenOwners; + + constructor(){} + + function name(uint256 _id) external view returns (string memory){ + return _name[_id]; + } + function symbol(uint256 _id) external view returns(string memory){ + return _symbol[_id]; + } + function uri(uint256 _id) external view returns (string memory) { + // require(exists(_id)); + return tokenURIs[_id]; + } + + function Addcollection(string memory name_, uint256 collectionId, string memory _uri) public { + Collections[collectionId].owner = tx.origin; + Collections[collectionId].name = name_; + Collections[collectionId].uri = _uri; + allCollection.push(collectionId); + SaleTokens[collectionId].push(0); + AucTokens[collectionId].push(0); + pendingTokens[collectionId].push(0); + } + + + function AddToken(string memory name_, string memory symbol_, uint256 _tokenId,bytes memory data,string memory _uri, uint256 collectionId) public { + _mint(tx.origin,_tokenId,1,data); + _name[_tokenId] = name_; + _symbol[_tokenId] = symbol_; + tokenOwners[_tokenId] = tx.origin; + _setURI(_tokenId,_uri); + allTokenstatus memory x; + x.status = Tokenstatus.pending; + x.tokenId = _tokenId; + allTokens[collectionId].push(x); + allTokensindex[_tokenId] = allTokens[collectionId].length - 1; + pendingTokens[collectionId].push(_tokenId); + _indexForPending[_tokenId] = pendingTokens[collectionId].length - 1; + pendingTokens[collectionId][0]++; + Collections[collectionId].allTokens.push(_tokenId); + tokenFromCollection[_tokenId] = collectionId; + } + + function _setURI(uint256 _id,string memory _uri) internal { + tokenURIs[_id] = _uri; + } + function _setOwner(uint256 _id,address _owner) public { + require (tokenOwners[_id] == msg.sender || operatorApproval[tokenOwners[_id]][msg.sender] == true,"Is not owner!"); + tokenOwners[_id] = _owner; + } + + function _getOwner(uint256 _id) public view returns (address){ + return tokenOwners[_id]; + } + + function setImagePrice(uint256 _id, uint256 _price) external { + require(_getOwner(_id) == tx.origin,"not owner!"); + imagePrice[_id] = _price; + } + + function getImagePrice(uint256 _id) external view returns (uint256){ + return imagePrice[_id]; + } + + function setSaleState(uint256 _id, bool isSale) external { + require(_getOwner(_id) == tx.origin,"not owner!"); + uint256 collectionId = tokenFromCollection[_id]; + if (isSale == true){ + allTokens[collectionId][allTokensindex[_id]].status = Tokenstatus.onsell; + if (_listedForSale[_id].index == 0){ + SaleTokens[collectionId].push(_id); + _listedForSale[_id].index = SaleTokens[collectionId].length-1; + } + else{ + SaleTokens[collectionId][_listedForSale[_id].index] = _id; + } + SaleTokens[collectionId][0]=SaleTokens[collectionId][0].add(1); pendingTokens[collectionId][0]=pendingTokens[collectionId][0].sub(1); + delete pendingTokens[collectionId][_indexForPending[_id]]; + } + else { + allTokens[collectionId][allTokensindex[_id]].status = Tokenstatus.pending; + pendingTokens[collectionId][_indexForPending[_id]] = _id; + pendingTokens[collectionId][0]=pendingTokens[collectionId][0].add(1); SaleTokens[collectionId][0]=SaleTokens[collectionId][0].sub(1); + delete SaleTokens[collectionId][_listedForSale[_id].index]; + } + _listedForSale[_id].isOnSale = isSale; + } + + function getSaleState(uint256 _id) external view returns (bool){ + return _listedForSale[_id].isOnSale; + } + + function setAuctionState(uint256 _id, bool isAuction) external { + require(_getOwner(_id) == tx.origin,"not owner!"); + uint256 collectionId = tokenFromCollection[_id]; + if (isAuction == true){ + allTokens[collectionId][allTokensindex[_id]].status = Tokenstatus.onauction; + if (_listedForAuction[_id].index == 0){ + AucTokens[collectionId].push(_id); + _listedForAuction[_id].index = AucTokens[collectionId].length-1; + } + else{ + AucTokens[collectionId][_listedForAuction[_id].index] = _id; + } + AucTokens[collectionId][0]=AucTokens[collectionId][0].add(1); pendingTokens[collectionId][0]=pendingTokens[collectionId][0].sub(1); + delete pendingTokens[collectionId][_indexForPending[_id]]; + } + else { + allTokens[collectionId][allTokensindex[_id]].status = Tokenstatus.pending; + pendingTokens[collectionId][_indexForPending[_id]] = _id; + pendingTokens[collectionId][0]=pendingTokens[collectionId][0].add(1); AucTokens[collectionId][0]=AucTokens[collectionId][0].sub(1); + delete AucTokens[collectionId][_listedForAuction[_id].index]; + } + _listedForAuction[_id].isOnSale = isAuction; + } + + function getAuctionState(uint256 _id) external view returns (bool) { + return _listedForAuction[_id].isOnSale; + } + function setAuctionInfo(uint256 _id, uint256 _price, uint256 _time) external{ + require(_getOwner(_id) == tx.origin ,"not owner!"); + tokenAuction[_id].price = _price; + tokenAuction[_id].time = _time; + delete tokenAuction[_id].HighestBid; + } + + function getAuctionPrice(uint256 _id) external view returns (uint256){ + return tokenAuction[_id].price; + } + + function getAuctionTime(uint256 _id) external view returns (uint256){ + return tokenAuction[_id].time; + } + + function getOnSaleList(uint256 collectionId) external view returns (uint256[] memory){ + /* uint256[] memory _List; + for (uint i = 0; i < SaleTokens.length;i++){ + if (SaleTokens[i] != 0){ + _List.push(SaleTokens[i]); + } + }*/ + return SaleTokens[collectionId]; + } + + function getAuctionList(uint256 collectionId) external view returns (uint256[] memory){ + /*uint256[] memory _List; + for (uint i = 0; i < SaleTokens.length;i++){ + if (AucTokens[i] != 0){ + _List.push(AucTokens[i]); + } + }*/ + return AucTokens[collectionId]; + } + + function getHighestBidInfo(uint256 _id) external view returns (uint256, address){ + return (tokenAuction[_id].HighestBid.value, tokenAuction[_id].HighestBid.buyer); + } + + function setHighestBidInfo(uint256 _id, uint256 _value, address _buyer) external { + require(_getOwner(_id) == tx.origin || operatorApproval[tokenOwners[_id]][msg.sender] == true,"not owner!"); + tokenAuction[_id].HighestBid.value = _value; + tokenAuction[_id].HighestBid.buyer = _buyer; + } + + function getAllTokens(uint256 CollectionId) public view returns(allTokenstatus[] memory){ + return allTokens[CollectionId]; + } + + function getPendingList(uint256 collectionId) external view returns (uint256[] memory){ + /*uint256[] memory _List; + for (uint i = 0; i < SaleTokens.length;i++){ + if (AucTokens[i] != 0){ + _List.push(AucTokens[i]); + } + }*/ + return pendingTokens[collectionId]; + } + + function getCollectionId(uint256 _tokenId) external view returns(uint256){ + return tokenFromCollection[_tokenId]; + } + + function getCollectionsNum() external view returns(uint256){ + return allCollection.length; + } + + function getCollectionInfo(uint256 _collectionnId) external view returns(Collection memory){ + return Collections[_collectionnId]; + } +} diff --git a/NFT/SafeMath.sol b/NFT/SafeMath.sol new file mode 100755 index 0000000..5edf715 --- /dev/null +++ b/NFT/SafeMath.sol @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + + +/** + * @title SafeMath + * @dev Math operations with safety checks that throw on error + */ +library SafeMath { + + /** + * @dev Multiplies two numbers, throws on overflow. + */ + function mul(uint256 a, uint256 b) internal pure returns (uint256 c) { + // Gas optimization: this is cheaper than asserting 'a' not being zero, but the + // benefit is lost if 'b' is also tested. + // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522 + if (a == 0) { + return 0; + } + + c = a * b; + assert(c / a == b); + return c; + } + + /** + * @dev Integer division of two numbers, truncating the quotient. + */ + function div(uint256 a, uint256 b) internal pure returns (uint256) { + // assert(b > 0); // Solidity automatically throws when dividing by 0 + // uint256 c = a / b; + // assert(a == b * c + a % b); // There is no case in which this doesn't hold + return a / b; + } + + /** + * @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend). + */ + function sub(uint256 a, uint256 b) internal pure returns (uint256) { + assert(b <= a); + return a - b; + } + + /** + * @dev Adds two numbers, throws on overflow. + */ + function add(uint256 a, uint256 b) internal pure returns (uint256 c) { + c = a + b; + assert(c >= a); + return c; + } +} \ No newline at end of file diff --git a/NFT/TokenWETD.sol b/NFT/TokenWETD.sol new file mode 100755 index 0000000..11e3de5 --- /dev/null +++ b/NFT/TokenWETD.sol @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +contract WETH9 { + string internal name; + string internal symbol; + uint8 internal decimals; + uint256 internal totalsupply; + + event Approval(address indexed src, address indexed guy, uint wad); + event Transfer(address indexed src, address indexed dst, uint wad); + event Deposit(address indexed dst, uint wad); + event Withdrawal(address indexed src, uint wad); + + mapping (address => uint) internal balanceOf; + mapping (address => mapping (address => uint)) internal allowance; + + constructor (){ + name = "Wrapped Etd"; + symbol = "WETH"; + decimals = 18; + totalsupply = 100000000000 * (10 ** decimals); + balanceOf[msg.sender] = totalsupply; + } + + function withdraw(uint wad) public { + require(balanceOf[msg.sender] >= wad); + balanceOf[msg.sender] -= wad; + payable(msg.sender).transfer(wad); + emit Withdrawal(msg.sender, wad); + } + + function totalSupply() public view returns (uint) { + return totalsupply; + } + + function approve(address guy, uint wad) public returns (bool) { + allowance[msg.sender][guy] = wad; + emit Approval(msg.sender, guy, wad); + return true; + } + + function transfer(address dst, uint wad) public returns (bool) { + return transferFrom(msg.sender, dst, wad); + } + + function transferFrom(address src, address dst, uint wad) + public + returns (bool) + { + require(balanceOf[src] >= wad); + + if (src != msg.sender) { + require(allowance[src][msg.sender] != 0,"Not permit"); + require(allowance[src][msg.sender] >= wad,"allowance is too low"); + allowance[src][msg.sender] -= wad; + } + + balanceOf[src] -= wad; + balanceOf[dst] += wad; + + emit Transfer(src, dst, wad); + + return true; + } + + function _balanceOf(address who) external view returns (uint256){ + return balanceOf[who]; + } +} \ No newline at end of file diff --git a/NFT/erc1155.sol b/NFT/erc1155.sol new file mode 100755 index 0000000..e2b71a1 --- /dev/null +++ b/NFT/erc1155.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "./SafeMath.sol"; +import "./Address.sol"; +import "./Common.sol"; +import "./IERC1155TokenReceiver.sol"; +import "./IERC1155.sol"; +import "./ERC165.sol"; +import "./IERC1155Metadata.sol"; + +// A sample implementation of core ERC1155 function. +contract ERC1155 is IERC1155, ERC165, CommonConstants +{ + using SafeMath for uint256; + using Address for address; + + // id => (owner => balance) + mapping (uint256 => mapping(address => uint256)) internal balances; + + // owner => (operator => approved) + mapping (address => mapping(address => bool)) internal operatorApproval; + +/////////////////////////////////////////// ERC165 ////////////////////////////////////////////// + + /* + bytes4(keccak256('supportsInterface(bytes4)')); + */ + bytes4 constant private INTERFACE_SIGNATURE_ERC165 = 0x01ffc9a7; + + /* + bytes4(keccak256("safeTransferFrom(address,address,uint256,uint256,bytes)")) ^ + bytes4(keccak256("safeBatchTransferFrom(address,address,uint256[],uint256[],bytes)")) ^ + bytes4(keccak256("balanceOf(address,uint256)")) ^ + bytes4(keccak256("balanceOfBatch(address[],uint256[])")) ^ + bytes4(keccak256("setApprovalForAll(address,bool)")) ^ + bytes4(keccak256("isApprovedForAll(address,address)")); + */ + bytes4 constant private INTERFACE_SIGNATURE_ERC1155 = 0xd9b67a26; + + function supportsInterface(bytes4 _interfaceId) external pure returns (bool) { + if (_interfaceId == INTERFACE_SIGNATURE_ERC165 || + _interfaceId == INTERFACE_SIGNATURE_ERC1155) { + return true; + } + + return false; + } +/////////////////////////////////////////// ERC1155 ////////////////////////////////////////////// + + /** + @notice Transfers `_value` amount of an `_id` from the `_from` address to the `_to` address specified (with safety call). + @dev Caller must be approved to manage the tokens being transferred out of the `_from` account (see "Approval" section of the standard). + MUST revert if `_to` is the zero address. + MUST revert if balance of holder for token `_id` is lower than the `_value` sent. + MUST revert on any other error. + MUST emit the `TransferSingle` event to reflect the balance change (see "Safe Transfer Rules" section of the standard). + After the above conditions are met, this function MUST check if `_to` is a smart contract (e.g. code size > 0). If so, it MUST call `onERC1155Received` on `_to` and act appropriately (see "Safe Transfer Rules" section of the standard). + @param _from Source address + @param _to Target address + @param _id ID of the token type + @param _value Transfer amount + @param _data Additional data with no specified format, MUST be sent unaltered in call to `onERC1155Received` on `_to` + */ + function safeTransferFrom(address _from, address _to, uint256 _id, uint256 _value, bytes calldata _data) internal { + + require(_to != address(0x0), "_to must be non-zero."); + require(_from == msg.sender || operatorApproval[_from][msg.sender] == true, "Need operator approval for 3rd party transfers."); + // SafeMath will throw with insuficient funds _from + // or if _id is not valid (balance will be 0) + balances[_id][_from] = balances[_id][_from].sub(_value); + balances[_id][_to] = _value.add(balances[_id][_to]); + + // MUST emit event + emit TransferSingle(msg.sender, _from, _to, _id, _value); + + // Now that the balance is updated and the event was emitted, + // call onERC1155Received if the destination is a contract. + if (_to.isContract()) { + _doSafeTransferAcceptanceCheck(msg.sender, _from, _to, _id, _value, _data); + } + } + + /** + @notice Transfers `_values` amount(s) of `_ids` from the `_from` address to the `_to` address specified (with safety call). + @dev Caller must be approved to manage the tokens being transferred out of the `_from` account (see "Approval" section of the standard). + MUST revert if `_to` is the zero address. + MUST revert if length of `_ids` is not the same as length of `_values`. + MUST revert if any of the balance(s) of the holder(s) for token(s) in `_ids` is lower than the respective amount(s) in `_values` sent to the recipient. + MUST revert on any other error. + MUST emit `TransferSingle` or `TransferBatch` event(s) such that all the balance changes are reflected (see "Safe Transfer Rules" section of the standard). + Balance changes and events MUST follow the ordering of the arrays (_ids[0]/_values[0] before _ids[1]/_values[1], etc). + After the above conditions for the transfer(s) in the batch are met, this function MUST check if `_to` is a smart contract (e.g. code size > 0). If so, it MUST call the relevant `ERC1155TokenReceiver` hook(s) on `_to` and act appropriately (see "Safe Transfer Rules" section of the standard). + @param _from Source address + @param _to Target address + @param _ids IDs of each token type (order and length must match _values array) + @param _values Transfer amounts per token type (order and length must match _ids array) + @param _data Additional data with no specified format, MUST be sent unaltered in call to the `ERC1155TokenReceiver` hook(s) on `_to` + */ + function safeBatchTransferFrom(address _from, address _to, uint256[] calldata _ids, uint256[] calldata _values, bytes calldata _data) internal { + + // MUST Throw on errors + require(_to != address(0x0), "destination address must be non-zero."); + require(_ids.length == _values.length, "_ids and _values array length must match."); + require(_from == msg.sender || operatorApproval[_from][msg.sender] == true, "Need operator approval for 3rd party transfers."); + + for (uint256 i = 0; i < _ids.length; ++i) { + uint256 id = _ids[i]; + uint256 value = _values[i]; + + // SafeMath will throw with insuficient funds _from + // or if _id is not valid (balance will be 0) + balances[id][_from] = balances[id][_from].sub(value); + balances[id][_to] = value.add(balances[id][_to]); + } + + // Note: instead of the below batch versions of event and acceptance check you MAY have emitted a TransferSingle + // event and a subsequent call to _doSafeTransferAcceptanceCheck in above loop for each balance change instead. + // Or emitted a TransferSingle event for each in the loop and then the single _doSafeBatchTransferAcceptanceCheck below. + // However it is implemented the balance changes and events MUST match when a check (i.e. calling an external contract) is done. + + // MUST emit event + emit TransferBatch(msg.sender, _from, _to, _ids, _values); + + // Now that the balances are updated and the events are emitted, + // call onERC1155BatchReceived if the destination is a contract. + if (_to.isContract()) { + _doSafeBatchTransferAcceptanceCheck(msg.sender, _from, _to, _ids, _values, _data); + } + } + + /** + @notice Get the balance of an account's Tokens. + @param _owner The address of the token holder + @param _id ID of the Token + @return The _owner's balance of the Token type requested + */ + function balanceOf(address _owner, uint256 _id) external view returns (uint256) { + // The balance of any account can be calculated from the Transfer events history. + // However, since we need to keep the balances to validate transfer request, + // there is no extra cost to also privide a querry function. + return balances[_id][_owner]; + } + + + /** + @notice Get the balance of multiple account/token pairs + @param _owners The addresses of the token holders + @param _ids ID of the Tokens + @return The _owner's balance of the Token types requested (i.e. balance for each (owner, id) pair) + */ + function balanceOfBatch(address[] calldata _owners, uint256[] calldata _ids) external view returns (uint256[] memory) { + + require(_owners.length == _ids.length); + + uint256[] memory balances_ = new uint256[](_owners.length); + + for (uint256 i = 0; i < _owners.length; ++i) { + balances_[i] = balances[_ids[i]][_owners[i]]; + } + + return balances_; + } + + /** + @notice Enable or disable approval for a third party ("operator") to manage all of the caller's tokens. + @dev MUST emit the ApprovalForAll event on success. + @param _operator Address to add to the set of authorized operators + @param _approved True if the operator is approved, false to revoke approval + */ + function setApprovalForAll(address _operator, bool _approved) external { + operatorApproval[tx.origin][_operator] = _approved; + emit ApprovalForAll(tx.origin, _operator, _approved); + } + + /** + @notice Queries the approval status of an operator for a given owner. + @param _owner The owner of the Tokens + @param _operator Address of authorized operator + @return True if the operator is approved, false if not + */ + function isApprovedForAll(address _owner, address _operator) external view returns (bool) { + return operatorApproval[_owner][_operator]; + } + +/////////////////////////////////////////// Internal ////////////////////////////////////////////// + + function _doSafeTransferAcceptanceCheck(address _operator, address _from, address _to, uint256 _id, uint256 _value, bytes memory _data) internal { + + // If this was a hybrid standards solution you would have to check ERC165(_to).supportsInterface(0x4e2312e0) here but as this is a pure implementation of an ERC-1155 token set as recommended by + // the standard, it is not necessary. The below should revert in all failure cases i.e. _to isn't a receiver, or it is and either returns an unknown value or it reverts in the call to indicate non-acceptance. + + + // Note: if the below reverts in the onERC1155Received function of the _to address you will have an undefined revert reason returned rather than the one in the require test. + // If you want predictable revert reasons consider using low level _to.call() style instead so the revert does not bubble up and you can revert yourself on the ERC1155_ACCEPTED test. + require(ERC1155TokenReceiver(_to).onERC1155Received(_operator, _from, _id, _value, _data) == ERC1155_ACCEPTED, "contract returned an unknown value from onERC1155Received"); + } + + function _doSafeBatchTransferAcceptanceCheck(address _operator, address _from, address _to, uint256[] memory _ids, uint256[] memory _values, bytes memory _data) internal { + + // If this was a hybrid standards solution you would have to check ERC165(_to).supportsInterface(0x4e2312e0) here but as this is a pure implementation of an ERC-1155 token set as recommended by + // the standard, it is not necessary. The below should revert in all failure cases i.e. _to isn't a receiver, or it is and either returns an unknown value or it reverts in the call to indicate non-acceptance. + + // Note: if the below reverts in the onERC1155BatchReceived function of the _to address you will have an undefined revert reason returned rather than the one in the require test. + // If you want predictable revert reasons consider using low level _to.call() style instead so the revert does not bubble up and you can revert yourself on the ERC1155_BATCH_ACCEPTED test. + require(ERC1155TokenReceiver(_to).onERC1155BatchReceived(_operator, _from, _ids, _values, _data) == ERC1155_BATCH_ACCEPTED, "contract returned an unknown value from onERC1155BatchReceived"); + } + + function _mint(address to,uint256 id,uint256 amount,bytes memory data) internal { + require(to != address(0), "ERC1155: mint to the zero address"); + address operator = msg.sender; + balances[id][to] += amount.add(balances[id][to]); + emit TransferSingle(operator, address(0), to, id, amount); + if (to.isContract()) { + _doSafeTransferAcceptanceCheck(operator, address(0), to, id, amount, data); + } + } + + function _mintBatch(address to,uint256[] memory ids,uint256[] memory amounts,bytes memory data) internal { + 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; + + for (uint256 i = 0; i < ids.length; i++) { + balances[ids[i]][to] = amounts[i].add(balances[ids[i]][to]); + } + emit TransferBatch(operator, address(0), to, ids, amounts); + if (to.isContract()) { + _doSafeBatchTransferAcceptanceCheck(operator, address(0), to, ids, amounts, data); + } + } +} \ No newline at end of file diff --git a/NFT/supportInterface.sol b/NFT/supportInterface.sol new file mode 100755 index 0000000..3256483 --- /dev/null +++ b/NFT/supportInterface.sol @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "./ERC165.sol"; + +/** + * @dev Implementation of standard for detect smart contract interfaces. + */ +contract SupportsInterface is + ERC165 +{ + + /** + * @dev Mapping of supported intefraces. You must not set element 0xffffffff to true. + */ + mapping(bytes4 => bool) internal supportedInterfaces; + + /** + * @dev Contract constructor. + */ + constructor() + { + supportedInterfaces[0x01ffc9a7] = true; // ERC165 + } + + /** + * @dev Function to check which interfaces are suported by this contract. + * @param _interfaceID Id of the interface. + * @return True if _interfaceID is supported, false otherwise. + */ + function supportsInterface( + bytes4 _interfaceID + ) + external + // override + view + returns (bool) + { + return supportedInterfaces[_interfaceID]; + } + +} \ No newline at end of file diff --git a/Readme.md b/Readme.md old mode 100644 new mode 100755 diff --git a/erc1155/EIP-1155.md b/erc1155/EIP-1155.md old mode 100644 new mode 100755 diff --git a/erc777/EIP-777.md b/erc777/EIP-777.md old mode 100644 new mode 100755