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

Potential Mismanagement of Token Decimals and Precision

Summary

The contract does not explicitly handle discrepancies in token decimals between asset and underlying tokens involved in swaps. This oversight can lead to calculation errors, incorrect slippage handling, and financial discrepancies during swaps.

Technical Details

Root Cause

The _swapUnderlyingToAsset function performs a direct comparison of minOut and _amount:

require(minOut > _amount, "minOut too low");

This assumes that both tokens (asset and underlying) use the same decimal configuration. If they differ, the comparison becomes invalid, leading to potential precision mismatches.

Vulnerable Code

function _swapUnderlyingToAsset(uint256 _amount, uint256 minOut, IVeloRouter.route[] calldata _path) internal {
require(minOut > _amount, "minOut too low");
uint256 underlyingBalance = underlying.balanceOf(address(this));
require(underlyingBalance >= _amount, "not enough underlying balance");
IVeloRouter(router).swapExactTokensForTokens(_amount, minOut, _path, address(this), block.timestamp);
}

Potential Attack Scenarios

Scenario 1: Precision Exploitation

  1. Setup: The asset token uses 6 decimals, while the underlying token uses 18 decimals.

  2. Execution: An attacker provides a minOut value that appears valid due to mismatched decimal precision, bypassing the require(minOut > _amount) check.

  3. Impact: The swap executes at an unfavorable rate, reducing the strategy's profitability and harming users.

Scenario 2: Slippage Manipulation

  1. Setup: A swap involves tokens with differing decimal configurations.

  2. Execution: Incorrect slippage calculations based on mismatched decimals result in swaps that fail or execute with excessive losses.

  3. Impact: Attackers exploit this inconsistency to profit from manipulated slippage conditions.

Scenario 3: Fund Misallocation

  1. Setup: Post-swap, the strategy allocates funds based on incorrect assumptions about token decimals.

  2. Execution: Tokens are incorrectly distributed, causing financial discrepancies in the strategy’s accounting.

  3. Impact: Misallocation affects user withdrawals and share calculations, reducing trust in the protocol.


Impact

  1. Financial Risk: Precision errors can lead to financial losses through miscalculated swaps or fund mismanagement.

  2. Operational Risk: Misallocation of funds post-swap affects the strategy’s ability to maintain accurate accounting and user balances.

  3. Exploitation Risk: Attackers can exploit slippage or precision mismatches to profit at the expense of the protocol.


** Recommendations**

1. Normalize Token Decimals

Before performing any calculations or comparisons, normalize token amounts to a common decimal standard:

function normalizeAmount(uint256 amount, uint8 decimals) internal pure returns (uint256) {
return amount * (10 ** (18 - decimals));
}

2. Use Token Metadata

Fetch token decimals dynamically using ERC20’s decimals() function to ensure accurate calculations:

uint8 assetDecimals = IERC20(asset).decimals();
uint8 underlyingDecimals = IERC20(underlying).decimals();
uint256 normalizedAmount = normalizeAmount(_amount, underlyingDecimals);
require(minOut > normalizedAmount, "minOut too low");

3. Implement Decimal-Aware Calculations

Ensure all calculations involving token amounts account for their respective decimal configurations. Use utility libraries or helpers to handle precision.


Proof of Concept (PoC)

Steps to Exploit:

  1. Deploy the contract with two tokens:

    • TokenA (6 decimals) as asset.

    • TokenB (18 decimals) as underlying.

  2. Call _swapUnderlyingToAsset with a minOut value designed to bypass the require(minOut > _amount) check due to mismatched precision.

  3. Observe the swap executing at an unfavorable rate, reducing the protocol’s profitability.

Expected Fix Behavior:

  1. Call _swapUnderlyingToAsset with mismatched decimals.

  2. Observe the function normalizing decimals and accurately enforcing the require(minOut > _amount) condition.

Updates

Lead Judging Commences

inallhonesty Lead Judge
8 months ago

Appeal created

inallhonesty Lead Judge 7 months ago
Submission Judgement Published
Invalidated
Reason: Lack of quality

Support

FAQs

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