🔪Arithmetic pitfall 2: Precision Loss Due To Rounding

Introduction:

Precision loss in Solidity’s arithmetic operations is not just a mathematical nuance but a formidable issue that can unravel a multitude of adversities affecting the integrity, functionality, and security of a smart contract. This lack of precision can silently erode token values, skew distributive fairness, create systemic vulnerabilities, and even unlock doors to potential DDoS attacks. This tutorial aims to spotlight the various dimensions of implications that precision loss can precipitate, coupled with insightful examples and remediation strategies to shield contracts from such precarious pitfalls.

The Multifaceted Implications of Precision Loss:

1. Token Value Erosion:

Precision loss could lead to the diminution of token values, particularly in financial computations or token distributions. Users might receive fewer tokens or assets than they are rightfully entitled to, resulting in discrepancies and financial losses.

2. Inequitable Distribution:

In contracts involving reward or asset distribution, precision loss could foster inequality. Some users might gain undue benefits, while others might face disadvantages, thereby undermining the fairness and integrity of the distribution process.

3. Vulnerability to DDoS Attacks:

An adversary could exploit the precision loss vulnerability to initiate DDoS attacks, overburdening the network, disrupting services, and causing accessibility issues, leading to a trust deficit in the system’s robustness. For example, a mathematical operation could round down to 0, leading to the division by 0 vulnerability discussed in the last chapter.

4. Systemic Value Loss:

The cumulative effect of precision loss across various operations could lead to a significant value leak from the ecosystem, affecting the overall financial health and sustainability of the platform or application.

Illustrative Scenarios:

Consider a reward distribution smart contract where precision loss could lead to users getting lesser rewards, possibly paving the way for inequitable distributions and making the system susceptible to manipulative attacks.

Example Illustrating Precision Loss:

solidityCopy codepragma solidity ^0.8.0;

contract PrecisionLossExample {
    function divide(uint256 a, uint256 b) public pure returns (uint256) {
        return a / b;
    }
}

// If the function divide(3, 2) is called, it will return 1, instead of 1.5 or 2.

In this example, the divide function will result in precision loss because the division of 3 by 2 is 1.5, but Solidity will return 1 due to floor rounding.

Illustrative Scenarios:

Consider a reward distribution smart contract where precision loss could lead to users getting lesser rewards, possibly paving the way for inequitable distributions and making the system susceptible to manipulative attacks.

solidityCopy code// Hypothetical Function Illustrating Precision Loss Vulnerabilities

function distributeRewards(uint256 totalRewards, uint256 userCount) public {
    uint256 rewardPerUser = totalRewards / userCount;
    // Potential precision loss, leading to undistributed rewards
}

Mitigation Strategies:

  1. Perform Multiplication Before Division: Prioritize multiplication operations before division to maintain higher accuracy levels and reduce the impacts of floor rounding.

    solidityCopy coderesult = (a * multiplier) / b;
  2. Utilize Scaling Techniques: Scale values before performing arithmetic operations, especially division, to preserve precision. It involves multiplying the operands by a power of 10, performing the calculation, and scaling down the result.

    solidityCopy coderesult = (a * 1000) / b;
    result = result / 1000; // Scaling down the result
  3. Adopt Fixed-Point Libraries: Consider employing fixed-point arithmetic libraries like ABDK Math 64.64, which facilitates operations involving real numbers in Solidity, helping mitigate precision loss.

  4. Conduct Rigorous Testing: Ensure to test mathematical computations thoroughly, considering various scenarios and edge cases to ascertain that precision loss doesn’t adversely impact the contract’s functionalities.

Real World Examples:

[H-01] pull() will most certainly fail - Code4rena

The actual token withdrawn from withdraw() will most certainly less than the _amount, due to precision loss in _tokensToShares() and withdraw(). As a result, IDetailedERC20(_token).safeTransfer(_recipient, _amount) will revert due to insufficant balance.

[H-01] withdraw() will most certainly fail - Code4rena

The actual token withdrew from Token.withdraw() will most certainly be less than the tokenAmounts[i], due to precision loss in the calculation of TokenAmount. As a result, IERC20(_Tokens[i]).safeTransfer(to, actualTokenAmounts[i])will revert due to insufficant balance.

Conclusion:

Precision loss due to floor rounding in Solidity is a subtle yet critical concern that developers must navigate attentively. By employing strategic mitigation techniques like pre-emptive multiplication, value scaling, leveraging fixed-point libraries, and rigorous testing, developers can significantly alleviate the risks associated with precision loss, thereby bolstering the accuracy and reliability of their smart contracts’ arithmetic operations.

Last updated