> ## 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 트랜잭션의 구조, 작동 제한, 그리고 일반적인 스왑에서 발생하는 두 가지 수수료 범주(Solana 네트워크 수수료와 Raydium 프로토콜 수수료)에 대해 설명합니다.

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

  [영문판 보기 →](/solana-fundamentals/transactions-and-fees)
</Info>

<Info>
  Solana 트랜잭션은 원자적으로 실행되는 명령어 목록입니다. 트랜잭션 구조(명령어, 계정, 서명자, 컴퓨트 예산)를 이해하는 것은 Raydium으로 무엇을 구축하든 디버깅하든 최적화하든 필수입니다. 이 페이지에서는 그 구조, 제약 조건, 그리고 두 가지 수수료 범주(Solana 네트워크 수수료, Raydium 프로토콜 수수료)가 실제 스왑에서 어떻게 적용되는지 다룹니다.
</Info>

## 트랜잭션 구조

Solana 트랜잭션은 세 가지 핵심 구성요소로 이루어져 있습니다:

* **메시지**: 명령어의 순서 목록, 참조하는 계정, 최근 블록해시입니다.
* **서명**: 각 서명자마다 하나씩, 트랜잭션이 승인되었음을 증명합니다.
* **최근 블록해시**: 트랜잭션이 최근 것임을 증명합니다. 오래된 블록해시(150개 슬롯 이상 지난)를 가진 트랜잭션은 거부됩니다.

### 명령어

명령어는 다음을 지정합니다:

* `program_id` — 호출할 프로그램입니다.
* `accounts` — 프로그램이 접근할 수 있는 계정(그리고 쓰기 가능/서명자 플래그)입니다.
* `data` — 프로그램이 해석하는 불투명한 바이트입니다.

단일 트랜잭션에는 여러 명령어가 포함될 수 있습니다. 순서대로 실행되며, 하나가 실패하면 이전의 모든 명령어는 롤백됩니다(원자적).

일반적인 Raydium 스왑 트랜잭션에는 다음이 포함됩니다:

1. `ComputeBudget::SetComputeUnitLimit` — 기본 CU 한도를 높입니다.
2. `ComputeBudget::SetComputeUnitPrice` — 우선순위 수수료를 설정합니다.
3. 선택사항 `CreateAssociatedTokenAccount` — 사용자가 없으면 출력 ATA를 생성합니다.
4. `Raydium::SwapBaseInput` — 스왑을 실행합니다.
5. 선택사항 `CloseAccount` — 래핑된 SOL ATA를 닫습니다.

SDK는 `raydium.trade.swap()`을 통해 이를 자동으로 패킹합니다.

## 트랜잭션의 계정

트랜잭션의 모든 명령어가 터치하는 모든 계정은 트랜잭션의 계정 키 목록에 나열되어야 합니다. 각 계정에는 플래그가 지정됩니다:

* **서명자 / 비서명자**: 계정의 소유자가 트랜잭션에 서명해야 합니까?
* **쓰기 가능 / 읽기 전용**: 트랜잭션이 계정을 수정할 수 있습니까?

런타임은 이러한 플래그를 강제합니다. 프로그램이 쓰기 불가능한 계정에 쓰려고 하면 실패하고, 런타임은 필수 서명자가 없는 트랜잭션을 거부합니다.

CPMM 스왑의 경우 계정 목록에는 약 13개의 항목이 있습니다([`solana-fundamentals/account-model`](/ko/solana-fundamentals/account-model) 참조). 여러 틱 어레이 크로싱이 있는 CLMM 스왑은 20개 이상일 수 있습니다.

## 트랜잭션 크기 제한

Solana는 트랜잭션을 **1232바이트**로 제한합니다(서명, 메시지, 헤더 포함). 이는 복잡한 트랜잭션의 가장 일반적인 장애물입니다. Raydium의 CLMM 멀티홉 라우팅은 이 한계에 자주 도달합니다.

일반적인 약 1000바이트 Raydium 스왑의 분석:

| 구성요소                  | 크기           |
| --------------------- | ------------ |
| 서명                    | 64 B         |
| 서명 개수                 | 1 B          |
| 메시지 헤더                | 3 B          |
| 블록해시                  | 32 B         |
| 계정 키 (13 × 32 B)      | 416 B        |
| 명령어 (4 × \~100-150 B) | 400–600 B    |
| **합계**                | \~900–1100 B |

### 주소 조회 테이블 (ALTs)

ALT를 사용하면 트랜잭션이 전체 32바이트 공개 키 대신 게시된 테이블의 1바이트 인덱스로 계정을 참조할 수 있습니다. 이는 트랜잭션을 크게 압축합니다:

* 20개 계정을 직접 참조하는 트랜잭션: \~640 B의 공개 키.
* ALT를 사용하는 동일한 트랜잭션: \~20 B의 인덱스 + ALT 참조.

Raydium은 메인넷의 CPMM/CLMM 스왑 경로에 대한 ALT를 유지합니다. SDK는 이를 자동으로 사용합니다. 멀티홉 경로를 구축하는 어그리게이터는 이에 크게 의존합니다.

```ts theme={null}
import { VersionedTransaction } from "@solana/web3.js";

// SDK는 ALT 참조를 포함한 v0(버전화된) tx를 구축합니다
const { transaction } = await raydium.trade.swap({ /* ... */ });
// transaction은 VersionedTransaction이지, 레거시 Transaction이 아닙니다.
```

## 컴퓨트 예산

모든 트랜잭션에는 **컴퓨트 유닛(CU) 예산**이 있습니다. 초과하면 실행이 종료되고 트랜잭션이 실패합니다.

* **기본값**: 트랜잭션당 200,000 CU입니다.
* **최대값**: 트랜잭션당 1,400,000 CU입니다(`ComputeBudget::SetComputeUnitLimit`을 통해 상향 가능).
* **블록당 상한**: 블록당 48M CU(프로토콜 수준).

일반적인 Raydium CU 소비([`integration-guides/priority-fee-tuning`](/ko/integration-guides/priority-fee-tuning)의 전체 표 참조):

| 명령어                | CU        |
| ------------------ | --------- |
| CPMM 스왑            | \~140,000 |
| CLMM 스왑 (틱 크로싱 없음) | \~170,000 |
| CLMM 스왑 (4 틱 크로싱)  | \~320,000 |
| Farm v6 스테이크       | \~130,000 |
| CPMM 풀 생성          | \~250,000 |

항상 `ComputeBudget`을 통해 명시적 CU 한도를 설정하세요. 그렇지 않으면 기본값인 200k를 받게 되는데, 이는 대부분의 Raydium 명령어에는 너무 낮습니다.

```ts theme={null}
import { ComputeBudgetProgram } from "@solana/web3.js";

tx.add(
  ComputeBudgetProgram.setComputeUnitLimit({ units: 300_000 }),
);
```

CU 한도를 너무 낮게 설정하면 한도에 도달할 때 트랜잭션이 실패합니다. 너무 높게 설정하면 혼잡 상태에서 우선순위가 낮아질 수 있고(가격 책정 모델에 따라 사용하지 않은 컴퓨트에 대해 비용을 지불할 수 있습니다).

## 우선순위 수수료

기본 트랜잭션 수수료(서명당 5000 라모포트) 외에도, 검증자들은 점점 더 **우선순위 수수료**를 지불하는 트랜잭션을 우선순위화합니다: 마이크로라모포트 단위의 CU당 팁입니다.

```
priority_fee = compute_unit_price (micro-lamports) × compute_unit_limit
```

예: 10,000 µL/CU × 300,000 CU = 3,000,000 µL = 0.003 SOL.

우선순위 수수료는 로컬입니다. 블록 내 순서에만 영향을 미치며, 포함 가능성을 높이지는 않습니다. 혼잡 상태에서 합리적인 우선순위 수수료를 설정하는 것이 필수입니다.

```ts theme={null}
tx.add(
  ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 10_000 }),
);
```

동적으로 이를 조정하는 방법은 [`integration-guides/priority-fee-tuning`](/ko/integration-guides/priority-fee-tuning)을 참조하세요.

## 명령어 개수 및 계정 개수 제한

1232바이트 총 한도 외에도:

* **트랜잭션당 최대 계정**: 128입니다.
* **명령어당 최대 계정 (CPI)**: 64입니다.
* **트랜잭션당 최대 명령어**: 하드 한도는 없으며, 크기 한도로만 제한됩니다.
* **최대 CPI 깊이**: 4입니다(프로그램은 다른 프로그램을 호출할 수 있으며, 이는 4단계까지 중첩될 수 있습니다).

여러 틱 어레이를 크로싱하는 Raydium CLMM 스왑은 계정 한도에 강하게 도달할 수 있습니다. 단일 스왑은 풀, 입력/출력 보관소, 입력/출력 ATA, 여러 틱 어레이, 가능하면 전송 훅 프로그램의 추가 계정, 그리고 필수 컴퓨트 예산/시스템/토큰 프로그램 참조를 터치합니다. CPI를 통해 Raydium을 구성하는 설계(예: 자동 컴파운더)는 이를 고려해야 합니다.

## Raydium 스왑의 수수료 범주

사용자 스왑 트랜잭션은 두 가지 범주의 수수료를 지불합니다:

### Solana 네트워크 수수료

검증자에게 SOL로 지불됩니다.

* **기본 서명 수수료**: 서명당 5000 라모포트입니다. 거의 항상 1 서명 = 0.000005 SOL입니다.
* **우선순위 수수료**: CU 가격 × CU 한도(마이크로라모포트). 혼잡도에 따라 다릅니다. [`integration-guides/priority-fee-tuning`](/ko/integration-guides/priority-fee-tuning)을 참조하세요.

이 수수료는 검증자에게 지불되며, Raydium과 무관하며, 실패한 트랜잭션에도 부과됩니다(일부 우선순위 수수료 엣지 케이스 제외).

### Raydium 프로토콜 수수료

스왑 금액에서 공제됩니다.

* **스왑 수수료**: 입력의 백분율입니다(CPMM 일반적으로 0.25%, CLMM 등급당 0.01%–1%). LP와 프로토콜 목적지 사이에 분할됩니다. [`ray/protocol-fees`](/ko/ray/protocol-fees)를 참조하세요.

이 수수료는 Raydium 회계의 내부입니다. 사용자는 이를 무수수료 풀이 생성할 출력 금액보다 작은 출력 금액으로 봅니다.

### 예: CPMM 0.25% 등급을 통해 \$1000 USDC → SOL

| 수수료 범주                      | 금액                        | 수취 대상     |
| --------------------------- | ------------------------- | --------- |
| 기본 서명 수수료                   | 0.000005 SOL (\~\$0.0007) | 검증자       |
| 우선순위 수수료 (10k µL × 300k CU) | 0.003 SOL (\~\$0.45)      | 검증자       |
| CPMM 스왑 수수료 (0.25%)         | \$2.50                    | LP + 프로토콜 |
| **총 사용자 비용**                | \~\$2.95                  |           |

슬리피지(가격 영향 + 시장 변동)는 수수료가 아니지만 동일한 하단선에 영향을 미칩니다.

## 버전화된 트랜잭션

Solana에는 두 가지 트랜잭션 형식이 있습니다:

* **레거시**: 원본 형식, ALT 지원 없음.
* **v0 (버전화됨)**: ALT 지원, 향후 버전으로 확장 가능.

모든 최신 Solana 도구는 v0를 사용합니다. Raydium SDK는 기본적으로 v0 트랜잭션을 내보냅니다.

```ts theme={null}
// v0 tx를 직접 구축합니다
import { VersionedTransaction, TransactionMessage } from "@solana/web3.js";

const msg = new TransactionMessage({
  payerKey:        owner.publicKey,
  recentBlockhash: blockhash,
  instructions:    [ /* ... */ ],
}).compileToV0Message([lookupTableAccount]);

const tx = new VersionedTransaction(msg);
tx.sign([owner]);
```

## 블록해시 신선도

트랜잭션에는 최근 약 150개 슬롯(약 60초) 이내의 블록해시가 포함되어야 합니다. 그 범위를 넘어서면 검증자가 거부합니다.

재시도 루프의 경우 각 재시도마다 새 블록해시를 가져옵니다:

```ts theme={null}
async function sendWithRetry(tx, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash();
    tx.message.recentBlockhash = blockhash;
    tx.sign([owner]);
    try {
      return await connection.sendRawTransaction(tx.serialize());
    } catch (e) {
      if (i === maxRetries - 1) throw e;
    }
  }
}
```

우선순위 수수료 에스컬레이션 패턴을 사용한 완전한 재시도는 [`integration-guides/priority-fee-tuning`](/ko/integration-guides/priority-fee-tuning)을 참조하세요.

## 병렬 실행

Solana는 멀티코어 검증자에서 충돌하지 않는 트랜잭션을 병렬로 실행합니다. 두 트랜잭션이 동일한 계정에 쓰면 충돌합니다.

Raydium에 대한 함의:

* 동일한 풀의 두 스왑은 병렬로 실행될 수 없습니다. 둘 다 풀 상태에 씁니다.
* 풀 A의 스왑과 풀 B의 스왑은 계정 목록이 겹치지 않으면 병렬로 실행됩니다.
* 읽기 전용 트랜잭션은 동일한 계정에서 쓰기 프로그램을 절대 차단하지 않습니다(읽기 전용은 자신과 동시에 실행되지만 쓰기와는 동시에 실행되지 않음).

이것이 Solana가 단일 풀 직렬화에도 불구하고 높은 DEX 처리량을 유지할 수 있는 이유입니다.

## 트랜잭션 확인 수준

트랜잭션을 제출할 때 확인 수준을 선택합니다:

| 수준          | 대기       | 최종성                |
| ----------- | -------- | ------------------ |
| `processed` | \~400 ms | 최종화되지 않음. 롤백될 수 있음 |
| `confirmed` | \~1 s    | 과반 투표됨             |
| `finalized` | \~13 s   | 과반 루트됨             |

스왑 UX의 경우 `confirmed`가 표준입니다. 큰 가치를 처리하는 작업(풀 생성, 보상 충전)의 경우 `finalized`가 더 안전합니다.

```ts theme={null}
await connection.sendAndConfirmTransaction(tx, [owner], {
  commitment: "confirmed",
});
```

## 시뮬레이션

Solana는 제출하기 전에 트랜잭션을 시뮬레이션할 수 있습니다:

```ts theme={null}
const sim = await connection.simulateTransaction(tx);
console.log(sim.value.logs);
console.log(sim.value.unitsConsumed);
```

Raydium SDK는 `getBestSwapInfo`를 계산할 때 내부적으로 시뮬레이션을 사용하여 선택된 경로가 실제로 성공하는지 확인합니다. 시뮬레이션은 무료가 아닙니다. RPC 용량을 소비하지만 비용을 지불하기 전에 오류를 포착합니다.

## 참고 자료

* [`solana-fundamentals/account-model`](/ko/solana-fundamentals/account-model) — 트랜잭션의 계정.
* [`solana-fundamentals/pdas-and-cpis`](/ko/solana-fundamentals/pdas-and-cpis) — 프로그램이 서로를 호출하는 방법.
* [`integration-guides/priority-fee-tuning`](/ko/integration-guides/priority-fee-tuning) — CU 한도 및 우선순위 수수료 조정.
* [`ray/protocol-fees`](/ko/ray/protocol-fees) — Raydium 프로토콜 수수료 구조.

출처:

* [Solana Transaction docs](https://docs.solana.com/developing/programming-model/transactions).
* [Address Lookup Tables proposal](https://docs.solana.com/developing/lookup-tables).
* [Compute budget documentation](https://docs.solana.com/developing/programming-model/runtime).
