Skip to content

Latest commit

 

History

History
76 lines (56 loc) · 2.78 KB

030.md

File metadata and controls

76 lines (56 loc) · 2.78 KB

Abundant Navy Kestrel

High

Vesting position fees are incorrectly collected, causing loss of funds for the protocol

Summary

Vesting position fees are incorrectly collected, causing loss of funds for the protocol

Root Cause

To get the vesting position fees, we have the following code:

        if (ongoingVestingPosition) {
            collectPositionFees(vestPosition.tickLower, mainPosition.tickUpper);
        }

The issue is that we incorrectly use mainPosition.tickUpper for the upper tick of the position. As this is not the correct vesting position, the fees from it will remain uncollected during the protocol fee calculations:

        if (ongoingVestingPosition) {
            collectPositionFees(vestPosition.tickLower, mainPosition.tickUpper);
        }

        (uint256 afterBal0, uint256 afterBal1) = idleBalances();

        uint256 protocolFees0 = ((afterBal0 - preBal0) * protocolFee) / 10_000;
        uint256 protocolFees1 = ((afterBal1 - preBal1) * protocolFee) / 10_000;

The fees will be collected during the _withdrawPartOfVestingPosition() call but protocol will lose out on their share of them, resulting in loss of funds for deadrosesxyz.

Internal Pre-conditions

  1. A rebalance has occurred after the vesting position has been set (check attack path to see why)

External Pre-conditions

No external pre-conditions

Attack Path

  1. Vesting position is added with the following ticks:
        vp.tickLower = mainPosition.tickLower;
        vp.tickUpper = mainPosition.tickUpper;
  1. Collecting fees will work normally if the state stays as is, the upper tick of the vesting position is the same as the one of the main position
  2. A rebalancing occurs where we change the position's tick boundaries based on the current tick:
        mainPosition.tickLower = tickBorder - halfWidth;
        mainPosition.tickUpper = tickBorder + halfWidth;
  1. Now, the vesting position and the main position do not share the same tick boundaries
  2. This will cause a loss of funds for the protocol as the fees of the vesting position won't be received here:
        uint256 protocolFees0 = ((afterBal0 - preBal0) * protocolFee) / 10_000;
        uint256 protocolFees1 = ((afterBal1 - preBal1) * protocolFee) / 10_000;
  1. We will get the vesting fees after, during the _withdrawPartOfVestingPosition() call, however protocol will not receive their part of those fees

Impact

Loss of funds for the protocol as they will miss out on the vesting position fees.

PoC

No response

Mitigation

        if (ongoingVestingPosition) {
+            collectPositionFees(vestPosition.tickLower, vestingPosition.tickUpper);
-            collectPositionFees(vestPosition.tickLower, mainPosition.tickUpper);
        }