关上CHAINPIP社区,进入利用,创立一个新利用;

将模板代码删除,上传本次测试的合约代码。

这是一个合乎ERC721规范的NFT合约代码,其中包含了几个罕用的标准接口和合约,上面是个合约的具体信息:
IERC65.sol

pragma solidity ^0.8.0;/** * @dev ERC165标准接口, 详见 * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * 合约能够申明反对的接口,供其余合约查看 * */interface IERC165 {    /**     * @dev 如果合约实现了查问的`interfaceId`,则返回true     * 规定详见:https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]     *     */    function supportsInterface(bytes4 interfaceId) external view returns (bool);}

IERC721.sol

// SPDX-License-Identifier: MITpragma solidity ^0.8.0;import "./IERC165.sol";/** * @dev ERC721标准接口. */interface IERC721 is IERC165 {    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) external view returns (uint256 balance);    function ownerOf(uint256 tokenId) external view returns (address owner);    function safeTransferFrom(        address from,        address to,        uint256 tokenId,        bytes calldata data    ) external;    function safeTransferFrom(        address from,        address to,        uint256 tokenId    ) external;    function transferFrom(        address from,        address to,        uint256 tokenId    ) external;    function approve(address to, uint256 tokenId) external;    function setApprovalForAll(address operator, bool _approved) external;    function getApproved(uint256 tokenId) external view returns (address operator);    function isApprovedForAll(address owner, address operator) external view returns (bool);}

IERC721Receiver.sol

// SPDX-License-Identifier: MITpragma solidity ^0.8.0;// ERC721接收者接口:合约必须实现这个接口来通过平安转账接管ERC721interface IERC721Receiver {    function onERC721Received(        address operator,        address from,        uint tokenId,        bytes calldata data    ) external returns (bytes4);}

IERC721Metadata.sol

// SPDX-License-Identifier: MITpragma solidity ^0.8.0;interface IERC721Metadata {    function name() external view returns (string memory);    function symbol() external view returns (string memory);    function tokenURI(uint256 tokenId) external view returns (string memory);}

Strings.sol

// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)pragma solidity ^0.8.4;/** * @dev String operations. */library Strings {    bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";    uint8 private constant _ADDRESS_LENGTH = 20;    /**     * @dev Converts a `uint256` to its ASCII `string` decimal 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.sol        if (value == 0) {            return "0";        }        uint256 temp = value;        uint256 digits;        while (temp != 0) {            digits++;            temp /= 10;        }        bytes memory buffer = new bytes(digits);        while (value != 0) {            digits -= 1;            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));            value /= 10;        }        return string(buffer);    }    /**     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.     */    function toHexString(uint256 value) internal pure returns (string memory) {        if (value == 0) {            return "0x00";        }        uint256 temp = value;        uint256 length = 0;        while (temp != 0) {            length++;            temp >>= 8;        }        return toHexString(value, length);    }    /**     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.     */    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {        bytes memory buffer = new bytes(2 * length + 2);        buffer[0] = "0";        buffer[1] = "x";        for (uint256 i = 2 * length + 1; i > 1; --i) {            buffer[i] = _HEX_SYMBOLS[value & 0xf];            value >>= 4;        }        require(value == 0, "Strings: hex length insufficient");        return string(buffer);    }    /**     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.     */    function toHexString(address addr) internal pure returns (string memory) {        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);    }}

Address.sol

// SPDX-License-Identifier: MITpragma solidity ^0.8.1;// Address库library Address {    // 利用extcodesize判断一个地址是否为合约地址    function isContract(address account) internal view returns (bool) {        uint size;        assembly {            size := extcodesize(account)        }        return size > 0;    }}

ERC721.sol

// SPDX-License-Identifier: MIT// by 0xAApragma solidity ^0.8.4;import "./IERC165.sol";import "./IERC721.sol";import "./IERC721Receiver.sol";import "./IERC721Metadata.sol";import "./Address.sol";import "./String.sol";contract ERC721 is IERC721, IERC721Metadata{    using Address for address; // 应用Address库,用isContract来判断地址是否为合约    using Strings for uint256; // 应用String库,    // Token名称    string public override name;    // Token代号    string public override symbol;    // tokenId 到 owner address 的持有人映射    mapping(uint => address) private _owners;    // address 到 持仓数量 的持仓量映射    mapping(address => uint) private _balances;    // tokenID 到 受权地址 的受权映射    mapping(uint => address) private _tokenApprovals;    //  owner地址。到operator地址 的批量受权映射    mapping(address => mapping(address => bool)) private _operatorApprovals;    /**     * 构造函数,初始化`name` 和`symbol` .     */    constructor(string memory name_, string memory symbol_) {        name = name_;        symbol = symbol_;    }    // 实现IERC165接口supportsInterface    function supportsInterface(bytes4 interfaceId)        external        pure        override        returns (bool)    {        return            interfaceId == type(IERC721).interfaceId ||            interfaceId == type(IERC165).interfaceId ||            interfaceId == type(IERC721Metadata).interfaceId;    }    // 实现IERC721的balanceOf,利用_balances变量查问owner地址的balance。    function balanceOf(address owner) external view override returns (uint) {        require(owner != address(0), "owner = zero address");        return _balances[owner];    }    // 实现IERC721的ownerOf,利用_owners变量查问tokenId的owner。    function ownerOf(uint tokenId) public view override returns (address owner) {        owner = _owners[tokenId];        require(owner != address(0), "token doesn't exist");    }    // 实现IERC721的isApprovedForAll,利用_operatorApprovals变量查问owner地址是否将所持NFT批量受权给了operator地址。    function isApprovedForAll(address owner, address operator)        external        view        override        returns (bool)    {        return _operatorApprovals[owner][operator];    }    // 实现IERC721的setApprovalForAll,将持有代币全副受权给operator地址。调用_setApprovalForAll函数。    function setApprovalForAll(address operator, bool approved) external override {        _operatorApprovals[msg.sender][operator] = approved;        emit ApprovalForAll(msg.sender, operator, approved);    }    // 实现IERC721的getApproved,利用_tokenApprovals变量查问tokenId的受权地址。    function getApproved(uint tokenId) external view override returns (address) {        require(_owners[tokenId] != address(0), "token doesn't exist");        return _tokenApprovals[tokenId];    }         // 受权函数。通过调整_tokenApprovals来,受权 to 地址操作 tokenId,同时开释Approval事件。    function _approve(        address owner,        address to,        uint tokenId    ) private {        _tokenApprovals[tokenId] = to;        emit Approval(owner, to, tokenId);    }    // 实现IERC721的approve,将tokenId受权给 to 地址。条件:to不是owner,且msg.sender是owner或受权地址。调用_approve函数。    function approve(address to, uint tokenId) external override {        address owner = _owners[tokenId];        require(            msg.sender == owner || _operatorApprovals[owner][msg.sender],            "not owner nor approved for all"        );        _approve(owner, to, tokenId);    }    // 查问 spender地址是否被能够应用tokenId(他是owner或被受权地址)。    function _isApprovedOrOwner(        address owner,        address spender,        uint tokenId    ) private view returns (bool) {        return (spender == owner ||            _tokenApprovals[tokenId] == spender ||            _operatorApprovals[owner][spender]);    }    /*     * 转账函数。通过调整_balances和_owner变量将 tokenId 从 from 转账给 to,同时开释Tranfer事件。     * 条件:     * 1. tokenId 被 from 领有     * 2. to 不是0地址     */    function _transfer(        address owner,        address from,        address to,        uint tokenId    ) private {        require(from == owner, "not owner");        require(to != address(0), "transfer to the zero address");        _approve(owner, address(0), tokenId);        _balances[from] -= 1;        _balances[to] += 1;        _owners[tokenId] = to;        emit Transfer(from, to, tokenId);    }        // 实现IERC721的transferFrom,非平安转账,不倡议应用。调用_transfer函数    function transferFrom(        address from,        address to,        uint tokenId    ) external override {        address owner = ownerOf(tokenId);        require(            _isApprovedOrOwner(owner, msg.sender, tokenId),            "not owner nor approved"        );        _transfer(owner, from, to, tokenId);    }    /**     * 平安转账,平安地将 tokenId 代币从 from 转移到 to,会查看合约接收者是否理解 ERC721 协定,以避免代币被永恒锁定。调用了_transfer函数和_checkOnERC721Received函数。条件:     * from 不能是0地址.     * to 不能是0地址.     * tokenId 代币必须存在,并且被 from领有.     * 如果 to 是智能合约, 他必须反对 IERC721Receiver-onERC721Received.     */    function _safeTransfer(        address owner,        address from,        address to,        uint tokenId,        bytes memory _data    ) private {        _transfer(owner, from, to, tokenId);        require(_checkOnERC721Received(from, to, tokenId, _data), "not ERC721Receiver");    }    /**     * 实现IERC721的safeTransferFrom,平安转账,调用了_safeTransfer函数。     */    function safeTransferFrom(        address from,        address to,        uint tokenId,        bytes memory _data    ) public override {        address owner = ownerOf(tokenId);        require(            _isApprovedOrOwner(owner, msg.sender, tokenId),            "not owner nor approved"        );        _safeTransfer(owner, from, to, tokenId, _data);    }    // safeTransferFrom重载函数    function safeTransferFrom(        address from,        address to,        uint tokenId    ) external override {        safeTransferFrom(from, to, tokenId, "");    }    /**      * 铸造函数。通过调整_balances和_owners变量来铸造tokenId并转账给 to,同时开释Tranfer事件。铸造函数。通过调整_balances和_owners变量来铸造tokenId并转账给 to,同时开释Tranfer事件。     * 这个mint函数所有人都能调用,理论应用须要开发人员重写,加上一些条件。     * 条件:     * 1. tokenId尚不存在。     * 2. to不是0地址.     */    function _mint(address to, uint tokenId) internal virtual {        require(to != address(0), "mint to zero address");        require(_owners[tokenId] == address(0), "token already minted");        _balances[to] += 1;        _owners[tokenId] = to;        emit Transfer(address(0), to, tokenId);    }    // 销毁函数,通过调整_balances和_owners变量来销毁tokenId,同时开释Tranfer事件。条件:tokenId存在。    function _burn(uint tokenId) internal virtual {        address owner = ownerOf(tokenId);        require(msg.sender == owner, "not owner of token");        _approve(owner, address(0), tokenId);        _balances[owner] -= 1;        delete _owners[tokenId];        emit Transfer(owner, address(0), tokenId);    }    // _checkOnERC721Received:函数,用于在 to 为合约的时候调用IERC721Receiver-onERC721Received, 以防 tokenId 被不小心转入黑洞。    function _checkOnERC721Received(        address from,        address to,        uint tokenId,        bytes memory _data    ) private returns (bool) {        if (to.isContract()) {            return                IERC721Receiver(to).onERC721Received(                    msg.sender,                    from,                    tokenId,                    _data                ) == IERC721Receiver.onERC721Received.selector;        } else {            return true;        }    }    /**     * 实现IERC721Metadata的tokenURI函数,查问metadata。     */    function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {        require(_owners[tokenId] != address(0), "Token Not Exist");        string memory baseURI = _baseURI();        return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : "";    }    /**     * 计算{tokenURI}的BaseURI,tokenURI就是把baseURI和tokenId拼接在一起,须要开发重写。     * BAYC的baseURI为ipfs://QmeSjSinHpPnmXmspMjwiXyN6zS4E9zccariGR3jxcaWtq/      */    function _baseURI() internal view virtual returns (string memory) {        return "";    }}

编译、部署合约,设置NFT名称为HHTest,符号为HH。

合约部署胜利后,进入ABI操作页面,开始测试合约的mint函数,测试铸造一个NFT。

铸造实现后应用合约地址在opensea的测试链版中查问,能够发现咱们刚刚铸造的NFT能够在其中查问进去,因为合约用的是无聊猿的tokenURI地址,所以显示的是无聊猿的信息。