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 about 1 year 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!