diff --git a/contracts/BlockMarket.sol b/contracts/BlockMarket.sol new file mode 100644 index 0000000..e3e61be --- /dev/null +++ b/contracts/BlockMarket.sol @@ -0,0 +1,132 @@ +// // SPDX-License-Identifier: SEE LICENSE IN LICENSE +// pragma solidity 0.8.28; + +// import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +// import "@openzeppelin/contracts/token/ERC721/IERC721.sol"; + +// struct Listing{ +// address owner; +// uint256 tokenId; +// IERC20 paymentToken; +// address NftToken; +// bool isNative; +// uint256 price; +// bool sold; +// uint minOffer; +// } + +// struct OfferDetails{ +// uint256 listId; +// uint256 offerAmount; +// address offerrer; +// address paymentToken; +// bool status; +// } + +// contract BlockMarketPlace { + +// mapping (uint256 listid => Listing list) public idToListing; +// mapping (uint256 offerid => OfferDetails offer) public idToOffer; +// uint256 lastUpdatedid; +// address marketOwner; +// function listNft(Listing memory list) external { +// uint listId = lastUpdatedid++; +// require(list.price > 0, "Invalid price"); +// require(list.minOffer > 0, "Invalid min offer"); +// if(list.isNative){ +// require(address(list.paymentToken) == address(0)); +// } +// Listing memory listing; +// listing.owner = msg.sender; +// listing.tokenId = list.tokenId; +// listing.paymentToken = list.paymentToken; +// listing.price = list.price; +// listing.isNative = list.isNative; +// listing.minOffer = list.minOffer; +// listing.NftToken = list.NftToken; +// idToListing[listId] = listing; + + +// IERC721(list.NftToken).transferFrom(msg.sender, address(this), list.tokenId); +// } + +// function buyNft(uint256 listId) external payable { +// Listing memory l = idToListing[listId]; +// require(!l.sold, "ALready Sold"); +// idToListing[listId].sold = true; +// if(l.isNative){ +// require(msg.value == l.price, "Incorrect price"); +// (bool s,) = l.owner.call{value: l.price * 97/100}(""); +// (bool ss,) = marketOwner.call{value: l.price * 3/100}(""); +// require(s, "Owner transfer failed"); +// require(ss, "MarketOwner Transfer failed"); +// }else{ +// l.paymentToken.transferFrom(msg.sender, l.owner, l.price * 97/100); +// l.paymentToken.transferFrom(msg.sender, marketOwner, l.price * 3/100); +// } +// IERC721(l.NftToken).transferFrom(address(this), msg.sender, l.tokenId); +// } + +// function offer(uint256 listid, address paymentToken, uint256 amount) external payable { +// Listing storage l = idToListing[listid]; +// require(!l.sold, "Already sold"); +// require(msg.sender != l.owner, "Owner cannot offer"); + +// uint256 offerAmount; +// if (l.isNative) { +// offerAmount = msg.value; +// require(offerAmount >= l.minOffer, "Offer too low"); +// } else { +// require(paymentToken != address(0), "Invalid token"); +// require(amount >= l.minOffer, "Offer too low"); +// require(IERC20(paymentToken).transferFrom(msg.sender, address(this), amount), "ERC20 transfer failed"); +// offerAmount = amount; +// } + +// uint256 offerid = ++lastUpdatedid; +// idToOffer[offerid] = OfferDetails({ +// listId: listid, +// offerAmount: offerAmount, +// offerrer: msg.sender, +// paymentToken: paymentToken +// }); +// } + +// function acceptOffer(uint256 offerid) external { +// OfferDetails memory offer = idToOffer[offerid]; +// Listing storage l = idToListing[offer.listId]; +// require(msg.sender == l.owner, "Only owner can accept offer"); +// require(!l.sold, "Already sold"); + +// l.sold = true; +// if (l.isNative) { +// (bool success,) = l.owner.call{value: offer.offerAmount}(""); +// require(success, "Transfer to owner failed"); +// } else { +// require(IERC20(offer.paymentToken).transfer(l.owner, offer.offerAmount), "Transfer to owner failed"); +// } +// IERC721(l.NftToken).transferFrom(address(this), offer.offerrer, l.tokenId); +// delete idToOffer[offerid]; +// } + +// function cancelOffer(uint256 offerid) external { +// OfferDetails storage offer = idToOffer[offerid]; +// require(offer.offerrer == msg.sender, "Not offerer"); +// Listing memory l = idToListing[offer.listId]; +// if (l.isNative) { +// (bool s,) = msg.sender.call{value: offer.offerAmount}(""); +// require(s, "Refund failed"); +// } else { +// IERC20(offer.paymentToken).transfer(msg.sender, offer.offerAmount); +// } +// delete idToOffer[offerid]; +// } + +// function cancelListing(uint256 listid) external { +// Listing storage l = idToListing[listid]; +// require(msg.sender == l.owner, "Not owner"); +// require(!l.sold, "Already sold"); +// delete idToListing[listid]; +// IERC721(l.NftToken).transferFrom(address(this), msg.sender, l.tokenId); +// } +// } \ No newline at end of file diff --git a/contracts/BlockMarketPlace.sol b/contracts/BlockMarketPlace.sol new file mode 100644 index 0000000..86e5952 --- /dev/null +++ b/contracts/BlockMarketPlace.sol @@ -0,0 +1,133 @@ +// SPDX-License-Identifier: SEE LICENSE IN LICENSE +pragma solidity 0.8.28; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/token/ERC721/IERC721.sol"; +c + +uint256 public lastUpdatedid; +uint256 public lastOfferId; +address public marketOwner; + + constructor() { + marketOwner = msg.sender; + } + + function listNft(Listing memory list) external { + uint listId = lastUpdatedid++; + require(list.price > 0, "Invalid price"); + require(list.minOffer > 0, "Invalid min offer"); + if(list.isNative){ + require(address(list.paymentToken) == address(0), "ERC20 Payment is not supported"); + } + Listing memory listing; + listing.owner = msg.sender; + listing.tokenId = list.tokenId; + listing.paymentToken = list.paymentToken; + listing.price = list.price; + listing.isNative = list.isNative; + listing.minOffer = list.minOffer; + listing.NftToken = list.NftToken; + idToListing[listId] = listing; + + + IERC721(list.NftToken).transferFrom(msg.sender, address(this), list.tokenId); + } + function getListing(uint256 listId) external view returns(Listing memory){ + return idToListing[listId]; + } + function buyNft(uint256 listId) external payable { + Listing memory l = idToListing[listId]; + require(!l.sold, "ALready Sold"); + idToListing[listId].sold = true; + + if(l.isNative){ + require(msg.value == l.price, "Incorrect price"); + (bool s,) = l.owner.call{value: l.price * 97/100}(""); + (bool ss,) = marketOwner.call{value: l.price * 3/100}(""); + require(s, "Owner transfer failed"); + require(ss, "MarketOwner Transfer failed"); + }else{ + l.paymentToken.transferFrom(msg.sender, l.owner, l.price * 97/100); + l.paymentToken.transferFrom(msg.sender, marketOwner, l.price * 3/100); + } + IERC721(l.NftToken).transferFrom(address(this), msg.sender, l.tokenId); + } + + function offer(uint256 listid, uint256 offerAmount) external payable { + uint256 offerId = lastOfferId++; + Listing memory l = idToListing[listid]; + require(!l.sold, "Already sold"); + if(l.isNative){ + require(msg.value >= l.minOffer, "Invalid offer"); + require(offerAmount == 0, "Cannot offer erc20"); + }else { + require(offerAmount >= l.minOffer, "Invalid offer"); + l.paymentToken.transferFrom(msg.sender, address(this), offerAmount); + } + require(msg.sender != l.owner, "Owner cannot offer"); + OfferDetails memory offer_; + offer_.listId = listid; + offer_.offerrer = msg.sender; + offer_.offerAmount = l.isNative ? msg.value : offerAmount; + + idToOffer[offerId] = offer_; + } + + function getOffer(uint256 offerId) external view returns(OfferDetails memory o) { + o = idToOffer[offerId]; + } + + function acceptOffer(uint256 offerid) external { + OfferDetails memory offer_ = idToOffer[offerid]; + Listing memory l = idToListing[offer_.listId]; + // Checks + require(l.owner == msg.sender, "Unauthorized seller"); + require(!l.sold, "Already Sold"); + require(offer_.offerrer != address(0), "Invalid offer"); + // Effects + idToListing[offer_.listId].sold = true; + idToOffer[offerid].status = true; + // Interactions + if(l.isNative){ + (bool success,) = l.owner.call{value: offer_.offerAmount * 97/100}(""); + (bool success2,) = marketOwner.call{value: offer_.offerAmount * 3/100}(""); + require(success, "Failed owner transfer"); + require(success2, "Failed marketPlace commission transfer"); + }else{ + l.paymentToken.transfer(l.owner, offer_.offerAmount * 97/100); + l.paymentToken.transfer(marketOwner, offer_.offerAmount * 3/100); + } + IERC721(l.NftToken).transferFrom(address(this), offer_.offerrer, l.tokenId); + } + + function cancelOffer(uint256 offerid) external{ + OfferDetails memory offer_ = idToOffer[offerid]; + Listing memory l = idToListing[offer_.listId]; + // Checks + require(!offer_.status, "Offer already accepted"); + require(msg.sender == offer_.offerrer, "Unauthorized offerrer"); + // Effects + delete idToOffer[offerid]; + // Interactions + if(l.isNative){ + (bool s,) = offer_.offerrer.call{value: offer_.offerAmount}(""); + require(s, "Failed refund"); + }else{ + l.paymentToken.transfer(offer_.offerrer, offer_.offerAmount); + } + + } + + function cancelListing(uint256 listid) external { + Listing memory l = idToListing[listid]; + // Checks + require(msg.sender == l.owner, "Unauthorized user"); + require(!l.sold, "Already sold"); + // Effects + delete idToListing[listid]; + // Interaction + IERC721(l.NftToken).transferFrom(address(this), l.owner, l.tokenId); + } + +} \ No newline at end of file diff --git a/contracts/BlockNft.sol b/contracts/BlockNft.sol new file mode 100644 index 0000000..0533a7c --- /dev/null +++ b/contracts/BlockNft.sol @@ -0,0 +1,16 @@ +// // SPDX-License-Identifier: SEE LICENSE IN LICENSE +// pragma solidity ^0.8.28; + +// import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; + +// contract BlockNft is ERC721{ +// uint256 public tokenID; +// constructor() ERC721("BlockNft", "BKN"){} + +// function mint(address recepient) external returns(uint256){ +// tokenID++; +// uint256 tokenId = tokenID; +// _safeMint(recepient, tokenId); +// return tokenId; +// } +// } \ No newline at end of file diff --git a/contracts/BlockHeaderToken.sol b/contracts/BlockToken.sol similarity index 100% rename from contracts/BlockHeaderToken.sol rename to contracts/BlockToken.sol diff --git a/contracts/MyBlockMarketPlace.sol b/contracts/MyBlockMarketPlace.sol new file mode 100644 index 0000000..4ab689c --- /dev/null +++ b/contracts/MyBlockMarketPlace.sol @@ -0,0 +1,30 @@ +// // SPDX-License-Identifier: MIT +// pragma solidity ^0.8.20; + +// struct Listing { +// address owner; +// uint256 id; +// address nftToken; +// uint256 tokenId; +// IERC20 paymentToken; +// bool isNative; +// uint256 price; +// bool sold; +// uint256 minOffer; +// } + +// struct OfferDetails { +// uint256 offerAmount; +// address offerer; +// } + +// contract BlockMarketPlace [ + +// mapping(uint256 listid => Listing list) public idToListing; +// mapping(uint256 offerid => OfferDetails offer) public idToOffer; +// uint256 lastUpdated; + +// function listNft(Listing memory list) external { +// uint listid = +// } +// ] \ No newline at end of file diff --git a/contracts/NFT.sol b/contracts/NFT.sol new file mode 100644 index 0000000..f9fe475 --- /dev/null +++ b/contracts/NFT.sol @@ -0,0 +1,124 @@ +// // SPDX-License-Identifier: MIT +// pragma solidity ^0.8.20; + +// import "@openzeppelin/contracts/token/ERC721/IERC721.sol"; +// import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + +// contract BlockMarketPlace { +// uint256 public listCounter; +// uint256 public constant COMMISSION_PERCENT = 3; +// address public immutable feeReceiver; + +// struct Listing { +// address owner; +// uint256 id; +// address nftToken; +// uint256 tokenId; +// IERC20 paymentToken; +// bool isNative; +// uint256 price; +// bool sold; +// uint256 minOffer; +// } + +// struct OfferDetails { +// uint256 offerAmount; +// address offerer; +// } + +// mapping(uint256 => Listing) public idToListing; +// mapping(uint256 => OfferDetails[]) public listingOffers; + +// constructor(address _feeReceiver) { +// feeReceiver = _feeReceiver; +// } + +// function listNft( +// address nftToken, +// uint256 tokenId, +// address paymentToken, +// bool isNative, +// uint256 price, +// uint256 minOffer +// ) external { +// require(price > 0, "Price must be greater than 0"); + +// IERC721(nftToken).safeTransferFrom(msg.sender, address(this), tokenId); + +// idToListing[listCounter] = Listing({ +// owner: msg.sender, +// id: listCounter, +// nftToken: nftToken, +// tokenId: tokenId, +// paymentToken: IERC20(paymentToken), +// isNative: isNative, +// price: price, +// sold: false, +// minOffer: minOffer +// }); + +// listCounter++; +// } + +// function buyNft(uint256 listId) external payable { +// Listing storage listing = idToListing[listId]; +// require(!listing.sold, "Already sold"); + +// uint256 commission = (listing.price * COMMISSION_PERCENT) / 100; +// uint256 sellerAmount = listing.price - commission; + +// if (listing.isNative) { +// require(msg.value == listing.price, "Incorrect native amount"); +// payable(listing.owner).transfer(sellerAmount); +// payable(feeReceiver).transfer(commission); +// } else { +// IERC20 token = listing.paymentToken; +// require(token.transferFrom(msg.sender, address(this), listing.price), "Payment failed"); +// require(token.transfer(listing.owner, sellerAmount), "Payout failed"); +// require(token.transfer(feeReceiver, commission), "Commission failed"); +// } + +// listing.sold = true; +// IERC721(listing.nftToken).safeTransferFrom(address(this), msg.sender, listing.tokenId); +// } + +// function makeOffer(uint256 listId, uint256 offerAmount) external payable { +// Listing storage listing = idToListing[listId]; +// require(!listing.sold, "Already sold"); +// require(offerAmount >= listing.minOffer, "Offer too low"); + +// if (listing.isNative) { +// require(msg.value == offerAmount, "Incorrect ETH"); +// } else { +// require(listing.paymentToken.transferFrom(msg.sender, address(this), offerAmount), "Transfer failed"); +// } + +// listingOffers[listId].push(OfferDetails({ +// offerAmount: offerAmount, +// offerer: msg.sender +// })); +// } + +// function acceptOffer(uint256 listId, uint256 offerIndex) external { +// Listing storage listing = idToListing[listId]; +// require(msg.sender == listing.owner, "Only owner"); +// require(!listing.sold, "Already sold"); + +// OfferDetails memory offer = listingOffers[listId][offerIndex]; +// uint256 commission = (offer.offerAmount * COMMISSION_PERCENT) / 100; +// uint256 payout = offer.offerAmount - commission; + +// if (listing.isNative) { +// payable(listing.owner).transfer(payout); +// payable(feeReceiver).transfer(commission); +// } else { +// listing.paymentToken.transfer(listing.owner, payout); +// listing.paymentToken.transfer(feeReceiver, commission); +// } + +// listing.sold = true; +// IERC721(listing.nftToken).safeTransferFrom(address(this), offer.offerer, listing.tokenId); +// delete listingOffers[listId]; // Clear offers +// } +// } + diff --git a/contracts/counterV2.sol b/contracts/counterV2.sol new file mode 100644 index 0000000..807ca29 --- /dev/null +++ b/contracts/counterV2.sol @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.28; + +interface ICounterV2{ + function setCount(uint256 _count) external; + + function getCount() external view returns(uint256); + + function increaseCountByOne() external; + + function resetCount() external; + + function decreaseCountByOne() external; +} + +contract CounterV2 is ICounterV2 { + uint256 public count; + address owner; + + constructor(){ + owner = msg.sender; + } + + function setCount(uint256 _count) public { + require(_count > 0, "Count must be greater than 0"); + require(msg.sender == owner, "You are unauthorised"); + count = _count; + } + + function getCount() public view returns(uint256) { + return count; + } + + function getOwner() public view returns(address) { + return owner; + } + + function increaseCountByOne() public { + require(msg.sender == owner, "You are unauthorised"); + count+=1; + } + + function resetCount() public { + require(count > 0,"Cannot reset value , It's already at default"); + require(msg.sender == owner, "You are Unauthorised"); + count = 0; + } + + function decreaseCountByOne() external { + require(msg.sender == owner, "You are unauthorised"); + count-=1; + } +} + +contract callerCounterV2 { + ICounterV2 public _IC; + address public contractAddress; + constructor (address _contractAddress) { + contractAddress = _contractAddress; + _IC = ICounterV2(contractAddress); + + } + + function callDecreaseCountByOne() public { + _IC.decreaseCountByOne(); + } +} + \ No newline at end of file diff --git a/solidity-cohort-7 b/solidity-cohort-7 new file mode 160000 index 0000000..3e67ebe --- /dev/null +++ b/solidity-cohort-7 @@ -0,0 +1 @@ +Subproject commit 3e67ebe07a61f61516150ebf30710b9c4748f74b diff --git a/test/BlockMarketPlace.js b/test/BlockMarketPlace.js new file mode 100644 index 0000000..e8bc4bd --- /dev/null +++ b/test/BlockMarketPlace.js @@ -0,0 +1,281 @@ +const { + loadFixture, +} = require("@nomicfoundation/hardhat-toolbox/network-helpers"); +// const { anyValue } = require("@nomicfoundation/hardhat-chai-matchers/withArgs"); +const { expect, assert } = require("chai"); +const { ethers } = require("hardhat"); +const { bigint } = require("hardhat/internal/core/params/argumentTypes"); + +// util functon +const deployBlockMarketPlace = async () => { + // target the BlockMarketPlace contract within our contract folder + const [owner_, addr1, addr2] = await ethers.getSigners(); + const BlockMarketPlaceContract = await ethers.getContractFactory( + "BlockMarketPlace" + ); // target BlockMarketPlace.sol + const BlockNftContract = await ethers.getContractFactory("BlockNft"); + const BlockTokenContract = await ethers.getContractFactory("BlockToken"); + let name_ = "BlockToken"; + let symbol_ = "BCT"; + const BlockToken = await BlockTokenContract.deploy( + name_, + symbol_, + owner_.address + ); // deploy the BlockToken contract + const blocknft = await BlockNftContract.deploy(); + const marketplace = await BlockMarketPlaceContract.connect(owner_).deploy(); + // deploy the BlockMarketPlace contract + return { marketplace, blocknft, BlockToken, owner_, addr1, addr2 }; // return the deployed instance of our BlockMarketPlace contract +}; + +describe("BlockMarketPlace Test Suite", () => { + describe("Deployment", () => { + it("Should return set values upon deployment", async () => { + const { marketplace, owner_ } = await loadFixture(deployBlockMarketPlace); + expect(await marketplace.marketOwner()).to.eq(owner_); + }); + }); + + describe("Listing", () => { + it("Should list Nft accordingly", async () => { + const { marketplace, addr1, BlockToken, blocknft } = await loadFixture( + deployBlockMarketPlace + ); + let tokenId = 1; + await blocknft.connect(addr1).mint(addr1); + let token = await ethers.getContractAt("IERC20", BlockToken); + await blocknft + .connect(addr1) + .setApprovalForAll(marketplace.getAddress(), true); + await marketplace.connect(addr1).listNft({ + owner: addr1, + tokenId: tokenId, + paymentToken: token, + NftToken: blocknft.getAddress(), + isNative: false, + price: 100000, + sold: false, + minOffer: 10, + }); + + expect(await blocknft.ownerOf(tokenId)).to.eq( + await marketplace.getAddress() + ); + }); + + it("Should revert upon setting unaccepted values", async () => { + const { marketplace, addr1, BlockToken, blocknft } = await loadFixture( + deployBlockMarketPlace + ); + let tokenId = 1; + await blocknft.connect(addr1).mint(addr1); + let token = await ethers.getContractAt("IERC20", BlockToken); + await blocknft + .connect(addr1) + .setApprovalForAll(marketplace.getAddress(), true); + let tx1 = marketplace.connect(addr1).listNft({ + owner: addr1, + tokenId: tokenId, + paymentToken: token, + NftToken: blocknft.getAddress(), + isNative: false, + price: 0, + sold: false, + minOffer: 10, + }); + + await expect(tx1).to.be.revertedWith("Invalid price"); + // tx2 + let tx2 = marketplace.connect(addr1).listNft({ + owner: addr1, + tokenId: tokenId, + paymentToken: token, + NftToken: blocknft.getAddress(), + isNative: false, + price: 10000, + sold: false, + minOffer: 0, + }); + + await expect(tx2).to.be.revertedWith("Invalid min offer"); + + // tx3 + let tx3 = marketplace.connect(addr1).listNft({ + owner: addr1, + tokenId: tokenId, + paymentToken: token, + NftToken: blocknft.getAddress(), + isNative: true, + price: 10000, + sold: false, + minOffer: 10, + }); + + await expect(tx3).to.be.revertedWith("ERC20 Payment is not supported"); + + let ZeroAddress = "0x0000000000000000000000000000000000000000"; + marketplace.connect(addr1).listNft({ + owner: addr1, + tokenId: tokenId, + paymentToken: ZeroAddress, + NftToken: blocknft.getAddress(), + isNative: true, + price: 10000, + sold: false, + minOffer: 10, + }); + + let [, , paymentToken, , ,] = await marketplace.getListing(1); + console.log(paymentToken); + + expect(await paymentToken).to.eq(ZeroAddress); + + });}); + + describe("Buy NFT", () => { + it("Should allow a user to buy a listed NFT with ERC20", async () => { + const { marketplace, blocknft, BlockToken, addr1, addr2, owner_ } = await loadFixture(deployBlockMarketPlace); + let tokenId = 1; + await blocknft.connect(addr1).mint(addr1); + await blocknft.connect(addr1).setApprovalForAll(marketplace.getAddress(), true); + + await marketplace.connect(addr1).listNft({ + owner: addr1, + tokenId, + paymentToken: BlockToken, + NftToken: blocknft.getAddress(), + isNative: false, + price: 100, + sold: false, + minOffer: 10, + }); + + await BlockToken.connect(owner_).mint(200, owner_); + await BlockToken.connect(owner_).transfer(addr2.address, 100); + await BlockToken.connect(addr2).approve(marketplace.getAddress(), 100); + + await marketplace.connect(addr2).buyNft(0); + + expect(await blocknft.ownerOf(tokenId)).to.equal(addr2.address); + expect((await marketplace.getListing(0)).sold).to.equal(true); + }); +}); + +describe("Offer", () => { + it("Should allow a user to make an offer with ERC20", async () => { + const { marketplace, blocknft, BlockToken, addr1, addr2, owner_ } = await loadFixture(deployBlockMarketPlace); + let tokenId = 1; + await blocknft.connect(addr1).mint(addr1); + await blocknft.connect(addr1).setApprovalForAll(marketplace.getAddress(), true); + + await marketplace.connect(addr1).listNft({ + owner: addr1, + tokenId, + paymentToken: BlockToken, + NftToken: blocknft.getAddress(), + isNative: false, + price: 100, + sold: false, + minOffer: 10, + }); + + await BlockToken.connect(owner_).mint(200, owner_); + await BlockToken.connect(owner_).transfer(addr2.address, 50); + await BlockToken.connect(addr2).approve(marketplace.getAddress(), 50); + + await marketplace.connect(addr2).offer(0, 20); + + const offer = await marketplace.getOffer(0); + expect(offer.offerAmount).to.equal(20); + expect(offer.offerrer).to.equal(addr2.address); + }); +}); + +describe("Accept Offer", () => { + it("Should allow the owner to accept an offer", async () => { + const { marketplace, blocknft, BlockToken, addr1, addr2, owner_ } = await loadFixture(deployBlockMarketPlace); + let tokenId = 1; + await blocknft.connect(addr1).mint(addr1); + await blocknft.connect(addr1).setApprovalForAll(marketplace.getAddress(), true); + + await marketplace.connect(addr1).listNft({ + owner: addr1, + tokenId, + paymentToken: BlockToken, + NftToken: blocknft.getAddress(), + isNative: false, + price: 100, + sold: false, + minOffer: 10, + }); + + await BlockToken.connect(owner_).mint(200, owner_); + await BlockToken.connect(owner_).transfer(addr2.address, 50); + await BlockToken.connect(addr2).approve(marketplace.getAddress(), 50); + + await marketplace.connect(addr2).offer(0, 20); + + await marketplace.connect(addr1).acceptOffer(0); + + expect(await blocknft.ownerOf(tokenId)).to.equal(addr2.address); + expect((await marketplace.getListing(0)).sold).to.equal(true); + }); +}); + +describe("Cancel Offer", () => { + it("Should allow the offerer to cancel their offer", async () => { + const { marketplace, blocknft, BlockToken, addr1, addr2, owner_ } = await loadFixture(deployBlockMarketPlace); + let tokenId = 1; + await blocknft.connect(addr1).mint(addr1); + await blocknft.connect(addr1).setApprovalForAll(marketplace.getAddress(), true); + + await marketplace.connect(addr1).listNft({ + owner: addr1, + tokenId, + paymentToken: BlockToken, + NftToken: blocknft.getAddress(), + isNative: false, + price: 100, + sold: false, + minOffer: 10, + }); + + await BlockToken.connect(owner_).mint(200, owner_); + await BlockToken.connect(owner_).transfer(addr2.address, 50); + await BlockToken.connect(addr2).approve(marketplace.getAddress(), 50); + + await marketplace.connect(addr2).offer(0, 20); + + await marketplace.connect(addr2).cancelOffer(0); + + const offer = await marketplace.getOffer(0); + expect(offer.offerrer).to.equal(ethers.constants.AddressZero); + }); +}); + +describe("Cancel Listing", () => { + it("Should allow the owner to cancel their listing", async () => { + const { marketplace, blocknft, BlockToken, addr1 } = await loadFixture(deployBlockMarketPlace); + let tokenId = 1; + await blocknft.connect(addr1).mint(addr1); + await blocknft.connect(addr1).setApprovalForAll(marketplace.getAddress(), true); + + await marketplace.connect(addr1).listNft({ + owner: addr1, + tokenId, + paymentToken: BlockToken, + NftToken: blocknft.getAddress(), + isNative: false, + price: 100, + sold: false, + minOffer: 10, + }); + + await marketplace.connect(addr1).cancelListing(0); + + const listing = await marketplace.getListing(0); + expect(listing.owner).to.equal(ethers.constants.AddressZero); + expect(await blocknft.ownerOf(tokenId)).to.equal(addr1.address); + }); + }); +}); \ No newline at end of file diff --git a/test/BlockToken.js b/test/BlockToken.js index f51869d..612ba3c 100644 --- a/test/BlockToken.js +++ b/test/BlockToken.js @@ -47,7 +47,7 @@ describe("BlockToken Test Suite", () => { await BlockToken.connect(owner_).mint(1000, addr1); expect(await BlockToken.balanceOf(addr1)).to.eq(1000); - // test that another user cant call successfully + let malicioustxn = BlockToken.connect(addr1).mint(1000, addr1); await expect(malicioustxn).to.be.revertedWith( "BlockToken:: Unauthorized User"