Solana KitSolana Kit Docs
openbudgetfun/solana_kit ★9999⑂99

Build a Transaction

Assemble a transaction message with a fee payer, a lifetime, and one or more instructions.

Solana Kit models transaction construction as a sequence of immutable transformations. This keeps the transaction pipeline easy to inspect and test.

Build a transaction message#

Transaction messages are assembled incrementally. The most common pattern is:

  1. Create an empty message.
  2. Set the fee payer.
  3. Set a lifetime constraint using a recent blockhash.
  4. Append one or more instructions.
import 'dart:typed_data';

import 'package:solana_kit/solana_kit.dart';

Future<void> main() async {
  final rpc = createSolanaRpc(url: 'https://api.devnet.solana.com');
  final feePayer = generateKeyPairSigner();
  final latestBlockhash = await rpc.getLatestBlockhashValue().send();

  final instruction = Instruction(
    programAddress: const Address('11111111111111111111111111111111'),
    accounts: [
      AccountMeta(
        address: feePayer.address,
        role: AccountRole.writableSigner,
      ),
    ],
    data: Uint8List(0),
  );

  final message = createTransactionMessage(version: TransactionVersion.v0)
      .withFeePayer(feePayer.address)
      .withBlockhashLifetime(
        BlockhashLifetimeConstraint(
          blockhash: latestBlockhash.value.blockhash.value,
          lastValidBlockHeight: latestBlockhash.value.lastValidBlockHeight,
        ),
      )
      .appendInstruction(instruction);

  print(message);
}

This separation keeps transaction construction explicit and makes it easier to reason about fee payment, expiry, and instruction ordering. If you prefer a more fluent style, the transaction-message extension methods build on the same underlying model.

Why the lifetime constraint matters#

Without a recent blockhash or a durable nonce, the network cannot determine whether a transaction is still valid. Solana Kit makes lifetime setup explicit so expiry handling is not hidden behind a large helper.

Blockhash-based lifetime#

Use BlockhashLifetimeConstraint for the common case.

Durable nonce lifetime#

Use setTransactionMessageLifetimeUsingDurableNonce(...) when the transaction must remain valid until a nonce account changes.

Compile the message#

Once the message is fully assembled, compile it into the wire-level message representation:

final compiledMessage = compileTransactionMessage(message);

At this stage you have a canonical message layout that can be signed and serialized.

Next steps#