> ## Documentation Index
> Fetch the complete documentation index at: https://www.helius.dev/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Solana 과거 계정 API (베타)

> Helius getHistoricalAccountInfo 및 getHistoricalTokenAccountsByOwner(베타)를 사용하여 과거의 모든 슬롯 또는 트랜잭션 시점에 해당하는 Solana 계정 상태를 읽습니다.

> [!NOTE]
>
> 과거 계정 상태 기능은 베타 버전입니다. 매개변수, 가격, 응답 형식 및 데이터 범위는 변경될 수 있습니다.

## 과거 계정 상태란 무엇인가요?

`getAccountInfo` 및 `getTokenAccountsByOwner` 같은 표준 Solana RPC 메서드는 계정의 현재 상태만 반환합니다. 검증자는 각 계정의 최신 버전만 유지하므로 쓰기가 발생할 때마다 이전 버전이 대체됩니다. 트랜잭션 기록으로도 이 공백을 메울 수 없습니다. `getTransaction` 및 `getBlock`는 프로그램이 쓴 계정 데이터가 아니라 명령어, 로그 및 잔액 변경 사항을 반환합니다.

Helius의 과거 계정 메서드는 과거 슬롯 시점 또는 해당 슬롯 내 특정 트랜잭션 직후의 계정을 반환합니다. 같은 슬롯의 두 트랜잭션 사이에서 상태를 읽을 수 있으므로 한 슬롯에서 계정이 여러 번 작성되더라도 특정 트랜잭션이 변경한 내용을 정확히 확인할 수 있습니다. 다음과 같은 용도로 사용하세요.

* 감사, 회계 또는 세금 신고를 위해 특정 시점의 지갑 토큰 잔액 확인
* 트랜잭션이 실행되기 직전과 직후에 접근한 계정을 읽어 트랜잭션 디버깅
* 원장을 직접 재실행하지 않고 과거 슬롯 시점의 풀, 볼트, 오라클 같은 프로토콜 계정 읽기

이 메서드는 Helius 전용 RPC 메서드이며 표준 Solana RPC에 포함되지 않습니다.

## 어떤 메서드를 사용해야 하나요?

| 필요한 항목 | 사용할 메서드 | 반환 값 |
| - | - | - |
| 과거 위치의 계정 하나 | [`getHistoricalAccountInfo`](https://www.helius.dev/docs/ko/api-reference/rpc/http/gethistoricalaccountinfo) | 계정이 존재하지 않았다면 `null`, 그렇지 않으면 해당 계정 |
| 과거 위치의 지갑 토큰 계정 | [`getHistoricalTokenAccountsByOwner`](https://www.helius.dev/docs/ko/api-reference/rpc/http/gethistoricaltokenaccountsbyowner) | SPL Token 및 Token-2022 계정 페이지. 선택적으로 하나의 민트로 제한 가능 |

두 메서드는 주소, 기록상 위치를 선택하는 쿼리 객체, 구성 객체라는 동일한 세 가지 매개변수를 사용합니다.

## 제공 여부 및 가격

* **플랜**: Business [플랜](https://www.helius.dev/docs/ko/billing/plans.md) 이상.
* **비용**: 베타 기간에는 호출당 0크레딧입니다(가격은 변경될 수 있음).
* **요청 속도 제한**: `getHistoricalAccountInfo`는 초당 100개의 요청을 허용하며 최대 버스트는 100입니다. `getHistoricalTokenAccountsByOwner`는 초당 10개의 요청을 허용하며 최대 버스트는 10입니다. 이 제한은 플랜의 RPC 요청 속도 제한과 별개이며, 이를 초과한 요청은 HTTP `429`을 반환합니다. [요청 속도 제한](https://www.helius.dev/docs/ko/billing/rate-limits.md)을 참조하세요.
* **네트워크**: 메인넷에서만 사용할 수 있습니다. 표준 메인넷 엔드포인트인 `https://mainnet.helius-rpc.com` 또는 [Gatekeeper](https://www.helius.dev/docs/ko/gatekeeper/overview.md) 엔드포인트인 `https://beta.helius-rpc.com`에서 호출하세요. 데브넷은 오류 `-32601`을 반환합니다.

## 데이터 범위

기록은 슬롯 444,959,999(2026년 9월 7일)부터 제공됩니다. 이는 에포크 1029의 마지막 슬롯이므로 에포크 1030 시작 시점의 상태를 보유합니다. 이전 슬롯에 대한 요청은 오류 `-32018`("계정 기록을 사용할 수 없음")을 반환합니다.

## 기록상 위치 선택

두 번째 매개변수는 두 개의 선택적 필드 `slot` 및 `transactionIndex`가 있는 쿼리 객체입니다.

| 쿼리 | 반환되는 상태 |
| - | - |
| 생략 또는 `{}` | 요청한 확정 수준을 상한으로 하는 최신 인덱싱 슬롯 시점 |
| `{ "slot": 445000000 }` | 모든 트랜잭션과 에포크 보상 같은 비트랜잭션 쓰기가 처리된 슬롯 445,000,000의 끝 시점 |
| `{ "slot": 445000000, "transactionIndex": 10 }` | 슬롯 445,000,000에서 인덱스 10인 트랜잭션이 실행된 직후 |

`transactionIndex`를 사용하려면 `slot`가 필요합니다.

에포크 보상 같은 비트랜잭션 쓰기는 슬롯 끝에 적용됩니다. `transactionIndex`가 있는 쿼리에는 슬롯의 마지막 트랜잭션을 지정하더라도 이러한 쓰기가 포함되지 않습니다. 이를 포함하려면 `transactionIndex` 없이 `slot`를 쿼리하세요.

### 트랜잭션 전후의 상태 읽기

트랜잭션이 변경한 내용을 확인하려면 계정을 두 번 읽으세요.

* **트랜잭션 이후**: 해당 트랜잭션 자체의 `slot` 및 `transactionIndex`를 쿼리합니다.
* **트랜잭션 이전**: 동일한 `slot`와 트랜잭션의 `transactionIndex`에서 1을 뺀 값을 쿼리합니다. 트랜잭션이 해당 슬롯의 첫 번째 트랜잭션(인덱스 0)이면 `transactionIndex` 없이 이전 슬롯을 쿼리합니다.

[`getTransactionsForAddress`](https://www.helius.dev/docs/ko/rpc/gettransactionsforaddress)는 모든 트랜잭션에 대한 `slot` 및 `transactionIndex`를 반환하므로, 여기에서 트랜잭션의 위치를 찾아 이 메서드에 바로 전달할 수 있습니다.

```bash theme={"system"}
# State of the account right after the transaction at index 10 in slot 445000000
curl https://mainnet.helius-rpc.com/?api-key=YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": "1",
    "method": "getHistoricalAccountInfo",
    "params": [
      "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
      { "slot": 445000000, "transactionIndex": 10 },
      { "encoding": "jsonParsed" }
    ]
  }'
```

## lastUpdatedAt 이해하기

반환되는 모든 계정에는 수신한 상태를 생성한 쓰기의 위치인 `lastUpdatedAt`가 포함됩니다.

```json theme={"system"}
"lastUpdatedAt": { "slot": 444999837, "transactionIndex": 700 }
```

* \*\*`slot` 및 `transactionIndex`\*\*는 쿼리한 위치 또는 그 이전의 마지막 쓰기를 가리킵니다. 위 예시에서는 슬롯 445,000,000에 대한 쿼리가 슬롯 444,999,837에서 인덱스 700인 트랜잭션이 마지막으로 쓴 상태를 반환했습니다.
* \*\*`transactionIndex: null`\*\*는 에포크 보상처럼 쓰기가 트랜잭션 외부에서 발생했다는 의미입니다.
* \*\*`transactionIndex: null`가 포함된 `slot: 444959999`\*\*는 기록 범위가 시작된 이후 계정이 변경되지 않았다는 의미입니다. 해당 슬롯에서 계정이 작성되었다는 의미는 아닙니다.

## null 값의 의미

쿼리한 위치에 계정이 존재하지 않았다면 `value`는 `null`입니다. 계정이 아직 생성되지 않았거나 이미 닫힌 경우입니다.

* **`null` 응답에는 `lastUpdatedAt`가 없습니다.** 따라서 계정이 생성되거나 닫힌 시점을 알 수 없습니다. 해당 트랜잭션을 찾으려면 [`getTransactionsForAddress`](https://www.helius.dev/docs/ko/rpc/gettransactionsforaddress)를 사용하세요.
* **존재한 적이 없는 주소**도 오류가 아닌 `null`를 반환합니다.
* **기록 범위보다 이전의 슬롯**은 계정 존재 여부와 관계없이 모든 주소에 대해 오류 `-32018`을 반환합니다.

## 계정 기록을 역순으로 탐색하기

`lastUpdatedAt`를 커서로 사용하여 계정이 가졌던 모든 상태를 최신순으로 나열하세요. 각 상태를 읽은 후 수신한 쓰기 직전의 위치를 쿼리합니다.

| 수신한 `lastUpdatedAt` | 다음 쿼리 |
| - | - |
| `{ "slot": S, "transactionIndex": N }`, 여기서 N은 0보다 큼 | `{ "slot": S, "transactionIndex": N - 1 }` |
| `{ "slot": S, "transactionIndex": 0 }` | `{ "slot": S - 1 }` |
| `{ "slot": S, "transactionIndex": null }` | `{ "slot": S - 1 }` |

`value`가 `null`이면 탐색을 중지하세요. 방금 지나온 쓰기에서 계정이 생성되었다는 의미입니다. 또한 `lastUpdatedAt.slot`가 기록 범위의 시작인 444,959,999에 도달해도 중지하세요.

```typescript theme={"system"}
const url = `https://mainnet.helius-rpc.com/?api-key=${process.env.HELIUS_API_KEY}`;
const COVERAGE_START_SLOT = 444959999;

type Position = { slot?: number; transactionIndex?: number };

async function getAccountHistory(address: string, start: Position = {}, maxStates = 100) {
  const states = [];
  let position = start;

  while (states.length < maxStates) {
    const response = await fetch(url, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        jsonrpc: "2.0",
        id: "1",
        method: "getHistoricalAccountInfo",
        params: [address, position, { encoding: "base64" }],
      }),
    });
    const { result, error } = await response.json();
    if (error) throw new Error(`${error.code}: ${error.message}`);

    const account = result.value;
    if (!account) break; // The account didn't exist before this write

    states.push(account);
    const { slot, transactionIndex } = account.lastUpdatedAt;
    if (slot <= COVERAGE_START_SLOT) break; // Reached the start of history coverage

    // Step to the position just before this write
    position = transactionIndex ? { slot, transactionIndex: transactionIndex - 1 } : { slot: slot - 1 };
  }

  return states; // Newest first
}
```

* **현재 닫힌 계정**은 최신 슬롯에서 `null`를 반환합니다. 계정이 아직 존재했던 시점의 `start` 위치를 전달하세요.
* **비트랜잭션 쓰기**는 이전 슬롯으로 이동합니다. 해당 슬롯의 앞부분에서 트랜잭션이 동일한 계정에 쓰기도 했다면 탐색 시 그 상태를 건너뜁니다.
* **시간순으로 탐색하려면** [`getTransactionsForAddress`](https://www.helius.dev/docs/ko/rpc/gettransactionsforaddress) 및 `sortOrder: "asc"`를 사용하여 계정의 트랜잭션을 오래된 순서대로 나열하세요. 그런 다음 각 트랜잭션의 `slot` 및 `transactionIndex`에서 상태를 읽습니다.

## 응답 컨텍스트

모든 응답의 `context.slot`는 Helius가 요청을 처리할 당시 인덱싱한 최신 슬롯입니다. 쿼리한 슬롯이 아닙니다. 수신한 데이터를 해석하려면 요청의 `slot` 또는 `lastUpdatedAt`를 사용하세요.

## 일관된 페이지네이션

`getHistoricalTokenAccountsByOwner`는 결과를 한 번에 한 페이지씩 반환합니다. 각 응답에는 `value.accounts` 및 `value.paginationKey`가 포함됩니다.

* **`paginationKey`를 다시 전달하여** 구성 객체에서 다음 페이지를 가져오세요.
* **`paginationKey`가 `null`일 때만 중지하세요.** 페이지가 짧거나 비어 있어도 뒤에 결과가 더 있을 수 있습니다.
* **모든 페이지에서 `slot`를 고정하세요.** `slot`를 생략하면 각 페이지가 최신 인덱싱 슬롯을 읽으므로 페이지마다 서로 다른 시점의 데이터가 반환될 수 있습니다.
* **`limit`를** 1\~5,000 사이로 설정하세요. 기본값은 5,000입니다.

## 인코딩 및 파싱된 데이터

* **지원되는 인코딩**은 `base64`(기본값), `base64+zstd` 및 `jsonParsed`입니다. `base58` 및 `binary`는 지원되지 않습니다.
* **`jsonParsed` 토큰 계정**은 쿼리한 위치 시점의 민트 소수 자릿수를 사용하므로 이후 민트가 변경되었더라도 수량이 정확합니다. 해당 위치에서 민트를 읽을 수 없으면 계정은 base64로 대체됩니다.
* \*\*`dataSlice`\*\*는 `getAccountInfo`에서와 동일하게 작동합니다.

## 확정 수준

`commitment`는 `finalized`(기본값) 및 `confirmed`를 허용합니다. `processed`는 지원되지 않습니다. 요청한 확정 수준에서 허용하는 것보다 새로운 `slot`는 오류 `-32004`을 반환합니다.

## 오류

| 코드 | 의미 | 해결 방법 |
| - | - | - |
| `-32018` | 슬롯이 기록 범위 시작보다 이전임 | 슬롯 444,959,999 이상을 쿼리하세요 |
| `-32004` | 슬롯이 요청한 확정 수준에서 허용하는 것보다 새로움 | `confirmed`를 사용하거나 더 오래된 슬롯을 쿼리하세요 |
| `-32602` | 잘못된 매개변수 | 오류 메시지에서 해당 필드를 확인하세요 |
| `-32601` | 메서드를 찾을 수 없음 | Helius 메인넷 또는 Gatekeeper 엔드포인트를 호출하세요. 과거 계정 메서드는 데브넷에서 사용할 수 없습니다 |

## 자주 묻는 질문

### 특정 슬롯에서 Solana 계정의 상태를 가져오려면 어떻게 해야 하나요?

주소 및 `{ "slot": S }`를 사용하여 `getHistoricalAccountInfo`를 호출하세요. 슬롯 S의 끝 시점에 해당하는 계정을 `getAccountInfo`와 동일한 형식으로 반환합니다.

### 같은 슬롯의 두 트랜잭션 사이에 있는 계정 상태를 읽을 수 있나요?

예. 쿼리에 `transactionIndex`를 추가하면 해당 트랜잭션이 실행된 직후의 계정 상태를 가져올 수 있습니다. [트랜잭션 전후의 상태 읽기](#트랜잭션-전후의-상태-읽기)를 참조하세요.

### 얼마나 오래된 기록까지 쿼리할 수 있나요?

기록은 2026년 9월 7일의 슬롯 444,959,999부터 시작합니다. 이전 슬롯은 오류 `-32018`을 반환합니다.

### 과거 계정 메서드가 포함된 플랜은 무엇인가요?

Business 플랜 이상입니다. 베타 기간에는 호출 비용이 0크레딧이며 가격은 변경될 수 있습니다. 이 메서드는 메인넷에서만 사용할 수 있습니다.

### 요청 속도 제한은 어떻게 되나요?

`getHistoricalAccountInfo`는 초당 100개의 요청을 허용하고, `getHistoricalTokenAccountsByOwner`는 초당 10개의 요청을 허용합니다. 두 제한 모두 플랜의 RPC 요청 속도 제한과 별개입니다. [제공 여부 및 가격](#제공-여부-및-가격)을 참조하세요.

### 계정의 모든 과거 상태를 가져오려면 어떻게 해야 하나요?

`lastUpdatedAt`를 사용하여 한 쓰기에서 이전 쓰기로 역순으로 이동하세요. [계정 기록을 역순으로 탐색하기](#계정-기록을-역순으로-탐색하기)를 참조하세요.

### 새로운 SDK가 필요한가요?

아니요. 이들은 JSON-RPC 메서드이므로 모든 HTTP 클라이언트를 사용할 수 있습니다. 표준 Solana 클라이언트 라이브러리에는 이 메서드가 포함되어 있지 않으므로 위 예시처럼 요청을 직접 보내세요.

## 다음 단계

> [card] [getHistoricalAccountInfo](https://www.helius.dev/docs/ko/api-reference/rpc/http/gethistoricalaccountinfo.md)
>
> 과거 슬롯 또는 트랜잭션 시점의 단일 계정을 읽습니다

> [card] [getHistoricalTokenAccountsByOwner](https://www.helius.dev/docs/ko/api-reference/rpc/http/gethistoricaltokenaccountsbyowner.md)
>
> 과거 슬롯 시점의 지갑 토큰 계정을 나열합니다

> [card] [getTransactionsForAddress](https://www.helius.dev/docs/ko/rpc/gettransactionsforaddress.md)
>
> 검사할 트랜잭션의 슬롯 및 transactionIndex를 찾습니다

> [card] [Historical data overview](https://www.helius.dev/docs/ko/rpc/historical-data.md)
>
> 트랜잭션 기록, 전송 및 기타 보관 메서드


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.