Calculating the Signed Transaction Hash
When working with the Aptos, you may want to retrieve a transaction from the blockchain immediately after submitting it. To do this, you need the signed transaction hash (also known as tx_hash
), which uniquely identifies the transaction on-chain.
While the Aptos REST API returns the transaction hash after submission, some developers may want to precompute it (e.g., for optimistic UIs, monitoring, or debugging purposes). This guide explains how to accurately compute the hash of a signed transaction.
Here is the installation link for the SDK we will use in this example:
To test this example you can try it after your first transaction
Process overview
Aptos uses a specific flow to generate the transaction hash:
- Serialize the signed transaction using Binary Canonical Serialization (BCS).
- Prepend a domain-specific prefix.
- Hash the resulting bytes using SHA3-256.
Without proper serialization and prefixing, your calculated hash may not match the one on-chain.
Code to Calculate the Transaction Hash
Step 1: Serialize the signed transaction
We first convert the transaction data into a standardized binary format using Binary Canonical Serialization (BCS). This ensures consistent representation across different platforms.
serializer = Serializer()
signed_txn.serialize(serializer)
bcs_bytes = serializer.output()
Step 2: Create the domain separator hash
A domain separator adds context to prevent hash collisions between different types of data. We create a hash of the string “APTOS::Transaction”.
domain_separator = b"APTOS::Transaction"
prefix_hash = hashlib.sha3_256(domain_separator).digest()
Step 3: Add the transaction variant
Different transaction types are identified by variant bytes. For user transactions, this is 0
.
user_transaction_variant = bytes([0])
Step 4: Create the final hash
We combine all components and generate the SHA3-256 hash.
hash_input = prefix_hash + user_transaction_variant + bcs_bytes
hash_bytes = hashlib.sha3_256(hash_input).digest()
Step 5: Format the result
Convert the binary hash to a hexadecimal string with a “0x” prefix.
tx_hash = "0x" + hash_bytes.hex()
Step 6: Full code block
import hashlib
from aptos_sdk.transactions import SignedTransaction
from aptos_sdk.bcs import Serializer
def get_transaction_hash(signed_txn: SignedTransaction) -> str:
# Step 1: Serialize the signed transaction using BCS
serializer = Serializer()
signed_txn.serialize(serializer)
bcs_bytes = serializer.output()
# Step 2: Prepare the domain-specific prefix hash
domain_separator = b"APTOS::Transaction"
prefix_hash = hashlib.sha3_256(domain_separator).digest()
# Step 3: Prepend the variant byte for UserTransaction (0)
user_transaction_variant = bytes([0])
# Step 4: Concatenate all pieces and hash
hash_input = prefix_hash + user_transaction_variant + bcs_bytes
hash_bytes = hashlib.sha3_256(hash_input).digest()
# Step 5: Convert to hexadecimal string with '0x' prefix
tx_hash = "0x" + hash_bytes.hex()
return tx_hash