Skip to content

Latest commit

 

History

History
911 lines (676 loc) · 23.9 KB

File metadata and controls

911 lines (676 loc) · 23.9 KB

Simple Token - ERC20 with Transfer Fees

Project 1.1: Token ERC20 com Taxas (ERC20 Token with Fees)

Solidity Hardhat OpenZeppelin License Tests

Educational Smart Contract Project - Production-quality code with comprehensive documentation, security analysis, and architecture design decisions.

Author: Wesley Santos | Status: Educational/Testnet Ready | Last Updated: February 2026


📑 Documentation Index

🎯 Navigate Efficiently: See DOCUMENTATION_INDEX.md for reading paths and detailed descriptions

This project includes 10 comprehensive documents (~200 pages) covering everything from beginner tutorials to production deployment planning:

📘 Core Documentation (Start Here)

Document Length Audience Purpose
README.md 20 pages Everyone Project overview, features, installation
TUTORIAL.md 25 pages Beginners Step-by-step hands-on guide
QUICK_REFERENCE.md 15 pages Developers Command cheatsheet

🔒 Security & Architecture (For Technical Reviews)

Document Length Audience Purpose
SECURITY.md 30 pages Auditors, Security Threat model & attack vectors
ARCHITECTURE.md 25 pages Engineers Design decisions & trade-offs
TEST_COVERAGE.md 20 pages QA, Auditors Test strategy & coverage

🚀 Production & Career (For Serious Projects)

Document Length Audience Purpose
PRODUCTION_READINESS.md 25 pages Founders, CTOs Mainnet checklist ($80k-225k budget)
PORTFOLIO_SHOWCASE.md 25 pages Job Seekers Career value & interview tips
PROJECT_SUMMARY.md 5 pages Everyone Quick reference card

🎯 Advanced Topics

Document Length Audience Purpose
CHALLENGES.md 15 pages Intermediate+ Enhancement ideas

📚 Total Documentation

  • 10 files | ~200 pages | ~50,000 words | 50+ code examples | 30+ tables

Real-World Use Cases | Casos de Uso no Mundo Real

Practical Applications | Aplicações Práticas

This token mechanism is used by several real-world projects and platforms. Here are practical examples:

1. Deflationary Community Tokens

  • Use Case: Create scarcity and value appreciation through automatic token burning
  • Example: A community launches a token with 1 billion supply. With 2% burn on transfers, the circulating supply decreases over time, potentially increasing value for holders
  • Real Projects:
    • SafeMoon - Implements transaction fees with burn mechanism (3% burn, 2% redistribution)
    • Shiba Inu - Uses burn mechanisms to reduce supply over time
    • BabyDoge - 5% fee split between holders and liquidity

2. DeFi Platforms with Transaction Fees

  • Use Case: Generate revenue for protocol treasury or liquidity pools
  • Example: A DEX uses a governance token where 2% of transfers go to staking rewards or protocol development
  • Real Projects:
    • Reflect Finance (RFI) - Pioneered the reflection/fee mechanism
    • Safuu - Auto-staking with rebase mechanism and fees
    • EverGrow - Rewards holders in stablecoins from transaction fees

3. Loyalty and Rewards Programs

  • Use Case: Corporate loyalty programs where large transfers have fees but small purchases don't
  • Example: A retail chain creates a token. Customers earn tokens (whitelisted), but secondary market trading has fees to discourage speculation
  • Real Projects:
    • Crypto.com (CRO) - Used for cashback and rewards (no transfer fees, but similar whitelist concepts)
    • Binance Coin (BNB) - Fee discounts on platform

4. Gaming Economies

  • Use Case: In-game currency with anti-bot and anti-farming measures
  • Example: Game tokens where player-to-player trades have small fees, but official game transactions are whitelisted
  • Real Projects:
    • Axie Infinity (SLP/AXS) - Gaming tokens with marketplace fees
    • The Sandbox (SAND) - Gaming platform token with transaction controls

5. Charity and Redistribution Tokens

  • Use Case: Automatic donations to charity wallets or holder redistribution
  • Example: 2% of every transfer goes to a charity wallet (whitelisted), creating passive donations
  • Real Projects:
    • ElonGate - 10% transaction fee split between charity and holders
    • FEG Token - Redistribution to holders on every transaction

Similar Mechanisms in Production | Mecanismos Similares em Produção

Tokens with Transfer Fees:

  1. SafeMoon (SAFEMOON) - 10% fee (5% to holders, 5% to liquidity)
  2. Reflect Finance (RFI) - 1% fee redistributed to all holders
  3. Bonfire (BONFIRE) - 10% fee (5% burn, 5% liquidity)
  4. PigToken (PIG) - Automatic burn mechanism

Platforms Using Fee Mechanisms:

  1. Uniswap V2/V3 - 0.3% swap fee
  2. PancakeSwap - 0.25% trading fee
  3. SushiSwap - Fee sharing with token holders
  4. Curve Finance - Trading fees distributed to veCRV holders

Key Differences:

  • This implementation uses automatic burning instead of redistribution
  • Whitelist system for flexible fee exemptions
  • Owner-controlled fee percentage (adjustable)
  • Maximum transaction limits for security
  • Pausable for emergency situations

When to Use This Pattern | Quando Usar Este Padrão

Good for:

  • Community-driven tokens with deflationary tokenomics
  • Loyalty programs with secondary market controls
  • Gaming tokens with anti-bot measures
  • Projects wanting to reward long-term holders
  • Tokens needing revenue generation mechanism

Avoid for:

  • Payment tokens (fees reduce usability)
  • Utility tokens with high-frequency usage
  • Stablecoins (fees affect peg stability)
  • Integration with DeFi protocols (fees complicate liquidity)

Table of Contents


Overview

This project implements a custom ERC20 token with a 2% transfer fee mechanism. It demonstrates fundamental Solidity concepts including:

  • ERC20 standard implementation using OpenZeppelin
  • Custom fee logic with automatic burning
  • Whitelist functionality for fee exemption
  • Access control with Ownable pattern
  • Pausable mechanism for emergency situations
  • Maximum transaction limits

Learning Focus: This is a beginner-level project designed to solidify understanding of ERC20 tokens, state management, modifiers, events, and best practices in Solidity development.


Features

Core Functionality

  1. Transfer with 2% Fee

    • Every transfer deducts a 2% fee from the sender
    • Fee is automatically burned (removed from total supply)
    • Reduces inflation over time
  2. Whitelist System

    • Addresses on the whitelist pay no fees
    • Owner can add/remove addresses from whitelist
    • Deployer is automatically whitelisted
  3. Configurable Fee

    • Owner can change fee percentage (0% to 10% maximum)
    • Fee stored in basis points (200 = 2%)
    • Cannot exceed MAX_FEE_PERCENT (1000 = 10%)
  4. Maximum Transaction Limit

    • Optional maximum amount per transaction
    • Can be set or removed by owner
    • Helps prevent large dumps
  5. Pausable Transfers

    • Owner can pause all transfers in emergency
    • Can be unpaused when situation is resolved
    • Useful for security incidents or upgrades

Advanced Features

  • Custom Errors: Gas-efficient error handling (Solidity 0.8.4+)
  • Events: Comprehensive event emission for off-chain tracking
  • View Functions: Calculate fees and check contract state
  • NatSpec Documentation: Full inline documentation for all functions

Technical Specifications

  • Solidity Version: 0.8.33
  • License: MIT
  • Standards: ERC20 (OpenZeppelin 5.x)
  • Development Framework: Hardhat
  • Testing: Chai + Ethers.js
  • Network: Hardhat Network (local), Sepolia (testnet)

Dependencies

{
  "hardhat": "^2.22.0",
  "@nomicfoundation/hardhat-toolbox": "^5.0.0",
  "@openzeppelin/contracts": "^5.x"
}

Prerequisites

Required Software

  1. Node.js (v20 or higher)

    node --version  # Should show v20.x or higher
  2. npm (comes with Node.js)

    npm --version   # Should show 10.x or higher
  3. Git (for version control)

    git --version

Recommended Tools

  • VS Code with Solidity extension
  • MetaMask (for testnet deployment)
  • Sepolia ETH (for testnet deployment - get from faucet)

Installation

Step 1: Clone or Navigate to Project

cd .../solidity-projects/01-simple-token

Step 2: Install Dependencies

# Install Node.js dependencies
# Instalar dependências Node.js
npm install

This installs:

  • Hardhat and all plugins
  • OpenZeppelin contracts
  • Testing libraries (Chai, Ethers.js)
  • Development tools

Step 3: Verify Installation

# Check Hardhat installation
# Verificar instalação do Hardhat
npx hardhat version

# Compile contracts to test setup
# Compilar contratos para testar configuração
npx hardhat compile

You should see:

Solidity 0.8.33 is not fully supported yet...
Compiled 8 Solidity files successfully

Project Structure

01-simple-token/
├── contracts/
│   └── SimpleToken.sol          # Main ERC20 token with fees
├── test/
│   └── SimpleToken.test.js      # Comprehensive test suite (47 tests)
├── scripts/
│   └── deploy.js                # Deployment script with verification
├── ignition/
│   └── modules/                 # Alternative deployment method (Hardhat Ignition)
├── hardhat.config.js            # Hardhat configuration
├── package.json                 # Project dependencies
├── .gitignore                   # Git ignore rules
└── README.md                    # This file

Smart Contract Details

SimpleToken.sol

Inheritance Hierarchy:

SimpleToken
├── ERC20 (OpenZeppelin)
├── Ownable (OpenZeppelin)
└── Pausable (OpenZeppelin)

Key State Variables

uint256 public feePercent;              // Current fee in basis points (200 = 2%)
uint256 public constant MAX_FEE_PERCENT = 1000;  // Maximum 10% fee
uint256 public maxTransactionAmount;    // Max amount per transaction (0 = no limit)
mapping(address => bool) public whitelist;       // Fee-exempt addresses
uint256 public totalFeesBurned;         // Cumulative fees burned

Main Functions

Transfer Functions

// Transfer tokens with automatic fee deduction
// Transferir tokens com dedução automática de taxa
function transfer(address to, uint256 amount) public override returns (bool)

// Transfer from another address (requires approval)
// Transferir de outro endereço (requer aprovação)
function transferFrom(address from, address to, uint256 amount) public override returns (bool)

Admin Functions (Owner Only)

// Change fee percentage (0-1000 basis points)
// Mudar porcentagem de taxa (0-1000 pontos base)
function setFeePercent(uint256 newFeePercent) external onlyOwner

// Add address to whitelist (no fees)
// Adicionar endereço à whitelist (sem taxas)
function addToWhitelist(address account) external onlyOwner

// Remove address from whitelist
// Remover endereço da whitelist
function removeFromWhitelist(address account) external onlyOwner

// Set maximum transaction amount
// Definir valor máximo de transação
function setMaxTransactionAmount(uint256 amount) external onlyOwner

// Pause/Unpause all transfers
// Pausar/Despausar todas as transferências
function pause() external onlyOwner
function unpause() external onlyOwner

View Functions (Read-Only)

// Calculate fee for a given amount
// Calcular taxa para um dado valor
function calculateFee(uint256 amount) external view returns (uint256 feeAmount, uint256 transferAmount)

// Check if address is whitelisted
// Verificar se endereço está na whitelist
function isWhitelisted(address account) external view returns (bool)

// Get all contract information in one call
// Obter todas informações do contrato em uma chamada
function getContractInfo() external view returns (...)

Events

event FeePercentChanged(uint256 oldFeePercent, uint256 newFeePercent, uint256 timestamp);
event WhitelistAdded(address indexed account, uint256 timestamp);
event WhitelistRemoved(address indexed account, uint256 timestamp);
event FeeBurned(address indexed from, address indexed to, uint256 amount, uint256 timestamp);
event MaxTransactionAmountChanged(uint256 oldAmount, uint256 newAmount, uint256 timestamp);

Custom Errors

error FeePercentTooHigh(uint256 requested, uint256 maximum);
error InvalidAddress();
error TransactionAmountTooHigh(uint256 amount, uint256 maximum);
error TransferToZeroAddress();
error ZeroAmount();

Testing

Run All Tests

# Run complete test suite
# Executar suite completa de testes
npx hardhat test

Expected output:

SimpleToken
  Deployment
    ✓ Should set the correct token name and symbol
    ✓ Should mint initial supply to deployer
    ... (47 tests total)

47 passing (2s)

Run Specific Test File

npx hardhat test test/SimpleToken.test.js

Run with Gas Reporter

# Enable gas reporting
# Habilitar relatório de gas
REPORT_GAS=true npx hardhat test

Test Coverage

# Generate coverage report
# Gerar relatório de cobertura
npx hardhat coverage

Test Categories

  1. Deployment Tests (9 tests)

    • Token initialization
    • Parameter validation
    • Initial state
  2. Transfer Tests (8 tests)

    • Fee deduction
    • Whitelist functionality
    • Fee burning
    • Edge cases
  3. TransferFrom Tests (2 tests)

    • Allowance mechanism
    • Fee with approvals
  4. Whitelist Management (5 tests)

    • Add/remove addresses
    • Access control
    • Event emission
  5. Fee Management (5 tests)

    • Change fee percentage
    • Validation
    • Events
  6. Max Transaction Tests (4 tests)

    • Set/remove limits
    • Enforcement
  7. Pausable Tests (5 tests)

    • Pause/unpause
    • Transfer prevention
  8. View Functions (3 tests)

    • Read-only operations
    • Calculations
  9. Edge Cases (4 tests)

    • Complex scenarios
    • Multiple transfers
    • Different fee percentages
  10. Gas Optimization (2 tests)

    • Custom errors usage

Deployment

Deploy to Local Network

# Start local Hardhat node (in separate terminal)
# Iniciar node Hardhat local (em terminal separado)
npx hardhat node

# Deploy to local network (in another terminal)
# Fazer deploy na rede local (em outro terminal)
npx hardhat run scripts/deploy.js --network localhost

Deploy to Sepolia Testnet

Step 1: Get Sepolia ETH

Get test ETH from a Sepolia faucet:

Step 2: Set Up Environment Variables

Create a .env file in project root:

# Create .env file
# Criar arquivo .env
touch .env

Add your private key and RPC URL:

PRIVATE_KEY=your_private_key_here
SEPOLIA_RPC_URL=https://sepolia.infura.io/v3/YOUR_INFURA_KEY
ETHERSCAN_API_KEY=your_etherscan_api_key

IMPORTANT: Never commit .env to Git! It's already in .gitignore.

Step 3: Update hardhat.config.js

Uncomment the Sepolia network configuration:

sepolia: {
  url: process.env.SEPOLIA_RPC_URL || "",
  accounts: process.env.PRIVATE_KEY ? [process.env.PRIVATE_KEY] : [],
  chainId: 11155111,
},

Step 4: Deploy

# Deploy to Sepolia
# Fazer deploy na Sepolia
npx hardhat run scripts/deploy.js --network sepolia

Step 5: Verify on Etherscan

# Verify contract (use output from deploy script)
# Verificar contrato (usar output do script de deploy)
npx hardhat verify --network sepolia <CONTRACT_ADDRESS> "Simple Token" "SMPL" "1000000000000000000000000" "200"

Interacting with the Contract

Using Hardhat Console

# Open Hardhat console
# Abrir console Hardhat
npx hardhat console --network localhost
// Get contract instance
// Obter instância do contrato
const SimpleToken = await ethers.getContractFactory("SimpleToken");
const token = await SimpleToken.attach("CONTRACT_ADDRESS");

// Check balance
// Verificar saldo
const [owner] = await ethers.getSigners();
const balance = await token.balanceOf(owner.address);
console.log("Balance:", ethers.formatEther(balance));

// Transfer tokens
// Transferir tokens
const tx = await token.transfer("RECIPIENT_ADDRESS", ethers.parseEther("100"));
await tx.wait();

// Add to whitelist
// Adicionar à whitelist
await token.addToWhitelist("ADDRESS");

// Change fee
// Mudar taxa
await token.setFeePercent(300); // Change to 3%

Using Ethers.js Script

Create a script in scripts/interact.js:

const { ethers } = require("hardhat");

async function main() {
  const tokenAddress = "YOUR_CONTRACT_ADDRESS";
  const token = await ethers.getContractAt("SimpleToken", tokenAddress);
  
  // Get contract info
  // Obter informações do contrato
  const info = await token.getContractInfo();
  console.log("Token Name:", info.name_);
  console.log("Symbol:", info.symbol_);
  console.log("Total Supply:", ethers.formatEther(info.totalSupply_));
  
  // Calculate fee for 1000 tokens
  // Calcular taxa para 1000 tokens
  const [fee, transfer] = await token.calculateFee(ethers.parseEther("1000"));
  console.log("Fee:", ethers.formatEther(fee));
  console.log("Amount after fee:", ethers.formatEther(transfer));
}

main().catch(console.error);

Run it:

npx hardhat run scripts/interact.js --network localhost

Security Considerations

Implemented Security Features

  1. Access Control

    • Only owner can modify critical parameters
    • Ownable pattern from OpenZeppelin
  2. Input Validation

    • Custom errors for invalid inputs
    • Zero address checks
    • Fee percentage limits
  3. Pausable Pattern

    • Emergency stop mechanism
    • Owner can pause/unpause
  4. Checks-Effects-Interactions

    • State changes before external calls
    • Prevents reentrancy
  5. Custom Errors

    • Gas-efficient error handling
    • Clear error messages

Potential Risks

  1. Centralization

    • Owner has significant control
    • Single point of failure
    • Mitigation: Use multi-sig wallet for production
  2. Fee Mechanism

    • Fee affects user experience
    • Could impact token liquidity
    • Mitigation: Keep fees reasonable, clear documentation
  3. Burn Mechanism

    • Deflationary (reduces supply)
    • Cannot be reversed
    • Mitigation: This is by design

Best Practices Applied

  • ✅ Latest Solidity version (0.8.33)
  • ✅ OpenZeppelin battle-tested contracts
  • ✅ Comprehensive test coverage
  • ✅ Custom errors (gas optimization)
  • ✅ Events for all state changes
  • ✅ NatSpec documentation
  • ✅ Input validation
  • ✅ Access control

Recommended Audits

Before mainnet deployment:

  1. Internal code review
  2. External security audit
  3. Bug bounty program
  4. Test on testnet for extended period

Gas Optimization

Techniques Used

  1. Custom Errors

    // Instead of: require(condition, "Error message");
    // Use: if (!condition) revert CustomError();

    Saves ~50 gas per error

  2. Unchecked Math

    unchecked {
        _balances[from] -= amount;
        _balances[to] += amount;
    }

    Safe when overflow is impossible

  3. Storage Packing

    • uint256 variables grouped together
    • Bool variables grouped together
  4. View Functions

    • No gas cost when called externally
    • Used for calculations and queries

Gas Comparison

Operation Gas Cost (approx)
Transfer (no fee) ~52,000
Transfer (with fee) ~65,000
Add to whitelist ~45,000
Change fee ~30,000

Learning Outcomes

By completing this project, you learned:

Solidity Concepts

  • ✅ ERC20 token standard
  • ✅ Inheritance and interfaces
  • ✅ State variables and storage
  • ✅ Functions and modifiers
  • ✅ Events and logging
  • ✅ Custom errors
  • ✅ Access control patterns
  • ✅ Pausable pattern

Development Skills

  • ✅ Hardhat framework setup
  • ✅ Smart contract compilation
  • ✅ Unit testing with Chai
  • ✅ Deployment scripts
  • ✅ Contract verification
  • ✅ Git version control

Best Practices

  • ✅ Code organization
  • ✅ Documentation (NatSpec)
  • ✅ Security considerations
  • ✅ Gas optimization
  • ✅ Testing strategies
  • ✅ Error handling

Tools Mastery

  • ✅ Node.js and npm
  • ✅ Hardhat
  • ✅ OpenZeppelin
  • ✅ Ethers.js
  • ✅ Chai testing library

Common Issues

Issue 1: "Module not found"

npm install

Issue 2: "Insufficient funds"

Make sure you have enough ETH for gas on the network you're deploying to.

Issue 3: "Nonce too high"

Reset your MetaMask account or use:

npx hardhat clean

Issue 4: Compilation errors

Check Solidity version compatibility:

// hardhat.config.js
solidity: {
  version: "0.8.33"
}

Issue 5: Test failures

Clear cache and recompile:

npx hardhat clean
npx hardhat compile
npx hardhat test

References

Documentation

ERC20 Standard

Learning Resources

Tools


Next Steps

After mastering this project:

  1. Enhance the Token

    • Add snapshot functionality
    • Implement voting power
    • Add reward distribution
  2. Build a Frontend

    • React + Ethers.js
    • Token swap interface
    • Dashboard with analytics
  3. Next Project

    • Move to Project 1.2: Voting System
    • Or explore Project 1.3: NFT Collection
  4. Go Deeper

    • Study DeFi protocols
    • Learn about security audits
    • Practice on Ethernaut challenges

License

MIT License - See LICENSE file for details


Contact & Support

  • Author: Solidity Learning Projects
  • GitHub: [My GitHub]

Built with ❤️ for the Solidity community

Last Updated: February 2026