EVM, wallet, gas, smart contract, DeFi, Layer 2 e perché hai pagato 40$ di fee per spostare 10$.
Spiegato senza hype, senza "questa tecnologia cambierà il mondo", senza grafici che vanno sempre su.
"Non è solo una moneta, è un computer mondiale." — Sì, un computer che costa 80$ a transazione nei momenti sbagliati.
E perché non è "Bitcoin ma meglio"
Bitcoin è un registro distribuito per trasferire valore. Fa una cosa sola, la fa bene, non si vuole complicare la vita.
Ethereum è un computer distribuito programmabile. Oltre a trasferire ETH puoi eseguire codice arbitrario su migliaia di nodi in contemporanea — codice che nessuno può fermare, censurare o modificare una volta deployato. Questo codice si chiama smart contract.
Il prezzo di questa flessibilità: è più complesso, più costoso da usare, e ha una superficie d'attacco molto più grande.
Ogni account, ogni saldo, ogni variabile di ogni contratto — tutto in un unico stato condiviso aggiornato ad ogni blocco
Ethereum Virtual Machine: il motore che esegue il bytecode dei contratti. Deterministico — tutti i nodi ottengono lo stesso risultato
Proof of Stake dal 2022 (The Merge). I validatori mettono in stake 32 ETH come garanzia. Niente più mining, -99.95% consumo energetico
La tua chiave privata è il tuo account. Punto.
Il tipo di account che usi tu. Controllato da una chiave privata.
0x1a2b3c...Creato dal deploy di uno smart contract. Non ha chiave privata — è governato dal suo codice.
# Chiave privata: 32 byte casuali (256 bit) 0x4c0883a69102937d6231471b5dbb6e538eba2ef2d22b1432db0e0f4c3b7aa9c3 # Chiave pubblica: derivata con curva ellittica secp256k1 (stessa di Bitcoin) # pubkey = privkey × G (G = punto generatore della curva) # Indirizzo Ethereum: ultimi 20 byte del keccak256(pubkey) 0x9Ae5A9876543210aBcDeF1234567890aBcDeF12 # Seed phrase (BIP-39): 12 o 24 parole → entropia → chiave privata abandon ability able about above absent absorb abstract absurd abuse access accident # Con questa frase ricrei tutte le chiavi di tutti gli account del wallet # HD wallet (BIP-44): m/44'/60'/0'/0/0 → primo account ETH
| Wallet | Tipo | Quando usarlo |
|---|---|---|
| MetaMask | Browser extension / mobile | Uso quotidiano DeFi, dApp. Il più supportato. |
| Ledger / Trezor | Hardware | Somme importanti. La chiave privata non lascia mai il device. |
| Rabby | Browser extension | Come MetaMask ma mostra simulazione transazione prima di firmare |
| Frame | Desktop | Per sviluppatori, integra hardware wallet |
| Safe (Gnosis) | Smart contract multisig | Tesoreria DAO, fondi di team. Richiede N/M firme. |
Perché hai pagato 40$ per spostare 20$, spiegato
Ogni operazione nell'EVM costa una quantità fissa di gas. Sommare due numeri: 3 gas. Scrivere in storage: 20.000 gas. Una transazione semplice (trasferimento ETH): 21.000 gas.
Il gas è un'unità di misura computazionale — non dipende dal prezzo di ETH. Quello che varia è il prezzo del gas (in Gwei), che determina quanto ETH paghi in totale.
# Fee totale = (Base Fee + Priority Fee) × Gas Used Base Fee # bruciata — eliminata dalla circolazione. Fissata dal protocollo. # sale se il blocco precedente era >50% pieno, scende se <50% # sale/scende max del 12.5% per blocco Priority Fee # "mancia" al validatore. Scegli tu quanto dare. # bassa = tx lenta. Alta = tx veloce. Max Fee # il massimo che sei disposto a pagare in totale. # se Base Fee + Priority Fee < Max Fee → paghi solo quello che serve # il resto viene rimborsato # Esempio pratico: Gas Used = 21,000 # trasferimento ETH standard Base Fee = 20 Gwei Priority = 2 Gwei Fee totale = 21,000 × 22 Gwei = 462,000 Gwei = 0.000462 ETH # a ETH = 3,000$ → circa 1.38$
Il gas price segue l'attività della rete. Ore di picco = fee alte.
Cosa succede dal click "Invia" alla conferma finale
# Struttura di una tx Ethereum { nonce: 42, # numero progressivo tx dell'account (0, 1, 2, ...) to: "0xAbCd...", # destinatario (o null se deploy contratto) value: 1000000000000000000, # wei (= 1 ETH) data: "0x...", # calldata: vuoto per trasferimento ETH, # oppure ABI-encoded per chiamate a contratti maxFeePerGas: 25000000000, # 25 Gwei maxPriorityFeePerGas: 2000000000, # 2 Gwei gasLimit: 21000, chainId: 1, # 1 = mainnet, 137 = Polygon, 42161 = Arbitrum v, r, s: ... # firma ECDSA }
| Fase | Cosa succede |
|---|---|
| Pending | Tx inviata, nel mempool dei nodi. Aspetta un validatore che la includa nel prossimo blocco. |
| Inclusa | Entrata in un blocco. 1 conferma. Tecnicamente reversibile se c'è un reorg (raro su ETH). |
| Finalizzata | Dopo ~13 minuti (2 epoch di PoS). A questo punto è praticamente impossibile reverire. |
| Fallita | Revert del contratto, gas esaurito. Gas usato consumato, effetti annullati. La tx è comunque on-chain. |
Una tx rimane pending se il gas price era troppo basso. Soluzione: invia una nuova tx con lo stesso nonce ma fee più alta.
# In MetaMask: Settings → Advanced → Customize transaction nonce # Poi invia una nuova tx con: # - stesso nonce della tx bloccata # - fee più alte (almeno +10% del gas price attuale) # - to: il tuo stesso indirizzo, value: 0 ETH (se vuoi solo sbloccarla) # La nuova tx "sovrascrive" quella vecchia — i miner scelgono quella più pagata # Alternativa: aspettare. Se il gas scende, prima o poi viene presa.
Codice immutabile su blockchain. Ottimo per automazione, terribile per i bug.
Un smart contract è un programma che vive all'indirizzo 0x... sulla blockchain. Una volta deployato, nessuno può modificarlo o fermarlo — nemmeno chi l'ha scritto (salvo che non abbia inserito una funzione di upgrade o kill). Il codice è legge. Compreso il codice con i bug.
The DAO hack del 2016 ha rubato 60M$ sfruttando un bug di reentrancy. Il codice funzionava esattamente come scritto — il problema era che era scritto male.
// SPDX-License-Identifier: MIT // pragma indica la versione di Solidity richiesta pragma solidity ^0.8.20; contract SimpleStorage { // variabile di stato: vive nello storage del contratto (costoso!) uint256 private value; address public owner; // evento: emesso su blockchain, leggibile off-chain a costo zero event ValueChanged(uint256 newValue, address changedBy); // modifier: riutilizza controlli comuni modifier onlyOwner() { require(msg.sender == owner, "Non sei il proprietario"); _; } constructor() { owner = msg.sender; // chi deploya diventa owner } // write function: modifica stato, costa gas function setValue(uint256 _value) external onlyOwner { value = _value; emit ValueChanged(_value, msg.sender); } // read function: view = non modifica stato, gratis da chiamare function getValue() external view returns (uint256) { return value; } // receive ETH receive() external payable {} }
# Compilare e deployare con Foundry (il tool moderno) forge init mio-progetto cd mio-progetto forge build # compila, genera ABI e bytecode forge test # esegui i test forge create --rpc-url $RPC_URL \ --private-key $PRIVATE_KEY \ src/SimpleStorage.sol:SimpleStorage # Con Hardhat (alternativa storica, JS/TS) npx hardhat compile npx hardhat run scripts/deploy.js --network mainnet # Chiamare un contratto via cast (Foundry CLI) cast call 0xContractAddr "getValue()(uint256)" --rpc-url $RPC_URL cast send 0xContractAddr "setValue(uint256)" 42 \ --private-key $PRIVATE_KEY --rpc-url $RPC_URL
| Vulnerabilità | Cosa succede | Esempio storico |
|---|---|---|
| Reentrancy | Il contratto chiama un esterno che ri-entra nella funzione prima che lo stato sia aggiornato | The DAO (60M$, 2016) |
| Integer overflow | Solidity <0.8: i numeri si avvolgono silenziosamente. 255+1=0 per uint8. | BatchOverflow, 2018 |
| Access control | Funzioni privilegiate chiamabili da chiunque | Parity Wallet freeze (280M$ bloccati, mai recuperati) |
| Oracle manipulation | Il prezzo usato dal contratto viene manipolato via flash loan | Mango Markets (100M$, 2022) |
| Unchecked return | Il valore di ritorno di una chiamata esterna non viene controllato | Molto comune in contratti DeFi |
I protocolli che permettono ai wallet di capire cosa stai inviando
Token fungibili. USDC, LINK, UNI, DAI. Ogni unità è identica alle altre.
NFT. Ogni token ha un ID unico. CryptoPunks, Bored Apes. Non fungibili per definizione.
Multi-token. Un contratto gestisce sia fungibili che non. Usato in gaming e marketplace.
Quando hai USDC nel wallet, non hai niente "nel wallet" — il contratto USDC tiene un mapping address → balance. Il tuo wallet mostra il saldo leggendo quel mapping.
// Interfaccia minima ERC-20 interface IERC20 { function totalSupply() external view returns (uint256); function balanceOf(address account) external view returns (uint256); function transfer(address to, uint256 amount) external returns (bool); // Approval: permetti a un contratto di spendere i tuoi token function approve(address spender, uint256 amount) external returns (bool); function allowance(address owner, address spender) external view returns (uint256); function transferFrom(address from, address to, uint256 amount) external returns (bool); }
approve(uniswap, type(uint256).max) — autorizzi Uniswap a spendere tutti i tuoi token a volontà, per sempre. Se quel contratto ha un bug o viene compromesso, i tuoi token spariscono. Usa revoke.cash o app.unrekt.net per vedere e revocare le approvazioni pendenti.
Finanza decentralizzata — opportunità reali, rischi reali, perdite molto reali
Niente order book, niente intermediari. I trade avvengono contro pool di liquidità tramite un AMM (Automated Market Maker).
Come funziona un AMM (formula x·y=k):
Principali DEX: Uniswap (V3 concentrated liquidity), Curve (stablecoin ottimizzato), Balancer (pool multi-asset)
Depositi collaterale, prendi in prestito fino a una certa percentuale (LTV). Automatizzato da contratti, nessuna banca.
Depositi due token in un pool DEX. Ogni swap nel pool ti paga una percentuale delle fee (0.05%–1% per trade su Uniswap V3).
| Rischio | Descrizione |
|---|---|
| Smart contract bug | Il protocollo viene hackerato. Fondi persi. Nessun rimborso. |
| Rug pull | Il team drena la liquidità e sparisce. Più comune con token nuovi e pool su DEX minori. |
| Oracle manipulation | Il prezzo usato dal protocollo viene manipolato per svuotare il protocollo. |
| Governance attack | Chi ha abbastanza token di governance può proporre e approvare operazioni malevole. |
| Cascata di liquidazioni | Crollo rapido → liquidazioni massive → crollo ulteriore → altri liquidati. Luna/UST docet. |
| Phishing | Sito fake identico all'originale, ti fa firmare una transazione che svuota il wallet. |
Perché Ethereum L1 è lento e costoso, e come si risolve
Ethereum L1 processa ~15 tx/secondo. Visa ne fa ~24.000. La soluzione naïve sarebbe aumentare la dimensione dei blocchi — ma renderebbe i nodi più costosi da gestire, centralizzando la rete.
La soluzione adottata: spostare l'esecuzione fuori dalla chain, pubblicare solo la prova del risultato su L1. Sicurezza garantita da L1, throughput molto più alto, fee molto più basse.
# Bridge nativo Arbitrum (più sicuro, più lento) # L1 → L2: ~10 minuti # L2 → L1: 7 giorni (challenge period Optimistic Rollup) # Bridge veloci di terze parti (Hop, Across, Stargate) # L2 → L1: minuti (non aspettano il challenge period) # Rischio: sicurezza dipende dal bridge, non da Ethereum # Costo: fee leggermente più alta per il market maker che fa il bridge veloce
L'upgrade che ha abbassato le fee degli L2 di 10–100x. Introduce i blob transaction: tipo di dato temporaneo (~18 giorni) allegato ai blocchi, usato dagli L2 per pubblicare i loro batch su L1 a costo molto inferiore rispetto al calldata. Post-Dencun le fee su Arbitrum/Optimism sono scese a frazioni di centesimo.
Come connettersi alla rete senza fidarsi di nessuno (o fidarsi di Infura)
# Ethereum espone un'API JSON-RPC (HTTP o WebSocket) # Tutti i wallet, Etherscan, dApp usano questo sotto # Saldo di un account curl -X POST https://mainnet.infura.io/v3/YOUR_KEY \ -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","method":"eth_getBalance","params":["0xAbCd...","latest"],"id":1}' {"result":"0x16345785d8a0000"} # hex wei = 0.1 ETH # Blocco corrente cast block-number --rpc-url https://mainnet.infura.io/v3/YOUR_KEY # Leggere una variabile di un contratto cast call 0xA0b86991c6218... "totalSupply()(uint256)" \ --rpc-url https://mainnet.infura.io/v3/YOUR_KEY
Il DNS di Ethereum. Perché 0x1a2b3c4d è più difficile da memorizzare di mario.eth
ENS è un set di smart contract su Ethereum che mappano nomi leggibili (mario.eth) a indirizzi (0xAbCd...), hash IPFS, indirizzi Bitcoin, profili, e altro.
# Risolvere un nome ENS cast resolve-name mario.eth --rpc-url $RPC_URL 0x1234abcd... # Reverse lookup: da indirizzo a nome ENS cast lookup-address 0x1234abcd... --rpc-url $RPC_URL mario.eth # I nomi ENS sono NFT ERC-721 — puoi comprarli e venderli su OpenSea # Registrazione: app.ens.domains # Costo: ~5$/anno per nomi >= 5 caratteri, più per nomi corti
mario.eth direttamente senza conoscere l'indirizzo 0x. Verifica sempre che il destinatario sia corretto — ENS è immutabile e i trasferimenti non sono reversibili.
L'unico argomento che conta davvero
Mai fare
Sempre fare
| Attacco | Come funziona | Come difendersi |
|---|---|---|
| Approval phishing | Ti fa fare approve su un contratto malevolo. Quando vuole, drena tutti i token approvati. | Leggi cosa firmi. Usa Rabby (mostra simulazione). Revoca approvazioni. |
| Permit phishing | Ti fa firmare un permit off-chain (nessuna tx visibile). Il relayer drena i token dopo. | Diffidia di richieste di firma che non generano transazione on-chain. |
| Address poisoning | Ti manda 0$ da un indirizzo simile al tuo destinatario. Copi-incolli quello sbagliato. | Verifica sempre i primi e gli ultimi 4-6 caratteri dell'indirizzo. |
| Fake token airdrop | Ricevi token sconosciuti. Provi a venderli, approvi un contratto malevolo. | Ignora token sconosciuti ricevuti. Non interagire mai con loro. |
| Discord/Twitter hack | Account ufficiali vengono hackerati, postano link a "mint" fasulli. | Non mintare niente nei momenti di "urgenza". Verifica il contratto su Etherscan prima. |
Il kit minimo per muoversi senza improvvisare
Non deployare mai su mainnet senza aver testato prima. Le reti di test sono identiche alla mainnet ma con ETH finto e gratuito.
| Rete | Uso | Faucet |
|---|---|---|
| Sepolia | La testnet principale per sviluppo dApp e smart contract. Usa questa. | sepoliafaucet.com, faucet.quicknode.com, alchemy.com/faucets/ethereum-sepolia |
| Holesky | Testnet per validatori e staking. Non per sviluppo dApp normale. | holesky-faucet.pk910.de |
| Localhost (Anvil) | Nodo locale Foundry. Zero latenza, fork di mainnet, account pre-finanziati con 10.000 ETH ciascuno. | built-in |
| Localhost (Hardhat) | Come Anvil ma per progetti Hardhat. | built-in |
# Avviare un nodo locale con Anvil (Foundry) — la scorciatoia più utile anvil Available Accounts ================== (0) 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 (10000 ETH) (1) 0x70997970C51812dc3A010C7d01b50e0d17dc79C8 (10000 ETH) ... Private Keys ================== (0) 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 ... Listening on 127.0.0.1:8545 # Fork di mainnet (accedi allo stato reale ma in locale) anvil --fork-url https://mainnet.infura.io/v3/YOUR_KEY # Deploy su Sepolia con Foundry forge create --rpc-url https://rpc.sepolia.org \ --private-key $PRIVATE_KEY_TESTNET \ src/MyContract.sol:MyContract # Configura la rete in Hardhat (hardhat.config.js) # networks: { sepolia: { url: "https://rpc.sepolia.org", accounts: [PRIVATE_KEY] } } npx hardhat run scripts/deploy.js --network sepolia
Ethereum non è difficile da usare. È difficile da usare in sicurezza. La barriera non è tecnica — è psicologica: capire che non esiste "recupero account", che le tx sono irreversibili, che "il contratto ha detto di farlo" non è una scusa.
Inizia con piccole somme. Impara il sistema prima di metterci dentro quello che non puoi permetterti di perdere. E usa sempre un hardware wallet per le somme che contano. Questa frase la scrivono tutti e pochi la seguono — poi leggono le storie degli altri sui forum.