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