Summary
In the QuantAMMStorage.sol::ScalarQuantAMMBaseStorage contract, there's functions called quantAMMPackEight32, quantAMMPack32Array and QuantAMMStorage.sol::ScalarRuleQuantAMMStorage contract has _quantAMMPack128Array which have require checks to check values can't overflow or underflow. However, that require checks have a wrong revert message which is confusing.
Vulnerability Details
QuantAMMStorage.sol::ScalarQuantAMMBaseStorage::quantAMMPackEight32:
function quantAMMPackEight32(
int256 _firstInt,
int256 _secondInt,
int256 _thirdInt,
int256 _fourthInt,
int256 _fifthInt,
int256 _sixthInt,
int256 _seventhInt,
int256 _eighthInt
) internal pure returns (int256 packed) {
@>
require(
_firstInt <= MAX32 && _firstInt >= MIN32 && _secondInt <= MAX32 && _secondInt >= MIN32 && _thirdInt <= MAX32
&& _thirdInt >= MIN32 && _fourthInt <= MAX32 && _fourthInt >= MIN32 && _fifthInt <= MAX32
&& _fifthInt >= MIN32 && _sixthInt <= MAX32 && _sixthInt >= MIN32 && _seventhInt <= MAX32
&& _seventhInt >= MIN32 && _eighthInt <= MAX32 && _eighthInt >= MIN32,
@> "Overflow"
);
.
.
.
}
QuantAMMStorage.sol::ScalarQuantAMMBaseStorage::quantAMMPack32Array:
function quantAMMPack32Array(int256[] memory _sourceArray) internal pure returns (int256[] memory targetArray) {
.
.
...
uint256 stickyEndElems = _sourceArray.length - nonStickySourceLength;
if (stickyEndElems > 0) {
uint256 offset = 224;
int256 packed;
for (uint256 i = nonStickySourceLength; i < _sourceArray.length;) {
unchecked {
int256 elem = _sourceArray[i] / 1e9;
@> require(elem <= MAX32 && elem >= MIN32, "Overflow");
packed |= int256(uint256(elem << 224) >> 224) << offset;
offset -= 32;
++i;
}
}
targetArray[storageIndex] = packed;
}
}
QuantAMMStorage.sol::ScalarRuleQuantAMMStorage::_quantAMMPack128Array:
function _quantAMMPack128Array(int256[] memory _sourceArray) internal pure returns (int256[] memory targetArray) {
uint256 sourceArrayLength = _sourceArray.length;
uint256 targetArrayLength = sourceArrayLength;
uint256 storageIndex;
require(_sourceArray.length != 0, "LEN0");
if (_sourceArray.length % 2 == 0) {
unchecked {
targetArrayLength = (targetArrayLength) / 2;
}
targetArray = new int256[](targetArrayLength);
for (uint256 i; i < sourceArrayLength - 1;) {
targetArray[storageIndex] = _quantAMMPackTwo128(_sourceArray[i], _sourceArray[i + 1]);
unchecked {
i += 2;
++storageIndex;
}
}
} else {
int256 lastArrayItem = _sourceArray[_sourceArray.length - 1];
@>
@> require(
(lastArrayItem >= int256(type(int128).min)) && (lastArrayItem <= int256(type(int128).max)),
@> "Last array element overflow"
);
.
.
...
}
.
.
...
}
Impact
Revert message creates confusion among devs, auditors, and users.
Tools Used
Manual Review
Recommendations
Please update that wrong revert message to right one "Over/Underflow". Update the message as updated below...
QuantAMMStorage.sol::ScalarQuantAMMBaseStorage::quantAMMPackEight32:
function quantAMMPackEight32(
int256 _firstInt,
int256 _secondInt,
int256 _thirdInt,
int256 _fourthInt,
int256 _fifthInt,
int256 _sixthInt,
int256 _seventhInt,
int256 _eighthInt
) internal pure returns (int256 packed) {
- require(
- _firstInt <= MAX32 && _firstInt >= MIN32 && _secondInt <= MAX32 && _secondInt >= MIN32 && _thirdInt <= MAX32
- && _thirdInt >= MIN32 && _fourthInt <= MAX32 && _fourthInt >= MIN32 && _fifthInt <= MAX32
- && _fifthInt >= MIN32 && _sixthInt <= MAX32 && _sixthInt >= MIN32 && _seventhInt <= MAX32
- && _seventhInt >= MIN32 && _eighthInt <= MAX32 && _eighthInt >= MIN32,
- "Overflow"
- );
+ require(
+ _firstInt <= MAX32 && _firstInt >= MIN32 && _secondInt <= MAX32 && _secondInt >= MIN32 && _thirdInt <= MAX32
+ && _thirdInt >= MIN32 && _fourthInt <= MAX32 && _fourthInt >= MIN32 && _fifthInt <= MAX32
+ && _fifthInt >= MIN32 && _sixthInt <= MAX32 && _sixthInt >= MIN32 && _seventhInt <= MAX32
+ && _seventhInt >= MIN32 && _eighthInt <= MAX32 && _eighthInt >= MIN32,
+ "Over/Underflow"
+ );
.
.
.
}
QuantAMMStorage.sol::ScalarQuantAMMBaseStorage::quantAMMPack32Array:
function quantAMMPack32Array(int256[] memory _sourceArray) internal pure returns (int256[] memory targetArray) {
.
.
...
//pack up to 7 sticky ends
uint256 stickyEndElems = _sourceArray.length - nonStickySourceLength;
if (stickyEndElems > 0) {
uint256 offset = 224;
int256 packed;
for (uint256 i = nonStickySourceLength; i < _sourceArray.length;) {
unchecked {
int256 elem = _sourceArray[i] / 1e9;
// @info: wrong error message
- require(elem <= MAX32 && elem >= MIN32, "Overflow");
+ require(elem <= MAX32 && elem >= MIN32, "Over/Underflow");
packed |= int256(uint256(elem << 224) >> 224) << offset;
offset -= 32;
++i;
}
}
targetArray[storageIndex] = packed;
}
}
QuantAMMStorage.sol::ScalarRuleQuantAMMStorage::_quantAMMPack128Array:
function _quantAMMPack128Array(int256[] memory _sourceArray) internal pure returns (int256[] memory targetArray) {
uint256 sourceArrayLength = _sourceArray.length;
uint256 targetArrayLength = sourceArrayLength;
uint256 storageIndex;
require(_sourceArray.length != 0, "LEN0");
if (_sourceArray.length % 2 == 0) {
unchecked {
targetArrayLength = (targetArrayLength) / 2;
}
targetArray = new int256[](targetArrayLength);
for (uint256 i; i < sourceArrayLength - 1;) {
targetArray[storageIndex] = _quantAMMPackTwo128(_sourceArray[i], _sourceArray[i + 1]);
unchecked {
i += 2;
++storageIndex;
}
}
} else {
int256 lastArrayItem = _sourceArray[_sourceArray.length - 1];
- require(
- (lastArrayItem >= int256(type(int128).min)) && (lastArrayItem <= int256(type(int128).max)),
- "Last array element overflow"
- );
+ require(
+ (lastArrayItem >= int256(type(int128).min)) && (lastArrayItem <= int256(type(int128).max)),
+ "Last array element over/underflow"
);
.
.
...
}
.
.
...
}