CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-solders

Python bindings for Solana Rust tools providing high-performance blockchain development primitives, RPC functionality, and testing infrastructure.

Pending
Overview
Eval results
Files

transaction-construction.mddocs/

Transaction Construction

Transaction and message building with support for both legacy and versioned formats. This includes instruction compilation, message construction, address lookup table integration, and transaction signing for efficient Solana blockchain interactions.

Capabilities

Transaction Types

Core transaction structures supporting both legacy and modern versioned formats with address lookup table compression.

class Transaction:
    """
    Legacy transaction format containing instructions and signatures.
    """
    def __init__(self, instructions: List[Instruction], payer: Optional[Pubkey]):
        """
        Create transaction with instructions and payer.
        
        Parameters:
        - instructions: List[Instruction], instructions to execute
        - payer: Optional[Pubkey], fee payer account
        """

    @staticmethod
    def new_with_payer(instructions: List[Instruction], payer: Optional[Pubkey]) -> 'Transaction':
        """
        Create new transaction with specified payer.
        
        Parameters:
        - instructions: List[Instruction], instructions to include
        - payer: Optional[Pubkey], account that pays transaction fees
        
        Returns:
        Transaction object
        """

    @staticmethod
    def new_unsigned(instructions: List[Instruction]) -> 'Transaction':
        """
        Create unsigned transaction without payer.
        
        Parameters:
        - instructions: List[Instruction], instructions to include
        
        Returns:
        Unsigned Transaction object
        """

    @staticmethod
    def new_with_compiled_instructions(
        num_required_signatures: int,
        num_readonly_signed_accounts: int,
        num_readonly_unsigned_accounts: int,
        account_keys: List[Pubkey],
        recent_blockhash: Hash,
        instructions: List[CompiledInstruction]
    ) -> 'Transaction':
        """
        Create transaction from pre-compiled instructions.
        
        Parameters:
        - num_required_signatures: int, number of signatures required
        - num_readonly_signed_accounts: int, readonly accounts that must sign
        - num_readonly_unsigned_accounts: int, readonly accounts (no signing)
        - account_keys: List[Pubkey], all accounts referenced in transaction
        - recent_blockhash: Hash, recent network blockhash
        - instructions: List[CompiledInstruction], compiled instructions
        
        Returns:
        Transaction object
        """

    def sign(self, signers: List[Union[Keypair, Presigner]], recent_blockhash: Hash) -> None:
        """
        Sign transaction with provided signers.
        
        Parameters:
        - signers: List of keypairs or presigners
        - recent_blockhash: Hash, recent network blockhash for replay protection
        """

    def partial_sign(self, signers: List[Union[Keypair, Presigner]], recent_blockhash: Hash) -> None:
        """
        Partially sign transaction (allows additional signatures later).
        
        Parameters:
        - signers: List of available signers (subset of required)
        - recent_blockhash: Hash, recent network blockhash
        """

    def verify(self) -> bool:
        """
        Verify all signatures in the transaction.
        
        Returns:
        bool, True if all signatures are valid
        """

    def serialize(self) -> bytes:
        """
        Serialize transaction to bytes for network transmission.
        
        Returns:
        bytes, serialized transaction
        """

    @classmethod
    def deserialize(cls, data: bytes) -> 'Transaction':
        """
        Deserialize transaction from bytes.
        
        Parameters:
        - data: bytes, serialized transaction data
        
        Returns:
        Transaction object
        """

    @property
    def message(self) -> Message:
        """Get the transaction message."""

    @property
    def signatures(self) -> List[Signature]:
        """Get transaction signatures."""
class VersionedTransaction:
    """
    Versioned transaction supporting address lookup tables for compression.
    """
    def __init__(self, message: VersionedMessage, signatures: List[Signature]):
        """
        Create versioned transaction with message and signatures.
        
        Parameters:
        - message: VersionedMessage, transaction message (legacy or v0)
        - signatures: List[Signature], transaction signatures
        """

    @staticmethod
    def new_unsigned(message: VersionedMessage) -> 'VersionedTransaction':
        """
        Create unsigned versioned transaction.
        
        Parameters:
        - message: VersionedMessage, transaction message
        
        Returns:
        Unsigned VersionedTransaction
        """

    def sign(self, signers: List[Union[Keypair, Presigner]]) -> None:
        """
        Sign versioned transaction.
        
        Parameters:
        - signers: List of keypairs or presigners
        """

    def serialize(self) -> bytes:
        """
        Serialize versioned transaction to bytes.
        
        Returns:
        bytes, serialized transaction
        """

    @classmethod
    def deserialize(cls, data: bytes) -> 'VersionedTransaction':
        """
        Deserialize versioned transaction from bytes.
        
        Parameters:
        - data: bytes, serialized transaction data
        
        Returns:
        VersionedTransaction object
        """

    @property
    def message(self) -> VersionedMessage:
        """Get the transaction message."""

    @property
    def signatures(self) -> List[Signature]:
        """Get transaction signatures."""

Message Construction

Message structures that contain instructions and account metadata for transaction execution.

class Message:
    """
    Legacy message format containing instructions and account metadata.
    """
    def __init__(
        self,
        header: MessageHeader,
        account_keys: List[Pubkey],
        recent_blockhash: Hash,
        instructions: List[CompiledInstruction]
    ):
        """
        Create message with header, accounts, blockhash, and instructions.
        
        Parameters:
        - header: MessageHeader, message metadata
        - account_keys: List[Pubkey], accounts referenced in message
        - recent_blockhash: Hash, recent network blockhash
        - instructions: List[CompiledInstruction], compiled instructions
        """

    @staticmethod
    def new_with_compiled_instructions(
        num_required_signatures: int,
        num_readonly_signed_accounts: int,
        num_readonly_unsigned_accounts: int,
        account_keys: List[Pubkey],
        recent_blockhash: Hash,
        instructions: List[CompiledInstruction]
    ) -> 'Message':
        """
        Create message from compiled instructions and metadata.
        
        Returns:
        Message object
        """

    @staticmethod
    def new_with_blockhash(instructions: List[Instruction], payer: Optional[Pubkey], blockhash: Hash) -> 'Message':
        """
        Create message from instructions with specified blockhash.
        
        Parameters:
        - instructions: List[Instruction], instructions to compile
        - payer: Optional[Pubkey], fee payer
        - blockhash: Hash, recent blockhash
        
        Returns:
        Message object
        """

    def serialize(self) -> bytes:
        """Serialize message to bytes."""

    @classmethod
    def deserialize(cls, data: bytes) -> 'Message':
        """Deserialize message from bytes."""

    def is_key_passed_to_program(self, key_index: int, program_id_index: int) -> bool:
        """
        Check if account key is passed to specific program.
        
        Parameters:
        - key_index: int, index of account key
        - program_id_index: int, index of program ID
        
        Returns:
        bool, True if key is passed to program
        """

    def is_key_called_as_program(self, key_index: int) -> bool:
        """
        Check if account key is called as program.
        
        Parameters:
        - key_index: int, index of account key
        
        Returns:
        bool, True if key is invoked as program
        """

    @property
    def header(self) -> MessageHeader:
        """Get message header."""

    @property
    def account_keys(self) -> List[Pubkey]:
        """Get account keys."""

    @property
    def recent_blockhash(self) -> Hash:
        """Get recent blockhash."""

    @property
    def instructions(self) -> List[CompiledInstruction]:
        """Get compiled instructions."""
class MessageV0:
    """
    Version 0 message with address lookup table support for compression.
    """
    def __init__(
        self,
        header: MessageHeader,
        account_keys: List[Pubkey],
        recent_blockhash: Hash,
        instructions: List[CompiledInstruction],
        address_table_lookups: List[MessageAddressTableLookup]
    ):
        """
        Create v0 message with address lookup tables.
        
        Parameters:
        - header: MessageHeader, message metadata
        - account_keys: List[Pubkey], static account keys
        - recent_blockhash: Hash, recent network blockhash
        - instructions: List[CompiledInstruction], compiled instructions
        - address_table_lookups: List[MessageAddressTableLookup], lookup table references
        """

    @staticmethod
    def try_compile(
        payer: Pubkey,
        instructions: List[Instruction],
        address_lookup_table_accounts: List[AddressLookupTableAccount],
        recent_blockhash: Hash
    ) -> 'MessageV0':
        """
        Compile instructions into v0 message using lookup tables.
        
        Parameters:
        - payer: Pubkey, fee payer account
        - instructions: List[Instruction], instructions to compile
        - address_lookup_table_accounts: List[AddressLookupTableAccount], available lookup tables
        - recent_blockhash: Hash, recent blockhash
        
        Returns:
        MessageV0 object
        
        Raises:
        - CompileError: if compilation fails
        """

    def serialize(self) -> bytes:
        """Serialize v0 message to bytes."""

    @classmethod
    def deserialize(cls, data: bytes) -> 'MessageV0':
        """Deserialize v0 message from bytes."""

    @property
    def address_table_lookups(self) -> List[MessageAddressTableLookup]:
        """Get address table lookups."""

Message Components

Supporting structures for message construction and metadata.

class MessageHeader:
    """
    Message header containing account signature and readonly counts.
    """
    def __init__(
        self,
        num_required_signatures: int,
        num_readonly_signed_accounts: int,
        num_readonly_unsigned_accounts: int
    ):
        """
        Create message header with account counts.
        
        Parameters:
        - num_required_signatures: int, total signatures required
        - num_readonly_signed_accounts: int, readonly accounts that must sign
        - num_readonly_unsigned_accounts: int, readonly accounts (no signing)
        """

    @property
    def num_required_signatures(self) -> int:
        """Number of signatures required."""

    @property
    def num_readonly_signed_accounts(self) -> int:
        """Number of readonly accounts that must sign."""

    @property
    def num_readonly_unsigned_accounts(self) -> int:
        """Number of readonly unsigned accounts."""
class MessageAddressTableLookup:
    """
    Reference to addresses from an address lookup table.
    """
    def __init__(
        self,
        account_key: Pubkey,
        writable_indexes: List[int],
        readonly_indexes: List[int]
    ):
        """
        Create address table lookup.
        
        Parameters:
        - account_key: Pubkey, address of lookup table account
        - writable_indexes: List[int], indexes of writable addresses
        - readonly_indexes: List[int], indexes of readonly addresses
        """

    @property
    def account_key(self) -> Pubkey:
        """Lookup table account address."""

    @property
    def writable_indexes(self) -> List[int]:
        """Writable address indexes."""

    @property
    def readonly_indexes(self) -> List[int]:
        """Readonly address indexes."""

Instruction Building

Individual instruction construction with program invocation and account specification.

class Instruction:
    """
    Transaction instruction containing program ID, accounts, and data.
    """
    def __init__(self, program_id: Pubkey, accounts: List[AccountMeta], data: bytes):
        """
        Create instruction with program, accounts, and data.
        
        Parameters:
        - program_id: Pubkey, program to invoke
        - accounts: List[AccountMeta], accounts required by instruction
        - data: bytes, instruction-specific data
        """

    @property
    def program_id(self) -> Pubkey:
        """Program to invoke."""

    @property
    def accounts(self) -> List[AccountMeta]:
        """Accounts required by instruction."""

    @property
    def data(self) -> bytes:
        """Instruction-specific data."""
class AccountMeta:
    """
    Account metadata specifying permissions and signing requirements.
    """
    def __init__(self, pubkey: Pubkey, is_signer: bool, is_writable: bool):
        """
        Create account metadata.
        
        Parameters:
        - pubkey: Pubkey, account address
        - is_signer: bool, whether account must sign transaction
        - is_writable: bool, whether account data may be modified
        """

    @staticmethod
    def new(pubkey: Pubkey, is_signer: bool) -> 'AccountMeta':
        """
        Create writable account metadata.
        
        Parameters:
        - pubkey: Pubkey, account address
        - is_signer: bool, whether account must sign
        
        Returns:
        Writable AccountMeta
        """

    @staticmethod
    def new_readonly(pubkey: Pubkey, is_signer: bool) -> 'AccountMeta':
        """
        Create readonly account metadata.
        
        Parameters:
        - pubkey: Pubkey, account address
        - is_signer: bool, whether account must sign
        
        Returns:
        Readonly AccountMeta
        """

    @property
    def pubkey(self) -> Pubkey:
        """Account address."""

    @property
    def is_signer(self) -> bool:
        """Whether account must sign."""

    @property
    def is_writable(self) -> bool:
        """Whether account may be modified."""
class CompiledInstruction:
    """
    Compiled instruction with account indexes instead of pubkeys.
    """
    def __init__(self, program_id_index: int, accounts: List[int], data: bytes):
        """
        Create compiled instruction.
        
        Parameters:
        - program_id_index: int, index of program ID in account keys
        - accounts: List[int], indexes of accounts in account keys
        - data: bytes, instruction data
        """

    @property
    def program_id_index(self) -> int:
        """Program ID index in account keys."""

    @property
    def accounts(self) -> List[int]:
        """Account indexes."""

    @property
    def data(self) -> bytes:
        """Instruction data."""

Version Management

Transaction version handling and type definitions.

class Legacy:
    """Transaction version marker for legacy format."""
    
# Type aliases for version handling
TransactionVersion = Union[Legacy, int]
VersionedMessage = Union[Message, MessageV0]

Usage Examples

Basic Transaction Creation

from solders.keypair import Keypair
from solders.pubkey import Pubkey
from solders.transaction import Transaction
from solders.instruction import Instruction, AccountMeta
from solders.hash import Hash

# Create keypairs
payer = Keypair()
recipient = Keypair()
program_id = Pubkey.from_string("11111111111111111111111111111112")

# Create instruction
accounts = [
    AccountMeta(payer.pubkey(), is_signer=True, is_writable=True),
    AccountMeta(recipient.pubkey(), is_signer=False, is_writable=True)
]
instruction = Instruction(program_id, accounts, b"instruction_data")

# Create and sign transaction
transaction = Transaction.new_with_payer([instruction], payer.pubkey())
recent_blockhash = Hash.from_string("11111111111111111111111111111112")
transaction.sign([payer], recent_blockhash)

# Serialize for transmission
serialized = transaction.serialize()

Versioned Transaction with Lookup Tables

from solders.transaction import VersionedTransaction
from solders.message import MessageV0
from solders.address_lookup_table_account import AddressLookupTableAccount

# Assume we have lookup table accounts loaded
lookup_tables = []  # List of AddressLookupTableAccount objects

# Compile v0 message
message_v0 = MessageV0.try_compile(
    payer=payer.pubkey(),
    instructions=[instruction],
    address_lookup_table_accounts=lookup_tables,
    recent_blockhash=recent_blockhash
)

# Create versioned transaction
versioned_tx = VersionedTransaction.new_unsigned(message_v0)
versioned_tx.sign([payer])

Multi-Instruction Transaction

from solders.system_program import transfer, TransferParams
from solders.compute_budget import set_compute_unit_limit

# Create multiple instructions
transfer_ix = transfer(TransferParams(
    from_pubkey=payer.pubkey(),
    to_pubkey=recipient.pubkey(),
    lamports=1000000
))

compute_budget_ix = set_compute_unit_limit(200000)

# Combine in transaction
multi_instruction_tx = Transaction.new_with_payer([
    compute_budget_ix,  # Always include compute budget first
    transfer_ix
], payer.pubkey())

multi_instruction_tx.sign([payer], recent_blockhash)

Partial Signing Workflow

# Create transaction requiring multiple signers
multi_signer_accounts = [
    AccountMeta(payer.pubkey(), is_signer=True, is_writable=True),
    AccountMeta(recipient.pubkey(), is_signer=True, is_writable=True),  # Also must sign
    AccountMeta(Pubkey.from_string("11111111111111111111111111111112"), is_signer=False, is_writable=False)
]

multi_signer_ix = Instruction(program_id, multi_signer_accounts, b"multi_signer_data")
multi_signer_tx = Transaction.new_with_payer([multi_signer_ix], payer.pubkey())

# Partial sign with available signers
multi_signer_tx.partial_sign([payer], recent_blockhash)

# Later, add remaining signatures
multi_signer_tx.partial_sign([recipient], recent_blockhash)

# Verify all signatures are present
assert multi_signer_tx.verify()

Message Serialization

from solders.message import Message, to_bytes_versioned, from_bytes_versioned

# Create message directly
message = Message.new_with_blockhash([instruction], payer.pubkey(), recent_blockhash)

# Serialize legacy message
message_bytes = message.serialize()

# Serialize versioned message
versioned_bytes = to_bytes_versioned(message)

# Deserialize versioned message
restored_message = from_bytes_versioned(versioned_bytes)

Signer Types

# Union type for all signer implementations
Signer = Union[Keypair, Presigner, NullSigner]

Different signer types provide flexibility for various signing scenarios:

  • Keypair: Standard Ed25519 keypair for direct signing
  • Presigner: Container for pre-computed signatures
  • NullSigner: No-op signer for simulation and readonly operations

Error Handling

Transaction Errors

class SanitizeError(Exception):
    """Transaction sanitization errors during construction or validation."""

class TransactionError(Exception):
    """General transaction processing errors."""

class CompileError(Exception):
    """Message compilation errors, especially with address lookup tables."""

Common error scenarios:

from solders.transaction import Transaction, SanitizeError
from solders.message import MessageV0, CompileError

try:
    # Invalid transaction construction
    invalid_tx = Transaction.new_with_payer([], None)  # No payer
except SanitizeError as e:
    print(f"Transaction sanitization failed: {e}")

try:
    # Message compilation failure
    message_v0 = MessageV0.try_compile(
        payer=payer.pubkey(),
        instructions=[],  # Empty instructions
        address_lookup_table_accounts=[],
        recent_blockhash=recent_blockhash
    )
except CompileError as e:
    print(f"Message compilation failed: {e}")

Install with Tessl CLI

npx tessl i tessl/pypi-solders

docs

account-management.md

cryptographic-primitives.md

error-handling.md

index.md

network-sysvars.md

rpc-functionality.md

system-programs.md

testing-infrastructure.md

token-operations.md

transaction-construction.md

transaction-status.md

tile.json