Solidity Cheat Sheet
Struttura del contratto
Ogni file inizia con una licenza e un pragma; il contratto è l'unità di deploy.
| Sintassi | Significato |
|---|---|
// SPDX-License-Identifier: MIT | Commento di licenza che il compilatore si aspetta alla riga 1 |
pragma solidity ^0.8.0; | Versione del compilatore per cui è scritto il file |
contract Counter { ... } | Dichiarare un contratto (stato + funzioni) |
constructor(uint start) { count = start; } | Viene eseguito una sola volta, al deploy |
import "./Token.sol"; | Importare un altro file |
import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; | Importare un pacchetto di libreria |
interface IToken { function balanceOf(address a) external view returns (uint); } | Dichiarare un'interfaccia (senza corpi) |
library Math { function min(uint a, uint b) internal pure returns (uint) { ... } } | Una libreria di funzioni riutilizzabili |
Tipi valore
Gli interi hanno dimensioni fisse e niente decimali; la 0.8 fa revert in caso di overflow.
| Tipo | Cosa contiene |
|---|---|
uint256 / uint | Intero senza segno, da 0 a 2^256 - 1 (uint è uint256) |
uint8, uint16, ... uint128 | Interi senza segno più piccoli, a passi di 8 bit |
int256 / int | Intero con segno (ammette i negativi) |
bool | true o false |
address | Indirizzo di 20 byte di un account o di un contratto |
address payable | Indirizzo che può ricevere Ether tramite transfer/send |
bytes32, bytes1... | Array di byte a dimensione fissa |
enum Status { Open, Closed } | Insieme di costanti con nome, memorizzato come uint8 |
1 ether, 1 gwei, 1 wei | Unità di Ether: 1 ether = 10^18 wei |
1 days, 2 hours, 30 minutes | Unità di tempo, in secondi |
Tipi riferimento e posizione dei dati
Array, stringhe, bytes, struct e mapping vivono in storage, memory o calldata.
| Sintassi | Significato |
|---|---|
string memory name | Stringa UTF-8 dinamica (una copia temporanea) |
bytes memory data | Array di byte dinamico |
uint[] public scores; | Array dinamico in storage |
uint[3] fixed; | Array a dimensione fissa di 3 |
uint[] memory tmp = new uint[](5); | Allocare un array in memory |
scores.push(42); | Aggiungere a un array in storage |
scores.pop(); | Rimuovere l'ultimo elemento |
scores.length | Numero di elementi |
storage | Persistente, on-chain, costoso da scrivere |
memory | Temporaneo, vive per una sola chiamata |
calldata | Input di sola lettura delle funzioni external, il più economico |
Mapping e struct
Un mapping è una tabella hash senza lunghezza e senza iterazione; una struct raggruppa campi.
| Sintassi | Significato |
|---|---|
mapping(address => uint) public balances; | Archivio chiave-valore, ogni chiave esiste (predefinito 0) |
balances[msg.sender] += 1; | Leggere/scrivere per chiave |
mapping(address => mapping(address => uint)) allowance; | Mapping annidato |
struct User { string name; uint age; bool active; } | Definire una struct |
User memory u = User("Ada", 36, true); | Creare una struct in memory |
User memory u = User({name: "Ada", age: 36, active: true}); | Creazione con campi nominati |
users[msg.sender] = u; | Salvare una struct in un mapping |
users[msg.sender].age = 37; | Aggiornare un campo in storage |
delete users[msg.sender]; | Riportare ai valori predefiniti |
Funzioni e visibilità
Ogni funzione dichiara chi può chiamarla e se legge o scrive lo stato.
| Sintassi | Significato |
|---|---|
function add(uint a, uint b) public pure returns (uint) { return a + b; } | Una funzione con parametri e un valore di ritorno |
public | Chiamabile da ovunque (dentro e fuori) |
external | Chiamabile solo dall'esterno del contratto |
internal | Questo contratto e i contratti che lo ereditano |
private | Solo questo contratto |
view | Legge lo stato, non lo scrive mai |
pure | Non legge alcuno stato |
payable | Può ricevere Ether con la chiamata |
returns (uint sum, bool ok) | Più valori di ritorno con nome |
(uint s, bool ok) = f(); | Destrutturare più valori di ritorno |
uint public count; | Una variabile di stato public riceve un getter automatico count() |
Modifier, costanti ed ereditarietà
Riusa i controlli con i modifier; fissa i valori con constant e immutable.
| Sintassi | Significato |
|---|---|
modifier onlyOwner() { require(msg.sender == owner, "Not owner"); _; } | Definire un modifier (_ = esegue il corpo della funzione) |
function withdraw() public onlyOwner { ... } | Applicare un modifier |
uint public constant MAX = 100; | Costante in fase di compilazione |
address public immutable owner; | Impostato una volta nel costruttore, poi fisso |
contract Token is ERC20, Ownable { ... } | Ereditare da altri contratti |
function f() public virtual { ... } | Permettere l'override |
function f() public override { ... } | Fare l'override di una funzione del genitore |
super.f(); | Chiamare l'implementazione del genitore |
abstract contract Base { function f() public virtual; } | Contratto con funzioni non implementate |
Controllo del flusso
Le solite istruzioni della famiglia C; niente switch, e i cicli costano gas a ogni iterazione.
| Sintassi | Significato |
|---|---|
if (x > 5) { ... } else if (x > 2) { ... } else { ... } | Rami condizionali |
for (uint i = 0; i < n; i++) { ... } | Ciclo con contatore |
while (x < 10) { x++; } | Ciclo finché una condizione è vera |
do { ... } while (cond); | Viene eseguito almeno una volta |
break; / continue; | Uscire dal ciclo / passare all'iterazione successiva |
x > 0 ? a : b | Espressione ternaria |
a / b | Divisione intera (scarta il resto) |
a % b | Resto |
a ** 2 | Elevamento a potenza |
unchecked { x++; } | Salta i controlli di overflow (risparmia gas, usalo con cautela) |
Errori: require, revert, assert
Un controllo fallito annulla l'intera transazione e rimborsa il gas non usato.
| Sintassi | Significato |
|---|---|
require(amount > 0, "Amount must be positive"); | Validare input o stato; revert con un messaggio |
revert("Not allowed"); | Interrompere senza condizioni |
error Insufficient(uint available, uint requested); | Dichiarare un errore personalizzato (più economico delle stringhe) |
revert Insufficient(balance, amount); | Revert con un errore personalizzato |
assert(total == a + b); | Verificare un invariante che non deve mai fallire |
try token.transfer(to, amt) returns (bool ok) { ... } catch { ... } | Gestire una chiamata esterna che fallisce |
Eventi
Gli eventi scrivono log a cui le app off-chain possono iscriversi; non sono leggibili dai contratti.
| Sintassi | Significato |
|---|---|
event Transfer(address indexed from, address indexed to, uint value); | Dichiarare un evento |
emit Transfer(msg.sender, to, amount); | Emetterlo |
indexed | Parametro filtrabile (fino a 3 per evento) |
event Log(string message); | Si può registrare qualsiasi tipo ABI |
Ether, indirizzi e variabili globali
Il contesto della transazione arriva da msg, block e tx.
| Sintassi | Significato |
|---|---|
msg.sender | Indirizzo che ha chiamato questa funzione |
msg.value | Wei inviati con la chiamata (richiede payable) |
block.timestamp | Orario del blocco corrente (secondi dall'epoch) |
block.number | Altezza del blocco corrente |
tx.origin | L'account esterno che ha avviato la tx (da evitare per l'autenticazione) |
address(this).balance | Saldo in Ether di questo contratto |
payable(to).transfer(1 ether); | Invia Ether, fa revert in caso di errore |
(bool ok, ) = to.call{value: amt}(""); | Invio di basso livello, restituisce un flag di successo |
receive() external payable {} | Viene eseguita con un semplice trasferimento di Ether |
fallback() external payable {} | Viene eseguita quando nessuna funzione corrisponde |
keccak256(abi.encodePacked(a, b)) | Calcolare l'hash di valori |
abi.encode(x), abi.decode(data, (uint)) | Codificare / decodificare dati ABI |
Tutta la sintassi Solidity che usi ogni giorno, in una sola pagina. Questa Solidity cheat sheet è un riferimento rapido per il linguaggio degli smart contract di Ethereum e di ogni chain EVM: dichiarare un contratto, scegliere i tipi, salvare dati in mapping e struct, scrivere funzioni con la visibilità e la mutabilità giuste, e proteggerle con require, modifier ed eventi.
La sintassi è quella di Solidity 0.8, che controlla l'overflow aritmetico per impostazione predefinita e funziona con Remix, Hardhat e Foundry. Copia ciò che ti serve o provalo dal vivo nel playground Solidity: scrivi un contratto, compilalo ed eseguilo su una EVM nel browser.