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

PositionAction.sol#decreaseLever with EXACT_IN primary swaps would always brick if swapFee is non-zero. #8

Closed
c4-bot-9 opened this issue Oct 18, 2024 · 2 comments
Labels
2 (Med Risk) Assets not at direct risk, but function/availability of the protocol could be impacted or leak value bug Something isn't working duplicate-27 🤖_primary AI based primary recommendation 🤖_14_group AI based duplicate group recommendation satisfactory satisfies C4 submission criteria; eligible for awards sponsor confirmed Sponsor agrees this is a problem and intends to fix it (OK to use w/ "disagree with severity") sufficient quality report This report is of sufficient quality

Comments

@c4-bot-9
Copy link
Contributor

Lines of code

https://github.com/code-423n4/2024-10-loopfi/blob/main/src/proxy/PositionAction.sol#L488

Vulnerability details

Impact

PositionAction.sol#decreaseLever with EXACT_IN primary swaps would always brick if swapFee is non-zero.

Bug Description

Note: This is a new issue that was introduced by the latest code diff (Doesn't exist in the 2024-07 Loopfi contest).

When performing decreaseLever, in the flashloan fallback onCreditFlashLoan(), we need to payoff the flashloan along with the fees.

For EXACT_IN primary swaps, if extra underlying tokens are swapped out, they are sent back to the vault as payed off debt. However, the issue here is when calculating the residual amount, it does not take flashloan fees into account.

The buggy line is uint256 residualAmount = swapAmountOut - subDebt;, where subDebt is the amount of token taken from flashloan, but fees also need to be subtracted here.

    function onCreditFlashLoan(
        address /*initiator*/,
        uint256 /*amount*/,
        uint256 fee,
        bytes calldata data
    ) external returns (bytes32) {
        if (msg.sender != address(flashlender)) revert PositionAction__onCreditFlashLoan__invalidSender();
        (LeverParams memory leverParams, uint256 subCollateral, address residualRecipient) = abi.decode(
            data,
            (LeverParams, uint256, address)
        );

        uint256 subDebt = leverParams.primarySwap.amount;
        underlyingToken.forceApprove(address(leverParams.vault), subDebt + fee);
        // sub collateral and debt
        ICDPVault(leverParams.vault).modifyCollateralAndDebt(
            leverParams.position,
            address(this),
            address(this),
            0,
            -toInt256(subDebt)
        );
        
        // withdraw collateral and handle any CDP specific actions
        uint256 withdrawnCollateral = _onDecreaseLever(leverParams, subCollateral);

        if (leverParams.primarySwap.swapType == SwapType.EXACT_IN) {
            leverParams.primarySwap.amount = withdrawnCollateral;

            bytes memory swapData = _delegateCall(
                address(swapAction),
                abi.encodeWithSelector(swapAction.swap.selector, leverParams.primarySwap)
            );

            uint256 swapAmountOut = abi.decode(swapData, (uint256));
            
            // @audit-bug: FEES ARE NOT TAKEN INTO ACCOUNT.
@>          uint256 residualAmount = swapAmountOut - subDebt;

            // sub collateral and debt
            if (residualAmount > 0) {
                underlyingToken.forceApprove(address(leverParams.vault), residualAmount);
                ICDPVault(leverParams.vault).modifyCollateralAndDebt(
                    leverParams.position,
                    address(this),
                    address(this),
                    0,
                    -toInt256(residualAmount)
                );
            }
        } else {
            ...
        }

        underlyingToken.forceApprove(address(flashlender), subDebt + fee);
        return CALLBACK_SUCCESS_CREDIT;
    }

Proof of Concept

N/A

Tools Used

Manual Review

Recommended Mitigation Steps

Change to uint256 residualAmount = swapAmountOut - subDebt - fee;

Assessed type

DoS

@c4-bot-9 c4-bot-9 added 2 (Med Risk) Assets not at direct risk, but function/availability of the protocol could be impacted or leak value bug Something isn't working labels Oct 18, 2024
c4-bot-6 added a commit that referenced this issue Oct 18, 2024
@c4-bot-11 c4-bot-11 added 🤖_14_group AI based duplicate group recommendation 🤖_primary AI based primary recommendation labels Oct 18, 2024
@howlbot-integration howlbot-integration bot added primary issue Highest quality submission among a set of duplicates sufficient quality report This report is of sufficient quality labels Oct 19, 2024
@amarcu amarcu added sponsor disputed Sponsor cannot duplicate the issue, or otherwise disagrees this is an issue sponsor confirmed Sponsor agrees this is a problem and intends to fix it (OK to use w/ "disagree with severity") and removed sponsor disputed Sponsor cannot duplicate the issue, or otherwise disagrees this is an issue labels Oct 25, 2024
@c4-judge c4-judge added duplicate-27 and removed primary issue Highest quality submission among a set of duplicates labels Nov 11, 2024
@c4-judge
Copy link

koolexcrypto marked the issue as duplicate of #27

@c4-judge c4-judge added the satisfactory satisfies C4 submission criteria; eligible for awards label Nov 11, 2024
@c4-judge
Copy link

koolexcrypto marked the issue as satisfactory

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
2 (Med Risk) Assets not at direct risk, but function/availability of the protocol could be impacted or leak value bug Something isn't working duplicate-27 🤖_primary AI based primary recommendation 🤖_14_group AI based duplicate group recommendation satisfactory satisfies C4 submission criteria; eligible for awards sponsor confirmed Sponsor agrees this is a problem and intends to fix it (OK to use w/ "disagree with severity") sufficient quality report This report is of sufficient quality
Projects
None yet
Development

No branches or pull requests

4 participants