> ## 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.

# 계정 모델

> Solana의 계정 중심 아키텍처 — 계정은 상태를 저장하고, 프로그램은 계정에 작동하는 상태 없는 코드입니다. 렌트, 소유권, 프로그램 계정 vs 데이터 계정, 그리고 Raydium의 풀 상태를 읽을 때 이 모든 것이 의미하는 바를 알아봅니다.

<Info>
  **이 페이지는 AI 자동 번역입니다. 모든 내용은 영문판을 기준으로 합니다.**

  [영문판 보기 →](/solana-fundamentals/account-model)
</Info>

<Info>
  Raydium의 코드를 읽기 전에 이해해야 할 가장 중요한 것은 Solana의 계정 모델입니다. Ethereum과 달리 Solana는 상태가 계약 코드와 함께 존재하지 않습니다. 대신 Solana 프로그램은 완전히 상태 없는 구조를 가지고 있습니다: 모든 상태는 별도의 "계정"에 살며, 프로그램이 이 계정들에 작동합니다. Raydium의 모든 풀, 포지션, 그리고 보관소는 계정입니다 — 이러한 계정들이 어떻게 작동하는지 이해하면 나머지 문서를 이해할 수 있습니다.
</Info>

## 기본 분리: 프로그램 vs 계정

### 프로그램

Solana의 **프로그램**은 실행 가능한 코드입니다 — 파일에서 로드되고 `Pubkey`에 배포되며 트랜잭션을 통해 호출될 수 있는 컴파일된 바이너리입니다. 프로그램에는 관련된 상태가 없습니다. 로직만 포함합니다.

Raydium의 프로그램:

* CPMM: `CPMMoo8L3F4NbTegBCKVNunggL7H1Zpdmwpwh8KMoZ0F`
* CLMM: `CAMMCzo5YL8w4VFF8KVHrK22GGUsp5VTaW7grrKgrWqK`
* AMM v4: `675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8`

각각은 고정된 바이너리입니다. 프로그램은 호출 사이에 아무것도 "기억하지" 않습니다.

### 계정

**계정**은 온체인의 데이터 행입니다. 모든 계정은 다음을 가집니다:

* `pubkey` — 주소입니다.
* `owner` — 계정을 소유한 프로그램입니다 (쓰기를 제어합니다).
* `data` — 원본 바이트입니다.
* `lamports` — SOL 잔액입니다 (1 SOL = 1,000,000,000 lamports).
* `rent_epoch` — 레거시 렌트 수금 필드입니다 (렌트 면제가 필수가 된 이후로는 무시됩니다).

Raydium 풀을 조회할 때, 하나 이상의 계정을 읽고 있습니다. 스왑이 실행될 때, CPMM 프로그램은 여러 계정을 읽고 씁니다 — 풀 상태, 보관소, 관찰 상태, 그리고 사용자의 토큰 계정입니다.

## 소유권

모든 계정은 정확히 한 프로그램에 의해 소유됩니다. 오직 그 프로그램의 코드만 계정의 `data` 필드를 수정할 수 있습니다. 사용자는 서명할 수 있는 계정에서 `lamports`를 수정할 수 있습니다 (SOL 전송/수신), 하지만 `data`를 수정하려면 소유자 프로그램이 대신 해야 합니다.

예시:

* 사용자 지갑: 시스템 프로그램에 의해 소유됩니다. Lamports가 여기에 있습니다. 서명하여 전송합니다.
* USDC 토큰 계정: SPL 토큰 프로그램에 의해 소유됩니다. 토큰 프로그램의 `transfer` 명령이 잔액을 업데이트합니다.
* Raydium 풀 상태 계정: CPMM 프로그램에 의해 소유됩니다. CPMM의 명령만 준비금, 수수료 등을 수정할 수 있습니다.
* Raydium 포지션 NFT의 `PersonalPositionState`: CLMM 프로그램에 의해 소유됩니다.

"소유"는 엄격합니다: 프로그램 A가 프로그램 B가 소유한 계정에 쓰려고 하면, Solana 런타임이 트랜잭션을 거부합니다.

## 렌트 및 렌트 면제

계정을 만드는 것은 저장소 공간을 소비합니다. Solana는 그 공간에 렌트를 청구합니다. 하지만 2020년 이후 모든 새 계정은 **렌트 면제** 상태여야 합니다 — 즉, 2년에 걸쳐 지불해야 할 렌트가 미리 지불된 충분한 lamports를 보유해야 합니다. 실제로:

* 렌트 면제 계정은 영구적으로 지속됩니다.
* 계정을 닫으면 lamports가 종료 서명자에게 반환됩니다.

165바이트 계정(예: SPL 토큰 계정)의 경우, 렌트 면제는 약 0.00204 SOL입니다. 1,440바이트 Raydium CPMM 풀 상태의 경우, 약 0.011 SOL입니다.

### Raydium 렌트 비용

| 계정                         | 크기        | 렌트          |
| -------------------------- | --------- | ----------- |
| CPMM PoolState             | \~1,440 B | \~0.011 SOL |
| CLMM PoolState             | \~1,500 B | \~0.012 SOL |
| CLMM TickArray             | \~9,000 B | \~0.063 SOL |
| CLMM PersonalPositionState | \~280 B   | \~0.003 SOL |
| ATA                        | 165 B     | \~0.002 SOL |
| Vault (Token Account)      | 165 B     | \~0.002 SOL |

풀 생성은 여러 계정의 렌트를 한 번에 필요로 합니다 — 이것이 CPMM 풀 생성이 총 약 0.15 SOL이 드는 이유입니다.

## 데이터 vs 실행 가능 계정

계정은 두 가지 유형으로 나뉩니다:

### 데이터 계정

상태를 보유합니다 (풀 준비금, 토큰 잔액, 사용자 포지션). `executable = false`. 대다수입니다.

### 실행 가능 계정

프로그램 바이트코드를 보유합니다. `executable = true`. 이들은 프로그램입니다 (CPMM, CLMM 등). 프로그램은 바이트코드 외에 데이터가 없습니다.

### 프로그램 파생 계정 (PDA)

PDA는 주소가 프로그램과 일부 시드에서 *결정론적으로 파생*된 데이터 계정입니다 — 이 주소에는 개인 키가 존재하지 않습니다. 오직 파생 프로그램만 `invoke_signed`를 통해 PDA를 대신하여 서명할 수 있습니다.

Raydium은 PDA를 광범위하게 사용합니다:

* 풀 상태 PDA: `[poolTypeDiscriminator, mintA, mintB, ammConfig]`에서 파생됩니다.
* 보관소 PDA: `[pool, mint]`에서 파생됩니다.
* 관찰 상태 PDA: `[observationSeed, pool]`에서 파생됩니다.

PDA를 사용하면 Raydium은 키를 관리하지 않고도 예측 가능한 주소에서 계정을 만들 수 있습니다. 누구나 알려진 풀의 시드가 주어지면 PDA 주소를 계산할 수 있습니다.

[`solana-fundamentals/pdas-and-cpis`](/ko/solana-fundamentals/pdas-and-cpis)를 참조하세요.

## 트랜잭션 및 계정 참조

모든 Solana 트랜잭션은 읽거나 쓸 계정의 명시적 목록을 포함합니다. 런타임은 다음을 강제합니다:

* 나열된 계정은 읽거나 쓸 수 있습니다 (`is_writable` 플래그에 따라).
* 나열되지 않은 계정은 건드릴 수 없습니다.

Raydium 스왑의 경우, 트랜잭션의 계정 목록은 다음을 포함합니다:

```
[readonly] CPMM program
[writable] pool state
[readonly] amm config
[readonly] pool authority (PDA)
[writable] input vault
[writable] output vault
[writable] user input ATA
[writable] user output ATA
[readonly] input mint
[readonly] output mint
[readonly] input token program
[readonly] output token program
[writable] observation state
[signer,writable] user
```

이 명시적 열거는 Solana 트랜잭션이 빠르고 병렬화 가능한 이유입니다 — 런타임이 미리 상충하지 않는 트랜잭션을 결정할 수 있습니다.

## 계정 크기 및 데이터 레이아웃

모든 Raydium 계정은 고정되거나 제한된 크기를 가집니다. 레이아웃은 코드에서 정의되며 (Rust 구조체와 `#[repr(C)]`), [`sdk-api/anchor-idl`](/ko/sdk-api/anchor-idl)에서 문서화됩니다.

Anchor 프로그램은 생성하는 모든 계정에 8바이트 **판별자**를 앞에 붙입니다. 이는 `hash("account:<StructName>")[0..8]`에서 파생됩니다. 이를 통해 클라이언트가 처음 8바이트를 읽는 것만으로 계정의 유형을 식별할 수 있습니다 — `getProgramAccounts` 스캔에서 한 유형의 모든 계정을 열거할 때 중요합니다.

### Raydium 풀 상태 읽기

SDK를 통해:

```ts theme={null}
const pool = await raydium.cpmm.getPoolInfoFromRpc({ poolId });
console.log(pool.poolInfo);
```

원본 RPC + 레이아웃을 통해:

```ts theme={null}
const accountInfo = await connection.getAccountInfo(poolId);
const data = accountInfo.data;
// 처음 8바이트(판별자)를 건너뛴 후, 구조체 레이아웃에 따라 파싱합니다.
const poolState = CpmmPoolStateLayout.decode(data.slice(8));
```

레이아웃은 SDK 소스의 `src/raydium/cpmm/layout.ts`에 있습니다.

## 작동 예시: 토큰 계정 읽기

사용자의 USDC 잔액을 읽어봅시다.

```ts theme={null}
import { Connection, PublicKey } from "@solana/web3.js";
import { getAssociatedTokenAddressSync, AccountLayout } from "@solana/spl-token";

const connection = new Connection("https://api.mainnet-beta.solana.com");
const user       = new PublicKey("YourUserWallet...");
const usdcMint   = new PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v");

// 1. ATA 주소를 계산합니다 (PDA 스타일 파생).
const ata = getAssociatedTokenAddressSync(usdcMint, user);

// 2. 계정을 읽습니다.
const accountInfo = await connection.getAccountInfo(ata);
if (!accountInfo) {
  console.log("ATA는 아직 존재하지 않습니다 (사용자가 USDC를 보유한 적이 없습니다).");
  return;
}

// 3. 소유자가 SPL 토큰 프로그램인지 확인합니다.
console.assert(accountInfo.owner.toBase58() === "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA");

// 4. 데이터를 디코딩합니다.
const parsed = AccountLayout.decode(accountInfo.data);
console.log("Balance (smallest units):", parsed.amount.toString());
console.log("Mint:",                     new PublicKey(parsed.mint).toBase58());
console.log("Owner:",                    new PublicKey(parsed.owner).toBase58());
```

이 패턴 — 주소 파생, 계정 가져오기, 소유자 확인, 디코딩 — Raydium 풀을 포함한 모든 온체인 읽기에 적용됩니다.

## Raydium에 이것이 중요한 이유

계정 모델은 Raydium의 설계를 형성합니다:

* **풀 상태는 단일 계정입니다** — 풀에 대한 모든 것 (민트, 준비금, 수수료, 관리자)이 풀 프로그램이 소유한 하나의 계정에 살고 있습니다.
* **LP 토큰은 표준 SPL 토큰 계정입니다** — Raydium은 토큰화를 SPL 토큰 프로그램에 위임합니다.
* **틱 배열은 청크로 나뉩니다** — CLMM은 계정이 고정 할당 크기를 가지기 때문에 확장 가능한 단일 틱 배열을 가질 수 없습니다. 대신, 청크된 `TickArray` PDA를 사용합니다.
* **포지션 NFT는 Metaplex NFT입니다** — CLMM 포지션은 Metaplex에 따른 표준 NFT입니다. 포지션 상태는 별도 PDA입니다.

이를 이해하면 "X는 어디에 있는가?"라는 질문을 올바르게 답할 수 있습니다:

* "풀 준비금은 어디에 있는가?" → 두 개의 보관소 계정 (토큰 계정)은 SPL 토큰 프로그램이 소유하며, 권한은 풀 프로그램의 PDA에 위임됩니다.
* "CLMM의 틱 데이터는 어디에 있는가?" → 일련의 TickArray PDA, 각각 60개의 연속 틱을 다룹니다.
* "내 팜 스테이크는 어디에 있는가?" → `[user, farmId]`에서 파생된 `UserLedger` PDA, 팜 프로그램이 소유합니다.

## 포인터

* [`solana-fundamentals/programs-and-anchor`](/ko/solana-fundamentals/programs-and-anchor) — 프로그램이 계정을 처리하는 방법입니다.
* [`solana-fundamentals/pdas-and-cpis`](/ko/solana-fundamentals/pdas-and-cpis) — PDA 파생 및 CPI입니다.
* [`solana-fundamentals/transactions-and-fees`](/ko/solana-fundamentals/transactions-and-fees) — 계정이 트랜잭션에서 참조되는 방법입니다.
* [`sdk-api/anchor-idl`](/ko/sdk-api/anchor-idl) — Raydium 프로그램의 계정 레이아웃입니다.

출처:

* [Solana Account docs](https://docs.solana.com/developing/programming-model/accounts).
* [SPL Token program](https://spl.solana.com/token) — 토큰 계정이 사는 곳입니다.
