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

# Abonnement und Aktualisierungen des Kontos

> Erfahren Sie, wie Sie sich für Kontoaktualisierungen anmelden und Zustandänderungen effizient mit Laserstream verfolgen können.

Beim Erstellen von Anwendungen, die auf On-Chain-Änderungen reagieren müssen, ist das Abfragen von RPC-Endpunkten für Kontoaktualisierungen ineffizient und langsam. Kontoabonnements lösen dies, indem sie in Echtzeit Aktualisierungen über Kontoänderungen direkt an Ihre Anwendung liefern.

Dieser Leitfaden behandelt alles, was Sie über Kontoabonnements wissen müssen: was sie sind, wie sie funktionieren und wie Sie sie für Ihren spezifischen Anwendungsfall optimieren können.

***

## Der Kontext des Kontomodells

<Info>
  Überspringen Sie diesen Abschnitt, wenn Sie mit Solana-Konten und ihrer Struktur vertraut sind.
</Info>

Solana verwendet ein kontobasiertes Modell, bei dem jedes Datenstück in einem Konto lebt - einem Container, der sowohl Daten als auch Metadaten hält. Jedes Konto hat:

* **Daten**: Die tatsächlichen Bytes, die den Programmzustand, Token-Salden oder andere Informationen speichern
* **Besitzer**: Das Programm, das dieses Konto kontrolliert und seine Daten ändern kann
* **Lamports**: Der SOL-Saldo des Kontos für Freistellung von Miete
* **Ausführbar**: Ob dieses Konto Programmcode enthält

Programme sind zustandslos - sie speichern keine Daten intern. Stattdessen erstellen und verwalten sie separate Konten, um ihren Zustand zu speichern. Wenn Sie mit einem Programm interagieren, geben Sie die Konten an, von denen es lesen oder schreiben soll.

Dieses Design macht Kontoabonnements leistungsstark: Sie können Änderungen an bestimmten Konten überwachen, alle von einem Programm verwalteten Konten oder Konten, die bestimmten Kriterien entsprechen.

***

## Einfaches Kontoabonnement

Beginnen wir mit einem einfachen Beispiel, das sich auf Änderungen in Token-Konten abonniert. Dieses Skript benachrichtigt Sie, wann immer sich Token-Salden ändern:

```ts [expandable] theme={"system"}
import { subscribe, CommitmentLevel, SubscribeUpdate, LaserstreamConfig } from 'helius-laserstream';
import bs58 from 'bs58';

// Utility function to recursively convert Buffer objects to base58 strings
function convertBuffersToBase58(obj: any): any {
  if (obj === null || obj === undefined) {
    return obj;
  }
  
  if (Buffer.isBuffer(obj)) {
    return bs58.encode(obj);
  }
  
  if (Array.isArray(obj)) {
    return obj.map(convertBuffersToBase58);
  }
  
  if (typeof obj === 'object') {
    const result: any = {};
    for (const key in obj) {
      if (obj.hasOwnProperty(key)) {
        result[key] = convertBuffersToBase58(obj[key]);
      }
    }
    return result;
  }
  
  return obj;
}

async function main() {
  console.log('🏦 Basic Account Subscription Example');

  const config: LaserstreamConfig = {
    apiKey: 'YOUR_API_KEY', // from https://dashboard.helius.dev/
    endpoint: 'https://laserstream-mainnet-ewr.helius-rpc.com', // pick the closest region
  };

  const request = {
    accounts: {
      "token-accounts": {
        account: [], // Specific account pubkeys (empty = all)
        owner: ["TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"], // Token program
        filters: [
          {
            // Only token accounts (165 bytes)
            datasize: 165
          }
        ]
      }
    },
    commitment: CommitmentLevel.CONFIRMED,
    transactions: {}, slots: {}, transactionsStatus: {}, blocks: {}, blocksMeta: {}, entry: {}, accountsDataSlice: []
  };

  const stream = await subscribe(
    config,
    request,
    async (update: SubscribeUpdate) => {
      const readableUpdate = convertBuffersToBase58(update);
      console.log('🏦 Account Update:', JSON.stringify(readableUpdate, null, 2));
    },
    async (err) => console.error('❌ Stream error:', err)
  );

  console.log(`✅ Account subscription started (id: ${stream.id})`);

  process.on('SIGINT', () => {
    console.log('\n🛑 Cancelling stream...');
    stream.cancel();
    process.exit(0);
  });
}

main().catch(console.error);
```

Wenn Sie dieses grundlegende Abonnement ausführen, sehen Sie Echtzeit-Kontoaktualisierungen, die zu Ihrer Konsole gestreamt werden:

```
🏦 Basic Account Subscription Example
✅ Account subscription started (id: xyz789)

🏦 Account Update: {
  "filters": ["token-accounts"],
  "account": {
    "account": {
      "pubkey": "BKMHWYLAX4un3HUbR7a3u9jPmzCiLNa4mSj1RiX11eWF",
      "lamports": "2039280",
      "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
      "rentEpoch": "18446744073709551615",
      "data": "2NUx6Xw9QkmgJCyYUP3d8TPsjJhUpSM7hcy9Fi1juGc6g9DrpPFyGyvBZzu9qiAjFtyEDbNiLHYFJsq1dD5Wxr4LPcF9Dqs4AJa15L1N92pfinnoKVfCsVCcybhV1iwkCCTMeMyxTRA4tqJm6MrLwgKG3HmmwVdhsEuXjSsGJFXGzgfgPHucVzBEgAqcpH9JPpoaQyis2MFwRJLjenxzkE8xJzWHv1Zk2T",
      "writeVersion": "2697618495",
      "txnSignature": "5C9Hr5nG2j8eQz6inxPmfyjbYdmXddzUDyR1iQgEnjYQ3RNvuP4Zzc8t1enLNy7Rk8KNCtQPEQztENYWxkt9GaVD"
    },
    "slot": "352366983"
  },
  "createdAt": "2025-07-10T11:56:22.027Z"
}
```

**Was ist gerade passiert?** Unser Abonnement hat perfekt funktioniert! Wir haben Laserstream gebeten, uns über Änderungen an Token-Konten zu benachrichtigen, und es hat ein Update über Konto `BKMHWYLAX4un3HUbR7a3u9jPmzCiLNa4mSj1RiX11eWF` geliefert.

Dieses Konto hat:

* **2.039.280 Lamports** (\~0,002 SOL-Saldo - dies ist der mietfreie Betrag für dieses Token-Konto)
* **Besitzerprogramm** `TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA` (dies ist das SPL-Token-Programm)
* **Transaktionssignatur** `5C9Hr5nG2j8eQz6inxPmfyjbYdmXddzUDyR1iQgEnjYQ3RNvuP4Zzc8t1enLNy7Rk8KNCtQPEQztENYWxkt9GaVD`, die zeigt, welche spezifische Transaktion dieses Konto geändert hat
* **Slot 352366983**, der angibt, wann dieses Update auf der Blockchain aufgetreten ist
* **Datenfeld** mit 165 Bytes Kontodaten kodiert als base58

### Verständnis der Kontofilterung mit datasize

Das Datenfeld ist entscheidend - es enthält die tatsächliche Token-Kontostruktur. Lassen Sie uns dieses Verständnis für ein **intelligentes Kontofiltering** nutzen.

#### Warum datasize-Filterung verwenden?

Um zu verstehen, warum wir filtern müssen, lassen Sie uns zuerst verstehen, was Token-Konten tatsächlich sind. **Für jedes Token, das eine Wallet hält, gibt es ein separates Konto on-chain.** Wenn Ihre Wallet 3 verschiedene Token hält (USDC, BONK und SOL), haben Sie tatsächlich 1 Wallet-Konto (Ihr Haupt-SOL-Konto) plus 3 Token-Konten (eines für jeden Token-Typ). Jedes Token-Konto ist genau 165 Bytes lang und speichert: welches Token es hält (Mint-Adresse), wem es gehört (Ihre Wallet-Adresse) und wie viel von diesem Token es enthält (Menge).

Das Token-Programm besitzt **Millionen von Konten** auf Solana, aber nicht alle sind das, was wir als "Token-Konten" verstehen, die Benutzerbilanzen halten. Hier ist, was mit und ohne Filterung passiert:

**Ohne Filterung - Die Flut:**

```ts theme={"system"}
accounts: {
  "all-token-program-accounts": {
    owner: ["TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"] // ❌ Overwhelming!
  }
}
```

Dies abonniert ALLE vom Token-Programm verwalteten Konten, einschließlich:

* **Token-Konten** (165 Bytes) - Benutzerbilanzen: Millionen von Konten
* **Mint-Konten** (82 Bytes) - Token-Definitionen: Hunderttausende von Konten
* **Multisig-Konten** (355 Bytes) - Gemeinsame Wallet-Kontrollen: Zehntausende von Konten
* **Verbundene Token-Programmkonten** (verschiedene Größen) - Millionen von Konten

<Warning>
  **Ergebnis:** Ihre Anwendung erhält ständig Millionen von Kontoaktualisierungen, von denen die meisten nicht relevant sind.
</Warning>

**Mit intelligentem Filter - Chirurgische Präzision:**

```ts theme={"system"}
accounts: {
  "token-accounts-only": {
    owner: ["TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"],
    filters: [{ datasize: 165 }] // ✅ Only standard token accounts
  }
}
```

Dies filtert nur die 165-Byte-Konten heraus, die speziell die Benutzer-Token-Saldenkonten sind - genau das, was Sie für das Tracking von Token-Transfers, Saldoänderungen und Portfolioaktualisierungen benötigen.

**Der Unterschied:**

* **Ohne Filterung:** Millionen von Kontoaktualisierungen (Mint-Erstellungen, Multisig-Änderungen usw.)
* **Mit datasize-Filterung:** Nur Token-Saldoänderungen

Das ist eine erhebliche Reduzierung des Geräuschpegels und konzentriert sich nur auf die Konten, die tatsächlich Benutzer-Token-Bestände darstellen.

#### Woher kommen die 165 Bytes?

Das ist keine Magie - es stammt aus der [SPL-Token-Programm-Kontostruktur](https://github.com/solana-program/token/blob/d05d10807fe8cf157f6e1f024c708274c30c953a/program/src/state.rs#L87). Im Quellcode sehen wir, dass die `Account`-Struktur genau 165 Bytes definiert:

```rust theme={"system"}
pub struct Account {
    pub mint: Pubkey,                    // 32 bytes
    pub owner: Pubkey,                   // 32 bytes  
    pub amount: u64,                     // 8 bytes
    pub delegate: COption<Pubkey>,       // 4 + 32 bytes
    pub state: AccountState,             // 1 byte
    pub is_native: COption<u64>,         // 4 + 8 bytes
    pub delegated_amount: u64,           // 8 bytes
    pub close_authority: COption<Pubkey> // 4 + 32 bytes
}
// Total: 32+32+8+36+1+12+8+36 = 165 bytes
```

Diese feste Größe erlaubt es uns, präzise nach Standard-Token-Konten zu filtern und auszuschließen:

* Mint-Konten (82 Bytes)
* Multisig-Konten (355 Bytes)
* Verbundene Token-Programmkonten
* Andere tokenbezogene Konten mit unterschiedlichen Größen

Für die Berechnung der Kontogrößen in anderen Programmen schauen Sie sich die [Anchor Space Reference](https://www.anchor-lang.com/docs/references/space) an – sie zeigt Ihnen, wie viel Platz verschiedene Datentypen benötigen (Pubkey = 32 Bytes, u64 = 8 Bytes, etc.).

#### Dekodierung der Kontostruktur

Jetzt, da wir verstehen, warum wir nach 165 Bytes gefiltert haben, lassen Sie uns dekodieren, was sich in unserem Beispielkonto befindet:

```
Base58 data: 2NUx6Xw9QkmgJCyYUP3d8TPsjJhUpSM7hcy9Fi1juGc6g9...
```

Die 165 Bytes gliedern sich wie folgt:

* **Bytes 0-31:** Mint-Adresse (welches Token dieses Konto hält)
* **Bytes 32-63:** Eigentümeradresse (wem dieses Token-Konto gehört)
* **Bytes 64-71:** Token-Menge (wie viele Token sich im Konto befinden)
* **Bytes 72-164:** Zusätzliche Metadaten (Bevollmächtigter, Zustand, Schließberechtigung usw.)

Dieser strukturierte Ansatz gibt uns chirurgische Präzision: wir erhalten nur Updates für Standard-Token-Konten, nicht das Rauschen von anderen Kontotypen.

### Kombinieren von Filtern: datasize + memcmp für höchste Genauigkeit

Jetzt, wo wir wissen, dass sich die Mint-Adresse bei Bytes 0-31 befindet, können wir noch spezifischer werden. Angenommen, wir möchten nur USDC-Token-Konten überwachen. Wir können unseren `datasize`-Filter mit einem `memcmp`-Filter kombinieren, um die genaue Mint-Adresse zu treffen:

```ts theme={"system"}
const USDC_MINT = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v";

const request = {
  accounts: {
    "usdc-only": {
      owner: ["TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"],
      filters: [
        { datasize: 165 },                    // Standard token accounts only
        { 
          memcmp: {
            offset: 0,                         // Mint address starts at byte 0
            base58: USDC_MINT                  // Match this specific mint
          }
        }
      ]
    }
  },
  // ... other config
};
```

**Fortschrittliche Filterstrategie:**

1. **Besitzerfilter:** „Gib mir Konten, die vom Token-Programm verwaltet werden“ (Millionen von Konten)
2. **Datasize-Filter:** „Aber nur 165-Byte-Standard-Token-Konten“ (Hunderttausende)
3. **Memcmp-Filter:** „Und nur diejenigen, die USDC halten“ (Tausende)

Dieser Fortschritt von breit zu spezifisch ist der Schlüssel zur effizienten Kontoüberwachung. Jeder Filter schränkt die Ergebnismenge weiter ein, sodass Sie nur die genauen Updates erhalten, die Sie interessieren.

**Wichtig:** Alle Filter verwenden AND-Logik - jede Bedingung muss erfüllt sein, damit ein Konto-Update ausgelöst wird.

### Lesen von USDC-Kontoaktualisierungen: Wer, Wie viel, Wo?

Sehen wir uns nun an, was diese gefilterten Updates tatsächlich enthalten. Lassen Sie uns einen USDC-spezifischen Monitor erstellen, der die entscheidenden Fragen beantwortet, wenn sich ein Token-Konto ändert:

* **Wer** besitzt dieses Token-Konto?
* **Wie viel** USDC enthält es jetzt?
* **Wo** (welches spezifische Konto) hat sich geändert?
* **Wann** ist diese Änderung aufgetreten?
* **Welche Transaktion** hat die Änderung verursacht?

Die rohen Kontoaktualisierungen enthalten Binärdaten, die wir dekodieren müssen. Da Solana base58-Codierung für Adressen und Signaturen verwendet, nutzen wir die `bs58.encode()`-Funktion, um binäre Buffer-Objekte in lesbare Zeichenfolgen zu konvertieren.

```ts [expandable] theme={"system"}
import { subscribe, CommitmentLevel, SubscribeUpdate, LaserstreamConfig } from 'helius-laserstream';
import bs58 from 'bs58';

async function main() {
  console.log('USDC Account Monitor');

  const config: LaserstreamConfig = {
    apiKey: 'YOUR_API_KEY', // from https://dashboard.helius.dev/
    endpoint: 'https://laserstream-mainnet-ewr.helius-rpc.com', // pick the closest region
  };

  const USDC_MINT = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v";

  const request = {
    accounts: {
      "usdc-accounts": {
        account: [],
        owner: ["TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"],
        filters: [
          { datasize: 165 },                           // Standard token accounts
          { memcmp: { offset: 0, base58: USDC_MINT } } // Only USDC
        ]
      }
    },
    commitment: CommitmentLevel.CONFIRMED,
    transactions: {}, slots: {}, transactionsStatus: {}, blocks: {}, blocksMeta: {}, entry: {}, accountsDataSlice: []
  };

  const stream = await subscribe(
    config,
    request,
    async (update: SubscribeUpdate) => {
      explainAccountUpdate(update);
    },
    async (err) => console.error('Stream error:', err)
  );

  console.log(`Account monitor started (id: ${stream.id})`);

  process.on('SIGINT', () => {
    console.log('\nCancelling stream...');
    stream.cancel();
    process.exit(0);
  });
}

function explainAccountUpdate(update: SubscribeUpdate) {
  if (!update.account) return;
  
  const account = update.account.account;
  
  // Decode the key addresses
  const tokenAccountAddress = bs58.encode(account.pubkey);
  const transactionSignature = account.txnSignature ? bs58.encode(account.txnSignature) : 'Unknown';
  
  // Extract and decode the token account data (165 bytes)
  const walletOwner = bs58.encode(account.data.slice(32, 64));       // Bytes 32-63: Owner
  const tokenAmount = account.data.readBigUInt64LE(64);              // Bytes 64-71: Amount
  const usdcAmount = Number(tokenAmount) / 1_000_000;                // Convert to USDC (6 decimals)
  
  console.log(`Account: ${tokenAccountAddress}`);
  console.log(`Owner: ${walletOwner}`);
  console.log(`Balance: ${usdcAmount.toLocaleString()} USDC`);
  console.log(`Slot: ${update.account.slot}`);
  console.log(`Transaction: ${transactionSignature.slice(0, 8)}...`);
  console.log('---');
}

main().catch(console.error);
```

Wenn Sie diesen USDC-Monitor ausführen, sehen Sie saubere, strukturierte Ausgaben wie diese:

```
USDC Account Monitor
Account monitor started (id: abc123)

Account: 7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU
Owner: 9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM
Balance: 1,500 USDC
Slot: 352154103
Transaction: 5v8fy0eJ...
---
Account: BQy5rNRxLfcaK6554PMzsg4VJsFXzwGnAnayb8TZKgZX
Owner: HN7cABqLq46Es1jh92dQQisAq662SmxELLLsHHe4YWrH
Balance: 0 USDC
Slot: 352154103
Transaction: 5v8fy0eJ...
---
```

Jeder Block stellt ein USDC-Konto dar, das den Zustand geändert hat. Das erste Konto hält nun 1.500 USDC, während das zweite Konto auf 0 USDC geleert wurde. Sie erhalten den aktuellen Saldo sofort nach jeder Transaktion sowie welches spezifische Konto sich geändert hat und wann.

Kontoabonnements zeigen Ihnen das Endergebnis dessen, was mit jedem Konto passiert ist, aber nicht die Transaktionsdetails. Wenn Sie den vollständigen Transaktionskontext verstehen müssen (wer an wen gesendet hat, Gebühren usw.), müssen Sie die vollständige Transaktion mit der angezeigten Signatur abrufen.

## Komplette Filterreferenz

Neben den Basisfiltern `owner`, `datasize` und `memcmp`, die wir verwendet haben, unterstützen Kontoabonnements zusätzliche Filteroptionen, um Ihre Ergebnisse weiter zu verfeinern:

### Spezifische Kontofilterung

Überwachen Sie genaue Konten anhand ihrer öffentlichen Schlüssel:

```ts theme={"system"}
accounts: {
  "specific-accounts": {
    account: [
      "7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU",
      "BQy5rNRxLfcaK6554PMzsg4VJsFXzwGnAnayb8TZKgZX"
    ]
  }
}
```

Dieser Ansatz funktioniert gut, wenn Sie genau wissen, welche Konten für Ihre Anwendung wichtig sind - wie das Überwachen der Tresorkonten Ihrer Anwendung oder bestimmter Benutzerkonten.

Für sehr große Konten-Sets werden explizite Pubkey-Listen teuer — 32 Bytes pro Konto in der Abonnementanfrage. Ab etwa \~10.000 Konten verwenden Sie einen komprimierten [Cuckoo-Filter](/docs/de/laserstream/cuckoo-filters) (\~3–4 Bytes pro Konto), um Hunderttausende von Konten in einem einzigen Stream zu verfolgen. Verfügbar in den Rust- und JavaScript-SDKs.

### Kombinierte Filterstrategien

Die Stärke kommt aus der Kombination mehrerer Filtertypen. Hier ist das Grundmodell:

1. **Werfen Sie ein großes Netz** mit `owner` - "Gib mir alle von diesem Programm verwalteten Konten"
2. **Filter nach Struktur** mit `datasize` - "Aber nur Konten dieses speziellen Typs"
3. **Zielspezifische Daten** mit `memcmp` - "Und nur diejenigen mit diesen spezifischen Informationen"
4. **Überwachen Sie bekannte Konten** mit `account` - "Oder überwachen Sie einfach diese genauen Konten, die mir wichtig sind"

Zum Beispiel die Überwachung hochrangiger USDC-Konten:

```ts theme={"system"}
accounts: {
  "high-value-usdc": {
    owner: ["TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"],
    filters: [
      { datasize: 165 },                           // Token accounts only
      { memcmp: { offset: 0, base58: USDC_MINT } } // USDC only
      // Note: You'd implement balance filtering in your callback logic
    ]
  }
}
```

Der Schlüssel ist, dass jeder Filter das Volumen der erhaltenen Updates reduziert. Ohne Filterung könnten Sie überwältigende Mengen an Kontoaktualisierungen erhalten. Mit intelligenten Filtern erhalten Sie nur die Updates, die für Ihren spezifischen Anwendungsfall relevant sind.

### Das größere Bild verstehen

Betrachten Sie Kontoabonnements als das Beobachten eines Live-Feeds von Datenbankänderungen. Der Zustand von Solana ist im Wesentlichen ein massiver Key-Value-Store, bei dem jedes Konto ein Eintrag ist. Wenn Programme ausgeführt werden, ändern sie diese Konten. Ihr Abonnement ermöglicht es Ihnen, spezifische Einträge in Echtzeit ändern zu sehen.

Das Filtersystem funktioniert wie Datenbankindizes - Sie beobachten nicht nur "alle Änderungen", sondern "Änderungen an Konten, die diesen Kriterien entsprechen." Dies ermöglicht es, reaktionsschnelle Anwendungen zu erstellen, die sofort auf relevante On-Chain-Ereignisse reagieren, ohne Ihr System mit irrelevanten Daten zu überlasten.

## Anwendung dieses Musters auf andere Programme

Der Ansatz, den wir gelernt haben, funktioniert für jedes Solana-Programm. Hier ist das allgemeine Muster:

1. **Erforschen der Kontostruktur** - Überprüfen Sie den Quellcode oder die Dokumentation des Programms
2. **Beginnen Sie mit der Besitzerfilterung** - Ziel ist das Programm, das die Konten verwaltet
3. **Anwenden von Strukturfiltern** - Verwenden Sie Kontogröße, Datenmuster oder andere Merkmale, um auf spezifische Kontotypen einzugrenzen
4. **Hinzufügen gezielter Filter** - Fokussieren Sie sich auf spezifische Konten, Zustände oder Datenwerte, die für Ihre Anwendung wichtig sind
