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.

Martijn Vissers
  • 308
  • 2
  • 12

2 Answers2

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_
                    )
                )
            ));
    }
Martijn Vissers
  • 308
  • 2
  • 12
  • 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 '21 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 – Martijn Vissers Dec 31 '21 at 15:23
  • How u are passing a json data to string accepted function. Im stuck on same issue.Please help me out? – sachin murali May 30 '22 at 08:43
  • @sachinmurali I pass the JSON data as a string (string memory contractURI_). JavaScript's JSON.stringify() can be used for this if you're passing it from a js application – Martijn Vissers May 31 '22 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
Casareafer
  • 648
  • 2
  • 12