Skip to content

Transaction

solana.transaction

Library to package an atomic sequence of instructions to a transaction.

PACKET_DATA_SIZE

Constant for maximum over-the-wire size of a Transaction.

NonceInformation

NonceInformation to be used to build a Transaction.

Source code in solana/transaction.py
class NonceInformation(NamedTuple):
    """NonceInformation to be used to build a Transaction."""

    nonce: Blockhash
    """The current Nonce blockhash."""
    nonce_instruction: Instruction
    """AdvanceNonceAccount Instruction."""

nonce: Hash

The current Nonce blockhash.

nonce_instruction: Instruction

AdvanceNonceAccount Instruction.

Transaction

Transaction class to represent an atomic transaction.

Parameters:

Name Type Description Default
recent_blockhash Optional[Blockhash]

A recent transaction id.

None
nonce_info Optional[NonceInformation]

Nonce information. If populated, transaction will use a durable Nonce hash instead of a recent_blockhash.

None
fee_payer Optional[Pubkey]

The transaction fee payer.

None
instructions Optional[Sequence[Instruction]]

The instructions to be executed in this transaction.

None
Source code in solana/transaction.py
class Transaction:
    """Transaction class to represent an atomic transaction.

    Args:
        recent_blockhash: A recent transaction id.
        nonce_info: Nonce information.
            If populated, transaction will use a durable Nonce hash instead of a `recent_blockhash`.
        fee_payer: The transaction fee payer.
        instructions: The instructions to be executed in this transaction.
    """

    # Default (empty) signature
    __DEFAULT_SIG = bytes(64)

    def __init__(
        self,
        recent_blockhash: Optional[Blockhash] = None,
        nonce_info: Optional[NonceInformation] = None,
        fee_payer: Optional[Pubkey] = None,
        instructions: Optional[Sequence[Instruction]] = None,
    ) -> None:
        """Init transaction object."""
        self._solders = _build_solders_tx(
            recent_blockhash=recent_blockhash,
            nonce_info=nonce_info,
            fee_payer=fee_payer,
            instructions=instructions,
        )

    @classmethod
    def from_solders(cls, txn: SoldersTx) -> Transaction:
        """Convert from a `solders` transaction.

        Args:
            txn: The `solders` transaction.

        Returns:
            The `solana-py` transaction.
        """
        new_tx = cls()
        new_tx._solders = txn
        return new_tx

    def to_solders(self) -> SoldersTx:
        """Convert to a `solders` transaction.

        Returns:
            The `solders` transaction.
        """
        return self._solders

    def __eq__(self, other: Any) -> bool:
        """Equality defintion for Transactions."""
        if not isinstance(other, Transaction):
            return False
        return self.to_solders() == other.to_solders()

    @property
    def recent_blockhash(self) -> Optional[Blockhash]:
        """Optional[Blockhash]: The blockhash assigned to this transaction."""
        return self._solders.message.recent_blockhash

    @recent_blockhash.setter
    def recent_blockhash(self, blockhash: Optional[Blockhash]) -> None:  # noqa: D102
        self._solders = _build_solders_tx(
            recent_blockhash=blockhash,
            nonce_info=None,
            fee_payer=self.fee_payer,
            instructions=self.instructions,
        )

    @property
    def fee_payer(self) -> Optional[Pubkey]:
        """Optional[Pubkey]: The transaction fee payer."""
        account_keys = self._solders.message.account_keys
        return account_keys[0] if account_keys else None

    @fee_payer.setter
    def fee_payer(self, payer: Optional[Pubkey]) -> None:  # noqa: D102
        self._solders = _build_solders_tx(
            recent_blockhash=self.recent_blockhash,
            nonce_info=None,
            fee_payer=payer,
            instructions=self.instructions,
        )

    @property
    def instructions(self) -> Tuple[Instruction, ...]:
        """Tuple[Instruction]: The instructions contained in this transaction."""
        msg = self._solders.message
        return tuple(_decompile_instructions(msg))

    @instructions.setter
    def instructions(self, ixns: Sequence[Instruction]) -> None:  # noqa: D102
        self._solders = _build_solders_tx(
            recent_blockhash=self.recent_blockhash,
            nonce_info=None,
            fee_payer=self.fee_payer,
            instructions=ixns,
        )

    @property
    def signatures(self) -> Tuple[Signature, ...]:
        """Tuple[Signature]: Signatures for the transaction."""
        return tuple(self._solders.signatures)

    def signature(self) -> Signature:
        """The first (payer) Transaction signature.

        Returns:
            The payer signature.
        """
        return self._solders.signatures[0]

    def add(self, *args: Union[Transaction, Instruction]) -> Transaction:
        """Add one or more instructions to this Transaction.

        Args:
            *args: The instructions to add to this Transaction.
                If a `Transaction` is passsed, the instructions will be extracted from it.

        Returns:
            The transaction with the added instructions.
        """
        for arg in args:
            if isinstance(arg, Transaction):
                self.instructions = self.instructions + arg.instructions
            elif isinstance(arg, Instruction):
                self.instructions = (*self.instructions, arg)
            else:
                raise ValueError("invalid instruction:", arg)

        return self

    def compile_message(self) -> Message:  # pylint: disable=too-many-locals
        """Compile transaction data.

        Returns:
            The compiled message.
        """
        return self._solders.message

    def serialize_message(self) -> bytes:
        """Get raw transaction data that need to be covered by signatures.

        Returns:
            The serialized message.
        """
        return bytes(self.compile_message())

    def sign_partial(self, *partial_signers: Keypair) -> None:
        """Partially sign a Transaction with the specified keypairs.

        All the caveats from the `sign` method apply to `sign_partial`
        """
        self._solders.partial_sign(partial_signers, self._solders.message.recent_blockhash)

    def sign(self, *signers: Keypair) -> None:
        """Sign the Transaction with the specified accounts.

        Multiple signatures may be applied to a Transaction. The first signature
        is considered "primary" and is used when testing for Transaction confirmation.

        Transaction fields should not be modified after the first call to `sign`,
        as doing so may invalidate the signature and cause the Transaction to be
        rejected.

        The Transaction must be assigned a valid `recent_blockhash` before invoking this method.
        """
        self._solders.sign(signers, self._solders.message.recent_blockhash)

    def add_signature(self, pubkey: Pubkey, signature: Signature) -> None:
        """Add an externally created signature to a transaction.

        Args:
            pubkey: The public key that created the signature.
            signature: The signature to add.
        """
        presigner = Presigner(pubkey, signature)
        self._solders.partial_sign([presigner], self._solders.message.recent_blockhash)

    def verify_signatures(self) -> bool:
        """Verify signatures of a complete, signed Transaction.

        Returns:
            a bool indicating if the signatures are correct or not.
        """
        try:
            self._solders.verify()
        except TransactionError:
            return False
        return True

    def serialize(self, verify_signatures: bool = True) -> bytes:
        """Serialize the Transaction in the wire format.

        The Transaction must have a valid `signature` before invoking this method.
        verify_signatures can be added if the signature does not require to be verified.

        Args:
            verify_signatures: a bool indicating to verify the signature or not. Defaults to True

        Example:
            >>> from solders.keypair import Keypair
            >>> from solders.pubkey import Pubkey
            >>> from solders.hash import Hash
            >>> from solders.system_program import transfer, TransferParams
            >>> leading_zeros = [0] * 31
            >>> seed = bytes(leading_zeros + [1])
            >>> sender, receiver = Keypair.from_seed(seed), Pubkey(leading_zeros + [2])
            >>> transfer_tx = Transaction().add(transfer(TransferParams(from_pubkey=sender.pubkey(), to_pubkey=receiver, lamports=1000)))
            >>> transfer_tx.recent_blockhash = Hash(leading_zeros + [3])
            >>> transfer_tx.sign(sender)
            >>> transfer_tx.serialize().hex()
            '019d53be8af3a7c30f86c1092d2c3ea61d270c0cfa275a23ba504674c8fbbb724827b23b42dc8e08019e23120f1b6f40f9799355ce54185b4415be37ca2cee6e0e010001034cb5abf6ad79fbf5abbccafcc269d85cd2651ed4b885b5869f241aedf0a5ba2900000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000301020200010c02000000e803000000000000'

        Returns:
            The serialized transaction.
        """  # noqa: E501 pylint: disable=line-too-long
        if self.signatures == [Signature.default() for sig in self.signatures]:
            raise AttributeError("transaction has not been signed")

        if verify_signatures and not self.verify_signatures():
            raise AttributeError("transaction has not been signed correctly")

        return bytes(self._solders)

    @classmethod
    def deserialize(cls, raw_transaction: bytes) -> Transaction:
        """Parse a wire transaction into a Transaction object.

        Example:
            >>> raw_transaction = bytes.fromhex(
            ...     '019d53be8af3a7c30f86c1092d2c3ea61d270c0cfa2'
            ...     '75a23ba504674c8fbbb724827b23b42dc8e08019e23'
            ...     '120f1b6f40f9799355ce54185b4415be37ca2cee6e0'
            ...     'e010001034cb5abf6ad79fbf5abbccafcc269d85cd2'
            ...     '651ed4b885b5869f241aedf0a5ba290000000000000'
            ...     '0000000000000000000000000000000000000000000'
            ...     '0000000200000000000000000000000000000000000'
            ...     '0000000000000000000000000000000000000000000'
            ...     '0000000000000000000000000000000000000000000'
            ...     '000000301020200010c02000000e803000000000000'
            ... )
            >>> type(Transaction.deserialize(raw_transaction))
            <class 'solana.transaction.Transaction'>

        Returns:
            The deserialized transaction.
        """
        return cls.from_solders(SoldersTx.from_bytes(raw_transaction))

    @classmethod
    def populate(cls, message: Message, signatures: List[Signature]) -> Transaction:
        """Populate Transaction object from message and signatures.

        Example:
            >>> raw_message = bytes.fromhex(
            ...     '0200030500000000000000000000000000000000000000000000'
            ...     '0000000000000000000100000000000000000000000000000000'
            ...     '0000000000000000000000000000000200000000000000000000'
            ...     '0000000000000000000000000000000000000000000300000000'
            ...     '0000000000000000000000000000000000000000000000000000'
            ...     '0004000000000000000000000000000000000000000000000000'
            ...     '0000000000000005c49ae77603782054f17a9decea43b444eba0'
            ...     'edb12c6f1d31c6e0e4a84bf052eb010403010203050909090909'
            ... )
            >>> from solders.message import Message
            >>> from solders.signature import Signature
            >>> msg = Message.from_bytes(raw_message)
            >>> signatures = [Signature(bytes([1] * Signature.LENGTH)), Signature(bytes([2] * Signature.LENGTH))]
            >>> type(Transaction.populate(msg, signatures))
            <class 'solana.transaction.Transaction'>

        Returns:
            The populated transaction.
        """
        return cls.from_solders(SoldersTx.populate(message, signatures))

fee_payer: Optional[Pubkey] property writable

Optional[Pubkey]: The transaction fee payer.

instructions: Tuple[Instruction, ...] property writable

Tuple[Instruction]: The instructions contained in this transaction.

recent_blockhash: Optional[Blockhash] property writable

Optional[Blockhash]: The blockhash assigned to this transaction.

signatures: Tuple[Signature, ...] property readonly

Tuple[Signature]: Signatures for the transaction.

__init__(self, recent_blockhash=None, nonce_info=None, fee_payer=None, instructions=None) special

Init transaction object.

Source code in solana/transaction.py
def __init__(
    self,
    recent_blockhash: Optional[Blockhash] = None,
    nonce_info: Optional[NonceInformation] = None,
    fee_payer: Optional[Pubkey] = None,
    instructions: Optional[Sequence[Instruction]] = None,
) -> None:
    """Init transaction object."""
    self._solders = _build_solders_tx(
        recent_blockhash=recent_blockhash,
        nonce_info=nonce_info,
        fee_payer=fee_payer,
        instructions=instructions,
    )

add(self, *args)

Add one or more instructions to this Transaction.

Parameters:

Name Type Description Default
*args Union[Transaction, Instruction]

The instructions to add to this Transaction. If a Transaction is passsed, the instructions will be extracted from it.

()

Returns:

Type Description
Transaction

The transaction with the added instructions.

Source code in solana/transaction.py
def add(self, *args: Union[Transaction, Instruction]) -> Transaction:
    """Add one or more instructions to this Transaction.

    Args:
        *args: The instructions to add to this Transaction.
            If a `Transaction` is passsed, the instructions will be extracted from it.

    Returns:
        The transaction with the added instructions.
    """
    for arg in args:
        if isinstance(arg, Transaction):
            self.instructions = self.instructions + arg.instructions
        elif isinstance(arg, Instruction):
            self.instructions = (*self.instructions, arg)
        else:
            raise ValueError("invalid instruction:", arg)

    return self

add_signature(self, pubkey, signature)

Add an externally created signature to a transaction.

Parameters:

Name Type Description Default
pubkey Pubkey

The public key that created the signature.

required
signature Signature

The signature to add.

required
Source code in solana/transaction.py
def add_signature(self, pubkey: Pubkey, signature: Signature) -> None:
    """Add an externally created signature to a transaction.

    Args:
        pubkey: The public key that created the signature.
        signature: The signature to add.
    """
    presigner = Presigner(pubkey, signature)
    self._solders.partial_sign([presigner], self._solders.message.recent_blockhash)

compile_message(self)

Compile transaction data.

Returns:

Type Description
Message

The compiled message.

Source code in solana/transaction.py
def compile_message(self) -> Message:  # pylint: disable=too-many-locals
    """Compile transaction data.

    Returns:
        The compiled message.
    """
    return self._solders.message

deserialize(raw_transaction) classmethod

Parse a wire transaction into a Transaction object.

Examples:

>>> raw_transaction = bytes.fromhex(
...     '019d53be8af3a7c30f86c1092d2c3ea61d270c0cfa2'
...     '75a23ba504674c8fbbb724827b23b42dc8e08019e23'
...     '120f1b6f40f9799355ce54185b4415be37ca2cee6e0'
...     'e010001034cb5abf6ad79fbf5abbccafcc269d85cd2'
...     '651ed4b885b5869f241aedf0a5ba290000000000000'
...     '0000000000000000000000000000000000000000000'
...     '0000000200000000000000000000000000000000000'
...     '0000000000000000000000000000000000000000000'
...     '0000000000000000000000000000000000000000000'
...     '000000301020200010c02000000e803000000000000'
... )
>>> type(Transaction.deserialize(raw_transaction))
<class 'solana.transaction.Transaction'>

Returns:

Type Description
Transaction

The deserialized transaction.

Source code in solana/transaction.py
@classmethod
def deserialize(cls, raw_transaction: bytes) -> Transaction:
    """Parse a wire transaction into a Transaction object.

    Example:
        >>> raw_transaction = bytes.fromhex(
        ...     '019d53be8af3a7c30f86c1092d2c3ea61d270c0cfa2'
        ...     '75a23ba504674c8fbbb724827b23b42dc8e08019e23'
        ...     '120f1b6f40f9799355ce54185b4415be37ca2cee6e0'
        ...     'e010001034cb5abf6ad79fbf5abbccafcc269d85cd2'
        ...     '651ed4b885b5869f241aedf0a5ba290000000000000'
        ...     '0000000000000000000000000000000000000000000'
        ...     '0000000200000000000000000000000000000000000'
        ...     '0000000000000000000000000000000000000000000'
        ...     '0000000000000000000000000000000000000000000'
        ...     '000000301020200010c02000000e803000000000000'
        ... )
        >>> type(Transaction.deserialize(raw_transaction))
        <class 'solana.transaction.Transaction'>

    Returns:
        The deserialized transaction.
    """
    return cls.from_solders(SoldersTx.from_bytes(raw_transaction))

from_solders(txn) classmethod

Convert from a solders transaction.

Parameters:

Name Type Description Default
txn SoldersTx

The solders transaction.

required

Returns:

Type Description
Transaction

The solana-py transaction.

Source code in solana/transaction.py
@classmethod
def from_solders(cls, txn: SoldersTx) -> Transaction:
    """Convert from a `solders` transaction.

    Args:
        txn: The `solders` transaction.

    Returns:
        The `solana-py` transaction.
    """
    new_tx = cls()
    new_tx._solders = txn
    return new_tx

populate(message, signatures) classmethod

Populate Transaction object from message and signatures.

Examples:

>>> raw_message = bytes.fromhex(
...     '0200030500000000000000000000000000000000000000000000'
...     '0000000000000000000100000000000000000000000000000000'
...     '0000000000000000000000000000000200000000000000000000'
...     '0000000000000000000000000000000000000000000300000000'
...     '0000000000000000000000000000000000000000000000000000'
...     '0004000000000000000000000000000000000000000000000000'
...     '0000000000000005c49ae77603782054f17a9decea43b444eba0'
...     'edb12c6f1d31c6e0e4a84bf052eb010403010203050909090909'
... )
>>> from solders.message import Message
>>> from solders.signature import Signature
>>> msg = Message.from_bytes(raw_message)
>>> signatures = [Signature(bytes([1] * Signature.LENGTH)), Signature(bytes([2] * Signature.LENGTH))]
>>> type(Transaction.populate(msg, signatures))
<class 'solana.transaction.Transaction'>

Returns:

Type Description
Transaction

The populated transaction.

Source code in solana/transaction.py
@classmethod
def populate(cls, message: Message, signatures: List[Signature]) -> Transaction:
    """Populate Transaction object from message and signatures.

    Example:
        >>> raw_message = bytes.fromhex(
        ...     '0200030500000000000000000000000000000000000000000000'
        ...     '0000000000000000000100000000000000000000000000000000'
        ...     '0000000000000000000000000000000200000000000000000000'
        ...     '0000000000000000000000000000000000000000000300000000'
        ...     '0000000000000000000000000000000000000000000000000000'
        ...     '0004000000000000000000000000000000000000000000000000'
        ...     '0000000000000005c49ae77603782054f17a9decea43b444eba0'
        ...     'edb12c6f1d31c6e0e4a84bf052eb010403010203050909090909'
        ... )
        >>> from solders.message import Message
        >>> from solders.signature import Signature
        >>> msg = Message.from_bytes(raw_message)
        >>> signatures = [Signature(bytes([1] * Signature.LENGTH)), Signature(bytes([2] * Signature.LENGTH))]
        >>> type(Transaction.populate(msg, signatures))
        <class 'solana.transaction.Transaction'>

    Returns:
        The populated transaction.
    """
    return cls.from_solders(SoldersTx.populate(message, signatures))

serialize(self, verify_signatures=True)

Serialize the Transaction in the wire format.

The Transaction must have a valid signature before invoking this method. verify_signatures can be added if the signature does not require to be verified.

Parameters:

Name Type Description Default
verify_signatures bool

a bool indicating to verify the signature or not. Defaults to True

True

Examples:

>>> from solders.keypair import Keypair
>>> from solders.pubkey import Pubkey
>>> from solders.hash import Hash
>>> from solders.system_program import transfer, TransferParams
>>> leading_zeros = [0] * 31
>>> seed = bytes(leading_zeros + [1])
>>> sender, receiver = Keypair.from_seed(seed), Pubkey(leading_zeros + [2])
>>> transfer_tx = Transaction().add(transfer(TransferParams(from_pubkey=sender.pubkey(), to_pubkey=receiver, lamports=1000)))
>>> transfer_tx.recent_blockhash = Hash(leading_zeros + [3])
>>> transfer_tx.sign(sender)
>>> transfer_tx.serialize().hex()
'019d53be8af3a7c30f86c1092d2c3ea61d270c0cfa275a23ba504674c8fbbb724827b23b42dc8e08019e23120f1b6f40f9799355ce54185b4415be37ca2cee6e0e010001034cb5abf6ad79fbf5abbccafcc269d85cd2651ed4b885b5869f241aedf0a5ba2900000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000301020200010c02000000e803000000000000'

Returns:

Type Description
bytes

The serialized transaction.

Source code in solana/transaction.py
def serialize(self, verify_signatures: bool = True) -> bytes:
    """Serialize the Transaction in the wire format.

    The Transaction must have a valid `signature` before invoking this method.
    verify_signatures can be added if the signature does not require to be verified.

    Args:
        verify_signatures: a bool indicating to verify the signature or not. Defaults to True

    Example:
        >>> from solders.keypair import Keypair
        >>> from solders.pubkey import Pubkey
        >>> from solders.hash import Hash
        >>> from solders.system_program import transfer, TransferParams
        >>> leading_zeros = [0] * 31
        >>> seed = bytes(leading_zeros + [1])
        >>> sender, receiver = Keypair.from_seed(seed), Pubkey(leading_zeros + [2])
        >>> transfer_tx = Transaction().add(transfer(TransferParams(from_pubkey=sender.pubkey(), to_pubkey=receiver, lamports=1000)))
        >>> transfer_tx.recent_blockhash = Hash(leading_zeros + [3])
        >>> transfer_tx.sign(sender)
        >>> transfer_tx.serialize().hex()
        '019d53be8af3a7c30f86c1092d2c3ea61d270c0cfa275a23ba504674c8fbbb724827b23b42dc8e08019e23120f1b6f40f9799355ce54185b4415be37ca2cee6e0e010001034cb5abf6ad79fbf5abbccafcc269d85cd2651ed4b885b5869f241aedf0a5ba2900000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000301020200010c02000000e803000000000000'

    Returns:
        The serialized transaction.
    """  # noqa: E501 pylint: disable=line-too-long
    if self.signatures == [Signature.default() for sig in self.signatures]:
        raise AttributeError("transaction has not been signed")

    if verify_signatures and not self.verify_signatures():
        raise AttributeError("transaction has not been signed correctly")

    return bytes(self._solders)

serialize_message(self)

Get raw transaction data that need to be covered by signatures.

Returns:

Type Description
bytes

The serialized message.

Source code in solana/transaction.py
def serialize_message(self) -> bytes:
    """Get raw transaction data that need to be covered by signatures.

    Returns:
        The serialized message.
    """
    return bytes(self.compile_message())

sign(self, *signers)

Sign the Transaction with the specified accounts.

Multiple signatures may be applied to a Transaction. The first signature is considered "primary" and is used when testing for Transaction confirmation.

Transaction fields should not be modified after the first call to sign, as doing so may invalidate the signature and cause the Transaction to be rejected.

The Transaction must be assigned a valid recent_blockhash before invoking this method.

Source code in solana/transaction.py
def sign(self, *signers: Keypair) -> None:
    """Sign the Transaction with the specified accounts.

    Multiple signatures may be applied to a Transaction. The first signature
    is considered "primary" and is used when testing for Transaction confirmation.

    Transaction fields should not be modified after the first call to `sign`,
    as doing so may invalidate the signature and cause the Transaction to be
    rejected.

    The Transaction must be assigned a valid `recent_blockhash` before invoking this method.
    """
    self._solders.sign(signers, self._solders.message.recent_blockhash)

sign_partial(self, *partial_signers)

Partially sign a Transaction with the specified keypairs.

All the caveats from the sign method apply to sign_partial

Source code in solana/transaction.py
def sign_partial(self, *partial_signers: Keypair) -> None:
    """Partially sign a Transaction with the specified keypairs.

    All the caveats from the `sign` method apply to `sign_partial`
    """
    self._solders.partial_sign(partial_signers, self._solders.message.recent_blockhash)

signature(self)

The first (payer) Transaction signature.

Returns:

Type Description
Signature

The payer signature.

Source code in solana/transaction.py
def signature(self) -> Signature:
    """The first (payer) Transaction signature.

    Returns:
        The payer signature.
    """
    return self._solders.signatures[0]

to_solders(self)

Convert to a solders transaction.

Returns:

Type Description
SoldersTx

The solders transaction.

Source code in solana/transaction.py
def to_solders(self) -> SoldersTx:
    """Convert to a `solders` transaction.

    Returns:
        The `solders` transaction.
    """
    return self._solders

verify_signatures(self)

Verify signatures of a complete, signed Transaction.

Returns:

Type Description
bool

a bool indicating if the signatures are correct or not.

Source code in solana/transaction.py
def verify_signatures(self) -> bool:
    """Verify signatures of a complete, signed Transaction.

    Returns:
        a bool indicating if the signatures are correct or not.
    """
    try:
        self._solders.verify()
    except TransactionError:
        return False
    return True