I was working on a NFT marketplace app using NextJS as frontend and Solidity as backend. When I tried to sell an NFT using the frontend UI, I encountered this error:

Access to XMLHttpRequest at 'https://gateway.pinata.cloud/ipfs/QmbbWLfoPg9aSpFCKoYQRadQynmCRMjydVhkXJZKBXKnyT' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

Here is my code:

import {useState} from 'react';
import {ethers} from 'ethers';
import {useRouter} from 'next/router';
import Web3Modal from 'web3modal';
import {contractAddress, INFURA_URL, PINATA_KEY, PINATA_SECRET} from '../config.js';
import NFTMarketplace from "../abi/NFTMarketplace.json";
import axios from 'axios';
import Image from 'next/image';

export default function createNFT() {
    const [fileURL, setFileURL] = useState(null);
    const [formInput, updateFormInput] = useState({price: "", name: "", description: ""});
    const router = useRouter();
    const [loadingState, setLoadingState] = useState('Not loaded');

    // upload image to IPFS
    async function imageUpload(e) {
        const file = e.target.files[0];
        try {
            const formData = new FormData();
            formData.append("file", file);
            const resFile = await axios({
                method: "post",
                url: "https://api.pinata.cloud/pinning/pinFileToIPFS",
                data: formData,
                headers: {
                    'pinata_api_key': PINATA_KEY,
                    'pinata_secret_api_key': PINATA_SECRET,
                    'Content-Type': 'multipart/form-data'
                }
            });

            const imageURL = `https://gateway.pinata.cloud/ipfs/${
                resFile.data.IpfsHash
            }`;
            setFileURL(imageURL)

        } catch (e) {
            console.log(e)
        }
    }

    // upload metadata to IPFS and return URL to use in later transaction
    async function uploadToIPFS() {
        const {name, description, price} = formInput;
        if (!name || !description || !price || !fileURL) {
            return
        }
        setLoadingState('Loading...')

        try {
            let jsonData = JSON.stringify({
                "pinataMetadata": {
                    "name": `${
                        name.json
                    }`
                },
                "pinataContent": {
                    name,
                    description,
                    image: fileURL
                }
            })

            const resFile = await axios({
                method: "post",
                url: "https://api.pinata.cloud/pinning/pinJSONToIPFS",
                data: jsonData,
                headers: {
                    'pinata_api_key': PINATA_KEY,
                    'pinata_secret_api_key': PINATA_SECRET,
                    'Content-Type': 'application/json'
                }
            });

            const tokenURI = `https://gateway.pinata.cloud/ipfs/${
                resFile.data.IpfsHash
            }`;
            return tokenURI;
        } catch (error) {
            console.log("Error uploading file: ", error);
        }
    }

    async function listNFTForSale() {
        const tokenURI = await uploadToIPFS();
        const web3modal = new Web3Modal();
        const connection = await web3modal.connect();
        const provider = new ethers.providers.Web3Provider(connection);
        const getnetwork = await provider.getNetwork();
        const goerliChainId = 5;
        if (getnetwork.chainId != goerliChainId) {
            alert("You are not connected to the Goerli network!")
            return;
        }
        // sign the transaction
        const signer = provider.getSigner();
        const contract = new ethers.Contract(contractAddress, NFTMarketplace.abi, signer);
        const price = ethers.utils.parseUnits(formInput.price, 'ether');
        let listingPrice = await contract.getListingPrice();
        listingPrice = listingPrice.toString();
        let transaction = await contract.createToken(tokenURI, price, {value: listingPrice});
        await transaction.wait();
        router.push('/');
    }
    return (<div className='flex justify-center'>
        <div className='w-1/8 flex-col mr-10 mt-10'> {
            !fileURL && (<Image className='rounded mt-4' src='/image_place_holder.jpg' alt="Image placeholder" width={300} height={200}/>)
        }
            {
            fileURL && (<Image src={fileURL} alt="Image uploaded successfully" className='rounded mt-4' placeholder="blur" blurDataURL="/image_place_holder.jpg" width={300} height={200}/>)
        }</div>
        <div className='w-1/2 flex flex-col'>
            <input placeholder='Asset Name' className='mt-8 border rounded p-4' onChange={e=>updateFormInput({...formInput, name: e.target.value})}/>
            <textarea placeholder='Asset Description' className='mt-2 border rounded p-4' onChange={e=>updateFormInput({...formInput, description: e.target.value})}/>
            <input placeholder='Asset Price in Ethers' className='mt-2 border rounded p-4' type="number" onChange={e=>updateFormInput({...formInput, price: e.target.value})}/>
            <input type="file" name="Asset" className='my-4' onChange={imageUpload} /> {
            fileURL && (<button onClick={listNFTForSale} className="font-bold mt-4 bg-pink-500 text-white rounded p-4 shadow-lg"> {
                loadingState == 'Not loaded' ? 'Create NFT' : 'Uploading...'
            } </button>)
        } </div>
    </div>)
}

I don't have enough reputation so I can only provide links of images.

Unhandled Runtime Error on UI

NFT Sell Page UI

The error occurring on the Unhandled Runtime Error is:

Unhandled Runtime Error
AxiosError: Network Error

Call Stack
XMLHttpRequest.handleError
node_modules/axios/lib/adapters/xhr.js (154:0)

I tried installing the Access-Control-Allow-Origin extension on Chrome, but it doesn't work. Other approaches suggested usually work with ExpressJS and NodeJS but I'm working with NextJS. How do I resolve this?

1

There are 1 answers

0
monk13 On

I've encountered same problem and adding below to axios request headers solved my issue. I am not sure which request you are getting the error but you can expand the error in console, it should tell the file/line that generates the error.

'Accept': 'text/plain'

For example:

const resFile = await axios({
            method: "post",
            url: "https://api.pinata.cloud/pinning/pinFileToIPFS",
            data: formData,
            headers: {
                'Accept': 'text/plain',
                'pinata_api_key': PINATA_KEY,
                'pinata_secret_api_key': PINATA_SECRET,
                'Content-Type': 'multipart/form-data'
            }
        });

More on: https://knowledge.pinata.cloud/en/articles/6848516-how-to-fix-400-errors-with-dedicated-gateways

and

https://stackoverflow.com/a/35553666/18100033

Hope that helps.