QuantAMM

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

Transferred User Can Bypass Deposit Limit

Summary

The afterUpdate function of the contract fails to enforce a check limiting the number of deposits per user to 100. While the deposit function correctly reverts with a TooManyDeposits error when a user exceeds 100 deposits, the afterUpdate function does not apply the same restriction, allowing transferred users to bypass this limit. A malicious user can use this to transfer dust amounts to another users to prevent him removing liquidity.

Vulnerability Details

The contract enforces a limit of 100 deposits per user for the deposit function by checking the number of deposits in poolsFeeData[pool][msg.sender]. If this limit is exceeded, the transaction is reverted.

function addLiquidityProportional(
address pool,
uint256[] memory maxAmountsIn,
uint256 exactBptAmountOut,
bool wethIsEth,
bytes memory userData
) external payable saveSender(msg.sender) returns (uint256[] memory amountsIn) {
if (poolsFeeData[pool][msg.sender].length > 100) {
revert TooManyDeposits(pool, msg.sender);
}

However, the afterUpdate function, which is responsible for handling transfers, does not include a similar check. This allows users who receive LP tokens via transfer to accumulate more than 100 deposits, bypassing the limit set by the protocol.

function afterUpdate(address _from, address _to, uint256 _tokenID) public {
//
//
if (tokenIdIndexFound) {
if (_to != address(0)) {
// Update the deposit value to the current value of the pool in base currency (e.g. USD) and the block index to the current block number
//vault.transferLPTokens(_from, _to, feeDataArray[i].amount);
feeDataArray[tokenIdIndex].lpTokenDepositValue = lpTokenDepositValueNow;
feeDataArray[tokenIdIndex].blockTimestampDeposit = uint32(block.number);
feeDataArray[tokenIdIndex].upliftFeeBps = upliftFeeBps;
//actual transfer not a afterTokenTransfer caused by a burn
poolsFeeData[poolAddress][_to].push(feeDataArray[tokenIdIndex]);

https://github.com/Cyfrin/2024-12-quantamm/blob/a775db4273eb36e7b4536c5b60207c9f17541b92/pkg/pool-hooks/contracts/hooks-quantamm/UpliftOnlyExample.sol#L614

A malicious user can exploit this vulnerability to perform a denial-of-service (DoS) attack by transferring multiple small (dust) deposits to another user. This abuse causes the recipient's poolsFeeData array to grow excessively, making operations like withdrawing liquidity or transferring position NFTs increasingly gas-intensive due to the iterative for loops.

Impact

Users can bypass the protocol-imposed limit of 100 deposits.

Malicious actors can render key operations like liquidity removal or position transfers infeasible for targeted users Accumulating a large number of deposits for a single user can DOS removing liquidity and transfering position because of increased gas cost. If the loop iterates many times, it can quickly exceed the gas limit, causing the transaction to fail.

Tools Used

Manual

Recommendations

Add a check in the afterUpdate function to ensure the number of deposits for the recipient user does not exceed 100.

Updates

Lead Judging Commences

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

finding_afterUpdate_does_not_check_limit_NFT_per_user

Likelihood: Medium/High, anyone can receive an unlimited NFT number but will cost creation of LP tokens and sending them. Impact: Low/Medium, DoS the afterUpdate and addLiquidityProportional but will be mitigable on-chain because a lot of those NFT can be burn easily in onAfterRemoveLiquidity.

Support

FAQs

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