diff --git a/src/components/App.js b/src/components/App.js index 51d9532..77510ca 100644 --- a/src/components/App.js +++ b/src/components/App.js @@ -3,12 +3,15 @@ import AutoHideAlert, {alertRef} from "./AutoHideAlert.js"; import MintModal, {modalRef} from "./MintModal.js"; import {ThemeProvider} from "@mui/material"; import {theme} from "../styles/theme.js"; +import { Web3ContextProvider } from "./Web3Context"; export const App = () => { return -
- - -
+ +
+ + +
+
} diff --git a/src/components/ConfirmTxStep.js b/src/components/ConfirmTxStep.js new file mode 100644 index 0000000..2b278ea --- /dev/null +++ b/src/components/ConfirmTxStep.js @@ -0,0 +1,84 @@ +import React, { useContext } from 'react'; +import { Box, Button, CircularProgress, IconButton, Typography } from '@mui/material'; +import { isMetaMaskDesktop } from "../utils"; +import { getConfigChainID } from "../web3"; +import { NETWORKS } from "../constants"; +import { Web3Context } from "./Web3Context"; +import { ChevronLeft } from "@mui/icons-material"; + +export const ConfirmTxStep = ({ txHash, quantity, setIsLoading }) => { + const [{ wallet, chainID }, setState] = useContext(Web3Context) + + const renderConfirmText = () => { + if (wallet) { + console.log("current chainID", chainID) + if (chainID !== getConfigChainID()) { + const networkName = NETWORKS[getConfigChainID()]?.name + return { + title: `Switch to ${networkName ?? "correct"} network`, + subtitle: <> + Open your wallet and switch the network to {networkName ?? "correct one"} to proceed + + } + } + return { + title: "Confirm the transaction in your wallet", + subtitle: <> + Wait up to 2-3 sec until the transaction appears in your wallet +

+ {isMetaMaskDesktop() && "If you don't see the Confirm button, scroll down ⬇️"} + + } + } + return { + title: "Connect your wallet", + subtitle: <> + Connect your wallet to confirm the transaction + + } + } + + const { title, subtitle } = renderConfirmText() + + return + {!txHash && theme.palette.grey[500], + }} + onClick={() => setIsLoading(false)}> + + } + {txHash ? : + 👀 + } + + {txHash ? `Minting ${quantity} NFT...` : title} + + {!txHash && {subtitle}} + +} \ No newline at end of file diff --git a/src/components/MintModal.js b/src/components/MintModal.js index 06a73f1..596abb0 100644 --- a/src/components/MintModal.js +++ b/src/components/MintModal.js @@ -1,8 +1,9 @@ -import React, { useImperativeHandle, useState } from "react"; -import { Box, CircularProgress, Dialog, DialogContent, DialogTitle, IconButton, Typography } from "@mui/material"; +import React, { useContext, useImperativeHandle, useState } from "react"; +import { Box, Dialog, DialogContent, DialogTitle, IconButton, Typography } from "@mui/material"; import CloseIcon from '@mui/icons-material/Close'; import { QuantityModalStep } from './QuantityModalStep'; -import { isMobile } from "../utils"; +import { ConfirmTxStep } from "./ConfirmTxStep"; +import { Web3Context } from "./Web3Context"; const DialogTitleWithClose = ({ children, onClose }) => { return @@ -32,9 +33,14 @@ export const MintModal = (props, ref) => { const [isLoading, setIsLoading] = useState(false) const [step, setStep] = useState(1) const [quantity, setQuantity] = useState(1) + // TODO: migrate to hooks and global state / Context + // this is a hack + const [state, setState] = useContext(Web3Context) + const { wallet, chainID } = state const handleClose = () => { - setIsOpen(false); + setIsOpen(false) + setIsLoading(false) } useImperativeHandle(ref, () => ({ @@ -46,53 +52,27 @@ export const MintModal = (props, ref) => { - {isLoading && - - {txHash ? : - 👀 - } - - {txHash - ? `Minting ${quantity} NFT...` - : 'Confirm the transaction in your wallet'} - - {!txHash && - Wait up to 2-3 sec until the transaction appears in your wallet -

- {!isMobile() && "If you don't see the Confirm button, scroll down ⬇️"}
} -
- } + {isLoading && } {!isLoading && <> - - Mint now - - - {step === 1 && } - + + Mint now + + + {step === 1 && } + }
) diff --git a/src/components/QuantityModalStep.js b/src/components/QuantityModalStep.js index d0b4671..e87e8b3 100644 --- a/src/components/QuantityModalStep.js +++ b/src/components/QuantityModalStep.js @@ -12,7 +12,7 @@ import { parseTxError, roundToDecimal } from '../utils'; import { Attribution } from './Attribution'; import { isEthereumContract } from "../contract"; -export const QuantityModalStep = ({ setQuantity, setIsLoading, setTxHash, setStep }) => { +export const QuantityModalStep = ({ setQuantity, setIsLoading, setTxHash, state, setState }) => { const [quantityValue, setQuantityValue] = useState(1) const [maxTokens, setMaxTokens] = useState(undefined) const [mintPrice, setMintPrice] = useState(undefined) @@ -49,14 +49,18 @@ export const QuantityModalStep = ({ setQuantity, setIsLoading, setTxHash, setSte const onSuccess = async () => { setIsLoading(true) - const { tx } = await mint(quantityValue) + const { tx } = await mint(quantityValue, { + onConnectSuccess: (wallet) => setState({ ...state, wallet }), + setState: (wallet, chainID) => setState({ wallet, chainID }) + }) if (tx === undefined) { setIsLoading(false) } - tx?.on("transactionHash", (hash) => { + tx?.once("transactionHash", (hash) => { setTxHash(hash) - })?.on("confirmation", async () => { + })?.once("confirmation", async () => { setIsLoading(false) + setTxHash(undefined) showAlert(`Successfully minted ${quantityValue} NFTs${window.DEFAULTS?.redirectURL ? ". You will be redirected in less than a second" : ""}`, "success") // TODO: show success state in the modal if (window.DEFAULTS?.redirectURL) { @@ -64,7 +68,7 @@ export const QuantityModalStep = ({ setQuantity, setIsLoading, setTxHash, setSte window.location.href = window.DEFAULTS?.redirectURL }, 800) } - })?.on("error", (e) => { + })?.once("error", (e) => { setIsLoading(false) const { code, message } = parseTxError(e); if (code !== 4001) { diff --git a/src/components/Web3Context.js b/src/components/Web3Context.js new file mode 100644 index 0000000..469f0f0 --- /dev/null +++ b/src/components/Web3Context.js @@ -0,0 +1,33 @@ +import { createContext, useEffect, useState } from "react"; +import { currentAddress, getWalletAddressOrConnect, provider, web3 } from "../wallet"; +import { useWeb3 } from "../hooks/useWeb3"; + +const defaultContext = { + wallet: undefined, + chainID: undefined, +} + +export const Web3Context = createContext([defaultContext, () => defaultContext]); + +// TODO: remove this dirty hooks hack when migrate to RainbowKit + ethers or similar +export const Web3ContextProvider = (props) => { + const [state, setState] = useState(defaultContext) + const [web3, provider] = useWeb3([state.wallet, state.chainID]) + + useEffect(() => { + if (!provider) + return + + provider.on("chainChanged", (chainId) => { + console.log("chainChanged", chainId) + setState({ + ...state, + chainID: Number(String(provider.chainId).replace("0x", "")) + }) + }) + }, [provider]) + + return + {props.children} + +} \ No newline at end of file diff --git a/src/constants.js b/src/constants.js index 6d6b1f0..4587268 100644 --- a/src/constants.js +++ b/src/constants.js @@ -35,6 +35,54 @@ export const NETWORKS = { testnetID: 5, blockExplorerURL: "https://goerli.etherscan.io" }, + 10: { + name: "Optimism", + chain: "ethereum", + rpcURL: "https://mainnet.optimism.io/", + currency: { + "name": "Ether", + "symbol": "ETH", + "decimals": 18 + }, + testnetID: 420, + blockExplorerURL: "https://optimistic.etherscan.io" + }, + 420: { + name: "Optimism Goerli", + chain: "ethereum", + rpcURL: "https://goerli.optimism.io/", + currency: { + "name": "Goerli Ether", + "symbol": "ETH", + "decimals": 18 + }, + testnetID: 420, + blockExplorerURL: "https://goerli-optimism.etherscan.io" + }, + 42161: { + name: "Arbitrum One", + chain: "ethereum", + currency: { + "name": "Ether", + "symbol": "ETH", + "decimals": 18 + }, + testnetID: 421613, + rpcURL: "https://arb1.arbitrum.io/rpc/", + blockExplorerURL: "https://arbiscan.io", + }, + 421613: { + "name": "Arbitrum Görli", + "chain": "ethereum", + currency: { + "name": "Goerli Ether", + "symbol": "ETH", + "decimals": 18 + }, + testnetID: 421613, + rpcURL: "https://goerli-rollup.arbitrum.io/rpc/", + blockExplorerURL: "https://goerli.arbiscan.io" + }, 137: { name: "Polygon", chain: "polygon", @@ -83,6 +131,30 @@ export const NETWORKS = { testnetID: 97, blockExplorerURL: "https://testnet.bscscan.com", }, + 43114: { + name: "Avalanche", + chain: "AVAX", + rpcURL: "https://api.avax.network/ext/bc/C/rpc/", + currency: { + "name": "Avalanche", + "symbol": "AVAX", + "decimals": 18 + }, + testnetID: 43113, + blockExplorerURL: "https://snowtrace.io" + }, + 43113: { + name: "Avalanche Fuji", + chain: "AVAX", + rpcURL: "https://api.avax-test.network/ext/bc/C/rpc/", + currency: { + "name": "Avalanche", + "symbol": "AVAX", + "decimals": 18 + }, + testnetID: 43113, + blockExplorerURL: "https://cchain.explorer.avax-test.network" + }, 25: { name: "Cronos Blockchain", chain: "cronos", diff --git a/src/contract.js b/src/contract.js index 164f1c9..035c227 100644 --- a/src/contract.js +++ b/src/contract.js @@ -1,20 +1,15 @@ -import { getCurrentNetwork, isWeb3Initialized, switchNetwork, web3 } from './wallet.js'; +import { switchNetwork } from './wallet.js'; import { NETWORKS } from "./constants.js"; -import { getConfigChainID, readOnlyWeb3 } from "./web3"; +import { getConfigChainID, getWeb3Instance } from "./web3"; export let NFTContract; const abiMemoryCache = {}; -export const initContract = async (_web3, contract, shouldSwitchNetwork=true) => { - let currentNetwork = await getCurrentNetwork(); - if (shouldSwitchNetwork && !contract.allowedNetworks.includes(currentNetwork)) { - await switchNetwork(contract.allowedNetworks[0]) - currentNetwork = await getCurrentNetwork(); - } +export const initContract = async (web3Instance, contract) => { const address = contract.address[contract.allowedNetworks[0]]; const abi = contract.abi; - return new _web3.eth.Contract(abi, address); + return new web3Instance.eth.Contract(abi, address); } const initContractGlobalObject = async () => { @@ -101,13 +96,13 @@ const getEmbeddedMainABI = (address) => { return undefined } -export const setContracts = async (shouldSwitchNetwork=true) => { - await initContractGlobalObject(); - const _web3 = isWeb3Initialized() ? web3 : readOnlyWeb3 +export const setContracts = async ({ shouldSwitchNetwork = true, onNetworkSwitch } = {}) => { + await initContractGlobalObject() + const web3Instance = getWeb3Instance() if (shouldSwitchNetwork) { - await switchNetwork(window.CONTRACT.nft.allowedNetworks[0]); + await switchNetwork(window.CONTRACT.nft.allowedNetworks[0], onNetworkSwitch) } - NFTContract = await initContract(_web3, window.CONTRACT.nft, false); + NFTContract = await initContract(web3Instance, window.CONTRACT.nft) console.log("NFTContract", NFTContract) } diff --git a/src/hooks/useWeb3.js b/src/hooks/useWeb3.js new file mode 100644 index 0000000..9c434d1 --- /dev/null +++ b/src/hooks/useWeb3.js @@ -0,0 +1,14 @@ +import { useEffect, useState } from "react"; +import { provider, web3 } from "../wallet"; + +export const useWeb3 = (dependencies) => { + const [state, setState] = useState([]) + + useEffect(() => { + if (!provider) + return + setState([web3, provider]) + }, [...dependencies, web3, provider]) + + return state +} \ No newline at end of file diff --git a/src/mint/web3.js b/src/mint/web3.js index ef9d410..d7d9b48 100644 --- a/src/mint/web3.js +++ b/src/mint/web3.js @@ -1,4 +1,5 @@ -import { getWalletAddressOrConnect, web3 } from "../wallet.js"; +import { getConfigChainID, getWeb3Instance } from "../web3"; +import { getCurrentNetwork, getWalletAddressOrConnect } from "../wallet.js"; import { formatValue} from "../utils.js"; import { NFTContract } from "../contract.js" import { buildTx } from "../tx"; @@ -97,11 +98,12 @@ export const getMintedNumber = async () => { // totalSupply was removed to save gas when minting // but number minted still accessible in the contract as a private variable // TODO: remove this in NFTFactory v1.1 - const minted = await web3.eth.getStorageAt( + const web3Instance = getWeb3Instance() + const minted = await web3Instance.eth.getStorageAt( NFTContract._address, '0x00000000000000000000000000000000000000000000000000000000000000fb' ) - return web3.utils.hexToNumber(minted) + return web3Instance.utils.hexToNumber(minted) } export const getMaxSupply = async () => { @@ -142,9 +144,14 @@ export const getMaxTokensPerMint = async () => { return getDefaultMaxTokensPerMint() } -export const mint = async (nTokens) => { - const wallet = await getWalletAddressOrConnect(true); - if (!wallet) { +export const mint = async (nTokens, { onConnectSuccess, setState }) => { + const wallet = await getWalletAddressOrConnect({ + shouldSwitchNetwork: true, + onConnectSuccess + }) + const chainID = await getCurrentNetwork() + setState(wallet, chainID) + if (!wallet || chainID !== getConfigChainID()) { return { tx: undefined } } const numberOfTokens = nTokens ?? 1; diff --git a/src/tx.js b/src/tx.js index 785de07..bdc1d3f 100644 --- a/src/tx.js +++ b/src/tx.js @@ -34,6 +34,6 @@ const estimateMaxGasFee = async (tx) => { } const estimateMaxPriorityFeePerGas = async () => { - const chainID = await web3.eth.getChainId(); + const chainID = await getCurrentNetwork() return isEthereum(chainID) ? 2e9 : undefined; } diff --git a/src/utils.js b/src/utils.js index f9cbea7..127ea47 100644 --- a/src/utils.js +++ b/src/utils.js @@ -1,6 +1,8 @@ export const isMobile = () => /Mobi/i.test(window.navigator.userAgent) || /iPhone|iPod|iPad/i.test(navigator.userAgent); +export const isMetaMaskDesktop = (provider) => !isMobile() && provider?.isMetaMask + export const objectMap = (object, mapFn) => { return Object.keys(object).reduce((result, key) => { result[key] = mapFn(object[key]); @@ -8,7 +10,7 @@ export const objectMap = (object, mapFn) => { }, {}) } -export const normalizeURL = (u) => ((new URL(u).host).replace('www.', '')) +export const toHex = (number) => number ? `0x${number.toString(16)}` : undefined export const parseErrorCode = (error) => { try { diff --git a/src/wallet.js b/src/wallet.js index 2cbd902..c85bc7f 100644 --- a/src/wallet.js +++ b/src/wallet.js @@ -15,22 +15,26 @@ export const isWeb3Initialized = () => { return web3 && provider; } -const getWeb3ModalProviderOptions = ({ - forceConnect, - isMobileOnlyInjectedProvider, - isDesktopNoInjectedProvider -}) => { +export const getIsMobileOnlyInjectedProvider = () => isMobile() && window.ethereum + +export const getIsDesktopNoInjectedProvider = () => !isMobile() && !window.ethereum + +const getWeb3ModalProviderOptions = ({ forceConnect }) => { + const isMobileOnlyInjectedProvider = getIsMobileOnlyInjectedProvider() + const isDesktopNoInjectedProvider = getIsDesktopNoInjectedProvider() const walletConnectOptions = { rpc: objectMap(NETWORKS, (value) => (value.rpcURL)), qrcodeModalOptions: { mobileLinks: [ "rainbow", + "zerion", "trust", "ledger", "gnosis" ], desktopLinks: [ "rainbow", + "zerion", "trust", "ledger", "gnosis" @@ -130,19 +134,15 @@ const getWeb3ModalProviderOptions = ({ return !isMobileOnlyInjectedProvider ? allProviderOptions : {} } -const initWeb3Modal = (forceConnect, isMobileOnlyInjectedProvider) => { - const isDesktopNoInjectedProvider = !isMobile() && !window.ethereum +const initWeb3Modal = (forceConnect) => { + const isMobileOnlyInjectedProvider = getIsMobileOnlyInjectedProvider() const web3Modal = new Web3Modal({ cacheProvider: false, // Use custom Metamask provider because of conflicts with Coinbase injected provider // On mobile apps with injected web3, use ONLY injected providers disableInjectedProvider: !isMobileOnlyInjectedProvider, - providerOptions: getWeb3ModalProviderOptions({ - forceConnect, - isMobileOnlyInjectedProvider, - isDesktopNoInjectedProvider - }) + providerOptions: getWeb3ModalProviderOptions({ forceConnect }) }); return web3Modal @@ -151,7 +151,7 @@ const initWeb3Modal = (forceConnect, isMobileOnlyInjectedProvider) => { const initWeb3 = async (forceConnect = false) => { if (isWeb3Initialized()) return - const isMobileOnlyInjectedProvider = isMobile() && window.ethereum + const isMobileOnlyInjectedProvider = getIsMobileOnlyInjectedProvider() const web3Modal = initWeb3Modal(forceConnect, isMobileOnlyInjectedProvider) if (web3Modal.cachedProvider || forceConnect) { @@ -193,36 +193,39 @@ export const isWalletConnected = async () => { return accounts?.length > 0; } -export const getWalletAddressOrConnect = async (shouldSwitchNetwork, refresh) => { - const currentAddress = async () => { - if (!isWeb3Initialized()) { - return undefined; - } - try { - return (await provider?.request({ method: 'eth_requestAccounts' }))[0]; - } catch { - await provider.enable(); - return (await web3.eth.getAccounts())[0]; - } +export const currentAddress = async () => { + if (!isWeb3Initialized()) { + return undefined; } + try { + return (await provider?.request({ method: 'eth_requestAccounts' }))[0]; + } catch { + await provider.enable(); + return (await web3.eth.getAccounts())[0]; + } +} + +export const getWalletAddressOrConnect = async ({ shouldSwitchNetwork, onConnectSuccess, onNetworkSwitch }) => { if (!isWeb3Initialized()) { await connectWallet(); - if (refresh) { - window.location.reload(); - } } - // For multi-chain dapps (multi-chain contracts on the same page) + const address = await currentAddress(); + if (onConnectSuccess) + onConnectSuccess(address) if (shouldSwitchNetwork ?? true) { - await setContracts(shouldSwitchNetwork ?? true); + await setContracts({ + shouldSwitchNetwork: shouldSwitchNetwork ?? true, + onNetworkSwitch: onNetworkSwitch + }) } - return await currentAddress(); + return address } export const getCurrentNetwork = async () => { return Number(await provider?.request({ method: 'net_version' })); } -export const switchNetwork = async (chainID) => { +export const switchNetwork = async (chainID, onSwitch) => { if (!provider) { return } @@ -236,6 +239,7 @@ export const switchNetwork = async (chainID) => { method: 'wallet_switchEthereumChain', params: [{ chainId: chainIDHex }], }); + if (onSwitch) onSwitch() } catch (error) { // This error code indicates that the chain has not been added to MetaMask // if it is not, then install it into the user MetaMask @@ -295,6 +299,9 @@ const getConnectButton = () => { } export const updateWalletStatus = async () => { + if (getIsMobileOnlyInjectedProvider()) { + await tryInitWeb3(false) + } const connected = await isWalletConnected(); const button = getConnectButton(); if (button && connected) { @@ -307,7 +314,7 @@ export const updateConnectButton = () => { walletBtn?.addEventListener('click', async () => { await connectWallet() if (window.CONTRACT_ADDRESS && !window?.DISABLE_MINT) { - await setContracts(true) + await setContracts({ shouldSwitchNetwork: true }) await updateMintedCounter() } }); diff --git a/src/web3.js b/src/web3.js index df67cfe..0ff7e3f 100644 --- a/src/web3.js +++ b/src/web3.js @@ -1,5 +1,7 @@ import Web3 from "web3"; import { NETWORKS } from "./constants"; +import { toHex } from "./utils"; +import { isWeb3Initialized, provider, web3 } from "./wallet"; export const getConfigChainID = () => { // Default to Ethereum @@ -7,6 +9,20 @@ export const getConfigChainID = () => { return window.IS_TESTNET ? NETWORKS[networkID].testnetID : networkID; } +export const isCorrectNetwork = (provider) => { + if (!provider?.chainId) { + return null + } + const isHex = String(provider?.chainId)?.startsWith("0x") + const configChain = isHex ? toHex(getConfigChainID()) : getConfigChainID() + return String(configChain) === String(provider?.chainId) +} + +export const getWeb3Instance = () => + isWeb3Initialized() ? ( + isCorrectNetwork(provider) ? web3 : readOnlyWeb3 + ) : readOnlyWeb3 + const initReadOnlyWeb3 = () => { const configChainID = getConfigChainID() const rpcURL = NETWORKS[configChainID]?.rpcURL diff --git a/templates/textapes/embed.html b/templates/textapes/embed.html deleted file mode 100644 index 7e46477..0000000 --- a/templates/textapes/embed.html +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - diff --git a/templates/textapes/index.js b/templates/textapes/index.js deleted file mode 100644 index d1ce17a..0000000 --- a/templates/textapes/index.js +++ /dev/null @@ -1,111 +0,0 @@ -import { mint } from "../../mint/web3.js"; -import { init } from "../../mint/index.js"; -import { NFTContract } from "../../contract.js" -import {connectWallet} from "../../wallet.js"; - -let isLoading = false; - -const mintAndReveal = async (nTokens) => { - setShowLoading(true); - await mint(nTokens).then(async () => { - let tokenID; - await NFTContract.methods.walletOfOwner(wallet).call((err, res) => { - if (!err && res.length) { - console.log(res); - tokenID = parseInt(res.slice(-1)[0]); - } - }) - await reveal(tokenID); - isLoading = false; - }).catch((e) => { - isLoading = false; - }) -} - -const updateMintedCounter = async () => { - const counter = document.querySelector('#total-minted'); - if (counter) { - counter.textContent = - `Total minted: ${await NFTContract.methods.totalSupply().call()} / ${await NFTContract.methods.MAX_SUPPLY().call()}`; - console.log("Updated counter"); - } -} - -const launchMint = async () => { - await init(); - await connectWallet(); - - if (isLoading) { - return false; - } - isLoading = true; - - const startContainer = document.querySelector('#start-container'); - if (!startContainer) { - await mintAndReveal(1); - } - - updateMintedCounter(); - setInterval(updateMintedCounter, 5000); - - setShowLoading(false); - setShowReveal(false); - document.querySelector('#submit-quantity-form').addEventListener("submit", async (e) => { - const nTokens = document.querySelector('#quantity-select').value; - await mintAndReveal(nTokens); - }); -} - -const setShowLoading = (shouldShow) => { - const container = document.querySelector('#loading-container'); - (container ?? {}).style = shouldShow ? "display:flex" : "display:none"; - if (shouldShow) { - setShowReveal(false); - setShowQuantity(false); - } -} - -const setShowReveal = (shouldShow) => { - const generateContainer = document.querySelector('#generate-container'); - (generateContainer ?? {}).style = shouldShow ? "display:flex" : "display:none"; -} - -const setShowQuantity = (shouldShow) => { - const startContainer = document.querySelector('#start-container'); - (startContainer ?? {}).style = shouldShow ? "display:flex" : "display:none"; -} - -const reveal = async (tokenID) => { - const generateContainer = document.querySelector('#generate-container'); - if (!generateContainer) return; - - setShowLoading(false); - setShowReveal(true); - const url = await NFTContract.methods.tokenURI(tokenID).call(); - const result = await (await fetch(url)).json(); - const address = NFTContract._address; - - let heading = document.querySelector('#generate-heading') ?? {}; - if (heading?.tagName !== "H2" && heading?.tagName !== "H1") { - heading = heading.getElementsByTagName("h2")[0]; - } - heading.textContent = result.name; - (document.querySelector('#generate-description') ?? {}).textContent = result.description; - let img = document.querySelector('#generate-image'); - if (img?.tagName !== "IMG") { - img = img.getElementsByTagName("img")[0]; - } - img.src = `https://cloudflare-ipfs.com/ipfs/${result.image.split("//")[1]}`; - (document.querySelector('#generate-view-opensea') ?? {}).href = `https://opensea.io/assets/${address}/${tokenID}`; -} - -const shouldLaunchMint = () => { - const isWPEditorActive = document.body.classList.contains("elementor-editor-active"); - const isURL = document.location.href.includes("/mint") || document.location.href.includes("/generate"); - return isURL && !isWPEditorActive; -} - -if (shouldLaunchMint()) { - document.onload = launchMint(); -} -(document.querySelector('#mint-button') ?? {}).onclick = () => mintAndReveal();