Possible Division by Zero
Overview
- Severity: Low
- Confidence: Medium
- Affected Versions: All
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.