Last night, I was invited by Teacher LXDAO Vdel to talk to the students of the web3 internship program about DAPP development. At first glance, the need for on-chain interaction with wallets is just DAPP, and it's not that complicated. Moreover, with AI being so powerful now, writing a DAPP is not a matter of minutes. So I agreed, thinking, isn't this just a web3 hello world?
Later, after finishing my work, I thought about it and realized I might be suffering from the "curse of knowledge." I recalled my confusion and helplessness during my first hackathon when I created a replica of LXDAO Marry3 called Ring3, and reflecting on my experiences over the years participating in hackathons and projects across different chains, I suddenly felt it was worth sharing. At the same time, this is also a great opportunity to organize my experiences from the past few years, preparing a course while writing a blog post.
What is DAPP?#
The usual definition is: DAPP, short for Decentralized Application, is an application that runs on a blockchain. Unlike traditional centralized applications, DAPP does not rely on centralized servers but instead depends on the decentralized characteristics of the blockchain. Therefore, DAPP has the features of decentralization, trustlessness, and the absence of intermediaries.
The above is a very official introduction, but in reality, if you strictly follow the official server to create a DAPP and make everything decentralized, the user experience will be very poor, such as being difficult to access, slow speeds, and complex processes. In fact, even one of the greatest inventions of blockchain—decentralized exchanges like Uniswap—is not completely decentralized. Specifically, for example, the token list on Uniswap, if read from the blockchain every time, might take ages; also, data such as prices, slippage, trading volume, TVL, liquidity pools, etc., are retrieved and organized through centralized services that store blockchain data and provide web API/GraphQL interfaces, which are then called by the frontend for user access.
So, what exactly is a decentralized application (DAPP)? In my words, anything that requires on-chain interaction, involving write/read operations, can be considered a DAPP, just with varying degrees. DAPP and our traditional web development are not opposed; they can still be compatible. We can analyze a product's degree of decentralization using a Venn diagram:
The entire purple area can be defined as the DAPP area, focusing on several key areas:
- The brown area represents the vast majority of DAPPs: Most well-known DAPPs like Uniswap, Pendle, OpenSea, ENS, etc., use both decentralized and centralized technologies in their frontend and backend. The frontend typically does not deploy services using technologies like IPFS but may use decentralized CDN technologies to enhance user experience. The backend services are based on decentralized blockchain technology, where core services interact directly with the chain, but they synchronize blockchain data through centralized database servers to form indexes, enhancing data query speeds, which essentially improves user experience.
- Looking at the "simple DAPP" area below the brown area, applications in this area usually have relatively simple functions. Specifically, they may only need to read the asset status of a certain address or perform some simple write operations, such as minting NFTs or transferring NFTs. This type of DAPP was particularly popular around 2021, during the NFT boom, when many project teams created flashy web pages to enhance their NFT brand image to sell more NFTs. These DAPPs would determine if users were eligible to mint, how many NFTs they could mint, and then allow users to call smart contracts to mint, displaying the minted NFTs to users. By the way, LXDAO's Project 0, the Conscience NFT, was also born during that period, but the Conscience NFT stands out in the entire market with its simple web style but complete functionality, objectively introducing the NFT's features without flashy gimmicks, and can be understood as a pure art sales website. At that time, the price was only 0.01 ETH each, and now it's hard to come by
- Then looking at the "extreme DAPP" area in the brown area. Here, we won't discuss the CDN content distribution network; this service is indeed decentralized but still faces the issue of CDN service provider centralization. However, most of the time, we can accept using decentralized applications without an interactive interface. The decentralized frontend discussed here aims to avoid the centralization issues posed by network service providers, such as Tornado.cash, which is essentially an application that uses blockchain technology for money laundering. Whoever maintains it will face legal risks, and no server provider would want their servers to host such things. But technology is innocent; the community came up with a brilliant idea to deploy Tornado.cash's frontend code on IPFS (introduced in the next chapter). Simply put, it's like copying a store into flyers and distributing them to many people for safekeeping; if one place is shut down, others still exist. Of course, the downside is that accessing this website is incredibly slow. So this is not a common solution.
- Broadly speaking, the core of DAPP is a complete set of smart contracts; a DAPP can be constituted solely by smart contracts, but since blockchain is not just for programmers, to attract more users, a basic interactive interface is still necessary.
In summary, whether there is interaction with the chain and whether the core revolves around smart contracts are the most basic standards for judging a DAPP. Centralized frontends and backends can be compatible with DAPPs and play a very important role in enhancing user experience.
Basic Architecture of DAPP#
Based on our understanding of DAPP, the basic architecture of a DAPP can be simply divided into three parts: frontend, backend, and smart contracts. The frontend and backend are centralized, while the smart contracts are decentralized. Haha, of course, it's not that simple; if it were, there wouldn't be much to write about. Besides the content mentioned above, there are some important foundational services that support the operation of DAPPs. I have provided detailed explanations, and their relationships are shown in the diagram below, which doesn't require much elaboration:
IPFS#
The Chinese name is InterPlanetary File System, which can be understood as a decentralized file storage system, but without the complex consensus mechanism of blockchain, it distinguishes/retrieves files by verifying hash values.
Specifically, but simply put, you can understand it as a group of kind-hearted people maintaining a free storage facility on the internet. Uploaded files will be distributed across many storage facilities around the world (meaning that there are copies on several servers), and by calculating the file's hash value, it avoids duplicate storage. At the same time, users can find the complete data of the corresponding file through the file's hash value.
Of course, nothing is perfect; the price of free is that your files may be deleted at any time. However, IPFS also offers some paid storage services to ensure file storage through Filecoin (blockchain).
RPC Service Providers#
In fact, ordinary applications cannot and do not need to interact directly with the Ethereum network. The detailed underlying knowledge of blockchain will not be elaborated here; interested friends can look it up themselves.
DAPPs only need to "use" the blockchain, not "maintain" it. "Maintaining" the blockchain involves direct interaction with the chain, which means participating in blockchain mining/consensus, requiring synchronization of massive blockchain data. However, "using" the blockchain does not require concern for such vast data; it is similar to ordinary web services, only needing to open some interfaces.
RPC (Remote Procedure Call) service providers essentially provide an API interface, but with a special format requirement. RPC service providers typically run different types of Ethereum nodes (including full nodes, light nodes, or archive nodes) and expose the node functionalities through JSON-RPC interfaces. These interfaces follow Ethereum's JSON-RPC specifications, allowing developers to query blockchain data, send transactions, call smart contracts, etc., via HTTP or WebSocket requests.
Index Service Providers#
You can first look at RPC and then understand index services. This needs to be explained in more detail. When you use RPC to read blockchain data, you cannot query the data you need as freely as you would with a database. Typically, you can only read the current status of a contract or a wallet (like balance) or query detailed information about a single transaction/block or listen for certain events (like whether a new NFT has been minted or whether there are new transactions).
However, as a DApp, you usually need to query all transaction situations of a certain contract from its deployment to the present. Specifically, you might need to check all holders of a certain NFT contract. Without index services, you would need to start from the block where the contract was deployed, recording related NFT mint, transfer, burn, and other transactions block by block.
Theoretically, this is a service that is not so "necessary." If your project is not large, you can completely handle this yourself. However, the demand for such services is similar and universal, which is why index services exist. They check each block, recording relevant transactions in a database, making it convenient for developers to query using standard data query statements (usually providing GraphQL API), helping to reduce the development burden.
Oracles#
The name Oracle sounds grand, but it is essentially the bridge between blockchain and the real world. Consider a question: how does the blockchain know the current price of ETH? Intuitively, could we deploy a smart contract and find a trusted entity to tell the smart contract the price, which the smart contract would then use for subsequent operations? But the problem arises: who guarantees that this entity is trustworthy? We certainly cannot judge the truth of the message based solely on one entity's information; the verification of results must also be decentralized, which is where oracles come into play.
The basic principle of oracles is to ensure data reliability through multiple data sources and multiple data providers. Taking the ETH price as an example, the oracle network obtains ETH/USD price data from multiple exchanges like Coinbase, Binance, Kraken, etc., and then calculates a final price using a weighted average algorithm. If the price provided by a certain exchange differs too much from most other exchanges, it will be identified and excluded by the system. At the same time, data providers (oracle nodes) need to stake tokens as collateral; if they provide incorrect price data, their tokens will be forfeited, thus creating economic incentives to ensure data accuracy.
The most famous oracle project is Chainlink, which has established a large oracle network providing real-time price data for thousands of DeFi DAPPs. When you trade on Uniswap or borrow on Aave, these protocols need to know the accurate prices of various tokens to calculate trading ratios or liquidation conditions, and this price data is provided by oracles like Chainlink.
Recommended Toolchain#
In this section, I will first introduce a more general frontend and backend development toolchain, followed by some toolchains I have encountered on various chains.
General Technologies#
I highly recommend that anyone getting into DApp development prioritize learning JS because once you know JS, you can almost run the entire process by yourself.
Frontend Tech Stack:
- Frontend Framework: Next.js
- Style Library: Tailwind CSS
- UI Library: shadcn/ui
- Alternative Styling Solutions: Bruce's Tweet
- State Management: Zustand
- Form Validation: Zod
- Emerging Tech Stack: TanStack
Deployment and Tools:
- Simple Deployment: Vercel
- Operations Solution: Coolify
- Design Tool: Figma
- Prototyping Tool: Excalidraw
Backend Tech Stack:
- Simple Backend: Next.js API Routes + Vercel serverless functions
- Complex Backend: NestJS
- ORM: Prisma
- Database: PostgreSQL
- Deployment Platform: NorthFlank
Storage Services:
Cost Optimization:
- Recommended to search for "independent development poor ghost package" for more economical solutions.
Ecosystem Toolchain#
Blockchain | Wallet Plugin Links | Contract/Chain Interaction Libraries | Contract Development Framework/Language | RPC Providers | Index Services |
---|---|---|---|---|---|
ETH | RainbowKit, ConnectKit, Web3Modal | ethers.js, viem, web3.js | Foundry, Hardhat, Truffle (Solidity language) | Alchemy, Infura, QuickNode | The Graph, Moralis, Alchemy |
Solana | @solana/wallet-adapter | @solana/web3.js, @solana/spl-token | Anchor (framework), Rust (language) | Helius, QuickNode, Alchemy | Helius, Simple Hash |
BTC | UniSat, Xverse | bitcoinjs-lib, @scure/btc-signer | Bitcoin Script (scripting language) | BlockCypher, Blockstream API | Ordiscan, Blockstream |
Cosmos | @cosmos-kit/react | @cosmjs/stargate, cosmjs | Cosmos SDK (framework), CosmWasm (Rust language) | All Nodes, Stakely | Mintscan, Big Dipper |
Aptos | @aptos-labs/wallet-adapter | @aptos-labs/ts-sdk | Move (language), Aptos Framework | Aptos Labs, Nodereal | Aptos Labs, Aptoscan |
TON | @tonconnect/ui-react | @ton/ton, @ton/crypto | FunC (language), Blueprint (framework) | TonCenter, GetBlock | TonAPI, Toncenter |
In any case, Ethereum is currently the most mature chain, and the following chapters will use Ethereum as an example to introduce the entire process of DAPP development.
NFT Mint DAPP Demo#
Contract Development and Deployment (Choose one of the following)#
Preparation Before Development#
- Create an image: You can consider using your avatar or generating one with AI.
- Upload to Pinata IPFS
- Register and log in.
- Upload the file.
- Record the CID like this: bafkreigfpdewysnl5fq2ir57r26fhxpa6bg3qoy3sbkxlajq6dkf4wye3u
- You can access the image through the IPFS Gateway, like this: https://ipfs.io/ipfs/bafkreigfpdewysnl5fq2ir57r26fhxpa6bg3qoy3sbkxlajq6dkf4wye3u
- Prepare the string ipfs://{CID}, like this: ipfs://bafkreigfpdewysnl5fq2ir57r26fhxpa6bg3qoy3sbkxlajq6dkf4wye3u
- Prepare metadata
- Refer to the content below to write your own Metadata, name (name), description (description), attributes (attributes) can be written at will (note: attributes are an array with fixed contents of trait_type and value).
- Copy the content you just created and make it into a JSON file.
- Refer to the previous steps to upload to IPFS.
- Record the CID and prepare the IPFS URL, like this: ipfs://bafkreid7msiyufvgilrlkt6244psudmaycbbzika2aq57kou3xha5u36pe
{
"name": "My First Handmade NFT",
"description": "My First Handmade NFT by @hardman_eth",
"image": "ipfs://bafkreigfpdewysnl5fq2ir57r26fhxpa6bg3qoy3sbkxlajq6dkf4wye3u",
"attributes": [
{
"trait_type": "IQ",
"value": "80"
},
{
"trait_type": "Hat",
"value": "Pot"
}
]
}
- Prepare the etherscan API key
- Register and log in at https://etherscan.io/login; the mainnet API key is also valid for the testnet.
- Copy the API key and place it in the environment variable .env.
- Add the private key you plan to use for deployment (consider generating one yourself with a script or creating one directly; it is not recommended to use online tools due to security issues).
# Private key for deployment
PRIVATE_KEY=your_private_key_here
# Public Sepolia RPC URL, You can change it to your own private RPC
SEPOLIA_RPC_URL=https://ethereum-sepolia-rpc.publicnode.com
# Etherscan API key for contract verification (free from etherscan.io)
ETHERSCAN_API_KEY=your_etherscan_api_key
- Obtain test tokens
Any write operation on the blockchain requires paying gas fees. Since we are using the testnet, we can obtain some test tokens, also known as "water."
https://www.alchemy.com/faucets/ethereum-sepolia
You can also follow me on Twitter, DM me your address, and I will send you 0.1.
Based on the Foundry Framework#
- Install Foundry; I won't go into detail here; please refer to the official documentation.
- Initialize the Foundry project.
forge init foundry-nft
- Copy the .env file you prepared earlier into the directory.
- Install dependencies (OpenZeppelin).
forge install OpenZeppelin/openzeppelin-contracts
- Write the contract; you can directly ask AI to generate it, using a prompt like "Write a simple NFT contract, free mint, limited to 999 pieces, ipfs://bafkreid7msiyufvgilrlkt6244psudmaycbbzika2aq57kou3xha5u36pe," or refer directly to the contract code in the foundry-simple-nft repository.
- Write unit tests, referring to foundry-nft/test/SimpleNFT.t.sol.
- Prepare the deployment script, referring to foundry-nft/script/DeploySimpleNFT.s.sol.
- Deploy the contract and verify it.
# 1. Copy the environment variable file and fill in the private key
cp .env.example .env
# Edit the .env file to fill in your private key
# 2. Deploy to the Sepolia testnet
source .env && forge script script/DeploySimpleNFT.s.sol --rpc-url $SEPOLIA_RPC_URL --broadcast --verify
# Or use the public RPC to deploy directly
forge script script/DeploySimpleNFT.s.sol --rpc-url https://ethereum-sepolia-rpc.publicnode.com --broadcast
# 3. Or execute step by step
# First deploy
source .env && forge script script/DeploySimpleNFT.s.sol --rpc-url $SEPOLIA_RPC_URL --broadcast
# Then verify (requires contract address)
source .env && forge verify-contract <CONTRACT_ADDRESS> src/SimpleNFT.sol:SimpleNFT \
--etherscan-api-key $ETHERSCAN_API_KEY \
--chain sepolia
Frontend Development#
https://github.com/0xhardman/handmade-nft-frontend master branch
Integrate Wallet Plugins#
- Install RainbowKit, Wagmi, Viem.
npm install @rainbow-me/rainbowkit wagmi [email protected] @tanstack/react-query
- Configure the testnet network.
- Wrap the provider.
- Get a basic understanding of RainbowKit's configuration.
Roughly Understand Common Wagmi Hooks#
- useReadContract: Read data from a single contract.
- useWriteContract: Write data to the contract, such as minting or transferring.
- useAccount: Get basic information about the connected account (address, current network).
- useSignMessage: Sign messages.
- useBalance: Get the gas token balance or ERC20 token balance of the account.
- useWaitForTransactionReceipt: Wait for transaction confirmation.
- useSwitchChain: Switch the current chain.
- useSwitchAccount: Switch accounts.
Obtain ABI Files#
- If the contract is verified, you can download it from the blockchain explorer.
- If it is your own deployment, you can find it from the compiled files.
- For example, in Foundry, you can get it from out/SimpleNFT.out/SimpleNFT.json.
Function Implementation#
- Check the network and prompt to switch.
- Check wallet balance and prompt the user to top up.
- Click the button to call the contract to mint.
- Wait for transaction confirmation and prompt success.
- Display my NFT page.
Other Concepts That Newbies Might Not Know#
Mint#
It can be understood as the initial purchase. For example, buying a piece of art directly from the artist is called minting; your money goes directly to the artist to support them, distinguishing it from buying from a second-hand dealer or another buyer, where the second-hand dealer or buyer makes a profit from the price difference. From a technical perspective, minting refers to creating a new digital asset from a zero address (0x0000...) on the blockchain and assigning it to a user, as opposed to transferring, which moves an asset from one address to another.
What is Gas? Why is there Gas?#
This question is very classic. When I first encountered blockchain, I was also confused about why there were transaction fees for transfers. Moreover, these fees fluctuate; sometimes it's a few dollars, sometimes it's tens of dollars, which is even worse than banks!
In fact, Gas is the "transaction fee" of the Ethereum network, but it is not just a simple fee. Imagine Ethereum as a globally shared supercomputer; if you want this computer to do something for you (like transferring funds or executing smart contracts), you need to pay those who maintain this computer (miners/validators).
Technically, every operation consumes computational resources, and Gas is the unit that measures this resource consumption. A simple transfer might only require 21,000 Gas, but executing a complex smart contract (like trading on Uniswap) might require hundreds of thousands of Gas. Gas prices (Gas Price) change in real-time based on network congestion; when the network is busy, prices are high, and when it's idle, prices are low, similar to surge pricing for taxis.
So why is there Gas? Simply put, it prevents malicious attacks on the network (like infinite loops in code) while incentivizing miners/validators to maintain network security. Without Gas, the entire network would have been paralyzed by various junk transactions long ago.
Why Wait for Block Confirmation?#
Why do I have to wait several seconds or even minutes to see the result after clicking a button? This experience is too poor!
But this is actually an inevitable result of blockchain decentralization. In traditional centralized systems, like Alipay, when you transfer money, you only need to wait for Alipay's server to confirm, and it arrives instantly. But blockchain is different; it has no central server and is maintained by thousands of nodes worldwide.
Specifically, when you initiate a transaction, it is broadcast to the entire network and then waits to be packaged into a new block by miners (or validators). Ethereum generates a new block approximately every 12-15 seconds, so your transaction needs to wait at least one block time to be confirmed.
But that's not all; to prevent chain reorganization (simply put, the blockchain's fork rollback, which is a long story... you can look it up), it is usually recommended to wait for multiple block confirmations. For example, exchanges typically require 12 block confirmations before considering a transaction final, which is why sometimes you have to wait a few minutes.
However, for DAPPs, usually waiting for 1-2 block confirmations is sufficient, which takes about ten seconds to a minute. Although it's slower than centralized systems, the trade-off is the characteristics of decentralization, censorship resistance, and global borderlessness, which I think is worth it.
Recommended Resources#
EVM Ecosystem DApp Scaffold
Learn Blockchain, Solidity, and Full Stack Web3 Development with JavaScript
Web3 Internship Program
Everything You Need to Know About Converting Mnemonics to ETH Addresses
Conclusion#
There is actually a lot more I want to say, but focusing on "getting started" means I can't go too deep. Getting into blockchain isn't that simple; half an hour can only give everyone a "brief overview" of the thick book of DApp development. More practical experience and attempts are still needed!
Feel free to DM me on my Twitter for discussions!