The predict.fun protocol allows for users to have their loan/borrow proposals easily matched with the help of the matchProposals(...) function. However, due to an issue in the way the collateralAmount is updated in the proposal fulfilments, subsequent borrowers could end up paying more collateral than needed.
collateralAmountRequired is calculated using the parameters coming from the loanProposal instead of the borrowProposal. Because of this the collateral ratio of the borrower will wrongly increase, leading to a lower collateralAmountRequired in the borrow proposal context.
Lets look at some numbers to further dissect the problem:
Internal pre-conditions
Alice posts borrow proposal (2000 collateral, 1000 loanAmount, 1000 availableAmount)
Bob posts loan proposal (1500 collateral, 1000 loanAmount, 1000 availableAmount)
Naruto acceptBorrowRequest(aliceProposal, 300);
Naruto acceptLoanOffer(bobProposal, 500);
Alice with borrow proposal of (2000 collateral, 1000 loanAmount, 700 availableAmount)
Bob with loan proposal of (1500 collateral, 1000 loanAmount, 500 availableAmount)
External pre-conditions
No response
Attack Path
Let's invoke matchProposals on Alice and Bob.
AvailableAmount will be 500 as 500<700
collateralAmountRequired will be 1500*500/1000 = 750
That means that 750 collateral will be added to the fulfilment of the loan and borrow proposal.
Although that seems correct actually the correct borrow collateral should be calculated this way: 2000*500/1000 = 1000.
That means that we have a discrepancy of around 250 amount.
Now if we have someone to accept Alice's borrow proposal and decide to fill the whole amount of 200 left(700-500 from matchProposals).
She will pay that inflated collateral due to the discrepancy that happened in match proposal.
This is because of this formula in _calculateCollateralAmountRequired()
056Security
High
Borrower could pay inflated collateral.
Summary
The predict.fun protocol allows for users to have their loan/borrow proposals easily matched with the help of the matchProposals(...) function. However, due to an issue in the way the collateralAmount is updated in the proposal fulfilments, subsequent borrowers could end up paying more collateral than needed.
Root Cause
If we take a closer look into the matchProposals(...) function https://github.com/sherlock-audit/2024-09-predict-fun/blob/main/predict-dot-loan/contracts/PredictDotLoan.sol#L320-L449, we can see that when the proposal fulfilments are updated, there is a discrepancy between what values are given for the actual borrow fulfilment:
https://github.com/sherlock-audit/2024-09-predict-fun/blob/main/predict-dot-loan/contracts/PredictDotLoan.sol#L395-L408
collateralAmountRequired is calculated using the parameters coming from the loanProposal instead of the borrowProposal. Because of this the collateral ratio of the borrower will wrongly increase, leading to a lower collateralAmountRequired in the borrow proposal context.
Lets look at some numbers to further dissect the problem:
Internal pre-conditions
External pre-conditions
No response
Attack Path
https://github.com/sherlock-audit/2024-09-predict-fun/blob/main/predict-dot-loan/contracts/PredictDotLoan.sol#L1166-L1167
Impact
Due to the improper collateral calculations subsequent borrowers end up paying inflated collateral
PoC
The following PoC can be added in the PredictDotLoan.matchProposals.t.sol test file. I have added the following test helper function:
Mitigation
Recommended mitigation: