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

# getTokenAccountsByOwner 사용 방법

> getTokenAccountsByOwner 사용 사례, 코드 예제, 요청 매개변수, 응답 구조 및 팁을 학습합니다.

[`getTokenAccountsByOwner`](https://www.helius.dev/docs/api-reference/rpc/http/gettokenaccountsbyowner) RPC 메서드는 특정 공개 키가 소유한 모든 SPL [토큰 계정](https://www.helius.dev/blog/how-to-get-token-holders-on-solana)을 검색하는 데 사용됩니다. 이는 사용자의 토큰 보유를 표시하거나 다양한 토큰 계정과 상호 작용해야 하는 지갑 및 애플리케이션에 중요한 메서드입니다.

쿼리를 특정 토큰 `mint` 또는 `programId` (예: SPL 토큰 프로그램 또는 Token-2022 프로그램)으로 필터링해야 합니다.

광범위한 토큰 포트폴리오를 보유한 지갑의 경우 최대 10,000개의 계정을 요청당 구성 가능한 페이지 크기로 지원하는 커서 기반 페이지 매김을 제공하는 [`getTokenAccountsByOwnerV2`](/docs/ko/api-reference/rpc/http/gettokenaccountsbyownerv2)를 사용하는 것을 고려하십시오.

## 일반적인 사용 사례

* **사용자 포트폴리오 표시:** 주어진 사용자의 지갑 주소에 대한 모든 토큰 계정(따라서 잔액)을 가져와 전체 토큰 포트폴리오를 표시합니다.
* **애플리케이션 로직:** 전송이나 기타 상호작용을 시작하기 전에 특정 마인트에 대한 사용자의 특정 토큰 계정을 식별합니다.
* **검증:** 소유자가 특정 유형의 토큰에 대해 어떤 토큰 계정을 보유하고 있는지 확인합니다.
* **토큰 소유자 색인화:** 다른 방법보다 전역 색인화에 비효율적이지만, 알려진 소유자 집합을 위한 계정을 찾는 데 사용할 수 있습니다.

## 요청 매개변수

1. **`ownerPubkey`** (문자열, 필수): 검색하려는 계정 소유자의 base-58로 인코딩된 공개 키입니다.

2. **`filter`** (객체, 필수): `mint` 또는 `programId` 중 하나를 지정해야 하는 JSON 객체:
   * **`mint`** (문자열): 특정 토큰 마인트의 base-58로 인코딩된 공개 키입니다. 제공되면 `ownerPubkey`가 소유한 이 마인트에 대한 토큰 계정만 반환됩니다.
   * **`programId`** (문자열): 계정을 관리하는 토큰 프로그램의 base-58로 인코딩된 공개 키입니다. 일반적인 값은 다음과 같습니다:
     * SPL 토큰 프로그램: `TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA`
     * Token-2022 프로그램: `TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb`

3. **`options`** (객체, 선택적): 포함할 수 있는 선택적 구성 객체:
   * **`commitment`** (문자열, 선택적): [커밋먼트 레벨](https://www.helius.dev/blog/solana-commitment-levels)을 지정합니다.
   * **`encoding`** (문자열, 선택적): 계정 데이터의 인코딩. `"jsonParsed"`가 강력히 권장됩니다. 다른 옵션: `"base64"`, `"base64+zstd"`. 기본값은 `"base64"`입니다.
   * **`dataSlice`** (객체, 선택적): 계정 데이터의 특정 슬라이스를 검색합니다 (`offset`: usize, `length`: usize). `base58`, `base64`, `base64+zstd` 인코딩에만 해당됩니다.
   * **`minContextSlot`** (u64, 선택적): 쿼리의 최소 슬롯입니다.

## 응답 구조

JSON-RPC 응답의 `result.value` 필드는 객체 배열입니다. 각 객체는 `ownerPubkey`가 소유하고 `filter`와 일치하는 SPL 토큰 계정에 해당합니다.

`value` 배열의 각 객체는 다음을 포함합니다:

* **`pubkey`** (문자열): 토큰 계정 자체의 base-58로 인코딩된 공개 키.
* **`account`** (객체): 토큰 계정에 대한 자세한 정보:
  * **`lamports`** (u64): 임대 면제를 위한 Lamport 잔액.
  * **`owner`** (문자열): 소유 프로그램(예: 토큰 프로그램 공개 키).
  * **`data`**: 계정 데이터. `"jsonParsed"` 인코딩이 사용되면 다음을 포함합니다:
    * **`program`** (문자열): 예: `"spl-token"`.
    * **`parsed`**: 구조화된 정보를 가진 객체:
      * **`info`**: 다음과 같은 세부 사항 포함:
        * **`mint`** (문자열): 토큰의 마인트 주소.
        * **`owner`** (문자열): 토큰 계정의 소유자(요청의 `ownerPubkey`와 일치해야 합니다).
        * **`tokenAmount`** (객체): 토큰의 잔액 (`amount`, `decimals`, `uiAmount`, `uiAmountString`).
        * **`state`** (문자열): 토큰 계정의 상태 (예: `"initialized"`).
        * **`isNative`** (boolean): 계정이 래핑된 SOL을 보유하고 있는지 여부.
        * **`delegate`** (문자열, 선택적): 설정된 위임자 주소.
        * **`delegatedAmount`** (객체, 선택적): 위임자가 설정된 경우 위임된 금액.
      * **`type`** (문자열): 예: `"account"`.
  * **`executable`** (boolean): 계정이 실행 가능한지 여부.
  * **`rentEpoch`** (u64): 다음 에포크 임대가 만료되는 시점.
  * **`space`** (u64, `jsonParsed`가 아닌 경우): 바이트 단위의 원시 계정 데이터 길이.

**예제 응답 (`jsonParsed` 인코딩, `programId`로 필터링됨):**

```json theme={"system"}
{
  "jsonrpc": "2.0",
  "result": {
    "context": {
      "slot": 183459000
    },
    "value": [
      {
        "pubkey": "AssociatedTokenAccountPubkey1...",
        "account": {
          "data": {
            "program": "spl-token",
            "parsed": {
              "info": {
                "isNative": false,
                "mint": "SomeTokenMintPubkey...",
                "owner": "OwnerPubkeyProvidedInRequest...",
                "state": "initialized",
                "tokenAmount": {
                  "amount": "1000000000", // 1 token if decimals is 9
                  "decimals": 9,
                  "uiAmount": 1.0,
                  "uiAmountString": "1.0"
                }
              },
              "type": "account"
            },
            "space": 165
          },
          "executable": false,
          "lamports": 2039280,
          "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
          "rentEpoch": 380
        }
      },
      {
        "pubkey": "AnotherAssociatedTokenAccountPubkey...",
        "account": {
          // ... similar structure for another token owned by the same owner
        }
      }
    ]
  },
  "id": 1
}
```

## 코드 예제

<CodeGroup>
  ```bash cURL theme={"system"}
  # Replace <OWNER_PUBKEY> and <TOKEN_MINT_PUBKEY> or <TOKEN_PROGRAM_ID>

  # Example filtering by programId (SPL Token Program)
  curl -X POST -H "Content-Type: application/json" -d \
    '{
      "jsonrpc": "2.0",
      "id": 1,
      "method": "getTokenAccountsByOwner",
      "params": [
        "<OWNER_PUBKEY>",
        { "programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" },
        { "encoding": "jsonParsed" }
      ]
    }' \
    <YOUR_RPC_URL>

  # Example filtering by a specific mint
  curl -X POST -H "Content-Type: application/json" -d \
    '{
      "jsonrpc": "2.0",
      "id": 1,
      "method": "getTokenAccountsByOwner",
      "params": [
        "<OWNER_PUBKEY>",
        { "mint": "<SPECIFIC_TOKEN_MINT_PUBKEY>" },
        { "encoding": "jsonParsed", "commitment": "confirmed" }
      ]
    }' \
    <YOUR_RPC_URL>
  ```

  ```javascript JavaScript (using @solana/web3.js) theme={"system"}
  const { Connection, PublicKey } = require('@solana/web3.js');

  async function findOwnerTokenAccounts(ownerAddress, filter, encoding = 'jsonParsed') {
    // Replace with your RPC endpoint
    const connection = new Connection('https://mainnet.helius-rpc.com/?api-key=<api-key>');
    const ownerPubKey = new PublicKey(ownerAddress);

    try {
      let actualFilter;
      if (filter.mint) {
        actualFilter = { mint: new PublicKey(filter.mint) };
      } else if (filter.programId) {
        actualFilter = { programId: new PublicKey(filter.programId) };
      } else {
        console.error("Filter must contain either 'mint' or 'programId'");
        return;
      }

      const accounts = await connection.getTokenAccountsByOwner(
        ownerPubKey,
        actualFilter,
        { encoding }
      );

      console.log(`Found ${accounts.value.length} token accounts for owner ${ownerAddress}:`);
      accounts.value.forEach(accInfo => {
        console.log(`  Token Account: ${accInfo.pubkey.toBase58()}`);
        if (encoding === 'jsonParsed' && accInfo.account.data.parsed) {
          console.log(`    Mint: ${accInfo.account.data.parsed.info.mint}`);
          console.log(`    Balance: ${accInfo.account.data.parsed.info.tokenAmount.uiAmountString}`);
        }
        // console.log(JSON.stringify(accInfo, null, 2)); // For full details
      });

    } catch (error) {
      console.error(`Error fetching token accounts for owner ${ownerAddress}:`, error);
    }
  }

  // Replace with an actual owner's public key
  const exampleOwner = 'HXtBm8XZbxaTt41uqaKhwUAa6Z1aPyvJdsZVENiWsetg'; // Example wallet address

  // Example 1: Find all SPL Token Program accounts owned by `exampleOwner`
  findOwnerTokenAccounts(exampleOwner, { programId: 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA' });

  // Example 2: Find USDC token accounts owned by `exampleOwner`
  // const usdcMint = 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v';
  // findOwnerTokenAccounts(exampleOwner, { mint: usdcMint });

  // Example 3: Find Token-2022 Program accounts owned by `exampleOwner`
  // findOwnerTokenAccounts(exampleOwner, { programId: 'TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb' });
  ```
</CodeGroup>

## 개발자 팁

* **필터 필요:** 필터에서 `mint` 또는 `programId` 중 하나를 제공해야 합니다. 이러한 기본 필터 중 하나 없이 소유자의 모든 토큰 유형에 대한 모든 토큰 계정을 쿼리할 수 없습니다.
* **연관된 토큰 계정:** 이 메서드는 기본 연관된 토큰 계정(ATAs)과 그들이 소유할 수 있는 기타 SPL 토큰 계정(예: 이전 지갑 구현이나 커스텀 설정에서 온 계정)을 포함하여 공개 키가 소유한 모든 토큰 계정을 반환합니다.
* **인코딩:** `encoding` 옵션의 `"jsonParsed"` 사용을 강력히 권장합니다. 이는 이진 계정 데이터를 보다 사용하기 쉬운 JSON 구조로 해독합니다.
* **성능:** 소유자가 매우 많은 수의 토큰 계정을 보유한 경우(특히 `programId`로만 필터링할 때), 응답 크기가 클 수 있습니다. 이러한 경우에 대해 [`getTokenAccountsByOwnerV2`](/docs/ko/api-reference/rpc/http/gettokenaccountsbyownerv2)를 사용하여 내장된 페이지 매김 지원을 제공합니다.
* **Token-2022 (토큰 확장):** 전송 수수료, 이자 등과 같은 확장을 지원하는 Token-2022 프로그램을 사용하여 생성된 토큰으로 작업할 경우 올바른 `programId`: `TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb`을 사용하십시오.

이 가이드는 `getTokenAccountsByOwner` RPC 메서드에 대한 철저한 이해를 제공하여 Solana 주소에 대한 토큰 계정 정보를 효율적으로 검색할 수 있습니다.

## 대형 토큰 포트폴리오를 위한 페이지 매김

광범위한 토큰 보유를 가진 지갑의 경우 [`getTokenAccountsByOwnerV2`](/docs/ko/api-reference/rpc/http/gettokenaccountsbyownerv2)를 사용하십시오. 다음을 제공합니다:

* **커서 기반 페이지 매김**: `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: "getTokenAccountsByOwnerV2",
    params: [
      "9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM",
      { "programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" },
      {
        encoding: "jsonParsed",
        limit: 1000
      }
    ]
  })
});

const data = await response.json();
console.log(`Found ${data.result.value.length} token 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 token accounts available");
}
```

## 관련 메서드

<CardGroup cols={2}>
  <Card title="getTokenAccountsByOwnerV2" href="/docs/ko/api-reference/rpc/http/gettokenaccountsbyownerv2">
    대규모 포트폴리오를 위한 커서 기반 내비게이션을 갖춘 페이지 매김 버전
  </Card>

  <Card title="getTokenAccountBalance" href="/docs/ko/api-reference/rpc/http/gettokenaccountbalance">
    특정 토큰 계정의 잔액 가져오기
  </Card>
</CardGroup>
