Integer Division

Division in Solidity that truncates the result to a whole number, discarding any fractional remainder and potentially causing precision loss.

Integer division in Solidity always truncates toward zero, discarding any fractional remainder. When you divide 7 by 3, the result is 2—not 2.333. This behavior, while consistent with how integers work in most programming languages, causes precision loss that can compound into significant errors in financial calculations, reward distributions, and other math-heavy smart contract logic.

How Integer Division Works

Solidity has no native decimal or floating-point types. All division operations on uint and int types truncate:

1uint result1 = 7 / 3; // result1 = 2 (not 2.333...)
2uint result2 = 100 / 30; // result2 = 3 (not 3.333...)
3uint result3 = 1 / 2; // result3 = 0 (not 0.5)

The fractional portion is simply discarded. This isn't rounding—it's truncation toward zero.

The Division Before Multiplication Problem

A particularly dangerous pattern occurs when division precedes multiplication:

1// WRONG: Precision loss
2uint reward = (amount / totalSupply) * rewardPool;
3
4// If amount = 100, totalSupply = 1000, rewardPool = 500
5// (100 / 1000) * 500 = 0 * 500 = 0
6
7// CORRECT: Multiply first
8uint reward = (amount * rewardPool) / totalSupply;
9
10// (100 * 500) / 1000 = 50000 / 1000 = 50

In the wrong version, dividing 100 by 1000 yields 0 (truncated), making the entire calculation worthless. The correct version multiplies first, preserving precision until the final division.

This pattern is so common that static analysis tools like Aderyn include detectors specifically for it.

Real-World Impact

Integer division bugs have caused significant issues in production:

Reward calculations: Staking protocols that divide before multiplying may distribute fewer rewards than intended, or nothing at all for smaller stakers.

Fee calculations: Protocols computing fees as percentages can under-collect fees when division truncates intermediate results.

Price calculations: AMMs and oracles that incorrectly order operations may produce inaccurate prices, enabling arbitrage or manipulation.

Token distributions: Airdrops or vesting contracts can leave users with less than their fair share due to accumulated truncation errors.

Mitigation Strategies

Several approaches help manage integer division precision:

Multiply before dividing: Always arrange operations so multiplication happens before division when mathematically equivalent.

Use larger units internally: Store values in wei (10^18) or similar large denominators, only converting to human-readable units for display.

Scale factors: Multiply by a scale factor before division, then account for the scaling in subsequent calculations:

1uint PRECISION = 1e18;
2uint scaledResult = (amount * PRECISION * rewardPool) / totalSupply;
3uint finalResult = scaledResult / PRECISION;

Fixed-point libraries: Libraries like PRBMath, ABDKMath64x64, or Solmate's FixedPointMathLib provide fixed-point arithmetic with explicit precision handling.

Round up when appropriate: Sometimes truncation works against users (fees, liquidations). Libraries often provide divUp functions:

1function divUp(uint a, uint b) internal pure returns (uint) {
2 return (a + b - 1) / b;
3}

Detecting Integer Division Issues

Static analysis tools flag potential precision loss:

Division before multiplication: Direct detection of the dangerous pattern.

Division in loops: Accumulated truncation errors across iterations.

Division with small numerators: Operations where truncation to zero is likely.

However, not every division-before-multiplication is a bug. Context matters:

1// This might be intentional
2uint percentage = (amount / total) * 100; // Floor to nearest percent

Auditors and tools must consider whether precision loss is intentional or harmful.

Testing for Precision Issues

When auditing or testing contracts with division:

Test boundary values: Use inputs that produce small quotients before further operations.

Test with minimum values: Verify behavior with the smallest possible meaningful inputs.

Compare against reference implementation: Calculate expected results with high-precision arithmetic and compare.

Fuzz with constrained ranges: Generate random inputs focusing on values likely to trigger truncation issues.

Understanding integer division behavior is fundamental to writing secure smart contracts. While the rules are simple, their implications for complex financial calculations require careful attention during development and review.

Need expert guidance on Integer Division?

Our team at Zealynx has deep expertise in blockchain security and DeFi protocols. Whether you need an audit or consultation, we're here to help.

Get a Quote

oog
zealynx

Subscribe to Our Newsletter

Stay updated with our latest security insights and blog posts

© 2024 Zealynx