Summary
The feeDataArray[tokenIdIndex].blockTimestampDeposit is recored wrongly when transfer nft.
https://github.com/Cyfrin/2024-12-quantamm/blob/a775db4273eb36e7b4536c5b60207c9f17541b92/pkg/pool-hooks/contracts/hooks-quantamm/UpliftOnlyExample.sol#L610
Vulnerability Details
UpliftOnlyExample.sol#afterUpdate() function is as follows.
function afterUpdate(address _from, address _to, uint256 _tokenID) public {
...
if (tokenIdIndexFound) {
if (_to != address(0)) {
feeDataArray[tokenIdIndex].lpTokenDepositValue = lpTokenDepositValueNow;
@> feeDataArray[tokenIdIndex].blockTimestampDeposit = uint32(block.number);
feeDataArray[tokenIdIndex].upliftFeeBps = upliftFeeBps;
poolsFeeData[poolAddress][_to].push(feeDataArray[tokenIdIndex]);
if (tokenIdIndex != feeDataArrayLength - 1) {
for (uint i = tokenIdIndex + 1; i < feeDataArrayLength; i++) {
delete feeDataArray[i - 1];
feeDataArray[i - 1] = feeDataArray[i];
}
}
delete feeDataArray[feeDataArrayLength - 1];
feeDataArray.pop();
}
}
}
As we can see above, feeDataArray[tokenIdIndex].blockTimestampDeposit is recorded with block.number.
But UpliftOnlyExample.sol#addLiquidityProportional() function is as follows.
function addLiquidityProportional(
address pool,
uint256[] memory maxAmountsIn,
uint256 exactBptAmountOut,
bool wethIsEth,
bytes memory userData
) external payable saveSender(msg.sender) returns (uint256[] memory amountsIn) {
...
poolsFeeData[pool][msg.sender].push(
FeeData({
tokenID: tokenID,
amount: exactBptAmountOut,
lpTokenDepositValue: depositValue,
@> blockTimestampDeposit: uint40(block.timestamp),
upliftFeeBps: upliftFeeBps
})
);
nftPool[tokenID] = pool;
}
This is contradict.
Impact
Users and protocol will suffer from wrong blockTimestampDeposit.
Tools Used
Manual review
Recommendations
Modify UpliftOnlyExample.sol#afterUpdate() as follows.
function afterUpdate(address _from, address _to, uint256 _tokenID) public {
...
if (tokenIdIndexFound) {
if (_to != address(0)) {
feeDataArray[tokenIdIndex].lpTokenDepositValue = lpTokenDepositValueNow;
-- feeDataArray[tokenIdIndex].blockTimestampDeposit = uint32(block.number);
++ feeDataArray[tokenIdIndex].blockTimestampDeposit = uint32(block.timestamp);
feeDataArray[tokenIdIndex].upliftFeeBps = upliftFeeBps;
...
}
}
}