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
@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)
@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.
@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>>}
Deserialize a legacy transaction from binary.
@spec deserialize_message(binary()) :: {:ok, Signet.Solana.Transaction.Message.t(), binary()} | {:error, term()}
Deserialize a message from binary.
@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>>
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).
@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:
- User builds a message with the sponsor's pubkey as the fee payer
- User calls
sign_partial/2with their own seed to sign their position - User serializes the partially-signed transaction and sends it to the sponsor
- Sponsor deserializes and calls
add_signature/3to fill in their position - 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)