以太坊如何发布NFT到opensea

2024-01-31 14:40
文章标签 发布 以太 nft opensea

本文主要是介绍以太坊如何发布NFT到opensea,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前提说明:

此篇文章主要讲解,如何发布类似于网址 https://killaznft.com/ 或者 https://thesevensofficial.com/

这种基于项目方的NFT,进行网页售卖以及上架到OpenSea上进行展示和售卖的过程。对技术感兴趣可以添加文章最后的群二维码一起交流学习。

 此文章为原创,请勿转载。已经基于火币heco-nft生成为NFT进行确权,地址为:https://hecoinfo.com/tx/0x152a5ae4268185fdb66862152e3b48a7f50566cf83d48a90009e9e1523eb8c9f

以下是上述项目的截图:

 

​ 

​ 

开始教程

我们将以发布一张图片作为NFT盲盒,上传到opensea并售卖作为流程,演示如何发布NFT。

包括三个步骤:1 前提讲解 2 开始部署 3 开始网页售卖 4 开始上架OpenSea 5 解开盲盒与 OpenSea购买与售卖

以下内容均在测试网上进行部署:

1.前提讲解:
两种方式都可以实现:

第一种:  基于opensea直接发布——此种方式代表NFT的生成和管理,均被opensea后台默认的NFT管理合约进行管理,此种方式部署的NFT,不灵活,无法灵活配置自己的项目。

第二种:  自己发布NFT合约间接发布——使用自己的NFT合约生成NFT,导入opensea然后进行售卖。

2.开始部署:

第一种方式: 直接部署参考网址 https://blog.csdn.net/weixin_54594070/article/details/115007248

第二种方式: 合约部署方式如下

                       ① 编写NFT合约如下

/***Submitted for verification at Etherscan.io on 2021-08-18
*/pragma solidity >=0.6.0 <0.8.0;/** @dev Provides information about the current execution context, including the* sender of the transaction and its data. While these are generally available* via msg.sender and msg.data, they should not be accessed in such a direct* manner, since when dealing with GSN meta-transactions the account sending and* paying for execution may not be the actual sender (as far as an application* is concerned).** This contract is only required for intermediate, library-like contracts.*/
abstract contract Context {function _msgSender() internal view virtual returns (address payable) {return msg.sender;}function _msgData() internal view virtual returns (bytes memory) {this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691return msg.data;}
}/*** @dev Interface of the ERC165 standard, as defined in the* https://eips.ethereum.org/EIPS/eip-165[EIP].** Implementers can declare support of contract interfaces, which can then be* queried by others ({ERC165Checker}).** For an implementation, see {ERC165}.*/
interface IERC165 {/*** @dev Returns true if this contract implements the interface defined by* `interfaceId`. See the corresponding* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]* to learn more about how these ids are created.** This function call must use less than 30 000 gas.*/function supportsInterface(bytes4 interfaceId) external view returns (bool);
}/*** @dev Required interface of an ERC721 compliant contract.*/
interface IERC721 is IERC165 {/*** @dev Emitted when `tokenId` token is transferred from `from` to `to`.*/event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);/*** @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.*/event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);/*** @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.*/event ApprovalForAll(address indexed owner, address indexed operator, bool approved);/*** @dev Returns the number of tokens in ``owner``'s account.*/function balanceOf(address owner) external view returns (uint256 balance);/*** @dev Returns the owner of the `tokenId` token.** Requirements:** - `tokenId` must exist.*/function ownerOf(uint256 tokenId) external view returns (address owner);/*** @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients* are aware of the ERC721 protocol to prevent tokens from being forever locked.** Requirements:** - `from` cannot be the zero address.* - `to` cannot be the zero address.* - `tokenId` token must exist and be owned by `from`.* - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}.* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.** Emits a {Transfer} event.*/function safeTransferFrom(address from, address to, uint256 tokenId) external;/*** @dev Transfers `tokenId` token from `from` to `to`.** WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.** Requirements:** - `from` cannot be the zero address.* - `to` cannot be the zero address.* - `tokenId` token must be owned by `from`.* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.** Emits a {Transfer} event.*/function transferFrom(address from, address to, uint256 tokenId) external;/*** @dev Gives permission to `to` to transfer `tokenId` token to another account.* The approval is cleared when the token is transferred.** Only a single account can be approved at a time, so approving the zero address clears previous approvals.** Requirements:** - The caller must own the token or be an approved operator.* - `tokenId` must exist.** Emits an {Approval} event.*/function approve(address to, uint256 tokenId) external;/*** @dev Returns the account approved for `tokenId` token.** Requirements:** - `tokenId` must exist.*/function getApproved(uint256 tokenId) external view returns (address operator);/*** @dev Approve or remove `operator` as an operator for the caller.* Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.** Requirements:** - The `operator` cannot be the caller.** Emits an {ApprovalForAll} event.*/function setApprovalForAll(address operator, bool _approved) external;/*** @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.** See {setApprovalForAll}*/function isApprovedForAll(address owner, address operator) external view returns (bool);/*** @dev Safely transfers `tokenId` token from `from` to `to`.** Requirements:** - `from` cannot be the zero address.* - `to` cannot be the zero address.* - `tokenId` token must exist and be owned by `from`.* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.** Emits a {Transfer} event.*/function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;
}/*** @title ERC-721 Non-Fungible Token Standard, optional metadata extension* @dev See https://eips.ethereum.org/EIPS/eip-721*/
interface IERC721Metadata is IERC721 {/*** @dev Returns the token collection name.*/function name() external view returns (string memory);/*** @dev Returns the token collection symbol.*/function symbol() external view returns (string memory);/*** @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.*/function tokenURI(uint256 tokenId) external view returns (string memory);
}/*** @title ERC-721 Non-Fungible Token Standard, optional enumeration extension* @dev See https://eips.ethereum.org/EIPS/eip-721*/
interface IERC721Enumerable is IERC721 {/*** @dev Returns the total amount of tokens stored by the contract.*/function totalSupply() external view returns (uint256);/*** @dev Returns a token ID owned by `owner` at a given `index` of its token list.* Use along with {balanceOf} to enumerate all of ``owner``'s tokens.*/function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256 tokenId);/*** @dev Returns a token ID at a given `index` of all the tokens stored by the contract.* Use along with {totalSupply} to enumerate all tokens.*/function tokenByIndex(uint256 index) external view returns (uint256);
}/*** @title ERC721 token receiver interface* @dev Interface for any contract that wants to support safeTransfers* from ERC721 asset contracts.*/
interface IERC721Receiver {/*** @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}* by `operator` from `from`, this function is called.** It must return its Solidity selector to confirm the token transfer.* If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.** The selector can be obtained in Solidity with `IERC721.onERC721Received.selector`.*/function onERC721Received(address operator, address from, uint256 tokenId, bytes calldata data) external returns (bytes4);
}/*** @dev Implementation of the {IERC165} interface.** Contracts may inherit from this and call {_registerInterface} to declare* their support of an interface.*/
abstract contract ERC165 is IERC165 {/** bytes4(keccak256('supportsInterface(bytes4)')) == 0x01ffc9a7*/bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7;/*** @dev Mapping of interface ids to whether or not it's supported.*/mapping(bytes4 => bool) private _supportedInterfaces;constructor () internal {// Derived contracts need only register support for their own interfaces,// we register support for ERC165 itself here_registerInterface(_INTERFACE_ID_ERC165);}/*** @dev See {IERC165-supportsInterface}.** Time complexity O(1), guaranteed to always use less than 30 000 gas.*/function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {return _supportedInterfaces[interfaceId];}/*** @dev Registers the contract as an implementer of the interface defined by* `interfaceId`. Support of the actual ERC165 interface is automatic and* registering its interface id is not required.** See {IERC165-supportsInterface}.** Requirements:** - `interfaceId` cannot be the ERC165 invalid interface (`0xffffffff`).*/function _registerInterface(bytes4 interfaceId) internal virtual {require(interfaceId != 0xffffffff, "ERC165: invalid interface id");_supportedInterfaces[interfaceId] = true;}
}/*** @dev Wrappers over Solidity's arithmetic operations with added overflow* checks.** Arithmetic operations in Solidity wrap on overflow. This can easily result* in bugs, because programmers usually assume that an overflow raises an* error, which is the standard behavior in high level programming languages.* `SafeMath` restores this intuition by reverting the transaction when an* operation overflows.** Using this library instead of the unchecked operations eliminates an entire* class of bugs, so it's recommended to use it always.*/
library SafeMath {/*** @dev Returns the addition of two unsigned integers, with an overflow flag.** _Available since v3.4._*/function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {uint256 c = a + b;if (c < a) return (false, 0);return (true, c);}/*** @dev Returns the substraction of two unsigned integers, with an overflow flag.** _Available since v3.4._*/function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {if (b > a) return (false, 0);return (true, a - b);}/*** @dev Returns the multiplication of two unsigned integers, with an overflow flag.** _Available since v3.4._*/function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {// Gas optimization: this is cheaper than requiring 'a' not being zero, but the// benefit is lost if 'b' is also tested.// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522if (a == 0) return (true, 0);uint256 c = a * b;if (c / a != b) return (false, 0);return (true, c);}/*** @dev Returns the division of two unsigned integers, with a division by zero flag.** _Available since v3.4._*/function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {if (b == 0) return (false, 0);return (true, a / b);}/*** @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.** _Available since v3.4._*/function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {if (b == 0) return (false, 0);return (true, a % b);}/*** @dev Returns the addition of two unsigned integers, reverting on* overflow.** Counterpart to Solidity's `+` operator.** Requirements:** - Addition cannot overflow.*/function add(uint256 a, uint256 b) internal pure returns (uint256) {uint256 c = a + b;require(c >= a, "SafeMath: addition overflow");return c;}/*** @dev Returns the subtraction of two unsigned integers, reverting on* overflow (when the result is negative).** Counterpart to Solidity's `-` operator.** Requirements:** - Subtraction cannot overflow.*/function sub(uint256 a, uint256 b) internal pure returns (uint256) {require(b <= a, "SafeMath: subtraction overflow");return a - b;}/*** @dev Returns the multiplication of two unsigned integers, reverting on* overflow.** Counterpart to Solidity's `*` operator.** Requirements:** - Multiplication cannot overflow.*/function mul(uint256 a, uint256 b) internal pure returns (uint256) {if (a == 0) return 0;uint256 c = a * b;require(c / a == b, "SafeMath: multiplication overflow");return c;}/*** @dev Returns the integer division of two unsigned integers, reverting on* division by zero. The result is rounded towards zero.** Counterpart to Solidity's `/` operator. Note: this function uses a* `revert` opcode (which leaves remaining gas untouched) while Solidity* uses an invalid opcode to revert (consuming all remaining gas).** Requirements:** - The divisor cannot be zero.*/function div(uint256 a, uint256 b) internal pure returns (uint256) {require(b > 0, "SafeMath: division by zero");return a / b;}/*** @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),* reverting when dividing by zero.** Counterpart to Solidity's `%` operator. This function uses a `revert`* opcode (which leaves remaining gas untouched) while Solidity uses an* invalid opcode to revert (consuming all remaining gas).** Requirements:** - The divisor cannot be zero.*/function mod(uint256 a, uint256 b) internal pure returns (uint256) {require(b > 0, "SafeMath: modulo by zero");return a % b;}/*** @dev Returns the subtraction of two unsigned integers, reverting with custom message on* overflow (when the result is negative).** CAUTION: This function is deprecated because it requires allocating memory for the error* message unnecessarily. For custom revert reasons use {trySub}.** Counterpart to Solidity's `-` operator.** Requirements:** - Subtraction cannot overflow.*/function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {require(b <= a, errorMessage);return a - b;}/*** @dev Returns the integer division of two unsigned integers, reverting with custom message on* division by zero. The result is rounded towards zero.** CAUTION: This function is deprecated because it requires allocating memory for the error* message unnecessarily. For custom revert reasons use {tryDiv}.** Counterpart to Solidity's `/` operator. Note: this function uses a* `revert` opcode (which leaves remaining gas untouched) while Solidity* uses an invalid opcode to revert (consuming all remaining gas).** Requirements:** - The divisor cannot be zero.*/function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {require(b > 0, errorMessage);return a / b;}/*** @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),* reverting with custom message when dividing by zero.** CAUTION: This function is deprecated because it requires allocating memory for the error* message unnecessarily. For custom revert reasons use {tryMod}.** Counterpart to Solidity's `%` operator. This function uses a `revert`* opcode (which leaves remaining gas untouched) while Solidity uses an* invalid opcode to revert (consuming all remaining gas).** Requirements:** - The divisor cannot be zero.*/function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {require(b > 0, errorMessage);return a % b;}
}/*** @dev Collection of functions related to the address type*/
library Address {/*** @dev Returns true if `account` is a contract.** [IMPORTANT]* ====* It is unsafe to assume that an address for which this function returns* false is an externally-owned account (EOA) and not a contract.** Among others, `isContract` will return false for the following* types of addresses:**  - an externally-owned account*  - a contract in construction*  - an address where a contract will be created*  - an address where a contract lived, but was destroyed* ====*/function isContract(address account) internal view returns (bool) {// This method relies on extcodesize, which returns 0 for contracts in// construction, since the code is only stored at the end of the// constructor execution.uint256 size;// solhint-disable-next-line no-inline-assemblyassembly { size := extcodesize(account) }return size > 0;}/*** @dev Replacement for Solidity's `transfer`: sends `amount` wei to* `recipient`, forwarding all available gas and reverting on errors.** https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost* of certain opcodes, possibly making contracts go over the 2300 gas limit* imposed by `transfer`, making them unable to receive funds via* `transfer`. {sendValue} removes this limitation.** https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].** IMPORTANT: because control is transferred to `recipient`, care must be* taken to not create reentrancy vulnerabilities. Consider using* {ReentrancyGuard} or the* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].*/function sendValue(address payable recipient, uint256 amount) internal {require(address(this).balance >= amount, "Address: insufficient balance");// solhint-disable-next-line avoid-low-level-calls, avoid-call-value(bool success, ) = recipient.call{ value: amount }("");require(success, "Address: unable to send value, recipient may have reverted");}/*** @dev Performs a Solidity function call using a low level `call`. A* plain`call` is an unsafe replacement for a function call: use this* function instead.** If `target` reverts with a revert reason, it is bubbled up by this* function (like regular Solidity function calls).** Returns the raw returned data. To convert to the expected return value,* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].** Requirements:** - `target` must be a contract.* - calling `target` with `data` must not revert.** _Available since v3.1._*/function functionCall(address target, bytes memory data) internal returns (bytes memory) {return functionCall(target, data, "Address: low-level call failed");}/*** @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with* `errorMessage` as a fallback revert reason when `target` reverts.** _Available since v3.1._*/function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {return functionCallWithValue(target, data, 0, errorMessage);}/*** @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],* but also transferring `value` wei to `target`.** Requirements:** - the calling contract must have an ETH balance of at least `value`.* - the called Solidity function must be `payable`.** _Available since v3.1._*/function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {return functionCallWithValue(target, data, value, "Address: low-level call with value failed");}/*** @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but* with `errorMessage` as a fallback revert reason when `target` reverts.** _Available since v3.1._*/function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {require(address(this).balance >= value, "Address: insufficient balance for call");require(isContract(target), "Address: call to non-contract");// solhint-disable-next-line avoid-low-level-calls(bool success, bytes memory returndata) = target.call{ value: value }(data);return _verifyCallResult(success, returndata, errorMessage);}/*** @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],* but performing a static call.** _Available since v3.3._*/function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {return functionStaticCall(target, data, "Address: low-level static call failed");}/*** @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],* but performing a static call.** _Available since v3.3._*/function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) {require(isContract(target), "Address: static call to non-contract");// solhint-disable-next-line avoid-low-level-calls(bool success, bytes memory returndata) = target.staticcall(data);return _verifyCallResult(success, returndata, errorMessage);}/*** @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],* but performing a delegate call.** _Available since v3.4._*/function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {return functionDelegateCall(target, data, "Address: low-level delegate call failed");}/*** @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],* but performing a delegate call.** _Available since v3.4._*/function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {require(isContract(target), "Address: delegate call to non-contract");// solhint-disable-next-line avoid-low-level-calls(bool success, bytes memory returndata) = target.delegatecall(data);return _verifyCallResult(success, returndata, errorMessage);}function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {if (success) {return returndata;} else {// Look for revert reason and bubble it up if presentif (returndata.length > 0) {// The easiest way to bubble the revert reason is using memory via assembly// solhint-disable-next-line no-inline-assemblyassembly {let returndata_size := mload(returndata)revert(add(32, returndata), returndata_size)}} else {revert(errorMessage);}}}
}/*** @dev Library for managing* https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive* types.** Sets have the following properties:** - Elements are added, removed, and checked for existence in constant time* (O(1)).* - Elements are enumerated in O(n). No guarantees are made on the ordering.** ```* contract Example {*     // Add the library methods*     using EnumerableSet for EnumerableSet.AddressSet;**     // Declare a set state variable*     EnumerableSet.AddressSet private mySet;* }* ```** As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)* and `uint256` (`UintSet`) are supported.*/
library EnumerableSet {// To implement this library for multiple types with as little code// repetition as possible, we write it in terms of a generic Set type with// bytes32 values.// The Set implementation uses private functions, and user-facing// implementations (such as AddressSet) are just wrappers around the// underlying Set.// This means that we can only create new EnumerableSets for types that fit// in bytes32.struct Set {// Storage of set valuesbytes32[] _values;// Position of the value in the `values` array, plus 1 because index 0// means a value is not in the set.mapping (bytes32 => uint256) _indexes;}/*** @dev Add a value to a set. O(1).** Returns true if the value was added to the set, that is if it was not* already present.*/function _add(Set storage set, bytes32 value) private returns (bool) {if (!_contains(set, value)) {set._values.push(value);// The value is stored at length-1, but we add 1 to all indexes// and use 0 as a sentinel valueset._indexes[value] = set._values.length;return true;} else {return false;}}/*** @dev Removes a value from a set. O(1).** Returns true if the value was removed from the set, that is if it was* present.*/function _remove(Set storage set, bytes32 value) private returns (bool) {// We read and store the value's index to prevent multiple reads from the same storage slotuint256 valueIndex = set._indexes[value];if (valueIndex != 0) { // Equivalent to contains(set, value)// To delete an element from the _values array in O(1), we swap the element to delete with the last one in// the array, and then remove the last element (sometimes called as 'swap and pop').// This modifies the order of the array, as noted in {at}.uint256 toDeleteIndex = valueIndex - 1;uint256 lastIndex = set._values.length - 1;// When the value to delete is the last one, the swap operation is unnecessary. However, since this occurs// so rarely, we still do the swap anyway to avoid the gas cost of adding an 'if' statement.bytes32 lastvalue = set._values[lastIndex];// Move the last value to the index where the value to delete isset._values[toDeleteIndex] = lastvalue;// Update the index for the moved valueset._indexes[lastvalue] = toDeleteIndex + 1; // All indexes are 1-based// Delete the slot where the moved value was storedset._values.pop();// Delete the index for the deleted slotdelete set._indexes[value];return true;} else {return false;}}/*** @dev Returns true if the value is in the set. O(1).*/function _contains(Set storage set, bytes32 value) private view returns (bool) {return set._indexes[value] != 0;}/*** @dev Returns the number of values on the set. O(1).*/function _length(Set storage set) private view returns (uint256) {return set._values.length;}/*** @dev Returns the value stored at position `index` in the set. O(1).** Note that there are no guarantees on the ordering of values inside the* array, and it may change when more values are added or removed.** Requirements:** - `index` must be strictly less than {length}.*/function _at(Set storage set, uint256 index) private view returns (bytes32) {require(set._values.length > index, "EnumerableSet: index out of bounds");return set._values[index];}// Bytes32Setstruct Bytes32Set {Set _inner;}/*** @dev Add a value to a set. O(1).** Returns true if the value was added to the set, that is if it was not* already present.*/function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {return _add(set._inner, value);}/*** @dev Removes a value from a set. O(1).** Returns true if the value was removed from the set, that is if it was* present.*/function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {return _remove(set._inner, value);}/*** @dev Returns true if the value is in the set. O(1).*/function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {return _contains(set._inner, value);}/*** @dev Returns the number of values in the set. O(1).*/function length(Bytes32Set storage set) internal view returns (uint256) {return _length(set._inner);}/*** @dev Returns the value stored at position `index` in the set. O(1).** Note that there are no guarantees on the ordering of values inside the* array, and it may change when more values are added or removed.** Requirements:** - `index` must be strictly less than {length}.*/function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {return _at(set._inner, index);}// AddressSetstruct AddressSet {Set _inner;}/*** @dev Add a value to a set. O(1).** Returns true if the value was added to the set, that is if it was not* already present.*/function add(AddressSet storage set, address value) internal returns (bool) {return _add(set._inner, bytes32(uint256(uint160(value))));}/*** @dev Removes a value from a set. O(1).** Returns true if the value was removed from the set, that is if it was* present.*/function remove(AddressSet storage set, address value) internal returns (bool) {return _remove(set._inner, bytes32(uint256(uint160(value))));}/*** @dev Returns true if the value is in the set. O(1).*/function contains(AddressSet storage set, address value) internal view returns (bool) {return _contains(set._inner, bytes32(uint256(uint160(value))));}/*** @dev Returns the number of values in the set. O(1).*/function length(AddressSet storage set) internal view returns (uint256) {return _length(set._inner);}/*** @dev Returns the value stored at position `index` in the set. O(1).** Note that there are no guarantees on the ordering of values inside the* array, and it may change when more values are added or removed.** Requirements:** - `index` must be strictly less than {length}.*/function at(AddressSet storage set, uint256 index) internal view returns (address) {return address(uint160(uint256(_at(set._inner, index))));}// UintSetstruct UintSet {Set _inner;}/*** @dev Add a value to a set. O(1).** Returns true if the value was added to the set, that is if it was not* already present.*/function add(UintSet storage set, uint256 value) internal returns (bool) {return _add(set._inner, bytes32(value));}/*** @dev Removes a value from a set. O(1).** Returns true if the value was removed from the set, that is if it was* present.*/function remove(UintSet storage set, uint256 value) internal returns (bool) {return _remove(set._inner, bytes32(value));}/*** @dev Returns true if the value is in the set. O(1).*/function contains(UintSet storage set, uint256 value) internal view returns (bool) {return _contains(set._inner, bytes32(value));}/*** @dev Returns the number of values on the set. O(1).*/function length(UintSet storage set) internal view returns (uint256) {return _length(set._inner);}/*** @dev Returns the value stored at position `index` in the set. O(1).** Note that there are no guarantees on the ordering of values inside the* array, and it may change when more values are added or removed.** Requirements:** - `index` must be strictly less than {length}.*/function at(UintSet storage set, uint256 index) internal view returns (uint256) {return uint256(_at(set._inner, index));}
}/*** @dev Library for managing an enumerable variant of Solidity's* https://solidity.readthedocs.io/en/latest/types.html#mapping-types[`mapping`]* type.** Maps have the following properties:** - Entries are added, removed, and checked for existence in constant time* (O(1)).* - Entries are enumerated in O(n). No guarantees are made on the ordering.** ```* contract Example {*     // Add the library methods*     using EnumerableMap for EnumerableMap.UintToAddressMap;**     // Declare a set state variable*     EnumerableMap.UintToAddressMap private myMap;* }* ```** As of v3.0.0, only maps of type `uint256 -> address` (`UintToAddressMap`) are* supported.*/
library EnumerableMap {// To implement this library for multiple types with as little code// repetition as possible, we write it in terms of a generic Map type with// bytes32 keys and values.// The Map implementation uses private functions, and user-facing// implementations (such as Uint256ToAddressMap) are just wrappers around// the underlying Map.// This means that we can only create new EnumerableMaps for types that fit// in bytes32.struct MapEntry {bytes32 _key;bytes32 _value;}struct Map {// Storage of map keys and valuesMapEntry[] _entries;// Position of the entry defined by a key in the `entries` array, plus 1// because index 0 means a key is not in the map.mapping (bytes32 => uint256) _indexes;}/*** @dev Adds a key-value pair to a map, or updates the value for an existing* key. O(1).** Returns true if the key was added to the map, that is if it was not* already present.*/function _set(Map storage map, bytes32 key, bytes32 value) private returns (bool) {// We read and store the key's index to prevent multiple reads from the same storage slotuint256 keyIndex = map._indexes[key];if (keyIndex == 0) { // Equivalent to !contains(map, key)map._entries.push(MapEntry({ _key: key, _value: value }));// The entry is stored at length-1, but we add 1 to all indexes// and use 0 as a sentinel valuemap._indexes[key] = map._entries.length;return true;} else {map._entries[keyIndex - 1]._value = value;return false;}}/*** @dev Removes a key-value pair from a map. O(1).** Returns true if the key was removed from the map, that is if it was present.*/function _remove(Map storage map, bytes32 key) private returns (bool) {// We read and store the key's index to prevent multiple reads from the same storage slotuint256 keyIndex = map._indexes[key];if (keyIndex != 0) { // Equivalent to contains(map, key)// To delete a key-value pair from the _entries array in O(1), we swap the entry to delete with the last one// in the array, and then remove the last entry (sometimes called as 'swap and pop').// This modifies the order of the array, as noted in {at}.uint256 toDeleteIndex = keyIndex - 1;uint256 lastIndex = map._entries.length - 1;// When the entry to delete is the last one, the swap operation is unnecessary. However, since this occurs// so rarely, we still do the swap anyway to avoid the gas cost of adding an 'if' statement.MapEntry storage lastEntry = map._entries[lastIndex];// Move the last entry to the index where the entry to delete ismap._entries[toDeleteIndex] = lastEntry;// Update the index for the moved entrymap._indexes[lastEntry._key] = toDeleteIndex + 1; // All indexes are 1-based// Delete the slot where the moved entry was storedmap._entries.pop();// Delete the index for the deleted slotdelete map._indexes[key];return true;} else {return false;}}/*** @dev Returns true if the key is in the map. O(1).*/function _contains(Map storage map, bytes32 key) private view returns (bool) {return map._indexes[key] != 0;}/*** @dev Returns the number of key-value pairs in the map. O(1).*/function _length(Map storage map) private view returns (uint256) {return map._entries.length;}/*** @dev Returns the key-value pair stored at position `index` in the map. O(1).** Note that there are no guarantees on the ordering of entries inside the* array, and it may change when more entries are added or removed.** Requirements:** - `index` must be strictly less than {length}.*/function _at(Map storage map, uint256 index) private view returns (bytes32, bytes32) {require(map._entries.length > index, "EnumerableMap: index out of bounds");MapEntry storage entry = map._entries[index];return (entry._key, entry._value);}/*** @dev Tries to returns the value associated with `key`.  O(1).* Does not revert if `key` is not in the map.*/function _tryGet(Map storage map, bytes32 key) private view returns (bool, bytes32) {uint256 keyIndex = map._indexes[key];if (keyIndex == 0) return (false, 0); // Equivalent to contains(map, key)return (true, map._entries[keyIndex - 1]._value); // All indexes are 1-based}/*** @dev Returns the value associated with `key`.  O(1).** Requirements:** - `key` must be in the map.*/function _get(Map storage map, bytes32 key) private view returns (bytes32) {uint256 keyIndex = map._indexes[key];require(keyIndex != 0, "EnumerableMap: nonexistent key"); // Equivalent to contains(map, key)return map._entries[keyIndex - 1]._value; // All indexes are 1-based}/*** @dev Same as {_get}, with a custom error message when `key` is not in the map.** CAUTION: This function is deprecated because it requires allocating memory for the error* message unnecessarily. For custom revert reasons use {_tryGet}.*/function _get(Map storage map, bytes32 key, string memory errorMessage) private view returns (bytes32) {uint256 keyIndex = map._indexes[key];require(keyIndex != 0, errorMessage); // Equivalent to contains(map, key)return map._entries[keyIndex - 1]._value; // All indexes are 1-based}// UintToAddressMapstruct UintToAddressMap {Map _inner;}/*** @dev Adds a key-value pair to a map, or updates the value for an existing* key. O(1).** Returns true if the key was added to the map, that is if it was not* already present.*/function set(UintToAddressMap storage map, uint256 key, address value) internal returns (bool) {return _set(map._inner, bytes32(key), bytes32(uint256(uint160(value))));}/*** @dev Removes a value from a set. O(1).** Returns true if the key was removed from the map, that is if it was present.*/function remove(UintToAddressMap storage map, uint256 key) internal returns (bool) {return _remove(map._inner, bytes32(key));}/*** @dev Returns true if the key is in the map. O(1).*/function contains(UintToAddressMap storage map, uint256 key) internal view returns (bool) {return _contains(map._inner, bytes32(key));}/*** @dev Returns the number of elements in the map. O(1).*/function length(UintToAddressMap storage map) internal view returns (uint256) {return _length(map._inner);}/*** @dev Returns the element stored at position `index` in the set. O(1).* Note that there are no guarantees on the ordering of values inside the* array, and it may change when more values are added or removed.** Requirements:** - `index` must be strictly less than {length}.*/function at(UintToAddressMap storage map, uint256 index) internal view returns (uint256, address) {(bytes32 key, bytes32 value) = _at(map._inner, index);return (uint256(key), address(uint160(uint256(value))));}/*** @dev Tries to returns the value associated with `key`.  O(1).* Does not revert if `key` is not in the map.** _Available since v3.4._*/function tryGet(UintToAddressMap storage map, uint256 key) internal view returns (bool, address) {(bool success, bytes32 value) = _tryGet(map._inner, bytes32(key));return (success, address(uint160(uint256(value))));}/*** @dev Returns the value associated with `key`.  O(1).** Requirements:** - `key` must be in the map.*/function get(UintToAddressMap storage map, uint256 key) internal view returns (address) {return address(uint160(uint256(_get(map._inner, bytes32(key)))));}/*** @dev Same as {get}, with a custom error message when `key` is not in the map.** CAUTION: This function is deprecated because it requires allocating memory for the error* message unnecessarily. For custom revert reasons use {tryGet}.*/function get(UintToAddressMap storage map, uint256 key, string memory errorMessage) internal view returns (address) {return address(uint160(uint256(_get(map._inner, bytes32(key), errorMessage))));}
}/*** @dev String operations.*/
library Strings {/*** @dev Converts a `uint256` to its ASCII `string` representation.*/function toString(uint256 value) internal pure returns (string memory) {// Inspired by OraclizeAPI's implementation - MIT licence// https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.solif (value == 0) {return "0";}uint256 temp = value;uint256 digits;while (temp != 0) {digits++;temp /= 10;}bytes memory buffer = new bytes(digits);uint256 index = digits - 1;temp = value;while (temp != 0) {buffer[index--] = bytes1(uint8(48 + temp % 10));temp /= 10;}return string(buffer);}
}/*** @title ERC721 Non-Fungible Token Standard basic implementation* @dev see https://eips.ethereum.org/EIPS/eip-721*/
contract ERC721 is Context, ERC165, IERC721, IERC721Metadata, IERC721Enumerable {using SafeMath for uint256;using Address for address;using EnumerableSet for EnumerableSet.UintSet;using EnumerableMap for EnumerableMap.UintToAddressMap;using Strings for uint256;// Equals to `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`// which can be also obtained as `IERC721Receiver(0).onERC721Received.selector`bytes4 private constant _ERC721_RECEIVED = 0x150b7a02;// Mapping from holder address to their (enumerable) set of owned tokensmapping (address => EnumerableSet.UintSet) private _holderTokens;// Enumerable mapping from token ids to their ownersEnumerableMap.UintToAddressMap private _tokenOwners;// Mapping from token ID to approved addressmapping (uint256 => address) private _tokenApprovals;// Mapping from owner to operator approvalsmapping (address => mapping (address => bool)) private _operatorApprovals;// Token namestring private _name;// Token symbolstring private _symbol;// Optional mapping for token URIsmapping (uint256 => string) private _tokenURIs;// Base URIstring private _baseURI;/**     bytes4(keccak256('balanceOf(address)')) == 0x70a08231*     bytes4(keccak256('ownerOf(uint256)')) == 0x6352211e*     bytes4(keccak256('approve(address,uint256)')) == 0x095ea7b3*     bytes4(keccak256('getApproved(uint256)')) == 0x081812fc*     bytes4(keccak256('setApprovalForAll(address,bool)')) == 0xa22cb465*     bytes4(keccak256('isApprovedForAll(address,address)')) == 0xe985e9c5*     bytes4(keccak256('transferFrom(address,address,uint256)')) == 0x23b872dd*     bytes4(keccak256('safeTransferFrom(address,address,uint256)')) == 0x42842e0e*     bytes4(keccak256('safeTransferFrom(address,address,uint256,bytes)')) == 0xb88d4fde**     => 0x70a08231 ^ 0x6352211e ^ 0x095ea7b3 ^ 0x081812fc ^*        0xa22cb465 ^ 0xe985e9c5 ^ 0x23b872dd ^ 0x42842e0e ^ 0xb88d4fde == 0x80ac58cd*/bytes4 private constant _INTERFACE_ID_ERC721 = 0x80ac58cd;/**     bytes4(keccak256('name()')) == 0x06fdde03*     bytes4(keccak256('symbol()')) == 0x95d89b41*     bytes4(keccak256('tokenURI(uint256)')) == 0xc87b56dd**     => 0x06fdde03 ^ 0x95d89b41 ^ 0xc87b56dd == 0x5b5e139f*/bytes4 private constant _INTERFACE_ID_ERC721_METADATA = 0x5b5e139f;/**     bytes4(keccak256('totalSupply()')) == 0x18160ddd*     bytes4(keccak256('tokenOfOwnerByIndex(address,uint256)')) == 0x2f745c59*     bytes4(keccak256('tokenByIndex(uint256)')) == 0x4f6ccce7**     => 0x18160ddd ^ 0x2f745c59 ^ 0x4f6ccce7 == 0x780e9d63*/bytes4 private constant _INTERFACE_ID_ERC721_ENUMERABLE = 0x780e9d63;/*** @dev Initializes the contract by setting a `name` and a `symbol` to the token collection.*/constructor (string memory name_, string memory symbol_) public {_name = name_;_symbol = symbol_;// register the supported interfaces to conform to ERC721 via ERC165_registerInterface(_INTERFACE_ID_ERC721);_registerInterface(_INTERFACE_ID_ERC721_METADATA);_registerInterface(_INTERFACE_ID_ERC721_ENUMERABLE);}/*** @dev See {IERC721-balanceOf}.*/function balanceOf(address owner) public view virtual override returns (uint256) {require(owner != address(0), "ERC721: balance query for the zero address");return _holderTokens[owner].length();}/*** @dev See {IERC721-ownerOf}.*/function ownerOf(uint256 tokenId) public view virtual override returns (address) {return _tokenOwners.get(tokenId, "ERC721: owner query for nonexistent token");}/*** @dev See {IERC721Metadata-name}.*/function name() public view virtual override returns (string memory) {return _name;}/*** @dev See {IERC721Metadata-symbol}.*/function symbol() public view virtual override returns (string memory) {return _symbol;}/*** @dev See {IERC721Metadata-tokenURI}.*/function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");string memory _tokenURI = _tokenURIs[tokenId];string memory base = baseURI();// If there is no base URI, return the token URI.if (bytes(base).length == 0) {return _tokenURI;}// If both are set, concatenate the baseURI and tokenURI (via abi.encodePacked).if (bytes(_tokenURI).length > 0) {return string(abi.encodePacked(base, _tokenURI, '.json'));}// If there is a baseURI but no tokenURI, concatenate the tokenID to the baseURI.return string(abi.encodePacked(base, (tokenId.toString()),".txt"));}/*** @dev Returns the base URI set via {_setBaseURI}. This will be* automatically added as a prefix in {tokenURI} to each token's URI, or* to the token ID if no specific URI is set for that token ID.*/function baseURI() public view virtual returns (string memory) {return _baseURI;}/*** @dev See {IERC721Enumerable-tokenOfOwnerByIndex}.*/function tokenOfOwnerByIndex(address owner, uint256 index) public view virtual override returns (uint256) {return _holderTokens[owner].at(index);}/*** @dev See {IERC721Enumerable-totalSupply}.*/function totalSupply() public view virtual override returns (uint256) {// _tokenOwners are indexed by tokenIds, so .length() returns the number of tokenIdsreturn _tokenOwners.length();}/*** @dev See {IERC721Enumerable-tokenByIndex}.*/function tokenByIndex(uint256 index) public view virtual override returns (uint256) {(uint256 tokenId, ) = _tokenOwners.at(index);return tokenId;}/*** @dev See {IERC721-approve}.*/function approve(address to, uint256 tokenId) public virtual override {address owner = ERC721.ownerOf(tokenId);require(to != owner, "ERC721: approval to current owner");require(_msgSender() == owner || ERC721.isApprovedForAll(owner, _msgSender()),"ERC721: approve caller is not owner nor approved for all");_approve(to, tokenId);}/*** @dev See {IERC721-getApproved}.*/function getApproved(uint256 tokenId) public view virtual override returns (address) {require(_exists(tokenId), "ERC721: approved query for nonexistent token");return _tokenApprovals[tokenId];}/*** @dev See {IERC721-setApprovalForAll}.*/function setApprovalForAll(address operator, bool approved) public virtual override {require(operator != _msgSender(), "ERC721: approve to caller");_operatorApprovals[_msgSender()][operator] = approved;emit ApprovalForAll(_msgSender(), operator, approved);}/*** @dev See {IERC721-isApprovedForAll}.*/function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) {return _operatorApprovals[owner][operator];}/*** @dev See {IERC721-transferFrom}.*/function transferFrom(address from, address to, uint256 tokenId) public virtual override {//solhint-disable-next-line max-line-lengthrequire(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");_transfer(from, to, tokenId);}/*** @dev See {IERC721-safeTransferFrom}.*/function safeTransferFrom(address from, address to, uint256 tokenId) public virtual override {safeTransferFrom(from, to, tokenId, "");}/*** @dev See {IERC721-safeTransferFrom}.*/function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory _data) public virtual override {require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");_safeTransfer(from, to, tokenId, _data);}/*** @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients* are aware of the ERC721 protocol to prevent tokens from being forever locked.** `_data` is additional data, it has no specified format and it is sent in call to `to`.** This internal function is equivalent to {safeTransferFrom}, and can be used to e.g.* implement alternative mechanisms to perform token transfer, such as signature-based.** Requirements:** - `from` cannot be the zero address.* - `to` cannot be the zero address.* - `tokenId` token must exist and be owned by `from`.* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.** Emits a {Transfer} event.*/function _safeTransfer(address from, address to, uint256 tokenId, bytes memory _data) internal virtual {_transfer(from, to, tokenId);require(_checkOnERC721Received(from, to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer");}/*** @dev Returns whether `tokenId` exists.** Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}.** Tokens start existing when they are minted (`_mint`),* and stop existing when they are burned (`_burn`).*/function _exists(uint256 tokenId) internal view virtual returns (bool) {return _tokenOwners.contains(tokenId);}/*** @dev Returns whether `spender` is allowed to manage `tokenId`.** Requirements:** - `tokenId` must exist.*/function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) {require(_exists(tokenId), "ERC721: operator query for nonexistent token");address owner = ERC721.ownerOf(tokenId);return (spender == owner || getApproved(tokenId) == spender || ERC721.isApprovedForAll(owner, spender));}/*** @dev Safely mints `tokenId` and transfers it to `to`.** Requirements:d** - `tokenId` must not exist.* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.** Emits a {Transfer} event.*/function _safeMint(address to, uint256 tokenId) internal virtual {_safeMint(to, tokenId, "");}/*** @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is* forwarded in {IERC721Receiver-onERC721Received} to contract recipients.*/function _safeMint(address to, uint256 tokenId, bytes memory _data) internal virtual {_mint(to, tokenId);require(_checkOnERC721Received(address(0), to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer");}/*** @dev Mints `tokenId` and transfers it to `to`.** WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible** Requirements:** - `tokenId` must not exist.* - `to` cannot be the zero address.** Emits a {Transfer} event.*/function _mint(address to, uint256 tokenId) internal virtual {require(to != address(0), "ERC721: mint to the zero address");require(!_exists(tokenId), "ERC721: token already minted");_beforeTokenTransfer(address(0), to, tokenId);_holderTokens[to].add(tokenId);_tokenOwners.set(tokenId, to);emit Transfer(address(0), to, tokenId);}/*** @dev Destroys `tokenId`.* The approval is cleared when the token is burned.** Requirements:** - `tokenId` must exist.** Emits a {Transfer} event.*/function _burn(uint256 tokenId) internal virtual {address owner = ERC721.ownerOf(tokenId); // internal owner_beforeTokenTransfer(owner, address(0), tokenId);// Clear approvals_approve(address(0), tokenId);// Clear metadata (if any)if (bytes(_tokenURIs[tokenId]).length != 0) {delete _tokenURIs[tokenId];}_holderTokens[owner].remove(tokenId);_tokenOwners.remove(tokenId);emit Transfer(owner, address(0), tokenId);}/*** @dev Transfers `tokenId` from `from` to `to`.*  As opposed to {transferFrom}, this imposes no restrictions on msg.sender.** Requirements:** - `to` cannot be the zero address.* - `tokenId` token must be owned by `from`.** Emits a {Transfer} event.*/function _transfer(address from, address to, uint256 tokenId) internal virtual {require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer of token that is not own"); // internal ownerrequire(to != address(0), "ERC721: transfer to the zero address");_beforeTokenTransfer(from, to, tokenId);// Clear approvals from the previous owner_approve(address(0), tokenId);_holderTokens[from].remove(tokenId);_holderTokens[to].add(tokenId);_tokenOwners.set(tokenId, to);emit Transfer(from, to, tokenId);}/*** @dev Sets `_tokenURI` as the tokenURI of `tokenId`.** Requirements:** - `tokenId` must exist.*/function _setTokenURI(uint256 tokenId, string memory _tokenURI) internal virtual {require(_exists(tokenId), "ERC721Metadata: URI set of nonexistent token");_tokenURIs[tokenId] = _tokenURI;}/*** @dev Internal function to set the base URI for all token IDs. It is* automatically added as a prefix to the value returned in {tokenURI},* or to the token ID if {tokenURI} is empty.*/function _setBaseURI(string memory baseURI_) internal virtual {_baseURI = baseURI_;}/*** @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address.* The call is not executed if the target address is not a contract.** @param from address representing the previous owner of the given token ID* @param to target address that will receive the tokens* @param tokenId uint256 ID of the token to be transferred* @param _data bytes optional data to send along with the call* @return bool whether the call correctly returned the expected magic value*/function _checkOnERC721Received(address from, address to, uint256 tokenId, bytes memory _data)private returns (bool){if (!to.isContract()) {return true;}bytes memory returndata = to.functionCall(abi.encodeWithSelector(IERC721Receiver(to).onERC721Received.selector,_msgSender(),from,tokenId,_data), "ERC721: transfer to non ERC721Receiver implementer");bytes4 retval = abi.decode(returndata, (bytes4));return (retval == _ERC721_RECEIVED);}/*** @dev Approve `to` to operate on `tokenId`** Emits an {Approval} event.*/function _approve(address to, uint256 tokenId) internal virtual {_tokenApprovals[tokenId] = to;emit Approval(ERC721.ownerOf(tokenId), to, tokenId); // internal owner}/*** @dev Hook that is called before any token transfer. This includes minting* and burning.** Calling conditions:** - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be* transferred to `to`.* - When `from` is zero, `tokenId` will be minted for `to`.* - When `to` is zero, ``from``'s `tokenId` will be burned.* - `from` cannot be the zero address.* - `to` cannot be the zero address.** To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].*/function _beforeTokenTransfer(address from, address to, uint256 tokenId) internal virtual { }
}/*** @dev Contract module which provides a basic access control mechanism, where* there is an account (an owner) that can be granted exclusive access to* specific functions.** By default, the owner account will be the one that deploys the contract. This* can later be changed with {transferOwnership}.** This module is used through inheritance. It will make available the modifier* `onlyOwner`, which can be applied to your functions to restrict their use to* the owner.*/
abstract contract Ownable is Context {address private _owner;event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);/*** @dev Initializes the contract setting the deployer as the initial owner.*/constructor () internal {address msgSender = _msgSender();_owner = msgSender;emit OwnershipTransferred(address(0), msgSender);}/*** @dev Returns the address of the current owner.*/function owner() public view virtual returns (address) {return _owner;}/*** @dev Throws if called by any account other than the owner.*/modifier onlyOwner() {require(owner() == _msgSender(), "Ownable: caller is not the owner");_;}/*** @dev Leaves the contract without owner. It will not be possible to call* `onlyOwner` functions anymore. Can only be called by the current owner.** NOTE: Renouncing ownership will leave the contract without an owner,* thereby removing any functionality that is only available to the owner.*/function renounceOwnership() public virtual onlyOwner {emit OwnershipTransferred(_owner, address(0));_owner = address(0);}/*** @dev Transfers ownership of the contract to a new account (`newOwner`).* Can only be called by the current owner.*/function transferOwnership(address newOwner) public virtual onlyOwner {require(newOwner != address(0), "Ownable: new owner is the zero address");emit OwnershipTransferred(_owner, newOwner);_owner = newOwner;}
}contract KILLAz is ERC721, Ownable {using SafeMath for uint256;uint256 public immutable pricePerKILLA;uint256 public immutable maxPerTx;uint256 public immutable maxKILLAz;bool public isSaleActive;address private immutable reserveAddress;constructor(address _reserveAddress)publicERC721("KILLAz", "Kz"){pricePerKILLA = 0.029 * 10 ** 18;maxPerTx = 20;maxKILLAz = 9971;reserveAddress = _reserveAddress;}function flipSaleState() public onlyOwner {isSaleActive = !isSaleActive;}function setBaseURI(string memory baseURI) public onlyOwner {_setBaseURI(baseURI);}function reserveKILLAz() public onlyOwner {   require(totalSupply() < 100);for (uint256 i = 0; i < 50; i++) {uint256 mintIndex = totalSupply();_safeMint(reserveAddress, mintIndex);}}function mintKILLAz(uint256 numberOfTokens) public payable {require(isSaleActive, "Sale is not active");require(numberOfTokens <= maxPerTx, "No more than 20 tokens per transaction");require(totalSupply().add(numberOfTokens) <= maxKILLAz, "Purchase would exceed max supply of KILLAz");require(pricePerKILLA.mul(numberOfTokens) == msg.value, "Ether value is not correct");payable(owner()).transfer(msg.value);for (uint256 i = 0; i < numberOfTokens; i++) {uint256 mintIndex = totalSupply();if (totalSupply() < maxKILLAz) {_safeMint(msg.sender, mintIndex);}}}
}

                ② 打开remix发布合约:https://remix.ethereum.org/    输入网页售卖的收款地址并发布                   

     

   ③ 注册腾讯云,并开启腾讯云COS文件存储,并创建存储桶。

 ④ 上传一张图片到存储桶,生成图片的Url链接 https://nft-buc-1302315235.cos.ap-beijing.myqcloud.com/pic0/10.jpeg
 访问该链接可以访问到图片。

⑤ 新建txt文档,文档中存储构造符合OpenSea标准的NFT 元数据(元数据中保存了图片的url),如下:

{"attributes":[{"trait_type":"Background","value":"Fire"},{"trait_type":"Body","value":"Droid"},{"trait_type":"Weapon","value":"RPG"},{"trait_type":"Clothing","value":"None"},{"trait_type":"Mask","value":"None"},{"trait_type":"Primary Accessory","value":"Prayer Beads"},{"trait_type":"Secondary Accessory","value":"None"}],"name":"killaz #10","image":"https://nft-buc-1302315235.cos.ap-beijing.myqcloud.com/pic0/10.jpeg"}

⑥ 上传第五步新建的txt文档到存储桶,成功后url是 https://nft-buc-1302315235.cos.ap-beijing.myqcloud.com/txt0/10.txt

⑦ 开源合约。 开源成功后地址是 https://rinkeby.etherscan.io/address/0xA5b3628207a774Ac3260948eA285D5D2320cF7ba#codehttps://rinkeby.etherscan.io/address/

⑧ 打开售卖函数,调用mintKILLAZ函数。https://rinkeby.etherscan.io/address/0xA5b3628207a774Ac3260948eA285D5D2320cF7ba#writeContract

 

设置baseUri 也就是上传txt描述文件的前缀 

 

⑩导入opensea,查看我们发布的NFT,拷贝合约地址到https://testnets.opensea.io/get-listed/step-two 即 0xA5b3628207a774Ac3260948eA285D5D2320cF7ba到opensea 

导入后可以再opensea看到你发布的项目: 

⑩① 开始售卖。 选择一个点击sell

 ⑩②  重复上边修改上传图片和txt到存储桶的过程,即可修改盲盒图片进行解封。再开发一个网页进行售卖,即可完成开头讲的类似于网页售卖,opensea展示等。

教程延申:

上述过程太过复杂和难以维护,如果要方便维护,可以做一个后台管理系统,类似于本人开发的

然后结合网页,就可以做成 KILLAz 这种平台。

对技术感兴趣的可以加群交流,或者私聊我,qq:916968320

             

这篇关于以太坊如何发布NFT到opensea的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/664132

相关文章

五大特性引领创新! 深度操作系统 deepin 25 Preview预览版发布

《五大特性引领创新!深度操作系统deepin25Preview预览版发布》今日,深度操作系统正式推出deepin25Preview版本,该版本集成了五大核心特性:磐石系统、全新DDE、Tr... 深度操作系统今日发布了 deepin 25 Preview,新版本囊括五大特性:磐石系统、全新 DDE、Tree

Linux Mint Xia 22.1重磅发布: 重要更新一览

《LinuxMintXia22.1重磅发布:重要更新一览》Beta版LinuxMint“Xia”22.1发布,新版本基于Ubuntu24.04,内核版本为Linux6.8,这... linux Mint 22.1「Xia」正式发布啦!这次更新带来了诸多优化和改进,进一步巩固了 Mint 在 Linux 桌面

多模块的springboot项目发布指定模块的脚本方式

《多模块的springboot项目发布指定模块的脚本方式》该文章主要介绍了如何在多模块的SpringBoot项目中发布指定模块的脚本,作者原先的脚本会清理并编译所有模块,导致发布时间过长,通过简化脚本... 目录多模块的springboot项目发布指定模块的脚本1、不计成本地全部发布2、指定模块发布总结多模

高效+灵活,万博智云全球发布AWS无代理跨云容灾方案!

摘要 近日,万博智云推出了基于AWS的无代理跨云容灾解决方案,并与拉丁美洲,中东,亚洲的合作伙伴面向全球开展了联合发布。这一方案以AWS应用环境为基础,将HyperBDR平台的高效、灵活和成本效益优势与无代理功能相结合,为全球企业带来实现了更便捷、经济的数据保护。 一、全球联合发布 9月2日,万博智云CEO Michael Wong在线上平台发布AWS无代理跨云容灾解决方案的阐述视频,介绍了

Vue3项目开发——新闻发布管理系统(六)

文章目录 八、首页设计开发1、页面设计2、登录访问拦截实现3、用户基本信息显示①封装用户基本信息获取接口②用户基本信息存储③用户基本信息调用④用户基本信息动态渲染 4、退出功能实现①注册点击事件②添加退出功能③数据清理 5、代码下载 八、首页设计开发 登录成功后,系统就进入了首页。接下来,也就进行首页的开发了。 1、页面设计 系统页面主要分为三部分,左侧为系统的菜单栏,右侧

maven发布项目到私服-snapshot快照库和release发布库的区别和作用及maven常用命令

maven发布项目到私服-snapshot快照库和release发布库的区别和作用及maven常用命令 在日常的工作中由于各种原因,会出现这样一种情况,某些项目并没有打包至mvnrepository。如果采用原始直接打包放到lib目录的方式进行处理,便对项目的管理带来一些不必要的麻烦。例如版本升级后需要重新打包并,替换原有jar包等等一些额外的工作量和麻烦。为了避免这些不必要的麻烦,通常我们

禅道Docker安装包发布

禅道Docker安装包发布 大家好, 禅道Docker安装包发布。 一、下载地址 禅道开源版:   /dl/zentao/docker/docker_zentao.zip  备用下载地址:https://download.csdn.net/download/u013490585/16271485 数据库用户名: root,默认密码: 123456。运行时,可以设置 MYSQL_ROOT_P

C++编程:ZeroMQ进程间(订阅-发布)通信配置优化

文章目录 0. 概述1. 发布者同步发送(pub)与订阅者异步接收(sub)示例代码可能的副作用: 2. 适度增加缓存和队列示例代码副作用: 3. 动态的IPC通道管理示例代码副作用: 4. 接收消息的超时设置示例代码副作用: 5. 增加I/O线程数量示例代码副作用: 6. 异步消息发送(使用`dontwait`标志)示例代码副作用: 7. 其他可以考虑的优化项7.1 立即发送(ZMQ_IM

风格控制水平创新高!南理工InstantX小红书发布CSGO:简单高效的端到端风格迁移框架

论文链接:https://arxiv.org/pdf/2408.16766 项目链接:https://csgo-gen.github.io/ 亮点直击 构建了一个专门用于风格迁移的数据集设计了一个简单但有效的端到端训练的风格迁移框架CSGO框架,以验证这个大规模数据集在风格迁移中的有益效果。引入了内容对齐评分(Content Alignment Score,简称CAS)来评估风格迁移

Eclipse发布Maven项目到tomcat,无法加载到lib文件夹下的jar包

BMS 解决方法: 当我们发布web项目到tomcat时,访问地址时会报一个classnotfound的错误,但是eclipse中的项目中都已经添加了相应的类,有一种比较容易犯的错误是,你没有把额外所需的jar包加到tomcat中的lib文件夹中,在这里介绍一种在项目中直接添加jar包到lib目录下:  右键已创建的web项目——properties属性——点击Deployment Assem