Tadle

Tadle
DeFi
30,000 USDC
View results
Submission Details
Severity: high
Invalid

Decimal Precision Mismatch in Token Calculations

Summary:

In various functions across the contract, fixed decimal scalers are used for calculations involving ERC-20 tokens. However, these scalers are not adaptable to tokens with different decimal places (e.g., 8 or 18 decimals), leading to potential precision mismatches and incorrect calculations.

Vulnerability Details:

The contract uses constants such as REFERRAL_RATE_DECIMAL_SCALER, PLATFORM_FEE_DECIMAL_SCALER, and EACH_TRADE_TAX_DECIMAL_SCALER for scaling values:

uint256 referrerReferralBonus = platformFee.mulDiv(
referralInfo.referrerRate,
Constants.REFERRAL_RATE_DECIMAL_SCALER,
Math.Rounding.Floor
);
uint256 platformFee = depositAmount.mulDiv(
platformFeeRate,
Constants.PLATFORM_FEE_DECIMAL_SCALER
);
uint256 tradeTax = depositAmount.mulDiv(
makerInfo.eachTradeTax,
Constants.EACH_TRADE_TAX_DECIMAL_SCALER
);

These constants are set to fixed values like 1,000,000 or 10,000, which may not match the precision required for tokens with varying decimal places. For example, ERC-20 tokens with 18 decimal places require higher precision than those with 8 decimal places.

Impact:

Incorrect Calculations: Mismatch in decimal precision can lead to incorrect calculation of referral bonuses, fees, and taxes, causing financial discrepancies.

Proof of Concept (PoC)

1. getDepositAmount Function

Token with 18 Decimals

Parameters:

  • _offerType: Ask

  • _collateralRate: 500,000,000 (which is scaled for 18 decimals)

  • _amount: 1,000,000 tokens

  • Constants.COLLATERAL_RATE_DECIMAL_SCALER: 10,000 (which implies a 4-decimal scaler)

Calculation:

uint256 depositAmount = Math.mulDiv(
_amount,
_collateralRate,
Constants.COLLATERAL_RATE_DECIMAL_SCALER,
Math.Rounding.Ceil
);

Breaking it Down:

  1. Token Amount: 1,000,000 tokens

  2. Collateral Rate (scaled): 500,000,000 (18 decimal places)

  3. Scaler: 10,000 (4 decimal places)

Result:

depositAmount = Math.mulDiv(
1,000,000 * 500,000,000,
10,000
);

Calculating directly:

1,000,000 * 500,000,000 = 500,000,000,000,000
500,000,000,000,000 / 10,000 = 50,000,000,000

The result is 50,000,000,000, but this is incorrect because the scaler (10,000) does not match the precision required for a token with 18 decimals.

Token with 18 Decimals:

platformFeeRate: 5% (scaled to 50,000,000 for 18 decimals)
PLATFORM_FEE_DECIMAL_SCALER: 1,000,000 (implies 6 decimals)
Calculation:

uint256 platformFee = 1,000,000 * 50,000,000 / 1,000,000;
Results in an incorrect value due to scaling mismatch.

Token with 8 Decimals:

platformFeeRate: 5% (scaled to 50 for 8 decimals)
PLATFORM_FEE_DECIMAL_SCALER: 1,000,000 (implies 6 decimals)
Calculation:

uint256 platformFee = 1,000 * 50 / 10,000;
Results in a correct value but only for tokens with 8 decimals.

Tools Used:

Manual review

Recommendations:

Dynamic Scaling:

Implement logic to dynamically adjust scaling factors based on the token’s decimal precision. Retrieve the token’s decimals using the decimals() function and adjust calculations accordingly

Updates

Lead Judging Commences

0xnevi Lead Judge
10 months ago
0xnevi Lead Judge 10 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Appeal created

0xshadow1 Submitter
10 months ago
0xshadow1 Submitter
10 months ago
0xnevi Lead Judge
10 months ago
0xnevi Lead Judge 9 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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