Documentation Index
Fetch the complete documentation index at: https://docs.raydium.io/llms.txt
Use this file to discover all available pages before exploring further.
이 페이지는 AI 자동 번역입니다. 모든 내용은 영문판을 기준으로 합니다.영문판 보기 →
이 페이지는 실제 동작하는 페이지입니다. CLMM 프로그램에서 사용하는 공식, 고정소수점 규칙, 단계별 로직을 다룹니다. 집중 유동성 곡선 자체의 원리 —
L = sqrt(x · y)가 중요한 이유 — 에 대해서는 algorithms/clmm-math를 참고하세요. 이 페이지는 해당 내용을 이미 읽었다고 가정합니다.스콰트-가격 표현
CLMM은 가격을sqrt_price_x64로 저장합니다. 이는 token1-per-token0 가격의 제곱근을 Q64.64 고정소수점 수로 나타낸 것입니다:
여기서 p = token1_amount / token0_amount입니다. p 대신 sqrt를 사용하면 스왑 수학이 선형화되어 (토큰 수량 변화가 Δsqrt_price에 대해 선형이 됨) 많은 틱을 거치는 스왑에서도 x64 고정소수점이 정밀도를 유지합니다.
틱 ↔ 스콰트-가격 변환은 비트-단위 로그 근사를 통해 사전에 계산됩니다:
이는 tick_math::get_sqrt_price_at_tick의 조회 기반 지수 연산으로 구현됩니다.
유동성을 정준 단위로
범위[sqrt_a, sqrt_b] 내 (sqrt_a < sqrt_b인) 유동성 L 포지션은 다음과 같이 토큰 수량으로 매핑됩니다. sqrt_c = sqrt_price_x64를 풀의 현재 가격이라 하면:
| 경우 | amount0 | amount1 |
|---|---|---|
sqrt_c <= sqrt_a (풀 가격이 범위 아래) | L · (sqrt_b - sqrt_a) / (sqrt_a · sqrt_b) | 0 |
sqrt_a < sqrt_c < sqrt_b (범위 내) | L · (sqrt_b - sqrt_c) / (sqrt_c · sqrt_b) | L · (sqrt_c - sqrt_a) |
sqrt_c >= sqrt_b (풀 가격이 범위 위) | 0 | L · (sqrt_b - sqrt_a) |
x = L / sqrt_p, y = L · sqrt_p에서 나옵니다.
통합자는 보통 역을 원합니다: amount0 / amount1 입금이 주어졌을 때 범위에 맞는 최대 L을 계산합니다. SDK의 LiquidityMath.getLiquidityFromTokenAmounts가 이를 수행합니다. 범위 내 경우의 공식:
어느 쪽이든 제약이 결정되면 실제로 소비되는 비율이 정해지고, 다른 쪽에는 남은 부분이 있을 수 있습니다.
단일 틱 스왑 스텝
스왑은 스텝으로 진행됩니다. 각 스텝은 (a) 현재 틱 범위 내의 모든 사용 가능한 입력을 소비하되 틱을 넘지 않거나, (b) 가격을 다음 초기화된 틱으로 정확히 이동시킵니다. 현재 상태(sqrt_c, L)과 상향 스왑 (token0 입력, token1 출력, sqrt_price 증가)이 주어졌을 때, 다음 초기화된 틱까지의 거리를 sqrt_t라 하면, 이 미세 구간 내에서 입력과 가격의 관계는:
그리고
프로그램은 다음 두 가지 중 하나를 수행합니다:
-
전체 입력이 들어맞나요? 남은 입력 (수수료 차감 후)이
sqrt_t에 도달하는Δamount0보다 적으면 새로운sqrt_c'를 정확히 풀어냅니다: (정확한 입력token0 → token1스왑의 경우). 스왑은 틱을 넘지 않고 이 스텝에서 완료됩니다. -
입력이
Δamount0을 초과하나요?sqrt_c' = sqrt_t로 설정하고, 틱을 넘으면서 (liquidity_net적용), 남은 입력을Δamount0만큼 감소시키고, 출력을Δamount1만큼 증가시킨 후 반복합니다.
token1 → token0, 가격 하향)의 경우 공식은 sqrt_c와 sqrt_t가 바뀌고 반전이 다른 슬롯에 있습니다.
전체 Rust 구현은 raydium-clmm/programs/amm/src/libraries/swap_math.rs에 있습니다. 그 로직은 Uniswap v3의 SwapMath.computeSwapStep과 일대일로 일치합니다.
각 스텝의 수수료
거래 수수료는 각 스텝의 입력 수량에서 차감됩니다. CPMM과 동일한 규칙입니다:L_i의 포지션은 나중에 L_i · Δfee_growth_global / 2^{64} 토큰을 받을 것으로 읽습니다.
프로토콜 및 펀드 부분은 각각 PoolState.protocol_fees_token_{0,1}과 PoolState.fund_fees_token_{0,1}에 누적되며, CPMM과 동일합니다. 이들은 CollectProtocolFee / CollectFundFee로 정산됩니다.
범위 내외 수수료 성장
CLMM 수수료 회계의 까다로운 부분: 포지션은 풀의 가격이 범위 내에 있는 동안에만 수수료를 얻습니다. 풀은 글로벌 누적 수수료를 추적하지만, 포지션은 특정 범위 내의 누적 수수료를 알아야 합니다. 해결책은 틱 기반 누적기입니다. 각 틱은 다음을 저장합니다:- 풀의 가격이 이 틱 위에 있으면 (
tick_current >= this_tick),fee_growth_outside = fee_growth_global입니다. (지금까지 벌어진 모든 것은 현재 가격 상대로 이 틱 “아래” 즉 “바깥”입니다.) - 그렇지 않으면
fee_growth_outside = 0입니다.
fee_growth_outside를 뒤집습니다:
이것이 유지하는 불변식: 모든 틱 t에 대해 fee_growth_outside(t)는 tick_current가 t의 반대쪽에 있던 동안 발생한 수수료와 같습니다.
범위 [tick_lower, tick_upper] 내의 수수료 성장은 다음과 같이 유도됩니다:
포지션이 저장하는 것과 읽는 것
PersonalPositionState는 fee_growth_inside_0_last_x64와 fee_growth_inside_1_last_x64를 저장합니다: 포지션을 마지막으로 건드렸을 때의 fee_growth_inside 값입니다.
그 후 건드릴 때마다 (증가, 감소, 수집), 프로그램은:
- 위 공식을 사용하여 현재
fee_growth_inside_{0,1}_x64를 계산합니다. Δ = fee_growth_inside_now − fee_growth_inside_last를 계산합니다 (u128에 대한 모듈로 뺄셈).Δ × position.liquidity / 2^{64}을tokens_fees_owed_{0,1}에 더합니다.fee_growth_inside_last를 새 값으로 업데이트합니다.
CollectFees / DecreaseLiquidity에서만, tokens_fees_owed를 상대로 합니다.
보상
풀의 최대 3개 보상 스트림은 각각의reward_growth_global_x64 누적기에서 동일한 범위-내 기계를 사용합니다. 발행 시간에:
— 발행이 활동 유동성에 반비례하므로, 더 높은 밀도의 풀은 각 포지션당 초당 비례적으로 적게 지급하지만, 더 많은 포지션 총수에 걸쳐 지급합니다. 포지션당 보상 미지급은
이며 CollectReward로 청구합니다. products/clmm/fees를 참고하세요.
작업 예: 정확한 입력 스왑
다음을 가정합니다:tick_spacing = 60sqrt_price_x64 = 1 × 2^{64}— 가격 = 1.0, 따라서tick_current = 0.- 활동 유동성
L = 1_000_000 × 2^{64}. - 위의 다음 초기화된 틱:
t = 60(sqrt_price_b ≈1.003004 × 2^{64}). - 거래 수수료율: 500 (0.05%).
SwapBaseInput.
스텝 1 — 수수료:
999 < 2995.5이므로 전체 입력이 틱을 넘지 않고 들어갑니다.
스텝 3 — 새로운 가격:
sqrt_c'이 sqrt_c 약간 아래입니다. 위의 공식은 token1 → token0 스왑용입니다. 여기 예는 token0 → token1이므로 가격을 위로 올립니다 — token0 입력에 대한 해당 형식을 사용합니다:
token0 → token1 스왑의 예상 방향과 일치합니다: 가격과 함께 sqrt_c가 올라갑니다.)
스텝 4 — 출력 수량:
trade_fee_rate × protocol_fee_rate / 1e6 (펀드도 유사함)로 LP, 프로토콜, 펀드 간에 분할됩니다; LP 부분은 fee_growth_global_0_x64로 흐릅니다.
스왑 중 리미트 오더 매칭
스왑 스텝이 열린 리미트 오더를 보유한 틱을 넘을 때, 그 오더들은 스왑 입력을 먼저 소비합니다 (LP 곡선보다 전), 틱의 정확한 가격으로. 매칭은order_phase 코호트별로 틱 내에서 FIFO입니다.
TickState의 코호트별 상태
orders_amount에 참여하고 다음 order_phase를 상속받습니다; 이전 코호트가 완전히 소비될 때까지 채울 수 없습니다.
매칭 스텝
스왑 중 각 틱 교차 시 발생하는 매칭의 의사-코드:SettleLimitOrder (또는 DecreaseLimitOrder)를 호출할 때까지 풀의 출력 금고에 가상으로 앉아있습니다. 풀은 단순히 unfilled_ratio_x64를 통해 코호트가 얼마나 채워졌는지 추적합니다. 각 LimitOrderState는 열린 시간에 자신의 (order_phase, unfilled_ratio_x64) 스냅샷을 저장하므로, 정산은:
LP 곡선과의 상호작용
스왑 스텝에서 리미트-오더 매칭은 틱 에서 일어나고 (영Δsqrt_price); LP 곡선 소비는 틱 사이에서 일어납니다. 따라서 순서는:
- 틱
t_cross교차 (LPliquidity_net변화를 먼저 적용합니다. Uniswap-V3이 이렇게 하기 때문). t_cross에 앉아있는 리미트 오더를 채웁니다.- 다음 초기화된 틱이나
swap_input소진까지 LP 곡선을 따라 계속합니다.
동적 수수료 파생
PoolState.dynamic_fee_info는 변동성 상태를 전달합니다. 각 스왑 스텝은 스텝당 수수료율을 다음과 같이 계산합니다:
여기서:
- —
DYNAMIC_FEE_CONTROL_DENOMINATOR - —
VOLATILITY_ACCUMULATOR_SCALE vol_acc는 아래 업데이트 규칙 후의 스텝당 누적기입니다tick_spacing은PoolState.tick_spacing에서 나옵니다
누적기 업데이트
매 스왑마다 두 규칙을 이 순서로 적용합니다: 감소. 참조 바닥은 마지막 업데이트 이후 시간에 따라 감소합니다: 누적. 새 누적기는 참조에 이전 참조 인덱스 이후 순회한 틱-거리를 더한 것입니다:tick_spacing_index_reference ()는 원시 틱이 아니라 틱-스펙 단위입니다: .
틱 거리에서 포물선인 이유
누적기를 제곱하면 수수료는 가격이 참조점에서 걸어간 거리의 제곱으로 올라갑니다. 경험상 이는 무작위 이동 압력 하에서 가격의 분산 스케일링과 일치합니다: 2× 틱 편차는 4× 암시된 변동성을 의미하므로 4× 할증을 부과합니다.dynamic_fee_control 파라미터는 절대 수준을 보정합니다.
filter_period 윈도우는 작은 소수점 이하 진동 (예: MEV 봇의 샌드위칭)이 누적기를 부풀리는 것을 방지합니다. decay_period 윈도우는 과거의 단일 스파이크가 시장이 진정된 후 무한정 수수료를 부과하는 것을 방지합니다.
수치 견고성
- 모든 중간 곱은
u128또는u256형태 산술을 통과합니다. CLMM은U128Sqrt헬퍼와FullMath::mulDiv패턴을 Uniswap v3에서 직접 이식합니다. - 나눗셈 반올림은 불변식
k' ≥ k를 로컬에서 시행하기 위해 스텝별로 선택됩니다.SwapBaseInput은 출력을 내림합니다;SwapBaseOutput은 입력을 올림합니다. PoolState.liquidity를 0으로 떨어뜨리는 틱 교차는 허용됩니다 (가격은 “유동성 구멍”을 통과할 수 있음) 하지만 스왑은 단순히 다음 초기화된 틱으로 진행하며 입력을 소비하지 않고 수수료를 부과하지 않습니다.- 오버플로우 가드:
sqrt_price_x64는 포함 범위[MIN_SQRT_PRICE_X64, MAX_SQRT_PRICE_X64]내에 유지됩니다.[MIN_TICK, MAX_TICK]에 해당합니다. 경계 중 하나를 넘을 스왑은SqrtPriceLimitOverflow로 되돌립니다.
다음에 갈 곳
products/clmm/ticks-and-positions틱 맵이 걸음에 어떻게 참여하는지.products/clmm/fees수학의 수수료/보상 쪽을 자세히.algorithms/clmm-mathL = sqrt(x · y)및 범위-대-유동성 공식 뒤의 유도.
raydium-io/raydium-clmm—libraries/swap_math.rs,libraries/tick_math.rs- “Uniswap v3 Core” 백서, §6–7


