Flow

Sablier
FoundryDeFi
20,000 USDC
View results
Submission Details
Severity: high
Invalid

[H-4]Precision and Rounding Error Vulnerability in `Flow.stream()` Function's Token Streaming Calculations

Summary:

During the audit of the Flow contract, a significant vulnerability related to precision and rounding errors was identified. The implementation of the contract allows for calculations involving fixed-point numbers, which can lead to inaccuracies during arithmetic operations. These inaccuracies could potentially be exploited by malicious actors to manipulate token streaming and lead to financial losses.

Vulnerability Details:

The contract utilizes fixed-point mathematics for managing the streaming of tokens, specifically through the use of the UD21x18 and UD60x18 types. However, the implementation does not adequately handle precision and rounding during calculations, leading to discrepancies in expected outcomes.

Affected Functionality

The specific issue arises during the calculation of streamed amounts. A test case designed to verify the accuracy of streamed amounts revealed the following discrepancy:

  • Calculated Amount: 1,000,000,000,000,000,010 (1.000000000000000010)

  • Expected Amount: 11,000,000,000,000,000,000 (11.000000000000000000)

This mismatch indicates that the calculations performed by the contract do not align with the intended financial logic, thus exposing the contract to potential exploits.

Test Evidence:

// SPDX-License-Identifier: MIT
pragma solidity >=0.8.22;
import "forge-std/src/Test.sol";
import { UD60x18, ud60x18 } from "@prb/math/src/UD60x18.sol";
import { UD21x18, ud21x18 } from "@prb/math/src/UD21x18.sol";
import { Flow } from "src/types/DataTypes.sol"; // Adjust the import path
contract FlowTest is Test {
function testPrecisionAndRoundingErrors() public {
// Set up initial values for testing
uint256 initialDeposit = 1e18; // 1 token with 18 decimals
uint256 ratePerSecond = 1e18; // 1 token per second in 18-decimal format
uint256 duration = 10; // 10 seconds
// Calculate the expected total streamed amount
uint256 expectedTotalStreamed = initialDeposit + (ratePerSecond * duration);
// Create UD60x18 instances for fixed-point calculations
UD60x18 initialDepositFixed = ud60x18(initialDeposit);
UD60x18 ratePerSecondFixed = ud60x18(ratePerSecond);
UD60x18 durationFixed = ud60x18(duration);
// Calculate streamed amount using fixed-point arithmetic
UD60x18 totalStreamedFixed = initialDepositFixed + (ratePerSecondFixed * durationFixed);
// Convert back to standard uint256 for comparison
uint256 totalStreamed = totalStreamedFixed.unwrap();
// Assert that there are no precision issues
assertEq(totalStreamed, expectedTotalStreamed, "Precision or rounding error in streamed amount calculation");
}
}

The vulnerability was evidenced by the following test failure:

Ran 1 test for tests/DataTypes.t.sol:FlowTest
[FAIL: Precision or rounding error in streamed amount calculation: 1000000000000000010 != 11000000000000000000] testPrecisionAndRoundingErrors() (gas: 4126)

The test was designed to confirm the correctness of the streamed amount calculation but failed due to the identified precision issue.

Impact:

Financial Losses:

  • Users relying on the Flow.stream() function for accurate token transfers may experience financial losses due to the imprecision in the streamed amounts. This could lead to underpayment or overpayment scenarios, where users receive less than expected or inadvertently pay more than intended. Such discrepancies can accumulate over multiple transactions, resulting in substantial financial implications for users and potentially leading to trust erosion.

Market Manipulation Risks:

  • Malicious actors could exploit the rounding error to manipulate the streaming amounts to their advantage. For example, they could design transactions that intentionally exploit the rounding mechanism, allowing them to withdraw more tokens than they are entitled to, thereby draining resources from the contract. This could destabilize the token economy, particularly if large-scale manipulations occur.

Tools Used: Slither and Aderyn.

Recommendations:

Implement Fixed-Point Arithmetic:

  • Utilize fixed-point arithmetic libraries that inherently handle rounding issues. Instead of relying on floating-point calculations, which can introduce rounding errors, leverage libraries like PRBMath to perform all calculations with fixed-point numbers. This ensures that all arithmetic operations are precise and minimize the risk of rounding errors.

Explicit Rounding Strategies:

  • Clearly define the rounding strategy to be used in calculations. This includes specifying whether to round up, round down, or round to the nearest whole number. Make these decisions consistent throughout the contract to avoid discrepancies in how values are treated. Using standard rounding functions from trusted libraries can help maintain consistency.

Use SafeMath or Equivalent:

  • While Solidity 0.8 and later versions include built-in overflow and underflow checks, explicitly using libraries like SafeMath (or similar) can further reinforce safe arithmetic operations. This can help manage edge cases where precision issues could arise, especially when scaling values.

Updates

Lead Judging Commences

inallhonesty Lead Judge 10 months ago
Submission Judgement Published
Invalidated
Reason: Too generic

Support

FAQs

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