> ## 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) フィルタリング

> トークンアカウント (ATA) 拡張を使用して、LaserStream gRPC および WebSocket ストリームでウォレットの受信 SPL トークン転送をキャッチします。これは、単なる accountInclude フィルターでは見逃されてしまう、所有者ベースのマッチングです。

LaserStream の `tokenAccounts` フィルターは、ウォレットが所有する**関連トークンアカウント (ATA)** の活動にマッチするトランザクションサブスクリプションを可能にし、ウォレットの公開鍵が直接表示されるトランザクションだけでなく、[LaserStream gRPC](/ja/laserstream/grpc) と [LaserStream WSS](/ja/rpc/websocket/transaction-subscribe) の両方で同様に機能します。

## 問題: 単純なアカウントフィルターは受信トークン転送を見逃す

`accountInclude: [wallet]` でウォレットを監視すると、そのウォレットの公開鍵がトランザクションのアカウントキーに表示されるトランザクションにしかマッチしません。よくあるケースでは、誰かがウォレットに SPL トークン（たとえば USDC）を送信したとき、その転送はウォレットの**関連トークンアカウント (ATA)** — 別のプログラムによって導出されたアドレス — に触れ、ウォレットの公開鍵自体には触れません。

したがって、単純な `accountInclude: [wallet]` サブスクリプションは受信トークン転送をキャッチしません。ウォレットが所有するすべての ATA を事前に列挙し、各アカウントをフィルターに追加しなければなりませんが、ATA は需要に応じて作成される（一つのミントごとに一つ）ため、事前に完全なセットを知ることはできません。

## `tokenAccounts` 拡張の仕組み

トランザクションフィルターに `tokenAccounts` を設定することで、`accountInclude` ウォレットが所有するトークンアカウントに触れるトランザクションにもマッチするように拡張します。このマッチングは**所有者ベース**で行われます: LaserStream はマッチ時にあなたの `accountInclude` アドレスによって所有されるトークンアカウントを解決し、ウォレットが所有する任意のトークンアカウントをキャッチします — 通常のものだけでなく、導出された ATA アドレスも含みます。あなた自身で ATA をリストする必要はありません。

`tokenAccounts` を省略したサブスクリプションは以前と全く同じ動作をしますので、既存のフィルターに追加しても安全です。

## 拡張モード

`tokenAccounts` は三つの文字列値のいずれかを取ります:

| 値                  | マッチする                                          | ボリューム          | 使用目的                                   |
| ------------------ | ---------------------------------------------- | -------------- | -------------------------------------- |
| `"balanceChanged"` | 所有するトークン残高が実際に変わった（またはトークンアカウントが閉じられた）トランザクション | 少ない — 推奨のデフォルト | 実際にお金が動いたときに通知 — 入金、出金、ウォレットに決済されるスワップ |
| `"all"`            | ウォレットが所有するトークンアカウントを参照するトランザクション（残高が変わらなくても）   | 多い             | ウォレットのトークンアカウントに触れる何かも完全に把握            |
| `"none"`           | 拡張なし — フィールドを省略した状態と同じ                         | —              | デフォルト                                  |

まず `"balanceChanged"` を使用します。これは `"all"` のボリュームのごく一部で資金の実際の移動をキャプチャします。

## LaserStream gRPC で使用する

`SubscribeRequest` のトランザクションフィルターに `tokenAccounts` を追加します。[Helius LaserStream SDK](/ja/laserstream/clients) はこの文字列をワイヤーレベルの `TokenAccountExpansionControlFlag` enum に変換します（`yellowstone-grpc-proto` 12.5.0+ の一部）。

```typescript theme={"system"}
import { subscribe, CommitmentLevel, LaserstreamConfig, SubscribeRequest } from 'helius-laserstream';
import bs58 from 'bs58';

const wallet = '<WALLET_PUBKEY>';

const subscriptionRequest: SubscribeRequest = {
  transactions: {
    "wallet-activity": {
      accountInclude: [wallet],
      accountExclude: [],
      accountRequired: [],
      vote: false,
      failed: false,
      tokenAccounts: "balanceChanged" // also match the wallet's ATAs
    }
  },
  commitment: CommitmentLevel.CONFIRMED,
  accounts: {}, slots: {}, transactionsStatus: {},
  blocks: {}, blocksMeta: {}, entry: {}, accountsDataSlice: [],
};

const config: LaserstreamConfig = {
  apiKey: 'YOUR_API_KEY',
  endpoint: 'https://laserstream-mainnet-ewr.helius-rpc.com',
};

await subscribe(config, subscriptionRequest, async (data) => {
  if (!data.transaction?.transaction) return;
  const tx = data.transaction.transaction;
  // Token balances this wallet owns that changed in the tx
  const owned = (tx.meta?.postTokenBalances || []).filter((b: any) => b.owner === wallet);
  console.log(bs58.encode(tx.signature), owned);
}, async (error) => {
  console.error('Stream error:', error);
});
```

完全な例（事前および事後のバランスを差分化）については [トランザクション監視ガイド](/ja/laserstream/guides/transaction-monitoring) を参照してください。すべてのトランザクションフィルターフィールドについては [Subscribe Request リファレンス](/ja/laserstream/grpc) を参照してください。

## LaserStream WebSocket で使用する

同じフィールドは [`transactionSubscribe`](/ja/rpc/websocket/transaction-subscribe) WebSocket メソッドで利用可能です — 標準 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 拡張によってマッチすると、そのウォレットのトークン動作はトランザクションの `meta.postTokenBalances` と `meta.preTokenBalances` に記録されます。これらのエントリを `owner` でフィルタリングしてウォレットが実際に所有している残高を特定し、同じ `accountIndex` 上で `preTokenBalances` を `postTokenBalances` と比較し、各ミントがどれだけ動いたかを確認します。上記の例はフィルタリングステップを示し、[トランザクション監視ガイド](/ja/laserstream/guides/transaction-monitoring#example-4-watch-a-wallet-incl-token-transfers) は全体の差分を示します。

## 関連

<CardGroup cols={2}>
  <Card title="トランザクションモニタリング" icon="receipt" href="/ja/laserstream/guides/transaction-monitoring">
    完全なフィルタリング戦略と gRPC 経由の実行可能なウォレットウォッチの例。
  </Card>

  <Card title="transactionSubscribe (WebSocket)" icon="bolt" href="/ja/rpc/websocket/transaction-subscribe">
    WebSocket `transactionSubscribe` メソッド上の同じフィールド。
  </Card>

  <Card title="サブスクライブリクエストリファレンス" icon="filter" href="/ja/laserstream/grpc">
    すべてのトランザクションフィルターフィールドを含む。
  </Card>

  <Card title="圧縮フィルター" icon="layer-group" href="/ja/laserstream/cuckoo-filters">
    一つのストリームで数十万のアカウントをトラッキング。
  </Card>
</CardGroup>
