Test file:
const {expect} = require("chai");
const {ethers} = require("hardhat");
describe("NFT Marketplace", function () {
let NFTMarket;
let nftMarket;
let listingPrice;
let contractOwner;
let buyerAddress;
let nftMarketAddress
// returns a BigNumber representation of value, parsed with
// digits (if it's a number) or from the unit specified (if it's a string)
const auctionPrice = ethers.utils.parseUnits("100", "ether")
// hooks that perform before each test case
beforeEach(async () => { // get contract that we're targeting, so we can deploy or call the functions in that Contract
NFTMarket = await ethers.getContractFactory("NFTMarketplace");
// create a transaction to deploy the transaction and sends it to the network
// using the contract Signer, and returning a Promise to resolve to a Contract
nftMarket = await NFTMarket.deploy();
// return a Promise which will resolve once the contract is deployed
// or reject if there was an error during deployment
await nftMarket.deployed();
nftMarketAddress = nftMarket.address;
[contractOwner, buyerAddress] = await ethers.getSigners(); // get public address of the user wallet
listingPrice = await nftMarket.getListingPrice();
listingPrice = listingPrice.toString();
})
// mint and list NFT
const mintAndListNFT = async (tokenURI, auctionPrice) => {
const transaction = await nftMarket.createToken(tokenURI, auctionPrice, {value: listingPrice});
const receipt = await transaction.wait();
const tokenId = receipt.events[0].args.tokenId;
return tokenId;
}
describe("Resale of a marketplace item", async () => {
const tokenURI = "https://dummy-token.url/"; // test with a dummy token URI
const newNFTToken = await mintAndListNFT(tokenURI, auctionPrice);
await nftMarket.connect(buyerAddress).createMarketSale(newNFTToken, {value: auctionPrice});
await expect(nftMarket.resellToken(nftMarket, auctionPrice, {value: listingPrice})).to.be.revertedWith("You are not the owner of the token!");
await expect(nftMarket.connect(buyerAddress).resellToken(newNFTToken, auctionPrice, {value: 0})).to.be.rejectedWith("The amount sold does not equal the original listing price of the token!");
})
Contract file:
pragma solidity ^0.8.9;
import "@openzeppelin/contracts/utils/Counters.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
contract NFTMarketplace is ERC721URIStorage {
using Counters for Counters.Counter;
Counters.Counter private _tokenIDs; // total number of items created
Counters.Counter private _itemsSold; // total number of items sold
uint256 listingPrice = 0.001 ether; // price to list NFT on marketplace
address payable owner; // owner of the smart contract
constructor() ERC721("Metaverse Tokens", "META") {
owner == payable(msg.sender);
}
struct MarketItem {
uint256 tokenId;
address payable seller;
address payable owner;
uint256 price;
bool sold;
}
mapping(uint256 => MarketItem) private idToMarketItem;
event MarketItemCreated (uint256 indexed tokenId, address seller, address owner, uint256 price, bool sold);
// return the listing price of the NFT
function getListingPrice() public view returns(uint256) {
return listingPrice;
}
// update the listing price
function updatedListingPrice(uint _listingPrice) public payable{
require(owner == msg.sender, "You are not the owner!");
listingPrice = _listingPrice;
}
// create a NFT in the market
function createMarketItem(uint256 tokenId, uint256 price) private {
require(price > 0, "You must list an item with price more than 0!");
require(msg.value == listingPrice, "The amount of ether sent in the transaction does not equal the listing price!");
// seller is the msg.sender and owner is the address(this)
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, true);
}
// mints a token and list it in the market
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;
}
// creating the sale of a marketplace item
// transfers ownership of the item and funds between parties
function createMarketSale(uint256 tokenId) public payable {
uint price = idToMarketItem[tokenId].price;
address seller = idToMarketItem[tokenId].seller;
require(msg.value == price, "The amount of ethers sent does not equal to the price of the item!");
idToMarketItem[tokenId].owner = payable(msg.sender); // transfer ownership
idToMarketItem[tokenId].seller = payable(address(0));
idToMarketItem[tokenId].sold = true;
_itemsSold.increment();
_transfer(address(this), msg.sender, tokenId);
payable(owner).transfer(listingPrice);
payable(seller).transfer(msg.value);
}
// allows users to resell a token they have purchased
function resellToken(uint256 tokenId, uint256 price) public payable {
require(idToMarketItem[tokenId].owner == msg.sender, "You are not the owner of the token!");
require(msg.value == listingPrice, "The amount sold does not equal the original listing price of the token!");
idToMarketItem[tokenId].sold = false;
idToMarketItem[tokenId].seller = payable(msg.sender); // msg.sender refers to address where the contract is being called from
idToMarketItem[tokenId].owner = payable(address(this)); // address(this) refers to the address of the instance where the call is being made
idToMarketItem[tokenId].price = price;
_itemsSold.decrement();
_transfer(msg.sender, address(this), tokenId);
}
}
What do these lines of code do specifically under the test case for "Resale of a marketplace item"?
- const newNFTToken = await mintAndListNFT(tokenURI, auctionPrice);
- await nftMarket.connect(buyerAddress).createMarketSale(newNFTToken, {value: auctionPrice});
- await expect(nftMarket.resellToken(nftMarket, auctionPrice, {value: listingPrice})).to.be.revertedWith("You are not the owner of the token!");
- await expect(nftMarket.connect(buyerAddress).resellToken(newNFTToken, auctionPrice, {value: 0})).to.be.rejectedWith("The amount sold does not equal the original listing price of the token!");
Any help is appreciated. Thank you.