sherlock-audit / 2023-12-ubiquity-judging

2 stars 2 forks source link

infect3d - AmoMinterBorrow can DoS the pool by causing an underflow state #173

Closed sherlock-admin closed 7 months ago

sherlock-admin commented 8 months ago

infect3d

high

AmoMinterBorrow can DoS the pool by causing an underflow state

Summary

The amoMinterBorrow function in the UbiquityPool contract can lead to a underflow state in the pool's collateral balance.

Vulnerability Detail

This function allows an AMO minter to borrow collateral from the pool without accounting for the unclaimedPoolCollateral, which is increased everytime a user redeem Dollar tokens.

This can create a scenario where the total collateral balance collateral.balanceOf(address(this)) becomes less than the unclaimedPoolCollateral. This discrepancy leads to an arithmetic underflow in functions like redeemDollar, mintDollar, and collateralUsdBalance.

Impact

Once this underflow state is entered, there's 2 ways to exit it: 1) directly transfer collateral tokens to the contract to make its balance > unclaimedPoolCollateral 2) Users who redeemed call collectRedemption until unclaimedPoolCollateral < balance. Until then, its not possible to mint or redeem.

Code Snippet

https://github.com/sherlock-audit/2023-12-ubiquity/blob/main/ubiquity-dollar/packages/contracts/src/dollar/libraries/LibUbiquityPool.sol#L438-L443 https://github.com/sherlock-audit/2023-12-ubiquity/blob/main/ubiquity-dollar/packages/contracts/src/dollar/libraries/LibUbiquityPool.sol#L372 https://github.com/sherlock-audit/2023-12-ubiquity/blob/main/ubiquity-dollar/packages/contracts/src/dollar/libraries/LibUbiquityPool.sol#L268-L276 https://github.com/sherlock-audit/2023-12-ubiquity/blob/main/ubiquity-dollar/packages/contracts/src/dollar/libraries/LibUbiquityPool.sol#L256

Add this test to UbuiquityPoolFacet.t.sol to reproduce the issue

    function test_auditAmoBrickPool() public {
        address alice = makeAddr("alice");
        uint256 collateralIndex = 0;
        // vm.prank(address(dollarAmoMinter));

        //setting read-convenient configuration
        vm.startPrank(admin);
        ubiquityPoolFacet.setPriceThresholds(
            1000000, // mint threshold
            1000000 // redeem threshold
        );

        ubiquityPoolFacet.setFees(
            0, // collateral index
            0, // 1% mint fee
            0 // 2% redeem fee
        );
        vm.stopPrank();

        // balance setup of users
        uint256 depositAlice = 1000;
        collateralToken.mint(alice, depositAlice);
        vm.prank(alice);
        collateralToken.approve(address(ubiquityPoolFacet), type(uint).max);

        //Alice borrows, she sends collateral to the  which increase the collateral balance of the pool
        vm.prank(alice);
        (uint256 totalDollarMintAlice, /*uint256 collateralNeeded*/) = 
            ubiquityPoolFacet.mintDollar(collateralIndex, depositAlice, 0, type(uint).max);

        //Alice redeem its Dollars, which increases the unclaimedPoolCollateral
        vm.prank(alice);
        ubiquityPoolFacet.redeemDollar(collateralIndex, totalDollarMintAlice, 0);

        //AmoMinter borrow some collateral, which decrease the collateral balance of the pool
        vm.prank(address(dollarAmoMinter));
        ubiquityPoolFacet.amoMinterBorrow(1);

        //this set a state where collateral.balanceOf(address(this)) < (poolStorage.unclaimedPoolCollateral[collateralIndex])
        //creating a situation of underflow in redeemCollateral, mintDollar and collateralUsdBalance

        bytes memory arithmeticError = abi.encodeWithSignature("Panic(uint256)", 0x11);

        vm.expectRevert(arithmeticError);
        vm.prank(alice);
        ubiquityPoolFacet.redeemDollar(collateralIndex, 0, 0);

        vm.expectRevert(arithmeticError);
        vm.prank(alice);
        ubiquityPoolFacet.mintDollar(collateralIndex, depositAlice, 0, type(uint).max);

        vm.expectRevert(arithmeticError);
        ubiquityPoolFacet.collateralUsdBalance();
    }

Tool used

Manual Review

Recommendation

Make sure AmoMinter can only borrow amounts up to balance - unclaimedPoolCollateral

Duplicate of #1