
Web3: Decentralized Web
Understanding Web3 concepts and applications through practical experience

Understanding Web3 concepts and applications through practical experience
Public APIs face unexpected traffic floods without proper protection. Rate limiting, API key management, and IP restrictions to protect your API.

Started with admin/user roles but requirements grew complex. When RBAC isn't enough, ABAC provides attribute-based fine-grained control.

With 3 services needing separate logins, SSO unified authentication. One login grants access to everything.

Password resets were half my support tickets. Passkeys eliminate passwords entirely, but implementation is more complex than expected.

I'll be honest — I started because of the NFT hype. It was around 2021, when everyone around me was talking about "a monkey picture worth millions." As a developer, I genuinely couldn't wrap my head around how that was technically possible. Why is a JPEG so expensive?
Digging into that question led me to blockchain, which led me to smart contracts, which led me to the entire Web3 ecosystem. This post is my attempt to put down what I understood, in the order I understood it.
The core problem Web3 is trying to solve is this: in Web2, everything is controlled by centralized servers. My photos live on Meta's servers. My account belongs to the platform. If the company decides to delete it, it's gone. Web3 flips this — the idea is to return data ownership to users and build trust without a central authority.
When I first heard this, my reaction was "how is that even possible?" It only clicked after I actually understood how blockchains work.
| Feature | Web1 | Web2 | Web3 |
|---|---|---|---|
| Period | 1990-2004 | 2004-now | Now-future |
| Capability | Read | Read+Write | Read+Write+Own |
| Example | Static sites | SNS, Cloud | DApp, NFT |
| Data | Server | Central platform | Blockchain |
| Ownership | Webmaster | Platform | User |
If Web1 was "read-only internet" and Web2 was "participate and create," Web3 is "actually own what you create." The blockchain is the mechanism that makes ownership possible.
Web2: Client → Central Server → Database
Web3: Client → Blockchain (distributed nodes)
Think about how a bank transfer works. When I send money to a friend, the bank's server records "Account A minus $100, Account B plus $100." We trust this because we trust the institution.
Blockchain replaces the bank server with thousands of nodes spread across the world. To tamper with the ledger, an attacker would need to simultaneously take control of more than half of all nodes. Practically impossible. Instead of trusting an institution, you trust mathematics and cryptography. This is what "trustless" means — not that there's no trust, but that you don't need to trust a third party.
In Web2, you log in with a username and password. In Web3, a wallet replaces that. MetaMask is the most common example.
// Connect MetaMask
const accounts = await window.ethereum.request({
method: 'eth_requestAccounts'
});
console.log('Connected:', accounts[0]);
// 0x742d35Cc6634C0532925a3b844Bc454e4438f44e
Every wallet has two keys: a public key (your address — safe to share) and a private key (never share this, ever). When you sign a transaction with your private key, the network uses your public key to verify "yes, this person actually sent this." The signature is the authentication.
When I first installed MetaMask, it gave me a 12-word seed phrase and told me to write it down. I thought, "how important can this be?" Later I understood: those 12 words are the master key to everything. Lose them and no one can help you recover access. There's no customer service line to call, no "forgot password" button. That's what self-custody actually means.
A smart contract is code deployed on the blockchain. Once deployed, it cannot be modified, and it executes automatically when its conditions are met.
contract Token {
mapping(address => uint256) public balances;
function transfer(address to, uint256 amount) public {
require(balances[msg.sender] >= amount, "Insufficient balance");
balances[msg.sender] -= amount;
balances[to] += amount;
}
}
This looks like ordinary code at first. The difference is where it runs. This code is deployed across the entire Ethereum network. I can't shut down the server. No one can alter the code. That's what makes require so important — if there's a bug, money is gone and there's no rollback.
The thing that surprised me most about Solidity was msg.sender. The address of whoever is calling the function is automatically available. No separate authentication needed. Wallet signatures handle authentication. The moment that clicked, I understood how DApps can work without logins.
Vitalik Buterin coined this term. A blockchain can only reliably have two of three properties at once:
Bitcoin and Ethereum chose decentralization and security. They're slow. Ethereum mainnet handles roughly 15–30 TPS. Visa processes tens of thousands per second. That gap is enormous.
Layer 2 solutions are an attempt to bridge it. The idea: process transactions off-chain, then post only the proof to Ethereum mainnet. Using the bank analogy again — track small transactions in a side ledger, then report the net total to the bank periodically.
When I first heard about Layer 2, my concern was "doesn't this just re-centralize things?" The answer is: partially, but the proofs are posted to mainnet, so if a Layer 2 operator behaves maliciously, anyone can challenge it. It's not perfect decentralization, but it's a practical tradeoff that unlocks real scale.
DeFi replaces financial intermediaries with smart contracts. Instead of a bank taking deposits and lending them out for profit, code manages liquidity and distributes interest automatically.
Here's how I think about it. Traditional finance has a middleman: the bank. I deposit money, the bank lends it to others and keeps the spread. DeFi replaces that middleman with a smart contract. The code sets the rules and enforces them automatically.
DEX (Decentralized Exchange)Uniswap uses an AMM (Automated Market Maker) instead of an order book. There's a liquidity pool holding two assets, governed by the formula x * y = k. When you sell ETH, the pool's ETH increases and USDC decreases, automatically adjusting the price. No matching engine, no order book, no counterparty needed.
Aave and Compound let you deposit crypto and earn interest, or borrow against collateral. No credit check, no bank approval. The contract monitors your collateral ratio and automatically liquidates if it drops below the threshold. Open to anyone with a wallet, anywhere in the world.
StablecoinsUSDC and USDT are fiat-backed and pegged 1:1 to the dollar. DAI is crypto-collateralized — you lock up ETH to mint DAI. Each model has different trust assumptions.
The thing that struck me when I first used DeFi was the absence of permission. There's no application form for Uniswap. You just connect a wallet and call a function. That's also why there's no customer service when something goes wrong. The same property that enables permissionless access means there's no one to call.
.sol)Blockchains are isolated by design. A smart contract cannot make an HTTP request to api.weather.com. It can only read from the chain.
Oracles like Chainlink bridge this gap. An off-chain node fetches real-world data (price feeds, sports results, weather), signs it, and submits a transaction to put that data on-chain. Smart contracts then read from the oracle contract. The trust question just shifts: now you trust the oracle network instead of the chain itself.
Storing 1GB on Ethereum would cost millions of dollars. So most DApps store files on IPFS (InterPlanetary File System) and put only the hash on-chain.
IPFS uses content addressing: files are identified by the hash of their content (CID), not by location. If you change a single pixel in an image, the CID changes entirely. This is how NFT metadata achieves immutability. The catch: someone has to "pin" the file to keep it available. Services like Pinata handle this. If no one pins it, the file disappears.
import { create } from 'ipfs-http-client';
const ipfs = create({ url: 'https://ipfs.infura.io:5001' });
// Upload file
const { cid } = await ipfs.add('Hello Web3!');
console.log('IPFS CID:', cid.toString());
// Retrieve file
const data = await ipfs.cat(cid);
Here's the core connection pattern I kept coming back to when building:
import { ethers } from 'ethers';
// Provider: connects to the blockchain network
const provider = new ethers.providers.Web3Provider(window.ethereum);
// Signer: the wallet that will sign transactions
const signer = provider.getSigner();
// Contract instance: the interface to your deployed contract
const contract = new ethers.Contract(contractAddress, ABI, signer);
// Read (no gas cost)
const balance = await contract.balances(address);
// Write (costs gas, requires signing)
const tx = await contract.transfer(toAddress, amount);
await tx.wait(); // Wait for transaction to be confirmed
The ABI (Application Binary Interface) confused me at first. When you compile a Solidity contract, you get two outputs: Bytecode (the EVM machine code) and ABI (a JSON description of what functions exist and what their parameters are). Without the ABI, ethers.js has no idea how to communicate with the contract. It's just an opaque binary blob.
My first successful transaction on a testnet was a genuine milestone. I got fake ETH from a Sepolia faucet, deployed a contract I wrote, called a function, and watched the state change — all without a central server anywhere in the picture. That was the moment the concept stopped being abstract.
// ERC-721 NFT
contract MyNFT is ERC721 {
uint256 public tokenCounter;
constructor() ERC721("MyNFT", "MNFT") {
tokenCounter = 0;
}
function mint(string memory tokenURI) public returns (uint256) {
uint256 newTokenId = tokenCounter;
_safeMint(msg.sender, newTokenId);
_setTokenURI(newTokenId, tokenURI);
tokenCounter++;
return newTokenId;
}
}
The tokenURI points to JSON metadata stored on IPFS. That JSON contains the image CID, name, and attributes. So an NFT is really: a blockchain record saying "this unique token ID, pointing to this metadata hash, is owned by this address." The JPEG is not on the blockchain. Whether that makes it worth millions is a separate question.
Ethereum's ecosystem has agreed-upon interface specs:
Without a central authority, how does everyone agree on the same ledger state? That's what consensus algorithms solve.
Bitcoin's mechanism. Nodes compete to solve a computationally hard puzzle. The winner gets to write the next block and earns a reward. This is mining.
Ethereum's mechanism since "The Merge" in 2022. Validators stake ETH as collateral to earn the right to validate blocks. Malicious behavior results in slashing — losing part of the staked ETH.
Watching Ethereum actually execute this transition in real time was fascinating. Replacing the consensus mechanism on a live chain with hundreds of billions of dollars in assets on it — while keeping it running — is one of the most technically ambitious things I've seen pulled off in software.
Every operation costs gas. Efficient code saves real money for users.
Storage is the most expensive operation. Writing to a state variable (SSTORE) costs 20,000 gas. Reading (SLOAD) costs 200–800 gas. Use memory or calldata for temporary values instead of writing to storage.
Variable packing matters too:
// Inefficient: uses three 32-byte storage slots
uint128 a;
uint256 b;
uint128 c;
// Efficient: uses two 32-byte storage slots
uint128 a;
uint128 c; // Packed with a in the same slot
uint256 b;
The EVM operates in 32-byte slots. Variables smaller than 32 bytes that are declared consecutively get packed into the same slot. This reduces storage writes and saves gas. Writing code where byte alignment directly affects costs is a genuinely unusual programming environment.
"Code is Law" also means bugs are law. Once deployed, there's no patch.
Reentrancy AttackA function sends ETH before updating the sender's balance. A malicious contract's fallback function calls the withdraw function recursively, draining funds before the balance ever gets updated. This is how the DAO Hack in 2016 drained 3.6 million ETH. The controversy over whether to roll back the chain split Ethereum into ETH and ETC.
Rug PullDevelopers grant themselves admin control in the contract — the ability to drain the liquidity pool or mint unlimited tokens. They build hype, attract investment, then exercise that hidden control and disappear with the funds.
PhishingFake minting sites prompt users to connect their wallet. The user signs a transaction they think is innocent. Instead, it's an approval for the attacker to transfer all assets. The signature itself is the attack surface.
Smart contract audits exist for a reason. Contracts holding hundreds of millions of dollars can be completely drained by a few lines of flawed logic.
When I started learning Web3, I was skeptical about whether it would ever be practically useful. That skepticism is still partly warranted — most NFT projects failed, speculation drove irresponsible behavior, and scams are everywhere.
But the underlying technology deserves serious attention. Two parties transacting directly without needing to trust a third party. Code that enforces rules automatically and transparently. Users who genuinely own their data and assets. These are real ideas with real implications.
Where they matter most isn't monkey JPEGs. It's financial access for people without bank accounts. Censorship-resistant communication. Organizations governed by code rather than politics. The tool has genuine use cases — it's a question of where you point it.
That's what I keep coming back to as I continue building in this space. Technology is a tool. What it becomes depends entirely on what people choose to build with it.