import { Zora, constructMediaData, sha256FromBuffer, generateMetadata, constructBidShares, } from "@zoralabs/zdk"; // Zora provider import axios from "axios"; // axios requests import Web3Modal from "web3modal"; // Web3Modal import { providers } from "ethers"; // Ethers import { useState, useEffect } from "react"; // State management import { createContainer } from "unstated-next"; // Unstated-next containerization import WalletConnectProvider from "@walletconnect/web3-provider"; // WalletConnectProvider (Web3Modal) // Web3Modal provider options const providerOptions = { walletconnect: { package: WalletConnectProvider, options: { // Inject Infura infuraId: process.env.NEXT_PUBLIC_INFURA_ID, }, }, }; function useWeb3() { const [zora, setZora] = useState(null); // Zora provider const [modal, setModal] = useState(null); // Web3Modal const [address, setAddress] = useState(null); // ETH address /** * Setup Web3Modal on page load (requires window) */ const setupWeb3Modal = () => { // Creaste new web3Modal const web3Modal = new Web3Modal({ network: "mainnet", cacheProvider: true, providerOptions: providerOptions, }); // Set web3Modal setModal(web3Modal); }; /** * Authenticate and store necessary items in global state */ const authenticate = async () => { // Initiate web3Modal const web3Provider = await modal.connect(); await web3Provider.enable(); // Generate ethers provider const provider = new providers.Web3Provider(web3Provider); // Collect address const signer = provider.getSigner(); const address = await signer.getAddress(); setAddress(address); // Generate Zora provider const zora = new Zora(signer, 1); setZora(zora); }; /** * Converts File to an ArrayBuffer for hashing preperation * @param {File} file uploaded file * @returns {ArrayBuffer} from file */ const getFileBuffer = async (file) => { return new Promise((res, rej) => { // create file reader let reader = new FileReader(); // register event listeners reader.addEventListener("loadend", (e) => res(e.target.result)); reader.addEventListener("error", rej); // read file reader.readAsArrayBuffer(file); }); }; /** * Mints media to Zora * @param {File} file media to mint * @param {String} name of media * @param {String} description of media * @param {Number} fee to share with previous owner */ const mintMedia = async (file, name, description, fee) => { // Generate metadataJSON const metadataJSON = generateMetadata("zora-20210101", { description: description ? description : "", mimeType: file.type, name: name, version: "zora-20210101", }); // Generate media buffer const buffer = await getFileBuffer(file); // Generate content hashes const contentHash = sha256FromBuffer(Buffer.from(buffer)); const metadataHash = sha256FromBuffer(Buffer.from(metadataJSON)); // Upload files to fleek let formData = new FormData(); formData.append("upload", file); formData.append("name", name); formData.append("metadata", metadataJSON); // Post upload endpoint const upload = await axios.post("/api/upload", formData, { headers: { "Content-Type": "multipart/form-data", }, }); // Collect fileUrl and metadataUrl from Fleek const { fileUrl, metadataUrl } = upload.data; // Construct mediaData object const mediaData = constructMediaData( fileUrl, metadataUrl, contentHash, metadataHash ); const bidShares = constructBidShares( 0, // Creator share 100 - parseFloat(fee), // Owner share parseFloat(fee) // Previous owner share ); // Make transaction const tx = await zora.mint(mediaData, bidShares); await tx.wait(1); // Wait 1 confirmation and throw user to next screen }; // On load events useEffect(setupWeb3Modal, []); return { address, mintMedia, authenticate, }; } // Create unstate-next container const web3 = createContainer(useWeb3); export default web3;