Select Page

Develop NFT marketplace on Avalanche

dApp on Algorand

With the emergence of NFT marketplaces, people now have an opportunity to showcase their collectibles digitally. This also implies that the people with digital assets and collectibles can manage their assets effectively on a more secure and digital platform. NFT marketplaces are lucrative as they let people trade and exchange their digital commodities minted and stored on the marketplace.

From digital collectibles and assets to the gaming industry, NFT marketplace development powers all industries globally. Some fundamental properties of an NFT marketplace that adds to its credibility are as follows:

  • Unified and distinctive tokens
  • Rareness
  • Ownership rights
  • Transparency
  • Indivisibility
  • Interoperability
  • Secure asset transfer
  • Different blockchain and token compatibility

People prefer different blockchains as per their feasibility for NFT marketplace development like Ethereum, Binance, etc. One such robust blockchain preferred by people for NFT marketplace development is Avalanche. One of the major reasons people prefer a blockchain like Avanlache is that it uses the Proof-of-Stake consensus mechanism instead of Proof-of-Work. PoS increases the transaction speed and lowers network congestion on the Avalanche network.

Without further ado, let’s dive into the basics of Avalanche protocol and understand the process of NFT marketplace development on it.

Brief about Avalanche Network

Avalanche is a high-performance, customizable, scalable and secure blockchain network. It is one of the best decentralized smart contract platforms designed to scale global finance with instant transaction finality. Avalanche focuses on three major use cases as follows:

  • Developing and launching scalable applications ranging from permissioned to permissionless deployments.
  • Developing arbitrarily compact digital assets with customizable rules and covenants.

The major difference between Avalanche and other blockchain networks lies in the consensus protocol. Avalanche network functions via a novel PoS consensus approach which helps it achieve the security, quick finality and optimum level of throughput without minimizing decentralization of the network. It has an overarching motive to provide a unified platform for creating, transferring and trading digital assets in the form of NFTs.

Native token

Avalanche network’s native token AVAX is a hard-capped, scarce asset used for paying the fees, securing the platform by staking and providing a basic unit of account among the various subnets built on the Avalanche platform.

1 nAVAX = 0.000000001 AVAX

This platform has an easy user interface as anybody can build custom decentralized applications on it along with leveraging the unique advantages of Avalanche’s consensus model. Avalanche supports different consensus machines like WASM and EVM that are built using the GO programming language.

How does Avalanche’s consensus work?

Protocols in the Avalanche ecosystem function via repeated sub-sampled voting. At the time of determining whether a transaction is to be accepted or rejected, the validator will request a small subset of validators to confirm the state of the transaction. In the cases where the validator thinks that the transaction is invalid, has rejected the transaction already, or wants a conflicting transaction, the validator will then respond in the form of transaction rejection. In the opposite case, the validator will perceive that the transaction is accepted.

In case a large proportion (alpha a) of the validators tested responded in favor of accepting the transaction, then the validator will want to accept the transaction. In that scenario, when it is questioned about the transaction’s future, it will give a response for the transaction’s acceptance. In the same way, the validator will think of rejecting the transaction if a large proportion of the validators respond in favor of rejecting the transaction.

The validator will repeat the sampling process till the time all the alphas of the validators who were queried, respond in a similar way (accept or reject) for beta continuous rounds.

In the default case when a transaction has zero conflicts, the finalization is done spontaneously. When the conflicts happen, the unbiased validators instantly cluster around the conflicting transactions and enter a positive feedback loop until all the appropriate validators favor the transaction. This default case results in the acceptance of non-conflicting transactions and the acceptance of conflicting transactions.

Avalanche powers the Snowman Consensus Protocol. It is a chain-optimized consensus protocol that powers the network with high throughput, optimal smart contract functioning and maintains the network order. Avalanche platform features three built-in blockchains known as the Exchange Chain (X-Chain), Platform Chain (P-Chain) and the Contract Chain (C-Chain). Both the P-Chian and the C-Chain incorporate the Snowman consensus mechanism.

Now that we are familiar with the features of the Snowman Consensus Protocol, let’s look at some of its key features.

What are the key features of Snowman?

The fundamental features of the Snowman Consensus Protocol are as follows:

Speed

Snowman provides a novel consensus protocol that is developed by a team of Cornell computer scientists and has the capacity to permanently finalize transactions in approximately 1 second.

Scalability

Snowman increases the transaction processing power of the blockchain network by 4500 transactions per second. This is equal to an order of magnitude greater than all the existing blockchains.

Security

It ensures high security and guarantees network functioning well above the 51% standard of all other blockchain networks.

Flexible

Snowman Consensus Protocol helps in the easy creation of custom blockchains and dApps that have arbitrary logic.

Sustainability

It utilizes a sustainable Proof-of-Stake consensus algorithm instead of a Proof-of-Work consensus algorithm.

Smart contract support

Snowman Consensus Protocol also supports the creation of the Solidity smart contracts using the Ethereum tools like Remix, Truffle, Metamask; etc.

Private and public blockchains

Snowman consensus mechanism also helps in the seamless creation of own private and public blockchains on the Avalanche network.

Built for finance

It provides native support for easy development and trading the digital smart assets with custom and complex rulesets.

Let’s now explore the Avalanche architecture in the next section.

What are the benefits of developing on the Avalanche platform?

Avalanche offers innumerable benefits for its users. Talking about development and convenience, Avalanche has three main benefits as the following:

Fast and lost cost Solidity compatible dApp development

Avalanche protocol helps in the development and launch of robust Ethereum dApps. These decentralized applications quickly confirm and then process thousands of transactions. The TPS rate of the Avalanche platform is way above that of the other blockchain platforms.

Fundamental properties and the components of the platform, for instance, the subnetwork model, virtual machine, ethereum-standard RPC calls, etc; power the performance of the dApps and support the users by providing a superior experience.

Deployment of permissioned and customized blockchains

Avalanche functions in a way to caters to the diverse needs of its users. Therefore, it facilitates the deployment of custom-made blockchain platforms to suit the unique application requirements. Users can easily develop all the core components required for building a blockchain, for instance, the virtual machine lays the foundation for blockchain functioning.

Easy access to the network

The network powers the people to scale up to million other validators engaged voluntarily in the validation process. The moment someone buys a token, the person can then instantly join the network and participate as a validator. Avalanche also does not ask for complexly configured hardware to allow the people to join in.

Now that we know about the perks of developing on the Avalanche platform let us explore the step-by-step process of NFT marketplace development in the next section.

Launch a scalable and fast NFT Marketplace powered by Avalanche

Avalanche NFT Marketplace Development Company

How to develop an NFT marketplace on Avalanche?

In this NFt marketplace development process, React JS will be used to build the frontend and Ether JS for the smart interaction on the frontend. For the backend development, Avalanche smart contracts compiled and deployed using Hardhat will be used.

Pre-requisites

  • React JS
  • Hardhat
  • Ether JS
  • Solidity

Requirements

  • Pre-install Node JS and npm
  • Pre-install Hardhat
  • Pre-install Metamask browser extension
  • Pre-install create-react-app

Step 1

Build the workspace

Set up the workspace using the Hardhat and execute the

$ npx hardhat init

in the working directory. Then as prompted on the terminal, select:

Create a basic sample project

and add the below-mentioned file:

.gitignore

After doing the above steps, install all the dependencies and then delete the below-mentioned file from inside the contracts folder:

Greeter.sol

The initial workspace is now fully set up.

Step 2

NFT token creation

Mint the NFT token that will be stored and displayed on the NFT marketplace. For this, create a basic ERC-721 token by using the following command:

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 item
constructor() 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;
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
}
}

The logic in the above codes is very simple:

  • The user will call the getItem() function and then will pay the 0.5AVAX
  • Then the value of the token will be estimated via a random number
  • Lastly, the token will be minted

Step 3

Auction contract

In this part of development, two contracts namely the AuctionManager and the Auction contracts will be used. The AuctionManger contract will develop all the auctions by deploying the Auction contract via the parameters. It works in the following way:

  • The auction creator will enter the parameters targeting the direct buy price, starting price, minimum bid increment, auction endpoint and the token id.
  • The auction creator then approves the minted NFT to be auctioned to the AuctionManager contract.
  • The AuctionManager contract builds an auction using the parameters given on the platform and sends the minted NFT to the newly developed Auction contract.
  • After the auction is done, the auction creator and the winner will have to call all the withdrawal functions for the retrieval of their tokens.

Start with the auction contract functions

This auction contract will allow all the users to place their bids, cancel the entire auction in case of zero bids and withdraw all their funds and tokens after the completion of the auction. The following function returns the current position of the auction:

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 are four events in the contract as given below:

  • NewBid
  • WithdrawnToken
  • WithdrawFunds
  • AuctionCancelled

The NewBid event will be emitted every time when there is a new bid. The WithdrawToken will be emitted in a situation where the highest bidder withdraws his token. WithdrawFunds will be emitted at the time when the auction owner withdraws his funds. Lastly, the AuctionCancelled event will be emitted when the auction is canceled.

Follow the below-mentioned codes for the above events:

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

In this part, the user is required to declare some new variables as defined below:

  • endTime – This is defined as the auction’s end timestamp. The auction is bound to end if the current timestamp is equal to or greater than the actual endTime.
  • startTime – This is the timestamp that sets the beginning of the auction.
  • maxBid – This is the number of maximum bids.
  • maxBidder – maxBidder is the address of the maximum bidder on the network.
  • creator – Creator is defined as the auction creator’s address on the network.
  • bids – These are the array of bids used to display the current bids on the web page.
  • tokenId – This is the id of the token auctioned on the network.
  • isCancelled – This event is active when the auction has been canceled.
  • isDirectBuy – This event is active when someone places a bit with higher or of a value that is equal to the direct buying price.
  • minIncrement – This is the event that activates the minimum increment for the bid.
  • directBuyPrice – This event specifies the direct price for the auction.
  • startPrice – This is the starting price of the auction.
  • nftAddress – nftAddress states the address of an NFT contract.
  • nft – This is the event stating the NFT token minted on the network.

Follow the below-mentioned codes for regulating the above events:

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 token
1enum AuctionState { 2 OPEN, 3 CANCELLED, 4 ENDED, 5 DIRECT_BUY 6} 7 8struct Bid { // A bid on an auction 9 address sender; 10 uint256 bid; 11}
}

Block numbers will be used instead of timestamps in this process. In Avalanche there is no specified block rate, therefore the user should not rely on the block numbers. They should use the block.timestamp to measure the time of block mining.

The auction process will end when the present timestamp is greater than or equal to the endTime.

Constructor function

Let’s now get some parameters for the Auction Manager contract in this section. Follow the codes given below for the same:

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

Let us begin with the getAuctionState event. Firstly, check the auction if it has been canceled and then return the AuctionState.CANCELLED in that situation. After that, check if anyone bids more than or equal to the direct buying price and then return the AuctionState.DIRECT_BUY in that situation. After that, check if the current timestamp is greater than or equal to the current endTIme and then return the AuctionState.ENDED in that case. Otherwise, return the AuctionState.OPEN.

Follow the below-mentioned codes for the above events:

// 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
}

Then start placing the bids. Call the placeBid function and then send a specific amount of AVAX.

Before doing this check the following:

  • The bidder should not be the auction creator
  • The auction should be open
  • The bid should be more than the starting price
  • The bid should be more than the highest bidding amount along with the bid increment

Now follow the below-mentioned codes to place the bids:

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
}

After this, set a new max bidder and then store the value of the last highest bid and the bidder as this information is required later in the process.

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

Then, check if the bid msg.value is more than or equal to the direct buy price. In that case, set the isDirectBuy to true; and then close the auction.

if(msg.value >= directBuyPrice){ // If the bid is higher or equal to the direct buy price
isDirectBuy = true; // The auction has ended
}

After this, push the value of new bids in the bids array.

bids.push(Bid(msg.sender,msg.value));

Lastly, if there is a previous bid then, refund the highest previous bid to the bidder of the previous auction. Then emit a NewBid event by using the following codes:

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;

Below mentioned is the complete function of the bidding process:

// 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 increment
1address lastHightestBidder = maxBidder; // The address of the last highest bidder 2uint256 lastHighestBid = maxBid; // The last highest bid 3maxBid = msg.value; // The new highest bid 4maxBidder = msg.sender; // The address of the new highest bidder 5if(msg.value >= directBuyPrice){ // If the bid is higher than the direct buy price 6 isDirectBuy = true; // The auction has ended 7} 8bids.push(Bid(msg.sender,msg.value)); // Add the new bid to the list of bids 9 10if(lastHighestBid != 0){ // if there is a bid 11 address(uint160(lastHightestBidder)).transfer(lastHighestBid); // refund the previous bid to the previous highest bidder 12} 13 14emit NewBid(msg.sender,msg.value); // emit a new bid event 15return true; // The bid was placed successfully
}

Cancel auction

Follow the below-mentioned codes to cancel an auction:

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 completing the auction, the bidder with the highest bidding amount should be able to withdraw the NFT tokens. Then msg.sender should be the bidder with the highest amount and the auction should be completed either via direct buy or timeout, otherwise, the function will revert. After that, the NFT with token id tokenId will be sent to the highest bidder.

Set the maximum bidder’s initial value as per the auction creator’s wallet address, so in a case where the auction times out and no one is ready to bid, the auction creator gets to withdraw the token.

// 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 completing the auction, the auction creator should be able to withdraw all the funds. Make sure that the msg.sender is the auction owner and the auction is completed by either a direct buy or by timeout, otherwise the function will revert. After that, the maximum bid should be sent to the auction creator.

// 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 the bids

Get a function to retrieve the list of the bidders and the bids:

// Returns a list of all bids and addresses
function allBids()
external
view
returns (address[] memory, uint256[] memory)
{
address[] memory addrs = new address;
uint256[] memory bidPrice = new uint256;
for (uint256 i = 0; i < bids.length; i++) {
addrs[i] = bids[i].sender;
bidPrice[i] = bids[i].bid;
}
eturn (addrs, bidPrice);
}

Now the Auction contract is ready.

Step 4

Auction contract manager

Use the Auction contract manager to retrieve the list of all the auctions and to make the new ones. Follow the codes given below for a basic structure of this:

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; // auctions
1function createAuction(uint _endTime, uint _minIncrement, uint _directBuyPrice,uint _startPrice,address _nftAddress,uint _tokenId) external returns (bool) {} // create an auction 2function getAuctions() external view returns(address[] memory _auctions) {} // Return a list of all auctions 3function getAuctionInfo(address[] calldata _auctionsList) external view 4 returns ( 5 uint256[] memory directBuy, 6 address[] memory owner, 7 uint256[] memory highestBid, 8 uint256[] memory tokenIds, 9 uint256[] memory endTime, 10 uint256[] memory startPrice, 11 uint256[] memory auctionState 12 ) {} // Return the information of each auction address
}

Now build two functions, one for starting an auction and the other one for getting a list of auctions. Use the counter to assign a distinctive id for every auction, this will also help in keeping a track of the auctions.

Building the functions

Create an auction, but before doing so, check the following factors:

  • The direct buy price is more than zero
  • Starting price is more than the direct buying price
  • The end time is more than 5 minutes, therefore, nobody can create an auction lasting for a few seconds.

After checking these factors, build the functions using the below-mentioned codes:

1agma solidity ^0.7.0; 2 3import "./Auction.sol"; 4import "@openzeppelin/contracts/token/ERC721/IERC721.sol"; 5 6contract AuctionManager { 7 uint _auctionIdCounter; // auction Id counter 8 mapping(uint => Auction) public auctions; // auctions 9 10 // create an auction 11 function createAuction(uint _endTime, uint _minIncrement, uint _directBuyPrice,uint _startPrice,address _nftAddress,uint _tokenId) external returns (bool){ 12 require(_directBuyPrice > 0); // direct buy price must be greater than 0 13 require(_startPrice < _directBuyPrice); // start price is smaller than direct buy price 14 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) 15 16 uint auctionId = _auctionIdCounter; // get the current value of the counter 17 _auctionIdCounter++; // increment the counter 18 Auction auction = new Auction(msg.sender, _endTime, _minIncrement, _directBuyPrice, _startPrice, _nftAddress, _tokenId); // create the auction 19 IERC721 _nftToken = IERC721(_nftAddress); // get the nft token 20 _nftToken.transferFrom(msg.sender, address(auction), _tokenId); // transfer the token to the auction 21 auctions[auctionId] = auction; // add the auction to the map 22 return true; 23 } 24 25 // Return a list of all auctions 26 function getAuctions() external view returns(address[] memory _auctions) { 27 _auctions = new address[](_auctionIdCounter); // create an array of size equal to the current value of the counter 28 for(uint i = 0; i < _auctionIdCounter; i++) { // for each auction 29 _auctions[i] = address(auctions[i]); // add the address of the auction to the array 30 } 31 return _auctions; // return the array 32 } 33 34 // Return the information of each auction address 35 function getAuctionInfo(address[] calldata _auctionsList) 36 external 37 view 38 returns ( 39 uint256[] memory directBuy, 40 address[] memory owner, 41 uint256[] memory highestBid, 42 uint256[] memory tokenIds, 43 uint256[] memory endTime, 44 uint256[] memory startPrice, 45 uint256[] memory auctionState 46 ) 47 { 48 directBuy = new uint256[](_auctionsList.length); // create an array of size equal to the length of the passed array 49 owner = new address[](_auctionsList.length); // create an array of size equal to the length of the passed array 50 highestBid = new uint256[](_auctionsList.length); 51 tokenIds = new uint256[](_auctionsList.length); 52 endTime = new uint256[](_auctionsList.length); 53 startPrice = new uint256[](_auctionsList.length); 54 auctionState = new uint256[](_auctionsList.length); 55 56 57 for (uint256 i = 0; i < _auctionsList.length; i++) { // for each auction 58 directBuy[i] = Auction(auctions[i]).directBuyPrice(); // get the direct buy price 59 owner[i] = Auction(auctions[i]).creator(); // get the owner of the auction 60 highestBid[i] = Auction(auctions[i]).maxBid(); // get the highest bid 61 tokenIds[i] = Auction(auctions[i]).tokenId(); // get the token id 62 endTime[i] = Auction(auctions[i]).endTime(); // get the end time 63 startPrice[i] = Auction(auctions[i]).startPrice(); // get the start price 64 auctionState[i] = uint(Auction(auctions[i]).getAuctionState()); // get the auction state 65 } 66 67 return ( // return the arrays 68 directBuy, 69 owner, 70 highestBid, 71 tokenIds, 72 endTime, 73 startPrice, 74 auctionState 75 ); 76 } 77 78}

Now all the contracts are done!

Step 5

AVAX Fuji Testnet

The next step is to test the marketplace on the AVAC Fuji Testnet. Add the AVAX Fuji Testnet to the Metamask. Then open the Metamask to view the networks and then click on the Custom RPC.

Then deploy the contracts on the FUJI testnet Settings and add the network configuration in the hardhat config file. this is how the file will work:

networks:{
...
fuji: {
url: "https://api.avax-test.network/ext/bc/C/rpc",
chainId: 43113,
accounts: [
"PRIVATE_KEY",
],
},
}

Lastly, add some AVAX for the contract deployment.

Step 6

Contract deployment

Use the hardhat to deploy the NFT and AuctionManager contracts to the Fuji Testnet. Begin by editing the scripts/deploy.js file; follow the codes given below for the same:

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 address
const 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 address
console.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 the editing of deploy.js is done, continue the process by executing the following lines on the terminal to run the deploy.js script:

$ 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

Then note the addresses positively as they are required afterward at the time of interaction with the contracts.

Step 7

React application

Develop an interface to communicate with the marketplace. For this, use react and ether.js.

Execute the following codes on the terminal to start the process of interface development:

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

Then add the bootstrap CDN in the top/head section of the public/index.html file. Use the bootstrap to increase the speed of the process.

<head>
...
+ <link
+ rel="stylesheet"
+ href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css"
+ />
</head>
...
</body>
+ <script src="https://code.jquery.com/jquery-3.4.1.slim.min.js"></script>
+ <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js"></script>
+ <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js"></script>
</html>

Begin with a new App.js file and then import the ethers library. Assign the contract addresses to all the contract strings.

Create an auction, but before creating one, mint an NFT for the auction by suing the below mentioned codes:

import React from "react";
import { ethers } from "ethers";
const NFT_ADDRESS = "0xeb2283672cf716fF6A1d880436D3a9074Ba94375"; // NFT contract address
const AUCTIONMANAGER_ADDRESS = "0xea4b168866E439Db4A5183Dbcb4951DCb5437f1E"; // AuctionManager contract address
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
auctions: [], // Auctions to display
newAuction: {
// newAuction is a state variable for the form
startPrice: null,
endTime: null,
tokenId: null,
minIncrement: null,
directBuyPrice: null,
},
myItems: [],
};
}
render() {
return (
<div>
<div class="jumbotron d-flex align-items-center">
<div class="container">
<div class="auctions row"></div>
</div>
</div>
<div class="container">
<form>
<button type="submit" class="btn btn-primary">
Create Auction
</button>
</form>
<button class="btn btn-fanger">Mint NFT</button>
<p>
Your items
<br />
{(this.state.myItems || [""]).map((x) => `id: ${x} `) || ""}
</p>
</div>
</div>
);
}
}
export default App;

Step 8

Build the form

Start building the form and add a few elements to the form. Type in the start price, token id, minimum increment, duration of the auction and the direct price of buying.

<form>
<div class="mb-3">
<label for="startprice" class="form-label">
Start Price
</label>
<input
value={this.state.newAuction.startPrice}
onChange={(e) =>
this.setState({
newAuction: {
...this.state.newAuction,
startPrice: parseInt(e.target.value),
},
})
}
type="number"
class="form-control"
id="startprice"
/>
<label for="startprice" class="form-label">
Token Id
</label>
<input
value={this.state.newAuction.tokenId}
onChange={(e) =>
this.setState({
newAuction: {
...this.state.newAuction,
tokenId: parseInt(e.target.value),
},
})
}
type="number"
class="form-control"
id="startprice"
/>
<label class="form-label">Minimum Increment</label>
<input
value={this.state.newAuction.minIncrement}
onChange={(e) =>
this.setState({
newAuction: {
...this.state.newAuction,
minIncrement: parseInt(e.target.value),
},
})
}
type="number"
class="form-control"
/>
<label class="form-label">Direct Buy Price</label>
<input
value={this.state.newAuction.directBuyPrice}
onChange={(e) =>
this.setState({
newAuction: {
...this.state.newAuction,
directBuyPrice: parseInt(e.target.value),
},
})
}
type="number"
class="form-control"
/>

<label class="form-label">Duration In Minutes</label>
<input
value={this.state.newAuction.endTime}
onChange={(e) =>
this.setState({
newAuction: {
...this.state.newAuction,
endTime: parseInt(e.target.value),
},
})
}
type="number"
class="form-control"
/>
</div>

<button
type="button"
onClick={() => console.log(this.state.newAuction)}
class="btn btn-primary"
>
Create Auction
</button>
</form>

The form is now ready to regulate the interaction with the contracts.

Launch a scalable and fast NFT Marketplace powered by Avalanche

Avalanche NFT Marketplace Development Company

Step 9

Interact with the contracts

Contract ABI’s

Use the Contract Application Binary Interface (ABI) to communicate with the contracts on the network.

Then import these contracts in the React code at top of the App.js by running the following codes:

import AuctionArtifact from "./artifacts/Auction.json";
import AuctionManagerArtifact from "./artifacts/AuctionManager.json";
import NFTArtifact from "./artifacts/NFT.json";

After interacting with the contracts, the next step is to detect and connect to the MetaMask.

Step 10

Connect to the Metamask

To detect and connect to the MetaMask add an init function, that will be responsible for calling the user when the page is loaded:

class App extends React.Component {
async init(){}
...
}

Then connect the MetaMask wallet using the Ether.JS and call the init function the ComponentDidMount by running the following codes:

class App extends React.Component {
...
async init() {
if (window.ethereum) {
await window.ethereum.enable(); // Enable the Ethereum client
this.provider = new ethers.providers.Web3Provider(window.ethereum); // A connection to the Ethereum network
this.signer = this.provider.getSigner(); // Holds your private key and can sign things
this.setState({ currentAddress: this.signer.getAddress() }); // Set the current address
this._auctionManager = new ethers.Contract( // We will use this to interact with the AuctionManager
AUCTIONMANAGER_ADDRESS,
AuctionManagerArtifact.abi,
this.signer
);

this._nft = new ethers.Contract( // We will use this to interact with the NFT contract
NFT_ADDRESS,
NFTArtifact.abi,
this.signer
);
} else {
alert("No wallet detected");
}
}
componentDidMount() {
this.init();
}
...
}

Then select your account and continue the process, the MetaMask is finally connected to the web page.

Step 11

NFT Minting

Build the mint function which is required to call at the time of pressing the Mint NFt button.

Use the this.nft object that has been created earlier within the init function. Then, call the function getItem() that is located in the NFT contract and pass 0.5 AVAX as gas fees to min the NFTs:

async mint() {
// hash is the hash of the transaction
let { hash } = await this._nft.getItem({
// Calling the getItem function of the contract
value: ethers.utils.parseEther("0.5"), // 0.5 AVAX
});
console.log("Transaction sent! Hash:", hash);
await this.provider.waitForTransaction(hash); // Wait till the transaction is mined
console.log("Transaction mined!");
alert(`Transaction sent! Hash: ${hash}`);
}

Then call the function when the button is pressed by running the following code:

<button type="button" onClick={() => this.mint()} class="btn btn-danger">
Mint NFT
</button>

Step 12

Owned NFTs

USe the myItems function and retrieve the list of owned tokens:

async getItems() {
let items = await this._nft.myItems(); // Get the tokens owned by the user
console.log(items);
}

Then call the function at the last of the init() function, so every time the wallet is connected, the list of owned NFTs will be retrieved:

async init() {
if (window.ethereum) {
// if window.ethereum is defined
await window.ethereum.enable(); // Enable the Ethereum client
this.provider = new ethers.providers.Web3Provider(window.ethereum); // A connection to the Ethereum network
this.signer = this.provider.getSigner(); // Holds your private key and can sign things

this._auctionManager = new ethers.Contract( // We will use this to interact with the AuctionManager
AUCTIONMANAGER_ADDRESS,
AuctionManagerArtifact.abi,
this.signer
);

this._nft = new ethers.Contract( // We will use this to interact with the NFT
NFT_ADDRESS,
NFTArtifact.abi,
this.signer
);

+ this.getItems();
} else {
alert("No wallet detected"); // No wallet detected
}
}

Then convert the array of values to normal numbers, that are in BigNumber format after reloading the page:

async getItems() {
let items = await this._nft.myItems(); // Get the tokens owned by the user
items = items.map((x) => x.toNumber()); // Converts BigNumber to number for each item in array
this.setState({ myItems: items });
}

Lastly, click and refresh the page to view all the minted NFTs.

Step 13

Create an auction

Build a function for making auctions, but before calling the createAuction function in the Auction Manager, give the approval to the token to be used for the function. After giving approval to the Auction Manager, the token will be transferred to the newly created auction contract.

Check if there are any empty text fields

if (
!this.state.newAuction.minIncrement ||
!this.state.newAuction.directBuyPrice ||
!this.state.newAuction.startPrice ||
!this.state.newAuction.endTime ||
!this.state.newAuction.tokenId
)
return alert("Fill all the fields");

Then call the approve function of the NFt contract to approve the AuctionManager contract to send the NFT token that will be put for the process of auction.

let { hash: allowance_hash } = await this._nft.approve(
AUCTIONMANAGER_ADDRESS,
this.state.newAuction.tokenId
); // Approve the AUCTIONMANAGER to transfer the token
console.log("Approve Transaction sent! Hash:", allowance_hash);
await this.provider.waitForTransaction(allowance_hash); // Wait till the transaction is mined
console.log("Transaction mined!");

After this, call the createAuction function in the AuctionManager contract by running he following codes:

let { hash } = await this._auctionManager.createAuction(
this.state.newAuction.endTime * 60, // Converting minutes to seconds
ethers.utils.parseEther(this.state.newAuction.minIncrement.toString()), // Minimum increment in AVAX
ethers.utils.parseEther(this.state.newAuction.directBuyPrice.toString()), // Direct buy price in AVAX
ethers.utils.parseEther(this.state.newAuction.startPrice.toString()), // Start price in AVAX
NFT_ADDRESS, // The address of the NFT token
this.state.newAuction.tokenId // The id of the token
);
console.log("Transaction sent! Hash:", hash);
await this.provider.waitForTransaction(hash); // Wait till the transaction is mined
console.log("Transaction mined!");
alert(`Transaction sent! Hash: ${hash}`);

Then run the below-mentioned codes for the final function:

async createAuction() {
if (
!this.state.newAuction.minIncrement ||
!this.state.newAuction.directBuyPrice ||
!this.state.newAuction.startPrice ||
!this.state.newAuction.endTime ||
!this.state.newAuction.tokenId
)
return alert("Fill all the fields");

let { hash: allowance_hash } = await this._nft.approve(
AUCTIONMANAGER_ADDRESS,
this.state.newAuction.tokenId
); // Approve the AUCTIONMANAGER to transfer the token
console.log("Approve Transaction sent! Hash:", allowance_hash);
await this.provider.waitForTransaction(allowance_hash); // Wait till the transaction is mined
console.log("Transaction mined!");

let { hash } = await this._auctionManager.createAuction(
// Create an auction
this.state.newAuction.endTime * 60, // Converting minutes to seconds
ethers.utils.parseEther(this.state.newAuction.minIncrement.toString()), // Minimum increment in AVAX
ethers.utils.parseEther(this.state.newAuction.directBuyPrice.toString()), // Direct buy price in AVAX
ethers.utils.parseEther(this.state.newAuction.startPrice.toString()), // Start price in AVAX
NFT_ADDRESS, // The address of the NFT token
this.state.newAuction.tokenId // The id of the token
);
console.log("Transaction sent! Hash:", hash);
await this.provider.waitForTransaction(hash); // Wait till the transaction is mined
console.log("Transaction mined!");
alert(`Transaction sent! Hash: ${hash}`);
}

Call the function after pressing the Create Auction button:

...
<button
type="button"
+ onClick={() => this.createAuction()}
class="btn btn-primary"
>
Create Auction
</button>
...

Fill the form and then press the Create Auction button to begin the auction process.

The first auction on the NFT Marketplace has finally begun!

Step 14

Get the list of auctions

Build two functions namely the getAuctions() and the getAuctionsInfo() to get a list of all the auctions taking place on the network:

async getAuctions() {
let auctionsAddresses = await this._auctionManager.getAuctions(); // get a list of auction addresses
let auctions = await this._auctionManager.getAuctionInfo(auctionsAddresses); // I'll just pass all the addresses here, you can build a pagination system if you want
console.log("Auctions:", auctions);
this.setState({ auctions }); // Update the state
}

Then call this function at the end of the init( ) function:

...
this._nft = new ethers.Contract(NFT_ADDRESS, NFTArtifact.abi, this.signer); // We will use this to interact with the NFT
this.getItems();
+ this.getAuctions();
...

Organize the auction array and display them in the auction’s section section of the web page:

let new_auctions = [];

for (let i = 0; i < auctions.endTime.length; i++) {
let endTime = auctions.endTime[i].toNumber();
let tokenId = auctions.tokenIds[i].toNumber();
let auctionState = auctions.auctionState[i].toNumber();

let startPrice = ethers.utils.formatEther(auctions.startPrice[i]);
let directBuyPrice = ethers.utils.formatEther(auctions.directBuy[i]);
let highestBid = ethers.utils.formatEther(auctions.highestBid[i]);

let owner = auctions.owner[i];

let newAuction = {
endTime: endTime,
startPrice: startPrice,
owner: owner,
directBuyPrice: directBuyPrice,
tokenId: tokenId,
highestBid: highestBid,
auctionState: auctionState,
auctionAddress: auctionsAddresses[i],
};
new_auctions.push(newAuction);
}

this.setState({ auctions: new_auctions }); // Update the state

Then write a function to display an auction on the user-interface by running the following codes:

renderAuctionElement(auction) {
let state = "";
if (auction.auctionState === 0) {
state = "Open";
}
if (auction.auctionState === 1) {
state = "Cancelled";
}
if (auction.auctionState === 2) {
state = "Ended";
}
if (auction.auctionState === 3) {
state = "Direct Buy";
}
return (
<div style={{ background: "yellow" }} class="col">
<p>ID: {auction.tokenId}</p> {/* ID of the token */}
<p>Highest Bid: {auction.highestBid || 0}</p>
{/* Highest bid */}
<p>Direct Buy: {auction.directBuyPrice}</p> {/* Direct buy price */}
<p>Starting Price: {auction.startPrice}</p> {/* Starting price */}
<p>Owner: {auction.owner}</p> {/* Owner of the token */}
<p>
End Time: {Math.round((auction.endTime * 1000 - Date.now()) / 1000 / 60)}{" "}
{/* Time left in minutes */}
minutes
</p>
<p>Auction State: {state}</p>
<button class="btn-primary">See More</button>
</div>
);
}

In the above codes, the auction.endTime which is given in seconds is converted to milliseconds by multiplying it by 1000. Then, the result is subtracted from Date.now(), which s given in milliseconds. After that, the result is divided by 1000 to convert it to seconds. Lastly, it is divided by 60 to convert in minutes.

In the next part, map all the auctions into the function in the render method by using the following codes:

render() {
return (
<div class="jumbotron d-flex align-items-center">
<div class="container">
<div class="auctions row">
{this.state.auctions.map(this.renderAuctionElement)}
</div>
</div>
</div>
)
}

Finally, an auction has been created!

Step 15

Build an auction page

Use a state variable this.state.activeAuction to reflect the current auction. Then set this variable after pressing the see more button. If this variable does not contain a null value then it will reflect the auction data instead of the list of auctions. Set this variable back to null by using the go-back option.

Add a fresh setActiveAuction function by running the following codes:

setActiveAuction(auction) {
this.setState({ activeAuction: auction });
}

Then, use the following codes to fetch the data of the previous bids when the setActiveAuction function is called:

async setActiveAuction(auction) {
this._auction = new ethers.Contract( // Create a new instance of the contract
auction.auctionAddress,
AuctionArtifact.abi,
this.signer
);

let previousBids = await this._auction.allBids(); // Get the bids
let bids = []; // A list of bids
for (let i = 0; i < previousBids[0].length; i++) { // Loop through the bids
bids.push({ // Add the bid to the list
bidder: previousBids[0][i], // The bidder
bid: ethers.utils.formatEther(previousBids[1][i]), // The bid
});
}

auction.bids = bids; // Add the bids array to the auction object

this.setState({ activeAuction: auction }); // Update the state
}

Use the this.auction function to interact with the auction contract. Then display the random value assigned to every NFT earlier, now on the auction page:

let auctionTokenValue = await this._nft.itemValue(auction.tokenId); // Get the value of the token
auctionTokenValue = auctionTokenValue.toNumber(); // Convert BigNumber to number
auction.auctionTokenValue = auctionTokenValue; // Add the value of the token to the auction object

To know about the highest bidder, run the following codes:

let highestBidder = await this._auction.maxBidder(); // Get the highest bidder
auction.highestBidder = highestBidder; // Add the highest bidder to the auction object

Lastly, run the below-mentioned codes for the increment value:

let minIncrement = await this._auction.minIncrement(); // Get the minimum increment
auction.minIncrement = ethers.utils.formatEther(minIncrement); // Add the minimum increment to the auction object

Step 16

Render the selected auction

Write a sample render function for the chosen auction as given below:

renderActiveAuction() {
let activeAuction = this.state.activeAuction;
let state = "";
if (activeAuction.auctionState === 0) { // If the auction is open
state = "Open";
}
if (activeAuction.auctionState === 1) { // If the auction is cancelled
state = "Cancelled";
}
if (activeAuction.auctionState === 2) { // If the auction is ended
state = "Ended";
}
if (activeAuction.auctionState === 3) { // If the auction is ended by a direct buy
state = "Direct Buy";
}
return (
<div>
<div class="col">
<button
class="btn-secondary"
onClick={() => this.setState({ activeAuction: null })}
>
Go Back
</button>
<p>ID: {activeAuction.tokenId}</p> {/* ID of the token */}
<p>Highest Bid: {activeAuction.highestBid || 0} AVAX</p>
{/* Highest bid */}
<p>Direct Buy: {activeAuction.directBuyPrice} AVAX</p>{" "}
{/* Direct buy price */}
<p>Minimum Increment: {activeAuction.minIncrement} AVAX</p>{" "}
{/* Minimum increment in AVAX */}
<p>Starting Price: {activeAuction.startPrice} AVAX</p> {/* Starting price */}
<p>Owner: {activeAuction.owner}</p> {/* Owner of the token */}
<p>
End Time:{" "}
{Math.round(
(activeAuction.endTime * 1000 - Date.now()) / 1000 / 60
)}{" "}
{/* Time left in minutes */}
minutes
</p>
<p>Auction State: {state}</p>
</div>
<div class="col">
<h3>Bids</h3>
<table class="table">
<thead>
<tr>
<th>Bidder</th>
<th>Bid</th>
</tr>
</thead>
<tbody>
{activeAuction.bids.map((bid) => {
return (
<tr key={bid.bidder}>
<td>{bid.bidder}</td>
<td>{bid.bid} AVAX</td>
</tr>
);
})}
</tbody>
</table>
</div>
<div class="col">
<div>
<input type="number" placeholder="0.5" />
<button class="btn-primary">Place Pid</button>
</div>
<button class="btn-danger">Cancel Auction</button>
<button class="btn-secondary">Withdraw Funds</button>
<button class="btn-secondary">Withdraw Token</button>
</div>
</div>
);
}

If the this.state.activeAuction is null, then return this function in place of the list of auctions. Edit the render function by running the following codes:

...
<div class="container">
{this.state.activeAuction != null ? (
this.renderActiveAuction()
) : (
<div class="auctions row">
{this.state.auctions.map(this.renderAuctionElement)}
</div>
)}
</div>
...

Step 17

Auction functions

Call the placeBid function from the auction contract and transfer some AVAX by running the below-mentioned:

async placeBid(amount) {
if (!amount) return;
amount = ethers.utils.parseEther(amount.toString()); // Amount in AVAX
let { hash } = await this._auction.placeBid({ value: amount }); // Place a bid
await this.provider.waitForTransaction(hash); // Wait till the transaction is mined
alert(`Transaction sent! Hash: ${hash}`); // Show the transaction hash
this.setActiveAuction(this.state.activeAuction); // Update the active auction
}

Next, call the placeBid function at the time of pressing the button:

...
<div>
<input
type="number"
placeholder="0.5"
onChange={(e) => this.setState({ bidAmount: e.target.value })}
/>
<button
class="btn-primary"
onClick={() => this.placeBid(this.state.bidAmount)}
>
Place Pid
</button>
</div>
...

Switch to another account on MetaMask before placing the bid as the auction creator cannot place the bids from the same account. Then wait a bit until the auction gets over and withdraw the token if nobody is bidding a higher value.

Step 18

Withdraw token

Call the withdrawToken function from the Auction contract and then reflect an alert after the transaction gets mined:

async withdrawToken() {
let { hash } = await this._auction.withdrawToken(); // Withdraw the NFT token
await this.provider.waitForTransaction(hash); // Wait till the transaction is mined
alert(`Withdrawal Successful! Hash: ${hash}`); // Show the transaction hash
window.location.reload(); // Reload the page
}

Call this function at the time of pressing the withdraw token button:

...
<button onClick={()=>this.withdrawToken()} class="btn-secondary">Withdraw Token</button>
...

Step 19

Withdraw funds

Call the withdrawFunds function from the Auction contract and then call the function when the transaction is mining is done:

async withdrawFunds() {
let { hash } = await this._auction.withdrawFunds(); // Withdraw the funds
await this.provider.waitForTransaction(hash); // Wait till the transaction is mined
alert(`Withdrawal Successful! Hash: ${hash}`); // Show the transaction hash
window.location.reload(); // Reload the page
}

Call this function once the Withdraw Funds button is pressed:

...
<button onClick={()=>this.withdrawFunds()} class="btn-secondary">Withdraw Funds</button>
...

Now withdraw the funds by switching back to the account created earlier for auction and confirm the transaction.

Step 20

Cancel Auction

Call the cancelAuction function of Auction contract and show the alert once the transaction is mined:

async cancelAuction() {
let { hash } = await this._auction.cancelAuction(); // Cancel the auction
await this.provider.waitForTransaction(hash); // Wait till the transaction is mined
alert(`Auction Canceled! Hash: ${hash}`); // Show the transaction hash
window.location.reload(); // Reload the page
}

Then, call the function when the Cancel Auction button is clicked:

...
<button onClick={() => this.cancelAuction()} class="btn-danger">
Cancel Auction
</button>
...

Step 21

Deploy to Mainnet

Lastly, deploy the functional, marketplace to the Avalanche mainnet and add the network in the hardhat config file by running the following command:

networks:{
...
mainnet: {
url: "https://api.avax.network/ext/bc/C/rpc",
chainId: 43114,
accounts: [
"PRIVATE_KEY",
],
},
}
$ npx hardhat compile # Compiles the contracts
$ npx hardhat run scripts/deploy.js --network mainnet # runs the script on the Avalanche Mainnet, "mainnet" is specified inside the hardhat config file

Finally, the Avalanche NFT marketplace is live now!

Launch a scalable and fast NFT Marketplace powered by Avalanche

Avalanche NFT Marketplace Development Company

What Avalanche development services does LeewayHertz offer?

DeFi Apps Development

Our team develops DeFi Applications that fully comply with the Ethereum asset requirement. These applications support the trading of equities, commodities and alternative assets.

Solidity-based Smart Contracts

Our developers build solidity-based smart contracts through EVM (Ethereum virtual machine) and provide services that include architecture, designing, auditing and implementation of the Solidity smart contracts.

NFT Solutions

Our Avalanche developers have expertise in developing NFT solutions for blockchain-focused start-ups and enterprises. We develop and launch efficient NFT solutions based on the latest blockchain innovations.

Wallet Development

We design an easy-to-use and highly secure Avalanche wallet to trade assets on the network. We work according to the client’s needs and try to add and alter necessary attributes to ensure precision.

Final note

Avalanche has gained major traction and is moving fast towards shaping the future of the blockchain space. It is highly scalable in nature and functions on the basis of valuable consensus protocols like the Snowman. The regular updates on the Avalanche improve the platform in every aspect, making it more accessible for the users and the developers. It helps them in building innovative dApps by adding new use cases to the blockchain technology.

If you are looking for Avalanche NFT marketplace development, then connect with LeewayHertz. Our experts are right here to help you with Avalanche development and consultation.

Webinar Details

Author’s Bio

Akash Takyar
Akash Takyar
CEO LeewayHertz
Akash Takyar is the founder and CEO at LeewayHertz. The experience of building over 100+ platforms for startups and enterprises allows Akash to rapidly architect and design solutions that are scalable and beautiful.
Akash's ability to build enterprise-grade technology solutions has attracted over 30 Fortune 500 companies, including Siemens, 3M, P&G and Hershey’s. Akash is an early adopter of new technology, a passionate technology enthusiast, and an investor in AI and IoT startups.

Start a conversation by filling the form

Once you let us know your requirement, our technical expert will schedule a call and discuss your idea in detail post sign of an NDA.
All information will be kept confidential.

Insights

Follow Us