QuantAMM

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

Inconsistent timestamp storage when the LPNFT is transferred.

Summary

In the afterUpdate function of the UpliftOnlyExample contract, during NFT transfers, the blockTimestampDeposit is incorrectly set using block.number instead of block.timestamp, which is inconsistent with how it's set during initial deposits. This creates an invalid timestamp record.

Vulnerability Details

In addLiquidityProportional(), when creating new FeeData entries, blockTimestampDeposit is set to block.timestamp:

function addLiquidityProportional( // ...
poolsFeeData[pool][msg.sender].push(
FeeData({
tokenID: tokenID,
amount: exactBptAmountOut,
//this rounding favours the LP
@> lpTokenDepositValue: depositValue,
//known use of timestamp, caveats are known.
blockTimestampDeposit: uint40(block.timestamp),
upliftFeeBps: upliftFeeBps
})
);

However, in afterUpdate() when transferring LPNFTs, it incorrectly uses block.number instead:

function afterUpdate(address _from, address _to, uint256 _tokenID) public {
// ... snip ...
@> feeDataArray[tokenIdIndex].blockTimestampDeposit = uint32(block.number);

This creates an inconsistency where:

  1. Original deposits store Unix timestamps (seconds since epoch)

  2. Transferred positions store block numbers

  3. The field type is uint40 but block.number is cast to uint32

Impact

Although currently the value of blockTimestampDeposit is not used in any calculations, still users will get a wrong (inconsistent) time recorded on chain in case they transfer the LPNFT to another address.

Tools Used

Manual code review

Recommendations

Be consistent with using block.timestamp in the function afterUpdate.

feeDataArray[tokenIdIndex].blockTimestampDeposit = uint40(block.timestamp);
Updates

Lead Judging Commences

n0kto Lead Judge 10 months ago
Submission Judgement Published
Validated
Assigned finding tags:

finding_afterUpdate_blockNumber_instead_of_timestamp

Likelihood: Medium/High, any NFT transfer will change this variable. Impact: Informational/Very Low. This variable is unused and won’t impact anything, but the array is public and its getter will return a variable with inconsistencies.

Support

FAQs

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

Give us feedback!