Skip to content

Commit

Permalink
truffle-web3-nft-marketplace Genesis
Browse files Browse the repository at this point in the history
  • Loading branch information
eQereum committed Apr 22, 2022
0 parents commit 80f39af
Show file tree
Hide file tree
Showing 15 changed files with 557 additions and 0 deletions.
52 changes: 52 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# NFT Marketplace with Truffle/Web3js

This project represents deploying of NFT (ERC721) contract & NFT Marketplace for trading NFT tokens. You can also compare this project with **Hardhat/Ethers** version of it that published earlier in [**here**](https://github.com/0xhamedETH/hardhat-ethers-nextjs-nft-marketplace). This would be useful for learning both pack of tools.

### Clone the repository

```shell
git clone --recursive https://github.com/0xhamedETH/truffle-web3-nft-marketplace.git your-directory
```

### Install Packages

```shell
cd your-directory/ethereum
npm install
```

### Compile

compile first to create json artifacts in `build` folder

```shell
truffle compile
```

### Test

- Run `ganache-cli` in separate terminal

```shell
ganache-cli
```

- Run `truffle test` in main terminal

```shell
truffle test test/nft.test.js
```

### Deploy

For this step you first need to fill `.env` file with your api keys (`Alchemy`, ...)

You can deploy both contracts in any network you want (make sure `truffle-config.js` contains that network)

for example: `maticMumbai`

```shell
truffle migrate --reset --network maticMumbai
```

After a while, you would see deployment transaction details of both NFT and NFTMarketplace contracts in console.
5 changes: 5 additions & 0 deletions ethereum/.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
MNEMONIC = "12 keywords"
INFURA_PROJECT_ID=...
ALCHEMY_API_ID=...
ETHERSCAN_TEST_API_KEY=...
BSCSCAN_TEST_API_KEY=...
15 changes: 15 additions & 0 deletions ethereum/contracts/NFT.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// SPDX-License-Identifier: MIT

import './NFT/NFTLogics.sol';

pragma solidity ^0.8.13;

contract NFT is NFTLogics {
constructor(address _marketplaceAddress) ERC721('My Digital Marketplace', 'MDM') {
marketplaceAddress = _marketplaceAddress;
}

function createToken(string memory tokenURI) public returns (uint256) {
return _createToken(tokenURI);
}
}
7 changes: 7 additions & 0 deletions ethereum/contracts/NFT/INFT.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.13;

interface INFT {
event CreateTokenLog(uint256 indexed tokenId, string indexed tokenURI);
}
12 changes: 12 additions & 0 deletions ethereum/contracts/NFT/NFTContext.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// SPDX-License-Identifier: MIT

import './INFT.sol';
import '@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol';

pragma solidity ^0.8.13;

abstract contract NFTContext is ERC721URIStorage, INFT {
address internal owner;
uint256 internal _tokenIds;
address public marketplaceAddress;
}
16 changes: 16 additions & 0 deletions ethereum/contracts/NFT/NFTLogics.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// SPDX-License-Identifier: MIT
import './NFTContext.sol';
pragma solidity ^0.8.13;

abstract contract NFTLogics is NFTContext {
function _createToken(string memory tokenURI) internal returns (uint256) {
_tokenIds++;
uint256 newItemId = _tokenIds;

_mint(msg.sender, newItemId);
_setTokenURI(newItemId, tokenURI);
setApprovalForAll(marketplaceAddress, true);
emit CreateTokenLog(newItemId, tokenURI);
return newItemId;
}
}
31 changes: 31 additions & 0 deletions ethereum/contracts/NFTMarketplace.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// SPDX-License-Identifier: MIT
import './NFTMarketplace/NFTMarketplaceLogics.sol';
import './NFTMarketplace/NFTMarketplaceModifiers.sol';

pragma solidity ^0.8.13;

contract NFTMarketplace is NFTMarketplaceModifiers, NFTMarketPlaceLogics {
constructor() {
owner = payable(msg.sender);
}

function createMarketItem(
address nftContract,
uint256 tokenId,
uint256 price
) public payable nonReentrant {
_createMarketItem(nftContract, tokenId, price);
}

function buyItem(address nftContract, uint256 itemId) public payable nonReentrant {
_buyItem(nftContract, itemId);
}

function fetchUnsoldMarketItems() public view returns (MarketItem[] memory) {
return _fetchUnsoldMarketItems();
}

function fetchMyNFTsBoughtFromMarketplace() public view returns (MarketItem[] memory) {
return _fetchMyNFTsBoughtFromMarketplace();
}
}
31 changes: 31 additions & 0 deletions ethereum/contracts/NFTMarketplace/INFTMarketplace.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// SPDX-License-Identifier: MIT

import '@openzeppelin/contracts/token/ERC721/IERC721.sol';

pragma solidity ^0.8.13;

interface INFTMarketplace {
struct MarketItem {
uint256 itemId;
address nftContract;
uint256 tokenId;
address payable seller;
address payable owner;
uint256 price;
}

event CreateMarketItemLog(uint256 indexed itemId, address indexed nftContract, uint256 indexed tokenId, address seller, address owner, uint256 price);
event ItemSoldLog(uint256 indexed itemId, address indexed nftContract, uint256 indexed tokenId, address oldOwner, address newOwner);

function createMarketItem(
address nftContract,
uint256 tokenId,
uint256 price
) external payable;

function buyItem(address nftContract, uint256 itemId) external payable;

function fetchUnsoldMarketItems() external view returns (MarketItem[] memory);

function fetchMyNFTsBoughtFromMarketplace() external view returns (MarketItem[] memory);
}
14 changes: 14 additions & 0 deletions ethereum/contracts/NFTMarketplace/NFTMarketplaceContext.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// SPDX-License-Identifier: MIT

import './INFTMarketplace.sol';

pragma solidity ^0.8.13;

abstract contract NFTMarketplaceContext is INFTMarketplace {
uint256 internal _itemIds;
uint256 internal _itemsSold;

address payable owner;
uint256 listingPrice = 0.1 ether;
mapping(uint256 => MarketItem) public idToMarketItem;
}
78 changes: 78 additions & 0 deletions ethereum/contracts/NFTMarketplace/NFTMarketplaceLogics.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// SPDX-License-Identifier: MIT

import './NFTMarketplaceContext.sol';

pragma solidity ^0.8.13;

abstract contract NFTMarketPlaceLogics is NFTMarketplaceContext {
function _createMarketItem(
address nftContract,
uint256 tokenId,
uint256 price
) internal {
require(IERC721(nftContract).ownerOf(tokenId) == msg.sender, 'only owner of tokenId can create corresponding item');
require(price > 0, 'item price must be at least 1 wei');
require(msg.value == listingPrice, 'listing price is 0.1 ether');

_itemIds++;
uint256 itemId = _itemIds;
idToMarketItem[itemId] = MarketItem(itemId, nftContract, tokenId, payable(msg.sender), payable(address(0)), price);
IERC721(nftContract).transferFrom(msg.sender, address(this), tokenId);
emit CreateMarketItemLog(itemId, nftContract, tokenId, msg.sender, address(0), price);
}

function _buyItem(address nftContract, uint256 itemId) internal {
uint256 price = idToMarketItem[itemId].price;
uint256 tokenId = idToMarketItem[itemId].tokenId;
require(msg.value == price, 'submitted price differs from item price');

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

function _fetchUnsoldMarketItems() internal view returns (MarketItem[] memory) {
uint256 itemCount = _itemIds;
uint256 unsoldItemCount = _itemIds - _itemsSold;
uint256 currentIndex = 0;

MarketItem[] memory items = new MarketItem[](unsoldItemCount);
for (uint256 i = 0; i < itemCount; i++) {
if (idToMarketItem[i + 1].owner == address(0)) {
uint256 currentId = i + 1;
MarketItem storage currentItem = idToMarketItem[currentId];
items[currentIndex] = currentItem;
currentIndex += 1;
}
}

return items;
}

function _fetchMyNFTsBoughtFromMarketplace() internal view returns (MarketItem[] memory) {
uint256 totalItemCount = _itemIds;
uint256 itemCount = 0;
uint256 currentIndex = 0;

for (uint256 i = 0; i < totalItemCount; i++) {
if (idToMarketItem[i + 1].owner == msg.sender) {
itemCount += 1;
}
}

MarketItem[] memory items = new MarketItem[](itemCount);
for (uint256 i = 0; i < totalItemCount; i++) {
if (idToMarketItem[i + 1].owner == msg.sender) {
uint256 currentId = i + 1;
MarketItem storage currentItem = idToMarketItem[currentId];
items[currentIndex] = currentItem;
currentIndex += 1;
}
}

return items;
}
}
8 changes: 8 additions & 0 deletions ethereum/contracts/NFTMarketplace/NFTMarketplaceModifiers.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// SPDX-License-Identifier: MIT


import '@openzeppelin/contracts/security/ReentrancyGuard.sol';

pragma solidity ^0.8.13;

abstract contract NFTMarketplaceModifiers is ReentrancyGuard {}
8 changes: 8 additions & 0 deletions ethereum/migrations/1_NFTMarketplace&NFT_migration.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
const NFTMarketplace = artifacts.require('NFTMarketplace');
const NFT = artifacts.require('NFT');

module.exports = function (deployer) {
deployer.deploy(NFTMarketplace).then(function () {
return deployer.deploy(NFT, NFTMarketplace.address);
});
};
22 changes: 22 additions & 0 deletions ethereum/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"name": "truffle-nft-marketplace",
"version": "1.0.0",
"description": "",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "0xhamedETH",
"license": "MIT",
"dependencies": {
"@openzeppelin/contracts": "^4.5.0",
"@truffle/hdwallet-provider": "^2.0.4",
"ganache-cli": "^6.1.8",
"mocha": "^9.1.2",
"web3": "^1.6.0"
},
"devDependencies": {
"dotenv": "^16.0.0",
"prettier": "^2.5.1",
"prettier-plugin-solidity": "^1.0.0-beta.19"
}
}
Loading

0 comments on commit 80f39af

Please sign in to comment.