Coindaro

Notizie crypto, mercati e guide

Capitalizzazione 2,28 T $ −6,41 % in 24 oreVolume 24 h 91,15 Mld $Dominanza BTC 58,7 %ETH 10,1 %Fear & Greed 13 Paura estremaCrypto 22.238

Deploy smart contract su Sepolia: come creare la tua prima dApp

Deploy smart contract su Sepolia passo passo: contratto con Foundry, pagina con viem, connessione del wallet e verifica su Etherscan e Sourcify.

Avanzato 28 min di letturaAggiornato Da leggere prima: Certificazione blockchain: vale la pena? Libri, corsi e podcast
Un portatile, anelli di catena, un ingranaggio, una chiave e nodi collegati
Indice
  1. Come creare una dApp in tre pezzi: un contratto, una pagina e un wallet
  2. Testnet Ethereum: perché nel 2026 si usa Sepolia
  3. Preparare il progetto Foundry e il contratto Guestbook
    1. Installare Foundry e creare il progetto
    2. Il contratto: un libro degli ospiti senza denaro dentro
    3. Compilare e testare prima che qualcosa lasci il tuo computer
  4. Un wallet di prova, una chiave cifrata e un endpoint RPC
    1. Creare un wallet che esiste solo per le testnet
    2. Un endpoint RPC e un .env pulito
    3. Faucet Sepolia: ottenere ETH di test gratis
  5. Deploy smart contract su Sepolia con forge create o forge script
    1. Un solo comando: forge create con –broadcast
    2. Un deploy ripetibile: forge script
    3. Controllare il contratto dal terminale prima di costruire la pagina
  6. Verificare il contratto su Etherscan e Sourcify
    1. Etherscan con una chiave API V2
    2. Sourcify: verifica aperta, senza chiave
  7. Il front end con Vite e viem
    1. Leggere il contratto senza un wallet
    2. Trovare i wallet con EIP-6963
    3. Collegare un wallet con EIP-1193
    4. Scrivere sul contratto e mostrare il risultato
    5. Elencare i messaggi in modo sicuro
  8. Avviare la dApp e controllare ogni anello della catena
  9. Quando il deploy o la pagina non funzionano
  10. Che cosa cambia sulla mainnet, in linea di principio
  11. Mettere il deploy verificato nel portfolio

Hai un contratto Solidity che compila, supera i test e vive su una catena anvil locale che sparisce quando chiudi blockchain that runs exactly as written when it is called, holding and moving funds according to its code, without an intermediary able to change the outcome.">smart contract holding reserves of two or more tokens, supplied by users, that a decentralized exchange uses to execute trades automatically at a price set by a formula.">pool diverge, compared with simply holding the same tokens in a wallet. It becomes permanent when the provider withdraws.">il terminale. Nessun altro può chiamarlo. Per trasformarlo in una dApp servono tre cose in più: un indirizzo su una rete pubblica, un codice sorgente che chiunque possa controllare e una pagina web con un pulsante che uno sconosciuto possa premere. Questa lezione costruisce tutte e tre e mostra come fare il deploy di uno smart contract sulla testnet Sepolia, dove un errore costa al massimo qualche minuto.

Il progetto è un libro degli ospiti. Chiunque abbia un wallet firma un breve messaggio, il contratto lo salva insieme all’autore e all’ora, e la pagina elenca gli ultimi dieci. In tutto sono circa 60 righe tra Solidity e JavaScript. La parte difficile non è il codice, ma la catena di strumenti attorno: compilare, custodire una chiave, scegliere un endpoint RPC, ottenere ether di test, fare il deploy, verificare il sorgente e infine collegare una pagina al contratto. Ognuno di questi passaggi fallisce in un modo tipico, e a ogni passo diciamo quale.

Alcune regole valgono per tutta la lezione. L’ether di test non ha valore: non lo si compra mai, e chi lo vende o promette un «airdrop su testnet» sta mettendo in piedi il tipo di schema descritto nella nostra guida per evitare le truffe crypto. Si usa un wallet nuovo, creato solo per i test. E la chiave di quel wallet non deve mai avvicinarsi alla seed phrase di un wallet con fondi veri, per i motivi spiegati nella nostra lezione sulla sicurezza della seed phrase.

Come creare una dApp in tre pezzi: un contratto, una pagina e un wallet

Un’applicazione decentralizzata è un programma la cui logica gira su una blockchain e la cui interfaccia gira in un browser. Se l’idea è nuova, la nostra spiegazione di che cos’è una dApp la presenta; qui ne costruiamo una. Il contratto custodisce lo stato e fa rispettare le regole. La pagina legge quello stato attraverso un nodo e lo mostra. Il wallet firma le transazioni che cambiano lo stato, quindi la pagina non vede mai una chiave privata.

È la lezione 4 del percorso per sviluppatori. Presuppone che tu abbia fatto la lezione pratica su Solidity (eventi, errori personalizzati, msg.sender, test con Foundry) e che sappia dove cercare le cose dopo il nostro giro tra risorse e certificazioni per imparare la blockchain. Il linguaggio non lo rispieghiamo. Servono anche un terminale, Git, una versione recente di Node.js con supporto a lungo termine (LTS) con npm e un browser con l’estensione di un wallet come MetaMask. La prima volta calcola un pomeriggio, speso soprattutto tra account, chiavi e faucet più che sul codice.

Abbiamo scelto gli strumenti qui sotto perché ciascuno è il più piccolo che svolge il compito. Foundry compila, testa, fa il deploy e verifica da un’unica riga di comando. viem è una libreria TypeScript che parla con qualunque nodo Ethereum e qualunque wallet, senza un framework. Vite serve e impacchetta la pagina. Le versioni sono quelle in vigore al 27 ottobre 2026.

StrumentoVersione al 27 ottobre 2026Ruolo in questa lezioneDove l’abbiamo controllata
Foundry (forge, cast, anvil)v1.8.6, rilasciata il 21 ottobre 2026Compilare, testare, fare il deploy, verificarerelease su GitHub di foundry-rs
Compilatore Solidity0.8.38 (ultima release)Compila il contrattobinaries.soliditylang.org
viem2.57.12 (pubblicata il 26 ottobre 2026)Legge e scrive dalla paginaregistro npm, GitHub
Vite8.3.5Server di sviluppo e buildregistro npm
ethers6.17.0Alternativa a viemregistro npm
wagmi3.7.9Livello React sopra viem, per doporegistro npm

Perché viem e non ethers v6 o wagmi? ethers v6 fa tutto quello che serve in questa lezione e molti tutorial lo usano: avvolgeresti il wallet in un BrowserProvider, ne ricaveresti un signer e costruiresti un oggetto Contract. wagmi aggiunge hook React, cache e connettori di wallet sopra viem, cosa che ripaga in un’app più grande ma nasconde i passaggi che vogliamo farti vedere. viem con JavaScript semplice tiene visibile ogni richiesta, e quello che impari vale anche quando passerai a wagmi.

Testnet Ethereum: perché nel 2026 si usa Sepolia

Ethereum ha diverse reti di prova pubbliche, e sceglierne una sbagliata è il primo errore classico. La pagina sulle reti di ethereum.org è chiara: indica Sepolia come testnet predefinita consigliata per lo sviluppo di applicazioni (in inglese). Gli altri nomi che trovi nei tutorial più vecchi sono spariti o sono pensati per altri. Goerli risulta deprecata. Holesky, una rete grande costruita per provare lo staking, è deprecata: la Ethereum Foundation ne ha annunciato la chiusura il 1 settembre 2025 (in inglese) e ha indirizzato gli sviluppatori di app verso Sepolia. Hoodi, la sua erede, è destinata a validatori e fornitori di staking, non a contratti e front end.

Sepolia ha chain ID 11155111, che in esadecimale si scrive 0xaa36a7, la forma usata dai wallet. Ricorda entrambi i numeri: quello decimale compare in Etherscan e in Foundry, quello esadecimale nelle richieste ai wallet. Block explorer, faucet, provider RPC e i due servizi di verifica che useremo la supportano tutti. Al 27 ottobre 2026 l’elenco delle chain di Etherscan segna Sepolia come disponibile nel piano gratuito dell’API, mentre alcune testnet di layer 2 come Base Sepolia richiedono un piano a pagamento per l’accesso all’API. È un motivo per cominciare su Sepolia e passare a un layer 2 più avanti, quando i concetti della nostra guida a layer 1 e layer 2 conteranno davvero per il tuo progetto.

Perché non restare su anvil? Una catena locale è perfetta per i test e conviene continuare a usarla. Ma nessun altro può raggiungerla, il wallet va puntato a mano su di essa e non insegna nulla dei problemi reali di latenza, prezzi del gas, nonce ed explorer. Perché non la mainnet? Lì ogni transazione costa ether vero e non si annulla. Una testnet si comporta come la mainnet in tutto ciò che serve per imparare, tranne il prezzo.

Preparare il progetto Foundry e il contratto Guestbook

Installare Foundry e creare il progetto

Foundry si installa con il suo aggiornatore, foundryup. I due comandi qui sotto vengono dalla pagina di installazione di Foundry; apri un nuovo terminale tra l’uno e l’altro, oppure ricarica il profilo della shell, perché l’aggiornatore finisca nel percorso dei comandi. Su Windows la documentazione chiede Git Bash o WSL, non PowerShell.

curl -L https://foundry.paradigm.xyz | bash
foundryup

forge init guestbook
cd guestbook
rm src/Counter.sol test/Counter.t.sol script/Counter.s.sol

forge init crea un file foundry.toml, le cartelle src, test e script, ciascuna con un file d’esempio Counter, e installa la libreria forge-std in lib. Cancelliamo i tre file Counter e li sostituiamo con i nostri. La struttura finale dell’intero progetto è questa:

guestbook/
  foundry.toml
  .env            (never committed)
  .env.example    (committed, values empty)
  src/Guestbook.sol
  script/Deploy.s.sol
  web/            (the Vite page)

Il contratto: un libro degli ospiti senza denaro dentro

Salva questo file come src/Guestbook.sol. L’abbiamo compilato con il compilatore Solidity 0.8.38 (solc-js, ottimizzatore attivo, 200 esecuzioni): nessun errore, nessun avviso e 1.549 byte di codice di creazione. Il pragma ^0.8.28 accetta qualsiasi compilatore 0.8 dalla 0.8.28 in su.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

contract Guestbook {
    struct Entry {
        address author;
        uint64 timestamp;
        string message;
    }

    Entry[] private entries;

    event MessageSigned(address indexed author, uint256 indexed id, string message);

    error EmptyMessage();
    error MessageTooLong(uint256 length);

    function sign(string calldata message) external {
        uint256 length = bytes(message).length;
        if (length == 0) revert EmptyMessage();
        if (length > 140) revert MessageTooLong(length);

        entries.push(Entry(msg.sender, uint64(block.timestamp), message));
        emit MessageSigned(msg.sender, entries.length - 1, message);
    }

    function count() external view returns (uint256) {
        return entries.length;
    }

    function getEntry(uint256 id) external view returns (Entry memory) {
        return entries[id];
    }
}

Ogni riga usa qualcosa della lezione su Solidity, quindi spieghiamo solo le scelte di progetto. Il contratto non custodisce ether e non ha funzioni payable: un bug può rovinare un elenco di messaggi ma non far perdere denaro a nessuno, il livello di rischio giusto per un primo contratto pubblico. Non ha proprietario né costruttore, e questo semplifica la verifica, perché non ci sono argomenti del costruttore da codificare. Il limite di 140 conta i byte, non i caratteri: una lettera accentata o un’emoji occupano più byte, quindi un messaggio in italiano arriva al limite prima di quanto faccia pensare la sua lunghezza visibile.

I due errori personalizzati costano meno delle stringhe di revert e permettono alla pagina di dire all’utente esattamente perché una transazione è fallita. L’evento MessageSigned indicizza l’autore e il numero del messaggio, quindi un explorer o un indexer può filtrare per l’uno o per l’altro. La parte costosa del progetto è lo storage: ogni messaggio finisce nello stato della catena, ed ecco perché la lunghezza è limitata e perché un prodotto vero terrebbe i testi lunghi fuori dalla catena.

Compilare e testare prima che qualcosa lasci il tuo computer

Lancia forge build per compilare, poi scrivi in test/ almeno un test che firma un messaggio e controlla count(), e uno che si aspetta l’errore EmptyMessage. La lezione su Solidity ha mostrato come; qui conta l’abitudine. Ogni passaggio da qui in avanti tocca una rete pubblica e costa più tempo da rifare: un bug preso da forge test sul tuo portatile costa secondi, lo stesso bug scoperto dopo il deploy costa un nuovo deploy, una nuova verifica e un nuovo indirizzo nella tua pagina.

Un documento, un bug del software, una lente d'ingrandimento e un ingranaggio insieme
Un bug preso da forge test sul tuo portatile costa secondi; dopo il deploy costa un nuovo indirizzo.

Un wallet di prova, una chiave cifrata e un endpoint RPC

Creare un wallet che esiste solo per le testnet

Nell’estensione del tuo wallet crea un nuovo account oppure, meglio, un wallet separato con la sua seed phrase, e dagli un nome che non ti permetta di confonderlo con altro («Sepolia deployer» va bene). Questa chiave starà su un portatile e verrà digitata in strumenti per sviluppatori: trattala come già mezza esposta e non mandare mai asset veri al suo indirizzo. È la chiave, non l’app del wallet, a controllare un indirizzo.

Poi consegna quella chiave a Foundry in un keystore cifrato invece che in un file in chiaro. Il comando qui sotto chiede la chiave privata senza mostrarla e una password per cifrarla; da quel momento l’account è noto a ogni comando Foundry come deployer. La documentazione di Foundry sul deploy indica il keystore come opzione raccomandata e segna l’opzione --private-key in chiaro come sconsigliata. Altre due strade evitano del tutto il keystore: --ledger firma con un hardware wallet e --browser manda la transazione al wallet del browser per l’approvazione.

cast wallet import deployer --interactive
cast wallet list

Non usare mai gli account anvil predefiniti su una rete pubblica. Le loro chiavi sono pubblicate in ogni copia di Foundry e i bot sorvegliano i fondi inviati a quegli indirizzi.

Un endpoint RPC e un .env pulito

I tuoi strumenti raggiungono Sepolia attraverso un endpoint RPC, l’URL di un nodo che accetta richieste JSON-RPC. Alchemy, Infura, QuickNode, Chainstack e altri danno un endpoint Sepolia gratuito dopo l’apertura di un account, e di solito l’URL contiene la tua chiave API. Esistono anche endpoint pubblici senza account, ma hanno limiti di richieste e cambiano spesso. La definizione di Sepolia incorporata in viem include un RPC pubblico predefinito; non contarci per altro che una prima prova.

Metti l’endpoint e, più avanti, la tua chiave Etherscan in un file .env nella radice del progetto e tieni quel file fuori da Git. Foundry legge un file .env nella cartella del progetto, e la sua pagina sulle buone pratiche chiede di tenere i file .env fuori dal controllo di versione e di versionare invece un .env.example con i valori vuoti, così gli altri sanno quali variabili impostare. Il tuo .env contiene due righe:

SEPOLIA_RPC_URL=https://your-provider.example/v2/your-key
ETHERSCAN_API_KEY=your-etherscan-key

Aggiungi una riga con .env a .gitignore prima del primo commit e lancia git status per verificare che il file non compaia. Nota che cosa non c’è: nessuna chiave privata, perché la custodisce il keystore. Una chiave finita per errore in un repository pubblico va considerata rubata, anche su una testnet, perché la stessa abitudine, un giorno, costa denaro vero.

Poi dai all’endpoint un nome corto in foundry.toml, così ogni comando può dire --rpc-url sepolia:

[profile.default]
src = "src"
out = "out"
libs = ["lib"]

[rpc_endpoints]
sepolia = "${SEPOLIA_RPC_URL}"

Un dettaglio che inganna molti: in Foundry --chain non sceglie la rete. A decidere dove vanno le transazioni è l’URL dell’RPC. Passa sempre --rpc-url.

Faucet Sepolia: ottenere ETH di test gratis

Il deploy richiede gas, e su Sepolia il gas si paga con ether di test che si ottiene gratis da un faucet. Ethereum.org elenca dieci faucet Sepolia, tra cui quelli di Alchemy, Google Cloud Web3, Infura, QuickNode, Chainstack e il PoW Faucet. Le regole cambiano da uno all’altro e nel tempo. Il 27 ottobre 2026 la pagina del faucet di Alchemy diceva che non serviva alcun account, mentre quello di Google Cloud chiede di accedere con un account Google. Il rubinetto base di QuickNode non richiede un account, ma il wallet che riscuote deve avere un piccolo saldo su mainnet, che il faucet dichiara di volere per prevenire abusi e spam. Il PoW Faucet chiede solo il tuo indirizzo e un po’ di lavoro di mining svolto nel browser.

Importi e condizioni cambiano di mese in mese e le pagine dei faucet sono l’unica fonte affidabile, quindi qui non ne riportiamo. Incolla l’indirizzo del tuo wallet di prova, mai la sua chiave, e attendi la transazione. Un primo deploy di un contratto di queste dimensioni richiede solo una piccola frazione di quello che un faucet tipico eroga. Se un sito ti chiede la seed phrase o un pagamento per «sbloccare» ether di test, chiudilo. L’ETH di test non ha valore e non è oggetto di nessuna dichiarazione: per i token veri, la nostra guida alle tasse sulle crypto in Italia spiega come funziona il fisco.

Deploy smart contract su Sepolia con forge create o forge script

Foundry offre due modi per mettere il Guestbook su Sepolia. forge create fa il deploy di un solo contratto con un solo comando. forge script esegue uno script Solidity che può distribuire più contratti e chiamarli, registra tutto quello che ha fatto e si può rieseguire. Comincia dal primo, poi passa al secondo per tutto quello che ripeterai.

Un solo comando: forge create con –broadcast

source .env
forge create src/Guestbook.sol:Guestbook \
  --rpc-url $SEPOLIA_RPC_URL \
  --account deployer \
  --broadcast

Foundry chiede la password del keystore, firma, invia la transazione e stampa tre righe che contano: l’indirizzo del deployer, l’indirizzo del nuovo contratto e l’hash della transazione. Copia l’indirizzo del contratto: serve alla pagina.

Guarda --broadcast. Nel Foundry attuale, senza quel flag, forge create esegue una prova a secco: mostra che cosa succederebbe e non invia nulla. Molti tutorial scritti prima di questo cambiamento omettono il flag, e i loro lettori si chiedono perché sull’explorer non compaia nessun contratto. Le guide più vecchie passano anche --private-key sulla riga di comando, il che lascia la chiave nella cronologia della shell.

Un deploy ripetibile: forge script

Salva questo script come script/Deploy.s.sol. vm.startBroadcast() senza argomento usa il firmatario indicato sulla riga di comando, qui l’account del keystore.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

import {Script} from "forge-std/Script.sol";
import {Guestbook} from "../src/Guestbook.sol";

contract Deploy is Script {
    function run() external returns (Guestbook gb) {
        vm.startBroadcast();   // signer comes from --account on the command line
        gb = new Guestbook();
        vm.stopBroadcast();
    }
}

Eseguilo in tre modi. Il primo comando simula soltanto; il secondo invia davvero; il terzo, da usare solo se la rete è caduta a metà, carica l’esecuzione salvata e invia quello che manca ancora.

forge script script/Deploy.s.sol --rpc-url sepolia --account deployer
forge script script/Deploy.s.sol --rpc-url sepolia --account deployer --broadcast
forge script script/Deploy.s.sol --rpc-url sepolia --account deployer --broadcast --resume

La simulazione esegue il tuo script sullo stato reale di Sepolia e stima il gas senza inviare nulla. L’esecuzione vera scrive un registro in broadcast/Deploy.s.sol/11155111/run-latest.json con ogni transazione, il suo hash, l’indirizzo del contratto e la ricevuta. Molti team versionano quei registri per le reti pubbliche, perché sono la storia di che cosa è stato distribuito dove. La cartella cache/ è un altro discorso: la documentazione di Foundry avverte che le sue copie conservano l’URL RPC di ogni transazione, che può contenere la tua chiave API, quindi aggiungi cache/ a .gitignore.

Controllare il contratto dal terminale prima di costruire la pagina

Apri l’hash della transazione su sepolia.etherscan.io: dovresti vedere «Contract Creation», il tuo deployer come mittente e lo stato di successo. Poi parla con il contratto tramite cast, il client a riga di comando di Foundry. La prima chiamata è gratuita e non richiede chiavi, la seconda invia una vera transazione dal tuo wallet di prova.

export GUESTBOOK=0xYourContractAddress
cast call $GUESTBOOK "count()(uint256)" --rpc-url sepolia
cast send $GUESTBOOK "sign(string)" "hello from the terminal" --rpc-url sepolia --account deployer
cast call $GUESTBOOK "count()(uint256)" --rpc-url sepolia

Se il secondo count restituisce 1, sei riuscito a fare il deploy di uno smart contract su Sepolia che funziona, e ogni problema successivo sta nella pagina, non in Solidity.

Verificare il contratto su Etherscan e Sourcify

Subito dopo il deploy, Etherscan mostra solo il bytecode. Verificare vuol dire consegnare all’explorer il codice sorgente e le impostazioni del compilatore: lui li ricompila e, se il risultato coincide con quello che c’è sulla catena, pubblica il sorgente accanto all’indirizzo. I lettori possono allora controllare che cosa fa il contratto, l’explorer mostra le schede «Read» e «Write» ricavate dall’ABI, e wallet e altri strumenti possono decodificare le tue chiamate. Per un progetto da portfolio è la differenza tra «fidati di me» e «leggi tu stesso».

Etherscan con una chiave API V2

La verifica su Etherscan richiede una chiave API, gratuita con un account Etherscan. Dalla sua API V2 una sola chiave vale per tutte le chain EVM supportate da Etherscan: le richieste vanno a un unico endpoint e un parametro chainid sceglie la rete, come spiega la documentazione dell’API di Etherscan (in inglese). La documentazione parla di più di 60 chain; l’API con l’elenco delle chain ne restituiva 57 il 27 ottobre 2026. La stessa documentazione dà al piano gratuito 3 chiamate al secondo e fino a 100.000 chiamate al giorno su chain selezionate, Sepolia compresa, molto più di quanto serva per una verifica.

forge verify-contract --chain sepolia $GUESTBOOK src/Guestbook.sol:Guestbook --watch

La chiave viene da ETHERSCAN_API_KEY nel tuo ambiente, oppure da --etherscan-api-key. --watch attende e riporta il risultato invece di lasciarti ricaricare la pagina. Puoi anche verificare durante il deploy: aggiungi --verify a forge create o all’esecuzione con broadcast di forge script. Un contratto con argomenti del costruttore richiede di passarli con --constructor-args $(cast abi-encode "constructor(...)" ...); il nostro non ne ha, ed è uno dei motivi per cui l’abbiamo progettato così.

Sourcify: verifica aperta, senza chiave

Sourcify è un servizio e un database di verifica open source. Conserva il sorgente e i metadati del compilatore dei contratti verificati in un archivio pubblico, quindi la verifica non dipende da una sola azienda. La sua documentazione consiglia a chi usa Foundry e Hardhat di verificare con la riga di comando del framework, e l’esempio per Foundry non chiede alcuna chiave:

forge verify-contract $GUESTBOOK src/Guestbook.sol:Guestbook --chain sepolia --verifier sourcify

Sourcify distingue due livelli, rinominati nella documentazione attuale. Un exact match (un tempo «perfect match») significa che il bytecode distribuito è identico byte per byte, hash dei metadati compreso, quindi i file sorgente sono proprio quelli usati per compilare; aggiungere un commento o rinominare una variabile lo rompe. Un match semplice (un tempo «partial match») significa che il codice compila nello stesso contratto ma i metadati sono diversi. Anche appiattire i sorgenti (flattening) esclude l’exact match, quindi lascia che sia Foundry a inviare i file così come sono. Un terzo verificatore, Blockscout, usato da molte chain minori, è disponibile con --verifier blockscout.

Quando la verifica fallisce, la causa è quasi sempre una differenza tra le impostazioni usate per il deploy e quelle usate per verificare: un’altra versione del compilatore, l’ottimizzatore acceso in un caso e spento nell’altro, un numero diverso di esecuzioni, oppure argomenti del costruttore mancanti. Tieni quelle impostazioni in foundry.toml invece che sulla riga di comando, e i due passaggi leggeranno gli stessi valori. Un contratto appena creato può anche risultare «non trovato» per un minuto perché l’explorer non l’ha ancora indicizzato; --watch aspetta.

Il front end con Vite e viem

Crea la pagina accanto al contratto, poi installa viem. La pagina ha bisogno di due valori al momento della build, che Vite legge da web/.env perché i loro nomi cominciano con VITE_.

npm create vite@latest web -- --template vanilla
cd web
npm install viem

Poi crea web/.env con l’indirizzo stampato al deploy e un URL RPC di sola lettura:

VITE_CONTRACT_ADDRESS=0xYourContractAddress
VITE_RPC_URL=https://your-provider.example/v2/your-public-key

Tutto ciò che sta in un bundle front end è pubblico, anche quell’URL RPC. Usa una chiave separata che il provider limiti al tuo dominio, oppure un endpoint pubblico, e non mettere mai in web/.env la chiave Etherscan né altro di segreto. Sostituisci il corpo di web/index.html con questo scheletro: un riquadro per i pulsanti dei wallet, una riga di stato, un modulo e un elenco.

<h1>Guestbook (Sepolia)</h1>
<div id="wallets"></div>
<p id="status">No wallet connected.</p>
<form id="form"><input id="msg" maxlength="140" required><button>Sign</button></form>
<ul id="entries"></ul>
<script type="module" src="/main.js"></script>

Il JavaScript qui sotto va in web/main.js in cinque parti, in quest’ordine. Insieme formano un file di circa 80 righe. Abbiamo assemblato le cinque parti e verificato che il file sia un modulo JavaScript valido; una versione precedente dello stesso codice è stata compilata senza errori con Vite 8.3.5 e viem 2.57.12.

Leggere il contratto senza un wallet

import { createPublicClient, createWalletClient, custom, http, parseAbi } from 'viem'
import { sepolia } from 'viem/chains'

const CONTRACT = import.meta.env.VITE_CONTRACT_ADDRESS // set in .env: 0x... from the deployment
const abi = parseAbi([
  'function sign(string message)',
  'function count() view returns (uint256)',
  'function getEntry(uint256 id) view returns ((address author, uint64 timestamp, string message))',
  'event MessageSigned(address indexed author, uint256 indexed id, string message)',
  'error EmptyMessage()',
  'error MessageTooLong(uint256 length)',
])

// Reads need no wallet: a public RPC is enough.
const publicClient = createPublicClient({ chain: sepolia, transport: http(import.meta.env.VITE_RPC_URL) })

parseAbi trasforma le firme leggibili in un’ABI nel formato che serve a viem e ti dà il controllo dei tipi nell’editor. Potresti importare l’ABI completa da out/Guestbook.sol/Guestbook.json di Foundry; per sei voci, scriverle è più chiaro. Non saltare le due righe error: senza di esse viem non riesce a nominare l’errore personalizzato quando una transazione va in revert. Il client pubblico parla con il tuo endpoint RPC e non ha bisogno di un wallet, quindi un visitatore senza alcuna estensione può comunque leggere il libro degli ospiti. Conta: la maggior parte dei visitatori legge soltanto, e una pagina che pretende un wallet prima di mostrare qualcosa li perde.

Trovare i wallet con EIP-6963

Per anni le estensioni dei wallet si presentavano alle pagine tramite un unico oggetto globale, window.ethereum. Con due estensioni installate si contendevano quell’oggetto e la pagina si ritrovava quello caricato per ultimo. EIP-6963, uno standard in stato Final chiamato Multi Injected Provider Discovery, risolve il problema con due eventi del browser. La pagina lancia eip6963:requestProvider; ogni wallet risponde con eip6963:announceProvider, portando un oggetto info (un id univoco, un nome, un’icona e un identificatore in dominio inverso) e il suo provider. La pagina li elenca e l’utente sceglie.

// EIP-6963: wallets announce themselves; the page listens, then asks.
const providers = new Map()
window.addEventListener('eip6963:announceProvider', (event) => {
  providers.set(event.detail.info.uuid, event.detail)
  render()
})
window.dispatchEvent(new Event('eip6963:requestProvider'))

let walletClient, account

function render() {
  const box = document.getElementById('wallets')
  box.replaceChildren(...[...providers.values()].map(({ info, provider }) => {
    const b = document.createElement('button')
    b.textContent = 'Connect ' + info.name
    b.onclick = () => connect(provider)
    return b
  }))
}

L’ordine conta: registra prima l’ascoltatore, poi invia la richiesta, altrimenti i wallet rispondono quando nessuno ascolta e la pagina non mostra alcun pulsante. I wallet si annunciano anche da soli quando si caricano, quindi un ascoltatore registrato presto intercetta anche chi arriva tardi.

Collegare un wallet con EIP-1193

Il provider che ogni wallet consegna segue EIP-1193, l’interfaccia JavaScript standard tra una pagina e un wallet: una funzione request({ method, params }) più degli eventi. eth_requestAccounts apre la richiesta di connessione del wallet e restituisce gli indirizzi che l’utente consente. wallet_switchEthereumChain chiede al wallet di passare a Sepolia, usando il chain ID in esadecimale. Se l’utente rifiuta, il wallet restituisce l’errore 4001, che EIP-1193 definisce «User Rejected Request».

async function connect(provider) {
  // EIP-1193: provider.request({ method, params })
  const [address] = await provider.request({ method: 'eth_requestAccounts' })
  try {
    await provider.request({ method: 'wallet_switchEthereumChain', params: [{ chainId: '0xaa36a7' }] })
  } catch (e) {
    if (e.code === 4001) return setStatus('Network switch refused.')
    throw e // unknown chain: offer wallet_addEthereumChain instead
  }
  account = address
  walletClient = createWalletClient({ account, chain: sepolia, transport: custom(provider) })
  provider.on('accountsChanged', () => location.reload())
  provider.on('chainChanged', () => location.reload())
  setStatus('Connected: ' + address)
}

function setStatus(t) { document.getElementById('status').textContent = t }

Un wallet che non conosce la chain richiesta restituisce un errore invece di cambiare rete; la risposta consueta è chiamare wallet_addEthereumChain con nome, URL RPC e valuta della chain, poi riprovare. In MetaMask Sepolia è già nell’elenco delle reti: la sua pagina di supporto dice di attivare l’interruttore «Show test networks» per vederla, senza aggiungerla a mano. Altri wallet potrebbero non conoscerla. I due gestori di eventi ricaricano la pagina quando l’utente cambia account o rete nel wallet: rozzo, ma garantisce che la pagina non firmi mai da un indirizzo o su una chain che non si aspettava. Un’app vera aggiornerebbe invece il proprio stato.

Scrivere sul contratto e mostrare il risultato

document.getElementById('form').addEventListener('submit', async (e) => {
  e.preventDefault()
  if (walletClient === undefined) return setStatus('Connect a wallet first.')
  try {
    const hash = await walletClient.writeContract({
      address: CONTRACT, abi, functionName: 'sign', args: [document.getElementById('msg').value],
    })
    setStatus('Sent: ' + hash)
    await publicClient.waitForTransactionReceipt({ hash })
    setStatus('Confirmed.')
    load()
  } catch (err) {
    setStatus(err.shortMessage ?? err.message)
  }
})

writeContract costruisce la transazione, la manda al wallet per la firma e restituisce l’hash quando il wallet la trasmette. Quell’hash prova soltanto che la transazione è stata inviata. waitForTransactionReceipt aspetta che sia inclusa in un blocco, di solito entro uno o due slot (ethereum.org descrive Ethereum a prova di stake come diviso in slot da 12 secondi, in inglese, e Sepolia usa lo stesso consenso), e solo allora la pagina ricarica l’elenco. Se il contratto va in revert, viem decodifica l’errore personalizzato grazie alle due voci error dell’ABI e mette in shortMessage un riepilogo leggibile che nomina EmptyMessage o MessageTooLong.

Un wallet, una spina elettrica, blocchi impilati e uno scudo affiancati
Il wallet firma, la pagina attende la ricevuta e il messaggio entra nella catena.

Elencare i messaggi in modo sicuro

async function load() {
  const n = await publicClient.readContract({ address: CONTRACT, abi, functionName: 'count' })
  const list = document.getElementById('entries')
  list.replaceChildren()
  for (let i = Number(n) - 1; i >= Math.max(0, Number(n) - 10); i--) {
    const x = await publicClient.readContract({ address: CONTRACT, abi, functionName: 'getEntry', args: [BigInt(i)] })
    const li = document.createElement('li')
    li.textContent = x.author.slice(0, 8) + '…: ' + x.message   // textContent, never innerHTML
    list.append(li)
  }
}
if (CONTRACT) load()

Il ciclo legge fino a dieci messaggi, dal più recente, con una chiamata ciascuno. Va bene per una dimostrazione e va piano per un prodotto vero, che leggerebbe gli eventi MessageSigned o userebbe un indexer. Guarda textContent. I messaggi li scrivono degli sconosciuti e restano per sempre su una catena pubblica. Inserirli con innerHTML permetterebbe a chiunque di firmare un messaggio contenente uno script che gira nel browser di ogni visitatore: una falla di cross-site scripting che non potresti mai cancellare dalla catena. Considera ogni stringa on-chain come input non fidato.

Avviare la dApp e controllare ogni anello della catena

Avvia il server di sviluppo con npm run dev da web/ e apri l’indirizzo locale che stampa. Poi scorri questa lista in ordine: ogni passo mette alla prova un anello.

  1. La pagina si carica e, dopo un secondo, elenca il messaggio che hai firmato con cast. Questo prova che URL RPC e indirizzo del contratto sono giusti, senza alcun wallet di mezzo.
  2. Compare un pulsante «Connect» per ogni wallet installato. Se non ne compare nessuno, il wallet manca, è disattivato per questo sito o non supporta EIP-6963.
  3. Un clic apre il wallet e, dopo che accetti, la riga di stato mostra l’indirizzo di test e il wallet è su Sepolia.
  4. Scrivere un messaggio e premere Sign apre nel wallet una conferma che nomina il contratto e una commissione stimata in ETH Sepolia.
  5. Lo stato passa a «Sent», poi a «Confirmed», e il tuo messaggio compare in cima all’elenco.
  6. Su sepolia.etherscan.io la pagina del contratto mostra la tua transazione e, nei Logs di quella transazione, un evento MessageSigned con il tuo indirizzo.

npm run build produce una cartella statica dist/ che puoi ospitare dove vuoi. L’indirizzo del contratto e l’URL RPC vengono incorporati al momento della build, quindi ripeti la build dopo ogni nuovo deploy.

Quando il deploy o la pagina non funzionano

La maggior parte dei guasti in una prima dApp nasce da poche cause. Questa tabella collega il messaggio che vedi alla sua causa abituale.

Che cosa vediCausa abitualeRimedio
«insufficient funds» durante il deployIl wallet di prova non ha ETH Sepolia, oppure fai il deploy da un altro accountControlla il saldo con cast balance, usa un faucet, controlla –account
Il comando finisce ma sull’explorer non c’è nullaManca –broadcast: era una prova a seccoRilancia con –broadcast
Transazione inviata alla rete sbagliataURL RPC di un’altra chain; –chain non sceglie la retePassa –rpc-url sepolia e controlla il chain ID
«execution reverted» con EmptyMessage o MessageTooLongMessaggio vuoto, oppure più di 140 byteAccorcia il messaggio; lettere accentate ed emoji contano come più byte
Verifica: «bytecode does not match»Versione del compilatore, ottimizzatore o esecuzioni diversi dal deployTieni le impostazioni in foundry.toml; passa gli stessi valori
La pagina mostra un elenco vuotoIndirizzo del contratto sbagliato in web/.env, oppure la build è precedenteCorreggi l’indirizzo, riavvia npm run dev o rifai la build
Nessun pulsante per il walletAscoltatore aggiunto dopo la richiesta, oppure il wallet non supporta EIP-6963Registra prima l’ascoltatore; prova un altro wallet
Una transazione resta in sospesoUna transazione precedente dello stesso account è bloccata con una commissione bassaAspetta, oppure sostituiscila dal wallet con lo stesso nonce e una commissione più alta

Che cosa cambia sulla mainnet, in linea di principio

Sulla mainnet di Ethereum gli stessi comandi funzionano con un altro URL RPC, e ogni transazione si paga in ether vero. Il deploy costa il gas usato dalla transazione di creazione moltiplicato per il prezzo del gas in quel momento; il gas usato dipende soprattutto dalla dimensione del codice che salvi, e il prezzo si muove di minuto in minuto, quindi non diamo alcuna cifra. La simulazione di forge script o cast estimate dà le unità di gas; moltiplicale per il prezzo che il wallet mostra nel momento in cui fai il deploy. La nostra voce del glossario sulle commissioni di gas spiega come si combinano commissione base e mancia. Le reti layer 2 eseguono gli stessi contratti per una frazione della commissione, ed è per questo che la maggior parte delle nuove app parte da lì.

Il denaro cambia anche il modello di sicurezza. Un contratto che custodisce o muove fondi richiede un audit esterno prima del lancio, la chiave del deployer va su un hardware wallet (--ledger) e i diritti di amministrazione su un multisig invece che su un solo indirizzo. Il nostro libro degli ospiti ha evitato tutto questo non custodendo nulla, ed è proprio per questo che si presta a un primo deploy.

Poi le regole. Un libro degli ospiti su testnet non solleva alcuna questione legale. Una dApp che raccoglie depositi o emette un token venduto al pubblico può invece entrare nel campo del regolamento europeo sulle cripto-attività, MiCA, che disciplina l’offerta al pubblico di cripto-attività e i prestatori di servizi, e in quello delle norme antiriciclaggio, qualunque cosa dica il codice sulla decentralizzazione. Per il lato fiscale, quello che conta riguarda le cripto vere e non i token di una testnet, che non valgono nulla: ne parla la nostra guida alle tasse sulle crypto in Italia. Questa è la descrizione di un quadro, non una consulenza legale: un progetto che tocca il denaro di altri ha bisogno di un avvocato prima della mainnet.

Mettere il deploy verificato nel portfolio

Un contratto verificato su Sepolia, un repository pubblico con i test e una pagina online sono una voce migliore, nel portfolio di uno sviluppatore junior, di un attestato. Chi recluta può aprire l’explorer, leggere il sorgente, vedere i test e firmare il libro degli ospiti in meno di cinque minuti. Aggiungi un breve README che elenchi i comandi, l’indirizzo e che cosa cambieresti per la mainnet.

Da qui estendi il progetto un passo alla volta: leggere gli eventi invece di fare un ciclo, aggiungere un proprietario che possa mettere in pausa il contratto e testare che solo lui possa farlo, spostare la pagina su wagmi e React, oppure distribuire lo stesso contratto su una testnet di layer 2. Il nostro piano per diventare sviluppatore blockchain colloca questo progetto nel percorso più ampio, e il nostro quadro su lavoro e stipendi nella blockchain mostra quali ruoli lo richiedono. Una lezione successiva del percorso carriere guarda ai lavori nella DeFi.

Fonti

  1. ethereum.org: reti (testnet, faucet Sepolia) (in inglese) ethereum.org
  2. Blog della Ethereum Foundation: annuncio della chiusura di Holesky, 1 settembre 2025 (in inglese) blog.ethereum.org
  3. Documentazione di Foundry: deploy (forge script, keystore, verifica) (in inglese) getfoundry.sh
  4. Documentazione di Foundry: installazione (in inglese) getfoundry.sh
  5. EIP-1193: Ethereum Provider JavaScript API (in inglese) eips.ethereum.org
  6. EIP-6963: Multi Injected Provider Discovery (in inglese) eips.ethereum.org
  7. Documentazione dell'API V2 di Etherscan (in inglese) docs.etherscan.io
  8. Documentazione di Sourcify: come verificare (in inglese) docs.sourcify.dev
  9. Documentazione di viem (in inglese) viem.sh
  10. EUR-Lex: Regolamento (UE) 2023/1114 sui mercati delle cripto-attività (MiCA) eur-lex.europa.eu
  11. ethereum.org: proof of stake (slot da 12 secondi) (in inglese) ethereum.org
  12. Documentazione di Sourcify: exact match e match (in inglese) docs.sourcify.dev
  13. Documentazione dell'API di Etherscan: limiti di richieste (in inglese) docs.etherscan.io
  14. Supporto MetaMask: come vedere le testnet (in inglese) support.metamask.io
  15. Faucet Ethereum Sepolia di QuickNode (in inglese) faucet.quicknode.com
Redazione di Coindaro

Chi ha scritto questo articolo

Redazione

Guide, recensioni e glossario verificati sulle fonti primarie

  • Formazione crypto
  • Recensioni exchange
  • Wallet
  • Glossario

La redazione di Coindaro ricerca e scrive ogni articolo, recensione e guida pubblicata su Coindaro. Ogni fatto è verificato su fonti primarie come documenti ufficiali, autorità di regolamentazione e documentazione dei progetti, e ogni pagina cita le sue fonti. Copriamo mercati crypto, tecnologia e regolamentazione per i lettori di Europa e Nord America, in modo indipendente e senza contenuti a pagamento.

Continua a imparare