Build an NFT marketplace with Polygon and Flutter

Sameer Kashyap
CoinsBench
Published in
7 min readJan 18, 2022

--

As the Web3 space gains more momentum, more amazing use cases and applications are rolling out in multiple spaces such as Defi, gaming, DAOs, and more. It is important that the user experience remains great along with the complex infrastructure and protocols. Currently, most Dapps can only be built with javascript-powered libraries and frameworks as most of the web3 ecosystem is built on Javascript.

The current problem that Web3 is facing is accessibility to a wide range of devices especially mobile, because of a lack of tooling. That is where Flutter being an awesome UI framework comes to the rescue.
Although Flutter can power the mobile web3 movement, it does lack a mature ecosystem of tooling to interact with blockchain data and perform required operations. Luckily, as we wait for this ecosystem to grow, there are a few awesome tools that can get the job done.

A bit about Polygon

Polygon is an EVM-compatible layer 2 protocol for Ethereum, what this essentially means is, instead of Ethereum doing all the hard work of processing transactions, polygon uses its proof-of-stake mechanism that makes transactions faster and much cheaper and then groups clusters of transactions before sending them back to Ethereum, essentially acting as a commit chain.

Although this article won’t be going in-depth about blockchain and solidity basics, feel free to get started with some of the resources mentioned here.

A bit more about NFTs

NFTs or Non-Fungible Tokens are a blockchain standard that has a set of rules implemented that allow it has a unique identity on the blockchain which makes it atomic and non-replicable. Although ERC 721 is a golden standard there is a new popular standard called the ERC 1155 that allows the developer to create both ERC 20 and 721 tokens enabling less gas fees and managing a class of assets together.

Let’s dive into the code

Truffle init

Truffle is a tool for bootstrapping, testing, and deploying contracts. It helps us manage our contracts easily, there are of course many other popular tools such as hardhat and foundry. make sure to install truffle if you have not before using npm i -g truffle and create an environment using truffle init which will generate a standard set of folders and configuration files. We can start coding our contract in the /Contracts folder by creating a new file with the .sol extension.

NFT.sol

Let’s start by creating a contract that will implement the ERC721 token standard. this will help us mint the token itself as well as store metadata about the NFT that will resolve into a JSON, this is typically stored in decentralized storage like Filecoin and IPFS. we will go about this in the next part when we integrate everything with Flutter as most of it is done from the client-side.

The ERC721URIStorage will help us store the URI of metadata of each NFT. Counters here, is a simple util for tracking the id of each token, which we can use to declare the _tokenIds variable. We then create a newItemId using the current pointer for the _tokenIds variable.

We then have a set of methods that are accessed from the inherited contract. Within our own contract, we have only one method createToken that will be used to min the NFT.

Finally, we call _mint with the sender address and the newItemId to mint the token, next _setTokenUri is used to set the actual metadata associated with the NFT. We need call setApproveForAll with our market address so that our market contract can have the permission to transfer ownership to users.

Market.sol

Next, let’s create a market contract where all of the NFT information, such as buyer and seller will be stored, we will need this information to enable NFT transfers and handle other functions such as displaying sold items on the frontend.

Let’s initialize two Counters , _itemIds and _itemsSold to keep track of totalItems. we also define owner and listingPrice , this is the fee that users have to pay to the owner of the contract for listing their NFTs after minting them. The struct MarketItem will define the shape of each NFT item in the market, and mapping of the itemId to the MarketItem will help us easily fetch the item by id.

createMarketItem is a simple function that will push a new-minted NFT into the mapping that we created earlier with all the properties that are required to carry out transactions. We add two validations as require statements to make sure the price is greater than 0 and equal to the listing price, nonReentrarnt will help us prevent multiple calls or rate-limit the contract call.

createMarketSale will help in transferring the ownership as well as funds between the contract and the user who bought it. we fetch and extract the required data such as price and itemId to initiate the transfer.

we can call transfer directly on the seller address, as the seller is a payable address as we defined in the struct . The IERC721 will help up make the actual transfer of the NFT, we have to provide the nftContract address, seller, buyer address, and the actual tokenId . We also change the ownership of the MarketItem to the user who bought the item.

And finally, increment the _itemsSold and transfer the listingPrice to the owner of the contract as a fee.

We finally have to write a bunch of methods to perform read operations for specific data that we require to show in the frontend.

fetchMarketItems gets all the marketItems which are unsold to be displayed for sale. the logic is pretty simple, we first track the unsoldItemCount count to create an array of the total available marketItems. we then run a for loop for all marketItems and filter it out by checking if the owner of the item is equal to the contract address and push those items into the items array we created earlier by creating a new MarketItem object.

We finally return all the items.

Similarly, we have fetchMyNFTs that will return all the items that the user has purchased. We follow a similar logic as the previous function, but instead of filtering out by the contract address, we use the address of the user who called the contract. We create a new array we the calculated itemCount and then loop over the items to push owned items with their relevant tokenId .

Following the same pursuit as the past two, we use another function fetchItemsCreated to get all the NFTs that the user has minted. Here we compare the seller's address for each item instead of the owner's address and then return all those items.

Deploy!!

Finally, we are ready to deploy the contracts, we will just need to seup some configuration in truffle.

create a new file under the generated/migrations folder called 2_deploy_contracts.js

We will import the contracts into the javascript file and call deployer.delpoay(contract) we also need to call another deploy function as our NFT contract required the market Address to set permissions for the market to transfer items to a d different address.

be sure the install the dependency by using npm i @truffle/hdwallet-provider . Create a new file called .secret and paste the extracted mnemonic of your wallet which is funded. If you don’t have any funds yet, head over to the polygon faucet and drop some funds into your wallet by entering your wallet address.

We’ll then set a matic key with the above details such as a rpc link, networkId and other parameters, we will be deploying this to the matic Mumbai testnet.

All you have to do now is cd into the truffle directory and run truffle migrate --network matic . And your contract will start deploying. it might take a few seconds for the blocks to be confirmed, make sure you grab both the contract addresses as we will require it to interact with the contract from our flutter app.

And, Viola!, your contract is now live on the matic Mumbai testnet. Stay tuned for the second part where we will hook up the contract with our Flutter app using the web3dart package.

Follow my socials and connect with me as I try to bring more examples of Flutter + Web3.

--

--