• YouTube Channel
  • System Status
  • VS Code Extension
  • Possible Division by Zero

    Overview

    What is the Possible Division by Zero vulnerability?

    In Solidity, as in other programming languages, divide-by-zero errors can cause program execution to halt. Whether using checked or unchecked arithmetic, a divide-by-zero calculation will cause a Panic exception in the Ethereum Virtual Machine (EVM). Functions that use variable divisors without checking these values may be subject to such exceptions.

    Further reading: Solidity Documentation: Checked or Unchecked Arithmetic

    Technical example of vulnerable code

      // SPDX-License-Identifier: Unlicense
      pragma solidity ^0.8.0;
    
      contract SimplifiedLendingProtocol {
          mapping(address => uint256) public balances;
          uint256 public totalDeposited;
          uint256 public totalInterestPaid;
    
          uint256 public interestRatePerPeriod = 5e16; // 5% annual interest rate
          uint256 public constant SECONDS_PER_YEAR = 365 days;
    
          event InterestPaid(address user, uint256 interestAmount);
    
          function deposit() external payable {
              require(msg.value > 0, "Deposit amount must be greater than zero");
              balances[msg.sender] += msg.value;
              totalDeposited += msg.value;
          }
    
          function computeAnnualizedInterestRate(uint256 amountDeposited, uint256 scaleFactor) private view returns (uint256) {
              // Adjust the interest rate based on the scale factor
              uint256 adjustedInterestRate = (interestRatePerPeriod / scaleFactor);
              uint256 interest = (amountDeposited * adjustedInterestRate) / 1e18;
              return interest;
          }
    
          // Function to pay interest to a depositor with a scale factor for depositor tiers
          function payInterest(address depositor, uint256 scaleFactor) external {
              uint256 userBalance = balances[depositor];
    
              uint256 interest = computeAnnualizedInterestRate(userBalance, scaleFactor);
              payable(depositor).transfer(interest);
              totalInterestPaid += interest;
    
              emit InterestPaid(depositor, interest);
          }
    
          // Additional functionality omitted for brevity
      }
    
    

    In the example above, contract SimplifiedLendingProtocol represents a platform that allows depositors to deposit Ether and earn interest (with borrowing functionality omitted). The function payInterest() to make payments to depositors includes a variable, scaleFactor, which can be used to scale the interest rate offered to certain tiers of borrowers. However, when this variable is passed to computeAnnualizedInterestRate(), it is used as a divisor without any check; thus, inadvertent calls to the outer function passing zero could lead to execution errors.

    Technical example of how to fix the vulnerability

      // SPDX-License-Identifier: Unlicense
      pragma solidity ^0.8.0;
    
      contract SimplifiedLendingProtocolUpdated {
          mapping(address => uint256) public balances;
          uint256 public totalDeposited;
          uint256 public totalInterestPaid;
    
          uint256 public interestRatePerPeriod = 5e16; // 5% annual interest rate
          uint256 public constant SECONDS_PER_YEAR = 365 days;
    
          event InterestPaid(address user, uint256 interestAmount);
    
          function deposit() external payable {
              require(msg.value > 0, "Deposit amount must be greater than zero");
              balances[msg.sender] += msg.value;
              totalDeposited += msg.value;
          }
    
          function computeAnnualizedInterestRate(uint256 amountDeposited, uint256 scaleFactor) private view returns (uint256) {
              require(scaleFactor > 0, "Scale factor must be greater than zero");
              // Adjust the interest rate based on the scale factor
              uint256 adjustedInterestRate = (interestRatePerPeriod / scaleFactor);
              uint256 interest = (amountDeposited * adjustedInterestRate) / 1e18;
              return interest;
          }
    
          // Function to pay interest to a depositor with a scale factor for depositor tiers
          function payInterest(address depositor, uint256 scaleFactor) external {
              uint256 userBalance = balances[depositor];
    
              uint256 interest = computeAnnualizedInterestRate(userBalance, scaleFactor);
              payable(depositor).transfer(interest);
              totalInterestPaid += interest;
    
              emit InterestPaid(depositor, interest);
          }
    
          // Additional functionality omitted for brevity
      }
    
    

    In the revised example, contract SimplifiedLendingProtocolUpdated now performs a check in the computeAnnualizedInterestRate() function to ensure that the scaleFactor variable is greater than zero before performing division, avoiding the possibility of a divide-by-zero error.