paint-brush
Creeu un generador de rebuts només amb l'API d'arreel i el mètode RPCper@ileolami
184 lectures

Creeu un generador de rebuts només amb l'API d'arreel i el mètode RPC

per Ileolami19m2024/12/01
Read on Terminal Reader

Massa Llarg; Per llegir

Els rebuts són importants per validar les transaccions i proporcionar un comprovant de compra. Aquest article us mostrarà com crear un generador de rebuts senzill però eficaç mitjançant l'API Rootstock i un únic mètode RPC (Remote Procedure Call).
featured image - Creeu un generador de rebuts només amb l'API d'arreel i el mètode RPC
Ileolami HackerNoon profile picture
0-item
1-item

En el món actual, els rebuts són crucials per validar les transaccions i conservar el comprovant de les compres. Tant si es tracta d'un gran banc com d'una petita botiga a la carretera, els rebuts ajuden les empreses i els particulars a organitzar-se i fer un seguiment de les seves despeses.


Però aquí està la cosa: la majoria de les dApps no proporcionen rebuts i confien en els exploradors per verificar els detalls de la transacció. I si no haguessis de confiar en això? Imagineu-vos com de més convenient seria per als vostres usuaris generar rebuts directament, sense necessitat de revisar les seves carteres.


Si esteu creant una dApp basada en pagaments a Rootstock, aquest article us mostrarà com crear un generador de rebuts senzill però eficaç mitjançant l'API Rootstock i només un mètode RPC (Remote Procedure Call). Aquest enfocament facilita el procés i garanteix que els registres de transaccions siguin precisos i de fàcil accés.


Aprenem els passos i les eines necessàries per crear una experiència de generació de rebuts sense problemes.


Requisits previs

  1. Heu de tenir el node instal·lat al vostre dispositiu
  2. coneixements en Javascript
  3. S'ha instal·lat el marc Js que escolliu
  4. Editor de codi, per exemple, VScode

Faré servir React Typescript i TailwindCSS per a l'estil

Eina i Tecnologies

  1. Clau de l'API d'arreel
  2. Web3js : per interactuar amb RPC
  3. QRCode React : per generar un codi QR perquè els usuaris puguin escanejar i obtenir el seu rebut
  4. Jspdf : per generar el rebut en PDF

Instal·leu, importeu els paquets i creeu el component funcional

  1. Instal·leu totes les dependències mitjançant aquesta comanda:

     npm i web3js jspdf qrcode.react
  2. Creeu un fitxer nou o utilitzeu App.jsx

  3. Importeu els paquets al fitxer amb el següent:

     import { useState } from "react"; import Web3 from "web3"; import { jsPDF } from "jspdf"; import { QRCodeSVG } from "qrcode.react";
  4. Inicialitzar el component funcional

     const TransactionReceipt = () => { /......./ } export default TransactionReceipt;


Gestió de l'Estat i Iniciació Web3

El fragment de codi aquí gestionarà l'estat i la funcionalitat per obtenir i mostrar els detalls de la transacció mitjançant useState hook, Web3js, Rootstock RPC i 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}` );
  1. Gestió estatal :

    • const [transactionId, setTransactionId] = useState(""); : Aquesta línia inicialitza una variable d'estat transactionId . Aquesta variable d'estat serà responsable del hash de transacció introduït que altres variables i funcions aprofitaran per generar el rebut.
    • const [transactionDetails, setTransactionDetails] = useState<TransactionDetails | null>(null); : Aquesta línia inicialitza una variable d'estat transactionDetails amb un valor null i proporciona una funció setTransactionDetails per actualitzar-ne el valor. L'estat pot contenir un objecte TransactionDetails o null .
    • const [error, setError] = useState(""); : Aquesta línia inicialitza un error de variable d'estat amb una cadena buida i proporciona una funció setError per actualitzar-ne el valor.
  2. Interfície TypeScript :

    • interface TransactionDetails : defineix una interfície TypeScript per a l'estructura de l'objecte de detalls de transacció. Inclou propietats com transactionHash , from , to , cumulativeGasUsed , blockNumber i un contractAddress opcional.
  3. Inicialització Web3 :

    • const web3 = new Web3(https://rpc.testnet.rootstock.io/${import.meta.env.VITE_API_KEY}); : Aquesta línia inicialitza Web3js, connectant-se al punt final RPC a la xarxa de prova de Rootstock. L'URL del punt final inclou una clau d'API que es recupera de les variables d'entorn mitjançant import.meta.env.VITE_API_KEY .


Funció per obtenir els detalls de la transacció

El codi aquí obtindrà els detalls de la transacció mitjançant una funció asíncrona de Rootstock amb el mètode 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"); } } };
  1. Configuració de gestió d'errors :
    • try { ... } catch (err) { ... } : aquesta estructura s'utilitza per gestionar qualsevol error que es pugui produir durant l'execució de la funció.
  2. Restableix l'estat :
    • setError("");: Això esborra qualsevol missatge d'error anterior establint l'estat error en una cadena buida.
    • setTransactionDetails(null);: això esborra qualsevol detall de transacció anterior establint l'estat transactionDetails a null .
  3. Obteniu el rebut de la transacció :
    • const receipt = await web3.eth.getTransactionReceipt(transactionId) ;: Aquesta línia utilitza el mètode web3js per obtenir el rebut de transacció per a l'identificador de transacció introduït.
  4. Comprovar el rebut :
    • if (!receipt) { throw new Error("Transaction not found!"); } : Si no es troba el rebut (és a dir, el rebut és null o undefined ), es genera un error amb el missatge "Transacció no trobada!".
  5. Estableix els detalls de la transacció :
    • setTransactionDetails(receipt) : si es troba el rebut, actualitza l'estat transactionDetails amb el rebut obtingut.
  6. Gestió d'errors :
    • catch (err) { ... } : aquest bloc detecta qualsevol error que es produeixi durant l'execució del bloc try .
    • if (err instanceof Error) { setError(err.message); } else { setError("An unknown error occurred"); } : si l'error detectat és una instància de la classe Error, estableix l'estat error al missatge de l'error. En cas contrari, estableix l'estat error en un missatge d'error genèric "S'ha produït un error desconegut".


Funcions per generar PDF de rebut

Aquí s'utilitzarà el paquet Jspdf per generar el PDF que conté els detalls de la transacció.

 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"); };
  1. Comproveu els detalls de la transacció :
    • if (!transactionDetails) return; : Això comprova si transactionDetails és null o undefined . Si és així, la funció torna aviat i no fa res.


  2. Detalls de la transacció de desestructuració :
    • const { transactionHash, from, to, cumulativeGasUsed, blockNumber, contractAddress } = transactionDetails; : Això desestructura l'objecte transactionDetails per extreure propietats individuals per facilitar l'accés.


  3. Crea un document PDF :
    • const pdf = new jsPDF() : Això crea una nova instància de la classe jsPDF, que representa un document PDF.


  4. Estableix la mida de la lletra i afegiu el títol :
    • pdf.setFontSize(16) : Això estableix la mida de la lletra de l'encapçalament a 16.

    • pdf.text("Transaction Receipt", 10, 10); : Això afegeix el títol "Rebut de transacció" a les coordenades (10, 10) al document PDF.


  5. Afegeix els detalls de la transacció al PDF :
    • pdf.setFontSize(12); : Això estableix la mida de la lletra en 12 per a la resta del text.

    • pdf.text(Transaction Hash : ${transactionHash} , 10, 20); : Això afegeix el hash de la transacció a les coordenades (10, 20).

    • pdf.text(From: ${from}, 10, 30); : Això afegeix l'adreça del remitent a les coordenades (10, 30).

    • pdf.text(Contract Address: ${contractAddress}, 10, 40); : Això afegeix l'adreça del contracte a les coordenades (10, 40). Nota: aquesta línia s'ha de corregir per evitar la superposició de text.

    • pdf.text(To: ${to}, 10, 50); : Això afegeix l'adreça del destinatari a les coordenades (10, 50).

    • pdf.text(Gas acumulat utilitzat: ${cumulativeGasUsed} , 10, 60); : Això afegeix el gas acumulat utilitzat a les coordenades (10, 60).

    • pdf.text(Block Number: ${blockNumber}, 10, 70); : Això afegeix el número de bloc a les coordenades (10, 70).


  6. Desa el document PDF :
    • pdf.save("Transaction_Receipt.pdf");: Això desarà el document PDF amb el nom de fitxer "Transaction_Receipt.pdf" .

La interfície d'usuari

Aquí presentareu aquests components funcionals com a interfície d'usuari als usuaris.

Aquest codi ja ha inclòs l'estil amb 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>

Per al generador de codis QR, es va utilitzar la biblioteca qrcode.react i els detalls de la transacció es van xifrar amb el codi QR SVG.

Base de codi final i sortida

Si seguiu el pas, la vostra base de codi hauria de ser així:

 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;


A continuació, importeu el TransactionReceipt i representeu-lo al vostre fitxer App.tsx

Demostració

Conclusió

En aquest article, heu pogut crear un generador de rebuts en un codi PDF o QR mitjançant el mètode Rootstock API Key i RPC. Així que en el vostre proper projecte dApp, espero veure-hi aquesta característica.