10

I am trying to implement contract-level metadata for an NFT collection on OpenSea, However, if I do so with the following code, the contract's metadata won't update on the OpenSea collections' page, nor will it update the description of the contract on the tokens' pages.

The TokenURI is also stored on-chain and does update when given proper data. In my case, it'll be an SVG image along with some strings for information. (more below snippet)

The code is missing everything that isn't relevant.

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

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";

import "./base64.sol";

contract Test is ERC721Enumerable, ERC721URIStorage, Ownable {
    using Counters for Counters.Counter;
    using Strings for uint256;

    string private _contractURI;

    constructor() ERC721("Test", "T") {}

    function svgToImageURI(string memory _source) public pure returns (string memory) {
        string memory baseURL = "data:image/svg+xml;base64,";
        string memory svgBase64Encoded = Base64.encode(bytes(string(abi.encodePacked(_source))));
        return string(abi.encodePacked(baseURL, svgBase64Encoded));
    }

    function formatTokenURI(string memory _imageURI, string memory _name, string memory _description, string memory _properties) public pure returns (string memory) {
        return string(
            abi.encodePacked(
                "data:application/json;base64,",
                Base64.encode(
                    bytes(
                        abi.encodePacked(
                            '{"name":"', _name,
                            '", "description": "', _description, '"',
                            ', "attributes": ', _properties,
                            ', "image":"', _imageURI, '"}'
                        )
                    )
                )
            )
        );
    }

    function setTokenURI(uint256 _tokenId, string memory _tokenURI) public onlyOwner() {
        _setTokenURI(_tokenId, _tokenURI);
        emit tokenChanged(_tokenId);
    }

    function setContractURI(string memory contractURI_) public onlyOwner() {
        _contractURI = string(abi.encodePacked(
            "data:application/json;base64,",
            Base64.encode(
                bytes(
                    abi.encodePacked(
                        contractURI_
                    )
                )
            )
        ));
    }

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

The input I give to the setContractURI function is a simple JSON snippet from the OpenSea website so that I'm sure I comply with the rules of it.

{
  "name": "OpenSea Creatures",
  "description": "OpenSea Creatures are adorable aquatic beings primarily for demonstrating what can be done using the OpenSea platform. Adopt one today to try out all the OpenSea buying, selling, and bidding feature set.",
  "image": "https://openseacreatures.io/image.png",
  "external_link": "https://openseacreatures.io",
  "seller_fee_basis_points": 100, 
  "fee_recipient": "0xA97F337c39cccE66adfeCB2BF99C1DdC54C2D721"
}

What am I doing wrong? I'm on Polygon Mumbai testnet.

2
  • Which base64.sol library are you importing?
    – rbinnun
    Dec 22, 2021 at 10:57
  • 1
    @rbinnun, I am not 100% sure which it was, it just was one another big NFT collection was using. But it wasn't the issue in this case. Dec 29, 2021 at 9:56

2 Answers 2

8

It seems like my setContractURI function had one encodepacket too much. it looks like it is working now on OpenSea.

    function setContractURI(string memory contractURI_) public onlyOwner() {
        _contractURI = string(abi.encodePacked(
                "data:application/json;base64,",
                Base64.encode(
                    bytes(
                        contractURI_
                    )
                )
            ));
    }
4
  • By any chance, do you know how to set them for listing while we're uploading them? Right now, it just create the collection, add NFTs into it but, we need to list them manually
    – Dr.jacky
    Dec 29, 2021 at 10:45
  • 1
    @Dr.jacky I assume you mean listing the NFT collection? That still has to be done manually. If you really need to list it dynamically you'd have to check out OpenSea's own APIs Dec 31, 2021 at 15:23
  • How u are passing a json data to string accepted function. Im stuck on same issue.Please help me out? May 30, 2022 at 8:43
  • @sachinmurali I pass the JSON data as a string (string memory contractURI_). JavaScript's JSON.stringify(<json object>) can be used for this if you're passing it from a js application May 31, 2022 at 10:19
0

I struggled a while to get my contract metadata read by Opensea, Maibe this can help:

https://ethereum.stackexchange.com/a/131807/99976

Edit. added basic explanation:

I basically served a .json file with a simple http server

ie. my metadata is saved in metadata.json

my contractURI() returns the following:

https://www.myCoolDomain.com/metadata.json

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.