diff --git a/contracts/BlockMarketPlace.sol b/contracts/BlockMarketPlace.sol new file mode 100644 index 0000000..b07daa0 --- /dev/null +++ b/contracts/BlockMarketPlace.sol @@ -0,0 +1,155 @@ +// SPDX-License-Identifier: MIT +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; + bool status; +} + +contract BlockMarketPlace { + +mapping (uint256 listid => Listing list) public idToListing; +mapping (uint256 offerid => OfferDetails offer) public idToOffer; + +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..5c66aee --- /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/BlockToken.sol b/contracts/BlockToken.sol new file mode 100644 index 0000000..c2fc742 --- /dev/null +++ b/contracts/BlockToken.sol @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; + +contract BlockToken is ERC20{ + + address public owner; + + modifier onlyOwner { + require(msg.sender == owner, "BlockToken:: Unauthorized User"); + _; + } + + modifier notAmount0(uint256 _amount){ + require(_amount != 0, "BlockToken:: Zero amount not supported"); + _; + } + constructor(string memory _name, string memory _symbol, address _owner) ERC20(_name, _symbol){ + require(_owner != address(0), "BlockToken:: Zero address not supported"); + owner = _owner; + } + + function mint(uint256 _amount, address _recepient) onlyOwner notAmount0(_amount) external { + _mint(_recepient, _amount); + } + + function burn(uint256 _amount) notAmount0(_amount) external { + _burn(msg.sender, _amount); + } + + function burnFrom(address _user, uint256 _amount)onlyOwner notAmount0(_amount) external { + _burn(_user, _amount); + } + + +} \ No newline at end of file diff --git a/contracts/Counter.sol b/contracts/Counter.sol deleted file mode 100644 index fa8560c..0000000 --- a/contracts/Counter.sol +++ /dev/null @@ -1,48 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.28; - -interface ICounter { - function setCount(uint256 _count) external; - function increaseCountByOne() external; - function getCount() external view returns(uint256); - -} - -contract Counter is ICounter { - uint256 public count; - - function setCount(uint256 _count) external { - count = _count; - } - - function increaseCountByOne() public { - count += 1; - } - - function getCount() public view returns(uint256) { - return count; - } -} - - -// contract F { -// // Initializing interface IC -// IC public _ic; -// // Initializing the contract address -// address public contractCAddress; - -// constructor(address _contractCAddress) { -// // Set the contract address to the state variable contract address -// contractCAddress = _contractCAddress; -// // Passing the contract address into interface using the address instance of another contract -// _ic = IC(_contractCAddress); -// } - -// function setCount(uint256 _count) public { -// _ic.setCount(_count); -// } - -// function getCount() public view returns(uint256) { -// return _ic.getCount(); -// } -// } \ No newline at end of file diff --git a/contracts/CounterV2.sol b/contracts/CounterV2.sol new file mode 100644 index 0000000..7c895b9 --- /dev/null +++ b/contracts/CounterV2.sol @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.28; + +import "../interfaces/ICounterV2.sol"; + +// interface ICounterV2{ +// function setCount(uint count) external; +// function getCount() external returns (uint); +// function resetCount() external; +// function decreaseCount() external; +// } + +// contract CounterV2 { +contract CounterV2 is ICounterV2{ + + uint count; + address owner; + + constructor(){ + owner = msg.sender; + } + + // modifier onlyOwner() { + // require (owner == msg.sender, "unauthorized"); + // _; + // } + + function setCount(uint _count) public { + require(owner == msg.sender, "unauthorized"); + require(_count<=10, "count should not be greater than 10"); + count = _count; + } + + function getCount() public view returns(uint){ + return count; + } + + function resetCount() public{ + require(owner == msg.sender, "unauthorized"); + count = 0; + } + + function decreaseCount() public{ + count -= 1; + } + + function increaseCount() public{ + count+=1; + } + +} + +// contract CounterV2Caller{ +// ICounterV2 public icounterv2; + +// constructor(address _counterV2address){ +// icounterv2 = ICounterV2(_counterV2address); +// } + +// function decreaseCount() public{ +// icounterv2.decreaseCount(); +// } +// } \ No newline at end of file diff --git a/contracts/CounterV2Caller.sol b/contracts/CounterV2Caller.sol new file mode 100644 index 0000000..3615e2e --- /dev/null +++ b/contracts/CounterV2Caller.sol @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.28; +import "../interfaces/ICounterV2.sol"; +contract CounterV2Caller{ + ICounterV2 public icounterv2; + + constructor(address _counterV2address){ + icounterv2 = ICounterV2(_counterV2address); + } + + function decreaseCount() public{ + icounterv2.decreaseCount(); + } +} \ No newline at end of file diff --git a/interfaces/ICounterV2.sol b/interfaces/ICounterV2.sol new file mode 100644 index 0000000..5b76f53 --- /dev/null +++ b/interfaces/ICounterV2.sol @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.28; + +interface ICounterV2{ + function setCount(uint count) external; + function getCount() external returns (uint); + function resetCount() external; + function decreaseCount() external; +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 656a34f..cc2bf83 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,6 +5,9 @@ "packages": { "": { "name": "hardhat-project", + "dependencies": { + "@openzeppelin/contracts": "^5.4.0" + }, "devDependencies": { "@nomicfoundation/hardhat-toolbox": "^5.0.0", "hardhat": "^2.26.1" @@ -1305,6 +1308,12 @@ "node": ">= 12" } }, + "node_modules/@openzeppelin/contracts": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@openzeppelin/contracts/-/contracts-5.4.0.tgz", + "integrity": "sha512-eCYgWnLg6WO+X52I16TZt8uEjbtdkgLC0SUX/xnAksjjrQI4Xfn4iBRoI5j55dmlOhDv1Y7BoR3cU7e3WWhC6A==", + "license": "MIT" + }, "node_modules/@scure/base": { "version": "1.2.6", "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.2.6.tgz", diff --git a/package.json b/package.json index 0586079..a7c3ef4 100644 --- a/package.json +++ b/package.json @@ -3,10 +3,13 @@ "devDependencies": { "@nomicfoundation/hardhat-toolbox": "^5.0.0", "hardhat": "^2.26.1" - }, + }, "scripts": { - "test": "npx hardhat test", - "compile": "npx hardhat compile", + "test": "npx hardhat test", + "compile": "npx hardhat compile", "node": "npx hardhat node" + }, + "dependencies": { + "@openzeppelin/contracts": "^5.4.0" } } diff --git a/test/BlockMarketPlace.js b/test/BlockMarketPlace.js new file mode 100644 index 0000000..22ffd4b --- /dev/null +++ b/test/BlockMarketPlace.js @@ -0,0 +1,882 @@ +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, addr3] = 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, addr3 }; // 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("Cancel Listing", () => { + it("Should cancel listing", async () => { + const { marketplace, addr1, BlockToken, blocknft } = await loadFixture( + deployBlockMarketPlace + ); + let tokenId = 1; + let listId = 0; + 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, + }); + + await marketplace.connect(addr1).cancelListing(listId); + }); + + it("Should revert when unauthorized user cancel's listing", async () => { + const { marketplace, addr1, BlockToken, blocknft, addr2 } = + await loadFixture(deployBlockMarketPlace); + let tokenId = 1; + let listId = 0; + 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: 100, + sold: false, + minOffer: 10, + }); + + await expect( + marketplace.connect(addr2).cancelListing(listId) + ).to.be.revertedWith("Unauthorized user"); + }); + + it("Should revert if already sold", async () => { + const { marketplace, addr1, BlockToken, blocknft, addr2, owner_ } = + await loadFixture(deployBlockMarketPlace); + let tokenId = 1; + let listId = 0; + 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: 100, + sold: true, + minOffer: 10, + }); + + await BlockToken.connect(owner_).mint(1000, addr1); + await BlockToken.connect(addr1).transfer(addr2.address, 500); + await BlockToken.connect(addr2).approve(marketplace.getAddress(), 1000); + + await marketplace.connect(addr2).buyNft(listId); + + await expect( + marketplace.connect(addr1).cancelListing(listId) + ).to.be.revertedWith("Already sold"); + }); + }); + + describe("Buy Nft", () => { + it("Should buy successfully with tokens", async () => { + const { marketplace, addr1, BlockToken, blocknft, addr2, owner_ } = + 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 price = 1000; + let listId = 0; + + await marketplace.connect(addr1).listNft({ + owner: addr1, + tokenId: tokenId, + paymentToken: token, + NftToken: blocknft.getAddress(), + isNative: false, + price: 100, + sold: false, + minOffer: 10, + }); + + await BlockToken.connect(owner_).mint(2000, owner_); // mint token to owner addr + await BlockToken.connect(owner_).transfer(addr2.address, 1000); // transfer token to addr2 + await BlockToken.connect(addr2).approve(marketplace.getAddress(), 1000); // approve marketplace to spend tokens + expect(await BlockToken.balanceOf(addr2.address)).to.eq(1000); // check token balance of addr2 + + await marketplace.connect(addr2).buyNft(listId); + expect(await blocknft.ownerOf(tokenId)).to.eq(addr2.address); + expect((await marketplace.getListing(listId)).sold).to.equal(true); + + // listId is 0, not 1 + }); + + it("Should buy successfully with native", async () => { + const { marketplace, addr1, BlockToken, blocknft, addr2, owner_ } = + 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 ZeroAddress = "0x0000000000000000000000000000000000000000"; + let listId = 0; + + await marketplace.connect(addr1).listNft({ + owner: addr1, + tokenId: tokenId, + paymentToken: ZeroAddress, + NftToken: blocknft.getAddress(), + isNative: true, + price: 100, + sold: false, + minOffer: 10, + }); + + await marketplace.connect(addr2).buyNft(listId, { value: 100 }); + expect(await blocknft.ownerOf(tokenId)).to.eq(addr2.address); + expect((await marketplace.getListing(listId)).sold).to.equal(true); + }); + + it("Should revert upon setting invalid price", async () => { + const { marketplace, addr1, BlockToken, blocknft, addr2, owner_ } = + 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 listId = 0; + let ZeroAddress = "0x0000000000000000000000000000000000000000"; + + await marketplace.connect(addr1).listNft({ + owner: addr1, + tokenId: tokenId, + paymentToken: ZeroAddress, + NftToken: blocknft.getAddress(), + isNative: true, + price: 100, + sold: false, + minOffer: 10, + }); + + await expect( + marketplace.connect(addr2).buyNft(listId, { value: 50 }) + ).to.be.revertedWith("Incorrect price"); + expect((await marketplace.getListing(listId)).sold).to.equal(false); + }); + + it("Should revert if already sold", async () => { + const { marketplace, addr1, BlockToken, blocknft, addr2, addr3 } = + 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 listId = 0; + let ZeroAddress = "0x0000000000000000000000000000000000000000"; + + await marketplace.connect(addr1).listNft({ + owner: addr1, + tokenId: tokenId, + paymentToken: ZeroAddress, + NftToken: blocknft.getAddress(), + isNative: true, + price: 100, + sold: true, + minOffer: 10, + }); + + await marketplace.connect(addr2).buyNft(listId, { value: 100 }); + expect((await marketplace.getListing(listId)).sold).to.equal(true); + await expect( + marketplace.connect(addr3).buyNft(listId, { value: 100 }) + ).to.be.revertedWith("Already Sold"); + }); + }); + + describe("Offer", () => { + it("Should make offer with native", async () => { + const { marketplace, addr1, addr2, blocknft, BlockToken, owner_ } = + 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 listId = 0; + let ZeroAddress = "0x0000000000000000000000000000000000000000"; + + await marketplace.connect(addr1).listNft({ + owner: addr1, + tokenId: tokenId, + paymentToken: ZeroAddress, + NftToken: blocknft.getAddress(), + isNative: true, + price: 100, + sold: false, + minOffer: 10, + }); + + await marketplace + .connect(addr2) + .offer(listId, 0, { value: ethers.parseEther("50") }); + }); + + it("Should offer with tokens", async () => { + const { marketplace, addr1, addr2, blocknft, BlockToken, owner_ } = + 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 listId = 0; + let ZeroAddress = "0x0000000000000000000000000000000000000000"; + + await marketplace.connect(addr1).listNft({ + owner: addr1, + tokenId: tokenId, + paymentToken: token, + NftToken: blocknft.getAddress(), + isNative: false, + price: 100, + sold: false, + minOffer: 10, + }); + + await BlockToken.connect(owner_).mint(1000, addr1); + await BlockToken.connect(addr1).transfer(addr2.address, 500); + await BlockToken.connect(addr2).approve(marketplace.getAddress(), 1000); + + await marketplace.connect(addr2).offer(listId, 60); + }); + + it("Should revert if already sold", async () => { + const { marketplace, addr1, addr2, blocknft, BlockToken, owner_, addr3 } = + 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 listId = 0; + let ZeroAddress = "0x0000000000000000000000000000000000000000"; + + await marketplace.connect(addr1).listNft({ + owner: addr1, + tokenId: tokenId, + paymentToken: token, + NftToken: blocknft.getAddress(), + isNative: false, + price: 100, + sold: false, + minOffer: 10, + }); + + await BlockToken.connect(owner_).mint(1000, owner_); + await BlockToken.connect(owner_).transfer(addr3.address, 500); + await BlockToken.connect(addr3).approve(marketplace.getAddress(), 1000); + await marketplace.connect(addr3).buyNft(listId); + + await BlockToken.connect(owner_).mint(1000, addr1); + await BlockToken.connect(addr1).transfer(addr2.address, 500); + await BlockToken.connect(addr2).approve(marketplace.getAddress(), 1000); + await expect( + marketplace.connect(addr2).offer(listId, 60) + ).to.be.revertedWith("Already sold"); + }); + + it("Should revert when invalid offer is given (Native)", async () => { + const { marketplace, addr1, addr2, blocknft, BlockToken, owner_, addr3 } = + 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 listId = 0; + let ZeroAddress = "0x0000000000000000000000000000000000000000"; + + await marketplace.connect(addr1).listNft({ + owner: addr1, + tokenId: tokenId, + paymentToken: ZeroAddress, + NftToken: blocknft.getAddress(), + isNative: true, + price: 100, + sold: false, + minOffer: 10, + }); + + await expect( + marketplace.connect(addr2).offer(listId, 0, { value: 5 }) + ).to.be.revertedWith("Invalid offer"); + }); + + it("Should revert when invalid offer is given (Tokens)", async () => { + const { marketplace, addr1, addr2, blocknft, BlockToken, owner_, addr3 } = + 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 listId = 0; + let ZeroAddress = "0x0000000000000000000000000000000000000000"; + + await marketplace.connect(addr1).listNft({ + owner: addr1, + tokenId: tokenId, + paymentToken: token, + NftToken: blocknft.getAddress(), + isNative: false, + price: 100, + sold: false, + minOffer: 10, + }); + + await BlockToken.connect(owner_).mint(1000, addr1); + await BlockToken.connect(addr1).transfer(addr2.address, 500); + await BlockToken.connect(addr2).approve(marketplace.getAddress(), 1000); + await expect( + marketplace.connect(addr2).offer(listId, 5) + ).to.be.revertedWith("Invalid offer"); + }); + + it("Should revert if offering erc20", async () => { + const { marketplace, addr1, addr2, blocknft, BlockToken, owner_, addr3 } = + 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 listId = 0; + let ZeroAddress = "0x0000000000000000000000000000000000000000"; + + await marketplace.connect(addr1).listNft({ + owner: addr1, + tokenId: tokenId, + paymentToken: ZeroAddress, + NftToken: blocknft.getAddress(), + isNative: true, + price: 100, + sold: false, + minOffer: 10, + }); + + await BlockToken.connect(owner_).mint(1000, addr1); + await BlockToken.connect(addr1).transfer(addr3.address, 500); + await BlockToken.connect(addr3).approve(marketplace.getAddress(), 1000); + await expect( + marketplace.connect(addr3).offer(listId, ethers.parseUnits("50", 18), { + value: ethers.parseEther("10"), // Satisfy minOffer + }) + ).to.be.revertedWith("Cannot offer erc20"); + }); + + it("Should revert if owner tries to offer", async () => { + const { marketplace, addr1, addr2, blocknft, BlockToken, owner_, addr3 } = + 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 listId = 0; + let ZeroAddress = "0x0000000000000000000000000000000000000000"; + + await marketplace.connect(addr1).listNft({ + owner: addr1, + tokenId: tokenId, + paymentToken: ZeroAddress, + NftToken: blocknft.getAddress(), + isNative: true, + price: 100, + sold: false, + minOffer: 10, + }); + + await expect( + marketplace.connect(addr1).offer(listId, 0, { value: 50 }) + ).to.be.revertedWith("Owner cannot offer"); + }); + }); + + describe("Cancel Offer", () => { + it("Should Cancel Offer (Native)", async () => { + const { marketplace, addr1, addr2, blocknft, BlockToken, owner_, addr3 } = + 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 listId = 0; + let ZeroAddress = "0x0000000000000000000000000000000000000000"; + + await marketplace.connect(addr1).listNft({ + owner: addr1, + tokenId: tokenId, + paymentToken: ZeroAddress, + NftToken: blocknft.getAddress(), + isNative: true, + price: 100, + sold: false, + minOffer: 10, + }); + + await marketplace.connect(addr2).offer(listId, 0, { value: 40 }); + let offerId = 0; + await marketplace.connect(addr2).cancelOffer(offerId); + }); + + it("Should revert when offer has already been accepted", async () => { + const { marketplace, addr1, addr2, blocknft, BlockToken, owner_, addr3 } = + 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 listId = 0; + let ZeroAddress = "0x0000000000000000000000000000000000000000"; + + await marketplace.connect(addr1).listNft({ + owner: addr1, + tokenId: tokenId, + paymentToken: ZeroAddress, + NftToken: blocknft.getAddress(), + isNative: true, + price: 100, + sold: false, + minOffer: 10, + }); + + await marketplace.connect(addr2).offer(listId, 0, { value: 40 }); + let offerId = 0; + + await marketplace.connect(addr1).acceptOffer(offerId); + await expect( + marketplace.connect(addr2).cancelOffer(offerId) + ).to.be.revertedWith("Offer already accepted"); + }); + + it("Should Cancel Offer (Tokens)", async () => { + const { marketplace, addr1, addr2, blocknft, BlockToken, owner_, addr3 } = + 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 listId = 0; + let ZeroAddress = "0x0000000000000000000000000000000000000000"; + + await marketplace.connect(addr1).listNft({ + owner: addr1, + tokenId: tokenId, + paymentToken: token, + NftToken: blocknft.getAddress(), + isNative: false, + price: 100, + sold: false, + minOffer: 10, + }); + + await BlockToken.connect(owner_).mint(1000, addr1); + await BlockToken.connect(addr1).transfer(addr2.address, 500); + await BlockToken.connect(addr2).approve(marketplace.getAddress(), 1000); + + await marketplace.connect(addr2).offer(listId, 50); + let offerId = 0; + await marketplace.connect(addr2).cancelOffer(offerId); + }); + + it("Should revert when invalid offerer offers", async () => { + const { marketplace, addr1, addr2, blocknft, BlockToken, owner_, addr3 } = + 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 listId = 0; + let ZeroAddress = "0x0000000000000000000000000000000000000000"; + + await marketplace.connect(addr1).listNft({ + owner: addr1, + tokenId: tokenId, + paymentToken: ZeroAddress, + NftToken: blocknft.getAddress(), + isNative: true, + price: 100, + sold: false, + minOffer: 10, + }); + + await marketplace.connect(addr2).offer(listId, 0, { value: 40 }); + let offerId = 0; + await expect( + marketplace.connect(addr3).cancelOffer(offerId) + ).to.be.revertedWith("Unauthorized offerrer"); + }); + + it("Should get Offer", async () => { + const { marketplace, addr1, addr2, blocknft, BlockToken, owner_, addr3 } = + 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 listId = 0; + let ZeroAddress = "0x0000000000000000000000000000000000000000"; + + await marketplace.connect(addr1).listNft({ + owner: addr1, + tokenId: tokenId, + paymentToken: token, + NftToken: blocknft.getAddress(), + isNative: false, + price: 100, + sold: false, + minOffer: 10, + }); + + await BlockToken.connect(owner_).mint(1000, addr1); + await BlockToken.connect(addr1).transfer(addr2.address, 500); + await BlockToken.connect(addr2).approve(marketplace.getAddress(), 1000); + + await marketplace.connect(addr2).offer(listId, 50); + let offerId = 0; + await marketplace.connect(addr1).getOffer(offerId); + }); + }); + + describe("Accept Offer", () => { + it("Should accept offer (Native)", async () => { + const { marketplace, addr1, addr2, blocknft, BlockToken, owner_, addr3 } = + 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 listId = 0; + let ZeroAddress = "0x0000000000000000000000000000000000000000"; + + await marketplace.connect(addr1).listNft({ + owner: addr1, + tokenId: tokenId, + paymentToken: ZeroAddress, + NftToken: blocknft.getAddress(), + isNative: true, + price: 100, + sold: false, + minOffer: 10, + }); + + await marketplace.connect(addr2).offer(listId, 0, { value: 40 }); + let offerId = 0; + + await marketplace.connect(addr1).acceptOffer(offerId); + }); + + it("Should accept offer (Tokens)", async () => { + const { marketplace, addr1, addr2, blocknft, BlockToken, owner_, addr3 } = + 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 listId = 0; + let ZeroAddress = "0x0000000000000000000000000000000000000000"; + + await marketplace.connect(addr1).listNft({ + owner: addr1, + tokenId: tokenId, + paymentToken: token, + NftToken: blocknft.getAddress(), + isNative: false, + price: 100, + sold: false, + minOffer: 10, + }); + + await BlockToken.connect(owner_).mint(1000, owner_); + await BlockToken.connect(owner_).transfer(addr2.address, 700); + await BlockToken.connect(addr2).approve(marketplace.getAddress(), 1000); + + await marketplace.connect(addr2).offer(listId, 50); + let offerId = 0; + + await marketplace.connect(addr1).acceptOffer(offerId); + }); + + it("Should revert if invalid owner accepts offer", async () => { + const { marketplace, addr1, addr2, blocknft, BlockToken, owner_, addr3 } = + 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 listId = 0; + let ZeroAddress = "0x0000000000000000000000000000000000000000"; + + await marketplace.connect(addr1).listNft({ + owner: addr1, + tokenId: tokenId, + paymentToken: ZeroAddress, + NftToken: blocknft.getAddress(), + isNative: true, + price: 100, + sold: false, + minOffer: 10, + }); + + await marketplace.connect(addr2).offer(listId, 0, { value: 40 }); + let offerId = 0; + + await expect( + marketplace.connect(addr2).acceptOffer(offerId) + ).to.be.revertedWith("Unauthorized seller"); + }); + + it("Should revert if Already Sold", async () => { + const { marketplace, addr1, addr2, blocknft, BlockToken, owner_, addr3 } = + 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 listId = 0; + let ZeroAddress = "0x0000000000000000000000000000000000000000"; + + await marketplace.connect(addr1).listNft({ + owner: addr1, + tokenId: tokenId, + paymentToken: ZeroAddress, + NftToken: blocknft.getAddress(), + isNative: true, + price: 100, + sold: false, + minOffer: 10, + }); + + await marketplace.connect(addr2).offer(listId, 0, { value: 40 }); + let offerId = 0; + + await marketplace.connect(addr3).buyNft(listId, { value: 100 }); + await expect( + marketplace.connect(addr1).acceptOffer(offerId) + ).to.be.revertedWith("Already Sold"); + }); + }); +}); diff --git a/test/BlockToken.js b/test/BlockToken.js new file mode 100644 index 0000000..3eb454d --- /dev/null +++ b/test/BlockToken.js @@ -0,0 +1,162 @@ +const { + loadFixture, +} = require("@nomicfoundation/hardhat-toolbox/network-helpers"); +// const { anyValue } = require("@nomicfoundation/hardhat-chai-matchers/withArgs"); +const { expect } = require("chai"); + +// util functon +const deployBlockToken = async () => { + // target the BlockToken contract within our contract folder + let name_ = "BlockToken"; + let symbol_ = "BCT"; + const [owner_, addr1, addr2] = await ethers.getSigners(); + const BlockTokenContract = await ethers.getContractFactory("BlockToken"); // target BlockToken.sol + const BlockToken = await BlockTokenContract.deploy( + name_, + symbol_, + owner_.address + ); // deploy the BlockToken contract + return { BlockToken, owner_, addr1, addr2, name_, symbol_ }; // return the deployed instance of our BlockToken contract +}; + +// BlockToken Test Suite +describe("BlockToken Test Suite", () => { + describe("Deployment", () => { + it("Should return set values upon deployment", async () => { + const { BlockToken, name_, symbol_, owner_ } = await loadFixture( + deployBlockToken + ); + expect(await BlockToken.name()).to.eq(name_); + expect(await BlockToken.symbol()).to.eq(symbol_); + expect(await BlockToken.owner()).to.eq(owner_); + }); + + it("Should revert if owner is zero address", async () => { + let ZeroAddress = "0x0000000000000000000000000000000000000000"; + const BlockTokenContract = await ethers.getContractFactory("BlockToken"); + await expect( + BlockTokenContract.deploy("hh", "tt", ZeroAddress) + ).to.be.revertedWith("BlockToken:: Zero address not supported"); + }); + }); + + describe("Minting", () => { + it("Should allow onlyOwner Mint", async () => { + const { BlockToken, owner_, addr1 } = await loadFixture(deployBlockToken); + // test owner mints successfully + 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" + ); + }); + + it("Should revert if minting amount is zero", async () => { + const { BlockToken, owner_, addr1 } = await loadFixture(deployBlockToken); + await expect( + BlockToken.connect(owner_).mint(0, addr1) + ).to.be.revertedWith("BlockToken:: Zero amount not supported"); + }); + }); + + describe("Burning", () => { + it("Should not burn if user doesn't have tokens", async () => { + const { BlockToken, owner_, addr1 } = await loadFixture(deployBlockToken); + await expect( + BlockToken.connect(addr1).burn(1000) + ).to.be.revertedWithCustomError(BlockToken, "ERC20InsufficientBalance"); + }); + + it("Should Burn Tokens Successfully", async () => { + const { BlockToken, owner_, addr1 } = await loadFixture(deployBlockToken); + await BlockToken.connect(owner_).mint(1000, owner_); + expect(await BlockToken.balanceOf(owner_)).to.eq(1000); + + await BlockToken.connect(owner_).burn(100); + expect(await BlockToken.balanceOf(owner_)).to.eq(900); + }); + }); + + describe("Burning From", () => { + it("Should only allow owner", async () => { + const { BlockToken, owner_, addr1 } = await loadFixture(deployBlockToken); + await BlockToken.connect(owner_).mint(10000, addr1); + // expect(await BlockToken.balanceOf(addr1)).to.eq(10000); + const authorizedUser = await BlockToken.connect(owner_).burnFrom( + addr1, + 1000 + ); + expect(await BlockToken.balanceOf(addr1)).to.eq(9000); + const unauthorizedUser = BlockToken.connect(addr1).burnFrom(addr1, 1000); + await expect(unauthorizedUser).to.be.revertedWith( + "BlockToken:: Unauthorized User" + ); + }); + it("Should not send zero", async () => { + const { BlockToken, addr1, owner_ } = await loadFixture(deployBlockToken); + await expect( + BlockToken.connect(owner_).burnFrom(addr1, 0) + ).to.be.revertedWith("BlockToken:: Zero amount not supported"); + }); + }); + + describe("Transfer", () => { + it("should be called by owner", async () => { + const { BlockToken, owner_, addr1 } = await loadFixture(deployBlockToken); + await BlockToken.connect(owner_).mint(10000, owner_); + await BlockToken.connect(owner_).transfer(addr1, 1000); + const addrBalance = await BlockToken.balanceOf(addr1); + const ownerBalance = await BlockToken.balanceOf(owner_); + + expect(addrBalance).to.eq(1000); + expect(ownerBalance).to.eq(9000); + }); + it("amount to be sent should be less than the balance of the sender", async () => { + const { BlockToken, owner_, addr1 } = await loadFixture(deployBlockToken); + await BlockToken.connect(owner_).mint(10000, owner_); + const ownerBalance = await BlockToken.balanceOf(owner_); + expect(ownerBalance).to.be.greaterThanOrEqual(1000); + await BlockToken.connect(owner_).transfer(addr1, 1000); + const addrBalance = await BlockToken.balanceOf(addr1); + const ownerBalanceAfter = await BlockToken.balanceOf(owner_); + + expect(addrBalance).to.eq(1000); + expect(ownerBalanceAfter).to.eq(9000); + }); + it("should revert if amount to be sent is greter than the amount the sender has", async () => { + const { BlockToken, owner_, addr1 } = await loadFixture(deployBlockToken); + await expect(BlockToken.connect(owner_).transfer(addr1, 10000)).to.be + .reverted; + }); + it("address 0 should not be the receiver", async () => { + const { BlockToken, owner_, addr1 } = await loadFixture(deployBlockToken); + let ZeroAddress = "0x0000000000000000000000000000000000000000"; + await expect(BlockToken.connect(owner_).transfer(ZeroAddress, 1000)).to.be + .reverted; + }); + }); + + describe("Approve", () => { + it("address zero should not be the receiver", async () => { + const { BlockToken, owner_, addr1 } = await loadFixture(deployBlockToken); + let ZeroAddress = "0x0000000000000000000000000000000000000000"; + await expect(BlockToken.connect(owner_).approve(ZeroAddress, 1000)).to.be + .reverted; + }); + it("should send moeny to allowances", async () => { + const { BlockToken, owner_, addr1 } = await loadFixture(deployBlockToken); + await BlockToken.connect(owner_).approve(addr1, 1000); + const allowance = await BlockToken.allowance(owner_, addr1); + + expect(allowance).to.eq(1000); + }); + // it("address zero should not be the sender", async () => { + // const { BlockToken, owner_, addr1 } = await loadFixture(deployBlockToken); + // let ZeroAddress = "0x0000000000000000000000000000000000000000"; + // await expect(BlockToken.connect(ZeroAddress)).to.be.reverted; + // }); + }); +}); diff --git a/test/Counter.js b/test/Counter.js deleted file mode 100644 index 99b2931..0000000 --- a/test/Counter.js +++ /dev/null @@ -1,49 +0,0 @@ -const {loadFixture } = require("@nomicfoundation/hardhat-toolbox/network-helpers"); -// const { anyValue } = require("@nomicfoundation/hardhat-chai-matchers/withArgs"); -const { expect } = require("chai"); - -// util functon -const deployCounter = async () => { - // target the Counter contract within our contract folder - const CounterContract = await ethers.getContractFactory("Counter"); // target Counter.sol - const counter = await CounterContract.deploy(); // deploy the Counter contract - return counter ; // return the deployed instance of our counter contract -} - -// Counter Test Suite -describe("Counter Test Suite", () => { - describe("Deployment", () => { - it("Should return default values upon deployment", async () => { - const counter = await loadFixture(deployCounter); - expect(await counter.count()).to.eq(0); // assert that count = 0 upon deployment - }) - }) - - describe("Transactions", () => { - describe("SetCount", () => { - it("Should set appropriate count values", async () => { - const counter = await loadFixture(deployCounter); // extract deployed counter instace - let count1 = await counter.getCount(); // check initial count value before txn - expect(count1).to.eq(0); - await counter.setCount(10) // assert that count = 0 upon deployment - - let count2 = await counter.getCount(); // check initial count value before txn - expect(count2).to.eq(10) // check final count = 10 - }) - - it("Should set appropriate values for multiple setCount txns", async () => { - - }) - }) - - describe("IncreaseCountByOne", () => { - it("Should set appropriate increaseCountByOne value", async () => { - - }) - - it("Should set appropriate values for multiple increaseCountByOne txns", async () => { - - }) - }) - }) -}) \ No newline at end of file diff --git a/test/CounterV2.js b/test/CounterV2.js new file mode 100644 index 0000000..983e5fb --- /dev/null +++ b/test/CounterV2.js @@ -0,0 +1,74 @@ +const { + loadFixture, +} = require("@nomicfoundation/hardhat-toolbox/network-helpers"); +// const { anyValue } = require("@nomicfoundation/hardhat-chai-matchers/withArgs"); +const { expect } = require("chai"); + +// DEPLOY +const deployCounter = async () => { + const [owner, otherAccount] = await ethers.getSigners(); + + const CounterV2Contract = await ethers.getContractFactory("CounterV2"); //targeting counter.sol + const counter = await CounterV2Contract.deploy(); //if no constructor no need to put anything in the depl0y place + + return { counter, owner, otherAccount }; //return the deployed instance of our counter contract +}; + +describe("CounterV2 Test Suite", () => { + describe("Deployment", async () => { + it("Should return default values upon deployment", async () => { + const { counter } = await loadFixture(deployCounter); + expect(await counter.getCount()).to.eq(0); //assert count equal to 0 upon deployment + // console.log("counter here: ___", counter); + }); + }); + describe("Transactions", async () => { + it("Should set appropriate count values", async () => { + const { counter } = await loadFixture(deployCounter); + const counter1 = await counter.getCount(); + expect(counter1).to.eq(0); + await counter.setCount(10); + const counter2 = await counter.getCount(); + expect(counter2).to.eq(10); + }); + it("Should reset count values to 0", async () => { + const { counter } = await loadFixture(deployCounter); + // const counter1 = await counter.getCount(); + // expect(counter1).to.eq(0); + await counter.resetCount(); + const counter2 = await counter.getCount(); + expect(counter2).to.eq(0); + }); + it("Should increase count ", async () => { + const { counter } = await loadFixture(deployCounter); + const counter1 = await counter.getCount(); + expect(counter1).to.eq(0); + await counter.increaseCount(); + const counter2 = await counter.getCount(); + expect(counter2).to.eq(1); + }); + it("Should decrease count ", async () => { + const { counter } = await loadFixture(deployCounter); + // const counter1 = await counter.getCount(); + // expect(counter1).to.eq(0); + await counter.setCount(6); + await counter.decreaseCount(); + const counter2 = await counter.getCount(); + expect(counter2).to.eq(5); + }); + describe("Reverts", () => { + it("should revert if invalid owner calls setCount", async () => { + const { counter, otherAccount } = await loadFixture(deployCounter); + await expect( + counter.connect(otherAccount).setCount(10) + ).to.be.revertedWith("unauthorized"); + }); + it("should revert if invalid calls resetCount", async () => { + const { counter, otherAccount } = await loadFixture(deployCounter); + await expect( + counter.connect(otherAccount).resetCount() + ).to.be.revertedWith("unauthorized"); + }); + }); + }); +}); diff --git a/test/CounterV2Caller.js b/test/CounterV2Caller.js new file mode 100644 index 0000000..8e74c72 --- /dev/null +++ b/test/CounterV2Caller.js @@ -0,0 +1,49 @@ +const { + loadFixture, +} = require("@nomicfoundation/hardhat-toolbox/network-helpers"); +// const { anyValue } = require("@nomicfoundation/hardhat-chai-matchers/withArgs"); +const { expect } = require("chai"); + +// DEPLOY +const deployCounter = async () => { + // const [owner, otherAccount] = await ethers.getSigners(); + + const CounterV2Contract = await ethers.getContractFactory("CounterV2"); + const counterV2 = await CounterV2Contract.deploy(); //if no constructor no need to put anything in the depl0y place + const counterV2address = await counterV2.getAddress(); + + const CounterV2CallerContract = await ethers.getContractFactory( + "CounterV2Caller" + ); //targeting counter.sol + const counterV2Caller = await CounterV2CallerContract.deploy( + counterV2address + ); + + return { counterV2, counterV2Caller }; //return the deployed instance of our counter contract +}; + +describe("CounterV2Caller Test Suite", () => { + describe("Deployment", () => { + it("Should return default values upon deployment", async () => { + const { counterV2 } = await loadFixture(deployCounter); + expect(await counterV2.getCount()).to.eq(0); //assert count equal to 0 upon deployment + // console.log("counter here: ___", counter); + }); + }); + describe("Transactions", async () => { + it("Should successfully decrement", async () => { + const { counterV2, counterV2Caller } = await loadFixture(deployCounter); + await counterV2.setCount(10); + await counterV2Caller.decreaseCount(); + const countAfterChnage = await counterV2.getCount(); + expect(countAfterChnage).to.eq(9); + }); + // it("Should decrease count ", async () => { + // const { counter, counterV2 } = await loadFixture(deployCounter); + // await counter.setCount(9); + // await counterV2.decreaseCount(); + // const counter2 = await counter.getCount(); + // expect(counter2).to.eq(8); + // }); + }); +});