Hi, I am a Newbie in blockchain programming and must say thanks to your team for the excellent videos and tutorials you help us with. Now I have created and successfully created my NFT contract and deployed it. I also hosted it live on an externat server nft.turbotron.app. Now I can see items i mint in my items list and a contract interaction when i try to put it on sale too but i dont see the nft on my marketplace. below are photos showing this.
I have followed all the problems and solutions listed here and non works
I have deployed using truffle-ganache, ethereum testnet and now here and wverything works till now.
this is my ABI.js
var tokenContractAbi = [
{
“inputs”: [],
“stateMutability”: “nonpayable”,
“type”: “constructor”
},
{
“anonymous”: false,
“inputs”: [
{
“indexed”: true,
“internalType”: “address”,
“name”: “owner”,
“type”: “address”
},
{
“indexed”: true,
“internalType”: “address”,
“name”: “approved”,
“type”: “address”
},
{
“indexed”: true,
“internalType”: “uint256”,
“name”: “tokenId”,
“type”: “uint256”
}
],
“name”: “Approval”,
“type”: “event”
},
{
“anonymous”: false,
“inputs”: [
{
“indexed”: true,
“internalType”: “address”,
“name”: “owner”,
“type”: “address”
},
{
“indexed”: true,
“internalType”: “address”,
“name”: “operator”,
“type”: “address”
},
{
“indexed”: false,
“internalType”: “bool”,
“name”: “approved”,
“type”: “bool”
}
],
“name”: “ApprovalForAll”,
“type”: “event”
},
{
“anonymous”: false,
“inputs”: [
{
“indexed”: true,
“internalType”: “address”,
“name”: “from”,
“type”: “address”
},
{
“indexed”: true,
“internalType”: “address”,
“name”: “to”,
“type”: “address”
},
{
“indexed”: true,
“internalType”: “uint256”,
“name”: “tokenId”,
“type”: “uint256”
}
],
“name”: “Transfer”,
“type”: “event”
},
{
“inputs”: [
{
“internalType”: “uint256”,
“name”: “”,
“type”: “uint256”
}
],
“name”: “Items”,
“outputs”: [
{
“internalType”: “uint256”,
“name”: “id”,
“type”: “uint256”
},
{
“internalType”: “address”,
“name”: “creator”,
“type”: “address”
},
{
“internalType”: “string”,
“name”: “uri”,
“type”: “string”
}
],
“stateMutability”: “view”,
“type”: “function”
},
{
“inputs”: [
{
“internalType”: “address”,
“name”: “to”,
“type”: “address”
},
{
“internalType”: “uint256”,
“name”: “tokenId”,
“type”: “uint256”
}
],
“name”: “approve”,
“outputs”: [],
“stateMutability”: “nonpayable”,
“type”: “function”
},
{
“inputs”: [
{
“internalType”: “address”,
“name”: “owner”,
“type”: “address”
}
],
“name”: “balanceOf”,
“outputs”: [
{
“internalType”: “uint256”,
“name”: “”,
“type”: “uint256”
}
],
“stateMutability”: “view”,
“type”: “function”
},
{
“inputs”: [
{
“internalType”: “string”,
“name”: “uri”,
“type”: “string”
}
],
“name”: “createItem”,
“outputs”: [
{
“internalType”: “uint256”,
“name”: “”,
“type”: “uint256”
}
],
“stateMutability”: “nonpayable”,
“type”: “function”
},
{
“inputs”: [
{
“internalType”: “uint256”,
“name”: “tokenId”,
“type”: “uint256”
}
],
“name”: “getApproved”,
“outputs”: [
{
“internalType”: “address”,
“name”: “”,
“type”: “address”
}
],
“stateMutability”: “view”,
“type”: “function”
},
{
“inputs”: [
{
“internalType”: “address”,
“name”: “owner”,
“type”: “address”
},
{
“internalType”: “address”,
“name”: “operator”,
“type”: “address”
}
],
“name”: “isApprovedForAll”,
“outputs”: [
{
“internalType”: “bool”,
“name”: “”,
“type”: “bool”
}
],
“stateMutability”: “view”,
“type”: “function”
},
{
“inputs”: [],
“name”: “name”,
“outputs”: [
{
“internalType”: “string”,
“name”: “”,
“type”: “string”
}
],
“stateMutability”: “view”,
“type”: “function”
},
{
“inputs”: [
{
“internalType”: “uint256”,
“name”: “tokenId”,
“type”: “uint256”
}
],
“name”: “ownerOf”,
“outputs”: [
{
“internalType”: “address”,
“name”: “”,
“type”: “address”
}
],
“stateMutability”: “view”,
“type”: “function”
},
{
“inputs”: [
{
“internalType”: “address”,
“name”: “from”,
“type”: “address”
},
{
“internalType”: “address”,
“name”: “to”,
“type”: “address”
},
{
“internalType”: “uint256”,
“name”: “tokenId”,
“type”: “uint256”
}
],
“name”: “safeTransferFrom”,
“outputs”: [],
“stateMutability”: “nonpayable”,
“type”: “function”
},
{
“inputs”: [
{
“internalType”: “address”,
“name”: “from”,
“type”: “address”
},
{
“internalType”: “address”,
“name”: “to”,
“type”: “address”
},
{
“internalType”: “uint256”,
“name”: “tokenId”,
“type”: “uint256”
},
{
“internalType”: “bytes”,
“name”: “_data”,
“type”: “bytes”
}
],
“name”: “safeTransferFrom”,
“outputs”: [],
“stateMutability”: “nonpayable”,
“type”: “function”
},
{
“inputs”: [
{
“internalType”: “address”,
“name”: “operator”,
“type”: “address”
},
{
“internalType”: “bool”,
“name”: “approved”,
“type”: “bool”
}
],
“name”: “setApprovalForAll”,
“outputs”: [],
“stateMutability”: “nonpayable”,
“type”: “function”
},
{
“inputs”: [
{
“internalType”: “bytes4”,
“name”: “interfaceId”,
“type”: “bytes4”
}
],
“name”: “supportsInterface”,
“outputs”: [
{
“internalType”: “bool”,
“name”: “”,
“type”: “bool”
}
],
“stateMutability”: “view”,
“type”: “function”
},
{
“inputs”: [],
“name”: “symbol”,
“outputs”: [
{
“internalType”: “string”,
“name”: “”,
“type”: “string”
}
],
“stateMutability”: “view”,
“type”: “function”
},
{
“inputs”: [
{
“internalType”: “uint256”,
“name”: “tokenId”,
“type”: “uint256”
}
],
“name”: “tokenURI”,
“outputs”: [
{
“internalType”: “string”,
“name”: “”,
“type”: “string”
}
],
“stateMutability”: “view”,
“type”: “function”
},
{
“inputs”: [
{
“internalType”: “address”,
“name”: “from”,
“type”: “address”
},
{
“internalType”: “address”,
“name”: “to”,
“type”: “address”
},
{
“internalType”: “uint256”,
“name”: “tokenId”,
“type”: “uint256”
}
],
“name”: “transferFrom”,
“outputs”: [],
“stateMutability”: “nonpayable”,
“type”: “function”
}
];
var marketplaceContractAbi = [
{
“anonymous”: false,
“inputs”: [
{
“indexed”: false,
“internalType”: “uint256”,
“name”: “id”,
“type”: “uint256”
},
{
“indexed”: false,
“internalType”: “uint256”,
“name”: “tokenId”,
“type”: “uint256”
},
{
“indexed”: false,
“internalType”: “address”,
“name”: “tokenAddress”,
“type”: “address”
},
{
“indexed”: false,
“internalType”: “uint256”,
“name”: “askingPrice”,
“type”: “uint256”
}
],
“name”: “itemAdded”,
“type”: “event”
},
{
“anonymous”: false,
“inputs”: [
{
“indexed”: false,
“internalType”: “uint256”,
“name”: “id”,
“type”: “uint256”
},
{
“indexed”: false,
“internalType”: “address”,
“name”: “buyer”,
“type”: “address”
},
{
“indexed”: false,
“internalType”: “uint256”,
“name”: “askingPrice”,
“type”: “uint256”
}
],
“name”: “itemSold”,
“type”: “event”
},
{
“inputs”: [
{
“internalType”: “uint256”,
“name”: “tokenId”,
“type”: “uint256”
},
{
“internalType”: “address”,
“name”: “tokenAddress”,
“type”: “address”
},
{
“internalType”: “uint256”,
“name”: “askingPrice”,
“type”: “uint256”
}
],
“name”: “addItemToMarket”,
“outputs”: [
{
“internalType”: “uint256”,
“name”: “”,
“type”: “uint256”
}
],
“stateMutability”: “nonpayable”,
“type”: “function”
},
{
“inputs”: [
{
“internalType”: “uint256”,
“name”: “id”,
“type”: “uint256”
}
],
“name”: “buyItem”,
“outputs”: [],
“stateMutability”: “payable”,
“type”: “function”
},
{
“inputs”: [
{
“internalType”: “uint256”,
“name”: “”,
“type”: “uint256”
}
],
“name”: “itemsForSale”,
“outputs”: [
{
“internalType”: “uint256”,
“name”: “id”,
“type”: “uint256”
},
{
“internalType”: “address”,
“name”: “tokenAddress”,
“type”: “address”
},
{
“internalType”: “uint256”,
“name”: “tokenId”,
“type”: “uint256”
},
{
“internalType”: “address payable”,
“name”: “seller”,
“type”: “address”
},
{
“internalType”: “uint256”,
“name”: “askingPrice”,
“type”: “uint256”
},
{
“internalType”: “bool”,
“name”: “isSold”,
“type”: “bool”
}
],
“stateMutability”: “view”,
“type”: “function”
}
];
Here is my main.js
Moralis.initialize(“TParlQx00gYs7m2y6VhdtxvKD8FJksZeB0P7ChWN”);
Moralis.serverURL = ‘https://jqiu1xjbkzl9.bigmoralis.com:2053/server’
const TOKEN_CONTRACT_ADDRESS = “0x33460223496f1f57e8f4009f343b349967b9352f”;
const MARKETPLACE_CONTRACT_ADDRESS = “0x71827cf0fd499dd5bfe0993937d4384441f6f346”;
init = async () => {
hideElement(userItemsSection);
window.web3 = await Moralis.Web3.enable();
window.tokenContract = new web3.eth.Contract(tokenContractAbi, TOKEN_CONTRACT_ADDRESS);
window.marketplaceContract = new web3.eth.Contract(marketplaceContractAbi, MARKETPLACE_CONTRACT_ADDRESS);
initUser();
loadItems();
const soldItemsQuery = new Moralis.Query('SoldItems');
const soldItemsSubscription = await soldItemsQuery.subscribe();
soldItemsSubscription.on("create", onItemSold);
const itemsAddedQuery = new Moralis.Query('ItemsForSale');
const itemsAddedSubscription = await itemsAddedQuery.subscribe();
itemsAddedSubscription.on("create", onItemAdded);
}
onItemSold = async (item) => {
const listing = document.getElementById(item-${item.attributes.uid}
);
if (listing){
listing.parentNode.removeChild(listing);
}
user = await Moralis.User.current();
if (user){
const params = {uid: `${item.attributes.uid}`};
const soldItem = await Moralis.Cloud.run('getItem', params);
if (soldItem){
if (user.get('accounts').includes(item.attributes.buyer)){
getAndRenderItemData(soldItem, renderUserItem);
}
const userItemListing = document.getElementById(`user-item-${item.tokenObjectId}`);
if (userItemListing) userItemListing.parentNode.removeChild(userItemListing);
}
}
}
onItemAdded = async (item) => {
const params = {uid: ${item.attributes.uid}
};
const addedItem = await Moralis.Cloud.run(‘getItem’, params);
if (addedItem){
user = await Moralis.User.current();
if (user){
if (user.get(‘accounts’).includes(addedItem.ownerOf)){
const userItemListing = document.getElementById(user-item-${item.tokenObjectId}
);
if (userItemListing) userItemListing.parentNode.removeChild(userItemListing);
getAndRenderItemData(addedItem, renderUserItem);
return;
}
}
getAndRenderItemData(addedItem, renderItem);
}
}
initUser = async () => {
if (await Moralis.User.current()){
hideElement(userConnectButton);
showElement(userProfileButton);
showElement(openCreateItemButton);
showElement(openUserItemsButton);
loadUserItems();
}else{
showElement(userConnectButton);
hideElement(userProfileButton);
hideElement(openCreateItemButton);
hideElement(openUserItemsButton);
}
}
login = async () => {
try {
await Moralis.Web3.authenticate();
initUser();
} catch (error) {
alert(error)
}
}
logout = async () => {
await Moralis.User.logOut();
hideElement(userInfo);
initUser();
}
openUserInfo = async () => {
user = await Moralis.User.current();
if (user){
const email = user.get(‘email’);
if(email){
userEmailField.value = email;
}else{
userEmailField.value = “”;
}
userUsernameField.value = user.get('username');
const userAvatar = user.get('avatar');
if(userAvatar){
userAvatarImg.src = userAvatar.url();
showElement(userAvatarImg);
}else{
hideElement(userAvatarImg);
}
$('#userInfo').modal('show');
}else{
login();
}
}
saveUserInfo = async () => {
user.set(‘email’, userEmailField.value);
user.set(‘username’, userUsernameField.value);
if (userAvatarFile.files.length > 0) {
const avatar = new Moralis.File("avatar1.jpg", userAvatarFile.files[0]);
user.set('avatar', avatar);
}
await user.save();
alert("User info saved successfully!");
openUserInfo();
}
createItem = async () => {
if (createItemFile.files.length == 0){
alert("Please select a file!");
return;
} else if (createItemNameField.value.length == 0){
alert("Please give the item a name!");
return;
}
const nftFile = new Moralis.File("nftFile.jpg",createItemFile.files[0]);
await nftFile.saveIPFS();
const nftFilePath = nftFile.ipfs();
const metadata = {
name: createItemNameField.value,
description: createItemDescriptionField.value,
image: nftFilePath,
};
const nftFileMetadataFile = new Moralis.File("metadata.json", {base64 : btoa(JSON.stringify(metadata))});
await nftFileMetadataFile.saveIPFS();
const nftFileMetadataFilePath = nftFileMetadataFile.ipfs();
const nftId = await mintNft(nftFileMetadataFilePath);
user = await Moralis.User.current();
const userAddress = user.get('ethAddress');
switch(createItemStatusField.value){
case "0":
return;
case "1":
await ensureMarketplaceIsApproved(nftId, TOKEN_CONTRACT_ADDRESS);
await marketplaceContract.methods.addItemToMarket(nftId, TOKEN_CONTRACT_ADDRESS, web3.utils.toWei(createItemPriceField.value, "ether")).send({from: userAddress }); break;
case "2":
alert("Not yet supported!");
return;
}
}
mintNft = async (metadataUrl) => {
const receipt = await tokenContract.methods.createItem(metadataUrl).send({from: ethereum.selectedAddress});
console.log(receipt);
return receipt.events.Transfer.returnValues.tokenId;
}
openUserItems = async () => {
user = await Moralis.User.current();
if (user){
$(’#userItems’).modal(‘show’);
}else{
login();
}
}
loadUserItems = async () => {
const ownedItems = await Moralis.Cloud.run(“getUserItems”);
ownedItems.forEach(item => {
const userItemListing = document.getElementById(user-item-${item.tokenObjectId}
);
if (userItemListing) return;
getAndRenderItemData(item, renderUserItem);
});
}
loadItems = async () => {
const items = await Moralis.Cloud.run(“getItems”);
user = await Moralis.User.current();
items.forEach(item => {
if (user){
if (user.attributes.accounts.includes(item.ownerOf)){
const userItemListing = document.getElementById(user-item-${item.tokenObjectId}
);
if (userItemListing) userItemListing.parentNode.removeChild(userItemListing);
getAndRenderItemData(item, renderUserItem);
return;
}
}
getAndRenderItemData(item, renderItem);
});
}
initTemplate = (id) => {
const template = document.getElementById(id);
template.id = “”;
template.parentNode.removeChild(template);
return template;
}
renderUserItem = async (item) => {
const userItemListing = document.getElementById(user-item-${item.tokenObjectId}
);
if (userItemListing) return;
const userItem = userItemTemplate.cloneNode(true);
userItem.getElementsByTagName("img")[0].src = item.image;
userItem.getElementsByTagName("img")[0].alt = item.name;
userItem.getElementsByTagName("h5")[0].innerText = item.name;
userItem.getElementsByTagName("p")[0].innerText = item.description;
userItem.getElementsByTagName("input")[0].value = item.askingPrice ?? 1;
userItem.getElementsByTagName("input")[0].disabled = item.askingPrice > 0;
userItem.getElementsByTagName("button")[0].disabled = item.askingPrice > 0;
userItem.getElementsByTagName("button")[0].onclick = async () => {
user = await Moralis.User.current();
if (!user){
login();
return;
}
await ensureMarketplaceIsApproved(item.tokenId, item.tokenAddress);
await marketplaceContract.methods.addItemToMarket(item.tokenId, item.tokenAddress, userItem.getElementsByTagName("input")[0].value).send({from: user.get('ethAddress') });
};
userItem.id = `user-item-${item.tokenObjectId}`
userItems.appendChild(userItem);
}
renderItem = (item) => {
const itemForSale = marketplaceItemTemplate.cloneNode(true);
if (item.sellerAvatar){
itemForSale.getElementsByTagName(“img”)[0].src = item.sellerAvatar.url();
itemForSale.getElementsByTagName(“img”)[0].alt = item.sellerUsername;
}
itemForSale.getElementsByTagName("img")[1].src = item.image;
itemForSale.getElementsByTagName("img")[1].alt = item.name;
itemForSale.getElementsByTagName("h5")[0].innerText = item.name;
itemForSale.getElementsByTagName("p")[0].innerText = item.description;
itemForSale.getElementsByTagName("button")[0].innerText = `Buy for ${item.askingPrice}`;
itemForSale.getElementsByTagName("button")[0].onclick = () => buyItem(item);
itemForSale.id = `item-${item.uid}`;
itemsForSale.appendChild(itemForSale);
}
getAndRenderItemData = (item, renderFunction) => {
fetch(item.tokenUri)
.then(response => response.json())
.then(data => {
item.name = data.name;
item.description = data.description;
item.image = data.image;
renderFunction(item);
})
}
ensureMarketplaceIsApproved = async (tokenId, tokenAddress) => {
user = await Moralis.User.current();
const userAddress = user.get(‘ethAddress’);
const contract = new web3.eth.Contract(tokenContractAbi, tokenAddress);
const approvedAddress = await contract.methods.getApproved(tokenId).call({from: userAddress});
if (approvedAddress != MARKETPLACE_CONTRACT_ADDRESS){
await contract.methods.approve(MARKETPLACE_CONTRACT_ADDRESS,tokenId).send({from: userAddress});
}
}
buyItem = async (item) => {
user = await Moralis.User.current();
if (!user){
login();
return;
}
await marketplaceContract.methods.buyItem(item.uid).send({from: user.get(‘ethAddress’), value: item.askingPrice});
}
hideElement = (element) => element.style.display = “none”;
showElement = (element) => element.style.display = “block”;
// Navbar
const userConnectButton = document.getElementById(“btnConnect”);
userConnectButton.onclick = login;
const userProfileButton = document.getElementById(“btnUserInfo”);
userProfileButton.onclick = openUserInfo;
const openCreateItemButton = document.getElementById(“btnOpenCreateItem”);
openCreateItemButton.onclick = () => $(’#createItem’).modal(‘show’);
// User profile
const userInfo = document.getElementById(“userInfo”);
const userUsernameField = document.getElementById(“txtUsername”);
const userEmailField = document.getElementById(“txtEmail”);
const userAvatarImg = document.getElementById(“imgAvatar”);
const userAvatarFile = document.getElementById(“fileAvatar”);
document.getElementById(“btnCloseUserInfo”).onclick = () => hideElement(userInfo);
document.getElementById(“btnLogout”).onclick = logout;
document.getElementById(“btnSaveUserInfo”).onclick = saveUserInfo;
// Item creation
const createItemForm = document.getElementById(“createItem”);
const createItemNameField = document.getElementById(“txtCreateItemName”);
const createItemDescriptionField = document.getElementById(“txtCreateItemDescription”);
const createItemPriceField = document.getElementById(“numCreateItemPrice”);
const createItemStatusField = document.getElementById(“selectCreateItemStatus”);
const createItemFile = document.getElementById(“fileCreateItemFile”);
document.getElementById(“btnCloseCreateItem”).onclick = () => hideElement(createItemForm);
document.getElementById(“btnCreateItem”).onclick = createItem;
// User items
const userItemsSection = document.getElementById(“userItems”);
const userItems = document.getElementById(“userItemsList”);
document.getElementById(“btnCloseUserItems”).onclick = () => hideElement(userItemsSection);
const openUserItemsButton = document.getElementById(“btnMyItems”);
openUserItemsButton.onclick = openUserItems;
const userItemTemplate = initTemplate(“itemTemplate”);
const marketplaceItemTemplate = initTemplate(“marketplaceItemTemplate”);
// Items for sale
const itemsForSale = document.getElementById(“itemsForSale”);
init();
And index.html
TurbotronNFT<nav class="navbar navbar-expand-lg navbar-dark bg-transparent border-bottom border-light">
<a class="navbar-brand btn btn-outline-moralis" href="#">TurbotronNFT</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<form class="mx-2 d-inline flex-md-fill">
<input type="search" class="bg-transparent border-light form-control text-light mr-sm-2 rounded-pill" placeholder="Search by item or creator">
</form>
<ul class="navbar-nav mr-auto">
<li class="nav-item">
<a class="nav-link" id="btnMyItems" href="#">My items</a>
</li>
</ul>
<div class="d-flex">
<button class="btn btn-primary rounded-pill my-2 my-sm-0 mr-md-2" id="btnOpenCreateItem">Create</button>
<button class="btn btn-outline-moralis rounded-pill my-2 my-sm-0 " id="btnConnect">Connect wallet</button>
<button class="btn btn-outline-moralis rounded-pill my-2 my-sm-0" id="btnUserInfo">Profile</button>
</div>
</div>
</nav>
<div class="container">
<div class="row row-cols-1 row-cols-md-4 mt-5" id="itemsForSale">
</div>
</div>
<div class="col mb-4" id="marketplaceItemTemplate">
<div class="card h-100 border-light bg-transparent text-light">
<nav class="card-header navbar navbar-dark text-light p-1">
<img width="30" height="30" class="d-inline-block align-top rounded-circle" src="" alt="">
<span></span>
</nav>
<img src="..." class="card-img-top" alt="...">
<div class="card-body d-flex align-items-end">
<div class="w-100">
<h5 class="card-title"></h5>
<p class="card-text"></p>
<button class="btn btn-primary btn-block"></button>
</div>
</div>
</div>
</div>
<div class="col mb-4" id="itemTemplate">
<div class="card h-100 border-light bg-transparent text-light">
<img src="..." class="card-img-top" alt="...">
<div class="card-body d-flex align-items-end">
<div class="w-100">
<h5 class="card-title"></h5>
<p class="card-text"></p>
<div class="input-group mb-3">
<input type="number" min="1" step="1" class="form-control" placeholder="Price">
<div class="input-group-append">
<button class="btn btn-outline-secondary" type="button">Put for sale</button>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Modal -->
<div class="modal fade" id="userInfo" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content bg-dark text-light">
<div class="modal-header">
<h5 class="modal-title" >User Profile</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<div class="form-group">
<label for="txtUsername">Username</label>
<input type="text" class="form-control" id="txtUsername" required placeholder="Enter username">
</div>
<div class="form-group">
<label for="txtEmail">Email address</label>
<input type="email" class="form-control" id="txtEmail" aria-describedby="emailHelp" placeholder="Enter email">
<small id="emailHelp" class="form-text text-muted">Optional</small>
</div>
<img width="50" height="50" src="" id="imgAvatar" alt="">
<div class="form-group">
<label for="fileAvatar">Select Avatar</label>
<input type="file" class="form-control-file" id="fileAvatar">
</div>
</div>
<div class="modal-footer">
<button type="button" id="btnLogout" class="btn btn-secondary" data-dismiss="modal">Log out</button>
<button type="button" id="btnCloseUserInfo" class="btn btn-secondary" data-dismiss="modal">Close</button>
<button type="button" id="btnSaveUserInfo" class="btn btn-primary">Save</button>
</div>
</div>
</div>
</div>
<!-- Modal -->
<div class="modal fade" id="createItem" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content bg-dark text-light">
<div class="modal-header">
<h5 class="modal-title" >Create Item</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<div class="form-group">
<label for="txtUsername">Name</label>
<input type="text" class="form-control" id="txtCreateItemName" required placeholder="Enter name">
</div>
<div class="form-group">
<label for="txtCreateItemDescription">Description</label>
<textarea class="form-control" id="txtCreateItemDescription" cols="30" rows="5" placeholder="Enter description"></textarea>
</div>
<div class="form-group">
<label for="txtUsername">Price</label>
<input type="number" min="1" step="1" id="numCreateItemPrice" placeholder="Enter price" required class="form-control">
</div>
<div class="form-group">
<label for="selectCreateItemStatus">Status</label>
<select class="form-control" id="selectCreateItemStatus">
<option value="0">Not for sale</option>
<option value="1">Instant buy</option>
<option value="2">Accept Offers</option>
</select>
</div>
<div class="form-group">
<label for="fileCreateItemFile">Select file</label>
<input type="file" class="form-control-file" id="fileCreateItemFile">
</div>
</div>
<div class="modal-footer">
<button type="button" id="btnCloseCreateItem" class="btn btn-secondary" data-dismiss="modal">Close</button>
<button type="button" id="btnCreateItem" class="btn btn-primary">Create!</button>
</div>
</div>
</div>
</div>
<!-- Modal -->
<div class="modal fade" id="userItems" tabindex="-1">
<div class="modal-dialog modal-xl">
<div class="modal-content bg-dark text-light">
<div class="modal-header">
<h5 class="modal-title" >My Items</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body row row-cols-1 row-cols-md-4 mt-5" id="userItemsList">
</div>
<div class="modal-footer">
<button type="button" id="btnCloseUserItems" class="btn btn-secondary" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-Piv4xVNRyMGpqkS2by6br4gNJ7DXjqk09RmUpJ8jgGtD7zP9yug3goQfGII0yAns" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/web3@latest/dist/web3.min.js"></script>
<script src="https://unpkg.com/moralis/dist/moralis.js"></script>
<script src="abi.js"></script>
<script src="main.js"></script>
Project can be viewed and interacted with here nft.turbotron.app