Solidity

NFT 元數據未顯示在 opensea 上?

  • April 17, 2022

我正在使用開放式 Zeppelin 在 ETH 上開發 NFT 合約,並達到了我在 rinkeby 上部署的階段。但是,由於圖像和元數據未在 opensea 上顯示,因此 tokenURI 和 contractURI 似乎存在問題。

我像這樣實現 tokenURI 和 ContractURI:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.1;

import "hardhat/console.sol";
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
//access control
import "@openzeppelin/contracts/access/Ownable.sol";

// Helper functions OpenZeppelin provides.
import "@openzeppelin/contracts/utils/Counters.sol";
import "@openzeppelin/contracts/utils/Strings.sol";

import "./libraries/Base64.sol";

contract MetropolisWorldGenesis is ERC721, Ownable {

....

string private _contractURI;

function contractURI() public view returns (string memory) {
       return _contractURI;
   }

function tokenURI(uint256 _tokenId) public view override returns (string memory) {
       PropertyAttributes memory propAttributes = nftHolderAttributes[_tokenId];

       string memory json = Base64.encode(
           abi.encodePacked(
               '{"name": "',
               propAttributes.name,
               '", "description": "',propAttributes.description,'", "image": "',
               propAttributes.image,
               '", "attributes": [ { "trait_type": "Tower", "value": ',propAttributes.properties.tower,', "trait_type": "District", "value":',propAttributes.properties.district, ', "trait_type": "neighborhood", "value":',propAttributes.properties.neighborhood,',]}'
           )
       );

       string memory output = string(
           abi.encodePacked("data:application/json;base64,", json)
       );
       
       return output;
   }


   function setContractURI(
       string memory name, string memory desc,
       string memory image,string memory link, 
       uint royalty) public onlyOwner() {

       string memory x = Base64.encode(
           abi.encodePacked(
               '{"name": "',
               name,
               '", "description": "',
               desc,
               '", "image": "', 
               image,
               '", "external_link": "', 
               link,
               '","seller_fee_basis_points":"', royalty, // 100 Indicates a 1% seller fee
               '", "fee_recipient": "0xA97F337c39cccE66adfeCB2BF99C1DdC54C2D721" }' // Where seller fees will be paid to.}
           )
       );
       _contractURI = string(abi.encodePacked(
               "data:application/json;base64,", x
           ));
       console.log("contract uri updated");
   }
}

當在本地執行時,tokenURI 會返回以下輸出,它會解析瀏覽器中的正確數據:

data:application/json;base64,eyJuYW1lIjogIkdpbGRlZCBBdHRpYyIsICJkZXNjcmlwdGlvbiI6ICJUaGUgQXN0cm9ub21lcidzIFN0dWRpbwpVbmRlciB0aGUgZG9tZSBpcyBhIHBsYW5ldHJpdW0gClJlc2VhcmNoZXMgdGhlIG9yaWdpbnMgb2YgdGhlIE1ldHJvcG9saXMiLCAiaW1hZ2UiOiAiaXBmczovL1FtWnc3NzY1ZG04aHBIRndITDl3b29RSkNzSkd6TFR3WTIyNjVDR1lpeFB3aUciLCAiYXR0cmlidXRlcyI6IFsgeyAidHJhaXRfdHlwZSI6ICJUb3dlciIsICJ2YWx1ZSI6IFRvd2VyIDEsICJ0cmFpdF90eXBlIjogIkRpc3RyaWN0IiwgInZhbHVlIjpIaWdoLUZseWVyLCAidHJhaXRfdHlwZSI6ICJuZWlnaGJvcmhvb2QiLCAidmFsdWUiOkZyZWUgQWxsZXkgUXVhcnRlcnMsXX0=

任何想法我哪裡出錯了?

因此,當我認為這是創建動態元數據的一種完全可行的方法時,我需要的更改是在令牌 URI 函式的末尾添加正確的括號。所以功能變成了這個。一個微小但令人沮喪的變化。

function tokenURI(uint256 _tokenId) public view override returns (string memory) {
       PropertyAttributes memory propAttributes = nftHolderAttributes[_tokenId];

       string memory json = Base64.encode(
           abi.encodePacked(
               '{"name": "',
               propAttributes.name,
               '", "description": "',propAttributes.description,'", "image": "',
               propAttributes.image,
               '", "attributes": [ { "trait_type": "Tower", "value": ',propAttributes.properties.tower,', "trait_type": "District", "value":',propAttributes.properties.district, ', "trait_type": "neighborhood", "value":',propAttributes.properties.neighborhood,'}]}'
           )
       );

       string memory output = string(
           abi.encodePacked("data:application/json;base64,", json)
       );
       
       return output;
   }

我還了解到所有變數都必須是字元串,因此 contractURI 函式中的版稅變數導致它無法工作。並且設置合約 URI 功能需要更改為此。

function setContractURI(
       string memory name, string memory desc,
       string memory image,string memory link, 
       string memory royalty) public onlyOwner() {

       string memory x = Base64.encode(
           abi.encodePacked(
               '{"name": "',
               name,
               '", "description": "',
               desc,
               '", "image": "', 
               image,
               '", "external_link": "', 
               link,
               '","seller_fee_basis_points":"', royalty, // 100 Indicates a 1% seller fee
               '", "fee_recipient": "0xA97F337c39cccE66adfeCB2BF99C1DdC54C2D721" }' // Where seller fees will be paid to.}
           )
       );
       _contractURI = string(abi.encodePacked(
               "data:application/json;base64,", x
           ));
       console.log("contract uri updated");
   }

令牌 uri 應該是 URI,而不是 JSON 類型。您應該將您的 json 上傳到伺服器或類似 IPFS 的東西,並將您的 URI 帶到您的契約中。

有關更多資訊,請查看提案的原始網站。特別是檢查元數據部分。

引用自:https://ethereum.stackexchange.com/questions/124874