UTXO and account models · Lesson 3 of 6
The account model for analysts
8 min read
Ethereum and the many chains that copy its design keep a running balance for every address instead of a pile of discrete coins. That changes what can be traced, what a "transaction" means and who the real actor behind an action is. With smart accounts and account abstraction now common, the address that signs, the address that pays gas and the address that appears in the from field are often three different things, and an analyst who confuses them will attribute activity to the wrong party.
State, not coins
An account-model chain stores a world state: a mapping from each 20-byte address to an account record. On Ethereum that record has four fields:
| Field | Meaning | Analyst use |
|---|---|---|
nonce | Transactions sent (EOA) or contracts created (contract) | Activity count, ordering, fresh-address checks |
balance | Native currency, in wei | Holdings at a block |
codeHash | Hash of the account's code (empty for a plain EOA) | Telling EOAs, contracts and delegated EOAs apart |
storageRoot | Root of the account's key-value storage | Where token balances and contract data actually live |
Every block commits to the resulting state through the stateRoot in its header. Balances are read with eth_getBalance(address, block), and contract storage through eth_call (for example a token's balanceOf) or eth_getStorageAt.
The difference from the UTXO model is fundamental:
| Question | UTXO chains | Account chains |
|---|---|---|
| Unit of value | Discrete outputs, spent whole | A single balance per address |
| Change | A new output, often to a new address | None: the remainder stays in the balance |
| Linking a payment out to a payment in | Exact per output; ambiguous inside a multi-input transaction | Never exact: all deposits merge |
| Address reuse | Discouraged | Normal; one address for years |
| Replay protection | Each output can be spent once | Each transaction must use the next nonce |
Once 10 ETH arrives at an address that already holds 50 ETH, nothing in the data says which ETH left next; any attribution is a tracing convention (see the lesson Tracing funds forward and backward).
EOAs and contracts
An externally owned account (EOA) is controlled by a private key and is the only kind of account that can originate a transaction. A contract account has code and storage, cannot start anything by itself, and acts only when called. eth_getCode(address, block) returns 0x for an EOA and the deployed bytecode for a contract.
Three pitfalls make this check less simple than it looks:
- Timing. Code exists only from the block in which the contract was created. Addresses can be computed before deployment (CREATE2 makes this deliberate), so an address with no code at block N may be a contract at block N+1. Always check code at the block that matters.
- Destruction. Before the Dencun upgrade (March 2024),
SELFDESTRUCTdeleted a contract's code. Since EIP-6780 it does so only when called in the same transaction that created the contract; otherwise it just sends the balance away. - Delegation. Since the Pectra upgrade (May 2025), an EOA can carry the 23-byte EIP-7702 delegation designator
0xef0100followed by a delegate address. A naive "has code, so it is a contract" rule misclassifies it: the account is still controlled by its private key.
A robust classifier therefore returns three classes (EOA, contract, delegated EOA) as of a block, not two.
The nonce is a gift to analysts. For an EOA it equals the number of transactions it has sent, so an address with nonce 0 has never sent anything, and gaps or bursts in nonce use reveal operational patterns (see the lesson Account-model heuristics). Two caveats: each EIP-7702 authorization an EOA signs also increments its nonce, and a contract's nonce counts contract creations, starting at 1 under EIP-161. Contract addresses are derived from the deployer: CREATE uses the deployer's address and nonce, and CREATE2 uses the deployer, a salt and the hash of the creation code, which is why deployer links are strong evidence.
State versus history
A state query answers "what did this address hold at block N?". History answers "how did it get there?", and it lives in several places at once:
- top-level transactions (value sent, plus gas paid by the sender);
- traces of internal calls (value moved by contracts);
- logs (token transfers and other events);
- balance changes that are not transactions at all: priority fees credited to the block's fee recipient, consensus-layer withdrawals credited directly to addresses since April 2023 (EIP-4895: no gas, no code execution, no transaction hash), genesis allocations and, before September 2022, mining rewards.
Full nodes keep recent state only, so state at old blocks needs an archive node or a provider that offers one (see the lesson Node APIs and data access). The next lesson, Reconstructing balances and histories, shows how to rebuild a balance from these pieces and reconcile it against state.
Internal transactions
In the protocol, a transaction is only the signed, top-level message. When a contract forwards ETH during execution, that is a message call: it has no hash, no receipt and no log unless the code emits one. Explorers call them "internal transactions", a convenient but misleading label.
Consider a withdrawal from a contract wallet. The user's transaction sends 0 ETH to the wallet contract 0x7c3E…12; during execution, the contract calls 0xD4e5…3a with value 0xde0b6b3a7640000, which is 10^18 wei or 1 ETH. The transaction list for 0xD4e5…3a shows nothing, yet its balance rose by 1 ETH. Only a trace (see the lesson Raw Ethereum transactions, receipts and logs) explains the change. Reverted subcalls move nothing and must be excluded.
Token movements are different again: an ERC-20 transfer is a change in the token contract's storage, announced by a Transfer event, not an internal transaction (see the lesson Reading token transfers).
Smart accounts and account abstraction
A smart account is a wallet implemented as a contract, with rules such as multiple signers, spending limits, recovery or sponsored gas. Three designs matter for analysis.
Contract wallets (multisig wallets are the classic case) hold funds at a contract address. Owners sign off chain and one of them, or a relayer, submits the transaction. The economic actor is the contract; the EOA that sent the transaction may just be the last signer.
ERC-4337 adds account abstraction without protocol changes. Users sign a UserOperation (fields include sender, nonce, callData, gas limits, paymaster and signature) and send it to a separate mempool. A bundler packs many UserOperations into one transaction calling handleOps on a singleton EntryPoint contract, which validates and executes each one and pays the bundler from the account's deposit or a paymaster's. For each operation it emits:
UserOperationEvent(bytes32 indexed userOpHash, address indexed sender, address indexed paymaster, uint256 nonce, bool success, uint256 actualGasCost, uint256 actualGasUsed)
The consequences are concrete: the transaction's from is the bundler, one transaction can carry operations from unrelated users, the receipt covers the whole bundle, and the real actor is the event's sender. A query that lists smart accounts and their gas sponsors from raw logs:
-- One row per ERC-4337 UserOperation, with bundler, smart account and paymaster
SELECT
l.block_number,
l.tx_hash,
t.from_address AS bundler,
'0x' || SUBSTR(l.topic2, 27, 40) AS smart_account, -- indexed sender
'0x' || SUBSTR(l.topic3, 27, 40) AS paymaster -- zero address = none
FROM logs l
JOIN transactions t ON t.hash = l.tx_hash
WHERE l.topic0 = '0x49628fd1471006c1482da88028e9ce4dbb080b815c9b0344d39e5a8e6ec1419f'
AND l.address IN (SELECT address FROM entrypoint_contracts);
The topic0 value is the Keccak-256 hash of the event signature. Indexed addresses sit in 32-byte topics, left-padded with zeros, so the address is the last 40 hex characters; SUBSTR(topic, 27, 40) skips 0x and 24 padding characters. Some engines call the function SUBSTRING, and some store topics as binary, where you slice bytes instead. Restricting to known EntryPoint addresses (one per version) avoids matching look-alike events from other contracts.
EIP-7702 lets an existing EOA adopt smart-account behavior. A type 4 transaction carries authorizations [chain_id, address, nonce, y_parity, r, s]; each sets the signer's code to the delegation designator, which persists until replaced or cleared, and an authorization with chain_id 0 is valid on every chain. The address keeps its history and key but can now batch calls or have its gas paid by others. Delegation targets are also evidence: a public on-chain dashboard published by the trading firm Wintermute in June 2025 found that over 80% of early delegations pointed to copies of one "sweeper" contract that drains wallets whose keys have leaked.
Who signs versus who pays
| Pattern | Who authorizes | Transaction from (pays gas) | Where to find the real actor |
|---|---|---|---|
| Plain EOA transaction | EOA key | The same EOA | from |
| Contract wallet | Owners' signatures in call data | An owner or a relayer | to (the wallet) and its events |
| Meta-transaction (ERC-2771) | User's signature | A relayer via a trusted forwarder | Decoded call data |
| ERC-4337 | Smart account's validation rules | Bundler, reimbursed by account or paymaster | UserOperationEvent.sender |
| EIP-7702 sponsored | EOA's authorization and signed payload | A sponsor | The delegated EOA called |
Never equate the gas payer with the actor until the pattern is identified. Gas funding remains useful evidence, but under sponsorship it may point to a service rather than an owner (see the lesson Account-model heuristics).
Exam focus: the four account fields (nonce, balance, codeHash, storageRoot) and what the nonce means for EOAs and contracts; why coin-level tracing is impossible in a pooled balance; classifying EOAs, contracts and EIP-7702 delegated EOAs at a given block, including the0xef0100designator and the effect of EIP-6780; non-transaction balance changes such as EIP-4895 withdrawals and fee rewards; internal transactions as message calls visible only in traces; the ERC-4337 roles (UserOperation, bundler, EntryPoint, paymaster) and theUserOperationEventfields; extracting an address from an indexed topic; telling who signed, who paid gas and who acted.
Practice questions
Check your understanding. These questions do not count towards the exam.
Sign in to save your progress and continue where you left off. It is free. Sign in