sherlock-2025-04-burve-h06

[H-06] Fee Bypass in ValueFacet.removeValueSingle

보고서

Summary

출금 수수료를 계산하는 데 잘못된 변수를 이용하여 유저가 수수료를 지불하지 않고 출금할 수 있다.

Keyword

bug, arithmetic error, fee

Vulnerability

ValueFacet.removeValueSingle 함수를 호출하여 풀에서 출금을 할 때 수수료를 지불해야 한다. 수수료를 계산하기 위해 출금된 금액을 비율에 따라 계산해야 한다. 그런데 계산을 할 때 출금된 금액을 의미하는 변수인 realRemoved가 아니라 removedBalance를 이용한다. 이는 리턴값을 위해 정의된 변수로, 아직 초기화되지 않아 0으로 설정되어 있다. 따라서 realTax는 0으로 계산되고, 유저는 수수료를 지불하지 않으면서 출금할 수 있다.

function removeValueSingle(
    address recipient,
    uint16 _closureId,
    uint128 value,
    uint128 bgtValue,
    address token,
    uint128 minReceive
) external nonReentrant returns (uint256 removedBalance) {

    (uint256 removedNominal, uint256 nominalTax) = c.removeValueSingle(
        value,
        bgtValue,
        vid
    );
@>  uint256 realRemoved = AdjustorLib.toReal(token, removedNominal, false);
    Store.vertex(vid).withdraw(cid, realRemoved, false);
    // BUG: removedBalance is still zero here
    uint256 realTax = FullMath.mulDiv(
@>      removedBalance,
        nominalTax,
        removedNominal
    );
    c.addEarnings(vid, realTax);
@>  removedBalance = realRemoved - realTax;
    require(removedBalance >= minReceive, PastSlippageBounds());
    TransferHelper.safeTransfer(token, recipient, removedBalance);
}

Impact

유저가 수수료를 지불하지 않고 출금할 수 있다.

Mitigation

-    uint256 realTax = FullMath.mulDiv(
-        removedBalance,
-        nominalTax,
-        removedNominal
-    );
+    // Compute the real‐world fee based on the actual tokens removed
+    uint256 realTax = FullMath.mulDiv(
+        realRemoved,
+        nominalTax,
+        removedNominal
+    );

tags: bughunting, burve, smart contract, solidity, bug, arithmetic error, fee, severity high