sherlock-audit / 2024-02-tapioca-judging

2 stars 2 forks source link

bin2chen - sellCollateral() does not work properly #101

Closed sherlock-admin2 closed 6 months ago

sherlock-admin2 commented 6 months ago

bin2chen

medium

sellCollateral() does not work properly

Summary

The BBLeverage.sellCollateral() function does not work as expected.

Vulnerability Detail

The implementation of BBLeverage.sellCollateral() is as follows:

    function sellCollateral(address from, uint256 share, bytes calldata data)
        external
        optionNotPaused(PauseType.LeverageSell)
        solvent(from, false)
        notSelf(from)
        returns (uint256 amountOut)
    {
        if (address(leverageExecutor) == address(0)) {
            revert LeverageExecutorNotValid();
        }
        _allowedBorrow(from, share);
        _removeCollateral(from, address(this), share);

        _SellCollateralMemoryData memory memoryData;

        (, memoryData.obtainedShare) =
            yieldBox.withdraw(collateralId, address(this), address(leverageExecutor), 0, share);
        memoryData.leverageAmount = yieldBox.toAmount(collateralId, memoryData.obtainedShare, false);
        amountOut = leverageExecutor.getAsset(
@>          assetId, address(collateral), address(asset), memoryData.leverageAmount, from, data
        );
        memoryData.shareOut = yieldBox.toShare(assetId, amountOut, false);
        address(asset).safeApprove(address(yieldBox), type(uint256).max);
@>      yieldBox.depositAsset(collateralId, address(this), address(this), 0, memoryData.shareOut); // TODO Check for rounding attack?
        address(asset).safeApprove(address(yieldBox), 0);

        memoryData.partOwed = userBorrowPart[from];
        memoryData.amountOwed = totalBorrow.toElastic(memoryData.partOwed, true);
        memoryData.shareOwed = yieldBox.toShare(assetId, memoryData.amountOwed, true);
        if (memoryData.shareOwed <= memoryData.shareOut) {
            _repay(from, from, memoryData.partOwed);
        } else {
            //repay as much as we can
            uint256 partOut = totalBorrow.toBase(amountOut, false);
            _repay(from, from, partOut);
        }
    }
}

The code above has several issues:

  1. leverageExecutor.getAsset() receiver should be address(this). ---> for next step deposit to YB
  2. yieldBox.depositAsset() receiver should be from. ----> for next execute _repay(from,from)

Impact

sellCollateral() does not work properly.

Code Snippet

https://github.com/sherlock-audit/2024-02-tapioca/blob/main/Tapioca-bar/contracts/markets/bigBang/BBLeverage.sol#L126C1-L163C2

Tool used

Manual Review

Recommendation

    function sellCollateral(address from, uint256 share, bytes calldata data)
        external
        optionNotPaused(PauseType.LeverageSell)
        solvent(from, false)
        notSelf(from)
        returns (uint256 amountOut)
    {
...
        (, memoryData.obtainedShare) =
            yieldBox.withdraw(collateralId, address(this), address(leverageExecutor), 0, share);
        memoryData.leverageAmount = yieldBox.toAmount(collateralId, memoryData.obtainedShare, false);
        amountOut = leverageExecutor.getAsset(
-           assetId, address(collateral), address(asset), memoryData.leverageAmount, from, data
+           assetId, address(collateral), address(asset), memoryData.leverageAmount, address(this), data
        );
        memoryData.shareOut = yieldBox.toShare(assetId, amountOut, false);
        address(asset).safeApprove(address(yieldBox), type(uint256).max);
-       yieldBox.depositAsset(collateralId, address(this), address(this), 0, memoryData.shareOut); // TODO Check for rounding attack?
+       yieldBox.depositAsset(collateralId, address(this), from, 0, memoryData.shareOut); 
        address(asset).safeApprove(address(yieldBox), 0);

        memoryData.partOwed = userBorrowPart[from];
        memoryData.amountOwed = totalBorrow.toElastic(memoryData.partOwed, true);
        memoryData.shareOwed = yieldBox.toShare(assetId, memoryData.amountOwed, true);
        if (memoryData.shareOwed <= memoryData.shareOut) {
            _repay(from, from, memoryData.partOwed);
        } else {
            //repay as much as we can
            uint256 partOut = totalBorrow.toBase(amountOut, false);
            _repay(from, from, partOut);
        }
    }
}

Duplicate of #42

maarcweiss commented 6 months ago

This should be the main issue imo, duped with https://github.com/sherlock-audit/2024-02-tapioca-judging/issues/42 given that both issues happen in the same line and the narrative of being unusable is the same. The narrative would be that both issues are partially explained given that each one missed the other, though it can be explained in a common one (sellCollateral does not work).

sherlock-admin4 commented 6 months ago

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

WangAudit commented:

refer to comments on #100