Farseen0/scar-pairs huggingface dataset:
LOW severity: Simplify checks to fail faster and remove negation operator on final boolean result. **Description:** Many checks in the code use a pattern of:

Often these checks can be simplified with improved efficiency by re-writting to:
* use `||`  instead of `&&` which makes the check fail sooner, avoiding evaluation of subsequent components
* removes the need for the final `!` negation...

Vulnerable code:
if( !(check_1 && check_2 && check_3) ) revert Error();

// L218
- if (!(boxAmount > 0 && boxAmount <= MAX_BOX_AMOUNT_PER_REVEAL)) revert InvalidBoxAmount();
+ if(boxAmount == 0 || boxAmount > MAX_BOX_AMOUNT_PER_REVEAL) revert InvalidBoxAmount();

// L347
- if (!(oneTimeCodeData.boxAmount > 0 && oneTimeCodeData.boxAmount <= MAX_BOX_AMOUNT_PER_REVEAL)) {
+ if (oneTimeCodeData.boxAmount == 0 || oneTimeCodeData.boxAmount > MAX_BOX_AMOUNT_PER_REVEAL) {

// L417
- if (!(_boxIds.length > 0)) revert Unauthorized();
+ if (boxIds.length == 0) revert Unauthorized();

// L442
- if (!(ownerOf(_boxIds[i]) == msg.sender)) revert Unauthorized();
+ if (ownerOf(_boxIds[i]) != msg.sender) revert Unauthorized();

// L170
- if (!(boxTierId > 0 && boxTierId <= tierIdsLength)) revert InvalidTierId();
+ if (boxTierId == 0 || boxTierId > tierIdsLength) revert InvalidTierId();

// L173
- if (!(boxMintedTimestamp <= block.timestamp && boxMintedTimestamp > 0)) revert InvalidBlockTimestamp();
+ if (boxMintedTimestamp > block.timestamp || boxMintedTimestamp == 0) revert InvalidBlockTimestamp();
LOW severity: Incorrect state update in `RiskOracle::_processUpdate`. **Description:** Within the `RiskParameterUpdate` struct, there is a field [`bytes previousValue`](https://github.com/ChaosLabsInc/risk-oracle/blob/9449219174e3ee7da9a13a5db7fb566836fb4986/src/RiskOracle.sol#L15) that is intended to store the previous value of a parameter. This state update is...

Vulnerable code:
function test_PreviousValueIsCorrectForSpecificMarketAndType() public {
    bytes memory market1 = abi.encodePacked("market1");
    bytes memory market2 = abi.encodePacked("market2");
    bytes memory newValue1 = abi.encodePacked("value1");
    bytes memory newValue2 = abi.encodePacked("value2");
    bytes memory newValue3 = abi.encodePacked("value3");
    bytes memory newValue4 = abi.encodePacked("value4");
    string memory updateType = initialUpdateTypes[0];

    vm.startPrank(AUTHORIZED_SENDER);

    // Publish first update for market1 and type1
    riskOracle.publishRiskParameterUpdate(
        "ref1", newValue1, updateType, market1, abi.encodePacked("additionalData1")
    );

    // Publish second update for market1 and type1
    riskOracle.publishRiskParameterUpdate(
        "ref2", newValue2, updateType, market1, abi.encodePacked("additionalData2")
    );

    // Publish first update for market2 and type1
    riskOracle.publishRiskParameterUpdate(
        "ref3", newValue3, updateType, market2, abi.encodePacked("additionalData3")
    );

    // Publish first update for market1 and type1
    riskOracle.publishRiskParameterUpdate(
        "ref4", newValue4, updateType, market1, abi.encodePacked("additionalData4")
    );

    vm.stopPrank();

    // Fetch the latest update for market1 and type1
    RiskOracle.RiskParameterUpdate memory latestUpdateMarket1Type1 =
        riskOracle.getLatestUpdateByParameterAndMarket(updateType, market1);
    assertEq(latestUpdateMarket1Type1.previousValue, newValue2);

    // Fetch the latest update for market2 and type1
    RiskOracle.RiskParameterUpdate memory latestUpdateMarket2Type1 =
        riskOracle.getLatestUpdateByParameterAndMarket(updateType, market2);
    assertEq(latestUpdateMarket2Type1.previousValue, bytes(""));
}
LOW severity: Asymmetry in validation between `RiskOracle::addUpdateType` and contract constructor. **Description:** The following [validation](https://github.com/ChaosLabsInc/risk-oracle/blob/9449219174e3ee7da9a13a5db7fb566836fb4986/src/RiskOracle.sol#L92) is present within `RiskOracle::addUpdateType`:

However, this function has the `onlyOwner` modifier applied, so the validation is not...

Vulnerable code:
require(!validUpdateTypes[newUpdateType], "Update type already exists.");
LOW severity: Unreachable code can be removed. **Description:** Within [`RiskOracle::_processUpdate`](https://github.com/ChaosLabsInc/risk-oracle/blob/9449219174e3ee7da9a13a5db7fb566836fb4986/src/RiskOracle.sol#L155), the `else` branch of the ternary operator is unreachable due to `updateCounter` being initialized to 0 and incremented before...

Vulnerable code:
updateCounter++;
bytes memory previousValue = updateCounter > 0 ? updatesById[updateCounter - 1].newValue : bytes("");
LOW severity: Array length validation is not necessary. **Description:** [`RiskOracle::publishBulkRiskParameterUpdates`](https://github.com/ChaosLabsInc/risk-oracle/blob/9449219174e3ee7da9a13a5db7fb566836fb4986/src/RiskOracle.sol#L117-L142) currently validates that the lengths of all input arrays are equal.

This validation can be removed on account of.....

Vulnerable code:
function publishBulkRiskParameterUpdates(
    string[] memory referenceIds,
    bytes[] memory newValues,
    string[] memory updateTypes,
    bytes[] memory markets,
    bytes[] memory additionalData
) external onlyAuthorized {
    require(
        referenceIds.length == newValues.length && newValues.length == updateTypes.length
            && updateTypes.length == markets.length && markets.length == additionalData.length,
        "Mismatch between argument array lengths."
    );
    for (uint256 i = 0; i < referenceIds.length; i++) {
        require(validUpdateTypes[updateTypes[i]], "Unauthorized update type at index");
        _processUpdate(referenceIds[i], newValues[i], updateTypes[i], markets[i], additionalData[i]);
    }
}
HIGH severity: USDs stability can be compromised as collateral can be stolen by removing Hypervisor tokens directly from a vault without repaying USDs debt. **Description:** When the owner of a Smart Vault calls [`SmartVaultV4::depositYield`](https://github.com/the-standard/smart-vault/blob/c6837d4a296fe8a6e4bb5e0280a66d6eb8a40361/contracts/SmartVaultYieldManager.sol#L167-L180),...

Vulnerable code:
function removeAsset(address _tokenAddr, uint256 _amount, address _to) external onlyOwner {
    ITokenManager.Token memory token = getTokenManager().getTokenIfExists(_tokenAddr);
    if (token.addr == _tokenAddr && !canRemoveCollateral(token, _amount)) revert Undercollateralised();
    IERC20(_tokenAddr).safeTransfer(_to, _amount);
    emit AssetRemoved(_tokenAddr, _amount, _to);
}

it('can steal collateral hypervisor tokens', async () => {
  const ethCollateral = ethers.utils.parseEther('0.1')
  await user.sendTransaction({ to: Vault.address, value: ethCollateral });

  let { collateral, totalCollateralValue } = await Vault.status();
  let preYieldCollateral = totalCollateralValue;
  expect(getCollateralOf('ETH', collateral).amount).to.equal(ethCollateral);

  depositYield = Vault.connect(user).depositYield(ETH, HUNDRED_PC);
  await expect(depositYield).not.to.be.reverted;
  await expect(depositYield).to.emit(YieldManager, 'Deposit').withArgs(Vault.address, MockWeth.address, ethCollateral, HUNDRED_PC);

  ({ collateral, totalCollateralValue } = await Vault.status());
  expect(getCollateralOf('ETH', collateral).amount).to.equal(0);
  expect(totalCollateralValue).to.equal(preYieldCollateral);

  const mintedValue = ethers.utils.parseEther('100');
  await Vault.connect(user).mint(user.address, mintedValue);

  // Vault is fully collateralised after minting USDs
  expect(await Vault.undercollateralised()).to.be.equal(false);

  const hypervisorBalanceVault = await MockUSDsHypervisor.balanceOf(Vault.address);
  await Vault.connect(user).removeAsset(MockUSDsHypervisor.address, hypervisorBalanceVault , user.address);

  // Vault has no collateral left and as such is undercollateralised
  expect(await MockUSDsHypervisor.balanceOf(Vault.address)).to.be.equal(0);
  expect(await Vault.undercollateralised()).to.be.equal(true);

  // User has both the minted USDs and Hypervisor collateral tokens
  expect(await MockUSDsHypervisor.balanceOf(user.address)).to.be.equal(hypervisorBalanceVault);
  expect(await USDs.balanceOf(user.address)).to.be.equal(mintedValue);
});
HIGH severity: `USDs` self-backing breaks assumptions around economic peg-maintenance incentives. **Description:** When `SmartVaultYieldManager::deposit` is called via `SmartVaultV4::depositYield`, [at least 10%](https://github.com/the-standard/smart-vault/blob/c6837d4a296fe8a6e4bb5e0280a66d6eb8a40361/contracts/SmartVaultYieldManager.sol#L168) of the deposited collateral must be directed...

Vulnerable code:
function deposit(address _collateralToken, uint256 _usdPercentage) external returns (address _hypervisor0, address _hypervisor1) {
    if (_usdPercentage < MIN_USDS_PERCENTAGE) revert StablePoolPercentageError();
    uint256 _balance = IERC20(_collateralToken).balanceOf(address(msg.sender));
    IERC20(_collateralToken).safeTransferFrom(msg.sender, address(this), _balance);
    HypervisorData memory _hypervisorData = hypervisorData[_collateralToken];
    if (_hypervisorData.hypervisor == address(0)) revert HypervisorDataError();
    _usdDeposit(_collateralToken, _usdPercentage, _hypervisorData.pathToUSDC);
    /* snip: other hypervisor deposit */
}

if (_token0 == address(USDs) || _token1 == address(USDs)) {
    // both USDs and its vault pair are € stablecoins, but can be equivalent to €1 in collateral
    _usds += _underlying0 * 10 ** (18 - ERC20(_token0).decimals());
    _usds += _underlying1 * 10 ** (18 - ERC20(_token1).decimals());
HIGH severity: USD stablecoins are incorrectly assumed to always be at peg. **Description:** [`SmartVaultV4::yieldVaultCollateral`](https://github.com/the-standard/smart-vault/blob/c6837d4a296fe8a6e4bb5e0280a66d6eb8a40361/contracts/SmartVaultV4.sol#L79-L103) returns the value of collateral held in yield positions for a given Smart Vault. For all Gamma Vaults other than...

Vulnerable code:
function yieldVaultCollateral(ITokenManager.Token[] memory _acceptedTokens) private view returns (uint256 _usds) {
    for (uint256 i = 0; i < hypervisors.length; i++) {
        IHypervisor _Hypervisor = IHypervisor(hypervisors[i]);
        uint256 _balance = _Hypervisor.balanceOf(address(this));
        if (_balance > 0) {
            uint256 _totalSupply = _Hypervisor.totalSupply();
            (uint256 _underlyingTotal0, uint256 _underlyingTotal1) = _Hypervisor.getTotalAmounts();
            address _token0 = _Hypervisor.token0();
            address _token1 = _Hypervisor.token1();
            uint256 _underlying0 = _balance * _underlyingTotal0 / _totalSupply;
            uint256 _underlying1 = _balance * _underlyingTotal1 / _totalSupply;
            if (_token0 == address(USDs) || _token1 == address(USDs)) {
                // both USDs and its vault pair are € stablecoins, but can be equivalent to €1 in collateral
                _usds += _underlying0 * 10 ** (18 - ERC20(_token0).decimals());
                _usds += _underlying1 * 10 ** (18 - ERC20(_token1).decimals());
            } else {
                for (uint256 j = 0; j < _acceptedTokens.length; j++) {
                    ITokenManager.Token memory _token = _acceptedTokens[j];
                    if (_token.addr == _token0) _usds += calculator.tokenToUSD(_token, _underlying0);
                    if (_token.addr == _token1) _usds += calculator.tokenToUSD(_token, _underlying1);
                }
            }
        }
    }
}
HIGH severity: Yield deposits are susceptible to losses of up to 10\%. **Description:** To deal with the slippage incurred through multiple [[1](https://github.com/the-standard/smart-vault/blob/c6837d4a296fe8a6e4bb5e0280a66d6eb8a40361/contracts/SmartVaultYieldManager.sol#L99),...

Vulnerable code:
function significantCollateralDrop(uint256 _preCollateralValue, uint256 _postCollateralValue) private pure returns (bool) {
    return _postCollateralValue < 9 * _preCollateralValue / 10;
}
HIGH severity: Hardcoded pool fees can result in increased slippage and failed swaps. **Description:** The issue raised in the previous CodeHawks contest as report item [M-03](https://codehawks.the-standard.io/c/2023-12-the-standard/s/483) remains present in `SmartVaultV4::swap` where the pool fee is...

Vulnerable code:
ISwapRouter.ExactInputSingleParams memory params = ISwapRouter.ExactInputSingleParams({
        tokenIn: inToken,
        tokenOut: getTokenisedAddr(_outToken),
        fee: 3000, // @audit hardcoded pool fee
        recipient: address(this),
        deadline: block.timestamp + 60,
        amountIn: _amount - swapFee,
        amountOutMinimum: minimumAmountOut,
        sqrtPriceLimitX96: 0
    });

function _usdDeposit(address _collateralToken, uint256 _usdPercentage, bytes memory _pathToUSDC) private {
    _swapToUSDC(_collateralToken, _usdPercentage, _pathToUSDC);
    _swapToRatio(USDC, usdsHypervisor, ramsesRouter, 500);
    _deposit(usdsHypervisor);
}
...
function _withdrawUSDsDeposit(address _hypervisor, address _token) private {
    IHypervisor(_hypervisor).withdraw(_thisBalanceOf(_hypervisor), address(this), address(this), [uint256(0),uint256(0),uint256(0),uint256(0)]);
    _swapToSingleAsset(usdsHypervisor, USDC, ramsesRouter, 500);
    _sellUSDC(_token);
}
MEDIUM severity: Insufficient validation of Chainlink data feeds. **Description:** `PriceCalculator` is a contract responsible for providing the Chainlink oracle prices for assets used by The Standard. Here, the price for an asset is queried and then normalized to 18 decimals before being returned to the caller:

However, these calls to...

Vulnerable code:
function tokenToUSD(ITokenManager.Token memory _token, uint256 _tokenValue) external view returns (uint256) {
    Chainlink.AggregatorV3Interface tokenUsdClFeed = Chainlink.AggregatorV3Interface(_token.clAddr);
    uint256 scaledCollateral = _tokenValue * 10 ** getTokenScaleDiff(_token.symbol, _token.addr);
    (,int256 _tokenUsdPrice,,,) = tokenUsdClFeed.latestRoundData();
    return scaledCollateral * uint256(_tokenUsdPrice) / 10 ** _token.clDec;
}

function USDToToken(ITokenManager.Token memory _token, uint256 _usdValue) external view returns (uint256) {
    Chainlink.AggregatorV3Interface tokenUsdClFeed = Chainlink.AggregatorV3Interface(_token.clAddr);
    (, int256 tokenUsdPrice,,,) = tokenUsdClFeed.latestRoundData();
    return _usdValue * 10 ** _token.clDec / uint256(tokenUsdPrice) / 10 ** getTokenScaleDiff(_token.symbol, _token.addr);
}

-   (,int256 _tokenUsdPrice,,,) = tokenUsdClFeed.latestRoundData();
+   (uint80 _roundId, int256 _tokenUsdPrice, , uint256 _updatedAt, ) = tokenUsdClFeed.latestRoundData();
+   if(_roundId == 0) revert InvalidRoundId();
+   if(_tokenUsdPrice == 0) revert InvalidPrice();
+   if(_updatedAt == 0 || _updatedAt > block.timestamp) revert InvalidUpdate();
+   if(block.timestamp - _updatedAt > TIMEOUT) revert StalePrice();
HIGH severity: Allowance reset for incorrect token in `SmartVaultYieldManager::_sellUSDC`. **Description:** When swapping `USDC` in `SmartVaultYieldManager::_sellUSDC`, there is an allowance given to the router:

Consistent with all other swaps performed in this contract, the allowance is reset after interaction with the router; however, in this instance, the allowance is [incorrectly...

Vulnerable code:
IERC20(USDC).safeApprove(uniswapRouter, _balance);
ISwapRouter(uniswapRouter).exactInput(ISwapRouter.ExactInputParams({
    /* snip: swap */
}));
IERC20(USDs).safeApprove(uniswapRouter, 0);

IERC20(USDC).safeApprove(uniswapRouter, _balance);
  ISwapRouter(uniswapRouter).exactInput(ISwapRouter.ExactInputParams({
      /* snip: swap */
  }));
- IERC20(USDs).safeApprove(uniswapRouter, 0);
+ IERC20(USDC).safeApprove(uniswapRouter, 0);
LOW severity: Insufficient deadline protection when adding/removing collateral from yield positions. **Description:** When the owner of a Smart Vault transfers its collateral assets to/from one of the supported Gamma Vaults, several swaps are executed with a deadline of `block.timestamp + 60`. For example, in `SmartVaultYieldManager::_sellUSDC`:

This deadline will always be valid whenever the...

Vulnerable code:
ISwapRouter(uniswapRouter).exactInput(ISwapRouter.ExactInputParams({
    path: _pathFromUSDC,
    recipient: address(this),
    deadline: block.timestamp + 60,
    amountIn: _balance,
    amountOutMinimum: 0
}));
HIGH severity: Removal of Hypervisor data locks deposited Smart Vault collateral. **Description:** A Gamma Vault (aka Hypervisor) is an external contract that maintains and offers fungible shares in Uniswap V3 liquidity positions. The Standard leverages multiple Hypervisors to enable the collateral backing `USDs` to earn yield, configured by admin calls to...

Vulnerable code:
function _withdrawOtherDeposit(address _hypervisor, address _token) private {
    HypervisorData memory _hypervisorData = hypervisorData[_token];
    if (_hypervisorData.hypervisor != _hypervisor) revert IncompatibleHypervisor();
    /* snip: withdraw and swap */
}

it('locks collateral when hypervisor is removed', async () => {
  const ethCollateral = ethers.utils.parseEther('0.1')
  await user.sendTransaction({ to: Vault.address, value: ethCollateral });

  let { collateral, totalCollateralValue } = await Vault.status();
  let preYieldCollateral = totalCollateralValue;
  expect(getCollateralOf('ETH', collateral).amount).to.equal(ethCollateral);

  depositYield = Vault.connect(user).depositYield(ETH, HUNDRED_PC.div(10));
  await expect(depositYield).not.to.be.reverted;
  await expect(depositYield).to.emit(YieldManager, 'Deposit').withArgs(Vault.address, MockWeth.address, ethCollateral, HUNDRED_PC.div(10));

  ({ collateral, totalCollateralValue } = await Vault.status());
  expect(getCollateralOf('ETH', collateral).amount).to.equal(0);
  expect(totalCollateralValue).to.equal(preYieldCollateral);

  await YieldManager.connect(admin).removeHypervisorData(MockWeth.address);

  // collateral is still counted
  ({ collateral, totalCollateralValue } = await Vault.status());
  expect(getCollateralOf('ETH', collateral).amount).to.equal(0);
  expect(totalCollateralValue).to.equal(preYieldCollateral);

  // user cannot remove collateral
  await expect(Vault.connect(user).withdrawYield(MockWETHWBTCHypervisor.address, ETH))
    .to.be.revertedWithCustomError(YieldManager, 'IncompatibleHypervisor');
});
HIGH severity: `WETH` collateral cannot be swapped in `SmartVaultV4`. **Description:** [`SmartVaultV4::swap`](https://github.com/the-standard/smart-vault/blob/c6837d4a296fe8a6e4bb5e0280a66d6eb8a40361/contracts/SmartVaultV4.sol#L259-L277) allows Smart Vault collateral, specified by its `bytes32` symbol, to be swapped for other supported collateral tokens. The...

Vulnerable code:
function getToken(bytes32 _symbol) private view returns (ITokenManager.Token memory _token) {
    ITokenManager.Token[] memory tokens = ITokenManager(ISmartVaultManagerV3(manager).tokenManager()).getAcceptedTokens();
    for (uint256 i = 0; i < tokens.length; i++) {
        if (tokens[i].symbol == _symbol) _token = tokens[i];
    }
    if (_token.symbol == bytes32(0)) revert InvalidToken();
}

function getTokenisedAddr(bytes32 _symbol) private view returns (address) {
    ITokenManager.Token memory _token = getToken(_symbol);
    return _token.addr == address(0) ? ISmartVaultManagerV3(manager).weth() : _token.addr;
}

inToken == ISmartVaultManagerV3(manager).weth() ?
    executeNativeSwapAndFee(params, swapFee) :
    executeERC20SwapAndFee(params, swapFee);

it('cant swap WETH', async () => {
  const ethCollateral = ethers.utils.parseEther('0.1')
  await MockWeth.connect(user).deposit({value: ethCollateral});
  await MockWeth.connect(user).transfer(Vault.address, ethCollateral);

  let { collateral } = await Vault.status();
  expect(getCollateralOf('WETH', collateral).amount).to.equal(ethCollateral);

  await expect(
    Vault.connect(user).swap(
      ethers.utils.formatBytes32String('WETH'),
      ethers.utils.formatBytes32String('WBTC'),
      ethers.utils.parseEther('0.05'),
      0)
    ).to.be.revertedWithCustomError(Vault, 'TransferError');
});
HIGH severity: Liquidations could be blocked by reverting ERtransfers. **Description:** When liquidations are performed via `SmartVaultV4::liquidate`, ERC-20 collateral tokens are handled within a loop:

If the contract balance of a given ERC-20 is non-zero, it will proceed to perform a transfer to the protocol address, as show below:

However, if any of these...

Vulnerable code:
function liquidate() external onlyVaultManager {
    /* snip: validation, state updates & native liquidation
    ITokenManager.Token[] memory tokens = ITokenManager(ISmartVaultManagerV3(manager).tokenManager()).getAcceptedTokens();
    for (uint256 i = 0; i < tokens.length; i++) {
        if (tokens[i].symbol != NATIVE) liquidateERC20(IERC20(tokens[i].addr));
    }
}

function liquidateERC20(IERC20 _token) private {
    if (_token.balanceOf(address(this)) != 0) _token.safeTransfer(ISmartVaultManagerV3(manager).protocol(), _token.balanceOf(address(this)));
}
HIGH severity: Potentially incorrect encoding of swap paths. **Description:** During fork testing, it became apparent that swap paths should use packed encoding; however, the [existing mocked test suite](https://github.com/the-standard/smart-vault/blob/c6837d4a296fe8a6e4bb5e0280a66d6eb8a40361/test/SmartVault.js#L499-L509) does the following:

Referring to...

Vulnerable code:
// data about how yield manager converts collateral to USDC, vault addresses etc
await YieldManager.addHypervisorData(
  MockWeth.address, MockWETHWBTCHypervisor.address, 500,
  new ethers.utils.AbiCoder().encode(['address', 'uint24', 'address'], [MockWeth.address, 3000, USDC.address]),
  new ethers.utils.AbiCoder().encode(['address', 'uint24', 'address'], [USDC.address, 3000, MockWeth.address])
)
HIGH severity: Collateral tokens with more than 18 decimals are not supported. **Description:** Due to the existing decimals scaling logic within [`PriceCalculator::getTokenScaleDiff`](https://github.com/the-standard/smart-vault/blob/c6837d4a296fe8a6e4bb5e0280a66d6eb8a40361/contracts/PriceCalculator.sol#L15-L17), any collateral tokens with more than 18 decimals will not be...

Vulnerable code:
function getTokenScaleDiff(bytes32 _symbol, address _tokenAddress) private view returns (uint256 scaleDiff) {
    return _symbol == NATIVE ? 0 : 18 - ERC20(_tokenAddress).decimals();
}
HIGH severity: Unnecessary typecast of `msg.sender` to `address`. **Description:** There is an [instance](https://github.com/the-standard/smart-vault/blob/c6837d4a296fe8a6e4bb5e0280a66d6eb8a40361/contracts/SmartVaultYieldManager.sol#L169) of the `msg.sender` context variable that is unnecessarily cast to `address` in...

Vulnerable code:
uint256 _balance = IERC20(_collateralToken).balanceOf(address(msg.sender));
HIGH severity: Inconsistent use of equivalent function parameter and immutable variable in `SmartVaultYieldManager::_withdrawUSDsDeposit` is confusing. **Description:** When withdrawing collateral from the `USDs` Hypervisor in `SmartVaultYieldManager::_withdrawUSDsDeposit`, the `_hypervisor` parameter will always be equal to the immutable `usdsHypervisor` variable due to the following [conditional...

Vulnerable code:
_hypervisor == usdsHypervisor ?
    _withdrawUSDsDeposit(_hypervisor, _token) :
    _withdrawOtherDeposit(_hypervisor, _token);

function _withdrawUSDsDeposit(address _hypervisor, address _token) private {
    IHypervisor(_hypervisor).withdraw(_thisBalanceOf(_hypervisor), address(this), address(this), [uint256(0),uint256(0),uint256(0),uint256(0)]);
    _swapToSingleAsset(usdsHypervisor, USDC, ramsesRouter, 500);
    _sellUSDC(_token);
}