Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/0xapp123/nft-marketplace--avalanche
This is the Marketplace running on Avalanche Chain.
https://github.com/0xapp123/nft-marketplace--avalanche
avalanche evm marketplace nft react
Last synced: 25 days ago
JSON representation
This is the Marketplace running on Avalanche Chain.
- Host: GitHub
- URL: https://github.com/0xapp123/nft-marketplace--avalanche
- Owner: 0xapp123
- Created: 2024-04-02T06:41:08.000Z (10 months ago)
- Default Branch: master
- Last Pushed: 2024-04-09T10:28:37.000Z (10 months ago)
- Last Synced: 2024-11-10T12:46:00.375Z (3 months ago)
- Topics: avalanche, evm, marketplace, nft, react
- Language: JavaScript
- Homepage:
- Size: 1.21 MB
- Stars: 2
- Watchers: 1
- Forks: 1
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# NFT Marketplace on Avalanche
Step by step tutorial to build your own NFT marketplace on Avalanche using Hardhat and React.
# Table of contents
- [Introduction](#introduction)
- [Prerequisites](#prerequisites)
- [Requirements](#requirements)
- [Getting Started](#getting-started)
- [Building the workspace](#building-the-workspace)
- [Creating the NFT Token](#creating-the-nft-token)
- [Contracts for the marketplace](#contracts-for-the-marketplace)
- [Auction Contract](#auction-contract)
- [Starting with the functions](#starting-with-the-functions)
- [Events](#events)
- [Storage variables](#storage-variables)
- [Constructor function](#constructor-function)
- [Building the functions](#building-the-functions)
- [Get the auction state](#get-the-auction-state)
- [Placing bids](#placing-bids)
- [Cancel auction](#cancel-auction)
- [Withdraw Token](#withdraw-token)
- [Withdraw Funds](#withdraw-funds)
- [Get all bids](#get-all-bids)
- [Auction Manager Contract](#auction-manager-contract)
- [Building the functions](#building-the-functions-1)
- [Create auction](#create-auction)
- [Get Auctions](#get-auctions)
- [AVAX Fuji Testnet](#avax-fuji-testnet)
- [Deploying the contracts](#deploying-the-contracts)
- [React App](#react-app)
- [Building the form](#building-the-form)
- [Interacting with contracts](#interacting-with-contracts)
- [Contract ABI's](#contract-abis)
- [Detecting and connecting to metamask](#detecting-and-connecting-to-metamask)
- [Minting an NFT](#minting-an-nft)
- [Owned NFT's](#owned-nfts)
- [Creating an auction](#creating-an-auction)
- [Getting the list of auctions](#getting-the-list-of-auctions)
- [Building the auction page](#building-the-auction-page)
- [Rendering the selected auction](#rendering-the-selected-auction)
- [Auction Functions](#auction-functions)
- [Placing Bids](#placing-bids-1)
- [Withdraw Token](#withdraw-token-1)
- [Withdraw Funds](#withdraw-funds-1)
- [Cancel Auction](#cancel-auction-1)
- [Polishing the buttons](#polishing-the-buttons)
- [Place Bid Area](#place-bid-area)
- [Cancel Auction Button](#cancel-auction-button)
- [Withdraw Funds Button](#withdraw-funds-button)
- [Withdraw Token Button](#withdraw-token-button)
- [Finishing the React App](#finishing-the-react-app)
- [Using with other NFT contracts](#using-with-other-nft-contracts)
- [Next steps](#next-steps)
- [Tests](#tests)
- [Things to consider](#things-to-consider)
- [Deploying to the Avalanche Mainnet](#deploying-to-the-avalanche-mainnet)
- [Conclusion](#conclusion)# Introduction
We will be using [React JS](https://reactjs.org) to build the frontend of our NFT Marketplace and we will use [Ethers JS](https://docs.ethers.io/v5/) to interact with the smart contracts on the frontend. For the backend, we will be using our smart contracts that will be deployed on the [Avalanche](https://www.avax.network/) chain and that's all. Our NFT Marketplace will live on the blockchain. Totally decentralized! We will be using Hardhat to compile and deploy our smart contracts.
## Prerequisites
- Basic knowledge of [React JS](https://reactjs.org/).
- React is a JavaScript library for building user interfaces. React makes it easier to create interactive UIs. The whole UI of the NFT Marketplace is just a single file. You may use anything you would like to build your UI (Angular, Vanilla JS, Vue.js). The important part is to know how to interact with the blockchain and our smart contracts.
- Very basic knowledge of [Hardhat](https://hardhat.org/).
- Hardhat is a development environment to compile, deploy, test, and debug your solidity code. You may use [Truffle](https://www.trufflesuite.com/truffle) or any other framework that lets you deploy smart contracts as well. I do prefer using Hardhat.
- Basic knowledge of [Ethers JS](https://docs.ethers.io/v5/) library.
- [Ethers JS](https://docs.ethers.io/v5/) is a javascript library for interacting with the blockchain and our smart contracts. Once you get familiar with it, you may use it to interact with the chain in any javascript project. You may also use [Web3 JS](https://web3js.readthedocs.io/en/v1.5.0/) if you are more familiar with it. I find it easier to work with Ethers.
- Basic knowledge of [Solidity](https://docs.soliditylang.org/en/v0.8.6/#) language.
- We will be writing our smart contracts in **solidity**. A piece of basic knowledge is required for you to understand the concepts fully.## Requirements
- [Node JS](https://nodejs.org/en) and [npm](https://www.npmjs.com/) must be installed.
- [Hardhat](https://hardhat.org/) must be installed.
- [Metamask](https://metamask.io) extension must be installed on your browser.
- [create-react-app](https://www.npmjs.com/package/create-react-app) must be installed.# Getting Started
## Building the workspace
Let's get started by setting up our workspace using [Hardhat](https://hardhat.org/).
- Execute `$ npx hardhat init` in your working directory.
- When you are prompted on the terminal
- Choose `Create a basic sample project`.
- Add the `.gitignore` file.
- Install the dependencies.
- Delete the `Greeter.sol` file inside the contracts folder.This will set up our initial workspace.
## Creating the NFT Token
First, we need to create an NFT token that will be displayed in our marketplace.
Create a simple ERC-721 token.
[NFT.sol](NFT-Marketplace-dApp/contracts/NFT.sol)
```solidity
contract NFT is ERC721 {
using Counters for Counters.Counter;
Counters.Counter private _tokenIds;
mapping (uint => uint) public itemValue;
uint maxValue = 10000; // Max value of an itemconstructor() ERC721("Super NFT", "SPRNFT") {}
/**
Returns a random number
*/
function random() private view returns (uint) {
return uint(keccak256(abi.encodePacked(block.difficulty, block.timestamp, block.number)));
}function myItems() external view returns (uint[] memory items) {
// Returns an array of items that the user owns
items = new uint[](balanceOf(msg.sender));
uint _counter = 0;
for(uint i = 1; i < _tokenIds.current(); i++) { // i = 1 because the token counter is increased before the id is assigned
if(ownerOf(i) == msg.sender) { // if the user owns the item
items[_counter] = i; // add the item to the array
_counter++; // increase the counter
}
}
return items;
}function getItem() payable public returns (uint256) {
require(msg.value == 0.5 ether); // 0.5 AVAX is the cost of an item
_tokenIds.increment(); // Increase the counter
uint256 newItemId = _tokenIds.current(); // Get the current counter value
_mint(msg.sender, newItemId); // Mint the new item to the user
itemValue[newItemId] = random() % maxValue; // Set the item value to a random number modulus used to make sure that the value isn't bigger than maxValue
return newItemId; // Return the new item id
}
}
```**ALERT**
> **Secure random-number generation in the blockchain is a very difficult problem. Our method here is insecure, but since this is just an example, it will be good enough for our purposes.**
**ALERT**
The logic here is very simple.
- User calls the getItem() function and pays 0.5 AVAX
- The value of the token is determined using a random number.
- The token is minted to the user.And that's all.
# Contracts for the marketplace
We will have two contracts, `AuctionManager` and `Auction` contracts. AuctionManager contract will create the auctions by deploying the Auction contract using the parameters.
Here is how it will work:- The auction creator enters parameters for direct buy price, starting price, minimum bid increment, the token id, and the auction end time.
- The auction creator gives approval for the NFT that will be auctioned to the AuctionManager.
- The AuctionManager creates an Auction with the parameters given and then transfers the NFT to the newly created Auction contract.
- After the auction is completed, the auction creator and the auction winner must call the withdrawal functions to retrieve their tokens.## Auction Contract
### Starting with the functions
Our auction contract will allow users to place bids, cancel the auction if there are no bids and withdraw their tokens and funds after the auction has been completed. We will also need a function to get the current state of the auction.
```solidity
contract Auction {
function placeBid() payable external returns(bool){} // Place a bid on the auction
function withdrawToken() external returns(bool){} // Withdraw the token after the auction is over
function withdrawFunds() external returns(bool){} // Withdraw the funds after the auction is over
function cancelAuction() external returns(bool){} // Cancel the auction
function getAuctionState() public view returns(uint) {} // Get the auction state
function allBids() external view returns (address[] memory, uint256[] memory) {} // Returns a list of all bids and addresses
}
```### Events
There will be four events in the contract.
`NewBid` will be emitted each time there is a new bid.
`WithdrawToken` will be emitted when the highest bidder withdraws the token.
`WithdrawFunds` will be emitted when the auction owner withdraws the funds.
`AuctionCancelled` will be emitted when the auction gets canceled.```solidity
contract Auction {
event NewBid(address bidder, uint bid); // A new bid was placed
event WithdrawToken(address withdrawer); // The auction winner withdrawed the token
event WithdrawFunds(address withdrawer, uint256 amount); // The auction owner withdrawed the funds
event AuctionCancelled(); // The auction was cancelled
}
```### Storage variables
We will need to declare a few variables.
- `endTime` is the end timestamp of the auction. The auction will end if the current timestamp is equal or greater than the `endTime`.
- `startTime` is the timestamp that marks the start of the auction.
- `maxBid` the amount of max bid.
- `maxBidder` is the address of the max bidder.
- `creator` is the address of the auction creator.
- `bids` array of bids, we will use this to display recent bids on the web page.
- `tokenId` is the id of the token that has been auctioned.
- `isCancelled` will be true if the auction has been canceled.
- `isDirectBuy` will be true if someone placed a bit with a higher or equal value than the direct buy price.
- `minIncrement` is the minimum increment for the bid.
- `directBuyPrice` is the price for a direct buy.
- `startPrice` is the starting price for the auction.
- `nftAddress` is the address of the NFT contract
- `_nft` is the NFT token.```solidity
contract Auction {
uint256 public endTime; // Timestamp of the end of the auction (in seconds)
uint256 public startTime; // The block timestamp which marks the start of the auction
uint maxBid; // The maximum bid
address maxBidder; // The address of the maximum bidder
address creator; // The address of the auction creator
Bid[] public bids; // The bids made by the bidders
uint tokenId; // The id of the token
bool isCancelled; // If the the auction is cancelled
bool isDirectBuy; // True if the auction ended due to direct buy
uint minIncrement; // The minimum increment for the bid
uint directBuyPrice; // The price for a direct buy
uint startPrice; // The starting price for the auction
IERC721 _nft; // The NFT tokenenum AuctionState {
OPEN,
CANCELLED,
ENDED,
DIRECT_BUY
}struct Bid { // A bid on an auction
address sender;
uint256 bid;
}
}
```We would be using block numbers instead of timestamps. If we were developing this application on another chain such as Ethereum Mainnet, block timestamps are being set by the miners, and they are spoofable.
However, in Avalanche, there is no set block rate; thus, we cannot rely on block numbers. We will be using `block.timestamp` to measure time. Timestamps are guaranteed to be within 30 seconds of real-time therefore we do not need to worry about it. [Read more about it here.](https://support.avax.network/en/articles/5106526-measuring-time-in-smart-contracts).The auction will end when the current timestamp is greater than or equal to the `endTime`. `endTime` is the end timestamp of the auction.
### Constructor function
We will need to get some parameters from the `AuctionManager` contract.
```solidity
constructor(address _creator,uint _endTime,uint _minIncrement,uint _directBuyPrice, uint _startPrice,address _nftAddress,uint _tokenId){
creator = _creator; // The address of the auction creator
endTime = block.timestamp + _endTime; // The timestamp which marks the end of the auction (now + 30 days = 30 days from now)
startBlock = block.timestamp; // The timestamp which marks the start of the auction
minIncrement = _minIncrement; // The minimum increment for the bid
directBuyPrice = _directBuyPrice; // The price for a direct buy
startPrice = _startPrice; // The starting price for the auction
_nft = IERC721(_nftAddress); // The address of the nft token
nftAddress = _nftAddress;
tokenId = _tokenId; // The id of the token
maxBidder = _creator; // Setting the maxBidder to auction creator.
}
```### Building the functions
#### Get the auction state
Let's start with the `getAuctionState` function as we are going to use it in other functions.
First, we need to check if the auction has been canceled and return `AuctionState.CANCELLED` in that case.
Then, we need to check if anyone bid more or equal to the direct buy price and return `AuctionState.DIRECT_BUY` in that case.
Then, we need to check if the current timestamp is greater or equal to the `endTime` and return `AuctionState.ENDED` in that case.
Otherwise, we will return `AuctionState.OPEN`.```solidity
// Get the auction state
function getAuctionState() public view returns(AuctionState) {
if(isCancelled) return AuctionState.CANCELLED; // If the auction is cancelled return CANCELLED
if(isDirectBuy) return AuctionState.DIRECT_BUY; // If the auction is ended by a direct buy return DIRECT_BUY
if(block.timestamp >= endTime) return AuctionState.ENDED; // The auction is over if the block timestamp is greater than the end timestamp, return ENDED
return AuctionState.OPEN; // Otherwise return OPEN
}
```#### Placing bids
Let's start building the function for placing bids.
The user calls the `placeBid` function and sends an amount of AVAX.Firstly, there are few things we need to check;
- The bidder cannot be the auction creator
- The auction must be open.
- The bid must be greater than the start price.
- The bid must be greater than the highest bid + minimum bid increment.```solidity
function placeBid() payable external returns(bool){
require(msg.sender != creator); // The auction creator can not place a bid
require(getAuctionState() == AuctionState.OPEN); // The auction must be open
require(msg.value > startPrice); // The bid must be higher than the starting price
require(msg.value > maxBid + minIncrement); // The bid must be higher than the current bid
}
```Next, we will set the new max bid and the max bidder. After that, we will store the value of the last highest bid and the bidder because we will need this information later.
```solidity
address lastHightestBidder = maxBidder; // The address of the last highest bidder
uint256 lastHighestBid = maxBid; // The last highest bid
maxBid = msg.value; // The new highest bid
maxBidder = msg.sender; // The address of the new highest bidder
```Next, we have to check if the bid (`msg.value`) is greater or equal to the direct buy price. In that case, we will need to set the `isDirectBuy` to `true`; thus, close the auction.
```solidity
if(msg.value >= directBuyPrice){ // If the bid is higher or equal to the direct buy price
isDirectBuy = true; // The auction has ended
}
```Next, we have to push the value of the new bid into the bids array.
```solidity
bids.push(Bid(msg.sender,msg.value));
```Finally, if there is a previous bid, we have to refund the previous highest bid to the previous bidder. Also, we should emit a NewBid event.
```solidity
if(lastHighestBid != 0){ // if there is a bid
address(uint160(lastHightestBidder)).transfer(lastHighestBid); // refund the previous bid to the previous highest bidder
}emit NewBid(msg.sender,msg.value); // emit a new bid event
return true;
```Here is the complete function
```solidity
// Place a bid on the auction
function placeBid() payable external returns(bool){
require(msg.sender != creator); // The auction creator can not place a bid
require(getAuctionState() == AuctionState.OPEN); // The auction must be open
require(msg.value > startPrice); // The bid must be higher than the starting price
require(msg.value > maxBid + minIncrement); // The bid must be higher than the current bid + the minimum incrementaddress lastHightestBidder = maxBidder; // The address of the last highest bidder
uint256 lastHighestBid = maxBid; // The last highest bid
maxBid = msg.value; // The new highest bid
maxBidder = msg.sender; // The address of the new highest bidder
if(msg.value >= directBuyPrice){ // If the bid is higher than the direct buy price
isDirectBuy = true; // The auction has ended
}
bids.push(Bid(msg.sender,msg.value)); // Add the new bid to the list of bidsif(lastHighestBid != 0){ // if there is a bid
address(uint160(lastHightestBidder)).transfer(lastHighestBid); // refund the previous bid to the previous highest bidder
}emit NewBid(msg.sender,msg.value); // emit a new bid event
return true; // The bid was placed successfully
}
```#### Cancel auction
This is a very simple function. If there are no bids and the auction is open, the auction creator should be able to cancel the auction.
```solidity
function cancelAuction() external returns(bool){ // Cancel the auction
require(msg.sender == creator); // Only the auction creator can cancel the auction
require(getAuctionState() == AuctionState.OPEN); // The auction must be open
require(maxBid == 0); // The auction must not be cancelled if there is a bid
isCancelled = true; // The auction has been cancelled
_nft.transferFrom(address(this), creator, tokenId); // Transfer the NFT token to the auction creator
emit AuctionCanceled(); // Emit Auction Canceled event
return true;
}
```#### Withdraw Token
After the auction has been completed, the highest bidder should be able to withdraw the NFT token.
The `msg.sender` must be the highest bidder and the auction must be completed by either direct buy or timeout, otherwise the function must revert. After that, The NFT with the token id `tokenId` will be transferred to the highest bidder.We've set the max bidder initial value to the auction creator's wallet address, so if the auction times out and no one bids, the auction creator will be able to withdraw the token.
```solidity
// Withdraw the token after the auction is over
function withdrawToken() external returns(bool){
require(getAuctionState() == AuctionState.ENDED || getAuctionState() == AuctionState.DIRECT_BUY); // The auction must be ended by either a direct buy or timeout
require(msg.sender == maxBidder); // The highest bidder can only withdraw the token
_nft.transferFrom(address(this), maxBidder, tokenId); // Transfer the token to the highest bidder
emit WithdrawToken(maxBidder); // Emit a withdraw token event
}
```#### Withdraw Funds
After the auction has been completed, the auction creator should be able to withdraw the funds.
The `msg.sender` must be the auction owner and the auction must be completed by either a direct buy or timeout; otherwise, the function must revert. After that, the max bid amount must be transferred to the auction creator.```solidity
// Withdraw the funds after the auction is over
function withdrawFunds() external returns(bool){
require(getAuctionState() == AuctionState.ENDED || getAuctionState() == AuctionState.DIRECT_BUY); // The auction must be ended by either a direct buy or timeout
require(msg.sender == creator); // The auction creator can only withdraw the funds
address(uint160(msg.sender)).transfer(maxBid);
emit WithdrawFunds(msg.sender,maxBid); // Emit a withdraw funds event
}
```#### Get all bids
We will need a function to get a list of all bids and the bidders.
```solidity
// Returns a list of all bids and addresses
function allBids()
external
view
returns (address[] memory, uint256[] memory)
{
address[] memory addrs = new address[](bids.length);
uint256[] memory bidPrice = new uint256[](bids.length);
for (uint256 i = 0; i < bids.length; i++) {
addrs[i] = bids[i].sender;
bidPrice[i] = bids[i].bid;
}
eturn (addrs, bidPrice);
}
```Our **Auction** contract is ready. Here is the complete code:
[Auction Contract](NFT-Marketplace-dApp/contracts/Auction.sol)## Auction Manager Contract
We will use this contract to get a list of all auctions, and to create new ones.
Let's start with the basic structure.```solidity
pragma solidity ^0.7.0;import "./Auction.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";contract AuctionManager {
uint _auctionIdCounter; // auction Id counter
mapping(uint => Auction) public auctions; // auctionsfunction createAuction(uint _endTime, uint _minIncrement, uint _directBuyPrice,uint _startPrice,address _nftAddress,uint _tokenId) external returns (bool) {} // create an auction
function getAuctions() external view returns(address[] memory _auctions) {} // Return a list of all auctions
function getAuctionInfo(address[] calldata _auctionsList) external view
returns (
uint256[] memory directBuy,
address[] memory owner,
uint256[] memory highestBid,
uint256[] memory tokenIds,
uint256[] memory endTime,
uint256[] memory startPrice,
uint256[] memory auctionState
) {} // Return the information of each auction address
}
```We will need two functions, one for creating an auction and the other one for getting a list of auctions. We will use the counter to assign a unique id for each auction so we can keep track of them.
### Building the functions
#### Create auction
This is a very straightforward function.
First, we need to check that:
- Direct buy price is greater than zero.
- Start price is greater than the direct buy price.
- End time is greater than 5 minutes, so no one will be able to create an auction that lasts few seconds. That wouldn't make sense.```solidity
require(_directBuyPrice > 0); // direct buy price must be greater than 0
require(_startPrice < _directBuyPrice); // start price is smaller than direct buy price
require(_endTime > 5 minutes); // end time must be greater than 5 minutes (setting it to 5 minutes
```Then, we will create a new Auction contract using the parameters and assign an id to it.
```solidity
uint auctionId = _auctionIdCounter; // get the current value of the counter
_auctionIdCounter++; // increment the counter
Auction auction = new Auction(msg.sender, _endTime, _minIncrement, _directBuyPrice, _startPrice, _nftAddress, _tokenId); // create the auction
```Finally, we will transfer the NFT token to the newly generated Auction contract and update our auctions map.
```solidity
IERC721 _nftToken = IERC721(_nftAddress); // get the nft token
_nftToken.transferFrom(msg.sender, address(auction), _tokenId); // transfer the token to the auction
auctions[auctionId] = auction; // add the auction to the map
return true;
```See the complete function.
```solidity
// create an auction
function createAuction(uint _endTime, uint _minIncrement, uint _directBuyPrice,uint _startPrice,address _nftAddress,uint _tokenId) external returns (bool){
require(_directBuyPrice > 0); // direct buy price must be greater than 0
require(_startPrice < _directBuyPrice); // start price is smaller than direct buy price
require(_endTime > 5 minutes); // end time must be greater than 5 minutes (setting it to 5 minutes for testing you can set it to 1 days or anything you would like)uint auctionId = _auctionIdCounter; // get the current value of the counter
_auctionIdCounter++; // increment the counter
Auction auction = new Auction(msg.sender, _endTime, _minIncrement, _directBuyPrice, _startPrice, _nftAddress, _tokenId); // create the auction
IERC721 _nftToken = IERC721(_nftAddress); // get the nft token
_nftToken.transferFrom(msg.sender, address(auction), _tokenId); // transfer the token to the auction
auctions[auctionId] = auction; // add the auction to the map
return true;
}
```#### Get Auctions
This function will iterate over all auctions and return a list of auction addresses.
```solidity
// Return a list of all auctions
function getAuctions() external view returns(address[] memory _auctions) {
_auctions = new address[](_auctionIdCounter); // create an array of size equal to the current value of the counter
for(uint i = 0; i < _auctionIdCounter; i++) { // for each auction
_auctions[i] = address(auctions[i]); // add the address of the auction to the array
}
return _auctions; // return the array
}
```Then, we can use this list of auctions to display them on the web page. We will need a function to obtain information about the auctions. Given an array of auction addresses, we would like to get direct buy price, auction creator, starting price, highest bid, token id, auction state, and the end time.
```solidity
// Return the information of each auction address
function getAuctionInfo(address[] calldata _auctionsList)
external
view
returns (
uint256[] memory directBuy,
address[] memory owner,
uint256[] memory highestBid,
uint256[] memory tokenIds,
uint256[] memory endTime,
uint256[] memory startPrice,
uint256[] memory auctionState
)
{
directBuy = new uint256[](_auctionsList.length); // create an array of size equal to the length of the passed array
owner = new address[](_auctionsList.length); // create an array of size equal to the length of the passed array
highestBid = new uint256[](_auctionsList.length);
tokenIds = new uint256[](_auctionsList.length);
endTime = new uint256[](_auctionsList.length);
startPrice = new uint256[](_auctionsList.length);
auctionState = new uint256[](_auctionsList.length);for (uint256 i = 0; i < _auctionsList.length; i++) { // for each auction
directBuy[i] = Auction(auctions[i]).directBuyPrice(); // get the direct buy price
owner[i] = Auction(auctions[i]).creator(); // get the owner of the auction
highestBid[i] = Auction(auctions[i]).maxBid(); // get the highest bid
tokenIds[i] = Auction(auctions[i]).tokenId(); // get the token id
endTime[i] = Auction(auctions[i]).endTime(); // get the end time
startPrice[i] = Auction(auctions[i]).startPrice(); // get the start price
auctionState[i] = uint(Auction(auctions[i]).getAuctionState()); // get the auction state
}return ( // return the arrays
directBuy,
owner,
highestBid,
tokenIds,
endTime,
startPrice,
auctionState
);
}
```Here is the complete code: [AuctionManager.sol](NFT-Marketplace-dApp/contracts/AuctionManager.sol)
That's all for the contracts!
# AVAX Fuji Testnet
We are going to test the marketplace on AVAX Fuji Testnet. First, you need to add AVAX Fuji Testnet to metamask. Open metamask and view networks, then click on `Custom RPC`.
![Networks](images/nft-marketplace-networks.png)
We will deploy our contracts on FUJI testnet.
FUJI Testnet Settings:- Network Name: Avalanche FUJI C-Chain
- New RPC URL: https://api.avax-test.network/ext/bc/C/rpc
- ChainID: 43113
- Symbol: AVAX
- Explorer: https://cchain.explorer.avax-test.networkYou may find the configurations for the Avalanche Mainnet and Local Testnet (AVASH) [here](https://docs.avax.network/build/tutorials/smart-contracts/deploy-a-smart-contract-on-avalanche-using-remix-and-metamask#step-1-setting-up-metamask).
Next, we will add the network configuration in hardhat config file [`hardhat.config.js`](NFT-Marketplace-dApp/hardhat.config.js). If you do not know how that file works then take a look at [here](https://hardhat.org/config/#networks-configuration).
```js
networks:{
...
fuji: {
url: "https://api.avax-test.network/ext/bc/C/rpc",
chainId: 43113,
accounts: [
"PRIVATE_KEY",
],
},
}
```Lastly, we will need some AVAX to deploy our contracts. Use this [AVAX Fuji Testnet Faucet
](https://faucet.avax-test.network/) to get some test AVAX for free.# Deploying the contracts
We need to deploy our `NFT` and `AuctionManager` contracts to the Fuji Testnet. We will use hardhat to deploy the contracts, [learn more about it here](https://hardhat.org/guides/deploying.html). Start by editing the [`scripts/deploy.js`](NFT-Marketplace-dApp/scripts/deploy.js) file.
```js
const main = async () => {
const NftToken = await ethers.getContractFactory("NFT"); // NFT token contract
const nftToken = await NftToken.deploy(); // NFT token contract instance
await nftToken.deployed(); // wait for contract to be deployed
const nftTokenAddress = await nftToken.address; // NFT token contract addressconst AuctionManager = await ethers.getContractFactory("AuctionManager"); // Auction Manager contract
const auctionManager = await AuctionManager.deploy(); // Auction Manager contract instance
await auctionManager.deployed(); // wait for contract to be deployed
const auctionManagerAddress = await auctionManager.address; // Auction Manager contract addressconsole.log(`NFT deployed to: ${nftTokenAddress}`); // NFT token contract address
console.log(`Auction Manager deployed to: ${auctionManagerAddress}`); // Auction Manager contract address
};main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error);
process.exit(1);
});
```After you are done editing [`deploy.js`](deploy.NFT-Marketplace-dApp/scripts/deploy.js), execute the following lines on your terminal to run the [`deploy.js`](deploy.NFT-Marketplace-dApp/scripts/deploy.js) script.
```shell
$ npx hardhat compile # Compiles the contracts
$ npx hardhat run scripts/deploy.js --network fuji # runs the "deploy.js" script on fuji test network, "fuji" is specified inside the hardhat config file
```Pretty simple! If this looks unfamiliar to you, you may want to take a look at [hardhat guides](https://hardhat.org/guides/deploying.html).
Do not forget to note the addresses, as we will need them afterward to interact with the contracts.
![Deployed](images/nft-marketplace-deployed.png)# React App
Let's build an interface to interact with our marketplace. We are going to use `react` and `ether.js`.
Execute the following lines on your terminal to get started.
```bash
create-react-app frontend # creates a react app inside the frontend folder
cd frontend # go inside the frontend folder
npm install --save ethers # install ethers package
npm run start # start the react app
```Add bootstrap CDN in the head section of [`public/index.html`](NFT-Marketplace-dApp/frontend/public/index.html) file. We will use bootstrap to speed up.
```diff
...
+...