Building a Decentralized Social Platform for NFTs in 1 Week
Published on Feb 2022
A deep dive into developing a decentralized social platform allowing users to mint posts into NFTs, exploring Web3 basics, Gun JS for database, Polygon network, and front-end challenges.
Project Overview
Prior to coming down with Covid, I was on the hunt for a new project idea as usual. Given all the animosity towards NFTs, the inflated hype around Web3.0 and a general lack of trust in social media companies (ahem ahem “Meta”), a perfect project for me was somewhere in the above intersection.
So finally I landed on developing a Decentralized Social Platform where users could mint any of their posts (text/images/gifs etc.) into NFTs. Basically a Twitter with built in NFTs.
NFT and Web3 Basics
NFTs are Non-Fungible-Tokens. So what exactly is fungibility? Let’s take the example of a hoodie. On ordering one online, you’d receive a new hoodie. Say someone were to exchange that brand new hoodie and offer you an identical one it really wouldn’t matter to you right? The previous hoodie and the brand new one are identical to you. This means that the hoodies are fungible. Now suppose you were to use this hoodie for a couple of years. If someone were now to offer you a brand new hoodie in exchange for your current one then that won’t be an equal trade as there is only one hoodie in the world that has the exact coffee stains, dirt marks and wear and tear that your hoodie has. At that point your hoodie is non-fungible.
The same way, an NFT is a non-fungible (i.e. unique) token that represents any digital asset. Now this digital asset itself could be anything from an image to a video to a gif or an audio track.
As for what owning an NFT entails, here are the steps :
- User clicks a button on the front-end site to mint their post into an NFT.
- The post’s media is not stored on the blockchain directly because of the relatively large file size, network congestion and high transaction/gas fees. Instead, we store a hash of the media into a JSON metadata file. This hash is called the NFT’s content ID (CID) and is typically hosted on IPFS (Inter Planetary File System) which works in a similar fashion as the peer based BitTorrent protocol.

- This JSON metadata file has the CID referenced as a URI (Universal Resource Identifier) and is then also pinned onto IPFS and the hash returned from that is then written into the blockchain.
This essentially means that you as a person own the hash pointing to the metadata file stored off-chain, which itself points to the image stored off-chain.
Is this a stupid system? Sure.
Can the image an NFT links to be lost permanently? Totally.
Do I understand any of this? Barely.
Coming to Web 3.0, let’s rewind the clocks a bit. We know that Web 1 (~ 1990s) was mostly read only where we individuals could only consume content from static websites. Web 2 (~ mid 2000s) was read and write allowing users to upload their own content. The upcoming Web 3.0 is a mishmash of multiple things but as someone on Twitter explained it, it’s meant to be read, write and own, where users have complete ownership of their content on decentralized platforms that can remain free from a company’s censorship. It also aims to make users less dependent on centralized monoliths like Google, Meta, Amazon etc.
Project Structure
Given that the project is a Web 3 site with NFT minting functionality I’ve broken it down into the following parts:
Database
Since the project is supposed to be decentralized I was on the hunt for a decentralized database for the same. After seeing Fireship.io’s video on Gun JS I thought of giving it a try. Eventually I stumbled upon OrbitDB which is a database that uses IPFS for it’s data storage. While it could serve as a potential alternative to Gun, by then I was too deep into Gun and was quite happy with it.
As for how Gun JS works, it uses each browser that it connects to as a peer and stores some partial amounts of the encrypted data in the browser’s localStorage. The problem with this is that localStorage is sorta unreliable since some devices may or may not be online or an individual may clear out their browser data so the entire data set may not be accessible. To solve this I set up a NodeJS relay server on Heroku that any of the clients may connect to in case there are no other peers available. Not a perfect solution as Heroku has a tendency to restart dynos and in the process clear any data that is not version controlled on a daily basis. But it kinda works for now so I’m good with it.
Coming to the off chain data storage for media, I went with Pinata which served as a middle man between my site and IPFS. Pinata allowed me to pin all sorts of media including user profile pictures, NFT contents like images/videos/gifs, JSON metadata etc. The hash/CID we get on pinning a file to IPFS is then used as the URI within the NFT’s metadata JSON.
Smart Contract
When it comes to NFTs, the most common choice is ERC-721 and we can use a tool called OpenZeppelin to generate the initial boilerplate code.

We take the generated base contract and create a mapping to ensure each token has a unique URI and check if that URI is already owned. We also add an additional method to handle the minting of a new token where Ether (or other tokens like MATIC) can be sent from the end-user to the contract (Function taken straight from Fireship’s Web3 video).

The method first validates that the URI is not already taken and the minimum amount of Ether has been sent. On trying to mint a post, the user calls this method, their wallet prompts them for permission to transfer funds and executes the transaction. In return, they will be given a new token linked to the metadata URI on IPFS.
I used Alchemy, a platform that aims to be somewhat like the AWS for Web3 technologies, to create a new app on the Ropsten, Rinkeby and Polygon Mumbai testnets. I then copy the link to that network and paste it into the Hardhat config file, along with the private key for my MetaMask wallet since this account will be used to deploy the contract.

To deploy onto a testnet our account needs some money in it, so we get some fake ETHER/MATIC from any available faucets which send some fake money into our wallet address for testing. Using this fake MATIC/ETHER we then deploy the contract onto the test networks.

Since I used Hardhat as the framework to deploy my smart contracts, I wasn’t able to read the contract information on Etherscan which let me do things such as inputting the tokenID for an NFT and getting back the IPFS hash/CID for that NFT. So I used this Hardhat plugin which makes use of API keys from Etherscan to verify the contract and allow for reading the contract information.
Blockchain
Now to deploy the smart contract, the initial thought of using the Ethereum network was quickly brushed aside once I realized the deployment and gas fees would burn a massive a hole in my wallet. So the other alternative was our very own home-grown Polygon network, which is a Layer-2 network that operates on top of Ethereum’s existing network. Polygon also employs side chains, to divert traffic and avoid network congestion, thus making it ideal for my use case.
The contract was then deployed onto multiple testnets including Ropsten, Rinkeby and Polygon Mumbai. The contract information could then be read on their respective networks using Etherscan and Polyscan.
Front-End
The front-end for a Web3 app is quite straightforward and not too dissimilar from existing Web2 frameworks. I’m using React with a SCSS pre-processor for styling since I’ve used a similar setup in most of my previous projects.
Also for some reason, in spite of having the Solidity code build into the src directory, the React app wasn’t able to access the the compiled ABI. ABI stands for Application Binary Interface which serves as the middle man allowing the front-end to communicate with the smart contract deployed on a network. Eventually I just ended up copying the entirety of the JSON in the compiled ABI and pasted it directly into the React JSX.
Before using the app though, the user must have MetaMask installed which serves as their wallet. When the mint button is clicked it connects the user’s wallet to the smart contact on the blockchain, then mints a new token using the PayToMint method defined in the Solidity code.
Website Deployment
Initially I wanted the whole project to have a decentralized vibe to it including hosting it on IPFS through Fleek. Faced 2 problems here:
- First was the environment variables being used to set encryptions keys didn’t seem to work on Fleek no matter what. Tried to redeploy on the Internet Computer blockchain using Fleek again, but that didn’t solve my problem either (quelle surprise eh?).
- Second problem came up when I realized that since I was using React-Router with BrowserRouter, it only allows one base name, forcing me to use HashRouter if I intended to serve the site over an IPFS HTTP gateway. This meant I’d have to redo huge parts of the code and Lord knows I’m not going to bother with that.
So finally I just decided to just host it on Firebase.
Problems
Content Moderation
It’s quite tough on decentralized platforms since there’s no central body that can step in to deem certain material as objectionable and take appropriate action. So I started building my own super hacky system for democratic (?) content moderation using my own limited understanding of the term Relative Reputation systems. Here the platform calculates a “reputation score” for each user based on their past interactions. So an individual that’s been quite active and engages within DeSo frequently has a priority status given to them. In case some objectionable material is uploaded, users can report the post and the platform automatically deletes the post if a group consensus is reached for the post’s deletion. At least this way the power to control the material posted remains within the users of the platform though I’m sure there are significantly better approaches to this problem including a proper implementation of Relative Reputation or Web of Trust systems.
Contract Information
Since I used Hardhat as the framework to deploy my smart contracts, I wasn’t able to read the contract information on Etherscan which let me do things such as inputting the tokenID for an NFT and getting back the IPFS hash/CID for that NFT. So I used this Hardhat plugin which makes use of API keys from Etherscan to verify the contract and allow for reading the contract information.
Final Product

I also ended up designing a simple logo which is supposed to represent a blockchain with something like a camera shutter in the middle for the “social network” aspect of the site.
Fair warning, the site’s kinda buggy and breaks every once in a while.
If you wish to explore the entire codebase you can do at GitHub repo, and maybe go to DeSo Product Hunt page and give it an upvote if you’re feeling generous.
Now what?
From here there are plenty of paths I could follow.
I could potentially launch this to the Polygon mainnet but I don’t want to spend the money deploying and maintaining a test venture that currently has only 1 user.
Also turns out DeSo is already the name of blockchain foundation so … oops. And Aave recently came up with their own decentralized social app platform called the Lens Protocol so I guess I’m late to the party once again.
Feel free to reach out to me if you have any questions.