
Agave 4.2: Die Migrationscheckliste
Inhaltsverzeichnis
- Zeitplan für die Aktivierung
- Breaking Changes in Agave 4.2
- Transaction v1 lässt den gesamten Aufruf fehlschlagen
- Fehler beim Compute Budget von Transaction v1
- Unveränderte Accounts senden keine Updates mehr
- Ein neuer rewardType-Wert
- Token-2022: Ein Feld entfernt, Parsing erweitert
- Konstanten für Slot-Zeiten sind veraltet
- Prüfe, ob du fertig bist
- Agent-Audit ausführen
- Stream-Abhängigkeiten prüfen
- Fragen
Den Funktionsumfang von Agave 4.2 haben wir in unserer Release-Übersicht vorgestellt. In diesem Beitrag geht es um die Migration: Was nicht mehr funktioniert und wie du deine Integration prüfst, bevor das Feature-Gate aktiviert wird.
Die meisten dieser Änderungen liefern falsche oder fehlende Daten statt Fehlern. Deshalb tauchen sie nicht in deinen Fehlerprotokollen auf.
Zeitplan für die Aktivierung
| Wann | Was | Status |
| 11. Aug. 2026 | Anza empfiehlt 4.2 für das Mainnet; Validator-Upgrades beginnen | Läuft |
| Während des Node-Upgrades | Die Unterdrückung von Account-Updates und Änderungen an Token-2022 jsonParsed werden wirksam | Abgeschlossen |
| Erste Epochengrenze nach dem Upgrade | Der Wert DeactivatedStake rewardType erscheint in Rewards | Abgeschlossen |
| Epoche 1020 | Slot-Zeiten werden von 400 ms auf 350 ms verkürzt, der erste von vier Schritten auf dem Weg zu 200 ms | Abgeschlossen |
| Epoche 1024 | Slot-Zeiten werden von 350 ms auf 300 ms verkürzt | Geplant (voraussichtlich am 28. Aug.) |
| Feature-Gate, Datum noch offen | Transaction v1 (Transaktionen mit 4.096 Byte) | Ausstehend (kein Datum angekündigt, bereite dich also so vor, als würde es nächste Woche aktiviert) |
| Fünf Feature-Gates, Datum noch offen | Senkung der Rent, schrittweise von 6.960 Lamports/Byte auf 696 | Ausstehend |
| Agave 4.3, geplant für Okt. 2026 | Alpenglow-Konsens | Künftiges Release |
Breaking Changes in Agave 4.2
Transaction v1 lässt den gesamten Aufruf fehlschlagen
SIMD-0296 und SIMD-0385 erhöhen das Größenlimit für Solana-Transaktionen mit einem neuen Transaktionsformat auf 4.096 Byte.
Der zusätzliche Platz ermöglicht größere Onchain-Workloads, etwa ZK-Proofs oder DEX-Routen mit mehr Teilschritten.
Der Haken: Eine einzige v1-Transaktion in einem Block unterbricht getBlock für den gesamten Block, wenn der Aufruf maxSupportedTransactionVersion: 1 nicht setzt.
Auch die anderen Transaktionen werden nicht zurückgegeben; der gesamte Aufruf schlägt fehl. getTransaction und getTransactionsForAddress (mit transactionDetails = full) schlagen bei jeder v1-Transaktion auf dieselbe Weise fehl.
So behebst du das Problem:
- Aktualisiere dein SDK auf ein Release, das v1 decodieren kann. Die Unterstützung wird derzeit in verschiedenen Clients ergänzt. Falls dein SDK Transaction v1 noch nicht unterstützt, achte in den Release Notes auf Transaction v1 oder SIMD-0385.
- Beliebte JS-Clients: @solana/kit 8.0+, @solana/web3.js v3
- Beliebte Rust-Crates: solana-rpc-client-api 4.2+, solana-client 4.2+, solana-transaction 4.2+, solana-compute-budget 4.2+, weitere Anza-Crates.
- Setze
maxSupportedTransactionVersion: 1bei jedem Aufruf von getBlock, getTransaction und getTransactionsForAddress (mittransactionDetails = full) - Setze
maxSupportedTransactionVersion: 1im Optionsobjekt jedes Enhanced WebSockets-transactionSubscribe-Abonnements (wobeitransactionDetailsauffulloderaccountsgesetzt ist). Bei Abonnements aus den Dokumentationsbeispielen ist der Wert auf0gesetzt; erhöhe ihn auf1
{
"jsonrpc": "2.0",
"id": "1",
"method": "getTransactionsForAddress",
"params": [
"Vote111111111111111111111111111111111111111",
{
"transactionDetails": "full",
"sortOrder": "desc",
"filters": {
"status": "succeeded"
},
"maxSupportedTransactionVersion": 1
}
]
}
Der Parameter gibt die höchste Version an, die dein Client verarbeiten kann. Du kannst ihn schon heute bedenkenlos setzen. Er ändert nicht, wie Legacy- und v0-Transaktionen zurückgegeben werden.
Fehler beim Compute Budget von Transaction v1
Eine v1-Transaktion speichert ihr Compute-Limit und ihre Priority Fee im Objekt transactionConfig statt in ComputeBudget-Anweisungen. Gebühren-Dashboards und Schätzer für Priority Fees, die Gebühren durch den Abgleich dieser Anweisungen erkennen, interpretieren jede v1-Transaktion ohne Fehlermeldung so, als würde sie null bezahlen.
So behebst du das Problem:
Lies die Werte stattdessen aus dem neuen Feld priorityFee in der Transaktionskonfiguration. Beachte, dass das neue Feld priorityFee die Gesamtgebühr in Lamports angibt, nicht den Preis pro Compute Unit.
"message": {
"instructions": ["… no ComputeBudget instruction here …"],
"recentBlockhash": "...",
"transactionConfig": {
"computeUnitLimit": 200000,
"heapSize": null,
"loadedAccountsDataSizeLimit": 200000,
"priorityFee": 50000
}
}
Unveränderte Accounts senden keine Updates mehr
Agave 4.2 sendet Account-Ereignisse nur noch, wenn tatsächlich in einen Account geschrieben wird. Für LaserStream-gRPC- und WSS-Account-Abonnements bedeutet das etwa 80 % weniger Ereignisse.
So behebst du das Problem:
- Wenn du Transaktionen Account-Updates zuordnest, warte nicht mehr auf ein Update von jedem beschreibbaren Account. Behandle ein fehlendes Update als „Der Account hat sich nicht geändert“. Nur für den Gebührenzahler ist ein Update garantiert, da er immer die Gebühr bezahlt.
- Wenn du die Update-Häufigkeit als Zustandssignal verwendest, entferne diese Prüfung für Accounts, die häufig gesperrt, aber selten geändert werden. Ein ruhiger Account ist fehlerfrei; er sendet keine Ereignisse mehr, weil sich nichts geändert hat.
Ein neuer rewardType-Wert
Stake-Accounts, deren Deaktivierung abgeschlossen ist, erhalten ihre letzte Auszahlung jetzt unter dem neuen rewardType-Wert DeactivatedStake in den Reward-Arrays von getBlock und blockSubscribe. Die Struktur des Reward-Objekts ist mit Agave 4.1 identisch. Ein Parser, der nur bereits bekannte Reward-Typen akzeptiert, überspringt Auszahlungen vom Typ DeactivatedStake daher ohne Fehlermeldung.
getInflationReward ist nicht betroffen. Das Risiko besteht nur, wenn du rohe Reward-Arrays selbst analysierst.
So behebst du das Problem:
Füge DeactivatedStake zu den rewardType-Werten hinzu, die dein Parser akzeptiert. Protokolliere außerdem jeden unbekannten Wert, statt den Datensatz zu verwerfen.
{
"pubkey": "...",
"lamports": 10000000,
"postBalance": 50000000000,
"rewardType": "DeactivatedStake",
"commission": null,
"commissionBps": 500
}
Token-2022: Ein Feld entfernt, Parsing erweitert
In jsonParsed-Antworten verlieren depositConfidentialTransfer und withdrawConfidentialTransfer die Felder für Quelle und Ziel. Sie werden durch ein einzelnes Account-Feld ersetzt. Die bisherigen Bezeichnungen waren falsch; jede Anweisung betrifft einen Token-Account.
Aktualisiere deine Token-2022-Parser, damit sie das neue Feld unterstützen.
{
"parsed": {
"type": "depositConfidentialTransfer",
"info": {
"account": "6XVfUq9jZQtBfqcm1Rz8fBhViyoyzWiEUAaWnQ9AmXeR",
"mint": "8fJ7bCZo2vZ3vAnyCBQgZuLYuTX1qPnKvsMKotk92B2J",
"amount": 42,
"decimals": 9,
"owner": "F7yLk3s2iZDPBBvSNbXAaKPBnQ9vXqSSSzYUCGeUFhXn"
}
}
}
Burns mit Berechtigungsprüfung, unwrapLamports, confidentialBurn und Batch-Operationen werden jetzt als geparstes JSON statt als Rohbytes zurückgegeben.
{
"parsed": {
"type": "unwrapLamports",
"info": {
"source": "9rr9Xh6PXPKcVqbCB1qxGDWRUJJAdguqcUqVuUqEjqQK",
"destination": "BhU2wDgmvvMNC1vTSU4aG7BvW26MoTMSDL63hcMqziGL",
"amount": "1000000",
"authority": "F7yLk3s2iZDPBBvSNbXAaKPBnQ9vXqSSSzYUCGeUFhXn"
}
}
}
Mints mit zuvor nicht erkannten Erweiterungen gaben bisher ein leeres extensions-Array zurück. Unter Agave 4.2 wird das Array befüllt.
Wenn dein Code ein leeres Array als „keine Erweiterungen“ interpretiert, musst du damit rechnen, dass dort künftig Werte erscheinen.
"extensions": [
{
"extension": "transferFeeConfig",
"state": {
"transferFeeConfigAuthority": "...",
"withdrawWithheldAuthority": "...",
"withheldAmount": 0,
"olderTransferFee": {...},
"newerTransferFee": {...}
}
},
{
"extension": "permissionedBurnConfig",
"state": {
"authority": "3nGhQzXCzoDDvW9pkg8fVLGDrJc23uwFz7qzW26MoTMS"
}
}
]
Konstanten für Slot-Zeiten sind veraltet
Seit Epoche 1020 verwendet das Mainnet Slot-Zeiten von 350 ms. Die nächste Verkürzung auf 300 ms ist für Epoche 1024 geplant (voraussichtlich am 28. Aug.). Das Ziel sind 200 ms. Fest codierte 400-ms-Konstanten in Berechnungen von Slots zu Zeit liegen heute um 12,5 % daneben. Mit jedem weiteren Schritt wächst die Abweichung.
So behebst du das Problem:
Leite die Zeit aus Block-Zeitstempeln ab oder mache sie konfigurierbar. Stelle außerdem sicher, dass dein Indexer mithalten kann, wenn Blöcke schneller eintreffen.
Prüfe, ob du fertig bist
Führe das Agent-Audit aus und prüfe deine Abhängigkeiten, um sicherzustellen, dass du fertig bist.
Agent-Audit ausführen
Kopiere den folgenden Skill in deinen Coding-Agent.
Speichere ihn für Claude Code als .claude/skills/agave-42-readiness/SKILL.md.
Füge ihn bei anderen Agents als Aufgaben-Prompt ein.
---
name: agave-42-readiness
description: Audit this repository for Solana Agave 4.2 breaking changes. Use when asked to check Agave 4.2 readiness, migrate for transaction v1, or audit Solana RPC/streaming integration code.
---
# Agave 4.2 Readiness Audit
Audit the repository for the five Agave 4.2 breaking changes below. For each, locate the relevant code, judge whether it is affected, and report file:line with a verdict of PASS, FAIL, or NEEDS REVIEW. Do not modify code unless asked to fix findings.
## Check 1: Transaction v1 opt-in (highest priority)
Find every `getBlock`, `getTransaction`, and `getTransactionsForAddress` (with `transactionDetails = full`) call, plus every Enhanced WebSockets `transactionSubscribe` subscription. Search all languages, raw JSON-RPC request bodies (`"method": "getBlock"`, `"method": "transactionSubscribe"`), and SDK wrappers (`connection.getBlock`, `connection.getParsedTransaction`, `rpc_client.get_block`, `client.GetTransaction`, and similar).
- FAIL if `maxSupportedTransactionVersion` is absent or set to 0. Once the v1 feature gate activates, these calls fail on v1 transactions with JSON-RPC error code -32015: `"Transaction version (1) is not supported by the requesting client. Please use \"maxSupportedTransactionVersion\" in your request."` Also grep for `-32015` in logs and error handlers; hits mean the project has already been failing on versioned transactions.
- Also FAIL if the project deserializes raw transaction bytes (custom indexer, signer, relayer) and the decoder does not handle the v1 layout: version byte 0x81 (decimal 129, vs 0x80 for v0), signatures at the END of the transaction instead of the front, compute budget carried in a header config mask instead of instructions.
- Correct fix order: upgrade the Solana SDK to a v1-capable version (JS: @solana/kit 8.0+ or @solana/web3.js v3), then set `maxSupportedTransactionVersion: 1`. Flag if the parameter is set but the installed SDK version predates v1 support.
- Also FAIL if priority fee or compute budget extraction scans for ComputeBudget program instructions (`ComputeBudget111111111111111111111111111111`, `setComputeUnitPrice`, `setComputeUnitLimit`). A v1 transaction contains no such instructions; its values live in a `transactionConfig` object in the message. Scanning code reads every v1 transaction as paying zero priority fee.
- Units trap, FAIL even when the code reads `transactionConfig`: legacy/v0 `setComputeUnitPrice` is **micro-lamports per compute unit**; v1 `priorityFee` is a **total in lamports**. Code that ports the old `price × computeUnitLimit ÷ 1e6` math onto the new field misreports fees. `priorityFee` needs no multiplication. Null fields mean the sender did not set them.
Example v1 message:
```
"message": {
"instructions": ["… no ComputeBudget instruction here …"],
"recentBlockhash": "...",
"transactionConfig": {
"computeUnitLimit": 200000,
"heapSize": null,
"loadedAccountsDataSizeLimit": 200000,
"priorityFee": 50000
}
}
```
`"priorityFee": 50000` = this transaction pays 50,000 lamports total. Legacy and v0 messages omit `transactionConfig` entirely, so its presence (or `"version": 1` on the enclosing transaction) identifies v1.
## Check 2: rewardType parsed as a closed enum
Find code reading `rewardType` from `getBlock`, `blockSubscribe`, or Geyser/gRPC reward arrays. Search for the existing values too (`"Fee"`, `"Rent"`, `"Staking"`, `"Voting"` in JSON paths; `RewardType::` in Rust; reward-type enums in generated gRPC code).
- 4.2 adds the value `DeactivatedStake` — same capitalized casing as the existing JSON values (`"Staking"`, not `"staking"`). A reward entry looks like:
```
{
"pubkey": "...",
"lamports": 10000000,
"postBalance": 50000000000,
"rewardType": "DeactivatedStake",
"commission": null
}
```
- FAIL if unknown values throw, or fall into a match/switch arm or if/else chain that drops the record without logging: a Rust `match` without a logging wildcard arm, a TS `switch` whose `default` is silent, a lookup table where a missing key skips the entry. Closed parsers lose every deactivating stake account's final payout with no error.
- FAIL if a deserialization enum (serde, protobuf mapping, Zod/io-ts schema) rejects unknown reward-type strings; the whole reward array or block record errors out, not just one entry.
- PASS requires unknown values to be preserved or logged. If the project aggregates staking yield by filtering `rewardType == "Staking"`, add a NEEDS REVIEW noting the team must decide whether `DeactivatedStake` payouts belong in totals; they are final payouts, not recurring yield.
## Check 3: Transaction-to-account-update matching
Find logic that correlates transactions with account update notifications. Search for `accountSubscribe`, Yellowstone/LaserStream `SubscribeRequest` account filters, and code that builds a pending set of a transaction's writable accounts and waits to check them off as updates arrive.
- FAIL if it assumes every writable account in a transaction produces an update. On 4.2, an account that was write-locked but not modified emits nothing; logic awaiting the full set hangs forever. Typical patterns: a countdown/completion latch over `message.accountKeys` writable entries, a timeout that treats a missing update as an error, a reconciler that re-fetches "late" accounts. The fee payer is the only account guaranteed to update.
- The correct interpretation of a missing update is "this account did not change"; its pre-transaction state is still current.
- Also FAIL liveness or health checks that treat update frequency as a signal, and flag alert thresholds calibrated to pre-4.2 volume; account-subscription event counts drop roughly 80% on 4.2.
## Check 4: Token-2022 jsonParsed changes
Find parsers reading Token-2022 `jsonParsed` output: instruction types `depositConfidentialTransfer` and `withdrawConfidentialTransfer`, and mint-account `extensions` arrays.
- FAIL if confidential-transfer parsers read `source` or `destination`; 4.2 replaces both with a single `account` field. New shape:
```
"info": {
"account": "...", // was source + destination
"mint": "...",
"amount": 42,
"decimals": 9,
"owner": "..." // multisig: "multisigOwner" + "signers" array instead
}
```
- New instruction types now come back parsed instead of raw: `unwrapLamports`, `confidentialBurn`, permissioned burn, and batch operations. FAIL if code assumes these arrive as raw base64/base58 data, and flag `unwrapLamports` parsers that require `info.amount` or treat it as a number: it is a **string** and is **omitted entirely** when the instruction unwraps the full balance.
- Extensions array: on 4.1, one unrecognized extension type on a mint made the node return `"extensions": []`, hiding every extension including known ones. On 4.2 the full array returns, each entry as `{"extension": "<name>", "state": {...}}`, with still-undecodable ones as `{"extension": "unparseableExtension"}`. FAIL if code treats an empty array as proof of no extensions, or throws on extension names it does not recognize (`scaledUiAmountConfig`, `pausableConfig`, `permissionedBurnConfig`, `unparseableExtension`, and future values).
## Check 5: Slot timing and streaming dependencies
- FAIL on hardcoded slot-duration constants: `400`, `0.4`, `400_000` microseconds, `MS_PER_SLOT`, `SLOT_DURATION`, `DEFAULT_MS_PER_SLOT`, or slot-to-time math like `slots * 400`. Mainnet is 350ms, cutting to 300ms on Aug 28, 2026, stepping toward 200ms. Constants inherited from an SDK count as hardcoded. PASS requires timing derived from block timestamps (e.g. `getBlockTime` deltas over a few thousand slots) or a config value with a documented update path.
- Also flag capacity assumptions keyed to block rate: batch sizes, poll intervals, and queue depths sized for 400ms blocks fall behind as slots shorten.
- In Cargo.toml/Cargo.lock: FAIL if `yellowstone-grpc-client` < 13.3.0 or `yellowstone-grpc-proto` < 12.6.0 (first proto carrying transaction v1). Recommend client 13.3.0, proto 12.6.0, both declared.
- For Go gRPC clients: flag if generated protos predate transaction v1; regenerate from latest Yellowstone protos and solana-storage-proto.
- If the project uses the Helius LaserStream SDK (package names `helius-laserstream`, `laserstream` in dependencies): FAIL if below JS 0.8.4, Rust 0.6.3, or Go 0.2.0 (first releases with the v1-capable proto).
## Report format
Output a table: check, verdict, file:line references, one-line remediation. End with an overall verdict (READY / NOT READY) and the ordered fix list. Full migration guide: https://www.helius.dev/blog/agave-4-2-migration-checklistErweiternEinklappen
Stream-Abhängigkeiten prüfen
Rust: yellowstone-grpc-client 13.3.0 und yellowstone-grpc-proto 12.6.0, beide deklariert, anschließend cargo update.
Go: Generiere den Code aus den neuesten Yellowstone-Protos neu und führe solana-storage-proto aus.
LaserStream SDK: JS 0.8.4, Rust 0.6.3 und Go 0.2.0 oder höher enthalten das v1-fähige Proto. Deine Abonnements und Filter müssen auf keinem Pfad geändert werden.
Fragen
Wenn sich deine Integration unter 4.2 anders verhält und dieser Beitrag keine Erklärung liefert, melde dich auf Discord oder beim Support. Eine Aufschlüsselung nach Features findest du in der Übersicht zu 4.2.
Ähnliche Artikel
Helius abonnieren
Bleib bei der Solana-Entwicklung auf dem Laufenden und erhalte Updates, wenn wir neue Beiträge veröffentlichen


