Στον σημερινό κόσμο, οι αποδείξεις είναι ζωτικής σημασίας για την επικύρωση των συναλλαγών και την τήρηση αποδείξεων αγορών. Είτε πρόκειται για μια μεγάλη τράπεζα είτε για ένα μικρό κατάστημα στην άκρη του δρόμου, οι αποδείξεις βοηθούν τις επιχειρήσεις και τα άτομα να παραμείνουν οργανωμένες και να παρακολουθούν τις δαπάνες τους. Αλλά εδώ είναι το θέμα: τα περισσότερα δεν παρέχουν αποδείξεις και βασίζονται σε εξερευνητές για την επαλήθευση των λεπτομερειών συναλλαγής. Τι θα γινόταν αν δεν έπρεπε να βασιστείτε σε αυτό; Φανταστείτε πόσο πιο βολικό θα ήταν για τους χρήστες σας να δημιουργούν αποδείξεις απευθείας, χωρίς να χρειάζεται να ελέγξουν τα πορτοφόλια τους. dApps Εάν δημιουργείτε ένα dApp που βασίζεται σε πληρωμές στο Rootstock, αυτό το άρθρο θα σας δείξει πώς να δημιουργήσετε μια απλή αλλά αποτελεσματική γεννήτρια αποδείξεων χρησιμοποιώντας το Rootstock API και μία μόνο μέθοδο RPC (Remote Procedure Call). Αυτή η προσέγγιση διευκολύνει τη διαδικασία και διασφαλίζει ότι τα αρχεία συναλλαγών σας είναι ακριβή και εύκολη στην πρόσβαση. Ας μάθουμε τα βήματα και τα εργαλεία που χρειάζονται για να δημιουργήσουμε μια ομαλή εμπειρία δημιουργίας αποδείξεων. Προαπαιτούμενα Πρέπει να έχετε εγκατεστημένο τον κόμβο στη συσκευή σας γνώση Javascript Εγκατεστημένο πλαίσιο Js της επιλογής σας Επεξεργαστής κώδικα π.χ., VScode Θα χρησιμοποιήσω το React Typescript και το TailwindCSS για το στυλ Εργαλείο και Τεχνολογίες Κλειδί API Rootstock : για αλληλεπίδραση με το RPC Web3js : για να δημιουργήσετε έναν κωδικό QR για να σαρώσουν οι χρήστες και να λάβουν την απόδειξή τους QRCode React : για τη δημιουργία της απόδειξης σε PDF Jspdf Εγκαταστήστε, εισαγάγετε τα πακέτα και δημιουργήστε το λειτουργικό στοιχείο Εγκαταστήστε όλες τις εξαρτήσεις χρησιμοποιώντας αυτήν την εντολή: 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 : Αυτό ορίζει μια διεπαφή TypeScript για τη δομή του αντικειμένου λεπτομερειών συναλλαγής. Περιλαμβάνει ιδιότητες όπως , , , , και μια προαιρετική . interface TransactionDetails transactionHash from to cumulativeGasUsed blockNumber contractAddress : Εκκίνηση Web3 : Αυτή η γραμμή αρχικοποιεί το Web3js, συνδέοντας το τελικό σημείο RPC στο δίκτυο δοκιμής Rootstock. Η διεύθυνση URL τελικού σημείου περιλαμβάνει ένα κλειδί API που ανακτάται από μεταβλητές περιβάλλοντος χρησιμοποιώντας . const web3 = new Web3(https://rpc.testnet.rootstock.io/${import.meta.env.VITE_API_KEY}); 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 : Λήψη απόδειξης συναλλαγής ;: Αυτή η γραμμή χρησιμοποιεί τη μέθοδο web3js για την ανάκτηση της απόδειξης συναλλαγής για το αναγνωριστικό συναλλαγής που έχει εισαχθεί. const receipt = await web3.eth.getTransactionReceipt(transactionId) : Ελέγξτε για παραλαβή : Εάν η απόδειξη δεν βρεθεί (δηλαδή, η απόδειξη είναι ή ), εμφανίζεται ένα σφάλμα με το μήνυμα "Η συναλλαγή δεν βρέθηκε!". 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 : Αυτό δημιουργεί μια νέα παρουσία της κλάσης jsPDF, η οποία αντιπροσωπεύει ένα έγγραφο PDF. const pdf = new jsPDF() : Ορισμός μεγέθους γραμματοσειράς και προσθήκη τίτλου : Αυτό ορίζει το μέγεθος γραμματοσειράς της επικεφαλίδας σε 16. pdf.setFontSize(16) : Αυτό προσθέτει τον τίτλο "Απόδειξη συναλλαγής" στις συντεταγμένες (10, 10) στο έγγραφο PDF. pdf.text("Transaction Receipt", 10, 10); : Προσθήκη στοιχείων συναλλαγής σε PDF : Αυτό ορίζει το μέγεθος της γραμματοσειράς σε 12 για το υπόλοιπο κείμενο. pdf.setFontSize(12); : ${transactionHash} : Αυτό προσθέτει τον κατακερματισμό συναλλαγής στις συντεταγμένες (10, 20). pdf.text(Transaction Hash , 10, 20); : Προσθέτει τη διεύθυνση αποστολέα στις συντεταγμένες (10, 30). pdf.text(From: ${from}, 10, 30); : Αυτό προσθέτει τη διεύθυνση της σύμβασης στις συντεταγμένες (10, 40). Σημείωση: Αυτή η γραμμή πρέπει να διορθωθεί για να αποφευχθεί η επικάλυψη κειμένου. pdf.text(Contract Address: ${contractAddress}, 10, 40); : Προσθέτει τη διεύθυνση παραλήπτη στις συντεταγμένες (10, 50). pdf.text(To: ${to}, 10, 50); pdf.text(Cumulative Gas Used: ${cumulativeGasUsed} : Αυτό προσθέτει το αθροιστικό αέριο που χρησιμοποιείται στις συντεταγμένες (10, 60). , 10, 60); : Αυτό προσθέτει τον αριθμό μπλοκ στις συντεταγμένες (10, 70). pdf.text(Block Number: ${blockNumber}, 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 Διαδήλωση https://youtu.be/Xwkl9pu8UiM?embedable=true Σύναψη Σε αυτό το άρθρο, μπορέσατε να δημιουργήσετε μια γεννήτρια αποδείξεων σε κώδικα PDF ή QR χρησιμοποιώντας τη μέθοδο Rootstock API Key and RPC. Έτσι, στο επόμενο έργο σας dApp, ελπίζω να δω αυτό το χαρακτηριστικό σε αυτό.