Documentation Index
Fetch the complete documentation index at: https://voltaire.tevm.sh/llms.txt
Use this file to discover all available pages before exploring further.
Try it Live
Run Transaction examples in the interactive playground
Transaction Utilities
Utility methods for working with transactions across all types.
Format transaction to human-readable string.
function format(tx: Any): string
Usage
import { format } from 'tevm/Transaction'
const tx: Transaction.EIP1559 = {
type: Transaction.Type.EIP1559,
nonce: 5n,
to: recipientAddress,
value: 1500000000000000000n,
// ...
}
const formatted = format(tx)
// "EIP-1559 tx to 0x742d35Cc..., value: 1.5 ETH, nonce: 5"
// Contract creation
const deploy: Transaction.Legacy = {
type: Transaction.Type.Legacy,
nonce: 0n,
to: null,
value: 0n,
// ...
}
format(deploy)
// "Legacy tx contract creation, value: 0 ETH, nonce: 0"
Source: format.ts:6-20
getGasPrice
Get transaction gas price (handles all types).
function getGasPrice(tx: Any, baseFee?: bigint): bigint
Parameters
tx: Any - Any transaction type
baseFee?: bigint - Required for EIP-1559+ transactions
Returns
bigint - Gas price in wei
Throws
Error("baseFee required for EIP-1559+ transactions") - If baseFee missing for dynamic fee transactions
Usage
import { getGasPrice } from 'tevm/Transaction'
// Legacy/EIP-2930: Returns fixed gasPrice
const legacyTx: Transaction.Legacy = {
type: Transaction.Type.Legacy,
gasPrice: 20000000000n,
// ...
}
getGasPrice(legacyTx) // 20000000000n
// EIP-1559+: Calculates effective gas price
const eip1559Tx: Transaction.EIP1559 = {
type: Transaction.Type.EIP1559,
maxPriorityFeePerGas: 2000000000n,
maxFeePerGas: 30000000000n,
// ...
}
const baseFee = 15000000000n
getGasPrice(eip1559Tx, baseFee) // 17000000000n (15 + 2)
// Missing baseFee throws
try {
getGasPrice(eip1559Tx) // Error!
} catch (e) {
console.error(e.message) // "baseFee required for EIP-1559+ transactions"
}
Source: getGasPrice.ts:16-38
hasAccessList
Check if transaction supports access lists.
function hasAccessList(tx: Any): boolean
Returns
true - For EIP-2930, EIP-1559, EIP-4844, EIP-7702
false - For Legacy
Usage
import { hasAccessList, getAccessList } from 'tevm/Transaction'
const tx: Transaction.Any = /* ... */
if (hasAccessList(tx)) {
const accessList = getAccessList(tx)
console.log('Access list:', accessList)
} else {
console.log('No access list support')
}
Source: hasAccessList.ts:7-9
getAccessList
Get transaction access list.
function getAccessList(tx: Any): AccessList
Returns
AccessList - Transaction access list
[] - Empty array for Legacy transactions
Usage
import { getAccessList } from 'tevm/Transaction'
// EIP-1559 with access list
const eip1559: Transaction.EIP1559 = {
type: Transaction.Type.EIP1559,
accessList: [
{ address: addr1, storageKeys: [key1, key2] }
],
// ...
}
getAccessList(eip1559)
// [{ address: addr1, storageKeys: [key1, key2] }]
// Legacy returns empty
const legacy: Transaction.Legacy = { /* ... */ }
getAccessList(legacy) // []
Source: getAccessList.ts:7-12
getChainId
Get transaction chain ID.
function getChainId(tx: Any): bigint | null
Returns
bigint - Chain ID
null - For pre-EIP-155 Legacy transactions
Usage
import { getChainId } from 'tevm/Transaction'
// EIP-1559 (explicit chainId field)
const eip1559: Transaction.EIP1559 = {
type: Transaction.Type.EIP1559,
chainId: 1n,
// ...
}
getChainId(eip1559) // 1n
// Legacy with EIP-155
const legacy: Transaction.Legacy = {
type: Transaction.Type.Legacy,
v: 37n, // chainId = (37 - 35) / 2 = 1
// ...
}
getChainId(legacy) // 1n
// Pre-EIP-155 Legacy
const oldLegacy: Transaction.Legacy = {
type: Transaction.Type.Legacy,
v: 27n,
// ...
}
getChainId(oldLegacy) // null
Source: getChainId.ts:8-13
isSigned
Check if transaction has a signature.
function isSigned(tx: Any): boolean
Returns
true - If transaction has non-zero r and s
false - If r or s is all zeros
Usage
import { isSigned, getSender } from 'tevm/Transaction'
const signedTx: Transaction.EIP1559 = {
type: Transaction.Type.EIP1559,
r: Bytes32().fill(1),
s: Bytes32().fill(2),
// ...
}
isSigned(signedTx) // true
const unsignedTx: Transaction.EIP1559 = {
type: Transaction.Type.EIP1559,
r: Bytes32(), // All zeros
s: Bytes32(), // All zeros
// ...
}
isSigned(unsignedTx) // false
// Use for conditional logic
if (isSigned(tx)) {
const sender = getSender(tx)
console.log('Signed by:', sender)
}
Source: isSigned.ts:7-14
assertSigned
Assert transaction is signed (throws if not).
function assertSigned(tx: Any): void
Throws
Error("Transaction is not signed") - If r or s is all zeros
Usage
import { assertSigned, getSender } from 'tevm/Transaction'
try {
assertSigned(tx)
// Transaction is signed, safe to get sender
const sender = getSender(tx)
processTransaction(tx, sender)
} catch (e) {
console.error('Cannot process unsigned transaction')
return
}
Source: assertSigned.ts:6-13
Usage Patterns
Transaction Cost Calculation
import { getGasPrice } from 'tevm/Transaction'
function calculateMaxCost(
tx: Transaction.Any,
baseFee?: bigint
): bigint {
const gasPrice = getGasPrice(tx, baseFee)
return tx.gasLimit * gasPrice + tx.value
}
// Usage
const tx: Transaction.EIP1559 = {
type: Transaction.Type.EIP1559,
maxPriorityFeePerGas: 2000000000n,
maxFeePerGas: 30000000000n,
gasLimit: 21000n,
value: 1000000000000000000n,
// ...
}
const maxCost = calculateMaxCost(tx, 15000000000n)
// gasLimit * effectiveGasPrice + value
// 21000 * 17000000000 + 1000000000000000000
Replay Protection Check
import { getChainId } from 'tevm/Transaction'
import { TransactionError } from 'tevm/errors'
function validateChainId(
tx: Transaction.Any,
expectedChainId: bigint
): void {
const txChainId = getChainId(tx)
if (txChainId === null) {
throw new TransactionError('Transaction has no chain ID (pre-EIP-155)', {
code: 'MISSING_CHAIN_ID',
context: { txType: tx.type }
})
}
if (txChainId !== expectedChainId) {
throw new TransactionError(
`Wrong chain: expected ${expectedChainId}, got ${txChainId}`,
{
code: 'WRONG_CHAIN_ID',
context: { expected: expectedChainId, actual: txChainId }
}
)
}
}
import { hasAccessList, getAccessList } from 'tevm/Transaction'
function extractAddresses(tx: Transaction.Any): Set<AddressType> {
const addresses = new Set<AddressType>()
// Add sender
if (isSigned(tx)) {
addresses.add(getSender(tx))
}
// Add recipient
if (tx.to) {
addresses.add(tx.to)
}
// Add access list addresses
if (hasAccessList(tx)) {
const accessList = getAccessList(tx)
for (const item of accessList) {
addresses.add(item.address)
}
}
return addresses
}
Transaction Display
import { format, getGasPrice, getChainId } from 'tevm/Transaction'
function displayTransaction(
tx: Transaction.Any,
baseFee?: bigint
): void {
console.log('Transaction Details')
console.log('-------------------')
console.log(format(tx))
console.log('Chain ID:', getChainId(tx) || 'N/A')
try {
const gasPrice = getGasPrice(tx, baseFee)
console.log('Gas Price:', gasPrice, 'wei')
} catch {
console.log('Gas Price: Requires base fee')
}
console.log('Signed:', isSigned(tx) ? 'Yes' : 'No')
if (hasAccessList(tx)) {
const accessList = getAccessList(tx)
console.log('Access List Items:', accessList.length)
}
}
Signature Validation
import { isSigned, assertSigned, verifySignature, getSender } from 'tevm/Transaction'
function validateTransaction(
tx: Transaction.Any,
expectedSender?: AddressType
): { valid: boolean; sender?: AddressType; error?: string } {
// Check if signed
if (!isSigned(tx)) {
return { valid: false, error: 'Transaction not signed' }
}
// Verify signature
if (!verifySignature(tx)) {
return { valid: false, error: 'Invalid signature' }
}
// Get sender
const sender = getSender(tx)
// Check expected sender if provided
if (expectedSender && !Address.equals(sender, expectedSender)) {
return {
valid: false,
error: `Wrong sender: expected ${Address.toHex(expectedSender)}, got ${Address.toHex(sender)}`
}
}
return { valid: true, sender }
}
Transaction Pool Entry
import {
isSigned,
getSender,
getChainId,
getGasPrice,
hash
} from 'tevm/Transaction'
interface PoolEntry {
tx: Transaction.Any
hash: HashType
sender: AddressType
gasPrice: bigint
timestamp: number
}
function createPoolEntry(
tx: Transaction.Any,
baseFee?: bigint
): PoolEntry {
assertSigned(tx)
return {
tx,
hash: hash(tx),
sender: getSender(tx),
gasPrice: getGasPrice(tx, baseFee),
timestamp: Date.now()
}
}
- Cache getSender results - ECDSA recovery is expensive
- Batch getGasPrice calls - Reuse baseFee for multiple transactions
- Check isSigned before getSender - Avoid unnecessary recovery attempts
- Use hasAccessList before getAccessList - Skip unnecessary checks
// Bad: Redundant checks
if (tx.type !== Transaction.Type.Legacy) {
const accessList = getAccessList(tx)
}
// Good: Single check
if (hasAccessList(tx)) {
const accessList = getAccessList(tx)
}