QuantAMM

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

Missing NFT Burn on Liquidity Removal in QuantAMM Protocol

Summary

A critical vulnerability has been identified in the QuantAMM Protocol's liquidity management system. When users remove liquidity from pools, their corresponding LP NFTs are not burned, leading to a persistent representation of non-existent positions.

Vulnerability Details

UpliftOnlyExample.sol
LPNFT.sol

When users add liquidity, they correctly receive an NFT token representing their position through the LPNFT.mint() function. However, the protocol fails to implement the corresponding burn() function call in either removeLiquidityProportional() when liquidity is withdrawn. This oversight creates a dangerous mismatch between actual liquidity positions and their NFT representations. It enables malicious actors to retain governance rights, potentially double-claim benefits, or transfer "ghost" NFTs representing non-existent positions to unsuspecting buyers. The vulnerability is particularly severe because these orphaned NFTs maintain full functionality within the protocol's ecosystem, despite no longer being backed by actual liquidity.

// UpliftOnlyExample.sol
function removeLiquidityProportional(
uint256 bptAmountIn,
uint256[] memory minAmountsOut,
bool wethIsEth,
address pool
) external payable saveSender(msg.sender)
// 1. Attacker adds liquidity
addLiquidity() -> LPNFT.mint() // Gets tokenId X
// 2. Attacker removes liquidity
removeLiquidityProportional() // NFT not burned
// 3. Attacker retains NFT despite no position
// TokenId X still valid and owned by attacker
// Current Implementation (Missing Critical Step)
function removeLiquidityProportional(...) {
// Removes liquidity
amountsOut = _removeLiquidityProportional(
pool,
address(this),
msg.sender,
bptAmountIn,
minAmountsOut,
wethIsEth,
abi.encodePacked(msg.sender)
);
// ❌ Missing: LPNFT(nftAddress).burn(tokenId);
}

Impact

This could lead to significant protocol state corruption, especially in governance decisions where voting power should be directly tied to active liquidity positions, effectively allowing users to maintain protocol influence without any actual stake at risk.

Tools Used

Github

Recommendations

function removeLiquidityProportional(...) {
// Get user's NFT tokenId
uint256 tokenId = getUserTokenId(msg.sender, pool);
// Remove liquidity
amountsOut = _removeLiquidityProportional(...);
// Burn NFT
+ LPNFT(nftAddress).burn(tokenId);
emit LiquidityRemoved(msg.sender, pool, tokenId);
}
Updates

Lead Judging Commences

n0kto Lead Judge 11 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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

Give us feedback!