Skip to content
This repository has been archived by the owner on Oct 27, 2024. It is now read-only.

SilverChariot - When making a payment in OCC_Modular, interest is always calculated for one whole paymentInterval #28

Closed
sherlock-admin4 opened this issue Apr 25, 2024 · 1 comment
Labels
Duplicate A valid issue that is a duplicate of an issue with `Has Duplicates` label Medium A valid Medium severity issue Reward A payout will be made for this issue

Comments

@sherlock-admin4
Copy link
Contributor

sherlock-admin4 commented Apr 25, 2024

SilverChariot

medium

When making a payment in OCC_Modular, interest is always calculated for one whole paymentInterval

Summary

The loan APR is applied to the paymentInterval in OCC_Modular.amountOwed(). This will result in users paying more or less interest depending on the conditions around the loan at the moment of repayment.

Vulnerability Detail

In amountOwed() the APR is always applied to paymentInterval.

        interest = loans[id].principalOwed * loans[id].paymentInterval * loans[id].APR / (86400 * 365 * BIPS);

For better understanding the issue, I will give several examples:

1) Having gracePeriod > paymentInterval

Suppose paymentInterval = 5 days and gracePeriod = 20 days. Calling callLoan() after 25 days will make the user pay for only one paymentInterval, i.e 5 days instead of 25.

2) Using makePayment() in the beginning of an interval.

If a user want to make a payment in the beginning of a given interval, they will be charged interest for the whole interval, instead for only the time they have borrowed the loan for.

Impact

Miscalculation of interest.

Code Snippet

    function amountOwed(uint256 id) public view returns (
        uint256 principal, uint256 interest, uint256 lateFee, uint256 total
    ) {
        // 0 == Bullet.
        if (loans[id].paymentSchedule == 0) {
            if (loans[id].paymentsRemaining == 1) { principal = loans[id].principalOwed; }
        }
        // 1 == Amortization (only two options, use else here).
        else { principal = loans[id].principalOwed / loans[id].paymentsRemaining; }

        // Add late fee if past loans[id].paymentDueBy.
        if (block.timestamp > loans[id].paymentDueBy && loans[id].state == LoanState.Active) {
            lateFee = loans[id].principalOwed * (block.timestamp - loans[id].paymentDueBy) *
                loans[id].APRLateFee / (86400 * 365 * BIPS);
        }
        interest = loans[id].principalOwed * loans[id].paymentInterval * loans[id].APR / (86400 * 365 * BIPS);
        total = principal + interest + lateFee;
    }

Tool used

Manual Review

Recommendation

Add a new field lastInterestPaid to the Loan struct and use it to make the calculations.

Duplicate of #97

@github-actions github-actions bot closed this as completed May 5, 2024
@github-actions github-actions bot added Medium A valid Medium severity issue Duplicate A valid issue that is a duplicate of an issue with `Has Duplicates` label labels May 5, 2024
@sherlock-admin4
Copy link
Contributor Author

1 comment(s) were left on this issue during the judging contest.

panprog commented:

medium, dup of #97. This one assumes that makePayment is incorrect, comparing it to callLoan (which is assumed correct). Per my understanding, it's callLoan that is incorrect. Since this issue brings up the callLoan difference from makePayment, I consider this the same core reason.

@sherlock-admin2 sherlock-admin2 changed the title Clumsy Cobalt Lion - When making a payment in OCC_Modular, interest is always calculated for one whole paymentInterval SilverChariot - When making a payment in OCC_Modular, interest is always calculated for one whole paymentInterval May 11, 2024
@sherlock-admin2 sherlock-admin2 added the Reward A payout will be made for this issue label May 11, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Duplicate A valid issue that is a duplicate of an issue with `Has Duplicates` label Medium A valid Medium severity issue Reward A payout will be made for this issue
Projects
None yet
Development

No branches or pull requests

2 participants