Tracciabilità dell'olio, passo passo

8. Il QR e la pagina pubblica

Obiettivo: Collegare il QR della bottiglia a una funzione di sola lettura che risponde: esiste? è richiamata?

Il QR è come il numero di prenotazione: da solo non dice nulla, ma aprendo lo sportello giusto ti mostra la tua pratica.

L'indirizzo

Ogni bottiglia ha un indirizzo web fatto così: /b/<lotto>/<n>, per esempio /b/25B001/12. Il QR è solo quell'indirizzo disegnato come quadratini. Si crea con qualsiasi libreria QR, una riga per bottiglia, partendo dall'indirizzo pubblico del sito.

La funzione di verifica

Una funzione view legge i dati e non costa nulla a chi la chiama: nessun portafoglio, nessuna firma.

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

contract VerificaMinima {
    mapping(bytes32 => uint256) private _idPerCodice; // keccak256(codice) => id, 0 = sconosciuto
    mapping(uint256 => uint32) private _nBottiglie;
    mapping(uint256 => bool) private _richiamato;

    function verificaBottiglia(string calldata codice, uint32 n)
        external
        view
        returns (bool esiste, bool richiamato, uint256 id)
    {
        id = _idPerCodice[keccak256(bytes(codice))];
        if (id == 0) return (false, false, 0);
        esiste = n >= 1 && n <= _nBottiglie[id];
        richiamato = _richiamato[id];
    }
}

Riga per riga

  1. Tre elenchi di appoggio: dal codice (trasformato in numero con keccak256) al numero del lotto, poi bottiglie e richiamo di ciascun lotto. Nel contratto vero li riempiono creaLotto, imbottiglia e richiama.
  2. view significa "solo lettura"; restituisce tre valori con nome.
  3. Se il codice non è noto, l'id vale 0 e rispondiamo "non esiste".
  4. esiste è vero se n è tra 1 e il numero di bottiglie del lotto: è il terzo controllo del capitolo 4.
  5. richiamato alimenta il bollino rosso.

Chiamarla dalla pagina

import { Contract, JsonRpcProvider } from "ethers";

const abi = ["function verificaBottiglia(string codice, uint32 n) view returns (bool esiste, bool richiamato, uint256 id)"];
const contratto = new Contract(INDIRIZZO, abi, new JsonRpcProvider(RPC_URL));

// dall'indirizzo della pagina: /b/25B001/12
const [, , codice, n] = window.location.pathname.split("/");
const [esiste, richiamato] = await contratto.verificaBottiglia(codice, Number(n));

Riga per riga

  1. Importiamo ethers, una libreria che parla con la catena.
  2. L'abi è l'elenco delle funzioni che vogliamo chiamare, scritto in forma leggibile.
  3. Contract unisce indirizzo del contratto, abi e un collegamento alla rete (INDIRIZZO e RPC_URL sono i tuoi valori).
  4. Dall'indirizzo del browser separiamo codice del lotto e numero della bottiglia.
  5. Chiamiamo verificaBottiglia e riceviamo le risposte da mostrare.

Nella demo non serve neppure questo passaggio nel browser: il backend risponde a /api/pubblico/bottiglia/<lotto>/<n> con la verifica già fatta, e la pagina mostra il bollino.

Prova tu

Con la versione completa del contratto nel tuo progetto Hardhat, scrivi un test che crea un lotto da 5 bottiglie e controlla che verificaBottiglia("25B001", 5) dia esiste = true e verificaBottiglia("25B001", 6) dia false.

Cosa hai imparato

Per approfondire