QuantAMM

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

user can bypass paying fees by updating his position to another account then remove liquidity

Summary

User add liquidity to the protocol and if there is a positive change in price he pays fees that depend on BptAmount he is withdrawing

he can bypass paying this fee by updating his position to another account

File: UpliftOnlyExample.sol
576: function afterUpdate(address _from, address _to, uint256 _tokenID) public {
// CODE
605: if (tokenIdIndexFound) {
606: if (_to != address(0)) {
607: // 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
608: //vault.transferLPTokens(_from, _to, feeDataArray[i].amount);
609: feeDataArray[tokenIdIndex].lpTokenDepositValue = lpTokenDepositValueNow;
610: feeDataArray[tokenIdIndex].blockTimestampDeposit = uint32(block.number);
611: feeDataArray[tokenIdIndex].upliftFeeBps = upliftFeeBps;

as seen above the logic of updating the current lpTokenDepositValueNow is recorded

Scenario

  • User added liquidity where lpTokenDepositValueNow = 2e18

  • Time passes and lpTokenDepositValueNow = 10e18 (user should pay fees for that positive change )

  • user updated his position to his other account recording the current lpTokenDepositValueNow then remove liquidity

  • then a user removes liquidity with recorded lpTokenDepositValueNow of 10e18

  • user pays the minimum fee as there is no positive change in price

File: UpliftOnlyExample.sol
471: for (uint256 i = localData.feeDataArrayLength - 1; i >= 0; --i) {
472: localData.lpTokenDepositValue = feeDataArray[i].lpTokenDepositValue;
473:
474: localData.lpTokenDepositValueChange =
475: (int256(localData.lpTokenDepositValueNow) - int256(localData.lpTokenDepositValue)) /
476: int256(localData.lpTokenDepositValue);
477:
478: uint256 feePerLP;
479: // if the pool has increased in value since the deposit, the fee is calculated based on the deposit value
480: if (localData.lpTokenDepositValueChange > 0) {
481: feePerLP =
482: (uint256(localData.lpTokenDepositValueChange) * (uint256(feeDataArray[i].upliftFeeBps) * 1e18)) /
483: 10000;
484: }
485: // if the pool has decreased in value since the deposit, the fee is calculated based on the base value - see wp
486: else {
487: //in most cases this should be a normal swap fee amount.
488: //there always myst be at least the swap fee amount to avoid deposit/withdraw attack surgace.
489: feePerLP = (uint256(minWithdrawalFeeBps) * 1e18) / 10000;
490: }

Impact

Loss of funds/fees

Tools Used

manual review

Recommendations

incase of update the first recorded value should be the same

Updates

Lead Judging Commences

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

finding_afterUpdate_bypass_fee_collection_updating_the_deposited_value

Likelihood: High, any transfer will trigger the bug. Impact: High, will update lpTokenDepositValue to the new current value without taking fees on profit.

Support

FAQs

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

Give us feedback!