Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

mrKaplan - matchProposals function will revert while a proposal (borrowRequest/loanOffer) has less than 10% remaining value. #324

Open
sherlock-admin3 opened this issue Oct 7, 2024 · 0 comments
Labels
Sponsor Disputed The sponsor disputed this issue's validity

Comments

@sherlock-admin3
Copy link
Contributor

sherlock-admin3 commented Oct 7, 2024

mrKaplan

Medium

matchProposals function will revert while a proposal (borrowRequest/loanOffer) has less than 10% remaining value.

Summary

According to the README:
'''
Proposals can be matched against each other, instead of just asking the takers to accept the offers so that the best deals can be made.
'''
As proposals can never be allocated inside matchProposals function while one of them has less than 10% fulfill amount remaining, then the function becomes useless and then you will need to do it manually.

Root Cause

In PredictDotLoan.sol there's a function called _assertFulfillAmountNotTooLow that checks if the amount fulfilled is too low.

/**
     * @dev We want to ensure each fulfillment is at least 10% of the loan amount
     *      to prevent too many small loans from being created. It would be detrimental
     *      to user experience.
     *
     *      If the remaining loan amount is less than 10% of the loan amount, we allow the fulfillment to be smaller than 10%
     *      but the loan has to be fully fulfilled.
     */
    function _assertFulfillAmountNotTooLow(
        uint256 fulfillAmount,
        uint256 fulfilledAmount,
        uint256 loanAmount
    ) private pure {
        if (fulfillAmount != loanAmount - fulfilledAmount) {
            if (fulfillAmount < loanAmount / 10) {
                revert FulfillAmountTooLow();
            }
        }
    }

As this function is done in a way that when the amount is less than 10% of the amount fulfilled of one proposal, it passes with that same proposal, but not the other. The other proposal has different fulfillment so it reverts with FulfillAmountTooLow().

Internal pre-conditions

  1. Make one borrow request with some positionID
  2. Make one loan offer with the same positionID.
  3. Fill one of those proposals with >90% of the fulfillment.

External pre-conditions

No response

Attack Path

  1. Try to match the proposals by calling matchProposals.

Impact

  • Can never match this proposals through matchProposals.
  • Not according to the README.

PoC

  • borrowRequest proposal scenario.
function test_matchProposals_revertWhenFulfillIslessThanTenPercentOfBorrowRequest() public {
        IPredictDotLoan.Proposal memory loanOffer = _generateLoanOffer(IPredictDotLoan.QuestionType.Binary);
        IPredictDotLoan.Proposal memory borrowRequest = _generateBorrowRequest(IPredictDotLoan.QuestionType.Binary);
        
        // Fulfill most of the amount offered
        uint256 fulfillAmount = borrowRequest.loanAmount - (borrowRequest.loanAmount / 11);

        vm.prank(lender);
        predictDotLoan.acceptBorrowRequest(borrowRequest, fulfillAmount);

       vm.expectRevert(IPredictDotLoan.FulfillAmountTooLow.selector);
        predictDotLoan.matchProposals(borrowRequest, loanOffer);
    }
  • loanOffer proposal scenario:
function test_matchProposals_revertWhenFulfillIslessThanTenPercentOfLoanOffer() public {
        IPredictDotLoan.Proposal memory loanOffer = _generateLoanOffer(IPredictDotLoan.QuestionType.Binary);
        IPredictDotLoan.Proposal memory borrowRequest = _generateBorrowRequest(IPredictDotLoan.QuestionType.Binary);
        
        // Fulfill most of the amount offered
        uint256 fulfillAmount = loanOffer.loanAmount - (loanOffer.loanAmount / 11);

        vm.prank(borrower);
        predictDotLoan.acceptLoanOffer(loanOffer, fulfillAmount);

       vm.expectRevert(IPredictDotLoan.FulfillAmountTooLow.selector);
        predictDotLoan.matchProposals(borrowRequest, loanOffer);
    }

Mitigation

Check first if one of the proposals remaining fulfillment is less than 10% of the total. If yes, then avoid the checks _assertFulfillAmountNotTooLow of that proposal. But watch out by the storage manipulation on _updateFulfillment.

@sherlock-admin3 sherlock-admin3 added the Sponsor Disputed The sponsor disputed this issue's validity label Oct 7, 2024
@sherlock-admin2 sherlock-admin2 changed the title Fit Canvas Squid - matchProposals function will revert while a proposal (borrowRequest/loanOffer) has less than 10% remaining value. mrKaplan - matchProposals function will revert while a proposal (borrowRequest/loanOffer) has less than 10% remaining value. Oct 18, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Sponsor Disputed The sponsor disputed this issue's validity
Projects
None yet
Development

No branches or pull requests

1 participant