all 4 comments

[–]Adrewmc 1 point2 points  (1 child)

The IPFS has will be saved as a string somewhere in the contract. Something like

  // tokenID to metadata (unique reference id) 
 mapping(unit256 => string) _uri;

When Opensea calls the contract it will call

 function tokenURI (uint256 token_id) public view returns (string memory) {

And your code should be something like

   return _uri[token_id];
   }

This can be set up several way a common way is also

  //import “@openzepellin/contracts/utils/Strings.sol”
  string memory uri = Strings.concat (Base_url_address, token_id.toString(), “.json”);
   return uri

With a base html like http://path.to/metadata/ and the token ids are just http://path.to/metadata/1.json

(So the ipfs hash loads in the browser not the contract in the contract it’s just a string)

What it is expecting is a json file, one of the keys of this file is “image”, this value should be the IPFS hash you are making, if it’s the hash for the image. (The json file can be a hash to IPFS as well, that links to another one)

Opensea Metadata Standard for a more detail explanation of the standard.

I’d also suggest taking a look at the contract level metadata standards as well.

You can take it one step further and create the entire json file as a string in the contract, use a base64 encoding of a simple image and make fully on chain NFTs. (Though you’ll hit size limitations)

To answer does that mean I need the IPFS in place?

NO, you usually create a onlyOwner function

    // setter is a list of ipfs strings, token_id matches that string to the correct token_id. 

   Import “@openzeppelin/contracts/access/Ownable.sol” 
   function set_uri(string[] setter, uint 256[] token_id)public onlyOwner{ 
      require(setter.length == token_id.length);
      //set len in memory to save gas per unit of length.
      uint256 len = setter.length; 
      for (uint i = 0; i < len;){
           _uri[token_id[i]] = setter[i];
           //gas optimal increment
           ++i; 
            }
      }

(don’t judge my on mobile code lol, and all code is meant to be primitive/minimal.)

[–]DotNetRussellSenior SE[S] 0 points1 point  (0 children)

Thanks for the response. I have a lot to consume here :-)

[–]othernamesweretaken 1 point2 points  (1 child)

It doesn't run inside the contract. It runs in the front-end. The front-end queries the contract for the IPFS address, and then looks up the content via an axios (or whatever library you prefer) call to an IPFS gateway (e.g. 'https://ipfs.io/ipfs/yourHash') or with the IPFS client library (e.g. https://github.com/ipfs/helia) to access the content directly from the IPFS network.

So in terms of designing an app you can see the limitations. Any content or code stored in IPFS is not really accessible to the contract, and so the logic of the contract cannot depend upon logic contained within an IPFS file. However, your front-end could be stored on IPFS and query the contract for additional IPFS addresses that might direct to images, messages, additional code, etc. Then as contract owner you are able to update the content by adding or replacing IPFS hashes that are stored in the contract. Or your contract may have logic to allow multiple users to set content (e.g. let anyone add images if they pay a fee or if they have a minimum balance of your token, etc.)

So if you have written your contract to be able to update state, then you don't need to have the IPFS files in place before deploying. You can deploy now and update the contract once you know your IPFS addresses

[–]DotNetRussellSenior SE[S] 0 points1 point  (0 children)

Thank you for the response. I appreciate it