Skip to content

Commit

Permalink
completion update
Browse files Browse the repository at this point in the history
  • Loading branch information
svskaushik committed Nov 8, 2021
1 parent b904c2a commit 90ee1db
Show file tree
Hide file tree
Showing 12 changed files with 574 additions and 1 deletion.
2 changes: 2 additions & 0 deletions config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export const nftmarketaddress = "0x28E6D76B75C9A8855Fc5a9842236f2aE62cE8d84"
export const nftaddress = "0xdfF2a93F367caB2D66CED0f1fA5193264d11F834"
27 changes: 27 additions & 0 deletions contracts/NFT.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// contracts/NFT.sol
// 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";

contract NFT is ERC721URIStorage {
using Counters for Counters.Counter;
Counters.Counter private _tokenIds;
address contractAddress;

constructor(address marketplaceAddress) ERC721("Metaverse Tokens", "METT") {
contractAddress = marketplaceAddress;
}

function createToken(string memory tokenURI) public returns (uint) {
_tokenIds.increment();
uint256 newItemId = _tokenIds.current();

_mint(msg.sender, newItemId);
_setTokenURI(newItemId, tokenURI);
setApprovalForAll(contractAddress, true);
return newItemId;
}
}
166 changes: 166 additions & 0 deletions contracts/NFTMarket.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

import "@openzeppelin/contracts/utils/Counters.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";

import "hardhat/console.sol";

contract NFTMarket is ReentrancyGuard {
using Counters for Counters.Counter;
Counters.Counter private _itemIds;
Counters.Counter private _itemsSold;

address payable owner;
uint256 listingPrice = 0.025 ether;

constructor() {
owner = payable(msg.sender);
}
struct MarketItem {
uint itemId;
address nftContract;
uint256 tokenId;
address payable seller;
address payable owner;
uint256 price;
bool sold;
}

mapping(uint256 => MarketItem) private idToMarketItem;

event MarketItemCreated (
uint indexed itemId,
address indexed nftContract,
uint256 indexed tokenId,
address seller,
address owner,
uint256 price,
bool sold
);

/* Returns the listing price of the contract */
function getListingPrice() public view returns (uint256) {
return listingPrice;
}

/* Places an item for sale on the marketplace */
function createMarketItem(
address nftContract,
uint256 tokenId,
uint256 price
) public payable nonReentrant {
require(price > 0, "Price must be at least 1 wei");
require(msg.value == listingPrice, "Price must be equal to listing price");

_itemIds.increment();
uint256 itemId = _itemIds.current();

idToMarketItem[itemId] = MarketItem(
itemId,
nftContract,
tokenId,
payable(msg.sender),
payable(address(0)),
price,
false
);

IERC721(nftContract).transferFrom(msg.sender, address(this), tokenId);

emit MarketItemCreated(
itemId,
nftContract,
tokenId,
msg.sender,
address(0),
price,
false
);
}

/* Creates the sale of a marketplace item */
/* Transfers ownership of the item, as well as funds between parties */
function createMarketSale(
address nftContract,
uint256 itemId
) public payable nonReentrant {
uint price = idToMarketItem[itemId].price;
uint tokenId = idToMarketItem[itemId].tokenId;
require(msg.value == price, "Please submit the asking price in order to complete the purchase");

idToMarketItem[itemId].seller.transfer(msg.value);
IERC721(nftContract).transferFrom(address(this), msg.sender, tokenId);
idToMarketItem[itemId].owner = payable(msg.sender);
idToMarketItem[itemId].sold = true;
_itemsSold.increment();
payable(owner).transfer(listingPrice);
}

/* Returns all unsold market items */
function fetchMarketItems() public view returns (MarketItem[] memory) {
uint itemCount = _itemIds.current();
uint unsoldItemCount = _itemIds.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(0)) {
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 = _itemIds.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 created */
function fetchItemsCreated() public view returns (MarketItem[] memory) {
uint totalItemCount = _itemIds.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;
}
}
18 changes: 18 additions & 0 deletions hardhat.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
require("@nomiclabs/hardhat-waffle");
require('dotenv').config();
const projectId = process.env.ALCHEMY_API_KEY
const privateKey = process.env.KEY


module.exports = {
networks: {
hardhat: {
chainId: 1337,
},
mumbai: {
url: `https://polygon-mumbai.g.alchemy.com/v2/${projectId}`,
accounts: [privateKey]
}
},
solidity: "0.8.4",
};
113 changes: 113 additions & 0 deletions pages/create-item.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
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 {
nftaddress, nftmarketaddress
} from '../config'

import NFT from '../artifacts/contracts/NFT.sol/NFT.json'
import Market from '../artifacts/contracts/NFTMarket.sol/NFTMarket.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 createMarket() {
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, pass the URL to save it on Polygon */
createSale(url)
} catch (error) {
console.log('Error uploading file: ', error)
}
}

async function createSale(url) {
const web3Modal = new Web3Modal()
const connection = await web3Modal.connect()
const provider = new ethers.providers.Web3Provider(connection)
const signer = provider.getSigner()

/* next, create the item */
let contract = new ethers.Contract(nftaddress, NFT.abi, signer)
let transaction = await contract.createToken(url)
let tx = await transaction.wait()
let event = tx.events[0]
let value = event.args[2]
let tokenId = value.toNumber()
const price = ethers.utils.parseUnits(formInput.price, 'ether')

/* then list the item for sale on the marketplace */
contract = new ethers.Contract(nftmarketaddress, Market.abi, signer)
let listingPrice = await contract.getListingPrice()
listingPrice = listingPrice.toString()

transaction = await contract.createMarketItem(nftaddress, tokenId, price, { value: listingPrice })
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={createMarket} className="font-bold mt-4 bg-pink-500 text-white rounded p-4 shadow-lg">
Create Digital Asset
</button>
</div>
</div>
)
}
Loading

0 comments on commit 90ee1db

Please sign in to comment.