Two halves of one app
Think of an ordinary banking website. You see a polished screen in your browser — buttons, balances, a Send button — but the real money lives on the bank's servers, locked behind the company's database. The screen is just a friendly window onto a vault you can't see and don't control.
A decentralized app keeps the friendly window but swaps out the vault. The front-end is a normal website that can live on any server (even your laptop); the *logic and the money* sit in a smart contract on a public chain like Ethereum. So a dApp is really two halves: a front-end you look at, and on-chain code you can't fake or shut down. The front-end can vanish tomorrow and the contract — and your funds — carry on exactly as before.
The wallet as your signing pen
Your wallet isn't a place where coins are stored — those numbers live on the chain. The wallet's real job is to guard one secret: your private key. Think of that key as a signing pen that only you hold, with a signature no one else on Earth can forge. When a dApp wants you to do something, your wallet uses the pen to sign the request, proving the order genuinely came from you.
The cryptography behind that pen is a digital signature. The magic is one-way: your private key creates a signature that anyone can check against your public address, yet no amount of checking ever reveals the key itself. So the whole network can confirm *"yes, the owner of this account really authorized this"* without ever seeing your secret. Sign first, then the signed request can travel safely across the open internet.
Reading is free, writing costs gas
Every interaction with a contract falls into one of two buckets, and the difference decides whether you ever open your wallet. Reading asks the chain a question — *what's my balance? who owns this item?* — and changes nothing. Any node can answer from data it already holds, so reads are instant and free; no signature, no fee. That's why a dApp can show your balances the moment the page loads, before you've approved anything.
Writing is the other bucket: it *changes the shared state* — sending tokens, casting a vote, minting an item. A write has to be re-run and agreed on by every node on the network, then stored forever, so it can't be free. It must be a signed transaction and it carries a gas fee that pays for that worldwide computation. Reading is a librarian glancing at a shelf; writing is everyone in the library rewriting their copy of the book at once.
READ (a question) WRITE (a change)
cost: free cost: gas fee
signature: none signature: required
speed: instant speed: wait for a block
example: getBalance() example: transfer(to, 10)
Flow of a write:
front-end drafts tx -> wallet shows it -> YOU sign
-> broadcast -> a validator includes it in a block
-> every node re-runs it -> state updated foreverToken approvals: handing over a spending limit
Here is one move that trips up newcomers. Most contracts can't reach into your wallet and pull out your tokens — and that's by design. So when a dApp needs to move tokens *on your behalf* (say, a trading app swapping one coin for another), you first sign a separate transaction called an approval. It tells the token contract: *"this other contract is allowed to spend up to N of my tokens."*
// Solidity: the approval lives in the TOKEN contract
function approve(address spender, uint amount) public {
allowance[msg.sender][spender] = amount; // set a limit
}
// Later the dApp's contract may pull tokens, but only
// up to the limit you set:
// transferFrom(you, someoneElse, amount <= allowance)
// approve(dApp, 50) -> safe, capped at 50
// approve(dApp, UNLIMITED) -> convenient, but riskyApprovals are genuinely useful — they let an app act smoothly without nagging you to sign on every step. But the catch is the amount. To save you future popups, many dApps ask for an unlimited allowance, and people click through without reading. If that spending contract later turns out to be buggy or malicious, that standing permission is exactly what lets it drain the approved tokens. The fix is simple: prefer approving only the amount you're actually spending, and revoke old allowances you no longer use.
Putting it together
- Open the dApp. Its front-end loads and *reads* the chain for free to show your balances — no wallet popup yet.
- Click an action. The front-end *drafts* a transaction (for example, a swap) and hands it to your wallet — it cannot send it itself.
- Read and sign. Your wallet shows the request and the gas estimate; your signature turns it into a valid, authorized transaction.
- The network settles it. The signed write is broadcast, included in a block, re-run by every node, and recorded on-chain forever.
That's the whole pattern. A dApp is a front-end plus on-chain code; your wallet is the pen that signs; reads are free questions while writes are paid changes; and an approval is a spending limit worth setting carefully. Next we'll look at the tokens themselves — the standards that let one contract issue a coin or a collectible that every wallet and app instantly knows how to handle.