Unhandled Runtime Error Error: call revert exception (method="getListingPrice()", errorArgs=null, errorName=null, errorSignature=null, reason=null, code=CALL_EXCEPTION, version=abi/5.5.0)
I keep getting this error whenever I am trying to create a new NFT on an NFT marketplace that I will be hosting on polygon as soon as I get to deploy it on the mainnet.
here is my code for Marketplace smart contract:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "@openzeppelin/contracts/utils/Counters.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "hardhat/console.sol";
contract NFTMarketplace is ERC721URIStorage {
using Counters for Counters.Counter;
Counters.Counter private _tokenIds;
Counters.Counter private _itemsSold;
uint256 listingPrice = 0.025 ether;
address payable owner;
mapping(uint256 => MarketItem) private idToMarketItem;
struct MarketItem {
uint256 tokenId;
address payable seller;
address payable owner;
uint256 price;
bool sold;
}
event MarketItemCreated (
uint256 indexed tokenId,
address seller,
address owner,
uint256 price,
bool sold
);
constructor() ERC721("Metaverse Tokens", "METT") {
owner = payable(msg.sender);
}
/* Updates the listing price of the contract */
function updateListingPrice(uint _listingPrice) public payable {
require(owner == msg.sender, "Only marketplace owner can update listing price.");
listingPrice = _listingPrice;
}
/* Returns the listing price of the contract */
function getListingPrice() public view returns (uint256) {
return listingPrice;
}
/* Mints a token and lists it in the marketplace */
function createToken(string memory tokenURI, uint256 price) public payable returns (uint) {
_tokenIds.increment();
uint256 newTokenId = _tokenIds.current();
_mint(msg.sender, newTokenId);
_setTokenURI(newTokenId, tokenURI);
createMarketItem(newTokenId, price);
return newTokenId;
}
function createMarketItem(
uint256 tokenId,
uint256 price
) private {
require(price > 0, "Price must be at least 1 wei");
require(msg.value == listingPrice, "Price must be equal to listing price");
idToMarketItem[tokenId] = MarketItem(
tokenId,
payable(msg.sender),
payable(address(this)),
price,
false
);
_transfer(msg.sender, address(this), tokenId);
emit MarketItemCreated(
tokenId,
msg.sender,
address(this),
price,
false
);
}
/* allows someone to resell a token they have purchased */
function resellToken(uint256 tokenId, uint256 price) public payable {
require(idToMarketItem[tokenId].owner == msg.sender, "Only item owner can perform this operation");
require(msg.value == listingPrice, "Price must be equal to listing price");
idToMarketItem[tokenId].sold = false;
idToMarketItem[tokenId].price = price;
idToMarketItem[tokenId].seller = payable(msg.sender);
idToMarketItem[tokenId].owner = payable(address(this));
_itemsSold.decrement();
_transfer(msg.sender, address(this), tokenId);
}
/* Creates the sale of a marketplace item */
/* Transfers ownership of the item, as well as funds between parties */
function createMarketSale(
uint256 tokenId
) public payable {
uint price = idToMarketItem[tokenId].price;
address seller = idToMarketItem[tokenId].seller;
require(msg.value == price, "Please submit the asking price in order to complete the purchase");
idToMarketItem[tokenId].owner = payable(msg.sender);
idToMarketItem[tokenId].sold = true;
idToMarketItem[tokenId].seller = payable(address(0));
_itemsSold.increment();
_transfer(address(this), msg.sender, tokenId);
payable(owner).transfer(listingPrice);
payable(seller).transfer(msg.value);
}
/* Returns all unsold market items */
function fetchMarketItems() public view returns (MarketItem[] memory) {
uint itemCount = _tokenIds.current();
uint unsoldItemCount = _tokenIds.current() - _itemsSold.current();
uint currentIndex = 0;
MarketItem[] memory items = new MarketItem[](unsoldItemCount);
for (uint i = 0; i < itemCount; i++) {
if (idToMarketItem[i + 1].owner == address(this)) {
uint currentId = i + 1;
MarketItem storage currentItem = idToMarketItem[currentId];
items[currentIndex] = currentItem;
currentIndex += 1;
}
}
return items;
}
/* Returns only items that a user has purchased */
function fetchMyNFTs() public view returns (MarketItem[] memory) {
uint totalItemCount = _tokenIds.current();
uint itemCount = 0;
uint currentIndex = 0;
for (uint i = 0; i < totalItemCount; i++) {
if (idToMarketItem[i + 1].owner == msg.sender) {
itemCount += 1;
}
}
MarketItem[] memory items = new MarketItem[](itemCount);
for (uint i = 0; i < totalItemCount; i++) {
if (idToMarketItem[i + 1].owner == msg.sender) {
uint currentId = i + 1;
MarketItem storage currentItem = idToMarketItem[currentId];
items[currentIndex] = currentItem;
currentIndex += 1;
}
}
return items;
}
/* Returns only items a user has listed */
function fetchItemsListed() public view returns (MarketItem[] memory) {
uint totalItemCount = _tokenIds.current();
uint itemCount = 0;
uint currentIndex = 0;
for (uint i = 0; i < totalItemCount; i++) {
if (idToMarketItem[i + 1].seller == msg.sender) {
itemCount += 1;
}
}
MarketItem[] memory items = new MarketItem[](itemCount);
for (uint i = 0; i < totalItemCount; i++) {
if (idToMarketItem[i + 1].seller == msg.sender) {
uint currentId = i + 1;
MarketItem storage currentItem = idToMarketItem[currentId];
items[currentIndex] = currentItem;
currentIndex += 1;
}
}
return items;
}
}
here is the code for my create-nft.js:
import { useState } from "react";
import { ethers } from "ethers";
import { create as ipfsHttpClient } from "ipfs-http-client";
import { useRouter } from "next/router";
import Web3Modal from "web3modal";
const client = ipfsHttpClient("https://ipfs.infura.io:5001/api/v0");
import { marketplaceAddress, nft } from "../config";
import NFT from "../artifacts/contracts/NFT.sol/NFT.json";
import NFTMarketplace from "../artifacts/contracts/NFTMarketplace.sol/NFTMarketplace.json";
export default function CreateItem() {
const [fileUrl, setFileUrl] = useState(null);
const [formInput, updateFormInput] = useState({
price: "",
name: "",
description: "",
});
const router = useRouter();
async function onChange(e) {
const file = e.target.files[0];
try {
const added = await client.add(file, {
progress: (prog) => console.log(`received: ${prog}`),
});
const url = `https://ipfs.infura.io/ipfs/${added.path}`;
setFileUrl(url);
} catch (error) {
console.log("Error uploading file: ", error);
}
}
async function uploadToIPFS() {
const { name, description, price } = formInput;
if (!name || !description || !price || !fileUrl) return;
/* first, upload to IPFS */
const data = JSON.stringify({
name,
description,
image: fileUrl,
});
try {
const added = await client.add(data);
const url = `https://ipfs.infura.io/ipfs/${added.path}`;
/* after file is uploaded to IPFS, return the URL to use it in the transaction */
return url;
} catch (error) {
console.log("Error uploading file: ", error);
}
}
async function listNFTForSale() {
const url = await uploadToIPFS();
const web3Modal = new Web3Modal();
const connection = await web3Modal.connect();
const provider = new ethers.providers.Web3Provider(connection);
const signer = provider.getSigner();
/* next, create the item */
const price = ethers.utils.parseUnits(formInput.price, 'ether')
let contract = new ethers.Contract(marketplaceAddress, NFTMarketplace.abi, signer)
let listingPrice = await contract.getListingPrice()
listingPrice = listingPrice.toString()
let transaction = await contract.createToken(url, price, { value: listingPrice })
await transaction.wait()
await transaction.wait();
router.push("/");
}
return (
<div className="flex justify-center">
<div className="w-1/2 flex flex-col pb-12">
<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 Eth"
className="mt-2 border rounded p-4"
onChange={(e) =>
updateFormInput({ ...formInput, price: e.target.value })
}
/>
<input type="file" name="Asset" className="my-4" onChange={onChange} />
{fileUrl && <img className="rounded mt-4" width="350" src={fileUrl} />}
<button onClick={listNFTForSale} className="Create-nft-button">
Create NFT
</button>
</div>
</div>
);
}
I am not really aware of where I am going wrong so I can use your help to understand.