Στον σημερινό κόσμο, οι αποδείξεις είναι ζωτικής σημασίας για την επικύρωση των συναλλαγών και την τήρηση αποδείξεων αγορών. Είτε πρόκειται για μια μεγάλη τράπεζα είτε για ένα μικρό κατάστημα στην άκρη του δρόμου, οι αποδείξεις βοηθούν τις επιχειρήσεις και τα άτομα να παραμείνουν οργανωμένες και να παρακολουθούν τις δαπάνες τους.
Αλλά εδώ είναι το θέμα: τα περισσότερα dApps δεν παρέχουν αποδείξεις και βασίζονται σε εξερευνητές για την επαλήθευση των λεπτομερειών συναλλαγής. Τι θα γινόταν αν δεν έπρεπε να βασιστείτε σε αυτό; Φανταστείτε πόσο πιο βολικό θα ήταν για τους χρήστες σας να δημιουργούν αποδείξεις απευθείας, χωρίς να χρειάζεται να ελέγξουν τα πορτοφόλια τους.
Εάν δημιουργείτε ένα dApp που βασίζεται σε πληρωμές στο Rootstock, αυτό το άρθρο θα σας δείξει πώς να δημιουργήσετε μια απλή αλλά αποτελεσματική γεννήτρια αποδείξεων χρησιμοποιώντας το Rootstock API και μία μόνο μέθοδο RPC (Remote Procedure Call). Αυτή η προσέγγιση διευκολύνει τη διαδικασία και διασφαλίζει ότι τα αρχεία συναλλαγών σας είναι ακριβή και εύκολη στην πρόσβαση.
Ας μάθουμε τα βήματα και τα εργαλεία που χρειάζονται για να δημιουργήσουμε μια ομαλή εμπειρία δημιουργίας αποδείξεων.
Προαπαιτούμενα
- Πρέπει να έχετε εγκατεστημένο τον κόμβο στη συσκευή σας
- γνώση Javascript
- Εγκατεστημένο πλαίσιο Js της επιλογής σας
- Επεξεργαστής κώδικα π.χ., VScode
Θα χρησιμοποιήσω το React Typescript και το TailwindCSS για το στυλ
Εργαλείο και Τεχνολογίες
- Κλειδί API Rootstock
- Web3js : για αλληλεπίδραση με το RPC
- QRCode React : για να δημιουργήσετε έναν κωδικό QR για να σαρώσουν οι χρήστες και να λάβουν την απόδειξή τους
- Jspdf : για τη δημιουργία της απόδειξης σε PDF
Εγκαταστήστε, εισαγάγετε τα πακέτα και δημιουργήστε το λειτουργικό στοιχείο
Εγκαταστήστε όλες τις εξαρτήσεις χρησιμοποιώντας αυτήν την εντολή:
npm i web3js jspdf qrcode.react
Δημιουργήστε ένα νέο αρχείο ή χρησιμοποιήστε το
App.jsx
Εισαγάγετε τα πακέτα στο αρχείο με τα εξής:
import { useState } from "react"; import Web3 from "web3"; import { jsPDF } from "jspdf"; import { QRCodeSVG } from "qrcode.react";
Αρχικοποιήστε το λειτουργικό στοιχείο
const TransactionReceipt = () => { /......./ } export default TransactionReceipt;
State Management και Web3 Intilaiztion
Το απόσπασμα κώδικα εδώ θα διαχειρίζεται την κατάσταση και τη λειτουργικότητα για την ανάκτηση και την εμφάνιση λεπτομερειών συναλλαγής χρησιμοποιώντας useState hook, Web3js, Rootstock RPC και API.
const [transactionId, setTransactionId] = useState(""); interface TransactionDetails { transactionHash: string; from: string; to: string; cumulativeGasUsed: number; blockNumber: number; contractAddress?: string; } const [transactionDetails, setTransactionDetails] = useState<TransactionDetails | null>(null); const [error, setError] = useState(""); const web3 = new Web3( `https://rpc.testnet.rootstock.io/${import.meta.env.VITE_API_KEY}` );
Κρατική διαχείριση :
-
const [transactionId, setTransactionId] = useState("");
: Αυτή η γραμμή προετοιμάζει μια μεταβλητήtransactionId
. Αυτή η μεταβλητή κατάστασης θα είναι υπεύθυνη για τον κατακερματισμό συναλλαγής που έχει εισαχθεί, τον οποίο άλλες μεταβλητές και συναρτήσεις θα αξιοποιήσουν για να δημιουργήσουν την απόδειξη. -
const [transactionDetails, setTransactionDetails] = useState<TransactionDetails | null>(null);
: Αυτή η γραμμή προετοιμάζει μια μεταβλητήtransactionDetails
μεnull
τιμή και παρέχει μια συνάρτησηsetTransactionDetails
για την ενημέρωση της τιμής της. Η κατάσταση μπορεί να κρατήσει είτε ένα αντικείμενοTransactionDetails
είτεnull
. -
const [error, setError] = useState("");
: Αυτή η γραμμή προετοιμάζει έναerror
μεταβλητής κατάστασης με μια κενή συμβολοσειρά και παρέχει μια συνάρτησηsetError
για την ενημέρωση της τιμής της.
-
Διεπαφή TypeScript :
-
interface TransactionDetails
: Αυτό ορίζει μια διεπαφή TypeScript για τη δομή του αντικειμένου λεπτομερειών συναλλαγής. Περιλαμβάνει ιδιότητες όπωςtransactionHash
,from
,to
,cumulativeGasUsed
,blockNumber
και μια προαιρετικήcontractAddress
.
-
Εκκίνηση Web3 :
-
const web3 = new Web3(https://rpc.testnet.rootstock.io/${import.meta.env.VITE_API_KEY});
: Αυτή η γραμμή αρχικοποιεί το Web3js, συνδέοντας το τελικό σημείο RPC στο δίκτυο δοκιμής Rootstock. Η διεύθυνση URL τελικού σημείου περιλαμβάνει ένα κλειδί API που ανακτάται από μεταβλητές περιβάλλοντος χρησιμοποιώνταςimport.meta.env.VITE_API_KEY
.
-
Λειτουργία για ανάκτηση των λεπτομερειών συναλλαγής
Ο κώδικας εδώ θα ανακτήσει τις λεπτομέρειες της συναλλαγής χρησιμοποιώντας μια ασύγχρονη συνάρτηση από το Rootstock με τη μέθοδο web3.js.
const fetchTransactionDetails = async () => { try { setError(""); setTransactionDetails(null); const receipt = await web3.eth.getTransactionReceipt(transactionId); if (!receipt) { throw new Error("Transaction not found!"); } setTransactionDetails(receipt); } catch (err) { if (err instanceof Error) { setError(err.message); } else { setError("An unknown error occurred"); } } };
- Ρύθμιση χειρισμού σφαλμάτων :
-
try { ... } catch (err) { ... }
: Αυτή η δομή χρησιμοποιείται για τον χειρισμό τυχόν σφαλμάτων που ενδέχεται να προκύψουν κατά την εκτέλεση της συνάρτησης.
-
- Επαναφορά κατάστασης :
- setError("");: Διαγράφει τυχόν προηγούμενα μηνύματα σφάλματος ορίζοντας την κατάσταση
error
σε μια κενή συμβολοσειρά. - setTransactionDetails(null);: Διαγράφει τυχόν στοιχεία προηγούμενης συναλλαγής ορίζοντας την κατάσταση
transactionDetails
σεnull
.
- setError("");: Διαγράφει τυχόν προηγούμενα μηνύματα σφάλματος ορίζοντας την κατάσταση
- Λήψη απόδειξης συναλλαγής :
-
const receipt = await web3.eth.getTransactionReceipt(transactionId)
;: Αυτή η γραμμή χρησιμοποιεί τη μέθοδο web3js για την ανάκτηση της απόδειξης συναλλαγής για το αναγνωριστικό συναλλαγής που έχει εισαχθεί.
-
- Ελέγξτε για παραλαβή :
-
if (!receipt) { throw new Error("Transaction not found!"); }
: Εάν η απόδειξη δεν βρεθεί (δηλαδή, η απόδειξη είναιnull
ήundefined
), εμφανίζεται ένα σφάλμα με το μήνυμα "Η συναλλαγή δεν βρέθηκε!".
-
- Ορισμός λεπτομερειών συναλλαγής :
-
setTransactionDetails(receipt)
: Εάν βρεθεί η απόδειξη, ενημερώνει την κατάστασηtransactionDetails
με την απόδειξη που έχει ληφθεί.
-
- Χειρισμός σφαλμάτων :
-
catch (err) { ... }
: Αυτό το μπλοκ εντοπίζει τυχόν σφάλματα που προκύπτουν κατά την εκτέλεση του μπλοκtry
. -
if (err instanceof Error) { setError(err.message); } else { setError("An unknown error occurred"); }
: Εάν το σφάλμα εντοπισμού είναι μια εμφάνιση της κλάσης Σφάλμα, ορίζει την κατάστασηerror
στο μήνυμα του σφάλματος. Διαφορετικά, ορίζει την κατάστασηerror
σε ένα γενικό μήνυμα σφάλματος "Παρουσιάστηκε άγνωστο σφάλμα".
-
Λειτουργίες για τη δημιουργία PDF απόδειξης
Εδώ το πακέτο Jspdf θα χρησιμοποιηθεί για τη δημιουργία του PDF που περιέχει τις λεπτομέρειες της συναλλαγής.
const generatePDF = () => { if (!transactionDetails) return; const { transactionHash, from, to, cumulativeGasUsed, blockNumber, contractAddress, } = transactionDetails; const pdf = new jsPDF(); pdf.setFontSize(16); pdf.text("Transaction Receipt", 10, 10); pdf.setFontSize(12); pdf.text(`Transaction Hash: ${transactionHash}`, 10, 20); pdf.text(`From: ${from}`, 10, 30); pdf.text(`Contract Address: ${contractAddress}`, 10, 40); pdf.text(`To: ${to}`, 10, 40); pdf.text(`Cumulative Gas Used: ${cumulativeGasUsed}`, 10, 50); pdf.text(`Block Number: ${blockNumber}`, 10, 60); pdf.save("Transaction_Receipt.pdf"); };
- Ελέγξτε για λεπτομέρειες συναλλαγής :
if (!transactionDetails) return;
: Αυτό ελέγχει εάνtransactionDetails
είναιnull
ήundefined
. Εάν είναι, η συνάρτηση επιστρέφει νωρίς και δεν κάνει τίποτα.
- Στοιχεία συναλλαγής Destructure :
const { transactionHash, from, to, cumulativeGasUsed, blockNumber, contractAddress } = transactionDetails;
: Αυτό καταστρέφει το αντικείμενοtransactionDetails
για εξαγωγή μεμονωμένων ιδιοτήτων για ευκολότερη πρόσβαση.
- Δημιουργία εγγράφου PDF :
const pdf = new jsPDF()
: Αυτό δημιουργεί μια νέα παρουσία της κλάσης jsPDF, η οποία αντιπροσωπεύει ένα έγγραφο PDF.
- Ορισμός μεγέθους γραμματοσειράς και προσθήκη τίτλου :
pdf.setFontSize(16)
: Αυτό ορίζει το μέγεθος γραμματοσειράς της επικεφαλίδας σε 16.pdf.text("Transaction Receipt", 10, 10);
: Αυτό προσθέτει τον τίτλο "Απόδειξη συναλλαγής" στις συντεταγμένες (10, 10) στο έγγραφο PDF.
- Προσθήκη στοιχείων συναλλαγής σε PDF :
pdf.setFontSize(12);
: Αυτό ορίζει το μέγεθος της γραμματοσειράς σε 12 για το υπόλοιπο κείμενο.pdf.text(Transaction Hash
: ${transactionHash}, 10, 20);
: Αυτό προσθέτει τον κατακερματισμό συναλλαγής στις συντεταγμένες (10, 20).pdf.text(From: ${from}, 10, 30);
: Προσθέτει τη διεύθυνση αποστολέα στις συντεταγμένες (10, 30).pdf.text(Contract Address: ${contractAddress}, 10, 40);
: Αυτό προσθέτει τη διεύθυνση της σύμβασης στις συντεταγμένες (10, 40). Σημείωση: Αυτή η γραμμή πρέπει να διορθωθεί για να αποφευχθεί η επικάλυψη κειμένου.pdf.text(To: ${to}, 10, 50);
: Προσθέτει τη διεύθυνση παραλήπτη στις συντεταγμένες (10, 50).pdf.text(Cumulative Gas Used: ${cumulativeGasUsed}
, 10, 60);
: Αυτό προσθέτει το αθροιστικό αέριο που χρησιμοποιείται στις συντεταγμένες (10, 60).pdf.text(Block Number: ${blockNumber}, 10, 70);
: Αυτό προσθέτει τον αριθμό μπλοκ στις συντεταγμένες (10, 70).
- Αποθήκευση εγγράφου PDF :
- pdf.save("Transaction_Receipt.pdf");: Αυτό θα αποθηκεύσει το έγγραφο PDF με το όνομα αρχείου "Transaction_Receipt.pdf" .
Η διεπαφή χρήστη
Εδώ θα αποδώσετε αυτά τα λειτουργικά στοιχεία ως διεπαφή χρήστη στους χρήστες.
Αυτός ο κώδικας έχει ήδη συμπεριλάβει το στυλ χρησιμοποιώντας το Tailwindcss
return ( <div className="p-8 font-sans bg-gray-100 min-h-screen"> <div className="max-w-3xl m-auto bg-white p-6 rounded-lg shadow-lg"> <h1 className="text-3xl font-bold mb-6 text-center text-blue-600"> Transaction Receipt Generator </h1> <div className="mb-6"> <div className="flex"> <input type="text" id="transactionId" value={transactionId} onChange={(e) => setTransactionId(e.target.value)} placeholder="Enter transaction hash" className="border p-2 w-full rounded-l-lg" /> <button onClick={fetchTransactionDetails} className="p-2 bg-blue-500 text-white rounded-r-lg" > Fetch Details </button> </div> </div> {error && ( <p className="text-red-500 mt-4 text-center">Error: {error}</p> )} {transactionDetails && ( <div className="mt-6 flex flex-row gap-8"> <div className="w-2/3"> <h2 className="text-2xl font-semibold mb-4 text-center"> Transaction Details </h2> <div className="bg-gray-50 p-4 rounded-lg shadow-inner w-[460px]"> <p> <strong>Transaction Hash:</strong>{" "} {`${transactionDetails.transactionHash.slice( 0, 6 )}...${transactionDetails.transactionHash.slice(-6)}`} </p> <p> <strong>From:</strong> {transactionDetails.from} </p> <p> <strong>Contract Address:</strong>{" "} {transactionDetails.contractAddress} </p> <p> <strong>To:</strong> {transactionDetails.to} </p> <p> <strong>Cumulative Gas Used:</strong>{" "} {transactionDetails.cumulativeGasUsed.toString()} </p> <p> <strong>Block Number:</strong>{" "} {transactionDetails.blockNumber.toString()} </p> </div> <button onClick={generatePDF} className="mt-6 w-full p-3 bg-green-500 text-white rounded-lg" > Download PDF Receipt </button> </div> <div className="w-1/2 text-center"> <h3 className="text-xl font-semibold mb-4">QR Code</h3> <QRCodeSVG value={`Transaction Hash: ${ transactionDetails.transactionHash }, From: ${transactionDetails.from}, To: ${transactionDetails.to}, Contract Address: ${transactionDetails.contractAddress}, Cumulative Gas Used: ${transactionDetails.cumulativeGasUsed.toString()}, Block Number: ${transactionDetails.blockNumber.toString()}`} size={200} className="mx-auto" /> </div> </div> )} </div> </div>
Για τη δημιουργία κωδικών QR, χρησιμοποιήθηκε η βιβλιοθήκη qrcode.react και οι λεπτομέρειες της συναλλαγής κρυπτογραφήθηκαν σε αυτήν τον κωδικό QR SVG.
Τελική βάση κώδικα και έξοδος
Εάν ακολουθήσετε το βήμα, η βάση κωδίκων σας θα πρέπει να μοιάζει με αυτό:
import { useState } from "react"; import Web3 from "web3"; import { jsPDF } from "jspdf"; import { QRCodeSVG } from "qrcode.react"; const TransactionReceipt = () => { const [transactionId, setTransactionId] = useState(""); interface TransactionDetails { transactionHash: string; from: string; to: string; cumulativeGasUsed: number; blockNumber: number; contractAddress?: string; } const [transactionDetails, setTransactionDetails] = useState<TransactionDetails | null>(null); const [error, setError] = useState(""); const web3 = new Web3( `https://rpc.testnet.rootstock.io/${import.meta.env.VITE_API_KEY}` ); const fetchTransactionDetails = async () => { try { setError(""); setTransactionDetails(null); const receipt = await web3.eth.getTransactionReceipt(transactionId); if (!receipt) { throw new Error("Transaction not found!"); } setTransactionDetails(receipt); } catch (err) { if (err instanceof Error) { setError(err.message); } else { setError("An unknown error occurred"); } } }; const generatePDF = () => { if (!transactionDetails) return; const { transactionHash, from, to, cumulativeGasUsed, blockNumber, contractAddress, } = transactionDetails; const pdf = new jsPDF(); pdf.setFontSize(16); pdf.text("Transaction Receipt", 10, 10); pdf.setFontSize(12); pdf.text(`Transaction Hash: ${transactionHash}`, 10, 20); pdf.text(`From: ${from}`, 10, 30); pdf.text(`Contract Address: ${contractAddress}`, 10, 40); pdf.text(`To: ${to}`, 10, 40); pdf.text(`Cumulative Gas Used: ${cumulativeGasUsed}`, 10, 50); pdf.text(`Block Number: ${blockNumber}`, 10, 60); pdf.save("Transaction_Receipt.pdf"); }; return ( <div className="p-8 font-sans bg-gray-100 min-h-screen"> <div className="max-w-3xl m-auto bg-white p-6 rounded-lg shadow-lg"> <h1 className="text-3xl font-bold mb-6 text-center text-blue-600"> Transaction Receipt Generator </h1> <div className="mb-6"> <div className="flex"> <input type="text" id="transactionId" value={transactionId} onChange={(e) => setTransactionId(e.target.value)} placeholder="Enter transaction hash" className="border p-2 w-full rounded-l-lg" /> <button onClick={fetchTransactionDetails} className="p-2 bg-blue-500 text-white rounded-r-lg" > Fetch Details </button> </div> </div> {error && ( <p className="text-red-500 mt-4 text-center">Error: {error}</p> )} {transactionDetails && ( <div className="mt-6 flex flex-row gap-8"> <div className="w-2/3"> <h2 className="text-2xl font-semibold mb-4 text-center"> Transaction Details </h2> <div className="bg-gray-50 p-4 rounded-lg shadow-inner w-[460px]"> <p> <strong>Transaction Hash:</strong>{" "} {`${transactionDetails.transactionHash.slice( 0, 6 )}...${transactionDetails.transactionHash.slice(-6)}`} </p> <p> <strong>From:</strong> {transactionDetails.from} </p> <p> <strong>Contract Address:</strong>{" "} {transactionDetails.contractAddress} </p> <p> <strong>To:</strong> {transactionDetails.to} </p> <p> <strong>Cumulative Gas Used:</strong>{" "} {transactionDetails.cumulativeGasUsed.toString()} </p> <p> <strong>Block Number:</strong>{" "} {transactionDetails.blockNumber.toString()} </p> </div> <button onClick={generatePDF} className="mt-6 w-full p-3 bg-green-500 text-white rounded-lg" > Download PDF Receipt </button> </div> <div className="w-1/2 text-center"> <h3 className="text-xl font-semibold mb-4">QR Code</h3> <QRCodeSVG value={`Transaction Hash: ${ transactionDetails.transactionHash }, From: ${transactionDetails.from}, To: ${transactionDetails.to}, Contract Address: ${transactionDetails.contractAddress}, Cumulative Gas Used: ${transactionDetails.cumulativeGasUsed.toString()}, Block Number: ${transactionDetails.blockNumber.toString()}`} size={200} className="mx-auto" /> </div> </div> )} </div> </div> ); }; export default TransactionReceipt;
Στη συνέχεια, εισαγάγετε το TransactionReceipt
και αποδώστε το στο αρχείο App.tsx
Διαδήλωση
Σύναψη
Σε αυτό το άρθρο, μπορέσατε να δημιουργήσετε μια γεννήτρια αποδείξεων σε κώδικα PDF ή QR χρησιμοποιώντας τη μέθοδο Rootstock API Key and RPC. Έτσι, στο επόμενο έργο σας dApp, ελπίζω να δω αυτό το χαρακτηριστικό σε αυτό.