Capitolo 7 di 9
Il programma che porta il prezzo ogni mattina
Il contratto non si sveglia da solo: serve qualcuno che, ogni mattina, gli porti il numero. Quel qualcuno è un piccolo programma (il backend) che gira su un computer sempre acceso.
Il programma fa cinque passi: 1) interroga il Ministero, 2) calcola la mediana, 3) legge il prezzo del POL, 4) salva tutto in un piccolo archivio locale, 5) chiama setPrices sul contratto firmando con la chiave dell'updater, l'unico indirizzo con il ruolo del capitolo 4. Ogni giorno è registrato una volta sola, quindi rilanciarlo non crea doppioni.
import { Contract, JsonRpcProvider, Wallet } from "ethers";
function median(values) {
const s = [...values].sort((a, b) => a - b);
const m = s.length >> 1;
return s.length % 2 ? s[m] : (s[m - 1] + s[m]) / 2;
}
const abi = ["function setPrices(uint256 fuelEurPerLitre, uint256 polEur, uint64 sourceDate)"];
const provider = new JsonRpcProvider(process.env.RPC_URL);
const wallet = new Wallet(process.env.UPDATER_PRIVATE_KEY, provider);
const oracle = new Contract(process.env.ORACLE_ADDRESS, abi, wallet);
const fuelEur = median(pricesOfStations); // e.g. 1.989
const polEur = 0.10; // from a price service
const scale = (x) => BigInt(Math.round(x * 1e6));
const today = Math.floor(Date.parse(new Date().toISOString().slice(0, 10)) / 1000);
const tx = await oracle.setPrices(scale(fuelEur), scale(polEur), today);
await tx.wait();
medianè la funzione del capitolo 2.abiè l'elenco delle funzioni che il programma vuole chiamare, scritto come testo.providerè la porta d'accesso alla rete (l'indirizzo RPC);walletè l'updater, con la sua chiave privata presa da una variabile d'ambiente, mai scritta nel codice.oracleunisce indirizzo del contratto, elenco funzioni e wallet firmatario.scaletrasforma 1,989 in 1989000, il formato con sei decimali.todayè la data odierna a mezzanotte UTC in secondi, lasourceDatedel dato.setPricesinvia la transazione;tx.wait()aspetta che entri in un blocco.
Nel progetto il programma parte da solo alle 8:30 (ora di Roma) con un timer. Se la richiesta fallisce, riprova tre volte a dieci minuti l'una dall'altra.
Se la fonte non risponde
Se il Ministero è irraggiungibile o cambia formato, il programma non scrive nulla. Sulla blockchain resta il prezzo di ieri, con la sua data. Dopo 3 giorni, isFresh (capitolo 4) risponde «no» e buy() e sell() si fermano con l'errore «prezzo vecchio». È una scelta voluta: meglio fermarsi che operare su un numero che non rappresenta più la realtà.
Prova tu
Esegui nel terminale con Node.js la sola funzione median su una lista a tua scelta di 6 numeri (numero pari) e verifica a mano che sia la media dei due centrali.
Cosa hai imparato
- Un contratto non agisce da solo: un programma esterno gli porta il dato a orari fissi.
- La chiave dell'updater firma l'aggiornamento e non si scrive mai nel codice.
- Se la fonte manca, il prezzo diventa «vecchio» e le operazioni si fermano da sole.