Skip to main content
Agave 4.2 introduces transaction v1 (SIMD-0385). Once the feature gate activates on mainnet, wallets and programs start submitting v1 transactions, and any request that fetches full transaction data has to opt in to receive them. This page covers what changes, which Helius endpoints are affected, and how to update your code. For the full Agave 4.2 checklist, including reward types, account update semantics, and slot timing, see the Agave 4.2 migration checklist.

What changes in transaction v1

Legacy and v0 transactions are unchanged. For most integrations, two things about transaction v1 matter:
  • You must opt in to receive it. Requests for full transaction data need maxSupportedTransactionVersion: 1, and your client library needs a version that can deserialize v1.
  • The compute budget moves into the message header. A v1 message carries a transactionConfig object with computeUnitLimit, heapSize, loadedAccountsDataSizeLimit, and priorityFee. There are no ComputeBudget program instructions in a v1 transaction.
The wire format also changes (a new version byte and signatures at the end of the transaction), but that only affects code that decodes raw transaction bytes. See Decode raw transaction bytes below. In JSON responses, a v1 transaction reports "version": 1 and its message includes transactionConfig:
"priorityFee": 50000 means this transaction pays 50,000 lamports in total. A null field means the sender did not set it. Legacy and v0 messages omit transactionConfig entirely.

Set maxSupportedTransactionVersion to 1

Every request that returns full transaction data must declare the highest transaction version it can handle. Set maxSupportedTransactionVersion: 1 on: A request that omits the parameter, or sets it to 0, fails with JSON-RPC error -32015 as soon as it touches a v1 transaction:
For getBlock, one v1 transaction anywhere in the block fails the whole request. If you see -32015 in your logs, the project is already failing on versioned transactions.

Upgrade your SDK before raising the value

Setting maxSupportedTransactionVersion: 1 tells the node to return v1 transactions. Your client library still has to deserialize them. Upgrade first, then change the parameter: Older VersionedTransaction.deserialize implementations in JavaScript only handle legacy and v0 and throw on a leading 0x81 byte. Older Yellowstone protos predate the v1 message fields, so gRPC consumers on those versions never see transactionConfig. For Go gRPC clients, regenerate from the latest Yellowstone protos and solana-storage-proto.

Read priority fees from transactionConfig

Code that estimates a transaction’s priority fee by scanning for ComputeBudget program instructions (ComputeBudget111111111111111111111111111111, setComputeUnitPrice, setComputeUnitLimit) reads every v1 transaction as paying zero. On v1 the values live in message.transactionConfig, and the units differ: Do not port the legacy price × computeUnitLimit ÷ 1e6 math onto priorityFee. It is already the total.
priority-fee.ts
Branch on transactionConfig (or on version === 1) rather than on the presence of ComputeBudget instructions, since a legacy transaction with no priority fee also has none.

Decode raw transaction bytes with a v1-aware parser

This section only applies if you consume raw transaction bytes, for example from preconfSubscribe, preprocessedSubscribe, or a base64-encoded RPC response. If you work with json or jsonParsed responses, skip it. Transaction v1 changes the wire layout in two ways:
  • Version byte. A v1 transaction starts with 0x81 (decimal 129). A v0 transaction starts with 0x80.
  • Signatures move to the end. Legacy and v0 put signatures first, then the message. Transaction v1 puts the message first and the signatures last, so bincode-style decoders that expect a leading signature array fail on v1 bytes.
Byte-by-byte layout of a Solana transaction v1: version byte, header, config mask, lifetime specifier, address and instruction counts, three 32-byte addresses, compute unit config, instruction header, indices, discriminators, lamports, and a 64-byte signature at the end

Byte layout of a transaction v1 with three addresses and one instruction. The signature sits at the end, after the message.

For a field-by-field walkthrough of the v1 wire format, see Transaction v1 in the Solana transaction versions article. Use a decoder that understands the v1 layout:
  • Rust: agave-transaction-view parses legacy, v0, and v1 in place. wincode, the bincode-compatible serializer used by current Solana SDKs, also decodes v1 into VersionedTransaction.
  • JavaScript / TypeScript: @solana/kit 8.0+ or @solana/web3.js v3.
Custom decoders need to check the first byte: 0x81 means v1 and the signatures follow the message instead of preceding it.

Checklist

  1. Grep for getBlock, getTransaction, getTransactionsForAddress, transactionSubscribe, and blockSubscribe, including raw JSON-RPC bodies and SDK wrappers such as connection.getParsedTransaction.
  2. Upgrade to a v1-capable SDK.
  3. Set maxSupportedTransactionVersion: 1 on every call found in step 1.
  4. Replace ComputeBudget instruction scanning with a transactionConfig check, and treat priorityFee as total lamports.
  5. Replace bincode-style raw decoders with agave-transaction-view or an upgraded SDK.
  6. Bump streaming dependencies to the versions in the table above.
  7. Grep logs for -32015 after the change to confirm nothing still fails.
For a technical deep dive on Solana transaction version specifications, wire formats, and examples, read our article, Solana Transaction Versioning: Legacy, v0 and v1.

getTransaction guide

Parameters, response shape, and examples for fetching a single transaction.

getBlock guide

Fetch a full block, including every transaction it contains.

getTransactionsForAddress

Filtered, paginated transaction history for any address in one call.

Agave 4.2 migration checklist

Every Agave 4.2 breaking change, with remediation steps.