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.
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?
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:
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.