Decimal Limitation in CamelotRelayer and UniV3Relayer Contract Deployment
mediumLines of code
https://github.com/open-dollar/od-contracts/blob/v1.5.5-audit/src/contracts/oracles/CamelotRelayer.sol#L58 https://github.com/open-dollar/od-contracts/blob/v1.5.5-audit/src/contracts/oracles/CamelotRelayer.sol#L103-L105 https://github.com/open-dollar/od-contracts/blob/v1.5.5-audit/src/contracts/oracles/UniV3Relayer.sol#L64 https://github.com/open-dollar/od-contracts/blob/v1.5.5-audit/src/contracts/oracles/UniV3Relayer.sol#L110-L112
Vulnerability details
Impact
The current design of the CamelotRelayer and UniV3Relayer contracts limits its compatibility to only those _quoteTokens that have a decimal count of 18 or fewer. If an attempt is made to deploy the contract with a token having more than 18 decimals as the _quoteToken, the contract deployment will fail due to an underflow issue during the multiplier calculation. This poses no financial risk but restricts the contract's adaptability in the wider DeFi ecosystem, preventing its use with tokens that have more than 18 decimals.
Proof of Concept
The restriction emerges from the constructor, where the multiplier is deduced as 18 - IERC20Metadata(_quoteToken).decimals().
https://github.com/open-dollar/od-contracts/blob/v1.5.5-audit/src/contracts/oracles/CamelotRelayer.sol#L58 https://github.com/open-dollar/od-contracts/blob/v1.5.5-audit/src/contracts/oracles/UniV3Relayer.sol#L64
soliditymultiplier = 18 - IERC20Metadata(_quoteToken).decimals();
For tokens like YAMv2, which possess 24 decimals, the computation would attempt 18 - 24, which results in an underflow, making the contract deployment unsuccessful.
Tools Used
Manual
Recommended Mitigation Steps
-
Alter the datatype of
multipliertoint256to account for both positive and negative values. -
Adjust the multiplier's computation in the constructor to handle situations where token decimals might be greater or less than 18.
solidityint8 decimalsDifference = 18 - int8(IERC20Metadata(_quoteToken).decimals()); multiplier = int256(decimalsDifference);
- Revise the
_parseResultfunction to either multiply or divide the_quoteResultdepending on themultipliervalue.
solidityfunction _parseResult(uint256 _quoteResult) internal view returns (uint256 _result) { if (multiplier > 0) { return _quoteResult * (10 ** uint256(multiplier)); } else if (multiplier < 0) { return _quoteResult / (10 ** uint256(-multiplier)); } else { return _quoteResult; } }
Note: It will require additional code refactoring to make baseAmount and its value assignment as int256 as well.
Assessed type
Under/Overflow
