View Source Signet.Solana.Transaction (Signet v1.6.0)

Build, serialize, sign, and deserialize Solana transactions (legacy format).

A Solana transaction consists of signatures and a message. The message contains a header, ordered account keys, a recent blockhash, and compiled instructions. Each signer signs the raw serialized message bytes.

Example: Build and sign a SOL transfer

fee_payer = <<...>>  # 32-byte pubkey
recipient = <<...>>  # 32-byte pubkey
blockhash = <<...>>  # 32 bytes from getLatestBlockhash

instruction = Signet.Solana.SystemProgram.transfer(fee_payer, recipient, 1_000_000_000)

message = Signet.Solana.Transaction.build_message(fee_payer, [instruction], blockhash)
transaction = Signet.Solana.Transaction.sign(message, [fee_payer_seed])

# Serialize for RPC submission
bytes = Signet.Solana.Transaction.serialize(transaction)

Summary

Functions

Add a signature to a transaction at a specific signer position.

Build a compiled message from high-level instructions.

Decode a compact-u16 from the beginning of a binary.

Deserialize a legacy transaction from binary.

Deserialize a message from binary.

Encode a non-negative integer as a compact-u16 (variable-length).

Serialize a full transaction (signatures + message) for RPC submission.

Serialize a message to the bytes that get signed.

Sign a message with one or more seeds and produce a full transaction.

Partially sign a message, filling only the specified signer positions.

Types

@type t() :: %Signet.Solana.Transaction{
  message: Signet.Solana.Transaction.Message.t(),
  signatures: [<<_::512>>]
}

Functions

Link to this function

add_signature(transaction, index, arg)

View Source
@spec add_signature(t(), non_neg_integer(), <<_::512>>) :: t()

Add a signature to a transaction at a specific signer position.

Used to fill in a missing signature on a partially-signed transaction, typically by a sponsor or co-signer who receives the transaction from another party. See sign_partial/2 for the full sponsored transaction flow.

The index is the position in the signatures array (matching the account keys order in the message). The existing signature at that position is replaced.

Examples

# Sponsor receives a partially-signed transaction and adds their signature
{:ok, partial} = Transaction.deserialize(bytes_from_user)
msg_bytes = Transaction.serialize_message(partial.message)
sponsor_sig = :crypto.sign(:eddsa, :none, msg_bytes, [sponsor_seed, :ed25519])
full_trx = Transaction.add_signature(partial, 0, sponsor_sig)
Link to this function

build_message(arg1, instructions, arg2)

View Source
@spec build_message(
  <<_::256>>,
  [Signet.Solana.Transaction.Instruction.t()],
  <<_::256>>
) ::
  Signet.Solana.Transaction.Message.t()

Build a compiled message from high-level instructions.

Handles account deduplication, permission merging, ordering, and index compilation. The fee payer is always placed first as a writable signer.

Link to this function

decode_compact_u16(binary)

View Source
@spec decode_compact_u16(binary()) :: {non_neg_integer(), binary()}

Decode a compact-u16 from the beginning of a binary.

Returns {value, rest}.

Examples

iex> Signet.Solana.Transaction.decode_compact_u16(<<0, 99>>)
{0, <<99>>}

iex> Signet.Solana.Transaction.decode_compact_u16(<<128, 1, 99>>)
{128, <<99>>}
@spec deserialize(binary()) :: {:ok, t()} | {:error, term()}

Deserialize a legacy transaction from binary.

Link to this function

deserialize_message(arg)

View Source
@spec deserialize_message(binary()) ::
  {:ok, Signet.Solana.Transaction.Message.t(), binary()} | {:error, term()}

Deserialize a message from binary.

Link to this function

encode_compact_u16(value)

View Source
@spec encode_compact_u16(non_neg_integer()) :: binary()

Encode a non-negative integer as a compact-u16 (variable-length).

Examples

iex> Signet.Solana.Transaction.encode_compact_u16(0)
<<0>>

iex> Signet.Solana.Transaction.encode_compact_u16(127)
<<127>>

iex> Signet.Solana.Transaction.encode_compact_u16(128)
<<128, 1>>

iex> Signet.Solana.Transaction.encode_compact_u16(16384)
<<128, 128, 1>>
@spec serialize(t()) :: binary()

Serialize a full transaction (signatures + message) for RPC submission.

@spec serialize_message(Signet.Solana.Transaction.Message.t()) :: binary()

Serialize a message to the bytes that get signed.

@spec sign(Signet.Solana.Transaction.Message.t(), [<<_::256>>]) :: t()

Sign a message with one or more seeds and produce a full transaction.

Seeds must be ordered to match the signer positions in the message's account keys (i.e., the first num_required_signatures accounts).

Link to this function

sign_partial(message, signers)

View Source
@spec sign_partial(Signet.Solana.Transaction.Message.t(), %{
  required(non_neg_integer()) => <<_::256>>
}) ::
  t()

Partially sign a message, filling only the specified signer positions.

This is the core primitive for sponsored transactions (where one party pays fees on behalf of another). The typical flow is:

  1. User builds a message with the sponsor's pubkey as the fee payer
  2. User calls sign_partial/2 with their own seed to sign their position
  3. User serializes the partially-signed transaction and sends it to the sponsor
  4. Sponsor deserializes and calls add_signature/3 to fill in their position
  5. Sponsor submits the fully-signed transaction via Signet.Solana.RPC.send_transaction/2

signers is a map of %{account_index => seed} where account_index is the position of the signer in the message's account keys list (0-based). Positions not present in the map get zero-filled placeholder signatures.

Examples

# User is account[1], sponsor is account[0] (fee payer)
partial = Transaction.sign_partial(message, %{1 => user_seed})
# => %Transaction{signatures: [<<0::512>>, <user_sig>], ...}

# Serialize and send to sponsor
bytes = Transaction.serialize(partial)