Emhlabeni wanamuhla, amarisidi abalulekile ekuqinisekiseni okwenziwayo kanye nokugcina ubufakazi bokuthenga. Kungakhathaliseki ukuthi ibhange elikhulu noma isitolo esincane somgwaqo, amarisidi asiza amabhizinisi nabantu ngabanye ukuthi bahlale behlelekile futhi balandelele indlela abasebenzisa ngayo imali.
Kodwa nansi into: ama-dApps amaningi awanikezi amarisidi futhi athembele kubahloli ukuze baqinisekise imininingwane yokwenziwe. Kuthiwani uma bekungadingeki uthembele kulokho? Cabanga ukuthi kungaba lula kangakanani kubasebenzisi bakho ukwenza amarisidi ngokuqondile, ngaphandle kokudinga ukuhlola izikhwama zabo zemali.
Uma wakha i-dApp esekelwe enkokhelweni ku-Rootstock, lesi sihloko sizokukhombisa ukuthi ungayenza kanjani ijeneretha yamarisidi elula kodwa esebenzayo usebenzisa i-Rootstock API kanye nendlela eyodwa ye-RPC (I-Remote Procedure Call). Le ndlela yenza inqubo ibe lula futhi iqinisekisa ukuthi amarekhodi akho okwenziwayo anembile futhi kulula ukuwafinyelela.
Masifunde izinyathelo namathuluzi adingekayo ukuze udale umuzwa wokwenza amarisidi oshelelayo.
Ngizosebenzisa i-React Typescript ne-TailwindCSS ukwenza isitayela
Faka konke okuncikile usebenzisa lo myalo :
npm i web3js jspdf qrcode.react
Dala ifayela elisha noma sebenzisa i App.jsx
Ngenisa amaphakheji kufayela ngokulandelayo:
import { useState } from "react"; import Web3 from "web3"; import { jsPDF } from "jspdf"; import { QRCodeSVG } from "qrcode.react";
Qalisa ingxenye yokusebenza
const TransactionReceipt = () => { /......./ } export default TransactionReceipt;
Amazwibela ekhodi lapha azophatha isimo kanye nokusebenza kokulanda nokubonisa imininingwane yokwenziwe kusetshenziswa i-useState hook, Web3js, Rootstock RPC kanye ne-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}` );
Ukuphathwa Kwezwe :
const [transactionId, setTransactionId] = useState("");
: Lo mugqa uqalisa i transactionId
eguquguqukayo yesimo . Lokhu okuguquguqukayo kwesimo kuzoba nesibopho se-hashi yokwenziwayo efakiwe lapho ezinye izinto eziguquguqukayo nemisebenzi izoba namandla ukuze kukhiqizwe irisidi.const [transactionDetails, setTransactionDetails] = useState<TransactionDetails | null>(null);
: Lo mugqa uqalisa transactionDetails
eguquguqukayo yesimo enenani null
futhi inikeza umsebenzi setTransactionDetails
ukuze ubuyekeze inani layo. Isifunda singabamba into ethi TransactionDetails
noma null
.const [error, setError] = useState("");
: Lo mugqa uqalisa error
elishintshashintshayo lesimo ngochungechunge olungenalutho futhi uhlinzeka ngomsebenzi setError
ukuze ubuyekeze inani lalo.I-TypeScript Interface :
interface TransactionDetails
: Lokhu kuchaza isixhumi esibonakalayo se-TypeScript sesakhiwo sento yemininingwane yokwenziwe. Kuhlanganisa izici ezifana ne transactionHash
, from
, to
, cumulativeGasUsed
, blockNumber
, kanye contractAddress
ozikhethela lona .Ukuqaliswa kwe-Web3 :
const web3 = new Web3(https://rpc.testnet.rootstock.io/${import.meta.env.VITE_API_KEY});
: Lo mugqa uqalisa i-Web3js, ixhume endaweni yokugcina ye-RPC ku-Rootstock testnet. I-URL yephoyinti lokugcina ifaka phakathi ukhiye we-API otholwa kokuguquguqukayo kwemvelo kusetshenziswa import.meta.env.VITE_API_KEY
.
Ikhodi lapha izolanda imininingwane yokwenziwayo isebenzisa umsebenzi ongavumelanisiwe ku-Rootstock ngendlela ye-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) { ... }
: Lesi sakhiwo sisetshenziselwa ukuphatha noma yimaphi amaphutha angenzeka ngesikhathi sokwenziwa komsebenzi.error
kuyunithi yezinhlamvu engenalutho.transactionDetails
ukuthi null
.const receipt = await web3.eth.getTransactionReceipt(transactionId)
;: Lo mugqa usebenzisa indlela ye-web3js ukuze ulande irisidi yokwenziwe ye-Input TransactionId.if (!receipt) { throw new Error("Transaction not found!"); }
: Uma irisidi ingatholakali (okungukuthi, irisidi null
noma undefined
), ziphonswa iphutha ngomlayezo othi "Okwenziwe akutholakali!".setTransactionDetails(receipt)
: Uma irisidi itholwa, ibuyekeza isimo transactionDetails
neresidi elandiwe.catch (err) { ... }
: Leli bhulokhi libamba noma yimaphi amaphutha enzeka ngesikhathi kusetshenziswa ibhulokhi try
.if (err instanceof Error) { setError(err.message); } else { setError("An unknown error occurred"); }
: Uma iphutha elibanjwe yisibonelo sekilasi Lephutha, lisetha isimo error
kumlayezo wephutha. Uma kungenjalo, isetha isimo error
kumlayezo wephutha elijwayelekile "Kwenzeke iphutha elingaziwa".
Lapha iphakheji ye-Jspdf izosetshenziselwa ukukhiqiza i-PDF equkethe imininingwane yokwenziwe.
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;
: Lokhu kuhlola ukuthi transactionDetails
null
noma undefined
. Uma kunjalo, umsebenzi ubuya kusenesikhathi futhi awenzi lutho.
const { transactionHash, from, to, cumulativeGasUsed, blockNumber, contractAddress } = transactionDetails;
: Lokhu kucekela phansi into ye transactionDetails
ukukhipha izakhiwo ngazinye ukuze zifinyeleleke kalula.
const pdf = new jsPDF()
: Lokhu kudala isibonelo esisha sekilasi le-jsPDF, elimele idokhumenti ye-PDF.
pdf.setFontSize(16)
: Lokhu kusetha usayizi wefonti wesihloko ku-16.
pdf.text("Transaction Receipt", 10, 10);
: Lokhu kwengeza isihloko esithi "Irisidi Yokwenziwe" kumakhonsathi (10, 10) kudokhumenti ye-PDF.
pdf.setFontSize(12);
: Lokhu kusetha usayizi wefonti ku-12 kuwo wonke umbhalo.
pdf.text(Transaction Hash
: ${transactionHash} , 10, 20);
: Lokhu kungeza i-hashi yokwenziwayo kumazixhumanisi (10, 20).
pdf.text(From: ${from}, 10, 30);
: Lokhu kwengeza ikheli lomthumeli kumazixhumanisi (10, 30).
pdf.text(Contract Address: ${contractAddress}, 10, 40);
: Lokhu kwengeza ikheli lenkontileka kumazixhumanisi (10, 40). Qaphela: Lo mugqa kufanele ulungiswe ukugwema ukugqagqana kombhalo.
pdf.text(To: ${to}, 10, 50);
: Lokhu kwengeza ikheli lomamukeli kumazixhumanisi (10, 50).
pdf.text(I-Cumulative Gas Used: ${cumulativeGasUsed} , 10, 60);
: Lokhu kungeza igesi eqoqwayo esetshenziswa ezididiyelweni (10, 60).
pdf.text(Block Number: ${blockNumber}, 10, 70);
: Lokhu kwengeza inombolo yebhulokhi kuzixhumanisi (10, 70).
Lapha uzobe unikeza lezo zingxenye ezisebenzayo njenge-UI kubasebenzisi.
Le khodi isivele yafaka isitayela kusetshenziswa i-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>
Kujeneretha wekhodi ye-QR, kusetshenziswe umtapo wezincwadi we-qrcode.react, futhi imininingwane yokwenziwe yabethelwa kuyo ikhodi ye-QR SVG.
Uma ulandela lesi sinyathelo, i-codebase yakho kufanele ibukeke kanje:
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;
Bese, ngenisa i- TransactionReceipt
futhi uyinikeze kufayela lakho le App.tsx
Kulesi sihloko, ukwazile ukwakha ijeneretha yamarisidi ibe yi-PDF noma ikhodi ye-QR usebenzisa i-Rootstock API Key kanye nendlela ye-RPC. Ngakho kuphrojekthi yakho elandelayo ye-dApp, ngithemba ukubona lesi sici kuyo.