이 페이지는 AI 자동 번역입니다. 모든 내용은 영문판을 기준으로 합니다.영문판 보기 →
이 페이지는 각 계정의 레이아웃과 역할을 설명합니다. 시드(seed)는 표준값이며
reference/program-addresses에 정리되어 있습니다. CLMM 풀은 CPMM 풀보다 계정 수가 많은데, 이는 유동성이 틱 범위 전체에 희소하게 저장되기 때문입니다. 이 희소성을 이해하는 것이 이 페이지의 핵심입니다.계정 목록
활성 CLMM 풀은 아래의 계정 패밀리로 구성됩니다. 두 개의 민트와 해당 볼트를 제외한 모든 계정은 CLMM 프로그램이 소유합니다.PoolState
풀의 라이브 상태로, 모든 스왑과 포지션 변경 시 읽힙니다.
sqrt_price_x64와tick_current는 풀의 가격 상태입니다. 모든 스왑 시 함께 업데이트됩니다.tick_current는log_{1.0001}(price)의 내림값입니다.liquidity는 활성 유동성으로,tick_current를 포함하는 범위를 가진 모든 포지션의L값 합계입니다. 스왑이 틱을 넘을 때마다, 그리고 포지션이 열리거나 닫히거나 크기가 변경될 때마다 변경됩니다.fee_growth_global_{0,1}_x64는 풀 전체 역사에 걸쳐 유동성 단위당 누적된 수수료입니다. 포지션은 이 값을 읽어 자신에게 귀속된 수수료를 계산합니다.tick_spacing은 초기화 시AmmConfig에 고정되며 이후 변경되지 않습니다. 포지션 엔드포인트로 허용되는 틱 인덱스를 결정합니다.tick_array_bitmap은 현재 가격 주변의 일반적인 틱 범위를 커버하는 인라인 비트맵입니다. 포지션이 이 범위를 벗어나는 경우 오버플로 추적은 별도의TickArrayBitmapExtension에서 관리됩니다.fee_on은 풀 생성 시 고정됩니다.0(FromInput)은 기존 Uniswap-V3 동작을 재현합니다.1과2는 스왑 수수료를 단일 측면으로 라우팅합니다 — 트레이드오프는products/clmm/fees를 참고하세요.dynamic_fee_info는 동적 수수료 서차지의 변동성 상태를 보유합니다. 활성화된 경우, 모든 스왑은AmmConfig.trade_fee_rate위에dynamic_fee_component를 재계산합니다. 레이아웃은 아래DynamicFeeInfo섹션에 문서화되어 있으며, 동적 수수료를 사용하지 않는 풀은 전체 구조체가 0입니다.
AmmConfig
GET https://api-v3.raydium.io/main/clmm-config에서 확인하세요):
protocol_fee_rate과 fund_fee_rate는 거래 수수료의 일부로, CPMM과 동일한 방식을 따릅니다. products/clmm/fees를 참고하세요.
TickArrayState
CLMM은 틱 하나당 단일 레코드를 저장하지 않습니다. 그렇게 하면 수십억 개의 계정이 필요하기 때문입니다. 대신 TICK_ARRAY_SIZE개의 연속 틱(프로그램 버전에 따라 일반적으로 60 또는 88개)을 하나의 TickArrayState로 묶어 첫 사용 시 지연 생성합니다.
order_phase는 코호트 ID입니다. 코호트가 “전량 미체결”에서 “부분 체결”로 전환될 때마다 증가합니다.orders_amount는 현재(최신) 코호트의 입력 토큰 합계입니다.part_filled_orders_remaining은 진행 중인 스왑에 의해 현재 체결되고 있는 이전 코호트를 추적합니다.unfilled_ratio_x64는 코호트에 적용되는 Q64.64 배수입니다. 스왑이 코호트의 X%를 체결하면 비율은(1 − X)를 곱합니다. 각 열린 주문은 열린 시점의 자체(order_phase, unfilled_ratio_x64)스냅샷을 저장하므로, 정산 수학은 스냅샷 비교로 단순화됩니다.
- 포지션 엔드포인트 틱 t는
t % tick_spacing == 0을 만족해야 합니다. 프로그램은 간격에 맞지 않는 포지션을 거부합니다. - 틱의 배열은
floor(t / (TICK_ARRAY_SIZE * tick_spacing)) * (TICK_ARRAY_SIZE * tick_spacing)에 위치합니다. - 틱 배열은 지연 초기화됩니다: 초기화되지 않은 배열에 처음 닿는 포지션 또는 스왑이 이를 생성하며 임대료를 납부합니다.
- 틱 배열은 프로그램에 의해 절대 닫히지 않습니다. 한번 할당되면 내부의 모든 틱이
liquidity_gross == 0으로 돌아가도 풀의 수명 동안 유지됩니다. 이후 포지션과 스왑은 추가 임대료 없이 기존 계정을 재사용합니다.ClosePosition기반의 틱 배열 정리 경로는 존재하지 않습니다.
TickArrayBitmapExtension
PoolState.tick_array_bitmap(인라인)은 “현재 가격 근처” 범위인 ±1,024개의 틱 배열을 커버합니다. 극단적인 틱 값 등 이 범위를 벗어나는 경우 프로그램은 확장 계정을 별도로 관리합니다:
(MIN_TICK, MAX_TICK))은 이 계정이 필요하며, SDK가 자동으로 처리합니다.
포지션
CLMM 포지션은 세 개의 계정과 민트로 구성된 번들입니다:Position NFT 민트
공급량 1의 SPL Token 민트입니다. 민트 주소는 결정론적 PDA이며, 소유자 지갑의 Position NFT는 해당 단일 토큰을 보유하는 ATA입니다. NFT를 전송하는 것이 포지션을 이전하는 방법입니다 — 프로그램은 상태에 저장된 Pubkey가 아닌 NFT ATA 잔액의 현재 보유자에게 권한을 부여합니다.PersonalPositionState
열린 포지션 하나당 하나. NFT 민트를 키로 사용합니다.
ProtocolPositionState (deprecated)
이전 CLMM 버전은
(pool, tick_lower, tick_upper) 조합별 집계 정보를 ProtocolPositionState PDA에 저장했습니다. 최신 버전에서는 이 계정을 생성하거나 읽지 않습니다. 해당 슬롯은 ABI 호환성을 위해 OpenPosition / IncreaseLiquidity / DecreaseLiquidity 계정 목록에 UncheckedAccount로 남아 있지만, 프로그램이 기록하지 않습니다. 온체인에 남아 있는 기존 계정은 잔재이며, 관리자는 CloseProtocolPosition을 호출해 임대료를 회수할 수 있습니다.집계 범위 정보는 이제 TickArrayState의 두 엔드포인트 틱(liquidity_gross, liquidity_net, 그리고 틱별 fee_growth_outside_* / reward_growths_outside_x64)에서 직접 유도됩니다. fee_growth_inside = global − outside_lower − outside_upper 공식은 집계 포지션 계정 없이도 계속 작동합니다.Observation
(tick_cumulative[t1] − tick_cumulative[t0]) / (t1 − t0)에서 구간의 기하 평균 가격을 계산한 후 price = 1.0001 ** tick을 적용합니다. algorithms/clmm-math를 참고하세요.
DynamicFeeConfig와 DynamicFeeInfo
동적 수수료 파라미터는 두 곳에 저장됩니다. 재사용 가능한 템플릿인 DynamicFeeConfig는 관리자가 관리하며 옵트인한 풀들이 공유합니다. 풀별 런타임 상태인 DynamicFeeInfo는 PoolState에 내장되어 모든 스왑 시 업데이트됩니다.
DynamicFeeConfig
["dynamic_fee_config", index.to_be_bytes()]. create_dynamic_fee_config(관리자 전용)로 생성하고 update_dynamic_fee_config로 수정합니다. enable_dynamic_fee = true로 생성된 풀은 생성 시점에 5개의 캘리브레이션 파라미터(filter_period, decay_period, reduction_factor, dynamic_fee_control, max_volatility_accumulator)를 자체 DynamicFeeInfo에 스냅샷으로 저장합니다. 이후 DynamicFeeConfig를 수정해도 기존 풀에는 소급 적용되지 않습니다.
DynamicFeeInfo (PoolState에 내장)
DynamicFeeConfig에서 복사된 캘리브레이션 값입니다. 수수료 수학과 감쇠 규칙은 products/clmm/math와 products/clmm/fees에 문서화되어 있습니다.
공식에서 사용되는 상수:
LimitOrderState
열린 지정가 주문 하나당 하나의 계정.
- Open — 사용자가
open_limit_order를 호출하여 입력 토큰의total_amount를 예치하면, 주문이TickState코호트에 바인딩됩니다. - (선택사항) Increase / Decrease —
increase_limit_order는total_amount에 추가하고,decrease_limit_order는 미체결 토큰(및 해당 시점까지 정산된 출력)을 반환합니다. - Settle — 코호트가 전체 또는 부분적으로 체결되면, 소유자 또는 운영 키퍼가
settle_limit_order를 호출하여 출력 토큰을 소유자의 ATA로 전송합니다. - Close —
unfilled_amount == 0이 되면 계정을 닫을 수 있습니다. 임대료는 항상owner에게 반환됩니다.
[owner.as_ref(), limit_order_nonce.key().as_ref(), limit_order_nonce.order_nonce.to_be_bytes().as_ref()]. 주문 PDA는 따라서 (owner, nonce_index, order_nonce) 조합마다 고유합니다.
LimitOrderNonce
(wallet, nonce_index) 쌍별 카운터로, 단일 사용자가 PDA 충돌 없이 여러 지정가 주문 파이프라인을 병렬로 운영할 수 있게 합니다.
[user_wallet.as_ref(), &[nonce_index]]. 대부분의 클라이언트는 nonce_index = 0을 사용하고 order_nonce로 카디널리티를 관리합니다.
핵심 계정 유도
reference/program-addresses를 통해 이중으로 확인하세요.
라이프사이클 빠른 참조
TickArrayState 계정은 프로그램에 의해 절대 닫히지 않습니다 — 풀의 수명 동안 유지됩니다. 틱 배열이 한번 초기화되면 내부의 모든 틱이 liquidity_gross == 0으로 돌아가도 온체인에 남아 있습니다. 기존 틱 배열을 재사용하는 것은 무료이며, 한번도 초기화되지 않은 배열에 처음 접근하는 포지션만 임대료를 납부합니다.
관련 문서 안내
- 틱 수학과 범위 메커니즘:
products/clmm/ticks-and-positions. - 스왑 워크와 수수료 성장 수학:
products/clmm/math. - 인스트럭션 계정 목록:
products/clmm/instructions. - 수수료 및 리워드 발생:
products/clmm/fees. - 표준 프로그램 ID와 시드:
reference/program-addresses.

