Okay, Iām having some trouble again.
Iāve successfully deployed the marketplace contract to Mumbai testnet and was able to interact with it as I wanted.
However, now when I deployed the same contract to Ethereum mainnet I have some issues.
The NFT balance is successfully shown but once I list the NFTās for sale it does not show the transactions under the transactions tab nor does the explore page update the NFT to the green āBuy nowā display.
I had the exact same problem earlier but fixed it by changing:
const queryMarketItems = useMoralisQuery(āMarketItemsā);
.
.
.
const marketList = Moralis.Object.extend("MarketItems");
in NFTTokenIds.jsx
and NFTMarketTransactions.jsx
to:
const queryMarketItems = useMoralisQuery(āCreatedMarketItemsā);
.
.
.
const marketList = Moralis.Object.extend("CreatedMarketItems");
This worked like a charm while I used the Mumbai testnet, but now I have a similar issue despite using the same code.
The database class CreatedMarketItems
in my Ethereum mainnet dApp is populated successfully and have the exact same structure as the one I used for Mumbai testnet.
From my understanding there has to be some query which is faulty, but where?
This is my complete NFTTokenIds.jsx
:
import React, { useState, useEffect } from "react";
import { getNativeByChain } from "helpers/networks";
import { getCollectionsByChain } from "helpers/collections";
import {
useMoralis,
useMoralisQuery,
useNewMoralisObject,
} from "react-moralis";
import { Card, Image, Tooltip, Modal, Badge, Alert, Spin } from "antd";
import { useNFTTokenIds } from "hooks/useNFTTokenIds";
import {
FileSearchOutlined,
RightCircleOutlined,
ShoppingCartOutlined,
} from "@ant-design/icons";
import { useMoralisDapp } from "providers/MoralisDappProvider/MoralisDappProvider";
import { getExplorer } from "helpers/networks";
import { useWeb3ExecuteFunction } from "react-moralis";
const { Meta } = Card;
const styles = {
NFTs: {
display: "flex",
flexWrap: "wrap",
WebkitBoxPack: "start",
justifyContent: "flex-start",
margin: "0 auto",
maxWidth: "1000px",
gap: "10px",
},
banner: {
display: "flex",
justifyContent: "space-evenly",
alignItems: "center",
margin: "0 auto",
width: "600px",
//borderRadius: "10px",
height: "150px",
marginBottom: "40px",
paddingBottom: "20px",
borderBottom: "solid 1px #e3e3e3",
},
logo: {
height: "115px",
width: "115px",
borderRadius: "50%",
// positon: "relative",
// marginTop: "-80px",
border: "solid 4px white",
},
text: {
color: "#041836",
fontSize: "27px",
fontWeight: "bold",
},
};
function NFTTokenIds({ inputValue, setInputValue }) {
const fallbackImg =
"data:image/png;base64,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";
const { NFTTokenIds, totalNFTs, fetchSuccess } = useNFTTokenIds(inputValue);
const [visible, setVisibility] = useState(false);
const [nftToBuy, setNftToBuy] = useState(null);
const [loading, setLoading] = useState(false);
const contractProcessor = useWeb3ExecuteFunction();
const { chainId, marketAddress, contractABI, walletAddress } =
useMoralisDapp();
const nativeName = getNativeByChain(chainId);
const contractABIJson = JSON.parse(contractABI);
const { Moralis } = useMoralis();
const queryMarketItems = useMoralisQuery("CreatedMarketItems");
const fetchMarketItems = JSON.parse(
JSON.stringify(queryMarketItems.data, [
"objectId",
"createdAt",
"price",
"nftContract",
"itemId",
"sold",
"tokenId",
"seller",
"owner",
"confirmed",
])
);
const purchaseItemFunction = "createMarketSale";
const NFTCollections = getCollectionsByChain(chainId);
async function purchase() {
setLoading(true);
const tokenDetails = getMarketItem(nftToBuy);
const itemID = tokenDetails.itemId;
const tokenPrice = tokenDetails.price;
const ops = {
contractAddress: marketAddress,
functionName: purchaseItemFunction,
abi: contractABIJson,
params: {
nftContract: nftToBuy.token_address,
itemId: itemID,
},
msgValue: tokenPrice,
};
await contractProcessor.fetch({
params: ops,
onSuccess: () => {
console.log("success");
setLoading(false);
setVisibility(false);
updateSoldMarketItem();
succPurchase();
},
onError: (error) => {
setLoading(false);
failPurchase();
},
});
}
const handleBuyClick = (nft) => {
setNftToBuy(nft);
console.log(nft.image);
setVisibility(true);
};
function succPurchase() {
let secondsToGo = 5;
const modal = Modal.success({
title: "Success!",
content: `You have purchased this NFT`,
});
setTimeout(() => {
modal.destroy();
}, secondsToGo * 1000);
}
function failPurchase() {
let secondsToGo = 5;
const modal = Modal.error({
title: "Error!",
content: `There was a problem when purchasing this NFT`,
});
setTimeout(() => {
modal.destroy();
}, secondsToGo * 1000);
}
async function updateSoldMarketItem() {
const id = getMarketItem(nftToBuy).objectId;
const marketList = Moralis.Object.extend("CreatedMarketItems");
const query = new Moralis.Query(marketList);
await query.get(id).then((obj) => {
obj.set("sold", true);
obj.set("owner", walletAddress);
obj.save();
});
}
const getMarketItem = (nft) => {
const result = fetchMarketItems?.find(
(e) =>
e.nftContract === nft?.token_address &&
e.tokenId === nft?.token_id &&
e.sold === false &&
e.confirmed === true
);
return result;
};
return (
<>
<div>
{contractABIJson.noContractDeployed && (
<>
<Alert
message="No Smart Contract Details Provided. Please deploy smart contract and provide address + ABI in the MoralisDappProvider.js file"
type="error"
/>
<div style={{ marginBottom: "10px" }}></div>
</>
)}
{inputValue !== "explore" && totalNFTs !== undefined && (
<>
{!fetchSuccess && (
<>
<Alert
message="Unable to fetch all NFT metadata... We are searching for a solution, please try again later!"
type="warning"
/>
<div style={{ marginBottom: "10px" }}></div>
</>
)}
<div style={styles.banner}>
<Image
preview={false}
src={NFTTokenIds[0]?.image || "error"}
fallback={fallbackImg}
alt=""
style={styles.logo}
/>
<div style={styles.text}>
<>
<div>{`${NFTTokenIds[0]?.name}`}</div>
<div
style={{
fontSize: "15px",
color: "#9c9c9c",
fontWeight: "normal",
}}
>
Collection Size: {`${totalNFTs}`}
</div>
</>
</div>
</div>
</>
)}
<div style={styles.NFTs}>
{inputValue === "explore" &&
NFTCollections?.map((nft, index) => (
<Card
hoverable
actions={[
<Tooltip title="View Collection">
<RightCircleOutlined
onClick={() => setInputValue(nft?.addrs)}
/>
</Tooltip>,
]}
style={{ width: 240, border: "2px solid #e7eaf3" }}
cover={
<Image
preview={false}
src={nft?.image || "error"}
fallback={fallbackImg}
alt=""
style={{ height: "240px" }}
/>
}
key={index}
>
<Meta title={nft.name} />
</Card>
))}
{inputValue !== "explore" &&
NFTTokenIds.slice(0, 20).map((nft, index) => (
<Card
hoverable
actions={[
<Tooltip title="View On Blockexplorer">
<FileSearchOutlined
onClick={() =>
window.open(
`${getExplorer(chainId)}address/${nft.token_address}`,
"_blank"
)
}
/>
</Tooltip>,
<Tooltip title="Buy NFT">
<ShoppingCartOutlined onClick={() => handleBuyClick(nft)} />
</Tooltip>,
]}
style={{ width: 240, border: "2px solid #e7eaf3" }}
cover={
<Image
preview={false}
src={nft.image || "error"}
fallback={fallbackImg}
alt=""
style={{ height: "240px" }}
/>
}
key={index}
>
{getMarketItem(nft) && (
<Badge.Ribbon text="Buy Now" color="green"></Badge.Ribbon>
)}
<Meta title={nft.name} description={`#${nft.token_id}`} />
</Card>
))}
</div>
{getMarketItem(nftToBuy) ? (
<Modal
title={`Buy ${nftToBuy?.name} #${nftToBuy?.token_id}`}
visible={visible}
onCancel={() => setVisibility(false)}
onOk={() => purchase()}
okText="Buy"
>
<Spin spinning={loading}>
<div
style={{
width: "250px",
margin: "auto",
}}
>
<Badge.Ribbon
color="green"
text={`${
getMarketItem(nftToBuy).price / ("1e" + 18)
} ${nativeName}`}
>
<img
src={nftToBuy?.image}
style={{
width: "250px",
borderRadius: "10px",
marginBottom: "15px",
}}
/>
</Badge.Ribbon>
</div>
</Spin>
</Modal>
) : (
<Modal
title={`Buy ${nftToBuy?.name} #${nftToBuy?.token_id}`}
visible={visible}
onCancel={() => setVisibility(false)}
onOk={() => setVisibility(false)}
>
<img
src={nftToBuy?.image}
style={{
width: "250px",
margin: "auto",
borderRadius: "10px",
marginBottom: "15px",
}}
/>
<Alert
message="This NFT is currently not for sale"
type="warning"
/>
</Modal>
)}
</div>
</>
);
}
export default NFTTokenIds;
and NFTMarketTransactions.jsx
:
import React, { useState } from "react";
import { useMoralis, useMoralisQuery } from "react-moralis";
import { useMoralisDapp } from "providers/MoralisDappProvider/MoralisDappProvider";
import { Table, Tag, Space } from "antd";
import { PolygonCurrency} from "./Chains/Logos";
import moment from "moment";
const styles = {
table: {
margin: "0 auto",
width: "1000px",
},
};
function NFTMarketTransactions() {
const { walletAddress } = useMoralisDapp();
const { Moralis } = useMoralis();
const queryItemImages = useMoralisQuery("ItemImages");
const fetchItemImages = JSON.parse(
JSON.stringify(queryItemImages.data, [
"nftContract",
"tokenId",
"name",
"image",
])
);
const queryMarketItems = useMoralisQuery("CreatedMarketItems");
const fetchMarketItems = JSON.parse(
JSON.stringify(queryMarketItems.data, [
"updatedAt",
"price",
"nftContract",
"itemId",
"sold",
"tokenId",
"seller",
"owner",
])
)
.filter(
(item) => item.seller === walletAddress || item.owner === walletAddress
)
.sort((a, b) =>
a.updatedAt < b.updatedAt ? 1 : b.updatedAt < a.updatedAt ? -1 : 0
);
function getImage(addrs, id) {
const img = fetchItemImages.find(
(element) =>
element.nftContract === addrs &&
element.tokenId === id
);
return img?.image;
}
function getName(addrs, id) {
const nme = fetchItemImages.find(
(element) =>
element.nftContract === addrs &&
element.tokenId === id
);
return nme?.name;
}
const columns = [
{
title: "Date",
dataIndex: "date",
key: "date",
},
{
title: "Item",
key: "item",
render: (text, record) => (
<Space size="middle">
<img src={getImage(record.collection, record.item)} style={{ width: "40px", borderRadius:"4px"}} />
<span>#{record.item}</span>
</Space>
),
},
{
title: "Collection",
key: "collection",
render: (text, record) => (
<Space size="middle">
<span>{getName(record.collection, record.item)}</span>
</Space>
),
},
{
title: "Transaction Status",
key: "tags",
dataIndex: "tags",
render: (tags) => (
<>
{tags.map((tag) => {
let color = "geekblue";
let status = "BUY";
if (tag === false) {
color = "volcano";
status = "waiting";
} else if (tag === true) {
color = "green";
status = "confirmed";
}
if (tag === walletAddress) {
status = "SELL";
}
return (
<Tag color={color} key={tag}>
{status.toUpperCase()}
</Tag>
);
})}
</>
),
},
{
title: "Price",
key: "price",
dataIndex: "price",
render: (e) => (
<Space size="middle">
<PolygonCurrency/>
<span>{e}</span>
</Space>
),
}
];
const data = fetchMarketItems?.map((item, index) => ({
key: index,
date: moment(item.updatedAt).format("DD-MM-YYYY HH:mm"),
collection: item.nftContract,
item: item.tokenId,
tags: [item.seller, item.sold],
price: item.price / ("1e" + 18)
}));
return (
<>
<div>
<div style={styles.table}>
<Table columns={columns} dataSource={data} />
</div>
</div>
</>
);
}
export default NFTMarketTransactions;
const columns = [
{
title: "Date",
dataIndex: "date",
key: "date",
},
{
title: "Item",
key: "item",
},
{
title: "Collection",
key: "collection",
},
{
title: "Transaction Status",
key: "tags",
dataIndex: "tags",
},
{
title: "Price",
key: "price",
dataIndex: "price",
}
];
I canāt find anything different besides that my Ethereum mainnet dApp database is only populated with 4 classes while the Mumbai testnet database was automatically populated with many more classes, i.e:
ItemImages
PolygonBalance
PolygonBalancePending
PolygonNFTOwners
PolygonNFTOwnersPending
PolygonNFTTransfers
PolygonTransactions
I see that ItemImages
is queried in NFTMarketTransactions.jsx
.
This is the only thing I can come up with but donāt know how I should solve it.
Iāve made some minor aesthetic changes like removing the text in the footer.
I also gave the deployed Ethereum mainnet contract another name.
But I donāt see how any of these changes could cause my current error.
Thanks!