Skip to content
IRC-Coding IRC-Coding
Web3 blockchain development Smart Contracts DApps DeFi Ethereum Solidity

Web3 Blockchain Development Basics: Smart Contracts & DApps

Master Web3 blockchain development fundamentals: Smart Contracts, DApps, DeFi. Learn Ethereum, Solidity, Web3.js with practical examples.

S

schutzgeist

2 min read
Web3 Blockchain Development Basics: Smart Contracts & DApps

Web3 Blockchain Development Fundamentals: Smart Contracts, DApps & DeFi

This article is a comprehensive introduction to Web3 Blockchain Development Fundamentals – including Smart Contracts, DApps and DeFi with practical examples.

In a Nutshell

Web3 is the next generation of the internet based on blockchain technology and enables decentralized applications (DApps) that operate without central authorities.

Concise Technical Description

Web3 is a decentralized internet protocol built on blockchain technology that gives users control over their data and digital identities.

Core Components:

Blockchain Fundamentals

  • Distributed Ledger: Decentralized data storage
  • Consensus Mechanisms: Proof of Work, Proof of Stake
  • Cryptography: Hash functions, Digital signatures
  • Smart Contracts: Self-executing contracts
  • Gas Fees: Transaction costs

Ethereum Ecosystem

  • EVM: Ethereum Virtual Machine
  • Solidity: Smart Contract programming language
  • Web3.js: JavaScript library for Web3
  • Hardhat: Development environment
  • OpenZeppelin: Secure smart contract libraries

Decentralized Finance (DeFi)

  • DEX: Decentralized Exchanges
  • Lending: Decentralized lending platforms
  • Yield Farming: Liquidity provision
  • Staking: Token validation
  • Governance: Decentralized decision-making

Exam-Relevant Key Points

  • Web3: Decentralized internet based on blockchain
  • Blockchain: Decentralized database with cryptographic security
  • Smart Contracts: Self-executing contracts on the blockchain
  • DApps: Decentralized applications without central authority
  • DeFi: Decentralized financial services
  • Ethereum: Leading Smart Contract platform
  • Solidity: Programming language for Smart Contracts
  • Gas: Transaction costs on the blockchain
  • IHK-relevant: Modern blockchain development and architecture

Core Components

  1. Blockchain Technology: Distributed Ledger, consensus mechanisms
  2. Smart Contracts: Self-executing contracts with business logic
  3. DApps: Decentralized frontend applications
  4. DeFi Protocols: Financial services on the blockchain
  5. Wallet Integration: MetaMask, WalletConnect
  6. Web3 Libraries: Web3.js, Ethers.js
  7. Development Tools: Hardhat, Truffle, Remix
  8. Security: Audits, Best Practices, Vulnerability Scanning

Practical Examples

1. Smart Contract with Solidity

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/math/SafeMath.sol";

/**
 * @title DeFiToken
 * @dev ERC20 Token with extended functions for DeFi applications
 * @author Web3 Developer
 */
contract DeFiToken is ERC20, ERC20Burnable, ReentrancyGuard, Ownable {
    using SafeMath for uint256;
    
    // Events
    event TokensMinted(address indexed to, uint256 amount);
    event TokensBurned(address indexed from, uint256 amount);
    event LiquidityAdded(address indexed provider, uint256 tokenAmount, uint256 ethAmount);
    event LiquidityRemoved(address indexed provider, uint256 tokenAmount, uint256 ethAmount);
    event RewardClaimed(address indexed claimant, uint256 rewardAmount);
    
    // State variables
    uint256 public constant MAX_SUPPLY = 1000000000 * 10**18; // 1 Billion tokens
    uint256 public constant INITIAL_SUPPLY = 100000000 * 10**18; // 100 Million tokens
    uint256 public constant REWARD_RATE = 1 * 10**16; // 0.01 tokens per block
    
    uint256 public totalLiquidity;
    uint256 public totalRewardsDistributed;
    uint256 public lastRewardBlock;
    uint256 public rewardPerTokenStored;
    
    mapping(address => uint256) public userRewardPerTokenPaid;
    mapping(address => uint256) public rewards;
    mapping(address => uint256) public liquidityProvided;
    mapping(address => uint256) public depositTimestamp;
    
    // Arrays for staking pools
    struct Pool {
        uint256 totalStaked;
        uint256 rewardRate;
        uint256 lockPeriod;
        uint256 apr;
        bool active;
    }
    
    mapping(uint256 => Pool) public pools;
    mapping(address => mapping(uint256 => uint256)) public userStakes;
    mapping(address => mapping(uint256 => uint256)) public userStakeTimestamp;
    
    uint256 public poolCount;
    
    // Governance
    struct Proposal {
        uint256 id;
        address proposer;
        string description;
        uint256 voteCount;
        uint256 quorum;
        uint256 deadline;
        bool executed;
        mapping(address => bool) hasVoted;
    }
    
    mapping(uint256 => Proposal) public proposals;
    uint256 public proposalCount;
    mapping(address => uint256) public votingPower;
    
    // Modifiers
    modifier validAddress(address _addr) {
        require(_addr != address(0), "Invalid address");
        _;
    }
    
    modifier sufficientBalance(address _account, uint256 _amount) {
        require(balanceOf(_account) >= _amount, "Insufficient balance");
        _;
    }
    
    modifier sufficientLiquidity(uint256 _amount) {
        require(address(this).balance >= _amount, "Insufficient ETH liquidity");
        _;
    }
    
    modifier onlyWhenPaused() {
        require(!paused(), "Contract is paused");
        _;
    }
    
    // Constructor
    constructor(
        string memory _name,
        string memory _symbol,
        uint256 _initialMint
    ) ERC20(_name, _symbol) {
        require(_initialMint <= INITIAL_SUPPLY, "Initial mint exceeds limit");
        
        _mint(msg.sender, _initialMint);
        lastRewardBlock = block.number;
        
        // Create initial staking pool
        _createPool(100, 30 days, 10); // 100% APR, 30 days lock
    }
    
    /**
     * @dev Mint new tokens (owner only)
     */
    function mint(address _to, uint256 _amount) 
        external 
        onlyOwner 
        validAddress(_to)
        returns (bool) 
    {
        require(totalSupply() + _amount <= MAX_SUPPLY, "Exceeds max supply");
        
        _mint(_to, _amount);
        emit TokensMinted(_to, _amount);
        return true;
    }
    
    /**
     * @dev Add liquidity to the pool
     */
    function addLiquidity(uint256 _tokenAmount) 
        external 
        payable 
        nonReentrant 
        sufficientBalance(msg.sender, _tokenAmount)
        returns (uint256 liquidityTokens)
    {
        require(_tokenAmount > 0 && msg.value > 0, "Invalid amounts");
        
        // Calculate liquidity tokens
        uint256 ethReserve = address(this).balance - msg.value;
        uint256 tokenReserve = totalSupply() - _tokenAmount;
        
        if (ethReserve == 0 || tokenReserve == 0) {
            liquidityTokens = _tokenAmount;
        } else {
            liquidityTokens = min(
                (msg.value * tokenReserve) / ethReserve,
                _tokenAmount
            );
        }
        
        require(liquidityTokens > 0, "Insufficient liquidity minted");
        
        // Transfer tokens and ETH
        _transfer(msg.sender, address(this), _tokenAmount);
        
        // Update user liquidity
        liquidityProvided[msg.sender] += liquidityTokens;
        depositTimestamp[msg.sender] = block.timestamp;
        
        // Update total liquidity
        totalLiquidity += liquidityTokens;
        
        // Update rewards
        _updateReward(msg.sender);
        
        emit LiquidityAdded(msg.sender, _tokenAmount, msg.value);
        
        return liquidityTokens;
    }
    
    /**
     * @dev Remove liquidity from the pool
     */
    function removeLiquidity(uint256 _liquidityAmount) 
        external 
        nonReentrant 
        returns (uint256 ethAmount, uint256 tokenAmount)
    {
        require(_liquidityAmount > 0, "Invalid amount");
        require(liquidityProvided[msg.sender] >= _liquidityAmount, "Insufficient liquidity");
        
        // Calculate shares
        uint256 totalLiquidityTokens = totalLiquidity;
        uint256 ethReserve = address(this).balance;
        uint256 tokenReserve = balanceOf(address(this));
        
        ethAmount = (ethReserve * _liquidityAmount) / totalLiquidityTokens;
        tokenAmount = (tokenReserve * _liquidityAmount) / totalLiquidityTokens;
        
        require(ethAmount > 0 && tokenAmount > 0, "Insufficient withdraw amount");
        
        // Update user liquidity
        liquidityProvided[msg.sender] -= _liquidityAmount;
        totalLiquidity -= _liquidityAmount;
        
        // Update rewards
        _updateReward(msg.sender);
        _claimRewards(msg.sender);
        
        // Transfer ETH and tokens
        payable(msg.sender).transfer(ethAmount);
        _transfer(address(this), msg.sender, tokenAmount);
        
        emit LiquidityRemoved(msg.sender, tokenAmount, ethAmount);
        
        return (ethAmount, tokenAmount);
    }
    
    /**
     * @dev Create new staking pool
     */
    function createPool(uint256 _apr, uint256 _lockPeriod) external onlyOwner {
        _createPool(_apr, _lockPeriod, 0);
    }
    
    function _createPool(uint256 _apr, uint256 _lockPeriod, uint256 _rewardRate) internal {
        pools[poolCount] = Pool({
            totalStaked: 0,
            rewardRate: _rewardRate > 0 ? _rewardRate : REWARD_RATE,
            lockPeriod: _lockPeriod,
            apr: _apr,
            active: true
        });
        
        poolCount++;
    }
    
    /**
     * @dev Stake tokens in pool
     */
    function stake(uint256 _poolId, uint256 _amount) 
        external 
        nonReentrant 
        sufficientBalance(msg.sender, _amount)
        returns (bool)
    {
        require(_poolId < poolCount, "Invalid pool");
        require(pools[_poolId].active, "Pool not active");
        require(_amount > 0, "Invalid amount");
        
        // Update rewards before staking
        _updatePoolRewards(_poolId);
        _updateUserPoolRewards(_poolId, msg.sender);
        
        // Transfer tokens to contract
        _transfer(msg.sender, address(this), _amount);
        
        // Update staking
        userStakes[msg.sender][_poolId] += _amount;
        userStakeTimestamp[msg.sender][_poolId] = block.timestamp;
        pools[_poolId].totalStaked += _amount;
        
        // Update voting power
        votingPower[msg.sender] += _amount;
        
        return true;
    }
    
    /**
     * @dev Unstake tokens from pool
     */
    function unstake(uint256 _poolId, uint256 _amount) 
        external 
        nonReentrant 
        returns (bool)
    {
        require(_poolId < poolCount, "Invalid pool");
        require(userStakes[msg.sender][_poolId] >= _amount, "Insufficient stake");
        
        Pool storage pool = pools[_poolId];
        
        // Check lock period
        uint256 stakeTime = userStakeTimestamp[msg.sender][_poolId];
        require(
            block.timestamp >= stakeTime + pool.lockPeriod,
            "Tokens still locked"
        );
        
        // Update rewards before unstaking
        _updatePoolRewards(_poolId);
        _updateUserPoolRewards(_poolId, msg.sender);
        
        // Update staking
        userStakes[msg.sender][_poolId] -= _amount;
        pool.totalStaked -= _amount;
        
        // Update voting power
        votingPower[msg.sender] -= _amount;
        
        // Transfer tokens back
        _transfer(address(this), msg.sender, _amount);
        
        return true;
    }
    
    /**
     * @dev Claim rewards from pool
     */
    function claimRewards(uint256 _poolId) external nonReentrant returns (uint256) {
        require(_poolId < poolCount, "Invalid pool");
        require(userStakes[msg.sender][_poolId] > 0, "No stake in pool");
        
        // Update rewards
        _updatePoolRewards(_poolId);
        _updateUserPoolRewards(_poolId, msg.sender);
        
        uint256 reward = rewards[msg.sender];
        require(reward > 0, "No rewards to claim");
        
        // Reset rewards
        rewards[msg.sender] = 0;
        
        // Mint new tokens as reward
        _mint(msg.sender, reward);
        
        emit RewardClaimed(msg.sender, reward);
        
        return reward;
    }
    
    /**
     * @dev Create governance proposal
     */
    function createProposal(string memory _description, uint256 _quorum) 
        external 
        returns (uint256)
    {
        require(votingPower[msg.sender] >= 1000 * 10**18, "Insufficient voting power");
        require(bytes(_description).length > 0, "Empty description");
        
        Proposal storage proposal = proposals[proposalCount];
        proposal.id = proposalCount;
        proposal.proposer = msg.sender;
        proposal.description = _description;
        proposal.voteCount = 0;
        proposal.quorum = _quorum;
        proposal.deadline = block.timestamp + 7 days;
        proposal.executed = false;
        
        proposalCount++;
        
        return proposalCount - 1;
    }
    
    /**
     * @dev Vote for proposal
     */
    function vote(uint256 _proposalId) external {
        require(_proposalId < proposalCount, "Invalid proposal");
        require(block.timestamp <= proposals[_proposalId].deadline, "Voting ended");
        require(!proposals[_proposalId].hasVoted[msg.sender], "Already voted");
        require(votingPower[msg.sender] > 0, "No voting power");
        
        proposals[_proposalId].hasVoted[msg.sender] = true;
        proposals[_proposalId].voteCount += votingPower[msg.sender];
    }
    
    /**
     * @dev Execute proposal
     */
    function executeProposal(uint256 _proposalId) external onlyOwner {
        require(_proposalId < proposalCount, "Invalid proposal");
        require(block.timestamp > proposals[_proposalId].deadline, "Voting not ended");
        require(!proposals[_proposalId].executed, "Already executed");
        require(
            proposals[_proposalId].voteCount >= proposals[_proposalId].quorum,
            "Quorum not reached"
        );
        
        proposals[_proposalId].executed = true;
    }
    
    /**
     * @dev Update reward functions
     */
    function _updateReward(address _account) internal {
        if (_account == address(0)) return;
        
        rewardPerTokenStored = rewardPerToken();
        lastRewardBlock = block.number;
        
        rewards[_account] = earned(_account);
        userRewardPerTokenPaid[_account] = rewardPerTokenStored;
    }
    
    function _updatePoolRewards(uint256 _poolId) internal {
        // Implement pool-specific reward logic
        // This is a simplified version
    }
    
    function _updateUserPoolRewards(uint256 _poolId, address _account) internal {
        // Implement user-specific pool rewards
    }
    
    /**
     * @dev Helper functions
     */
    function rewardPerToken() public view returns (uint256) {
        if (totalLiquidity == 0) {
            return rewardPerTokenStored;
        }
        
        return rewardPerTokenStored.add(
            ((block.number.sub(lastRewardBlock)).mul(REWARD_RATE)).mul(1e18).div(totalLiquidity)
        );
    }
    
    function earned(address _account) public view returns (uint256) {
        return liquidityProvided[_account]
            .mul(rewardPerToken().sub(userRewardPerTokenPaid[_account]))
            .div(1e18)
            .add(rewards[_account]);
    }
    
    function getPoolInfo(uint256 _poolId) 
        external 
        view 
        returns (
            uint256 totalStaked,
            uint256 rewardRate,
            uint256 lockPeriod,
            uint256 apr,
            bool active
        ) 
    {
        require(_poolId < poolCount, "Invalid pool");
        Pool storage pool = pools[_poolId];
        return (pool.totalStaked, pool.rewardRate, pool.lockPeriod, pool.apr, pool.active);
    }
    
    function getUserStake(uint256 _poolId, address _user) 
        external 
        view 
        returns (uint256 amount, uint256 timestamp) 
    {
        require(_poolId < poolCount, "Invalid pool");
        return (userStakes[_user][_poolId], userStakeTimestamp[_user][_poolId]);
    }
    
    function getProposalInfo(uint256 _proposalId) 
        external 
        view 
        returns (
            address proposer,
            string memory description,
            uint256 voteCount,
            uint256 quorum,
            uint256 deadline,
            bool executed,
            bool hasVoted
        ) 
    {
        require(_proposalId < proposalCount, "Invalid proposal");
        Proposal storage proposal = proposals[_proposalId];
        return (
            proposal.proposer,
            proposal.description,
            proposal.voteCount,
            proposal.quorum,
            proposal.deadline,
            proposal.executed,
            proposal.hasVoted[msg.sender]
        );
    }
    
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }
    
    /**
     * @dev Emergency functions
     */
    function emergencyPause() external onlyOwner {
        _pause();
    }
    
    function emergencyUnpause() external onlyOwner {
        _unpause();
    }
    
    function emergencyWithdraw() external onlyOwner {
        payable(owner()).transfer(address(this).balance);
    }
    
    /**
     * @dev Fallback for ETH transfers
     */
    receive() external payable {
        // Accept ETH for liquidity
    }
    
    fallback() external payable {
        // Accept ETH for liquidity
    }
}

2. DApp Frontend with React and Web3.js

// src/components/Web3Provider.jsx
import React, { createContext, useContext, useEffect, useState } from 'react';
import Web3 from 'web3';
import { Contract } from 'web3-eth-contract';
import DeFiTokenABI from '../contracts/DeFiToken.json';

const Web3Context = createContext();

export const useWeb3 = () => {
  const context = useContext(Web3Context);
  if (!context) {
    throw new Error('useWeb3 must be used within a Web3Provider');
  }
  return context;
};

const Web3Provider = ({ children }) => {
  const [web3, setWeb3] = useState(null);
  const [account, setAccount] = useState(null);
  const [contract, setContract] = useState(null);
  const [networkId, setNetworkId] = useState(null);
  const [balance, setBalance] = useState('0');
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  const CONTRACT_ADDRESS = process.env.REACT_APP_CONTRACT_ADDRESS;
  const SUPPORTED_NETWORKS = {
    1: 'Ethereum Mainnet',
    3: 'Ropsten Testnet',
    4: 'Rinkeby Testnet',
    5: 'Goerli Testnet',
    42: 'Kovan Testnet',
    137: 'Polygon Mainnet',
    80001: 'Polygon Mumbai'
  };

  // Initialize Web3
  useEffect(() => {
    const initWeb3 = async () => {
      try {
        // Check if MetaMask is installed
        if (typeof window.ethereum !== 'undefined') {
          const web3Instance = new Web3(window.ethereum);
          setWeb3(web3Instance);

          // Request account access
          const accounts = await window.ethereum.request({
            method: 'eth_requestAccounts'
          });

          if (accounts.length > 0) {
            setAccount(accounts[0]);
            await setupContract(web3Instance);
            await getNetworkInfo(web3Instance);
            await updateBalance(web3Instance, accounts[0]);
          }

          // Setup event listeners
          setupEventListeners(web3Instance);
        } else {
          setError('MetaMask is not installed. Please install MetaMask to use this DApp.');
        }
      } catch (error) {
        console.error('Web3 initialization error:', error);
        setError('Failed to initialize Web3. Please check your wallet connection.');
      } finally {
        setLoading(false);
      }
    };

    initWeb3();
  }, []);

  const setupEventListeners = (web3Instance) => {
    // Account change
    window.ethereum.on('accountsChanged', (accounts) => {
      if (accounts.length === 0) {
        setAccount(null);
        setBalance('0');
      } else {
        setAccount(accounts[0]);
        updateBalance(web3Instance, accounts[0]);
      }
    });

    // Network change
    window.ethereum.on('chainChanged', () => {
      window.location.reload();
    });

    // Connect/Disconnect
    window.ethereum.on('connect', (connectInfo) => {
      console.log('Connected to blockchain:', connectInfo);
    });

    window.ethereum.on('disconnect', (error) => {
      console.error('Disconnected from blockchain:', error);
      setAccount(null);
      setBalance('0');
    });
  };

  const setupContract = async (web3Instance) => {
    try {
      const contractInstance = new web3Instance.eth.Contract(
        DeFiTokenABI.abi,
        CONTRACT_ADDRESS
      );
      setContract(contractInstance);
    } catch (error) {
      console.error('Contract setup error:', error);
      setError('Failed to setup smart contract.');
    }
  };

  const getNetworkInfo = async (web3Instance) => {
    try {
      const networkId = await web3Instance.eth.net.getId();
      setNetworkId(networkId);

      if (!SUPPORTED_NETWORKS[networkId]) {
        setError(`Unsupported network. Please switch to a supported network.`);
      }
    } catch (error) {
      console.error('Network info error:', error);
    }
  };

  const updateBalance = async (web3Instance, accountAddress) => {
    try {
      const balanceWei = await web3Instance.eth.getBalance(accountAddress);
      const balanceEth = web3Instance.utils.fromWei(balanceWei, 'ether');
      setBalance(balanceEth);
    } catch (error) {
      console.error('Balance update error:', error);
    }
  };

  const connectWallet = async () => {
    try {
      if (typeof window.ethereum !== 'undefined') {
        const accounts = await window.ethereum.request({
          method: 'eth_requestAccounts'
        });

        if (accounts.length > 0) {
          setAccount(accounts[0]);
          await updateBalance(web3, accounts[0]);
        }
      }
    } catch (error) {
      console.error('Wallet connection error:', error);
      setError('Failed to connect wallet.');
    }
  };

  const disconnectWallet = () => {
    setAccount(null);
    setBalance('0');
  };

  const switchNetwork = async (networkId) => {
    try {
      await window.ethereum.request({
        method: 'wallet_switchEthereumChain',
        params: [{ chainId: `0x${networkId.toString(16)}` }]
      });
    } catch (error) {
      console.error('Network switch error:', error);
      setError('Failed to switch network.');
    }
  };

  const value = {
    web3,
    account,
    contract,
    networkId,
    balance,
    loading,
    error,
    supportedNetworks: SUPPORTED_NETWORKS,
    connectWallet,
    disconnectWallet,
    switchNetwork,
    refreshBalance: () => updateBalance(web3, account)
  };

  return (
    <Web3Context.Provider value={value}>
      {children}
    </Web3Context.Provider>
  );
};

export default Web3Provider;

// src/components/TokenDashboard.jsx
import React, { useState, useEffect } from 'react';
import { useWeb3 } from './Web3Provider';
import { Card, CardHeader, CardContent, CardActions } from './UI/Card';
import Button from './UI/Button';
import Input from './UI/Input';
import Alert from './UI/Alert';
import LoadingSpinner from './UI/LoadingSpinner';

const TokenDashboard = () => {
  const { web3, account, contract, balance, refreshBalance } = useWeb3();
  const [tokenBalance, setTokenBalance] = useState('0');
  const [totalSupply, setTotalSupply] = useState('0');
  const [stakingData, setStakingData] = useState([]);
  const [liquidityData, setLiquidityData] = useState(null);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);
  const [success, setSuccess] = useState(null);

  // Form states
  const [stakeAmount, setStakeAmount] = useState('');
  const [liquidityTokenAmount, setLiquidityTokenAmount] = useState('');
  const [liquidityEthAmount, setLiquidityEthAmount] = useState('');

  // Load token data
  useEffect(() => {
    if (contract && account) {
      loadTokenData();
    }
  }, [contract, account]);

  const loadTokenData = async () => {
    try {
      setLoading(true);
      setError(null);

      const [
        tokenBalanceWei,
        totalSupplyWei,
        poolCount,
        userLiquidity,
        userRewards
      ] = await Promise.all([
        contract.methods.balanceOf(account).call(),
        contract.methods.totalSupply().call(),
        contract.methods.poolCount().call(),
        contract.methods.liquidityProvided(account).call(),
        contract.methods.earned(account).call()
      ]);

      setTokenBalance(web3.utils.fromWei(tokenBalanceWei, 'ether'));
      setTotalSupply(web3.utils.fromWei(totalSupplyWei, 'ether'));
      setLiquidityData({
        provided: web3.utils.fromWei(userLiquidity, 'ether'),
        rewards: web3.utils.fromWei(userRewards, 'ether')
      });

      // Load staking data
      const pools = [];
      for (let i = 0; i < poolCount; i++) {
        const [poolInfo, userStake] = await Promise.all([
          contract.methods.getPoolInfo(i).call(),
          contract.methods.getUserStake(i, account).call()
        ]);

        pools.push({
          id: i,
          ...poolInfo,
          userStake: {
            amount: web3.utils.fromWei(userStake.amount, 'ether'),
            timestamp: userStake.timestamp
          }
        });
      }
      setStakingData(pools);

    } catch (error) {
      console.error('Token data load error:', error);
      setError('Failed to load token data.');
    } finally {
      setLoading(false);
    }
  };

  const handleStake = async (poolId, amount) => {
    try {
      setLoading(true);
      setError(null);

      const amountWei = web3.utils.toWei(amount, 'ether');
      
      const tx = await contract.methods.stake(poolId, amountWei).send({
        from: account,
        gas: '300000'
      });

      setSuccess(`Successfully staked ${amount} tokens! Transaction: ${tx.transactionHash}`);
      setStakeAmount('');
      await loadTokenData();
      await refreshBalance();

    } catch (error) {
      console.error('Stake error:', error);
      setError('Failed to stake tokens.');
    } finally {
      setLoading(false);
    }
  };

  const handleUnstake = async (poolId, amount) => {
    try {
      setLoading(true);
      setError(null);

      const amountWei = web3.utils.toWei(amount, 'ether');
      
      const tx = await contract.methods.unstake(poolId, amountWei).send({
        from: account,
        gas: '300000'
      });

      setSuccess(`Successfully unstaked ${amount} tokens! Transaction: ${tx.transactionHash}`);
      await loadTokenData();
      await refreshBalance();

    } catch (error) {
      console.error('Unstake error:', error);
      setError('Failed to unstake tokens.');
    } finally {
      setLoading(false);
    }
  };

  const handleClaimRewards = async (poolId) => {
    try {
      setLoading(true);
      setError(null);

      const tx = await contract.methods.claimRewards(poolId).send({
        from: account,
        gas: '200000'
      });

      const rewards = await contract.methods.claimRewards(poolId).call({ from: account });
      setSuccess(`Successfully claimed ${web3.utils.fromWei(rewards, 'ether')} tokens!`);
      await loadTokenData();

    } catch (error) {
      console.error('Claim rewards error:', error);
      setError('Failed to claim rewards.');
    } finally {
      setLoading(false);
    }
  };

  const handleAddLiquidity = async () => {
    try {
      setLoading(true);
      setError(null);

      const tokenAmountWei = web3.utils.toWei(liquidityTokenAmount, 'ether');
      const ethAmountWei = web3.utils.toWei(liquidityEthAmount, 'ether');

      // Approve token transfer
      await contract.methods.approve(CONTRACT_ADDRESS, tokenAmountWei).send({
        from: account,
        gas: '100000'
      });

      // Add liquidity
      const tx = await contract.methods.addLiquidity(tokenAmountWei).send({
        from: account,
        value: ethAmountWei,
        gas: '300000'
      });

      setSuccess(`Successfully added liquidity! Transaction: ${tx.transactionHash}`);
      setLiquidityTokenAmount('');
      setLiquidityEthAmount('');
      await loadTokenData();
      await refreshBalance();

    } catch (error) {
      console.error('Add liquidity error:', error);
      setError('Failed to add liquidity.');
    } finally {
      setLoading(false);
    }
  };

  const handleRemoveLiquidity = async (amount) => {
    try {
      setLoading(true);
      setError(null);

      const amountWei = web3.utils.toWei(amount, 'ether');

      const tx = await contract.methods.removeLiquidity(amountWei).send({
        from: account,
        gas: '300000'
      });

      setSuccess(`Successfully removed liquidity! Transaction: ${tx.transactionHash}`);
      await loadTokenData();
      await refreshBalance();

    } catch (error) {
      console.error('Remove liquidity error:', error);
      setError('Failed to remove liquidity.');
    } finally {
      setLoading(false);
    }
  };

  if (loading && !tokenBalance) {
    return <LoadingSpinner />;
  }

  return (
    <div className="token-dashboard">
      <div className="dashboard-header">
        <h1>DeFi Token Dashboard</h1>
        <div className="account-info">
          <p><strong>Account:</strong> {account}</p>
          <p><strong>ETH Balance:</strong> {balance} ETH</p>
          <p><strong>Token Balance:</strong> {tokenBalance} DEFI</p>
        </div>
      </div>

      {error && <Alert type="error" message={error} />}
      {success && <Alert type="success" message={success} />}

      {/* Token Info */}
      <Card className="token-info-card">
        <CardHeader>
          <h2>Token Information</h2>
        </CardHeader>
        <CardContent>
          <div className="info-grid">
            <div className="info-item">
              <label>Total Supply</label>
              <span>{totalSupply} DEFI</span>
            </div>
            <div className="info-item">
              <label>Your Balance</label>
              <span>{tokenBalance} DEFI</span>
            </div>
            <div className="info-item">
              <label>Liquidity Provided</label>
              <span>{liquidityData?.provided || '0'} DEFI</span>
            </div>
            <div className="info-item">
              <label>Pending Rewards</label>
              <span>{liquidityData?.rewards || '0'} DEFI</span>
            </div>
          </div>
        </CardContent>
      </Card>

      {/* Staking Pools */}
      <Card className="staking-card">
        <CardHeader>
          <h2>Staking Pools</h2>
        </CardHeader>
        <CardContent>
          {stakingData.map((pool) => (
            <div key={pool.id} className="staking-pool">
              <div className="pool-header">
                <h3>Pool #{pool.id + 1}</h3>
                <span className={`pool-status ${pool.active ? 'active' : 'inactive'}`}>
                  {pool.active ? 'Active' : 'Inactive'}
                </span>
              </div>
              
              <div className="pool-info">
                <div className="pool-stat">
                  <label>APR</label>
                  <span>{pool.apr}%</span>
                </div>
                <div className="pool-stat">
                  <label>Lock Period</label>
                  <span>{pool.lockPeriod / 86400} days</span>
                </div>
                <div className="pool-stat">
                  <label>Total Staked</label>
                  <span>{web3.utils.fromWei(pool.totalStaked, 'ether')} DEFI</span>
                </div>
                <div className="pool-stat">
                  <label>Your Stake</label>
                  <span>{pool.userStake.amount} DEFI</span>
                </div>
              </div>

              <div className="pool-actions">
                {pool.active && (
                  <>
                    <div className="stake-form">
                      <Input
                        type="number"
                        placeholder="Amount to stake"
                        value={stakeAmount}
                        onChange={(e) => setStakeAmount(e.target.value)}
                        min="0"
                        step="0.01"
                      />
                      <Button
                        onClick={() => handleStake(pool.id, stakeAmount)}
                        disabled={!stakeAmount || parseFloat(stakeAmount) <= 0}
                      >
                        Stake
                      </Button>
                    </div>

                    {pool.userStake.amount > '0' && (
                      <>
                        <Button
                          variant="secondary"
                          onClick={() => handleUnstake(pool.id, pool.userStake.amount)}
                        >
                          Unstake All
                        </Button>
                        <Button
                          variant="outline"
                          onClick={() => handleClaimRewards(pool.id)}
                        >
                          Claim Rewards
                        </Button>
                      </>
                    )}
                  </>
                )}
              </div>
            </div>
          ))}
        </CardContent>
      </Card>

      {/* Liquidity Management */}
      <Card className="liquidity-card">
        <CardHeader>
          <h2>Liquidity Management</h2>
        </CardHeader>
        <CardContent>
          <div className="liquidity-form">
            <h3>Add Liquidity</h3>
            <div className="form-row">
              <Input
                type="number"
                placeholder="Token amount"
                value={liquidityTokenAmount}
                onChange={(e) => setLiquidityTokenAmount(e.target.value)}
                min="0"
                step="0.01"
              />
              <Input
                type="number"
                placeholder="ETH amount"
                value={liquidityEthAmount}
                onChange={(e) => setLiquidityEthAmount(e.target.value)}
                min="0"
                step="0.01"
              />
            </div>
            <Button
              onClick={handleAddLiquidity}
              disabled={!liquidityTokenAmount || !liquidityEthAmount || loading}
            >
              Add Liquidity
            </Button>
          </div>

          {liquidityData?.provided > '0' && (
            <div className="remove-liquidity">
              <h3>Remove Liquidity</h3>
              <div className="form-row">
                <Input
                  type="number"
                  placeholder="Amount to remove"
                  min="0"
                  max={liquidityData.provided}
                  step="0.01"
                />
                <Button
                  variant="danger"
                  onClick={() => handleRemoveLiquidity(liquidityData.provided)}
                >
                  Remove All
                </Button>
              </div>
            </div>
          )}
        </CardContent>
      </Card>
    </div>
  );
};

export default TokenDashboard;

// src/components/GovernancePanel.jsx
import React, { useState, useEffect } from 'react';
import { useWeb3 } from './Web3Provider';
import { Card, CardHeader, CardContent, CardActions } from './UI/Card';
import Button from './UI/Button';
import Input from './UI/Input';
import Alert from './UI/Alert';

const GovernancePanel = () => {
  const { web3, account, contract } = useWeb3();
  const [proposals, setProposals] = useState([]);
  const [votingPower, setVotingPower] = useState('0');
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);
  const [success, setSuccess] = useState(null);

  // Form states
  const [proposalDescription, setProposalDescription] = useState('');
  const [proposalQuorum, setProposalQuorum] = useState('');

  useEffect(() => {
    if (contract && account) {
      loadGovernanceData();
    }
  }, [contract, account]);

  const loadGovernanceData = async () => {
    try {
      setLoading(true);
      setError(null);

      const [proposalCount, userVotingPower] = await Promise.all([
        contract.methods.proposalCount().call(),
        contract.methods.votingPower(account).call()
      ]);

      setVotingPower(web3.utils.fromWei(userVotingPower, 'ether'));

      // Load proposals
      const proposalList = [];
      for (let i = 0; i < proposalCount; i++) {
        const proposalInfo = await contract.methods.getProposalInfo(i).call();
        proposalList.push({
          id: i,
          proposer: proposalInfo[0],
          description: proposalInfo[1],
          voteCount: web3.utils.fromWei(proposalInfo[2], 'ether'),
          quorum: web3.utils.fromWei(proposalInfo[3], 'ether'),
          deadline: new Date(proposalInfo[4] * 1000),
          executed: proposalInfo[5],
          hasVoted: proposalInfo[6]
        });
      }

      setProposals(proposalList.reverse()); // Newest first

    } catch (error) {
      console.error('Governance data load error:', error);
      setError('Failed to load governance data.');
    } finally {
      setLoading(false);
    }
  };

  const handleCreateProposal = async () => {
    try {
      setLoading(true);
      setError(null);

      const quorumWei = web3.utils.toWei(proposalQuorum, 'ether');

      const tx = await contract.methods.createProposal(
        proposalDescription,
        quorumWei
      ).send({
        from: account,
        gas: '200000'
      });

      setSuccess(`Proposal created successfully! Transaction: ${tx.transactionHash}`);
      setProposalDescription('');
      setProposalQuorum('');
      await loadGovernanceData();

    } catch (error) {
      console.error('Create proposal error:', error);
      setError('Failed to create proposal.');
    } finally {
      setLoading(false);
    }
  };

  const handleVote = async (proposalId) => {
    try {
      setLoading(true);
      setError(null);

      const tx = await contract.methods.vote(proposalId).send({
        from: account,
        gas: '100000'
      });

      setSuccess(`Vote cast successfully! Transaction: ${tx.transactionHash}`);
      await loadGovernanceData();

    } catch (error) {
      console.error('Vote error:', error);
      setError('Failed to cast vote.');
    } finally {
      setLoading(false);
    }
  };

  const handleExecuteProposal = async (proposalId) => {
    try {
      setLoading(true);
      setError(null);

      const tx = await contract.methods.executeProposal(proposalId).send({
        from: account,
        gas: '100000'
      });

      setSuccess(`Proposal executed successfully! Transaction: ${tx.transactionHash}`);
      await loadGovernanceData();

    } catch (error) {
      console.error('Execute proposal error:', error);
      setError('Failed to execute proposal.');
    } finally {
      setLoading(false);
    }
  };

  const canVote = (proposal) => {
    return !proposal.hasVoted && 
           votingPower > '0' && 
           new Date() < proposal.deadline && 
           !proposal.executed;
  };

  const canExecute = (proposal) => {
    return !proposal.executed && 
           new Date() > proposal.deadline && 
           proposal.voteCount >= proposal.quorum;
  };

  return (
    <div className="governance-panel">
      <div className="governance-header">
        <h1>Governance</h1>
        <div className="voting-info">
          <p><strong>Your Voting Power:</strong> {votingPower} DEFI</p>
        </div>
      </div>

      {error && <Alert type="error" message={error} />}
      {success && <Alert type="success" message={success} />}

      {/* Create Proposal */}
      <Card className="create-proposal-card">
        <CardHeader>
          <h2>Create Proposal</h2>
        </CardHeader>
        <CardContent>
          <div className="proposal-form">
            <div className="form-group">
              <label>Proposal Description</label>
              <textarea
                value={proposalDescription}
                onChange={(e) => setProposalDescription(e.target.value)}
                placeholder="Describe your proposal..."
                rows={4}
              />
            </div>
            <div className="form-group">
              <label>Quorum (tokens required)</label>
              <Input
                type="number"
                value={proposalQuorum}
                onChange={(e) => setProposalQuorum(e.target.value)}
                placeholder="1000000"
                min="0"
                step="0.01"
              />
            </div>
          </div>
        </CardContent>
        <CardActions>
          <Button
            onClick={handleCreateProposal}
            disabled={!proposalDescription || !proposalQuorum || votingPower < '1000'}
          >
            Create Proposal
          </Button>
        </CardActions>
      </Card>

      {/* Proposals List */}
      <Card className="proposals-card">
        <CardHeader>
          <h2>Proposals</h2>
        </CardHeader>
        <CardContent>
          {proposals.length === 0 ? (
            <p>No proposals yet.</p>
          ) : (
            <div className="proposals-list">
              {proposals.map((proposal) => (
                <div key={proposal.id} className="proposal-item">
                  <div className="proposal-header">
                    <h3>Proposal #{proposal.id + 1}</h3>
                    <div className="proposal-status">
                      {proposal.executed ? (
                        <span className="status-executed">Executed</span>
                      ) : new Date() > proposal.deadline ? (
                        <span className="status-expired">Expired</span>
                      ) : (
                        <span className="status-active">Active</span>
                      )}
                    </div>
                  </div>

                  <div className="proposal-content">
                    <p className="proposal-description">{proposal.description}</p>
                    
                    <div className="proposal-meta">
                      <div className="meta-item">
                        <label>Proposer:</label>
                        <span>{proposal.proposer}</span>
                      </div>
                      <div className="meta-item">
                        <label>Deadline:</label>
                        <span>{proposal.deadline.toLocaleDateString()}</span>
                      </div>
                      <div className="meta-item">
                        <label>Vote Count:</label>
                        <span>{proposal.voteCount} / {proposal.quorum}</span>
                      </div>
                    </div>

                    <div className="vote-progress">
                      <div className="progress-bar">
                        <div 
                          className="progress-fill"
                          style={{
                            width: `${Math.min((parseFloat(proposal.voteCount) / parseFloat(proposal.quorum)) * 100, 100)}%`
                          }}
                        />
                      </div>
                      <span className="progress-text">
                        {Math.round((parseFloat(proposal.voteCount) / parseFloat(proposal.quorum)) * 100)}%
                      </span>
                    </div>
                  </div>

                  <div className="proposal-actions">
                    {canVote(proposal) && (
                      <Button onClick={() => handleVote(proposal.id)}>
                        Vote
                      </Button>
                    )}
                    
                    {canExecute(proposal) && (
                      <Button variant="success" onClick={() => handleExecuteProposal(proposal.id)}>
                        Execute
                      </Button>
                    )}

                    {proposal.hasVoted && (
                      <span className="voted-indicator">✓ Voted</span>
                    )}
                  </div>
                </div>
              ))}
            </div>
          )}
        </CardContent>
      </Card>
    </div>
  );
};

export default GovernancePanel;

// src/App.jsx
import React from 'react';
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
import Web3Provider from './components/Web3Provider';
import TokenDashboard from './components/TokenDashboard';
import GovernancePanel from './components/GovernancePanel';
import Navbar from './components/Navbar';
import './App.css';

function App() {
  return (
    <Web3Provider>
      <Router>
        <div className="App">
          <Navbar />
          <main className="main-content">
            <Routes>
              <Route path="/" element={<TokenDashboard />} />
              <Route path="/governance" element={<GovernancePanel />} />
            </Routes>
          </main>
        </div>
      </Router>
    </Web3Provider>
  );
}

export default App;

3. DeFi Protocol with Python and Web3.py

# defi_protocol.py
import json
import time
from web3 import Web3
from web3.contract import Contract
from web3.middleware import geth_poa_middleware
from eth_account import Account
from eth_utils import to_checksum_address
from decimal import Decimal
import logging

# Configure logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

class DeFiProtocol:
    """
    DeFi Protocol implementation for automated trading and liquidity management
    """
    
    def __init__(self, provider_url, private_key=None):
        """
        Initialize DeFi Protocol
        
        Args:
            provider_url: Web3 provider URL
            private_key: Private key for transactions (optional)
        """
        self.w3 = Web3(Web3.HTTPProvider(provider_url))
        
        # Inject POA middleware for testnets
        if self.w3.eth.chain_id in [3, 4, 5, 42, 80001]:
            self.w3.middleware_onion.inject(geth_poa_middleware, layer=0)
        
        self.account = None
        if private_key:
            self.account = Account.from_key(private_key)
            self.w3.eth.default_account = self.account.address
        
        # Contract addresses and ABIs
        self.contracts = {}
        self.load_contracts()
        
        # Gas settings
        self.gas_price = self.w3.eth.gas_price
        self.gas_limit = 300000
        
    def load_contracts(self):
        """Load contract ABIs and addresses"""
        # Example contract ABIs (would normally load from files)
        erc20_abi = [
            {
                "constant": True,
                "inputs": [{"name": "_owner", "type": "address"}],
                "name": "balanceOf",
                "outputs": [{"name": "balance", "type": "uint256"}],
                "type": "function"
            },
            {
                "constant": False,
                "inputs": [
                    {"name": "_to", "type": "address"},
                    {"name": "_value", "type": "uint256"}
                ],
                "name": "transfer",
                "outputs": [{"name": "", "type": "bool"}],
                "type": "function"
            },
            {
                "constant": False,
                "inputs": [
                    {"name": "_spender", "type": "address"},
                    {"name": "_value", "type": "uint256"}
                ],
                "name": "approve",
                "outputs": [{"name": "", "type": "bool"}],
                "type": "function"
            }
        ]
        
        uniswap_router_abi = [
            {
                "constant": False,
                "inputs": [
                    {"name": "amountOutMin", "type": "uint256"},
                    {"name": "path", "type": "address[]"},
                    {"name": "to", "type": "address"},
                    {"name": "deadline", "type": "uint256"}
                ],
                "name": "swapExactETHForTokens",
                "outputs": [{"name": "amounts", "type": "uint256[]"}],
                "type": "function"
            },
            {
                "constant": False,
                "inputs": [
                    {"name": "amountIn", "type": "uint256"},
                    {"name": "amountOutMin", "type": "uint256"},
                    {"name": "path", "type": "address[]"},
                    {"name": "to", "type": "address"},
                    {"name": "deadline", "type": "uint256"}
                ],
                "name": "swapExactTokensForTokens",
                "outputs": [{"name": "amounts", "type": "uint256[]"}],
                "type": "function"
            },
            {
                "constant": True,
                "inputs": [
                    {"name": "amountIn", "type": "uint256"},
                    {"name": "reserveIn", "type": "uint256"},
                    {"name": "reserveOut", "type": "uint256"}
                ],
                "name": "getAmountOut",
                "outputs": [{"name": "amountOut", "type": "uint256"}],
                "type": "function"
            }
        ]
        
        # Contract addresses (example for Ethereum Mainnet)
        self.contract_addresses = {
            'WETH': '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',
            'USDC': '0xA0b86a33E6441E7C1A785D1A97b7327c2c0c0c0c',
            'DAI': '0x6B175474E89094C44Da98b954EedeAC495271d0F',
            'UNISWAP_ROUTER': '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D',
            'UNISWAP_FACTORY': '0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f'
        }
        
        # Initialize contracts
        for name, address in self.contract_addresses.items():
            if name in ['WETH', 'USDC', 'DAI']:
                self.contracts[name] = self.w3.eth.contract(
                    address=address,
                    abi=erc20_abi
                )
            elif name == 'UNISWAP_ROUTER':
                self.contracts[name] = self.w3.eth.contract(
                    address=address,
                    abi=uniswap_router_abi
                )
    
    def get_balance(self, token_symbol, address=None):
        """
        Get token balance for address
        
        Args:
            token_symbol: Token symbol (e.g., 'ETH', 'USDC', 'DAI')
            address: Address to check (default: current account)
        
        Returns:
            Token balance as Decimal
        """
        if address is None:
            if not self.account:
                raise ValueError("No account specified")
            address = self.account.address
        
        if token_symbol == 'ETH':
            balance_wei = self.w3.eth.get_balance(address)
            return Decimal(balance_wei) / Decimal(10**18)
        
        if token_symbol not in self.contracts:
            raise ValueError(f"Unknown token: {token_symbol}")
        
        contract = self.contracts[token_symbol]
        balance_wei = contract.functions.balanceOf(address).call()
        decimals = self.get_token_decimals(token_symbol)
        
        return Decimal(balance_wei) / Decimal(10**decimals)
    
    def get_token_decimals(self, token_symbol):
        """Get token decimals"""
        decimals_map = {
            'WETH': 18,
            'USDC': 6,
            'DAI': 18
        }
        return decimals_map.get(token_symbol, 18)
    
    def approve_token(self, token_symbol, spender_address, amount):
        """
        Approve token spending
        
        Args:
            token_symbol: Token symbol to approve
            spender_address: Address to approve for
            amount: Amount to approve (in human-readable format)
        
        Returns:
            Transaction hash
        """
        if not self.account:
            raise ValueError("No account configured")
        
        if token_symbol not in self.contracts:
            raise ValueError(f"Unknown token: {token_symbol}")
        
        contract = self.contracts[token_symbol]
        decimals = self.get_token_decimals(token_symbol)
        amount_wei = int(Decimal(amount) * Decimal(10**decimals))
        
        # Build transaction
        transaction = contract.functions.approve(
            spender_address,
            amount_wei
        ).build_transaction({
            'from': self.account.address,
            'gas': self.gas_limit,
            'gasPrice': self.gas_price,
            'nonce': self.w3.eth.get_transaction_count(self.account.address)
        })
        
        # Sign and send transaction
        signed_txn = self.w3.eth.account.sign_transaction(transaction, self.account.key)
        tx_hash = self.w3.eth.send_raw_transaction(signed_txn.rawTransaction)
        
        # Wait for confirmation
        receipt = self.w3.eth.wait_for_transaction_receipt(tx_hash)
        
        if receipt.status == 1:
            logger.info(f"Token approved: {tx_hash.hex()}")
            return tx_hash.hex()
        else:
            raise Exception("Transaction failed")
    
    def swap_eth_for_tokens(self, eth_amount, token_symbol, slippage_percent=1):
        """
        Swap ETH for tokens on Uniswap
        
        Args:
            eth_amount: Amount of ETH to swap
            token_symbol: Target token symbol
            slippage_percent: Maximum slippage percentage
        
        Returns:
            Transaction hash
        """
        if not self.account:
            raise ValueError("No account configured")
        
        if token_symbol not in self.contract_addresses:
            raise ValueError(f"Unknown token: {token_symbol}")
        
        router = self.contracts['UNISWAP_ROUTER']
        token_address = self.contract_addresses[token_symbol]
        
        # Calculate minimum amount out with slippage
        amount_out = self.get_swap_amount_out(eth_amount, 'ETH', token_symbol)
        min_amount_out = int(amount_out * (1 - slippage_percent / 100))
        
        # Build transaction
        eth_amount_wei = int(Decimal(eth_amount) * Decimal(10**18))
        deadline = int(time.time()) + 300  # 5 minutes
        
        transaction = router.functions.swapExactETHForTokens(
            min_amount_out,
            [self.contract_addresses['WETH'], token_address],
            self.account.address,
            deadline
        ).build_transaction({
            'from': self.account.address,
            'value': eth_amount_wei,
            'gas': self.gas_limit,
            'gasPrice': self.gas_price,
            'nonce': self.w3.eth.get_transaction_count(self.account.address)
        })
        
        # Sign and send transaction
        signed_txn = self.w3.eth.account.sign_transaction(transaction, self.account.key)
        tx_hash = self.w3.eth.send_raw_transaction(signed_txn.rawTransaction)
        
        # Wait for confirmation
        receipt = self.w3.eth.wait_for_transaction_receipt(tx_hash)
        
        if receipt.status == 1:
            logger.info(f"ETH swapped for {token_symbol}: {tx_hash.hex()}")
            return tx_hash.hex()
        else:
            raise Exception("Transaction failed")
    
    def swap_tokens_for_eth(self, token_symbol, token_amount, slippage_percent=1):
        """
        Swap tokens for ETH on Uniswap
        
        Args:
            token_symbol: Token symbol to swap
            token_amount: Amount of tokens to swap
            slippage_percent: Maximum slippage percentage
        
        Returns:
            Transaction hash
        """
        if not self.account:
            raise ValueError("No account configured")
        
        if token_symbol not in self.contract_addresses:
            raise ValueError(f"Unknown token: {token_symbol}")
        
        router = self.contracts['UNISWAP_ROUTER']
        token_address = self.contract_addresses[token_symbol]
        
        # Approve token spending
        self.approve_token(token_symbol, self.contract_addresses['UNISWAP_ROUTER'], token_amount)
        
        # Calculate minimum amount out with slippage
        amount_out = self.get_swap_amount_out(token_amount, token_symbol, 'ETH')
        min_amount_out = int(amount_out * (1 - slippage_percent / 100))
        
        # Build transaction
        decimals = self.get_token_decimals(token_symbol)
        token_amount_wei = int(Decimal(token_amount) * Decimal(10**decimals))
        deadline = int(time.time()) + 300  # 5 minutes
        
        transaction = router.functions.swapExactTokensForTokens(
            token_amount_wei,
            min_amount_out,
            [token_address, self.contract_addresses['WETH']],
            self.account.address,
            deadline
        ).build_transaction({
            'from': self.account.address,
            'gas': self.gas_limit,
            'gasPrice': self.gas_price,
            'nonce': self.w3.eth.get_transaction_count(self.account.address)
        })
        
        # Sign and send transaction
        signed_txn = self.w3.eth.account.sign_transaction(transaction, self.account.key)
        tx_hash = self.w3.eth.send_raw_transaction(signed_txn.rawTransaction)
        
        # Wait for confirmation
        receipt = self.w3.eth.wait_for_transaction_receipt(tx_hash)
        
        if receipt.status == 1:
            logger.info(f"{token_symbol} swapped for ETH: {tx_hash.hex()}")
            return tx_hash.hex()
        else:
            raise Exception("Transaction failed")
    
    def get_swap_amount_out(self, amount_in, token_in, token_out):
        """
        Calculate amount out for swap (simplified)
        
        Args:
            amount_in: Amount to swap
            token_in: Input token symbol
            token_out: Output token symbol
        
        Returns:
            Expected amount out
        """
        # This is a simplified calculation
        # In production, you would query the actual pool reserves
        
        # Example exchange rates (would be fetched from DEX)
        exchange_rates = {
            ('ETH', 'USDC'): 2000,  # 1 ETH = 2000 USDC
            ('ETH', 'DAI'): 2000,    # 1 ETH = 2000 DAI
            ('USDC', 'ETH'): 0.0005, # 1 USDC = 0.0005 ETH
            ('DAI', 'ETH'): 0.0005,  # 1 DAI = 0.0005 ETH
        }
        
        rate = exchange_rates.get((token_in, token_out))
        if rate is None:
            raise ValueError(f"No exchange rate for {token_in} -> {token_out}")
        
        return Decimal(amount_in) * Decimal(rate)
    
    def add_liquidity(self, token_symbol, token_amount, eth_amount):
        """
        Add liquidity to Uniswap pool
        
        Args:
            token_symbol: Token symbol to add
            token_amount: Amount of tokens to add
            eth_amount: Amount of ETH to add
        
        Returns:
            Transaction hash
        """
        if not self.account:
            raise ValueError("No account configured")
        
        # This would implement actual Uniswap liquidity addition
        # For now, it's a placeholder
        logger.info(f"Adding liquidity: {token_amount} {token_symbol} + {eth_amount} ETH")
        
        # In production, you would:
        # 1. Approve token spending
        # 2. Call Uniswap router's addLiquidityETH function
        # 3. Handle transaction and receipt
        
        return "0xplaceholder"
    
    def remove_liquidity(self, token_symbol, liquidity_amount):
        """
        Remove liquidity from Uniswap pool
        
        Args:
            token_symbol: Token symbol of the pool
            liquidity_amount: Amount of liquidity tokens to remove
        
        Returns:
            Transaction hash
        """
        if not self.account:
            raise ValueError("No account configured")
        
        # This would implement actual Uniswap liquidity removal
        logger.info(f"Removing liquidity: {liquidity_amount} from {token_symbol} pool")
        
        # In production, you would:
        # 1. Call Uniswap router's removeLiquidityETH function
        # 2. Handle transaction and receipt
        
        return "0xplaceholder"
    
    def get_portfolio_value(self, address=None):
        """
        Calculate total portfolio value in USD
        
        Args:
            address: Address to calculate for (default: current account)
        
        Returns:
            Portfolio value in USD
        """
        if address is None:
            if not self.account:
                raise ValueError("No account specified")
            address = self.account.address
        
        # Get balances
        eth_balance = self.get_balance('ETH', address)
        usdc_balance = self.get_balance('USDC', address)
        dai_balance = self.get_balance('DAI', address)
        
        # Calculate USD value (simplified)
        # In production, you would fetch real prices from oracles
        eth_price_usd = 2000  # Example price
        dai_price_usd = 1.0    # DAI is pegged to USD
        
        portfolio_value = (
            eth_balance * eth_price_usd +
            usdc_balance +
            dai_balance * dai_price_usd
        )
        
        return {
            'total_value_usd': portfolio_value,
            'breakdown': {
                'ETH': {'amount': eth_balance, 'value_usd': eth_balance * eth_price_usd},
                'USDC': {'amount': usdc_balance, 'value_usd': usdc_balance},
                'DAI': {'amount': dai_balance, 'value_usd': dai_balance * dai_price_usd}
            }
        }
    
    def monitor_gas_prices(self):
        """
        Monitor current gas prices
        
        Returns:
            Current gas price in Gwei
        """
        gas_price_wei = self.w3.eth.gas_price
        gas_price_gwei = gas_price_wei / 10**9
        
        return {
            'gas_price_wei': gas_price_wei,
            'gas_price_gwei': gas_price_gwei,
            'estimated_eth_cost': gas_price_wei * self.gas_limit / 10**18
        }
    
    def execute_arbitrage(self, token_symbol, min_profit_percent=1):
        """
        Execute arbitrage opportunity (simplified)
        
        Args:
            token_symbol: Token to arbitrage
            min_profit_percent: Minimum profit percentage required
        
        Returns:
            Transaction hash if arbitrage executed
        """
        # This is a simplified arbitrage implementation
        # In production, you would:
        # 1. Monitor prices across multiple DEXs
        # 2. Calculate profit opportunities
        # 3. Execute trades when profitable
        
        logger.info(f"Checking arbitrage opportunities for {token_symbol}")
        
        # Example: Check price difference between two DEXs
        # This is placeholder logic
        price_dex1 = self.get_swap_amount_out(1, 'ETH', token_symbol)
        price_dex2 = self.get_swap_amount_out(1, 'ETH', token_symbol) * 1.02  # 2% difference
        
        profit_percent = ((price_dex2 - price_dex1) / price_dex1) * 100
        
        if profit_percent >= min_profit_percent:
            logger.info(f"Arbitrage opportunity found: {profit_percent:.2f}% profit")
            # Execute arbitrage trades
            return "0xarbitrage_placeholder"
        
        return None

# Usage example
def main():
    """Example usage of DeFi Protocol"""
    
    # Initialize protocol
    provider_url = "https://mainnet.infura.io/v3/YOUR_PROJECT_ID"
    private_key = "YOUR_PRIVATE_KEY"  # Be careful with private keys!
    
    protocol = DeFiProtocol(provider_url, private_key)
    
    # Get portfolio value
    portfolio = protocol.get_portfolio_value()
    print(f"Portfolio Value: ${portfolio['total_value_usd']:.2f}")
    
    # Check gas prices
    gas_info = protocol.monitor_gas_prices()
    print(f"Gas Price: {gas_info['gas_price_gwei']:.2f} Gwei")
    
    # Swap ETH for USDC
    try:
        tx_hash = protocol.swap_eth_for_tokens(0.1, 'USDC', slippage_percent=1)
        print(f"Swap transaction: {tx_hash}")
    except Exception as e:
        print(f"Swap failed: {e}")
    
    # Check for arbitrage opportunities
    arbitrage_tx = protocol.execute_arbitrage('USDC', min_profit_percent=1)
    if arbitrage_tx:
        print(f"Arbitrage executed: {arbitrage_tx}")

if __name__ == "__main__":
    main()

Web3 Architecture

DeFi Ecosystem

graph TD
    A[User] --> B[Wallet]
    B --> C[DApp Frontend]
    C --> D[Web3.js/Ethers.js]
    D --> E[Smart Contracts]
    
    E --> F[DeFi Protocols]
    F --> G[DEX]
    F --> H[Lending]
    F --> I[Yield Farming]
    F --> J[Liquidity Pools]
    
    E --> K[Blockchain]
    K --> L[Ethereum]
    K --> M[Polygon]
    K --> N[BSC]
    
    O[Oracles] --> E
    P[Chainlink] --> O
    Q[Band Protocol] --> O
    
    R[Governance] --> E
    S[DAO] --> R
    T[Token Holders] --> R

Smart Contract Security

Common Vulnerabilities

VulnerabilityDescriptionProtection Measure
ReentrancyRecursive calls before state updateReentrancyGuard, Checks-Effects-Interactions
Integer OverflowArithmetic overflow/underflowSafeMath, Solidity 0.8+
Access ControlUnauthorized function callsModifiers, Role-based access
Front-RunningTransaction order manipulationCommit-reveal schemes
Oracle ManipulationPrice feed manipulationDecentralized oracles

DeFi Protocols Comparison

Leading DeFi Categories

CategoryProtocolsFunctionTVL (Billion $)
DEXUniswap, SushiSwapToken Swaps25+
LendingAave, CompoundLoans20+
YieldYearn, HarvestYield Optimization10+
DerivativesSynthetix, PerpetualDerivatives5+
OracleChainlink, BandPrice Feeds15+

Advantages and Disadvantages

Advantages of Web3/DeFi

  • Decentralization: No central authority required
  • Transparency: All transactions are publicly visible
  • Permissionless: Anyone can participate without permission
  • Programmability: Smart Contracts enable complex logic
  • Composability: Protocols can be combined

Disadvantages

  • Scalability: Limited transaction throughput
  • Gas Fees: High transaction costs during network congestion
  • User Experience: Complex wallet integration
  • Security Risks: Smart Contract Vulnerabilities
  • Regulatory Uncertainty: Uncertain regulatory landscape

Common Exam Questions

  1. What is the difference between Web2 and Web3? Web2 is centralized with servers, Web3 is decentralized with blockchain and smart contracts.

  2. Explain Smart Contracts! Smart Contracts are self-executing contracts on the blockchain that execute business logic without intermediaries.

  3. When are DeFi Protocols used? DeFi Protocols are used for decentralized financial services such as trading, lending, and yield farming.

  4. What are the main advantages of Blockchain? Decentralization, transparency, immutability, and security through cryptography.

Key Resources

  1. https://ethereum.org/
  2. https://docs.soliditylang.org/
  3. https://uniswap.org/
  4. https://aave.com/
Back to Blog
Share:

Related Posts