비용 함수와 라운딩
참고: Signals CLMSR 백서 v1.0 -- §4-§8
이 장은 시그널스가 거래 가격을 어떻게 책정하고 왜 라운딩 규칙이 중요한지 설명합니다. 코드를 감사한다면 LazyMulSegmentTree.sol, FixedPointMath.sol을 함께 열어 보세요. 온체인 구현은 여기에서 소개하는 구조와 동일하게 맞춰져 있습니다.
모든 빈을 하나의 잠재함수로 관리
CLMSR은 틱 보유량 전부를 단일 볼록 잠재함수에 담습니다.
유동성 파라미터 는 WAD 값으로 저장되고, 지수 가중치 가 기울기를 결정합니다. 가격은
으로 계산되어 누적 확률이 항상 1이 되도록 보장합니다. 범위를 만큼 매수하면 해당 범위에 포함된 빈의 가중치가 배가 되고, 비용은 잠재함수 변화량으로 계산됩니다.
판매는 에 부호만 반대로 적용한 동일한 식을 사용합니다.
지수 계산을 안전하게 유지
지수 함수는 PRB-Math 한계를 지키기 위해 청크 단위로 평가합니다. 구현 상 각 입력은 MAX_EXP_INPUT_WAD = 1e18을 넘지 않도록 제한되며, 이는 사실상 (chunk/alpha) <= 1을 만족하게 만듭니다. lazy segment tree가 큰 거래를 자동으로 나누기 때문에 단일 호출이 정밀도나 가스 한도를 초과하지 않습니다.
Lazy 세그먼트 트리 구현
CLMSR은 모든 지수 가중치를 희소한 지연 곱 세그먼트 트리에 보관해 매 거래마다 모든 빈을 직접 만지지 않고도 정확한 가격을 유지합니다.
- 리프는 단일 빈의 가중치를 추적하며 기본값은 1(빈 포지션의 가중치)입니다. 내부 노드는 자식 합계를 캐시해 업데이트 이후에도 한 슬롯만 읽어서 값을 확보합니다.
applyRangeFactor는 목표 범위의 리프 전체를 곱하지만 경로상의 노드만 방문합니다. 지연 전파 덕분에 시장이 수백 개의 빈을 운영해도 쓰기와 읽기 모두 복잡도를 유지합니다.- 대기 중인 승수는 플러시 임계치까지 누적되며, 임계치를 넘으면 트리가 승수를 두 자식에게 내려보내고 부모 노드를 재설정해 수치 오차가 누적되지 않도록 합니다.
- 루트 합계는 변경이 일어날 때마다 갱신되어 가격 계산의 분모가 됩니다.
CLMSRMarketCore는 이 캐시 값을 사용해 견적과 이벤트를 즉시 산출합니다.
대규모 거래도 MAX_EXP_INPUT_WAD 보호를 따릅니다. CLMSRMarketCore가 거래를 안전한 청크로 나눠 각 트리 업데이트가 PRB-Math에 허용된 지수만 전달하도록 합니다.
비용 견적 단계에서는 코어 컨트랙트가 캐시된 루트(Σ_before)를 읽고 getRangeSum으로 영향을 받는 범위를 좁힌 뒤, _calculateTradeCostInternal과 _calculateSellProceeds가 청크별로 합계를 갱신해 로그가 항상 최신 상태를 반영하도록 합니다. 거래가 승인되면 _applyFactorChunked가 동일한 청크 분할 로직으로 트리를 갱신하고, 멀티플라이어마다 RangeFactorApplied 이벤트를 발행합니다. 이 흐름 덕분에 백서에서 요구하는 것처럼 범위 전체 가격이 동시에 갱신되면서도 온체인 연산량은 빈 수에 대해 준선형으로 유지됩니다.
비대칭 라운딩
백서는 액션별로 한 번만 변환을 허용하며 방향을 고정해 “공짜 거래” 가능성을 닫습니다.
| 액션 | 라운딩 방향 | 사용 함수 |
|---|---|---|
| 매수 / 증가 | 올림 | fromWadRoundUp |
| 매도 / 감소 / 종료 | 내림 | fromWadFloor |
| 정산 지급 | 내림 | fromWadFloor |
구현 현황: 매수는 이미 올림을 사용합니다. 판매와 지급은 현재 배포된 컨트랙트에서 아직 올림을 적용하지만, 백서와 일치하도록 내림으로 바꿀 예정입니다. 업데이트 이전까지는 실제 수령액이 향후 기대치보다 약간 높을 수 있으니 대시보드에서 안내해야 합니다.
최소 비용 보장
매수 시 올림과 최소 주문 크기 덕분에 모든 거래는 최소 1 마이크로 SUSD 이상을 차감합니다. 공격자는 무료 더스트 포지션을 남겨둘 수 없고, 감사자는 모든 포지션에 실질적인 위험이 걸려 있다고 가정할 수 있습니다.
코드에서 확인할 위치
LazyMulSegmentTree.sol이 청크 분할과 지수 가중치 업데이트를 구현합니다.FixedPointMath.sol에 라운딩 헬퍼(fromWadRoundUp,fromWadFloor)가 있습니다.- 단위 테스트가 라운딩 방향과 청크 분할 에지 케이스를 검증합니다.
이 루틴을 안전하게 유지하는 상수는 안전 한계와 파라미터 장에서 이어서 다룹니다.