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

# 웹소켓을 통한 토큰 계정 (ATA) 필터링

> LaserStream WebSocket 스트림에서 tokenAccounts 필터를 사용해 wallet의 들어오는 SPL 토큰 전송을 포착합니다. plain accountInclude 필터가 놓치는 소유자 기반 매칭입니다.

[`transactionSubscribe`](/docs/ko/rpc/websocket/transaction-subscribe) 웹소켓 메서드의 `tokenAccounts` 필터는 \*\*wallet이 소유한 연관된 토큰 계정 (ATA)\*\*의 활동과 매칭할 수 있도록 구독을 허용합니다. 이는 wallet의 pubkey가 직접 나타나는 거래에만 매칭되는 것이 아닙니다. 동일한 필터는 gRPC에서도 사용할 수 있습니다 — gRPC 버전에 대해서는 [토큰 계정 (ATA) 필터링](/docs/ko/laserstream/token-account-filtering)을 참조하세요.

## 문제: 일반 계정 필터는 들어오는 토큰 전송을 놓칩니다

`accountInclude: [wallet]`으로 wallet을 관찰할 때, 해당 wallet pubkey가 거래의 계정 키에 나타나는 거래와만 매칭됩니다. 흔히 발생하는 경우가 있습니다: 누군가가 wallet에 SPL 토큰(예: USDC)을 보낼 때, 전송은 wallet의 **연관된 토큰 계정 (ATA)** — 별도의 프로그램 유도 주소 — 를 터치하며, 직접적으로 wallet pubkey에 나타나지 않습니다.

따라서 일반 `accountInclude: [wallet]` 구독은 들어오는 토큰 전송을 절대 볼 수 없습니다. 모든 ATA를 미리 나열하고 필터에 추가해야 할 것이지만, ATA는 수요에 따라 생성됩니다 (각 민트당 하나씩), 따라서 전체 세트를 사전에 알 수 없습니다.

## `tokenAccounts` 확장 작동 방식

구독 중 `tokenAccounts`을 설정하여 `accountInclude` wallet이 소유한 토큰 계정을 터치하는 거래와 **또한** 매칭하도록 확장합니다. 매칭은 **소유자 기반**입니다: LaserStream은 매칭 시점에 `accountInclude` 주소가 소유한 토큰 계정을 확인하므로, wallet이 소유한 모든 토큰 계정을 포착합니다 — 정규화되지 않은 계정을 포함하여 — 유도된 ATA 주소뿐만 아니라. 직접 ATA를 나열할 필요가 없습니다.

`tokenAccounts`을 생략한 구독은 이전과 동일하게 작동하므로 기존 필터에 추가해도 안전합니다.

## 확장 모드

`tokenAccounts`은 세 가지 문자열 값 중 하나를 가집니다.

| 값                  | 매칭                                           | 볼륨          | 사용 용도                                          |
| ------------------ | -------------------------------------------- | ----------- | ---------------------------------------------- |
| `"balanceChanged"` | 소유한 토큰 잔액이 실제로 변경되었거나 (또는 해당 토큰 계정이 닫힌) 거래   | 낮음 — 권장 기본값 | "실제로 자금이 이동되었을 때 알려줘" — wallet로의 입금, 인출, 스왑 처리 |
| `"all"`            | wallet이 소유한 토큰 계정을 참조하는 모든 거래, 잔액이 변경되지 않았어도 | 높음          | wallet의 토큰 계정을 터치하는 모든 것에 대한 전체 가시성            |
| `"none"`           | 확장 없음 — 필드를 생략한 것과 동일                        | —           | 기본값                                            |

`"balanceChanged"`으로 시작하세요. 이는 `"all"`의 볼륨의 일부에 대한 실제 자금 이동을 포착합니다.

## `transactionSubscribe`에서 사용하기

`tokenAccounts`는 표준 Solana WebSocket API에 대한 Helius 확장입니다. 잘못된 값을 사용하면 JSON-RPC 오류 `-32602`: `Invalid tokenAccounts value '<x>', expected one of: none, balanceChanged, all`이 반환됩니다.

```javascript theme={"system"}
const ws = new WebSocket('wss://mainnet.helius-rpc.com/?api-key=<API_KEY>');

ws.on('open', () => {
  ws.send(JSON.stringify({
    jsonrpc: '2.0',
    id: 1,
    method: 'transactionSubscribe',
    params: [
      {
        accountInclude: ['<WALLET_PUBKEY>'],
        tokenAccounts: 'balanceChanged' // also match the wallet's ATAs
      },
      { commitment: 'confirmed', encoding: 'jsonParsed', maxSupportedTransactionVersion: 0 }
    ]
  }));
  setInterval(() => ws.ping(), 30_000);
});

ws.on('message', (data) => {
  const msg = JSON.parse(data.toString());
  const result = msg.params?.result;
  if (!result) return;
  // Token balances this wallet owns that changed in the tx
  const owned = (result.transaction.meta.postTokenBalances || [])
    .filter((b) => b.owner === '<WALLET_PUBKEY>');
  console.log(result.signature, owned);
});
```

## 무엇이 매칭되었는지 읽기

ATA 확장을 통해 거래가 매칭되면, wallet의 토큰 이동은 거래의 `meta.postTokenBalances` 및 `meta.preTokenBalances`에 포함됩니다. 해당 항목들은 `owner`로 필터링하여 wallet이 실제로 소유한 잔액을 분리한 다음 동일한 `accountIndex`에서 `preTokenBalances`을 `postTokenBalances`와 비교하여 각 민트가 얼마나 이동했는지 확인하세요. 위의 예시는 필터링 단계를 보여줍니다.

## 관련 항목

<CardGroup cols={2}>
  <Card title="transactionSubscribe" icon="bolt" href="/docs/ko/rpc/websocket/transaction-subscribe">
    모든 `transactionSubscribe` 필터 및 옵션을 포함하여 `tokenAccounts`.
  </Card>

  <Card title="토큰 계정 필터링 (gRPC)" icon="coins" href="/docs/ko/laserstream/token-account-filtering">
    LaserStream gRPC 거래 필터에서 동일한 `tokenAccounts` 확장.
  </Card>

  <Card title="notifyOn 필터링" icon="filter" href="/docs/ko/rpc/websocket/notify-on-filtering">
    `accountSubscribe` 및 `programSubscribe`에서의 no-op 계정 업데이트 건너뛰기.
  </Card>

  <Card title="WebSocket 퀵스타트" icon="rocket" href="/docs/ko/rpc/websocket/quickstart">
    LaserStream WebSocket에 연결하고 첫 이벤트를 스트리밍합니다.
  </Card>
</CardGroup>
