Beginner FriendlyFoundry
100 EXP
View results
Submission Details
Severity: high
Valid

Incorrect logic in mulWadUp can lead to calculation errors

Summary

The mulWadUp() function has a condition to check if x / y == 1, and in that case it adds 1 to x. This is unnecessary, and can lead to errors.

Vulnerability Details

The condition if iszero(sub(div(add(z, x), y), 1)) checks if x / y == 1. This may have been added to adjust rounding upwards, but it is unnecessary and for big numbers may cause errors and overflows.

function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Equivalent to `require(y == 0 || x <= type(uint256).max / y)`.
if mul(y, gt(x, div(not(0), y))) {
mstore(0x40, 0xbac65e5b) // `MathMasters__MulWadFailed()`.
revert(0x1c, 0x04)
}
@> if iszero(sub(div(add(z, x), y), 1)) { x := add(x, 1) }
z := add(iszero(iszero(mod(mul(x, y), WAD))), div(mul(x, y), WAD))
}
}

Impact

The function will return incorrect calculations, which may lead to loss of funds if used in monetary transactions.

Tools Used

Foundry, Halmos, Manual review

Proof of Concept

This test should pass but will fail.

function testMulWadUpOverflow2() public {
uint256 x2 = 149453833408801632100269689951836288089;
uint256 y2 = 79700981937175649427451356571001433277;
assertEq(MathMasters.mulWadUp(x2, y2), (x2 * y2 - 1) / 1e18 + 1);
}

This test will overflow.

function testMulWadUpOverflow3() public {
uint256 y = MathMasters.sqrt(type(uint256).max);
uint256 x = type(uint256).max / y + 1;
uint256 r = MathMasters.mulWadUp(x, y);
console2.log("r", r);
}
forge test --mt testMulWadUpOverflow2
...
[FAIL. Reason: assertion failed] testMulWadUpOverflow2() (gas: 15259)
Logs:
Error: a == b not satisfied [uint]
Left: 11911617276956557497108380364885387729253693854339561184817
Right: 11911617276956557497108380364885387729173992872402385535389
...
```bash
forge test --mt testMulWadUpOverflow3
[PASS] testMulWadUpOverflow3() (gas: 3788)
Logs:
r 680564733841876926927

Recommended Mitigation

Remove the incorrect line.

function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Equivalent to `require(y == 0 || x <= type(uint256).max / y)`.
if mul(y, gt(x, div(not(0), y))) {
mstore(0x40, 0xbac65e5b) // `MathMasters__MulWadFailed()`.
revert(0x1c, 0x04)
}
- if iszero(sub(div(add(z, x), y), 1)) { x := add(x, 1) }
z := add(iszero(iszero(mod(mul(x, y), WAD))), div(mul(x, y), WAD))
}
}

Previous test passes, confirming that the mitigation is correct.

forge test --mt testMulWadUpOverflow2
...
[PASS] testMulWadUpOverflow2() (gas: 681)
Updates

Lead Judging Commences

inallhonesty Lead Judge over 1 year ago
Submission Judgement Published
Validated
Assigned finding tags:

`mulWadUp` has an unnecessary line that makes the result wrong for some inputs

Support

FAQs

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