Дар ҷаҳони имрӯза квитансияҳо барои тасдиқи транзаксияҳо ва нигоҳ доштани далели харидҳо муҳиманд. Новобаста аз он ки ин бонки калон ё дӯкони хурди канори роҳ аст, квитансияҳо ба корхонаҳо ва шахсони алоҳида кӯмак мекунанд, ки муташаккил бошанд ва хароҷоти онҳоро пайгирӣ кунанд.
Аммо ин аст, ки аксари dApps квитансия намедиҳанд ва барои тафтиши тафсилоти транзаксия ба муҳаққиқон такя мекунанд. Чӣ мешавад, агар шумо набояд ба он такя кунед? Тасаввур кунед, ки барои корбарони шумо бидуни тафтиши ҳамёнҳои худ мустақиман квитансия тавлид кардан то чӣ андоза қулайтар хоҳад буд.
Агар шумо дар асоси пардохт dApp дар Rootstock сохта истода бошед, ин мақола ба шумо нишон медиҳад, ки чӣ гуна як генератори содда ва самараноки квитансияро бо истифода аз Rootstock API ва танҳо як усули RPC (Занги дурдаст) эҷод кунед. Ин равиш равандро осонтар мекунад ва кафолат медиҳад, ки сабтҳои транзаксияҳои шумо дақиқ ва дастрас бошанд.
Биёед қадамҳо ва асбобҳоеро омӯзем, ки барои эҷоди таҷрибаи ҳамвор тавлид кардани квитансия лозиманд.
Ман барои ороиши 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;
Парчами рамз дар ин ҷо ҳолат ва функсияҳоро барои гирифтан ва намоиш додани тафсилоти транзаксия бо истифодаи 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 ба testnet 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
ба паёми хато муқаррар мекунад. Дар акси ҳол, он ҳолати 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(Гази истифодашуда: ${кумилятивии гази истифодашуда} , 10, 60);
: Ин гази ҷамъшавандаро, ки дар координатҳо (10, 60) истифода мешавад, илова мекунад.
pdf.text(Block Number: ${blockNumber}, 10, 70);
: Ин рақами блокро дар координатҳо (10, 70) илова мекунад.
Дар ин ҷо шумо он ҷузъҳои функсионалӣ ҳамчун UI ба корбарон пешкаш хоҳед кард.
Ин код аллакай услубро бо истифодаи 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 ва усули RPC созед. Ҳамин тавр, дар лоиҳаи навбатии dApp, ман умедворам, ки ин хусусиятро дар он бубинам.