Approved LPNFT senders can clear approver's pool fee data at specific index by transferring NFT from approver to approver. This will prevent approver from removing liquidity from the protocol at all.
UpliftOnlyExample.afterUpdate contains the logic behind the scene when LPNFT is transferred from one user to another.
First, it finds the fee data corresponding to the token ID getting transferred:
If the fee data related to tokenID is found, it updates and transfers it to receiver's fee data:
Then, it reorders sender's fee data and pops the sender's fee data array
The vulnerability lies on the fact that feeDataArrayLength is not updated when feeDataArray == poolsFeeData[poolAddress][_to] (i.e. _from == _to). If _from == _to, feeDataArray's length is increased by one, but feeDataArrayLength remains the old value.
So delete feeDataArray[feeDataArrayLength - 1] actually clears the item at feeDataArray.length - 2 and feeDataArray.pop will remove the last item from the array. Thus, the new last item of feeDataArray will be uninitialized FeeData.
This uninitialized fee data will throw division by zero error when the user tries to remove liquidity from the protocol
Consider the following scenario:
bob added some liquidity and get two LPNFTs
bob approves alice to spend one of his new minted LPNFTs
alice mischivaeously transfers the token from bob to bob, instead of spending it
now bob wants to remove the remaining liquidity but he couldn't due to zero division error
You can put the following code snippet to UpliftExample.t.sol
Invalid state of the protocol
User cannot remove liquidity from the protocol
Foundry
Prevent no-op transfer in LPNFT._update function. i.e. check if previousOwner == to
Likelihood: Low, when users wants to transfer tokens they already own to themselves. Impact: High, funds loss.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.