gotangible / hooks / useVerifyMetadata.js
useVerifyMetadata.js
Raw
import { useState } from "react";
import { useIPFS } from "./useIPFS";

/**
 * This is a hook that loads the NFT metadata in case it doesn't alreay exist
 * If metadata is missing, the object is replaced with a reactive object that updatees when the data becomes available
 * The hook will retry until request is successful (with OpenSea, for now)
 */
export const useVerifyMetadata = () => {
  const { resolveLink } = useIPFS();
  const [results, setResults] = useState({});

  /**
   * Fet Metadata  from NFT and Cache Results
   * @param {object} NFT
   * @returns NFT
   */
  function verifyMetadata(NFT) {
    //Pass Through if Metadata already present
    if (NFT.metadata) return NFT;
    //Get the Metadata
    getMetadata(NFT);
    //Return Hooked NFT Object
    return results?.[NFT.token_uri] ? results?.[NFT.token_uri] : NFT;
  } //verifyMetadata()

  /**
   * Extract Metadata from NFT,
   *  Fallback: Fetch from URI
   * @param {object} NFT
   * @returns void
   */
  async function getMetadata(NFT) {
    //Validate URI
    if (!NFT.token_uri || !NFT.token_uri.includes("://")) {
      console.log("getMetadata() Invalid URI", { URI: NFT.token_uri, NFT });
      return;
    }
    //Get Metadata
    fetch(NFT.token_uri)
      .then((res) => res.json())
      .then((metadata) => {
        if (!metadata) {
          //Log
          console.error(
            "useVerifyMetadata.getMetadata() No Metadata found on URI:",
            { URI: NFT.token_uri, NFT },
          );
        }
        //Handle Setbacks
        else if (
          metadata?.detail &&
          metadata.detail.includes("Request was throttled")
        ) {
          //Log
          console.warn(
            "useVerifyMetadata.getMetadata() Bad Result for:" +
              NFT.token_uri +
              "  Will retry later",
            { results, metadata },
          );
          //Retry That Again after 1s
          setTimeout(function () {
            getMetadata(NFT);
          }, 1000);
        } //Handle Opensea's {detail: "Request was throttled. Expected available in 1 second."}
        else {
          //No Errors
          //Set
          setMetadata(NFT, metadata);
          //Log
          console.log(
            "getMetadata() Late-load for NFT Metadata " + NFT.token_uri,
            { metadata },
          );
        } //Valid Result
      })
      .catch((err) => {
        console.error("useVerifyMetadata.getMetadata() Error Caught:", {
          err,
          NFT,
          URI: NFT.token_uri,
        });
      });
  } //getMetadata()

  /**
   * Update NFT Object
   * @param {object} NFT
   * @param {object} metadata
   */
  function setMetadata(NFT, metadata) {
    //Add Metadata
    NFT.metadata = metadata;
    //Set Image
    if (metadata?.image) NFT.image = resolveLink(metadata.image);
    //Set to State
    if (metadata && !results[NFT.token_uri])
      setResults({ ...results, [NFT.token_uri]: NFT });
  } //setMetadata()

  return { verifyMetadata };
}; //useVerifyMetadata()