Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

1 Commit
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸͺ™ ERC20 Token Contract

A fully compliant ERC20 token implementation built from scratch in Solidity, tested with Brownie and Python. Includes standard token functionality plus minting, burning, and approval race condition protection.


πŸ“‹ Table of Contents


Overview

This project implements a secure ERC20 token from scratch without relying on OpenZeppelin or any external libraries. Every function is hand-written and tested to demonstrate a deep understanding of the ERC20 standard, token economics, and Solidity security patterns.

The token supports the full ERC20 interface β€” transfers, approvals, delegated transfers β€” plus owner-controlled minting and public burning.


Features

  • Full ERC20 compliance β€” All six standard functions implemented
  • Minting β€” Owner can create new tokens and assign them to any address
  • Burning β€” Any token holder can permanently destroy their own tokens
  • Approval race condition protection β€” Prevents the classic double-spend attack on allowances
  • 18 decimal precision β€” Standard Ethereum token denomination
  • Event emission β€” Transfer and Approval events on every state change
  • Owner access control β€” Mint restricted to the deploying address

Project Structure

erc20-token/
β”‚
β”œβ”€β”€ contracts/
β”‚   └── MyToken.sol         # ERC20 token contract
β”‚
β”œβ”€β”€ tests/
β”‚   └── test_token.py       # Full test suite (23 tests)
β”‚
β”œβ”€β”€ build/                  # Auto-generated compiled artifacts
└── brownie-config.yaml     # Brownie project configuration

Smart Contract

State Variables

Variable Type Description
name string Full token name (e.g. "My Token")
symbol string Short ticker symbol (e.g. "MTK")
decimals uint8 Token precision β€” hardcoded to 18
totalSupply uint256 Total tokens in existence
owner address Deployer address β€” controls minting
balances mapping(address => uint256) Token balance per address
allowances mapping(address => mapping(address => uint256)) Approved spending limits

Events

Event Parameters Emitted When
Transfer from (indexed), to (indexed), value Tokens move between addresses, minted, or burned
Approval owner (indexed), spender (indexed), value A spending allowance is set

Transfer from address(0) signals a mint. Transfer to address(0) signals a burn. Block explorers like Etherscan use this convention to label transactions correctly.

Functions

Function Access Description
transfer(to, value) Public Send your own tokens to another address
approve(spender, value) Public Authorise another address to spend your tokens
transferFrom(from, to, value) Public Spend tokens on behalf of an approved owner
allowance(owner, spender) Public view Check approved spending limit
mint(to, value) Owner only Create new tokens and assign to an address
burn(value) Public Destroy your own tokens permanently

Getting Started

Prerequisites

  • Python 3.9+
  • Node.js 16+
  • pip

Installation

1. Clone the repository:

git clone https://github.com/YOUR_USERNAME/erc20-token.git
cd erc20-token

2. Create and activate a virtual environment:

python -m venv env
source env/bin/activate        # macOS/Linux
env\Scripts\activate           # Windows

3. Install Brownie:

pip install eth-brownie

4. Install Ganache:

npm install -g ganache

5. Compile the contract:

brownie compile

Running Tests

brownie test

Verbose mode β€” shows each test name individually:

brownie test -v

Test Coverage β€” 23 Tests

Deployment

Test What It Verifies
test_token_name Name stored correctly on deployment
test_token_symbol Symbol stored correctly
test_token_decimals Decimals hardcoded to 18
test_token_total_supply Supply calculated with correct decimal conversion
test_deployer_receives_total_supply All tokens sent to deployer on mint

Transfer

Test What It Verifies
test_transfer_succeeds Valid transfer updates recipient balance
test_transfer_deducts_sender_balance Sender balance decreases correctly
test_transfer_insufficient_balance Underfunded transfer is rejected
test_transfer_to_zero_address_fails Zero address transfers are blocked

Approve

Test What It Verifies
test_approve_sets_allowance Allowance recorded correctly
test_approve_requires_reset_to_zero Cannot change allowance without resetting first
test_approve_reset_to_zero_succeeds Allowance can be cleared to zero

TransferFrom

Test What It Verifies
test_transfer_from_succeeds Approved spender can move tokens
test_transfer_from_deducts_allowance Allowance reduces after use
test_transfer_from_exceeds_allowance Over-allowance transfer is rejected
test_transfer_from_without_approval_fails Unapproved spender is rejected

Mint

Test What It Verifies
test_owner_can_mint Owner can create new tokens
test_mint_increases_total_supply Total supply increases by minted amount
test_non_owner_cannot_mint Non-owners are rejected
test_mint_to_zero_address_fails Cannot mint to zero address

Burn

Test What It Verifies
test_holder_can_burn_tokens Token holder can destroy their own tokens
test_burn_decreases_total_supply Total supply decreases by burned amount
test_cannot_burn_more_than_balance Cannot burn more than you hold

Security Considerations

Approval Race Condition Protection

The standard ERC20 approve function has a known vulnerability where a spender can exploit the window between two approval transactions to spend both the old and new allowance.

This contract defends against it by requiring the allowance to be reset to zero before setting a new value:

require(
    _value == 0 || allowances[msg.sender][_spender] == 0,
    "Reset allowance to 0 first"
);

Safe flow:

approve(spender, 100)   β†’ allowance = 100
approve(spender, 0)     β†’ allowance = 0    ← reset first
approve(spender, 50)    β†’ allowance = 50   ← now safe to set new value

Checks-Effects-Interactions Pattern

Every state-changing function follows this order:

  1. Checks β€” all require statements run first
  2. Effects β€” state variables are updated
  3. Interactions β€” events are emitted last

This order prevents reentrancy attacks by ensuring state is always updated before any external communication occurs.

Overflow Protection

Built on Solidity ^0.8.0 which includes automatic overflow and underflow protection at the compiler level. No SafeMath library required.

Mint to Zero Address

Minting to address(0) is explicitly blocked. Tokens sent to the zero address are permanently unrecoverable β€” effectively burned without reducing totalSupply, which would corrupt token economics.


Key Concepts

Decimals and Token Units

Solidity has no floating point numbers. Token amounts are stored as whole integers with an implied decimal point.

1 token with 18 decimals is stored as:
1000000000000000000  (1 followed by 18 zeros)

When you call transfer(recipient, 100 * 10**18)
you are transferring exactly 100 tokens

The approve / transferFrom Pattern

This two-step pattern allows smart contracts to spend tokens on your behalf β€” essential for DeFi protocols like Uniswap, Aave, and Compound.

Step 1 β€” You call approve(uniswap, 100 * 10**18)
         "I authorise Uniswap to spend up to 100 of my tokens"

Step 2 β€” Uniswap calls transferFrom(you, uniswap, 100 * 10**18)
         "Uniswap claims the authorised tokens"

Mint and Burn Conventions

Action Transfer Event
Mint Transfer(address(0), recipient, amount)
Burn Transfer(holder, address(0), amount)

The zero address as source or destination is the universal on-chain signal for token creation and destruction.


Roadmap

  • Add increaseAllowance and decreaseAllowance helper functions
  • Add transferOwnership function
  • Implement token pause functionality for emergency stops
  • Deploy to Sepolia testnet
  • Add a token vesting schedule for gradual release of minted tokens

Tech Stack

  • Solidity ^0.8.0 β€” Smart contract language
  • Brownie 1.21.0 β€” Python Ethereum development framework
  • Ganache β€” Local Ethereum blockchain
  • web3.py β€” Ethereum Python library
  • pytest β€” Test runner

License

MIT

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages