Understanding ERC-20 Code
Tokens are just spreadsheets
When people say "I have 100 USDC in my wallet," they are technically wrong. The USDC is not in their wallet. The USDC smart contract simply has a spreadsheet, and next to their wallet address, the number is 100.
An ERC-20 token is a standardized smart contract. Because every ERC-20 contract has the exact same function names (like transfer and balanceOf), wallets like MetaMask know exactly how to interact with all of them.
Let's look at the core logic of a token contract.
The Core Data Structure: Mappings
To keep track of balances, Solidity uses a mapping. A mapping is like a dictionary or a hash table.
contract SimpleToken {
// This creates a dictionary linking an address to a number
mapping(address => uint256) public balanceOf;
// Total supply of the token
uint256 public totalSupply;
// Token metadata
string public name = "HashtagToken";
string public symbol = "HTG";
uint8 public decimals = 18;
}
In the balanceOf mapping:
- The Key is an
address(e.g.,0xabc...) - The Value is a
uint256(an unsigned integer, meaning no negative numbers).
If you call balanceOf[0xabc...], it returns the token balance of that address.
The Transfer Function
How do tokens move? We just subtract from one address in the mapping and add to another.
// An event we will trigger when tokens move
event Transfer(address indexed from, address indexed to, uint256 value);
function transfer(address _to, uint256 _amount) public returns (bool) {
// 1. Check: Does the sender have enough tokens?
require(balanceOf[msg.sender] >= _amount, "Not enough tokens");
// 2. Execute: Subtract from sender
balanceOf[msg.sender] = balanceOf[msg.sender] - _amount;
// 3. Execute: Add to receiver
balanceOf[_to] = balanceOf[_to] + _amount;
// 4. Log: Emit an event for the outside world
emit Transfer(msg.sender, _to, _amount);
return true;
}
Breaking down the transfer
require: This is our security check. If the caller (msg.sender) tries to send 100 tokens but only has 50, therequirestatement fails. The transaction reverts, no gas is spent on execution, and no balances change.- Math: We directly modify the
balanceOfmapping. The sender loses tokens, the receiver gains them. emit Transfer(...): Blockchains are closed systems. To let frontends (like Etherscan or your React app) know that a transfer happened without them having to constantly read the contract state, we emit an event. Apps listen for these events to update UI histories.
The Decimals Problem
Solidity does not support floating point numbers (decimals). You cannot have 1.5 tokens in the code.
To fix this, tokens use very large integers. When you define decimals = 18 in the contract, it tells the frontend (like MetaMask) to move the decimal point 18 places to the left when showing the number to the user.
If you want to transfer exactly 1 token, you must pass the number 1000000000000000000 (1 followed by 18 zeros) to the transfer function. The smart contract handles the massive integer, but MetaMask formats it nicely as "1.00" for the user.
Key takeaways
- Tokens do not live in wallets; they live in a
mappinginside a smart contract. - Transferring tokens just means doing math: subtracting from the sender's mapping balance and adding to the receiver's.
requirestatements protect against invalid actions (like spending more than you have).- Events are emitted so off-chain apps know when things happen.
- Solidity has no decimals. It uses massive integers, and the frontend handles the visual formatting.
Quiz: Understanding ERC-20 Code
1 / 5What data structure does an ERC-20 contract use to keep track of everyone's token balances?