For the complete documentation index, see llms.txt. This page is also available as Markdown.

50677 sc insight redundant code in dexaggregatorwrapperwithpredicateproxy impairs readability and potentially increases gas costs

Submitted on Jul 27th 2025 at 12:14:16 UTC by @KKam86 for Attackathon | Plume Network

  • Report ID: #50677

  • Report Type: Smart Contract

  • Report severity: Insight

  • Target: https://github.com/immunefi-team/attackathon-plume-network-nucleus-boring-vault/blob/main/src/helper/DexAggregatorWrapperWithPredicateProxy.sol

  • Impacts: (see details below)

Description

Brief/Intro

One of the functions in DexAggregatorWrapperWithPredicateProxy - depositOneInch has redundant code which unnecessarily complicates function logic. Redundant code impairs readability, produces additional gas costs or even can introduce new errors in contract logic.

Vulnerability Details

1

Redundant vault address validation (multiple checks)

Function depositOneInch validates vaultAddress three separate times:

  1. First time inside call to _oneInchHelper:

uint256 supportedAssetAmount = _oneInchHelper(
    supportedAsset,
    address(teller),
    executor,
    desc,
    data,
    nativeValueToWrap
);

Inside _oneInchHelper before approving assets to vaultAddress:

address vaultAddress = address(
    TellerWithMultiAssetSupport(payable(teller)).vault()
);
if (vaultAddress == address(0)) {
    revert("DexAggregatorWrapper: Invalid vault address for approval");
}

supportedAsset.safeApprove(vaultAddress, supportedAssetAmount);
  1. Second check immediately in depositOneInch after calling _oneInchHelper and before deposit:

address vaultAddress = address(teller.vault());
if (vaultAddress == address(0)) {
    // Handle error: Vault address cannot be zero if we need to transfer shares
    revert("DexAggregatorWrapper: Invalid vault address");
}
  1. Third check at the end of depositOneInch inside _calcSharesAndEmitEvent call path:

_calcSharesAndEmitEvent(
    supportedAsset,
    CrossChainTellerBase(address(teller)),
    address(desc.srcToken),
    desc.amount,
    supportedAssetAmount
);

And inside _calcSharesAndEmitEvent it again obtains and checks the vault address:

// Get vault address
address vaultAddress = address(teller.vault());
if (vaultAddress == address(0)) {
    revert("DexAggregatorWrapper: Invalid vault address");
}

These repeated checks for the same invariant are redundant and increase code complexity and gas usage.

2

Unnecessary shares recalculation in _calcSharesAndEmitEvent

The call to _calcSharesAndEmitEvent in depositOneInch recomputes shares solely to emit a Deposit event, but teller.deposit already returns the shares calculated using the same logic.

Example in depositOneInch:

shares = teller.deposit(
    supportedAsset,
    supportedAssetAmount,
    minimumMint
);

In TellerWithMultiAssetSupport.sol the deposit function returns shares via internal _erc20Deposit:

function deposit(
    ERC20 depositAsset,
    uint256 depositAmount,
    uint256 minimumMint
) external requiresAuth nonReentrant returns (uint256 shares)

And _erc20Deposit calculates shares as:

shares = depositAmount.mulDivDown(
    ONE_SHARE,
    accountant.getRateInQuoteSafe(depositAsset)
);

Where ONE_SHARE and accountant are initialized in TellerWithMultiAssetSupport constructor.

Meanwhile, shares calculation inside _calcSharesAndEmitEvent duplicates the same computation:

uint256 shares = supportedAssetAmount.mulDivDown(
    10 ** teller.vault().decimals(),
    AccountantWithRateProviders(teller.accountant()).getRateInQuoteSafe(
        supportedAsset
    )
);

This redundant recalculation is unnecessary since the shares were already computed and returned by teller.deposit.

Impact Details

  1. Increased gas costs — redundant operations consume additional gas which the user must pay for.

  2. Reduced readability — redundant and repeated checks make the code harder to reason about, maintain, and audit, increasing risk of errors.

References

  • https://github.com/immunefi-team/attackathon-plume-network-nucleus-boring-vault/blob/main/src/helper/DexAggregatorWrapperWithPredicateProxy.sol?utm_source=immunefi#L100

  • https://github.com/immunefi-team/attackathon-plume-network-nucleus-boring-vault/blob/main/src/helper/DexAggregatorWrapperWithPredicateProxy.sol?utm_source=immunefi#L275-L278

  • https://github.com/immunefi-team/attackathon-plume-network-nucleus-boring-vault/blob/main/src/helper/DexAggregatorWrapperWithPredicateProxy.sol?utm_source=immunefi#L106-L110

  • https://github.com/immunefi-team/attackathon-plume-network-nucleus-boring-vault/blob/main/src/helper/DexAggregatorWrapperWithPredicateProxy.sol?utm_source=immunefi#L114-L120

  • https://github.com/immunefi-team/attackathon-plume-network-nucleus-boring-vault/blob/main/src/helper/DexAggregatorWrapperWithPredicateProxy.sol?utm_source=immunefi#L397-L400

  • https://github.com/immunefi-team/attackathon-plume-network-nucleus-boring-vault/blob/main/src/helper/DexAggregatorWrapperWithPredicateProxy.sol?utm_source=immunefi#L103

  • https://github.com/immunefi-team/attackathon-plume-network-nucleus-boring-vault/blob/main/src/base/Roles/TellerWithMultiAssetSupport.sol#L353

  • https://github.com/immunefi-team/attackathon-plume-network-nucleus-boring-vault/blob/main/src/helper/DexAggregatorWrapperWithPredicateProxy.sol#L401-L404

Proof of Concept

(Empty)

Proof of Concept

(Empty)

Was this helpful?