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

Potential Decimal Mismatch

issue: Potential Decimal Mismatch

Description

Throughout the strategy’s internal functions (e.g., _deployFunds, _freeFunds, claimAndSwap), the code implicitly assumes both asset (alETH) and underlying (WETH) share the same decimal precision (commonly 18 decimals). However, there is no explicit check or handling if either token has non-standard decimals. If underlying or asset operates with a different number of decimals, arithmetic and comparisons (e.g., minOut > _amount) can become incorrect or misleading, potentially causing revert conditions or misallocated funds.

Impact: Low/Medium

  1. Unexpected Rounding / Scaling Errors

    • If tokens do not share 18 decimals, deposit, withdrawal, or swap amounts may be off by factors of 10.

  2. Silent Logical Inconsistencies

    • Even if the protocol doesn’t revert, user balances or yields could be understated or overstated.

  3. Potential for Partial or Total Lock-Up

    • In extreme cases, mismatched decimals might trigger consistent reverts in _deployFunds or claimAndSwap, blocking user operations.


Evidence from Code

No explicit decimal check or scaling logic is found:

// Example snippet:
ERC20 public underlying;
// ...
function _swapUnderlyingToAsset(uint256 _amount, uint256 minOut, IVeloRouter.route[] calldata _path) internal {
require(minOut > _amount, "minOut too low");
// ...
// No consideration if 'underlying.decimals() != asset.decimals()'
}

The code treats _amount and minOut as though both tokens share the same decimal basis.


Potential Failure Scenario

  1. Non-Standard Decimal Token

    • Suppose the transmuter’s underlyingToken() has 6 decimals (like USDC) instead of 18.

  2. Arithmetic Discrepancies

    • A check such as require(minOut > _amount) is meaningless if _amount is effectively scaled differently than minOut.

  3. Reverts / Incorrect Transfers

    • The contract may revert due to perceived “low” or “invalid” amounts, or may inadvertently pass incorrect amounts to external calls, creating or missing significant funds.


Recommended Mitigations

  1. Check & Enforce Matching Decimals

    uint8 assetDecimals = ERC20(asset).decimals();
    uint8 underlyingDecimals = underlying.decimals();
    require(assetDecimals == underlyingDecimals, "Decimal mismatch");
    • If the design mandates the same decimals, revert early for non-conformance.

  2. Implement Scaling Logic

    • If the protocol allows mixed decimals, include a scaling factor so amounts are normalized to a consistent base before comparisons or swaps:

      function scaleAmount(uint256 amount, uint8 fromDecimals, uint8 toDecimals) internal pure returns (uint256) {
      if (fromDecimals < toDecimals) {
      return amount * 10 ** (toDecimals - fromDecimals);
      } else if (fromDecimals > toDecimals) {
      return amount / 10 ** (fromDecimals - toDecimals);
      }
      return amount;
      }
    • This ensures _amount and minOut are compared accurately.

  3. Test with Non-Standard Decimals

    • Add unit or fuzz tests simulating 6-decimal tokens (e.g., USDC) or 8-decimal tokens (e.g., WBTC) to detect potential logical errors early.


Conc

While many tokens do use 18 decimals, ignoring the possibility of non-standard decimals can lead to subtle but significant bugs in deposit, withdrawal, and swapping logic. Adding a simple decimal check or proper scaling in the strategy ensures robust handling of a broader range of ERC20 tokens, preventing confusing reverts and ensuring accurate accounting.

Updates

Appeal created

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

Support

FAQs

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