Metadata provider
Our smart contract holds a reference to token metadata on IPFS, not the metadata itself. The role of the MetadataProvider
is to fetch the content from IPFS and translate it to a usable metadata object.
Create ./components/providers/MetadataProvider.tsx
and add the following import statement:
import { createContext, useContext, useCallback } from 'react'
Token metadata should follow the tzip-21 specification. Let's define a subset of the standard properties:
interface ZombieMetadata {
name: string
description?: string
displayUri: string
thumbnailUri: string
attributes: {
alive: boolean
}
}
We will define a context props interface for every provider. In this case:
interface MetadataProviderContextProps {
fetchMetadata: (tokenInfo: string) => Promise<ZombieMetadata>
ipfsUriToGateway: (ipfsUri: string) => string
}
Now we will define a helper function that replaces the IPFS URI with a HTTPS gateway, as most browsers still don't support IPFS natively. This isn't ideal because gateways are more centralised.
const ipfsUriToGateway = (ipfsUri: string) =>
ipfsUri.replace("ipfs://", "https://cloudflare-ipfs.com/ipfs/")
As we will reuse the above function a few times, you might prefer to move it into a utilities file rather than importing it's use from this component (as we do in this tutorial)
Create an empty context:
const MetadataContext = createContext<MetadataProviderContextProps>({
fetchMetadata: function (tokenInfo: string): Promise<ZombieMetadata> {
throw new Error("Function not implemented.")
},
ipfsUriToGateway,
})
const useMetadataContext = () => useContext(MetadataContext)
And now the provider implementation, it simply uses the Fetch API to retrieve a JSON from the gateway and return a ZombieMetadata
object.
const MetadataProvider = ({ children }: { children: React.ReactNode }) => {
const fetchMetadata = useCallback(async (tokenInfo: string) => {
if (!tokenInfo.startsWith("ipfs://")) {
throw new Error("Invalid tokenInfo")
}
const res = await fetch(ipfsUriToGateway(tokenInfo))
const metadata = await res.json()
console.log(metadata)
return metadata
}, [])
return (
<MetadataContext.Provider value={{ fetchMetadata, ipfsUriToGateway }}>
{children}
</MetadataContext.Provider>
)
}
export { MetadataProvider, useMetadataContext }
export type { ZombieMetadata }
Remember to include the Metadata provider in the app hierarchy in _app.tsx.
Last updated