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

# getProgramAccounts 사용 방법

> getProgramAccounts 사용 사례, 코드 예제, 요청 매개변수, 응답 구조 그리고 팁을 학습하세요.

[`getProgramAccounts`](https://www.helius.dev/docs/api-reference/rpc/http/getprogramaccounts) RPC 메서드는 Solana 블록체인을 쿼리하기 위한 강력한 도구입니다. 특정 온체인 프로그램에 소유된 모든 계정을 검색할 수 있게 해줍니다. 이는 특정 토큰 민트에 관련된 사용자의 모든 토큰 계정을 찾는 것에서부터 분산 애플리케이션의 사용자별 데이터 계정을 발견하는 것에 이르기까지 다양한 응용 프로그램에 필수적입니다.

프로그램이 소유할 수 있는 계정의 수가 많을 수 있기 때문에, `getProgramAccounts`는 강력한 필터링 기능을 제공하여 검색 범위를 좁히고 필요한 데이터만 효율적으로 검색할 수 있도록 합니다.

아주 많은 프로그램 계정을 쿼리해야 하는 애플리케이션의 경우, 페이지 크기를 요청당 최대 10,000 계정으로 구성할 수 있는 커서 기반 페이징 지원을 제공하는 [`getProgramAccountsV2`](/docs/ko/api-reference/rpc/http/getprogramaccountsv2)를 사용하는 것을 고려하세요.

## 일반 사용 사례

* **특정 민트에 대한 모든 토큰 계정 찾기:** 특정 SPL 토큰의 모든 보유자를 찾습니다.
* **사용자별 데이터 검색:** 특정 사용자를 위한 프로그램이 생성한 모든 계정을 가져옵니다 (예: 사용자의 DeFi 프로토콜 내 포지션, 게임 상태 등).
* **커스텀 계정 유형의 모든 인스턴스 나열:** 프로그램이 특정 계정 구조를 정의한 경우, `getProgramAccounts`는 해당 구조의 모든 인스턴스를 찾을 수 있습니다.
* **프로그램 상태 모니터링:** 프로그램과 관련된 모든 계정을 관찰하여 프로그램의 전체 상태나 활동을 추적합니다.
* **탐색기 및 분석 도구 구축:** 프로그램과 그와 관련된 계정에 대한 데이터를 집계합니다.

## 요청 매개변수

1. **`programId`** (`string`, 필수):
   * 가져오려는 계정의 프로그램에 대한 base-58로 인코딩된 공개 키.
   * 예제: `"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"` (SPL Token Program의 경우).

2. **`options`** (`object`, 선택 가능): 다음 필드를 가진 구성 객체:
   * **`commitment`** (`string`): [커밋 수준](https://www.helius.dev/blog/solana-commitment-levels)을 지정합니다 (예: `"finalized"`, `"confirmed"`).
   * **`encoding`** (`string`): 반환된 각 계정 내의 `data` 필드에 대한 인코딩. 기본값은 `"base64"`입니다.
     * `"base58"`: 바이너리 데이터에 대한 느린 대안.
     * `"base64"`: 바이너리 데이터에 대한 표준 base64 인코딩.
     * `"base64+zstd"`: Base64 인코딩, zstd 압축 바이너리 데이터.
     * `"jsonParsed"`: RPC 노드에 프로그램의 계정 유형에 대한 파서가 있는 경우 (예: SPL Token, Stake), `data` 필드는 구조화된 JSON 객체가 됩니다. 가독성과 사용의 용이성을 위해 매우 권장됩니다.
   * **`filters`** (`array`): 계정에 적용할 필터 객체 배열입니다. 성능과 관련성에 중요합니다. 최대 4개의 필터를 사용할 수 있습니다. 일반적인 필터는 다음을 포함합니다:
     * **`dataSize`** (`object`):
       * `dataSize` (`u64`): 계정의 데이터 길이를 바이트 단위로 필터링합니다. 예제: `{ "dataSize": 165 }` (SPL Token 계정의 경우).
     * **`memcmp`** (`object`): 메모리 비교. 계정 데이터의 슬라이스를 제공된 바이트와 비교합니다.
       * `offset` (`usize`): 비교를 시작할 계정 데이터의 바이트 오프셋.
       * `bytes` (`string`): 일치시킬 바이트의 base-58로 인코딩된 문자열. 바이트 문자열은 129바이트 미만이어야 합니다.
       * 예제: 특정 민트에 대한 토큰 계정을 찾으려면 `memcmp`를 사용하여 `offset: 0` (토큰 계정에 민트 주소가 저장된 경우)와 `bytes`를 민트의 공개 키로 설정합니다.
   * **`dataSlice`** (`object`): 각 계정 데이터의 특정 슬라이스만 반환합니다. 큰 계정에서 부분 데이터만 필요할 때 유용합니다.
     * `offset` (`usize`): 슬라이싱 시작 바이트 오프셋.
     * `length` (`usize`): 반환할 바이트 수.
     * *참고: `dataSlice`는 주로 바이너리 인코딩에 사용되며, `jsonParsed`에 사용되지 않습니다.*
   * **`withContext`** (`boolean`): `true`인 경우, 응답은 `RpcResponse` 객체가 되어 `context` (`slot`와 함께)를 포함하고, `value` (계정 배열)를 포함합니다. `false`이거나 생략된 경우, 일반적으로 계정 배열만 반환합니다. 동작은 RPC 제공자마다 약간 다를 수 있습니다.
   * **`minContextSlot`** (`u64`): 요청을 평가할 수 있는 최소 슬롯.

## 응답 구조

응답은 각 객체가 발견된 계정을 나타내는 객체 배열이며 다음을 포함합니다:

* **`pubkey`** (`string`): 계정의 base-58로 인코딩된 공개 키.
* **`account`** (`object`):
  * `lamports` (`u64`): 램포트로 된 계정의 잔고.
  * `owner` (`string`): 이 계정을 소유한 프로그램의 base-58로 인코딩된 공개 키 (이를 쿼리한 `programId`).
  * `data` (`string`, `array`, 또는 `object`): `encoding` 매개변수에 따라 포맷된 계정 데이터.
    * `jsonParsed`의 경우: 역직렬화된 계정 상태를 나타내는 JSON 객체입니다.
    * `base64`의 경우: `["encoded_string", "base64"]` 배열입니다.
  * `executable` (`boolean`): 계정이 실행 가능한지 여부 (즉, 프로그램 자체인지 여부).
  * `rentEpoch` (`u64`): 이 계정이 다음 렌트로 갚아야 할 시기인 에포크.
  * `space` (`u64`, 선택 사항): 계정의 바이트 단위 데이터 길이. 데이터를 버퍼로 한 경우 `data.length`로 참조되거나 구문 구조의 일부일 수 있습니다.

`withContext: true`가 사용된 경우, 이 배열은 `value` 필드의 `RpcResponse` 객체에 중첩됩니다.

## 예제

### 1. 특정 민트(USDC)에 대한 모든 토큰 계정 찾기

이 예제는 USDC를 보유한 모든 SPL 토큰 계정을 찾습니다. `dataSize`를 사용하여 토큰 계정(165 바이트)을 필터링하고 `memcmp`를 사용하여 오프셋 0에서 USDC 민트 주소와 일치시킵니다.

<CodeGroup>
  ```bash cURL theme={"system"}
  # Replace <api-key> with your Helius API key
  # USDC Mint: EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v
  # Token Program ID: TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA
  curl https://mainnet.helius-rpc.com/?api-key=<api-key> -X POST -H "Content-Type: application/json" -d \
    '{
      "jsonrpc": "2.0",
      "id": 1,
      "method": "getProgramAccounts",
      "params": [
        "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
        {
          "encoding": "jsonParsed",
          "filters": [
            { "dataSize": 165 },
            {
              "memcmp": {
                "offset": 0, 
                "bytes": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"
              }
            }
          ]
        }
      ]
    }'
  ```

  ```javascript JavaScript (using @solana/web3.js) theme={"system"}
  // Replace <api-key> with your Helius API key
  const { Connection, PublicKey } = require('@solana/web3.js');
  const { TOKEN_PROGRAM_ID } = require('@solana/spl-token');

  const USDC_MINT_ADDRESS = 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v';

  async function findUsdcTokenAccounts() {
    const connection = new Connection('https://mainnet.helius-rpc.com/?api-key=<api-key>');

    try {
      const accounts = await connection.getProgramAccounts(TOKEN_PROGRAM_ID, {
        encoding: 'jsonParsed',
        filters: [
          {
            dataSize: 165, // Standard token account size
          },
          {
            memcmp: {
              offset: 0, // Offset for the mint address in a token account
              bytes: USDC_MINT_ADDRESS, // Base-58 encoded mint address
            },
          },
        ],
      });

      console.log(`Found ${accounts.length} USDC token accounts.`);
      accounts.forEach((accountInfo, index) => {
        console.log(`--- Account ${index + 1} ---`);
        console.log(`  Pubkey: ${accountInfo.pubkey.toBase58()}`);
        // Accessing parsed data
        const parsedData = accountInfo.account.data.parsed.info;
        console.log(`  Owner: ${parsedData.owner}`);
        console.log(`  Amount: ${parsedData.tokenAmount.uiAmountString}`);
      });
    } catch (error) {
      console.error('Error fetching USDC token accounts:', error);
    }
  }

  findUsdcTokenAccounts();
  ```
</CodeGroup>

### 2. 특정 지갑 소유의 모든 토큰 계정 찾기

이 예제는 특정 지갑 주소 소유의 모든 SPL 토큰 계정을 찾습니다. `dataSize` (165 바이트) 및 `memcmp`를 토큰 계정에 소유자 공개 키가 저장된 오프셋 32에 사용합니다.

<CodeGroup>
  ```bash cURL theme={"system"}
  # Replace <api-key> with your Helius API key
  # Example Wallet Address: Helioo21241PANoNdeG55722hgUnp2VawDgsz2g
  # Token Program ID: TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA
  curl https://mainnet.helius-rpc.com/?api-key=<api-key> -X POST -H "Content-Type: application/json" -d \
    '{
      "jsonrpc": "2.0",
      "id": 1,
      "method": "getProgramAccounts",
      "params": [
        "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
        {
          "encoding": "jsonParsed",
          "filters": [
            { "dataSize": 165 },
            {
              "memcmp": {
                "offset": 32, 
                "bytes": "Helioo21241PANoNdeG55722hgUnp2VawDgsz2g"
              }
            }
          ]
        }
      ]
    }'
  ```

  ```javascript JavaScript (using @solana/web3.js) theme={"system"}
  // Replace <api-key> with your Helius API key
  const { Connection, PublicKey } = require('@solana/web3.js');
  const { TOKEN_PROGRAM_ID } = require('@solana/spl-token');

  const TARGET_WALLET_ADDRESS = 'Helioo21241PANoNdeG55722hgUnp2VawDgsz2g';

  async function findWalletTokenAccounts() {
    const connection = new Connection('https://mainnet.helius-rpc.com/?api-key=<api-key>');

    try {
      const accounts = await connection.getProgramAccounts(TOKEN_PROGRAM_ID, {
        encoding: 'jsonParsed',
        filters: [
          {
            dataSize: 165, // Standard token account size
          },
          {
            memcmp: {
              offset: 32, // Offset for the owner address in a token account
              bytes: TARGET_WALLET_ADDRESS, // Base-58 encoded wallet address
            },
          },
        ],
      });

      console.log(`Found ${accounts.length} token accounts for wallet ${TARGET_WALLET_ADDRESS}.`);
      accounts.forEach((accountInfo, index) => {
        console.log(`--- Account ${index + 1} (${accountInfo.pubkey.toBase58()}) ---`);
        const parsedData = accountInfo.account.data.parsed.info;
        console.log(`  Mint: ${parsedData.mint}`);
        console.log(`  Amount: ${parsedData.tokenAmount.uiAmountString}`);
      });
    } catch (error) {
      console.error('Error fetching token accounts for wallet:', error);
    }
  }

  findWalletTokenAccounts();
  ```
</CodeGroup>

## 고급 필터링

필터를 사용하여 쿼리를 최적화하여 응답 크기를 줄이고 성능을 향상시키세요:

```typescript theme={"system"}
// Example filtering by memcmp (memory comparison)
const response = await fetch(
  "https://mainnet.helius-rpc.com/?api-key=YOUR_API_KEY",
  {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      jsonrpc: "2.0",
      id: "1",
      method: "getProgramAccounts",
      params: [
        "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", // Solana Token Program
        {
          encoding: "jsonParsed",
          filters: [
            {
              dataSize: 165, // Size of token account data
            },
            {
              memcmp: {
                offset: 32, // Location of owner address in the token account
                bytes: "83astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDLVcri",
              },
            },
          ],
        },
      ],
    }),
  }
);
const data = await response.json();
console.log("Filtered program accounts data:", data);
```

<Card title="API Reference" horizontal icon="code" href="/docs/ko/api-reference/rpc/http/getprogramaccounts">
  getProgramAccounts
</Card>

### 필터 유형

* `memcmp`: 주어진 오프셋에서 특정 패턴과 일치하는 계정을 필터 처리합니다
* `dataSize`: 정확한 데이터 크기로 계정을 필터 처리합니다
* 다중 필터: 모든 조건을 만족해야 합니다 (논리적 AND)

## 개발자 팁

* **성능:** `getProgramAccounts`는 특히 필터가 없거나 많은 계정을 가진 프로그램인 경우 RPC 노드에서 리소스를 많이 소모할 수 있습니다. 항상 필터 (`dataSize`, `memcmp`) 및 가능한 경우 `dataSlice`를 사용하여 쿼리 범위와 응답 크기를 줄이세요.
* **큰 결과 집합:** 많은 결과를 반환하는 쿼리의 경우 응답이 잘리거나 시간 초과될 수 있습니다. 범위를 줄이기 위해 필터링을 사용하거나, 페이지 매김 지원을 위해 [`getProgramAccountsV2`](/docs/ko/api-reference/rpc/http/getprogramaccountsv2)를 고려하세요.
* **속도 제한:** RPC 제공자의 속도 제한을 주의하세요. 잦거나 무거운 `getProgramAccounts` 호출이 이러한 한도를 초과할 수 있습니다.
* **데이터 레이아웃 지식:** `memcmp`를 효과적으로 사용하려면 쿼리하는 계정 데이터의 바이트 레이아웃을 이해해야 합니다.
* **`jsonParsed` 가용성:** `jsonParsed` 인코딩은 특정 프로그램의 계정 유형에 대한 파서가 RPC 노드에 있는지에 따라 달라집니다. SPL 토큰과 같은 일반 프로그램에는 널리 지원됩니다.

`getProgramAccounts`는 프로그램이 소유한 계정 집합을 쿼리하고 상호 작용해야 하는 개발자에게 필수적인 메서드입니다. 필터링 옵션을 숙달하는 것이 효율적이고 견고한 Solana 애플리케이션을 구축하는 열쇠입니다.

## 대량 데이터셋에 대한 페이지 매김

많은 수의 계정을 소유한 프로그램을 다루는 애플리케이션의 경우, [`getProgramAccountsV2`](/docs/ko/api-reference/rpc/http/getprogramaccountsv2) 사용을 고려하세요. 이는 다음을 제공합니다:

* **커서 기반 페이지 매김**: `limit` (1-10,000)를 설정하고 `paginationKey`를 사용하여 결과를 탐색합니다
* **증분 업데이트**: 특정 슬롯 이후에 수정된 계정만 가져오려면 `changedSinceSlot`를 사용합니다
* **베터 퍼포먼스**: 시간 초과를 방지하고 메모리 사용량을 줄입니다
* **페이지 매김 동작**: 페이지 매김의 끝은 계정이 반환되지 않을 때만 표시됩니다. 필터링으로 인해 제한보다 적은 계정이 반환될 수 있습니다 - `paginationKey`가 null일 때까지 페이지 매김을 계속합니다.

```typescript theme={"system"}
// Example: Paginated query for all token accounts
const response = await fetch("https://mainnet.helius-rpc.com/?api-key=YOUR_API_KEY", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    jsonrpc: "2.0",
    id: "1",
    method: "getProgramAccountsV2",
    params: [
      "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
      {
        encoding: "base64",
        filters: [{ dataSize: 165 }],
        limit: 5000
      }
    ]
  })
});

const data = await response.json();
console.log(`Found ${data.result.accounts.length} accounts`);
if (data.result.paginationKey) {
  console.log("More results available, use paginationKey for next page");
  // Continue pagination even if fewer than limit accounts were returned
} else {
  console.log("End of pagination - no more accounts available");
}
```

## 관련 메서드

<CardGroup cols={2}>
  <Card title="getProgramAccountsV2" href="/docs/ko/api-reference/rpc/http/getprogramaccountsv2">
    대량 데이터를 위한 커서 기반 탐색이 포함된 페이지네이션 버전
  </Card>
</CardGroup>
