An attacker can potentially consume all loan proposals at relatively low cost
Summary
A malicious attacker can stack up repeated calls of acceptLoanOffer() , repay() in a same block thereby consuming loan proposals without giving any interest. Lenders will not get any compensation for providing liquidity and will have to sign proposals again.
However, there's no requirement of minimum duration required for a loan before repay() is called.
This implies that the act of borrowing and repaying can be performed in the same block. Since interest amount is time dependent, it will be zero.
A malicious attacker can take advantage of this by calling acceptLoanOffer() and repay() in the same block potentially consuming the all or majority of loan proposals.
The cost of attack is also relatively low since attacker only needs to pay gas fee and protocol fee which is between 0% to 2%
On the contrary, consuming all or majority of the loan offers will hinder refinance() process by repeatedly consuming loans leading to more defaults.
Lenders receive no compensation for providing liquidity and are burdened with the inconvenience of having to sign new loan offers repeatedly.
Internal pre-conditions
No response
External pre-conditions
No response
Attack Path
The malicious borrower calls acceptLoanOffer() for a loan offer.
Immediately within the same block, the borrower calls repay() before any significant time passes, allowing the borrower to return the principal without interest.
This process is repeated multiple times, consuming all available loan offers in just a few transactions.
Impact
All or majority of loan offers being consumed in just few transactions.
Hindered refinance functionality leading to more defaults.
Bad user experience for lenders, leading to trust erosion.
PoC
No response
Mitigation
Introduce a minimum loan duration for repay() function.
Pheonix
Medium
An attacker can potentially consume all loan proposals at relatively low cost
Summary
A malicious attacker can stack up repeated calls of
acceptLoanOffer()
,repay()
in a same block thereby consuming loan proposals without giving any interest. Lenders will not get any compensation for providing liquidity and will have to sign proposals again.Root Cause
The
repay()
function is responsible for repayment of the loan by borrower. It calculates the debt based on time elapsed since the start of loan can change the loan status fromActive/Called
toRepaid
https://github.com/sherlock-audit/2024-09-predict-fun/blob/main/predict-dot-loan/contracts/PredictDotLoan.sol#L454-L474However, there's no requirement of minimum duration required for a loan before
repay()
is called. This implies that the act of borrowing and repaying can be performed in the same block. Since interest amount is time dependent, it will be zero.A malicious attacker can take advantage of this by calling
acceptLoanOffer()
andrepay()
in the same block potentially consuming the all or majority of loan proposals.The cost of attack is also relatively low since attacker only needs to pay gas fee and protocol fee which is between 0% to 2% On the contrary, consuming all or majority of the loan offers will hinder
refinance()
process by repeatedly consuming loans leading to more defaults. Lenders receive no compensation for providing liquidity and are burdened with the inconvenience of having to sign new loan offers repeatedly.Internal pre-conditions
No response
External pre-conditions
No response
Attack Path
acceptLoanOffer()
for a loan offer.repay()
before any significant time passes, allowing the borrower to return the principal without interest.Impact
PoC
No response
Mitigation
Introduce a minimum loan duration for
repay()
function.