DEV Community

rim dinov
rim dinov

Posted on

Breaking DeFi Math: Using Foundry Fuzzing to Prove Critical Precision Loss


In smart contract security, the difference between a high-severity bug and a 'won't fix' is a working Proof of Concept (PoC). Today, I'm sharing how I used Foundry Fuzzing to expose a Critical Precision Loss vulnerability in Kuru Labs, leading to a 100% loss of user funds in specific edge cases."

Main Content (Markdown ะดะปั DEV.TO)
The Core Problem: Premature Division
Solidity's integer division truncates decimal points. If you divide before you multiply, you risk zeroing out the entire calculation.

Vulnerable code pattern:

Solidity
// This results in 0 if (p * s) < 1e18
uint256 bugged = ((p * s) / 1e18) * mult / 1e18;
The Fuzzing Solution
Instead of guessing numbers, I wrote a property-based test. I told Foundry: "Find any combination of p, s, and mult where the bugged result is 0, but the correct math says it should be more."

Solidity
function testPrecisionLossFuzz(uint256 p, uint256 s, uint256 mult) public {
vm.assume(p > 0 && p < 1e18);
vm.assume(s > 0 && s < 1e18);
vm.assume(mult > 1e18 && mult < 1e30);

uint256 bugged = ((p * s) / 1e18) * mult / 1e18;
uint256 correct = (p * s * mult) / (1e18 * 1e18);

if (correct > 0 && bugged == 0) {
    emit log_named_uint("Critical loss found! Correct was", correct);
    fail();
}
Enter fullscreen mode Exit fullscreen mode

}
The Result
Foundry found a counter-example in just 4 runs:

p: 10,000,000

s: 3,792,478,066

Correct: 379,247

Bugged: 0 (User receives nothing!)

Key Takeaway
Always follow the "Multiply before Divide" rule.
uint256 correct = (p * s * mult) / (1e18 * 1e18);

Check out the full PoC and experiment with the fuzzer here:
github.com/rdin777/kuru-precision-loss

Top comments (0)