ChainIntegrate — Guida operativa
LSP8 • mint • setCertificateData • revoke • supersede • freeze
ok / completato
attenzione
bloccante / gate

Come funziona la pagina “ChainIntegrate — dApp - Mint” (passo-passo)

Questa guida descrive in modo pratico cosa fa la pagina e in che ordine conviene usarla. La logica chiave è: prima connetti il wallet, poi fai login con firma, poi la UI abilita tutte le azioni owner-only (mint / setData / admin / freeze) solo se il wallet loggato coincide con owner() del contratto (verifica server-side via RPC).

Concetto base

Gate: Wallet + Sessione + Owner

La pagina usa tre “semafori” (pill in alto) per decidere se i pulsanti sono attivi:

  • Wallet connesso: hai un provider (window.lukso o window.ethereum) e un account selezionato.
  • Sessione autorizzata: dopo la firma, il server crea/valida una sessione (cookie) e la pagina la legge da ./api/status.php.
  • Owner del contratto: lato on-chain si confronta il tuo address con owner().
Effetto pratico: finché non hai wallet + sessione ok, quasi tutti i campi e bottoni sono disabilitati (opacity bassa).
Se non sei owner, anche con sessione ok, le funzioni owner-only ti daranno errore.
Componenti

Chi fa cosa (browser / server / chain)

Browser (JS)
Connessione wallet, firma login, chiamate on-chain via ethers, gestione form, QR canvas, copia link.
Server (API PHP)
Sessione, verify owner server-side, hashing “pepperato”, Pinata upload, storage JSON (summary + cleartext).
Endpoint citati dalla pagina (quelli importanti)
  • ./api/nonce.php → genera nonce per messaggio di login.
  • ./api/login.php → invia address/message/signature e apre sessione “pending”.
  • ./api/verify_owner.php → controlla via RPC che l’address loggato sia owner().
  • ./api/status.php → la UI legge auth e address sessione.
  • ./api/hash_fields.php → calcola tokenId e hash (pepper interno) server-side.
  • ./api/pinata_upload.php → carica PDF su Pinata e restituisce CID + URL.
  • ./api/cert_summary_mint.php → indice “operativo” (select list, status, ecc.).
  • ./api/cert_metadata_clear.php → cleartext JSON (solo dati umani) legati al tokenId.
  • ./api/clients_list.php → lista clienti per la select “Mint To”.
Flusso consigliato

La sequenza “giusta” per emettere un certificato

Qui sotto c’è la procedura completa, nell’ordine in cui evita più errori (tokenId sbagliato, hash mancanti, date non syncate, ecc.).

1

Connetti UP

Premi Connetti UP. La pagina cerca un provider (window.lukso oppure window.ethereum), chiama eth_requestAccounts, crea ethers.providers.Web3Provider e prende signer + address.
Se il chainId non è quello atteso (es. 4201), lo segnala in console (non blocca).
2

Login (firma)

Premi Login (firma). La pagina:
  • chiede un nonce a ./api/nonce.php
  • compone un messaggio testuale con address, nonce, issuedAt, URI
  • firma con signer.signMessage()
  • manda tutto a ./api/login.php
  • poi chiama ./api/verify_owner.php passando l’indirizzo contratto
Se va bene, la pill “Sessione” diventa ok e la UI sblocca i controlli.
3

Inizializza

Premi Inizializza. Qui la pagina:
  • crea new ethers.Contract(addr, ABI, signer)
  • legge owner() e calcola isOwner
  • tenta metadataFrozen() (freeze collezione)
Aggiorna lo “Stato rapido” (contract/owner/isOwner/metadataFrozen).
4

Genera tokenId (server-side)

Inserisci Numero certificato (umano) e premi Genera tokenId. Il server (con pepper interno) restituisce:
  • tokenId (bytes32) → finisce in mint_tokenId
  • certificateNumberHash (bytes32) → finisce in c_certificateNumberHash
In più la UI prepara i link verify_link e verify_qr e genera l’anteprima QR.
5

Seleziona il destinatario (Mint To)

Puoi incollare a mano l’address in “Mint: to”, oppure:
  • Carica clienti → chiama ./api/clients_list.php
  • scegli dalla dropdown → l’address viene copiato in automatico
6

Mint (on-chain) + indice JSON

Premi Mint. La pagina chiama mintCert(tokenId, to, data). Se confermata la tx:
  • scrive nello store “summary” (cert_summary_mint.php) i dati minimi: tokenId, to, status, txHash, certificateNumber
  • scrive anche il cleartext minimo (cert_metadata_clear.php) almeno con certificateNumber
Così poi le select “Carica lista” mostrano i certificati.
7

Compila i “dati umani” (manuale o da JSON)

Hai due strade:
  • Compila a mano nelle maschere (ragione sociale, P.IVA, ecc.)
  • Compila da JSON → carichi un .json e la UI popola i campi (supporta vari formati)
Nota: le date vengono inserite come YYYY-MM-DD e poi convertite in timestamp (sec) in campi nascosti.
8

Converti (server) → Hash

Premi Converti (server) → Hash + compila campi on-chain. Il server calcola i vari *Hash (pepper interno) e la UI li mette nei campi c_*Hash.
Questo è fondamentale perché setCertificateData scrive solo hash (non i valori in chiaro).
9

Documento: hash PDF + (opzionale) upload Pinata

Se hai un PDF:
  • Calcola hash PDF → usa WebCrypto SHA-256 e compila documentHash come bytes32
  • Upload PDF su Pinata → pinata_upload.php, ottieni CID e (se vuoto) compili documentURI
10

Invia setCertificateData (on-chain) + salva cleartext

Premi Invia setCertificateData. La pagina valida che ci siano:
  • certificateNumberHash
  • date (inspectionDate + validUntil)
  • documentHash
Poi manda la tx e aggiorna lo store “summary” (per liste/filtri). In parallelo prova a salvare il cleartext completo nel JSON (così nelle verifiche puoi mostrare i dati umani, se autorizzato).
Regola d’oro: tokenId e hash vengono generati server-side per tenere il pepper fuori dal browser. È il motivo per cui Numero certificato (umano) non va mai on-chain “in chiaro”.
Admin

Revoke e Supersede

Queste azioni cambiano lo stato del certificato:

  • Revoke: chiama revoke(tokenId) e patcha lo store summary a Revoked.
  • Supersede: chiama supersede(oldTokenId,newTokenId) e aggiorna lo store:
    • old → Superseded + supersededBy=new
    • new → supersedes=old
Nota pratica: la UI spinge molto sulle dropdown “Carica lista” per ridurre errori di incolla tokenId.
Metadata

Freeze token metadata (REV2)

Qui la pagina usa la freeze “per token”: freezeTokenMetadata(tokenId). Serve a bloccare modifiche future su setCertificateData per quel token.

  • Selezioni token dalla lista → compila freeze_tokenId
  • Premi freeze → tx on-chain + salvataggio nello store summary (tokenMetadataFrozen)
  • In lettura, la pagina prova a mostrare anche tokenMetadataFrozen(tokenId)
Occhio: questo è diverso da metadataFrozen() (freeze “collezione”). Qui è freeze “token-level”.
Lettura

Read: cosa mostra e da dove arriva

La sezione “Leggi certificato on-chain” fa una lettura completa dal contratto e (se possibile) arricchisce con cleartext dallo store server.

On-chain (sempre)
getCertificateData(tokenId) → hash + campi “numerici” + URI/status.
In più prova:
  • tokenMetadataFrozen(tokenId)
  • metadataFrozen()
  • supersededBy(tokenId) / supersedes(tokenId)
Off-chain (se disponibile e autorizzato)
cert_metadata_clear.php?action=get → dati “umani” (ragione sociale, P.IVA, ecc.) salvati in JSON.
Se fallisce (non presente o non autorizzato), la UI lascia solo l’on-chain.
Perché esiste anche lo store “summary”?
  • Per popolare le select (liste certificati) senza dover scansionare la chain.
  • Per mostrare status “operativo” (Valid/Revoked/Superseded) e link di navigazione rapida.
  • Per mantenere un indice coerente tra UI Admin / Freeze / Read.
Link e QR

Verify link e Verify QR: come vengono costruiti

Dopo aver ottenuto un tokenId valido (0x + 64 hex), la pagina genera due URL:

  • verify_link?t=<tokenId> → pagina di verifica “link”
  • verify_qr?t=<tokenId> → pagina di verifica “QR”
QR canvas: la pagina genera un’immagine QR usando un servizio esterno e la disegna nel canvas, poi permette download PNG dal canvas.
(Se un giorno vuoi 100% self-hosted anche per il QR, basta sostituire quel pezzo con una lib JS embedded.)
Utility

Clear: cosa pulisce e cosa NON tocca

Il bottone Clear resetta i campi “operativi” (form, output, file picker, canvas QR), ma non disconnette wallet e non resetta provider/signer/contract.

  • Non ti fa reinserire contract address e chainId
  • Pulisce outputs: out_mint/out_read/out_set/out_admin/out_meta
  • Pulisce select e tokenId in input
Troubleshooting

Problemi tipici e “diagnosi veloce”

  • Bottoni disabilitati → controlla: pill wallet ok? pill sessione ok? (se no, rifai login)
  • Errore owner-only → nello stato rapido isOwner deve essere true
  • TokenId non valido → deve essere 0x + 64 hex, tutto minuscolo/maiuscolo è indifferente
  • Date non passano → serve selezionare i campi type=date (poi vengono convertiti in timestamp)
  • documentHash mancante → o lo incolli oppure fai “Calcola hash PDF”
  • Liste vuote → lo store summary si popola solo dopo mint/set; usa “Carica lista” e verifica i PHP