Bitcoin has no balances. Its state is a set of unspent transaction outputs (UTXOs), and "your balance" is whatever your wallet adds up from the outputs it can spend. Ethereum stores a balance and a nonce for every account directly in its world state. Almost every difference in how you build, sign, and debug transactions on the two chains comes from this one design choice.
The UTXO model (Bitcoin)
A Bitcoin transaction consumes existing outputs as inputs and creates new outputs. Each output has an amount and a locking script, for example "spendable by whoever signs for this public key hash". The rules:
- An output is spent whole. To pay 0.3 BTC from a 1 BTC output, you create two outputs: 0.3 to the recipient and about 0.7 back to yourself as change.
- The fee is implicit:
sum(inputs) - sum(outputs). Leave out the change output by mistake and the whole difference goes to the miner. - An output can be spent only once. Two transactions that spend the same output conflict, and at most one can confirm.
Tx A: in: [UTXO#1 1.0 BTC]
out: [0.3 BTC -> Bob] [0.6999 BTC -> Alice change]
fee: 0.0001 BTC (implicit)
To validate new transactions, a node only needs the UTXO set, which it keeps in its chainstate database. There is no per-address balance table. Ask your node what a wallet can spend:
bitcoin-cli -rpcwallet=mywallet listunspent 1
bitcoin-cli -rpcwallet=mywallet getbalances
Every balance you see in a Bitcoin wallet is a sum computed on the fly.
The account model (Ethereum)
Ethereum's state maps each address to an account with four fields: nonce, balance, storageRoot and codeHash. A transfer just subtracts from one balance and adds to another. There is no change output and no coin selection.
Instead, every transaction from an externally owned account carries a nonce, which must equal the sender's current transaction count. Nonces give Ethereum replay protection and a strict ordering per sender.
import { , formatEther } ;
provider = (process..);
addr = ;
balance = provider.(addr);
nextNonce = provider.(addr, );
.((balance), nextNonce);