Қазіргі әлемде чектер транзакцияларды тексеру және сатып алуды растау үшін өте маңызды. Үлкен банк немесе жол бойындағы шағын дүкен болсын, түбіртектер кәсіпорындар мен жеке тұлғаларға ұйымшыл болып, олардың шығындарын қадағалауға көмектеседі.
Бірақ мұнда бір нәрсе бар: көптеген dApps түбіртектерді ұсынбайды және транзакция мәліметтерін тексеру үшін зерттеушілерге сенеді. Бұған сенудің қажеті болмаса ше? Пайдаланушыларыңызға әмияндарын тексеруді қажет етпей-ақ түбіртектерді тікелей жасау қаншалықты ыңғайлы болатынын елестетіп көріңіз.
Rootstock жүйесінде төлемге негізделген dApp құрып жатсаңыз, бұл мақала сізге 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;
Мұндағы код үзіндісі 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);
: Бұл жол null
мәні бар transactionDetails
күй айнымалысын инициализациялайды және оның мәнін жаңарту үшін 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});
: Бұл жол RPC соңғы нүктесіне Rootstock сынақ желісіне қосылатын Web3js инициализациясын жасайды. Соңғы нүкте URL мекенжайы import.meta.env.VITE_API_KEY
арқылы орта айнымалы мәндерінен шығарылатын API кілтін қамтиды.
Мұндағы код web3.js әдісімен Rootstock жүйесінен асинхронды функцияны пайдаланып транзакция мәліметтерін алады.
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()
: Бұл PDF құжатын көрсететін jsPDF сыныбының жаңа данасын жасайды.
pdf.setFontSize(16)
: Бұл тақырыптың қаріп өлшемін 16-ға орнатады.
pdf.text("Transaction Receipt", 10, 10);
: Бұл PDF құжатындағы координаттарда (10, 10) «Транзакция түбіртегі» тақырыбын қосады.
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
файлында көрсетіңіз
Бұл мақалада Rootstock API кілті және RPC әдісі арқылы түбіртек генераторын PDF немесе QR кодына құра алдыңыз. Сондықтан келесі dApp жобаңызда бұл мүмкіндікті көремін деп үміттенемін.