Buyers make first interest payment twice
Description
Callers of buyNow(...)
will always pay the first interest payment twice.
The first time happens when they pay the down payment—they can pay it in either ETH or WETH.
The down payment is equal to params.downpayment = params.pmt.pmt
where pmt
is given by
function calculatePMT(Loan storage loan)
internal
view
returns (PMT memory)
{
PMT memory pmt;
pmt.principal = loan.principal / loan.nper;
pmt.interest = loan.interest / loan.nper;
pmt.pmt = pmt.principal + pmt.interest;
return pmt;
}
The second time happens when distributeInterest(...)
is called:
LibLoan.distributeInterest(
reserveData,
params.pmt.interest,
_msgSender()
);
This pulls the same amount, but only WETH, directly from the buyer.
Impact
Users will be discouraged from using the protocol due to the extra large payment arising from high interest rates.
Recommendations
Remove the interest component from the down payment.
Remediation
Commit 3320ba3c↗ was indicated as containing the remediation for this issue. The params.downpayment
variable is now set to params.pmt.principal
instead of params.pmt.pmt
, meaning it will contain the value corresponding to the principal (without interest) of a single installment.
We note that a total of 29 commits exist between the commit under review and 3320ba3c↗; the diff between the two commits amounts to 24 solidity files changed, with 324 insertions and 525 deletions, containing other potentially relevant changes.