QuantAMM

QuantAMM
49,600 OP
View results
Submission Details
Severity: low
Invalid

Incorrect Storage Layout in Matrix Packing Leading to Data Corruption

Vulnerability Details

In _quantAMMPack128Matrix, when handling matrices where the total number of elements is odd, the code assumes that the last element should always be placed at the very end of the storage array (_targetArray[targetArrayLength - 1]). However, this assumption is incorrect because:

  1. The storage array length might be longer than what's needed for the matrix

  2. The code should continue placing elements sequentially at the current targetArrayIndex

  3. The current implementation could leave gaps (zeros) in the middle of the storage array

function _quantAMMPack128Matrix(int256[][] memory _sourceMatrix, int256[] storage _targetArray) internal {
// ... snip ...
if (((_sourceMatrix.length * _sourceMatrix.length) % 2) != 0) {
@> _targetArray[targetArrayLength - 1] =
int256(int128(_sourceMatrix[_sourceMatrix.length - 1][_sourceMatrix.length - 1]));
}
// ...

For example, if we have a 3x3 matrix (9 elements) and a target array of length 7, the last element would be placed at index 6 instead of index 4 where it should be according to the sequential packing pattern.

PoC

put this in test folder and run forge test --mp test/foundry/MatrixPack.t.sol -vvv

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
import "forge-std/Test.sol";
import "../../contracts/QuantAMMStorage.sol";
contract MatrixPackTest is VectorRuleQuantAMMStorage, Test {
int256[] public mockQuantAMMMatrix;
function setUp() public {
mockQuantAMMMatrix = new int256[](7);
}
function testPackMatrix() external {
int256[][] memory srcMatrix = _populateSrc();
_quantAMMPack128Matrix(srcMatrix, mockQuantAMMMatrix);
console.logInt(mockQuantAMMMatrix[0]);
console.logInt(mockQuantAMMMatrix[1]);
console.logInt(mockQuantAMMMatrix[2]);
console.logInt(mockQuantAMMMatrix[3]);
// @audit index 4 is zero because the value was placed at end of array. i.e index 6
assertEq(mockQuantAMMMatrix[4], 0);
assertEq(mockQuantAMMMatrix[5], 0);
console.logInt(mockQuantAMMMatrix[6]);
assertNotEq(mockQuantAMMMatrix[6], 0);
}
function _populateSrc() private pure returns (int256[][] memory _srcMatrix) {
_srcMatrix = new int256[][]();
_srcMatrix[0] = new int256[]();
_srcMatrix[1] = new int256[]();
_srcMatrix[2] = new int256[]();
_srcMatrix[0][0] = 1;
_srcMatrix[0][1] = 2;
_srcMatrix[0][2] = 3;
_srcMatrix[1][0] = 4;
_srcMatrix[1][1] = 5;
_srcMatrix[1][2] = 6;
_srcMatrix[2][0] = 7;
_srcMatrix[2][1] = 8;
_srcMatrix[2][2] = 9;
}
}

Impact

Data corruption when reading/unpacking the matrix incase of situation where by the matrix storage array is longer than data requirement.
Potential issues when interacting with other functions that expect packed data to be sequential.

Recommendations

Modify the code to place the last element at the current targetArrayIndex instead of forcing it to the end of the storage array:

if (((_sourceMatrix.length * _sourceMatrix.length) % 2) != 0) {
_targetArray[targetArrayIndex] =
int256(int128(_sourceMatrix[_sourceMatrix.length - 1][_sourceMatrix.length - 1]));
}

This ensures that elements are always packed sequentially without leaving gaps in the storage array.

Updates

Lead Judging Commences

n0kto Lead Judge 10 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
Assigned finding tags:

invalid_pack/unpack_matrix_array_odd_number_or_big_length

Called only in QuantammCovarianceBasedRule.sol with trusted parameters (set during creation or per a trusted function): `intermediateCovarianceStates[_poolAddress]`/`intermediateCovarianceStates[_poolParameters.pool]`. No real impact.

Support

FAQs

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

Give us feedback!