Skip to content

Ethereum Transactions

An Ethereum transaction directly debits a sender's account balance and credits a recipient's (or, for a contract call, triggers code execution) a structurally different operation than the UTXO-consuming transactions covered in Bitcoin Transactions. This chapter covers the transaction fields and the transaction type that's been Ethereum's default since 2021.

Core fields

  • nonce: the sender's current transaction count, covered in EOAs.
  • to: the recipient address, or empty for a contract-creation transaction (see Contract Creation).
  • value: the amount of ether (in wei) to transfer.
  • data: arbitrary byte data, used to encode a function call and its arguments when calling a contract (see Contract ABI), or contract initialization code for a creation transaction.
  • gasLimit: the maximum amount of gas the sender is willing to have this transaction consume.
  • signature (v, r, s), the ECDSA signature authorizing the transaction, covering everything else in the transaction.
  • chainId: which network this transaction is valid on (see Chain IDs), preventing a transaction signed for one network from being replayed on a different one.

Transaction types: legacy versus EIP-1559

Ethereum has used more than one transaction format over its history, distinguished by a type byte:

  • Type 0 (legacy): the original format, using a single gasPrice field, the sender specifies exactly how much they're willing to pay per unit of gas, and (before EIP-1559) the entire amount goes to the miner/validator who includes the transaction.
  • Type 2 (EIP-1559): introduced in the London upgrade (August 5, 2021) and the default format since, replacing the single gasPrice with two separate fields (maxFeePerGas and maxPriorityFeePerGas) feeding into the base-fee-and-tip mechanism covered fully in Gas Price and Fees.

Example: constructing and inspecting a transaction's fields with viem

import { parseEther, parseGwei } from "viem";

const transaction = {
  to: "0x0000000000000000000000000000000000dEaD" as const, // a conventional "burn" address
  value: parseEther("0.01"),
  maxFeePerGas: parseGwei("20"),
  maxPriorityFeePerGas: parseGwei("1.5"),
  gas: 21_000n, // the fixed cost of a simple ETH transfer — see chapters/ethereum/gas.md
};

console.log("value (wei):", transaction.value.toString());
console.log("maxFeePerGas (wei):", transaction.maxFeePerGas.toString());
console.log("maxPriorityFeePerGas (wei):", transaction.maxPriorityFeePerGas.toString());

Verified output from running this exact code:

value (wei): 10000000000000000
maxFeePerGas (wei): 20000000000
maxPriorityFeePerGas (wei): 1500000000

This specific example only constructs and displays the fields locally (parseEther/parseGwei are pure unit-conversion functions), so it doesn't require network access, unlike the account-reading example in Ethereum Accounts.

Common misconceptions

An Ethereum transaction's data field is not the same thing as a Bitcoin transaction's script. It's typically ABI-encoded function-call data interpreted by the EVM when executing a contract, a fundamentally different mechanism from Bitcoin's stack-based locking/unlocking scripts (see Bitcoin Script), even though both serve a broadly analogous "specify what this transaction is instructing" role.

Setting a high gasLimit does not mean a transaction will necessarily consume that much gas. It's a ceiling, not a target; a simple ETH transfer consumes exactly 21,000 gas regardless of a higher configured limit, and any unused gas (up to the limit) is not charged (see Gas).

Further reading


← Previous: Contract Accounts · Back to Ethereum · Next: Gas →