eth_getTransactionByHash
Returns information about a transaction requested by transaction hash. Essential for tracking transaction status and details.
When to Use This Method​
eth_getTransactionByHash
is crucial for:
- Transaction Tracking - Monitor transaction status after submission
- Payment Verification - Confirm payment details and recipients
- Transaction Explorers - Build transaction detail pages
- Debugging - Investigate failed or stuck transactions
Parameters​
- Transaction Hash -
DATA
, 32 Bytes- Hash of the transaction to retrieve
- Format:
0x
followed by 64 hexadecimal characters
{
"jsonrpc": "2.0",
"method": "eth_getTransactionByHash",
"params": [
"0x88df016429689c079f3b2f6ad39fa052532c56795b733da78a91ebe6a713944b"
],
"id": 1
}
Returns​
Object
- Transaction object, or null
when no transaction was found:
blockHash
- Hash of the block containing this transactionblockNumber
- Block number containing this transactionfrom
- Address of the sendergas
- Gas provided by the sendergasPrice
- Gas price in weimaxFeePerGas
- Maximum fee per gas (EIP-1559)maxPriorityFeePerGas
- Maximum priority fee per gas (EIP-1559)hash
- Transaction hashinput
- Input data sent with transactionnonce
- Number of transactions from senderto
- Receiver address (null for contract creation)transactionIndex
- Position in the blockvalue
- Value transferred in weitype
- Transaction type (0x0, 0x1, 0x2)v
,r
,s
- Signature values
Implementation Examples​
- JavaScript
- Python
import { JsonRpcProvider } from 'ethers';
const provider = new JsonRpcProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY');
// Transaction tracking system
class TransactionTracker {
constructor(provider) {
this.provider = provider;
this.cache = new Map();
}
async getTransaction(txHash) {
// Check cache first
if (this.cache.has(txHash)) {
const cached = this.cache.get(txHash);
if (Date.now() - cached.timestamp < 5000) {
return cached.data;
}
}
// Fetch transaction
const tx = await this.provider.getTransaction(txHash);
if (!tx) {
return { status: 'not_found' };
}
// Cache the result
const result = {
hash: tx.hash,
from: tx.from,
to: tx.to,
value: tx.value.toString(),
gasPrice: tx.gasPrice?.toString(),
gasLimit: tx.gasLimit.toString(),
nonce: tx.nonce,
data: tx.data,
blockNumber: tx.blockNumber,
blockHash: tx.blockHash,
confirmations: tx.confirmations,
status: tx.blockNumber ? 'confirmed' : 'pending',
type: tx.type,
maxFeePerGas: tx.maxFeePerGas?.toString(),
maxPriorityFeePerGas: tx.maxPriorityFeePerGas?.toString()
};
this.cache.set(txHash, {
data: result,
timestamp: Date.now()
});
return result;
}
async waitForConfirmation(txHash, confirmations = 1, timeout = 60000) {
const startTime = Date.now();
while (Date.now() - startTime < timeout) {
const tx = await this.getTransaction(txHash);
if (tx.status === 'not_found') {
await new Promise(resolve => setTimeout(resolve, 2000));
continue;
}
if (tx.confirmations >= confirmations) {
return tx;
}
await new Promise(resolve => setTimeout(resolve, 2000));
}
throw new Error('Transaction confirmation timeout');
}
async getTransactionWithReceipt(txHash) {
const [tx, receipt] = await Promise.all([
this.getTransaction(txHash),
this.provider.getTransactionReceipt(txHash)
]);
if (tx.status === 'not_found') {
return tx;
}
return {
...tx,
receipt: receipt ? {
status: receipt.status,
gasUsed: receipt.gasUsed.toString(),
effectiveGasPrice: receipt.effectiveGasPrice?.toString(),
logs: receipt.logs.length,
contractAddress: receipt.contractAddress
} : null
};
}
}
// Usage example
async function trackPayment(txHash) {
const tracker = new TransactionTracker(provider);
console.log('Tracking transaction:', txHash);
// Get initial status
const tx = await tracker.getTransaction(txHash);
console.log('Status:', tx.status);
if (tx.status === 'pending') {
console.log('Waiting for confirmation...');
const confirmed = await tracker.waitForConfirmation(txHash, 2);
console.log('Confirmed in block:', confirmed.blockNumber);
}
// Get full details with receipt
const fullDetails = await tracker.getTransactionWithReceipt(txHash);
console.log('Transaction details:', fullDetails);
return fullDetails;
}
from web3 import Web3
import asyncio
import time
from typing import Optional, Dict, Any
w3 = Web3(Web3.HTTPProvider('https://api-unichain-mainnet.n.dwellir.com/YOUR_API_KEY'))
class TransactionMonitor:
"""Monitor and analyze transactions on Unichain"""
def __init__(self, w3_instance):
self.w3 = w3_instance
self.tx_cache = {}
def get_transaction_details(self, tx_hash: str) -> Dict[str, Any]:
"""Get comprehensive transaction details"""
# Convert to hex if needed
if not tx_hash.startswith('0x'):
tx_hash = '0x' + tx_hash
# Check cache
if tx_hash in self.tx_cache:
cached = self.tx_cache[tx_hash]
if time.time() - cached['timestamp'] < 5:
return cached['data']
try:
# Fetch transaction
tx = self.w3.eth.get_transaction(tx_hash)
if not tx:
return {'status': 'not_found', 'hash': tx_hash}
# Parse transaction details
result = {
'hash': tx.hash.hex(),
'from': tx['from'],
'to': tx.get('to'),
'value': str(tx.value),
'value_eth': self.w3.from_wei(tx.value, 'ether'),
'gas': tx.gas,
'gas_price': str(tx.gasPrice) if tx.get('gasPrice') else None,
'max_fee_per_gas': str(tx.get('maxFeePerGas', 0)),
'max_priority_fee': str(tx.get('maxPriorityFeePerGas', 0)),
'nonce': tx.nonce,
'block_number': tx.blockNumber,
'block_hash': tx.blockHash.hex() if tx.blockHash else None,
'transaction_index': tx.transactionIndex,
'type': tx.type,
'input': tx.input.hex(),
'status': 'confirmed' if tx.blockNumber else 'pending'
}
# Calculate confirmations
if tx.blockNumber:
current_block = self.w3.eth.block_number
result['confirmations'] = current_block - tx.blockNumber
else:
result['confirmations'] = 0
# Cache result
self.tx_cache[tx_hash] = {
'data': result,
'timestamp': time.time()
}
return result
except Exception as e:
return {'status': 'error', 'error': str(e), 'hash': tx_hash}
def decode_input_data(self, input_data: str) -> Dict[str, Any]:
"""Decode transaction input data"""
if not input_data or input_data == '0x':
return {'type': 'transfer', 'data': None}
# Check for common function signatures
signatures = {
'0xa9059cbb': 'transfer(address,uint256)',
'0x095ea7b3': 'approve(address,uint256)',
'0x23b872dd': 'transferFrom(address,address,uint256)',
'0x70a08231': 'balanceOf(address)',
'0x18160ddd': 'totalSupply()',
'0x3ccfd60b': 'withdraw()',
'0xd0e30db0': 'deposit()'
}
if len(input_data) >= 10:
method_id = input_data[:10]
if method_id in signatures:
return {
'type': 'contract_call',
'method': signatures[method_id],
'data': input_data[10:]
}
return {'type': 'unknown', 'data': input_data}
async def wait_for_transaction(
self,
tx_hash: str,
confirmations: int = 1,
timeout: int = 60
) -> Dict[str, Any]:
"""Wait for transaction confirmation"""
start_time = time.time()
while time.time() - start_time < timeout:
tx = self.get_transaction_details(tx_hash)
if tx['status'] == 'not_found':
await asyncio.sleep(2)
continue
if tx['status'] == 'confirmed' and tx['confirmations'] >= confirmations:
return tx
await asyncio.sleep(2)
raise TimeoutError(f"Transaction {tx_hash} not confirmed within {timeout} seconds")
def analyze_transaction(self, tx_hash: str) -> Dict[str, Any]:
"""Analyze transaction for insights"""
tx = self.get_transaction_details(tx_hash)
if tx['status'] in ['not_found', 'error']:
return tx
analysis = {
'basic_info': tx,
'decoded_input': self.decode_input_data(tx['input']),
'is_contract_creation': tx['to'] is None,
'is_token_transfer': len(tx['input']) > 2,
'gas_efficiency': None
}
# Calculate gas efficiency for confirmed transactions
if tx['status'] == 'confirmed':
try:
receipt = self.w3.eth.get_transaction_receipt(tx_hash)
gas_used = receipt.gasUsed
gas_limit = tx['gas']
analysis['gas_efficiency'] = {
'used': gas_used,
'limit': gas_limit,
'efficiency': f"{(gas_used / gas_limit * 100):.2f}%"
}
except:
pass
return analysis
# Usage examples
monitor = TransactionMonitor(w3)
# Get transaction details
tx_details = monitor.get_transaction_details(
"0x88df016429689c079f3b2f6ad39fa052532c56795b733da78a91ebe6a713944b"
)
# Analyze transaction
analysis = monitor.analyze_transaction(
"0x88df016429689c079f3b2f6ad39fa052532c56795b733da78a91ebe6a713944b"
)
print(f"Transaction from: {tx_details['from']}")
print(f"Value: {tx_details['value_eth']} ETH")
print(f"Status: {tx_details['status']}")
print(f"Confirmations: {tx_details['confirmations']}")
Common Use Cases​
1. Payment Verification System​
// Verify payment received
async function verifyPayment(txHash, expectedAmount, expectedRecipient) {
const tx = await provider.getTransaction(txHash);
if (!tx) {
return { valid: false, reason: 'Transaction not found' };
}
// Check recipient
if (tx.to?.toLowerCase() !== expectedRecipient.toLowerCase()) {
return { valid: false, reason: 'Wrong recipient' };
}
// Check amount
if (tx.value.toString() !== expectedAmount) {
return { valid: false, reason: 'Wrong amount' };
}
// Check confirmations
if (!tx.blockNumber) {
return { valid: false, reason: 'Transaction pending' };
}
const receipt = await provider.getTransactionReceipt(txHash);
if (receipt.status === 0) {
return { valid: false, reason: 'Transaction failed' };
}
return {
valid: true,
confirmations: tx.confirmations,
blockNumber: tx.blockNumber
};
}
2. Transaction History Builder​
// Build transaction history for address
async function getAddressTransactions(address, txHashes) {
const transactions = [];
for (const hash of txHashes) {
const tx = await provider.getTransaction(hash);
if (!tx) continue;
const isIncoming = tx.to?.toLowerCase() === address.toLowerCase();
const isOutgoing = tx.from.toLowerCase() === address.toLowerCase();
transactions.push({
hash: tx.hash,
type: isIncoming ? 'incoming' : 'outgoing',
from: tx.from,
to: tx.to,
value: ethers.formatEther(tx.value),
timestamp: tx.blockNumber ?
(await provider.getBlock(tx.blockNumber)).timestamp : null,
status: tx.blockNumber ? 'confirmed' : 'pending',
gasPrice: tx.gasPrice ? ethers.formatGwei(tx.gasPrice) : null,
confirmations: tx.confirmations
});
}
return transactions.sort((a, b) => b.timestamp - a.timestamp);
}
3. Gas Price Analysis​
// Analyze gas usage patterns
async function analyzeGasUsage(txHash) {
const tx = await provider.getTransaction(txHash);
if (!tx) {
throw new Error('Transaction not found');
}
const receipt = await provider.getTransactionReceipt(txHash);
const block = await provider.getBlock(tx.blockNumber);
return {
txHash: tx.hash,
gasLimit: tx.gasLimit.toString(),
gasUsed: receipt ? receipt.gasUsed.toString() : null,
gasPrice: tx.gasPrice ? ethers.formatGwei(tx.gasPrice) : null,
maxFeePerGas: tx.maxFeePerGas ? ethers.formatGwei(tx.maxFeePerGas) : null,
maxPriorityFee: tx.maxPriorityFeePerGas ?
ethers.formatGwei(tx.maxPriorityFeePerGas) : null,
unichainFee: block.unichainFeePerGas ?
ethers.formatGwei(block.unichainFeePerGas) : null,
efficiency: receipt ?
((Number(receipt.gasUsed) / Number(tx.gasLimit)) * 100).toFixed(2) + '%' : null,
totalCost: receipt && tx.gasPrice ?
ethers.formatEther(receipt.gasUsed * tx.gasPrice) : null
};
}
Error Handling​
Error Scenario | Description | Solution |
---|---|---|
null response | Transaction not found | Check hash validity, wait for propagation |
Network timeout | RPC connection issues | Retry with exponential backoff |
Invalid hash | Malformed transaction hash | Validate hash format (66 characters) |
async function safeGetTransaction(txHash, retries = 3) {
// Validate hash format
if (!/^0x[a-fA-F0-9]{64}$/.test(txHash)) {
throw new Error('Invalid transaction hash format');
}
for (let i = 0; i < retries; i++) {
try {
const tx = await provider.getTransaction(txHash);
if (tx) {
return tx;
}
// Wait before retry if not found
if (i < retries - 1) {
await new Promise(resolve => setTimeout(resolve, 2000 * (i + 1)));
}
} catch (error) {
if (i === retries - 1) {
throw error;
}
await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1)));
}
}
return null;
}
Need help? Contact our support team or check the Unichain documentation.