Flaky Merlot Parrot
Medium
Imprecise Exchange Rate Calculations Will Cause Order Failures for Traders as Rounding Errors Prevent Expected Execution
The imprecise exchange rate calculation in AutomationMaster.sol
will cause order failures for traders as rounding errors prevent expected execution during the checkUpkeep()
and performUpkeep()
processes in Brackets.sol
.
In AutomationMaster.sol: _getExchangeRate(),
the following line:
//AutomationMaster.sol: _getExchangeRate()
return (priceIn * 1e8) / priceOut;
introduces rounding errors due to integer division. When this function is called by getExchangeRate() in AutomationMaster.sol, which is further invoked by checkInRange() in Brackets.sol, it leads to imprecise exchange rates being used for critical comparisons.
AutomationMaster.getExchangeRate()
must be called by Brackets.sol during checkUpkeep() or performUpkeep().- The
priceIn
andpriceOut
values for a token pair must result in a fractional exchange rate when multiplied and divided by 1e8.
- The external oracles providing priceIn and priceOut values must return rates that result in fine-grained differences not representable by the current precision.
- Traders must place orders with tight limits (e.g., stopLimitPrice) sensitive to small variations.
- A trader places a bracket order via Brackets.sol with strict conditions (e.g., stopLimitPrice of 1.23456789).
- The system processes the order and calls
checkUpkeep()
, which invokescheckInRange()
in Brackets.sol. checkInRange()
callsAutomationMaster.getExchangeRate()
to retrieve the current exchange rate.AutomationMaster.getExchangeRate()
uses_getExchangeRate()
to compute the rate:
//AutomationMaster.getExchangeRate()
return (priceIn * 1e8) / priceOut;
The calculation suffers a rounding error (e.g., 1.23456789 becomes 1.234567).
- The rounded exchange rate fails to satisfy the
checkInRange()
condition, causing the order to fail.
1- Missed Trade Opportunities:
Orders
fail to trigger during favorable market conditions due to slight inaccuracies, causing potential financial losses for traders.
2- User Trust Erosion: Repeated failures from imperceptible rate differences undermine user confidence in the platform.
3- Automation Disruption: Automated strategies depending on precise rate calculations become unreliable, affecting advanced users and bots.
Proof-of-Concept Contract: The contract below isolates the rounding error issue and demonstrates how fractional values are truncated due to integer division:
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;
contract TestRoundingError {
function _getExchangeRate(uint256 priceIn, uint256 priceOut) public pure returns (uint256 exchangeRate) {
// Vulnerable code demonstrating rounding errors
return (priceIn * 1e8) / priceOut;
}
}
-
Deploy the above contract.
-
Call calculateExchangeRate(123456789, 98765432):
priceIn = 123456789; // Mock oracle value for tokenIn
priceOut = 98765432; // Mock oracle value for tokenOut
Expected result: 1.24999999 Actual result: 1 (due to rounding).
- Compare this to strict order conditions, which fail due to the discrepancy.
- Increase Precision:
Use a higher scaling factor to reduce the impact of rounding errors:
uint256 exchangeRate = (priceIn * 1e18) / priceOut;
This minimizes precision loss while remaining computationally efficient.
- Incorporate Error Margins:
Allow comparisons with a tolerance range to handle minor inaccuracies:
uint256 acceptableErrorMargin = exchangeRate / 10000; // 0.01% margin
if (actualExchangeRate >= expectedExchangeRate - acceptableErrorMargin &&
actualExchangeRate <= expectedExchangeRate + acceptableErrorMargin) {
// Proceed with execution
}
3.Adopt Fixed-Point Arithmetic:
Consider libraries like ABDKMathQuad for higher precision if ultra-accurate computations are required.