SECTION 1: LEARNING OBJECTIVES

By the end of this lesson, you will be able to:

  • Define smart contracts and their role in digital finance.

  • Explain how smart contracts execute on the Ethereum Virtual Machine (EVM).

  • Differentiate between smart contracts and traditional legal contracts.

  • Describe the architecture of Decentralised Applications (DApps).

  • Identify major use cases in DeFi, NFTs, and tokenisation.

  • Understand security risks and common vulnerabilities.

  • Implement a token smart contract simulation in Python.

  • Design a simple DApp architecture for a financial use case.


SECTION 2: WHAT ARE SMART CONTRACTS?

2.1 Definition

smart contract is a self-executing program stored on a blockchain that automatically enforces, executes, and verifies the terms of an agreement when predetermined conditions are met. The concept was first proposed by Nick Szabo in the 1990s and realised with Ethereum in 2015.

2.2 Smart Contract Characteristics

text
┌─────────────────────────────────────────────────────────────────────────────┐
│                    SMART CONTRACT CHARACTERISTICS                          │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  ┌──────────────────────────────────────────────────────────────────────┐   │
│  │                    AUTONOMOUS                                        │   │
│  │  Executes automatically without human intervention.                  │   │
│  └──────────────────────────────────────────────────────────────────────┘   │
│                                                                             │
│  ┌──────────────────────────────────────────────────────────────────────┐   │
│  │                    TRUSTLESS                                          │   │
│  │  Relies on code and consensus, not on third parties.                 │   │
│  └──────────────────────────────────────────────────────────────────────┘   │
│                                                                             │
│  ┌──────────────────────────────────────────────────────────────────────┐   │
│  │                    TRANSPARENT                                       │   │
│  │  Code is open and verifiable on-chain.                              │   │
│  └──────────────────────────────────────────────────────────────────────┘   │
│                                                                             │
│  ┌──────────────────────────────────────────────────────────────────────┐   │
│  │                    IMMUTABLE                                         │   │
│  │  Once deployed, code cannot be changed (unless upgradable pattern). │   │
│  └──────────────────────────────────────────────────────────────────────┘   │
│                                                                             │
│  ┌──────────────────────────────────────────────────────────────────────┐   │
│  │                    PROGRAMMABLE                                      │   │
│  │  Can implement complex logic, state transitions, and interactions.  │   │
│  └──────────────────────────────────────────────────────────────────────┘   │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

2.3 Smart Contract vs Legal Contract

 
 
Aspect Smart Contract Legal Contract
Enforcement Code/consensus Court/law
Language Solidity, Rust, etc. Natural language
Interpretation Deterministic Subjective
Modification Hard (requires upgrade) Negotiable
Cost Gas fees Legal fees
Speed Instant Slow

SECTION 3: HOW SMART CONTRACTS WORK

3.1 Execution Architecture

text
┌─────────────────────────────────────────────────────────────────────────────┐
│                    SMART CONTRACT EXECUTION                                 │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  User Transaction                                                          │
│       │                                                                     │
│       v                                                                     │
│  ┌──────────────────────────────────────────────────────────────────────┐   │
│  │                    NODE RECEIVES TRANSACTION                         │   │
│  └──────────────────────────────────────────────────────────────────────┘   │
│       │                                                                     │
│       v                                                                     │
│  ┌──────────────────────────────────────────────────────────────────────┐   │
│  │                    EXECUTION IN EVM                                  │   │
│  │  • Validate signature                                                │   │
│  │  • Deduct gas                                                       │   │
│  │  • Load contract bytecode                                           │   │
│  │  • Execute opcodes                                                   │   │
│  │  • Update state                                                     │   │
│  └──────────────────────────────────────────────────────────────────────┘   │
│       │                                                                     │
│       v                                                                     │
│  ┌──────────────────────────────────────────────────────────────────────┐   │
│  │                    STATE CHANGE PROPAGATED                           │   │
│  │  • Mempool update                                                    │   │
│  │  • Block inclusion                                                   │   │
│  │  • Final state recorded                                              │   │
│  └──────────────────────────────────────────────────────────────────────┘   │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

3.2 The Ethereum Virtual Machine (EVM)

The EVM is a Turing-complete virtual machine that executes smart contract bytecode. Key components:

  • Stack: 256-bit words for operations.

  • Memory: volatile byte-addressable memory.

  • Storage: persistent key-value store (state).

  • Gas: unit of computational cost, prevents infinite loops.


SECTION 4: DECENTRALISED APPLICATIONS (DApps)

4.1 DApp Architecture

A DApp typically consists of:

  1. Frontend: Web/mobile UI (HTML/JS/React).

  2. Smart Contracts: Backend logic on the blockchain.

  3. Node/Provider: Interface to the blockchain (e.g., Web3.js, ethers.js).

  4. Wallet: User’s private key management (MetaMask).

text
┌─────────────────────────────────────────────────────────────────────────────┐
│                    DAPP ARCHITECTURE                                        │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  ┌─────────────────┐                                                       │
│  │  USER (Browser) │                                                       │
│  └────────┬────────┘                                                       │
│           │                                                                │
│           v                                                                │
│  ┌─────────────────┐     ┌──────────────────────────────────────────────┐  │
│  │  FRONTEND (UI)  │────▶│  WALLET (e.g., MetaMask)                     │  │
│  └────────┬────────┘     └──────────────────────────────────────────────┘  │
│           │                                                                │
│           v                                                                │
│  ┌──────────────────────────────────────────────────────────────────────┐   │
│  │                    WEB3 / ETHERS PROVIDER                            │   │
│  │  (Infura, Alchemy, or local node)                                   │   │
│  └──────────────────────────────────────────────────────────────────────┘   │
│           │                                                                │
│           v                                                                │
│  ┌──────────────────────────────────────────────────────────────────────┐   │
│  │                    BLOCKCHAIN NETWORK                                │   │
│  │  ┌────────────┐  ┌────────────┐  ┌────────────┐                    │   │
│  │  │ Smart      │  │ Smart      │  │ Smart      │                    │   │
│  │  │ Contract A │  │ Contract B │  │ Contract C │                    │   │
│  │  └────────────┘  └────────────┘  └────────────┘                    │   │
│  └──────────────────────────────────────────────────────────────────────┘   │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

4.2 Major DApp Categories in Digital Finance

 
 
Category Description Examples
DeFi (Lending) Borrow/lend crypto without intermediaries Aave, Compound
DEX (Trading) Peer-to-peer token swaps Uniswap, SushiSwap
Stablecoins Price-stable digital currencies USDC, DAI
Derivatives Synthetic assets, options, futures Synthetix, dYdX
Asset Management Yield farming, vaults Yearn Finance
NFT Marketplaces Digital collectibles and art OpenSea, Rarible

SECTION 5: TOKEN STANDARDS

5.1 ERC-20 (Fungible Tokens)

Standard interface for fungible tokens (like currencies):

solidity
interface ERC20 {
    function totalSupply() external view returns (uint256);
    function balanceOf(address owner) external view returns (uint256);
    function transfer(address to, uint256 amount) external returns (bool);
    function approve(address spender, uint256 amount) external returns (bool);
    function transferFrom(address from, address to, uint256 amount) external returns (bool);
}

5.2 ERC-721 (Non-Fungible Tokens)

Standard for unique, non-fungible tokens (NFTs):

solidity
interface ERC721 {
    function ownerOf(uint256 tokenId) external view returns (address);
    function transferFrom(address from, address to, uint256 tokenId) external;
    function approve(address to, uint256 tokenId) external;
}

SECTION 6: SECURITY CONSIDERATIONS

6.1 Common Vulnerabilities

 
 
Vulnerability Description Mitigation
Reentrancy Calling external contracts before state updates Checks-Effects-Interactions pattern
Integer Overflow Arithmetic wraparound Use SafeMath or Solidity 0.8+
Front-running Exploiting transaction order Commit-reveal schemes
Access Control Missing authorization Use modifiers, Ownable pattern
Gas Limits Loops causing out-of-gas errors Limit loop iterations
Delegatecall Contract proxy vulnerabilities Careful implementation

6.2 Security Best Practices

  • Use battle-tested libraries (OpenZeppelin).

  • Conduct thorough testing and audits.

  • Implement upgradeable proxy patterns.

  • Use time-locks for administrative functions.

  • Monitor contracts after deployment.


SECTION 7: IMPLEMENTATION IN PYTHON

python
# ===================================================================
# MODULE 1, LESSON 4: SMART CONTRACTS AND DApps
# ===================================================================

import hashlib
import json
import time
from typing import Dict, List, Tuple, Optional
from dataclasses import dataclass
import pandas as pd
import matplotlib.pyplot as plt
import warnings
warnings.filterwarnings('ignore')

print("="*70)
print("SMART CONTRACTS AND DECENTRALISED APPLICATIONS")
print("="*70)

# ----------------------------------------------------------------
# PART A: SIMPLE SMART CONTRACT SIMULATION (ERC-20 Token)
# ----------------------------------------------------------------

print("\n" + "-"*60)
print("PART A: Simple ERC-20 Token Smart Contract Simulation")
print("-"*60)

class ERC20Token:
    """
    A Python simulation of an ERC-20 token smart contract.
    """
    def __init__(self, name: str, symbol: str, total_supply: int):
        self.name = name
        self.symbol = symbol
        self.total_supply = total_supply
        self.balances: Dict[str, int] = {}
        self.allowances: Dict[Tuple[str, str], int] = {}
        self.owner = "contract_deployer"
        self.balances[self.owner] = total_supply
        self.events: List[Dict] = []
    
    def balance_of(self, address: str) -> int:
        return self.balances.get(address, 0)
    
    def transfer(self, sender: str, recipient: str, amount: int) -> bool:
        if self.balances.get(sender, 0) < amount:
            print(f"Error: Insufficient balance for {sender}")
            return False
        if amount <= 0:
            return False
        
        self.balances[sender] = self.balances.get(sender, 0) - amount
        self.balances[recipient] = self.balances.get(recipient, 0) + amount
        
        self.events.append({
            'type': 'Transfer',
            'from': sender,
            'to': recipient,
            'amount': amount,
            'timestamp': time.time()
        })
        print(f"Transfer {amount} {self.symbol} from {sender[:8]}... to {recipient[:8]}...")
        return True
    
    def approve(self, owner: str, spender: str, amount: int) -> bool:
        self.allowances[(owner, spender)] = amount
        print(f"Approved {spender[:8]}... to spend {amount} on behalf of {owner[:8]}...")
        return True
    
    def transfer_from(self, spender: str, from_addr: str, to_addr: str, amount: int) -> bool:
        if self.balances.get(from_addr, 0) < amount:
            return False
        if self.allowances.get((from_addr, spender), 0) < amount:
            return False
        
        self.balances[from_addr] = self.balances.get(from_addr, 0) - amount
        self.balances[to_addr] = self.balances.get(to_addr, 0) + amount
        self.allowances[(from_addr, spender)] = self.allowances.get((from_addr, spender), 0) - amount
        
        self.events.append({
            'type': 'TransferFrom',
            'from': from_addr,
            'to': to_addr,
            'spender': spender,
            'amount': amount,
            'timestamp': time.time()
        })
        return True
    
    def get_total_supply(self) -> int:
        return self.total_supply
    
    def get_events(self) -> List[Dict]:
        return self.events

# Create a token
token = ERC20Token("Digital Dollar", "USDD", 1000000)

# Create addresses
alice = "0x" + hashlib.sha256(b"alice").hexdigest()[:40]
bob = "0x" + hashlib.sha256(b"bob").hexdigest()[:40]
charlie = "0x" + hashlib.sha256(b"charlie").hexdigest()[:40]

print(f"Token: {token.name} ({token.symbol})")
print(f"Total Supply: {token.total_supply}")
print(f"Owner balance: {token.balance_of(token.owner)}")

# Transfer
print("\n--- Transfers ---")
token.transfer(token.owner, alice, 100000)
token.transfer(alice, bob, 40000)
token.transfer(bob, charlie, 20000)

# Approve and transferFrom
print("\n--- Approvals ---")
token.approve(bob, alice, 10000)
token.transfer_from(alice, bob, charlie, 5000)

# Show balances
print("\n--- Final Balances ---")
for name, addr in [("Owner", token.owner), ("Alice", alice), ("Bob", bob), ("Charlie", charlie)]:
    bal = token.balance_of(addr)
    print(f"{name}: {bal} {token.symbol}")

# Show events
print(f"\nTotal events: {len(token.get_events())}")

# ----------------------------------------------------------------
# PART B: SMART CONTRACT STATE MACHINE EXAMPLE
# ----------------------------------------------------------------

print("\n" + "-"*60)
print("PART B: Smart Contract State Machine")
print("-"*60)

class EscrowContract:
    """
    Simulates an escrow smart contract with state transitions.
    """
    class State:
        PENDING = "PENDING"
        DEPOSITED = "DEPOSITED"
        RELEASED = "RELEASED"
        CANCELLED = "CANCELLED"
    
    def __init__(self, buyer: str, seller: str, arbiter: str, amount: int):
        self.buyer = buyer
        self.seller = seller
        self.arbiter = arbiter
        self.amount = amount
        self.state = self.State.PENDING
        self.history: List[Tuple[str, str]] = []
        self.log_transition("Contract created", self.state)
    
    def log_transition(self, action: str, new_state: str):
        self.history.append((action, new_state))
    
    def deposit(self, from_addr: str):
        if from_addr != self.buyer:
            raise Exception("Only buyer can deposit")
        if self.state != self.State.PENDING:
            raise Exception("Invalid state for deposit")
        self.state = self.State.DEPOSITED
        self.log_transition("Deposit made", self.state)
        print(f"Deposit of {self.amount} received from buyer")
    
    def release(self, from_addr: str):
        if from_addr != self.arbiter:
            raise Exception("Only arbiter can release")
        if self.state != self.State.DEPOSITED:
            raise Exception("No deposit to release")
        self.state = self.State.RELEASED
        self.log_transition("Funds released to seller", self.state)
        print(f"Funds of {self.amount} released to seller")
    
    def cancel(self, from_addr: str):
        if from_addr != self.arbiter and from_addr != self.buyer:
            raise Exception("Only arbiter or buyer can cancel")
        if self.state not in [self.State.PENDING, self.State.DEPOSITED]:
            raise Exception("Cannot cancel in current state")
        self.state = self.State.CANCELLED
        self.log_transition("Contract cancelled", self.state)
        print(f"Contract cancelled, funds returned to buyer")
    
    def get_state(self) -> str:
        return self.state

# Simulate
buyer = "0xAlice"
seller = "0xBob"
arbiter = "0xCharlie"
escrow = EscrowContract(buyer, seller, arbiter, 1000)

print(f"Escrow state: {escrow.get_state()}")
escrow.deposit(buyer)
print(f"Escrow state: {escrow.get_state()}")
escrow.release(arbiter)
print(f"Escrow state: {escrow.get_state()}")

print("\n--- State Transition History ---")
for action, state in escrow.history:
    print(f"{action}: {state}")

# ----------------------------------------------------------------
# PART C: DAPP ARCHITECTURE DIAGRAM AND COMPONENTS
# ----------------------------------------------------------------

print("\n" + "-"*60)
print("PART C: DApp Architecture Components")
print("-"*60)

dapp_components = {
    "Frontend": {
        "Description": "User interface for interacting with the DApp.",
        "Technologies": ["React", "Vue.js", "HTML/CSS", "JavaScript"],
        "Role": "Display data, capture user input, connect to wallet."
    },
    "Wallet": {
        "Description": "Manages user private keys and signs transactions.",
        "Technologies": ["MetaMask", "WalletConnect", "Coinbase Wallet"],
        "Role": "Sign transactions, manage keys, connect to blockchain."
    },
    "Provider": {
        "Description": "Interface between DApp and blockchain network.",
        "Technologies": ["Web3.js", "Ethers.js", "Infura", "Alchemy"],
        "Role": "Send RPC calls, listen for events, encode/decode data."
    },
    "Smart Contracts": {
        "Description": "Application logic deployed on-chain.",
        "Technologies": ["Solidity", "Vyper", "Rust (Solana)"],
        "Role": "Enforce business logic, manage state, emit events."
    },
    "Blockchain": {
        "Description": "Decentralised execution and storage layer.",
        "Technologies": ["Ethereum", "Polygon", "Solana", "Avalanche"],
        "Role": "Execute transactions, reach consensus, store state."
    }
}

for component, details in dapp_components.items():
    print(f"\n{component.upper()}:")
    print(f"  Description: {details['Description']}")
    print(f"  Technologies: {', '.join(details['Technologies'])}")
    print(f"  Role: {details['Role']}")

# ----------------------------------------------------------------
# PART D: DAPP USE CASES IN DIGITAL FINANCE
# ----------------------------------------------------------------

print("\n" + "-"*60)
print("PART D: DApp Use Cases in Digital Finance")
print("-"*60)

use_cases = {
    "Decentralised Exchange (DEX)": {
        "Description": "Peer-to-peer token trading without order books.",
        "Key Contracts": ["Factory", "Router", "Pair"],
        "Example": "Uniswap V3"
    },
    "Lending Protocol": {
        "Description": "Deposit and borrow assets with variable rates.",
        "Key Contracts": ["Pool", "Reserve", "Oracle"],
        "Example": "Aave V3"
    },
    "Yield Aggregator": {
        "Description": "Automatically optimise yield strategies.",
        "Key Contracts": ["Vault", "Strategy", "Rewards"],
        "Example": "Yearn Finance"
    },
    "Stablecoin": {
        "Description": "Collateralised or algorithmic pegged tokens.",
        "Key Contracts": ["Minter", "StabilityPool", "Trove"],
        "Example": "MakerDAO (DAI)"
    },
    "Prediction Market": {
        "Description": "Trade outcomes of future events.",
        "Key Contracts": ["Market", "CategoricalMarket", "ScalarMarket"],
        "Example": "Augur, Polymarket"
    }
}

for name, details in use_cases.items():
    print(f"\n{name}:")
    print(f"  {details['Description']}")
    print(f"  Key Contracts: {', '.join(details['Key Contracts'])}")
    print(f"  Example: {details['Example']}")

# ----------------------------------------------------------------
# PART E: SMART CONTRACT SECURITY CHECKLIST
# ----------------------------------------------------------------

print("\n" + "-"*60)
print("PART E: Smart Contract Security Checklist")
print("-"*60)

security_checklist = {
    "Development Phase": [
        "Use latest Solidity version",
        "Use OpenZeppelin libraries",
        "Implement checks-effects-interactions pattern",
        "Use SafeMath or Solidity 0.8+ for arithmetic",
        "Avoid delegatecall unless necessary",
        "Use appropriate access control (Ownable, Roles)"
    ],
    "Testing Phase": [
        "Write comprehensive unit tests",
        "Test edge cases and boundary conditions",
        "Perform fuzz testing",
        "Test for reentrancy vulnerabilities",
        "Test gas optimization",
        "Test with multiple accounts"
    ],
    "Audit Phase": [
        "Engage professional security firms",
        "Conduct internal code review",
        "Run static analysis tools (Slither, Mythril)",
        "Check for known vulnerabilities (SWC Registry)",
        "Verify contract invariants",
        "Test upgradeability patterns"
    ],
    "Post-Deployment": [
        "Monitor on-chain activity",
        "Set up alerts for suspicious transactions",
        "Consider bug bounty programs",
        "Prepare emergency shutdown procedures",
        "Keep dependencies updated"
    ]
}

for phase, items in security_checklist.items():
    print(f"\n{phase.upper()}:")
    for item in items:
        print(f"  ✓ {item}")

# ----------------------------------------------------------------
# PART F: VISUALISE DAPP INTERACTIONS
# ----------------------------------------------------------------

print("\n" + "-"*60)
print("PART F: DApp Interaction Visualisation")
print("-"*60)

# Simulate user interactions over time
interactions = ['User Connect', 'Approve Token', 'Swap', 'Add Liquidity', 'Withdraw']
timestamps = np.cumsum(np.random.exponential(5, len(interactions)))
step = np.random.choice([1, 2, 3], size=len(interactions))

fig, ax = plt.subplots(figsize=(12, 4))
ax.scatter(timestamps, step, s=200, c='blue', alpha=0.6)
for i, label in enumerate(interactions):
    ax.annotate(label, (timestamps[i], step[i]), xytext=(5, 10),
                textcoords='offset points', fontsize=8)

ax.set_xlabel('Time (arbitrary units)')
ax.set_ylabel('Interaction Type')
ax.set_yticks([1, 2, 3])
ax.set_title('DApp User Interaction Flow')
ax.grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig('dapp_interactions.png', dpi=300, bbox_inches='tight')
plt.show()
print("DApp interactions chart saved as 'dapp_interactions.png'")

# ----------------------------------------------------------------
# PART G: SUMMARY AND RECOMMENDATIONS
# ----------------------------------------------------------------

print("\n" + "="*70)
print("PART G: Summary and Recommendations")
print("="*70)

print("""
Smart Contracts and DApps – Key Takeaways:

1. Smart contracts are self-executing programs on blockchain.
2. They are autonomous, trustless, transparent, and immutable.
3. EVM executes bytecode with gas as computational cost.
4. DApps consist of frontend + wallet + provider + smart contracts + blockchain.
5. Major token standards: ERC-20 (fungible) and ERC-721 (NFT).
6. DeFi applications include DEXs, lending, stablecoins, and yield aggregators.
7. Security is critical: reentrancy, access control, and integer overflow are common risks.

Recommendations:
  - Start with simple contracts and incrementally add complexity.
  - Always use audited libraries (OpenZeppelin).
  - Test extensively with local environments (Hardhat, Ganache).
  - Conduct external audits before mainnet deployment.
  - Monitor contracts post-deployment.
  - Stay updated on vulnerabilities and best practices.
""")