DeFiFoundrySolidity
16,653 OP
View results
Submission Details
Severity: high
Invalid

Incorrect balance check in `claimAndSwap` function let unprofitable swaps pass

Title

Incorrect balance check in claimAndSwap function let unprofitable swaps pass

Summary

claimAndSwap function misjudged the balance check before and after the claim & swap operation. This leads to potential fund loss for the strategy and let unprofitable swaps go through.

Vulnerability Details

Here's the implementation of claimAndSwap function in StrategyOp contract:

function claimAndSwap(uint256 _amountClaim, uint256 _minOut, IVeloRouter.route[] calldata _path ) external onlyKeepers {
transmuter.claim(_amountClaim, address(this));
>> uint256 balBefore = asset.balanceOf(address(this));
_swapUnderlyingToAsset(_amountClaim, _minOut, _path);
>> uint256 balAfter = asset.balanceOf(address(this));
require((balAfter - balBefore) >= _minOut, "Slippage too high");
transmuter.deposit(asset.balanceOf(address(this)), address(this));
}

As seen above, claimAndSwap only counts the asset.balanceOf(address(this)) for balance change. This isn't accurate because it doesn't represent the actual balance of strategy contract.
As seen in balanceDeployed function, strategy balance aggregates the following 3 types of balance:

  • underlying.balanceOf(addres(this))

  • asset.balanceOf(addres(this))

  • transmuter.getUnexchangedBalance(address(this))

The current implementation relies solely on asset.balanceOf(address(this)) to track balance changes. This approach can result in an inaccurate minOut check, because while the asset balance could increase the underlying balance would decrease based on the claim amount.
Eventually, it potentially would cause fund losses for the strategy by allowing unprofitable swaps to proceed unchecked.

Impact

The flawed implementation risks severe financial losses, as unprofitable swaps may bypass validation, directly impacting the strategy’s profitability and exposing user funds to unnecessary vulnerabilities.

Tools Used

Manual Review

Recommendations

Before/after balance should be accurately checked in claimAndSwap function. Make the following adjustment:

function claimAndSwap(uint256 _amountClaim, uint256 _minOut, IVeloRouter.route[] calldata _path ) external onlyKeepers {
transmuter.claim(_amountClaim, address(this));
- uint256 balBefore = asset.balanceOf(address(this));
+ uint256 balBefore = balanceDeployed();
_swapUnderlyingToAsset(_amountClaim, _minOut, _path);
- uint256 balAfter = asset.balanceOf(address(this));
+ uint256 balAfter = balanceDeployed();
require((balAfter - balBefore) >= _minOut, "Slippage too high");
transmuter.deposit(asset.balanceOf(address(this)), address(this));
}
Updates

Appeal created

inallhonesty Lead Judge 8 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.