Kind Aqua Ostrich
Medium
Potential division by zero in _calculateCollateralAmountRequired
cause the transaction to revert in PredictDotLoan.sol
Potential division by zero in _calculateCollateralAmountRequired
in PredictDotLoan.sol
cause the transaction to revert.
The function _calculateCollateralAmountRequired
is responsible for calculating the required collateral for a loan offer based on the proposal, the fulfillment so far, and the amount being fulfilled.
https://github.com/sherlock-audit/2024-09-predict-fun/blob/main/predict-dot-loan/contracts/PredictDotLoan.sol#L1161-L1171
The line 1169
performs a division by proposal.loanAmount
. If proposal.loanAmount
is zero, this will lead to a division by zero error, causing the transaction to revert. Also. there's no check in place to ensure that proposal.loanAmount
is non-zero, which makes this function vulnerable.
We can create a test case (PoC
below) to exploit this vulnerability by providing a Proposal struct where proposal.loanAmount == 0
. This will result in a transaction revert due to the division by zero.
- In the
testDivisionByZero()
function, we create aProposal
withloanAmount == 0
. - The function
_calculateCollateralAmountRequired
will attempt to perform the division(proposal.collateralAmount * fulfillAmount) / proposal.loanAmount
, which will result in a division by zero and cause the transaction to revert.
No response
No response
No response
- The division by zero will revert transactions, leading to disruption of contract operations. Users attempting to execute the function in legitimate contexts could encounter reverts, resulting in poor user experience and protocol inefficiency.
- An attacker could intentionally trigger division by zero by crafting a proposal with loanAmount == 0, leading to denial of service (DoS) attacks. By creating proposals with zero loanAmount, an attacker could prevent legitimate users from interacting with the contract, disrupting the entire loan issuance process.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract CollateralCalculation {
struct Proposal {
uint256 collateralAmount;
uint256 loanAmount; // This could be zero, causing a division by zero
}
struct Fulfillment {
uint256 collateralAmount;
uint256 loanAmount;
}
function calculateCollateralAmountRequired(
Proposal calldata proposal,
Fulfillment storage fulfillment,
uint256 fulfillAmount
) external view returns (uint256 collateralAmountRequired) {
// Vulnerable division by zero
if (fulfillment.loanAmount + fulfillAmount == proposal.loanAmount) {
collateralAmountRequired = proposal.collateralAmount - fulfillment.collateralAmount;
} else {
collateralAmountRequired = (proposal.collateralAmount * fulfillAmount) / proposal.loanAmount;
}
}
// Simple function to test the vulnerability
function testDivisionByZero() external view returns (uint256) {
Proposal memory proposal = Proposal({collateralAmount: 1000, loanAmount: 0}); // loanAmount is zero
Fulfillment storage fulfillment;
uint256 fulfillAmount = 100;
return calculateCollateralAmountRequired(proposal, fulfillment, fulfillAmount);
}
}
- Before performing the division, ensure
proposal.loanAmount
is non-zero:
require(proposal.loanAmount > 0, "Loan amount cannot be zero");
- If a
loanAmount == 0
scenario is valid (in specific cases), introduce logic to handle it gracefully without dividing by zero:
if (proposal.loanAmount == 0) {
collateralAmountRequired = 0;
} else {
collateralAmountRequired = (proposal.collateralAmount * fulfillAmount) / proposal.loanAmount;
}