一、说明
目前直接在支持BSC链的NFT平台上发行NFT作品是最为简单的方法,但是该处理方法存在一个问题,即发行的NFT作品无法在tp钱包显示图片,导致在tp钱包展示NFT 集合时比较混乱,无法正常显示NFT。
出现该问题的原因,主要是NFT图片的存储形式导致的。无论是nft图片存储到铸造平台的去中心化链上还是存储到ipfs等主流公链上都会存在链上数据与tp钱包之间的数据通信问题。主要考虑是NFT图片数据的访问链路或者接口与钱包直接的数据互信问题,导致无法在TP钱包展示NFT图片。如果此时可以正常在metamask等钱包展示NFT图片,但是无法在TP显示图片,进一步印证了该问题。
二、处理方案
解决该问题的处理方案,只能是脱离现有的NFT铸造平台,通过自部署NFT合约,设置NFT图片的存储方式以允许TP钱包访问,然后通过接口直接铸造NFT作品。
带有tokenURI的NFT合约源代码如下:
1、IERC721接口文件如下:
pragma solidity ^0.5.5; import "./ITRC165.sol"; /** * @dev Required interface of an TRC721 compliant contract. */ contract ITRC721 is ITRC165 { 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); /** * @dev Returns the number of NFTs in `owner`'s account. */ function balanceOf(address owner) public view returns (uint256 balance); /** * @dev Returns the owner of the NFT specified by `tokenId`. */ function ownerOf(uint256 tokenId) public view returns (address owner); /** * @dev Transfers a specific NFT (`tokenId`) from one account (`from`) to * another (`to`). * * * * Requirements: * - `from`, `to` cannot be zero. * - `tokenId` must be owned by `from`. * - If the caller is not `from`, it must be have been allowed to move this * NFT by either {approve} or {setApprovalForAll}. */ function safeTransferFrom(address from, address to, uint256 tokenId) public; /** * @dev Transfers a specific NFT (`tokenId`) from one account (`from`) to * another (`to`). * * Requirements: * - If the caller is not `from`, it must be approved to move this NFT by * either {approve} or {setApprovalForAll}. */ function transferFrom(address from, address to, uint256 tokenId) public; 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 safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) public; }
2、ITRC721Metadata 元数据接口合约源代码如下:
pragma solidity ^0.5.5; import "./ITRC721.sol"; /** * @title TRC-721 Non-Fungible Token Standard, optional metadata extension */ contract ITRC721Metadata is ITRC721 { function name() external view returns (string memory); function symbol() external view returns (string memory); function tokenURI(uint256 tokenId) external view returns (string memory); }
3、TRC721Metadata 元数据实现类合约源代码如下
pragma solidity ^0.5.5; import "./Counters.sol"; import "./TRC165.sol"; import "./TRC721.sol"; import "./ITRC721Metadata.sol"; contract TRC721Metadata is Context, TRC165, TRC721, ITRC721Metadata { // Token name string private _name; // Token symbol string private _symbol; // Base URI string private _baseURI; // Optional mapping for token URIs mapping(uint256 => string) private _tokenURIs; /* * bytes4(keccak256('name()')) == 0x06fdde03 * bytes4(keccak256('symbol()')) == 0x95d89b41 * bytes4(keccak256('tokenURI(uint256)')) == 0xc87b56dd * * => 0x06fdde03 ^ 0x95d89b41 ^ 0xc87b56dd == 0x5b5e139f */ bytes4 private constant _INTERFACE_ID_TRC721_METADATA = 0x5b5e139f; /** * @dev Constructor function */ constructor (string memory name, string memory symbol) public { _name = name; _symbol = symbol; // register the supported interfaces to conform to TRC721 via TRC165 _registerInterface(_INTERFACE_ID_TRC721_METADATA); } /** * @dev Gets the token name. * @return string representing the token name */ function name() external view returns (string memory) { return _name; } /** * @dev Gets the token symbol. * @return string representing the token symbol */ function symbol() external view returns (string memory) { return _symbol; } /** * @dev Returns the URI for a given token ID. May return an empty string. * * If the token's URI is non-empty and a base URI was set (via * {_setBaseURI}), it will be added to the token ID's URI as a prefix. * * Reverts if the token ID does not exist. */ function tokenURI(uint256 tokenId) external view returns (string memory) { require(_exists(tokenId), "TRC721Metadata: URI query for nonexistent token"); string memory _tokenURI = _tokenURIs[tokenId]; // Even if there is a base URI, it is only appended to non-empty token-specific URIs if (bytes(_tokenURI).length == 0) { return ""; } else { // abi.encodePacked is being used to concatenate strings return string(abi.encodePacked(_baseURI, _tokenURI)); } } /** * @dev Internal function to set the token URI for a given token. * * Reverts if the token ID does not exist. * * TIP: if all token IDs share a prefix (e.g. if your URIs look like * `http://api.myproject.com/token/<id>`), use {_setBaseURI} to store * it and save gas. */ function _setTokenURI(uint256 tokenId, string memory _tokenURI) internal { require(_exists(tokenId), "TRC721Metadata: 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}. * * _Available since v2.5.0._ */ function _setBaseURI(string memory baseURI) internal { _baseURI = baseURI; } /** * @dev Returns the base URI set via {_setBaseURI}. This will be * automatically added as a preffix in {tokenURI} to each token's URI, when * they are non-empty. * * _Available since v2.5.0._ */ function baseURI() external view returns (string memory) { return _baseURI; } /** * @dev Internal function to burn a specific token. * Reverts if the token does not exist. * Deprecated, use _burn(uint256) instead. * @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]; } } }
4、MinterRole NFT铸造者权限角色实现类合约源代码
pragma solidity ^0.5.5; import "./Context.sol"; import "./Roles.sol"; contract MinterRole is Context { using Roles for Roles.Role; event MinterAdded(address indexed account); event MinterRemoved(address indexed account); Roles.Role private _minters; constructor () internal { _addMinter(_msgSender()); } modifier onlyMinter() { require(isMinter(_msgSender()), "MinterRole: caller does not have the Minter role"); _; } function isMinter(address account) public view returns (bool) { return _minters.has(account); } function addMinter(address account) public onlyMinter { _addMinter(account); } function renounceMinter() public { _removeMinter(_msgSender()); } function _addMinter(address account) internal { _minters.add(account); emit MinterAdded(account); } function _removeMinter(address account) internal { _minters.remove(account); emit MinterRemoved(account); } }
5、NFT主合约核心代码如下:
pragma solidity ^0.5.5; import "./TRC721.sol"; import "./TRC721Enumerable.sol"; import "./TRC721MetadataMintable.sol"; contract NFT is TRC721, TRC721Enumerable, TRC721MetadataMintable { constructor() public TRC721Metadata("NFT", "NFT") { } }
通过自部署合约铸造NFT作品,即可将NFT图片存储到指定数据对象路径,即可解决TP无法显示NFT图片问题。
至此,完成NFT单品铸造完成后无法在tp钱包显示图片故障处理及解决方法。
pdf+视频(BSC币安链+TRX波场链)NFT发行教程及合约源代码下载:
币安智能链BSC+波场链TRX NFT发行(合约部署、开源、参数配置、开发、故障处理、工具使用)教程下载:
pdf+视频(TRX波场链+BSC币安链)NFT发行教程及合约源代码下载地址:
添加VX或者telegram获取全程线上免费指导
评论前必须登录!
注册