sherlock-2025-04-burve-m05

[M-05] Invariant Breaking

보고서

Summary

addValue 함수에서 Closure.balances와 Closure.targetX128를 deMinimus 조건 확인 없이 비례적으로 증가시킨다. 이때 실제로 예치된 값과 목표 값 사이의 불균형 금액도 함께 증가한다. deMinimus 조건을 확인하지 않으므로 목표값과 실제값 사이의 차이가 범위 내인지 확인하지 않는다. 따라서 시스템의 중요한 조건(실제 값이 목표 값의 범위 내일 것)을 위반하게 만들 수 있다.

Keyword

arithmetic error, business logic vul, dex

Vulnerability

유저는 ValueFacet.addValue를 호출하여 클로저에 속한 모든 종류의 토큰을 제공하며 유동성을 제공할 수 있다. 현재 예치된 토큰의 비율과 동일한 비율로 토큰을 제공하므로 토큰의 비율은 유지된다.

이 함수는 내부적으로 Closure.addValue를 호출하여 Closure.balances 와 Closure.targetX128를 비례적으로 스케일링한다.

function addValue(  
    Closure storage self,
    uint256 value,
    uint256 bgtValue
) internal returns (uint256[MAX_TOKENS] memory requiredBalances) {
    trimAllBalances(self); 
@>  uint256 scaleX128 = FullMath.mulDivX256(
        value,
        self.n * self.targetX128, 
        true
    );
@>  uint256 valueX128 = value << 128;
@>  self.targetX128 +=
        valueX128 / self.n + ((valueX128 % self.n) > 0 ? 1 : 0);  
    self.valueStaked += value;
    self.bgtValueStaked += bgtValue;  
 
    for (uint8 i = 0; i < MAX_TOKENS; ++i) {
        if (!self.cid.contains(i)) continue;
@>      requiredBalances[i] = FullMath.mulX128(
            scaleX128,
            self.balances[i],
            true
        );
@>      self.setBalance(i, self.balances[i] + requiredBalances[i]); // Closure.balances 업데이트
    }
}

클로저가 이미 조금 불균형 상태일 때(목표 잔고와 불일치) 스케일링 하면 기존의 불일치를 더욱 증폭시킬 수 있다. 이는 클로저의 총 가치가 시스템이 정의한 범위를 넘게 하고, 해당 클로저를 더 이상 사용할 수 없게 할 수 있다.

먼저 기존의 토큰 가치(Value) 은 다음과 같다. e는 효율성 계수, x는 현재 토큰 잔고, t는 목표로 하는 잔고이다. 가치 계산 문서 참고

수학적으로 t와 x를 k배만큼 스케일링했을 때의 토큰 가치 는 다음과 같다. 토큰 가치가 k배로 선형적으로 스케일링되긴 했지만, 이는 기존의 불일치도 이에 비례하여 증폭되었음을 의미한다.

README 에 명시된 바에 따르면 시스템은 “클로저의 가치는 t * 클로저에 등록된 토큰 수 로부터 deMinimus * (클로저에 등록된 토큰 수) 보다 많이 벗어날 수 없다.” 라는 조건을 만족해야 한다(코드를 보면 README의 설명은 좀 불완전한 것 같다). 즉, |클로저 총가치 - 클로저 총 목표가치| <= deMinimus * n 라는 의미이다.

또한, multi/Value.sol#L169-L170를 참고하면 클로저 총 가치의 상한은 t * 클로저에 등록된 토큰 수 + targetSlippageX128 임을 알 수 있다.

즉, 클로저의 총 가치는 다음 공식을 만족해야 한다.

예를 들어 클로저에 A, B, C 토큰이 등록되어 있다고 하자.

초기: A 토큰과 B토큰은 목표 잔고만큼 있다. C 토큰은 목표 잔고 + targetSlippageX128 만큼이 있다. 즉, C 토큰에 약간의 불균형이 존재한다.

v(A) = v(B) = target
v(C) = target + targetSlippageX128

위 상태에서는 시스템 조건을 만족한다.

이후 유저가 addValue를 호출하여 모든 토큰의 양을 1.5배 하였다. 클로저에 예치된 각 토큰의 전체 가치는 1.5배 된다.

v(A) = v(B) = 1.5 * target
v(c) = 1.5 * (target + targetSlippageX128)

이로 인해 클로저의 전체 가치는 다음과 같이 변한다.

시스템 조건을 만족하려면 클로저의 전체 가치는 다음 값 사이에 있어야 한다. 하지만 위 값은 이 조건을 만족하지 못한다. 불일치가 있는 상태에서 동일 비율로 입금하기에, 기존의 targetSlippageX128 만큼의 불일치를 포함한 비율로 입금하고, 이로 인해 (비율은 유지하지만) 불일치하는 양은 증가하기 때문이다.

따라서 addValue는 와 사이의 차이를 증폭시켜 시스템 조건을 깨트릴 수 있다.

Impact

기존의 불일치를 조정하지 않고 addValue를 호출하면 중요한 시스템 조건이 깨질 수 있으며, 이로 인해 해당 클로저에서의 유동성 관련 작업이 작동하지 않을 수 있다.

Mitigation

addValue를 호출할 때, 즉 한 종류의 토큰으로 유동성을 제공하는 게 아니라 전 종류 토큰을 비율에 맞춰 입금할 때에도 t 함수를 사용하여 목표 값을 재계산해야 한다.


tags: bughunting, burve, smart contract, solidity, severity medium, arithmetic error, business-logic-vul, dex