Στον σημερινό κόσμο, οι αποδείξεις είναι ζωτικής σημασίας για την επικύρωση των συναλλαγών και την τήρηση αποδείξεων αγορών. Είτε πρόκειται για μια μεγάλη τράπεζα είτε για ένα μικρό κατάστημα στην άκρη του δρόμου, οι αποδείξεις βοηθούν τις επιχειρήσεις και τα άτομα να παραμείνουν οργανωμένες και να παρακολουθούν τις δαπάνες τους.
Αλλά εδώ είναι το θέμα: τα περισσότερα dApps δεν παρέχουν αποδείξεις και βασίζονται σε εξερευνητές για την επαλήθευση των λεπτομερειών συναλλαγής. Τι θα γινόταν αν δεν έπρεπε να βασιστείτε σε αυτό; Φανταστείτε πόσο πιο βολικό θα ήταν για τους χρήστες σας να δημιουργούν αποδείξεις απευθείας, χωρίς να χρειάζεται να ελέγξουν τα πορτοφόλια τους.
Εάν δημιουργείτε ένα dApp που βασίζεται σε πληρωμές στο Rootstock, αυτό το άρθρο θα σας δείξει πώς να δημιουργήσετε μια απλή αλλά αποτελεσματική γεννήτρια αποδείξεων χρησιμοποιώντας το Rootstock API και μία μόνο μέθοδο RPC (Remote Procedure Call). Αυτή η προσέγγιση διευκολύνει τη διαδικασία και διασφαλίζει ότι τα αρχεία συναλλαγών σας είναι ακριβή και εύκολη στην πρόσβαση.
Ας μάθουμε τα βήματα και τα εργαλεία που χρειάζονται για να δημιουργήσουμε μια ομαλή εμπειρία δημιουργίας αποδείξεων.
Θα χρησιμοποιήσω το React Typescript και το TailwindCSS για το στυλ
Εγκαταστήστε όλες τις εξαρτήσεις χρησιμοποιώντας αυτήν την εντολή:
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;
Το απόσπασμα κώδικα εδώ θα διαχειρίζεται την κατάσταση και τη λειτουργικότητα για την ανάκτηση και την εμφάνιση λεπτομερειών συναλλαγής χρησιμοποιώντας 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) { ... }
: Αυτή η δομή χρησιμοποιείται για τον χειρισμό τυχόν σφαλμάτων που ενδέχεται να προκύψουν κατά την εκτέλεση της συνάρτησης.error
σε μια κενή συμβολοσειρά.transactionDetails
σε null
.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
σε ένα γενικό μήνυμα σφάλματος "Παρουσιάστηκε άγνωστο σφάλμα".
Εδώ το πακέτο 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
. Εάν είναι, η συνάρτηση επιστρέφει νωρίς και δεν κάνει τίποτα.
const { transactionHash, from, to, cumulativeGasUsed, blockNumber, contractAddress } = transactionDetails;
: Αυτό καταστρέφει το αντικείμενο transactionDetails
για εξαγωγή μεμονωμένων ιδιοτήτων για ευκολότερη πρόσβαση.
const pdf = new jsPDF()
: Αυτό δημιουργεί μια νέα παρουσία της κλάσης jsPDF, η οποία αντιπροσωπεύει ένα έγγραφο PDF.
pdf.setFontSize(16)
: Αυτό ορίζει το μέγεθος γραμματοσειράς της επικεφαλίδας σε 16.
pdf.text("Transaction Receipt", 10, 10);
: Αυτό προσθέτει τον τίτλο "Απόδειξη συναλλαγής" στις συντεταγμένες (10, 10) στο έγγραφο 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).
Εδώ θα αποδώσετε αυτά τα λειτουργικά στοιχεία ως διεπαφή χρήστη στους χρήστες.
Αυτός ο κώδικας έχει ήδη συμπεριλάβει το στυλ χρησιμοποιώντας το 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, ελπίζω να δω αυτό το χαρακτηριστικό σε αυτό.