En omfattende guide til at bygge en frontend event listener til blockchain smart contracts, der muliggør realtidsovervågning af ændringer i kontrakttilstand. Lær at integrere Web3.js eller ethers.js, afkode event-data og opdatere din applikations UI.
Frontend Blockchain Smart Contract Event Listener: Overvågning af Kontrakttilstand
Decentraliserede applikationer (DApps) kræver ofte realtidsopdateringer for at afspejle ændringer i den underliggende smart contracts tilstand. Det er her, event listeners kommer ind i billedet. Ved at overvåge events, der udsendes af smart contracts, kan frontend-applikationer reagere på tilstandsændringer og give brugerne opdateret information. Denne guide giver en omfattende oversigt over, hvordan man bygger en frontend event listener til blockchain smart contracts, med fokus på praktisk implementering og bedste praksis.
Hvad er Smart Contract Events?
Smart contracts, skrevet i sprog som Solidity, kan udsende events, når specifikke handlinger finder sted i kontrakten. Disse events fungerer som en notifikationsmekanisme, der signalerer til eksterne applikationer, at en tilstandsændring har fundet sted. Tænk på dem som log-poster, der permanent registreres på blockchainen. Events indeholder information om ændringen, hvilket giver applikationer mulighed for at reagere i overensstemmelse hermed.
Overvej for eksempel en simpel token-kontrakt. Den kan udsende en event, når tokens overføres mellem konti. Denne event vil typisk inkludere afsenderens adresse, modtagerens adresse og det overførte beløb. En frontend-applikation kan lytte efter denne event og opdatere brugerens saldo i realtid.
Hvorfor bruge Event Listeners?
Polling af blockchainen for tilstandsændringer er ineffektivt og ressourcekrævende. Event listeners giver en mere elegant og effektiv løsning ved at lade applikationer passivt vente på notifikationer. Dette reducerer belastningen på blockchainen og forbedrer DApp'ens responsivitet.
Væsentlige fordele ved at bruge event listeners inkluderer:
- Realtidsopdateringer: Giv brugere øjeblikkelig feedback på ændringer i kontrakttilstanden.
- Forbedret Effektivitet: Reducer behovet for konstant polling af blockchainen.
- Forbedret Brugeroplevelse: Skab en mere dynamisk og responsiv applikation.
- Reduceret Gasomkostninger: Undgå unødvendige læseoperationer på blockchainen.
Værktøjer og Teknologier
Flere værktøjer og biblioteker kan bruges til at bygge frontend event listeners. De mest populære muligheder inkluderer:
- Web3.js: Et JavaScript-bibliotek, der giver dig mulighed for at interagere med Ethereum-noder og smart contracts. Det giver en omfattende API til at tilgå blockchain-data, sende transaktioner og lytte efter events.
- Ethers.js: Et andet populært JavaScript-bibliotek til interaktion med Ethereum. Det er kendt for sin enkelhed, sikkerhed og ydeevne.
- Infura/Alchemy: Infrastrukturudbydere, der tilbyder pålidelig adgang til Ethereum-netværket. De leverer API'er til at læse blockchain-data og sende transaktioner, hvilket eliminerer behovet for at køre din egen Ethereum-node.
- WebSockets: En kommunikationsprotokol, der muliggør realtids, tovejskommunikation mellem en klient og en server. WebSockets bruges ofte til at levere event-notifikationer til frontenden.
Opbygning af en Frontend Event Listener: En Trin-for-Trin Guide
Dette afsnit beskriver de trin, der er involveret i at bygge en frontend event listener ved hjælp af Web3.js eller ethers.js.
Trin 1: Opsætning af dit udviklingsmiljø
Før du begynder, skal du sikre dig, at du har følgende installeret:
- Node.js: Et JavaScript-runtime-miljø.
- npm (Node Package Manager) eller yarn: En pakkehåndtering til installation af afhængigheder.
- En kodeditor: Visual Studio Code, Sublime Text eller en hvilken som helst anden editor, du foretrækker.
Opret en ny projektmappe og initialiser den med npm eller yarn:
mkdir my-dapp
cd my-dapp
npm init -y
Eller ved brug af yarn:
mkdir my-dapp
cd my-dapp
yarn init -y
Trin 2: Installation af afhængigheder
Installer Web3.js eller ethers.js sammen med eventuelle andre nødvendige afhængigheder. For eksempel kan du have brug for et bibliotek til håndtering af miljøvariabler.
Ved brug af npm:
npm install web3 dotenv
Ved brug af yarn:
yarn add web3 dotenv
Eller for ethers.js:
Ved brug af npm:
npm install ethers dotenv
Ved brug af yarn:
yarn add ethers dotenv
Trin 3: Konfiguration af din Web3 Provider
Du skal konfigurere en Web3-provider for at oprette forbindelse til Ethereum-netværket. Dette kan gøres ved hjælp af Infura, Alchemy eller en lokal Ethereum-node (som Ganache).
Opret en `.env`-fil i din projektmappe og tilføj din Infura- eller Alchemy-API-nøgle:
INFURA_API_KEY=YOUR_INFURA_API_KEY
Derefter, i din JavaScript-fil, skal du konfigurere Web3-provideren:
Ved brug af Web3.js:
require('dotenv').config();
const Web3 = require('web3');
const infuraApiKey = process.env.INFURA_API_KEY;
const web3 = new Web3(new Web3.providers.WebsocketProvider(`wss://mainnet.infura.io/ws/v3/${infuraApiKey}`));
Ved brug af ethers.js:
require('dotenv').config();
const { ethers } = require('ethers');
const infuraApiKey = process.env.INFURA_API_KEY;
const provider = new ethers.providers.WebSocketProvider(`wss://mainnet.infura.io/ws/v3/${infuraApiKey}`);
Bemærk: Erstat `mainnet` med det relevante netværk (f.eks. `ropsten`, `rinkeby`, `goerli`), hvis du bruger et testnetværk.
Trin 4: Hent kontraktens ABI og adresse
For at interagere med din smart contract skal du bruge dens Application Binary Interface (ABI) og adresse. ABI'en er en JSON-fil, der beskriver kontraktens funktioner og events. Adressen er kontraktens placering på blockchainen.
Du kan få ABI'en fra outputtet fra din Solidity-compiler. Adressen vil blive vist, efter du har deployet kontrakten.
Gem ABI'en i en JSON-fil (f.eks. `MyContract.json`) og adressen i din `.env`-fil:
CONTRACT_ADDRESS=0xYourContractAddress...
Trin 5: Oprettelse af en kontraktinstans
Brug ABI'en og adressen til at oprette en kontraktinstans i din JavaScript-fil:
Ved brug af Web3.js:
const contractAddress = process.env.CONTRACT_ADDRESS;
const contractABI = require('./MyContract.json').abi;
const myContract = new web3.eth.Contract(contractABI, contractAddress);
Ved brug af ethers.js:
const contractAddress = process.env.CONTRACT_ADDRESS;
const contractABI = require('./MyContract.json').abi;
const myContract = new ethers.Contract(contractAddress, contractABI, provider);
Trin 6: Lyt efter events
Nu kan du begynde at lytte efter events udsendt af din smart contract. Brug `events`-egenskaben på din kontraktinstans til at abonnere på events.
Ved brug af Web3.js:
myContract.events.MyEvent({
filter: {myIndexedParam: [20,23]}, // Valgfrit filter ved hjælp af indekserede parametre.
fromBlock: 'latest' // Begynd at lytte fra den seneste blok.
}, function(error, event){
if(!error)
{console.log(event);}
else
{console.log(error);}
})
.on('data', function(event){
console.log(event);
})
.on('changed', function(event){
// fjern event fra lokal database
})
.on('error', console.error);
Eller ved brug af async/await:
myContract.events.MyEvent({
filter: {myIndexedParam: [20,23]}, // Valgfrit filter ved hjælp af indekserede parametre.
fromBlock: 'latest' // Begynd at lytte fra den seneste blok.
})
.on('data', async function(event){
console.log(event);
// Behandl event-data her, f.eks. opdater UI'en
try {
// Eksempel: Interager med en anden del af din DApp.
// await someOtherFunction(event.returnValues);
} catch (error) {
console.error("Error processing event:", error);
}
})
.on('changed', function(event){
// fjern event fra lokal database
})
.on('error', console.error);
Ved brug af ethers.js:
myContract.on("MyEvent", (param1, param2, event) => {
console.log("Event MyEvent udsendt!");
console.log("Param1:", param1);
console.log("Param2:", param2);
console.log("Event Data:", event);
// Behandl event-data her, f.eks. opdater UI'en
});
I begge eksempler skal du erstatte `MyEvent` med navnet på den event, du vil lytte efter. Callback-funktionen vil blive udført, hver gang eventen udsendes. Du kan tilgå event-dataene via `event`-objektet.
Trin 7: Håndtering af event-data
`event`-objektet indeholder information om eventen, herunder de argumenter, der blev sendt til den, bloknummeret og transaktions-hashen. Du kan bruge disse data til at opdatere din applikations UI eller udføre andre handlinger.
For eksempel, hvis din event inkluderer en brugers saldo, kan du opdatere saldovisningen på frontenden:
// Inde i event-handleren
const balance = event.returnValues.balance; // Web3.js
// Eller
// const balance = param1; // ethers.js, forudsat at param1 er saldoen
document.getElementById('balance').textContent = balance;
Avancerede teknikker for Event Listeners
Dette afsnit udforsker nogle avancerede teknikker til at bygge mere sofistikerede event listeners.
Filtrering af events
Du kan filtrere events baseret på specifikke kriterier, såsom værdien af en indekseret parameter. Dette kan hjælpe dig med at indsnævre de events, du er interesseret i, og reducere mængden af data, du skal behandle.
I Web3.js kan du bruge `filter`-muligheden, når du abonnerer på events:
myContract.events.MyEvent({
filter: {myIndexedParam: [20, 23]}, // Lyt kun efter events, hvor myIndexedParam er 20 eller 23.
fromBlock: 'latest'
}, function(error, event){
console.log(event);
})
I ethers.js kan du specificere filtre, når du opretter kontraktinstansen eller tilknytter event listeneren:
// Filtrer efter event-navn og indekserede argumenter
const filter = myContract.filters.MyEvent(arg1, arg2);
myContract.on(filter, (arg1, arg2, event) => {
console.log("Event MyEvent udsendt med specifikke argumenter!");
console.log("Arg1:", arg1);
console.log("Arg2:", arg2);
console.log("Event Data:", event);
});
Lyt efter tidligere events
Du kan hente tidligere events, der fandt sted, før din event listener var aktiv. Dette kan være nyttigt til at initialisere din applikations tilstand eller til revisionsformål.
I Web3.js kan du bruge `getPastEvents`-metoden:
myContract.getPastEvents('MyEvent', {
fromBlock: 0,
toBlock: 'latest'
}, function(error, events){
console.log(events);
});
I ethers.js kan du forespørge i event-loggene ved hjælp af providerens `getLogs`-metode:
const blockNumber = await provider.getBlockNumber();
const filter = myContract.filters.MyEvent(arg1, arg2);
const logs = await provider.getLogs({
address: myContract.address,
fromBlock: blockNumber - 1000, // sidste 1000 blokke
toBlock: blockNumber,
topics: filter.topics // filtrer emner
});
for (const log of logs) {
const parsedLog = myContract.interface.parseLog(log);
console.log(parsedLog);
}
Håndtering af tilbageførte transaktioner
Transaktioner kan nogle gange blive tilbageført på grund af fejl eller utilstrækkelig gas. Når en transaktion tilbageføres, udsendes events forbundet med den transaktion ikke. Det er vigtigt at håndtere tilbageførte transaktioner elegant for at undgå uventet adfærd i din applikation.
En måde at håndtere tilbageførte transaktioner på er at overvåge transaktionskvitteringen. Kvitteringen indeholder information om transaktionen, herunder dens status (succes eller fiasko). Hvis status er `0x0`, blev transaktionen tilbageført.
Du kan bruge metoden `web3.eth.getTransactionReceipt` (Web3.js) eller `provider.getTransactionReceipt` (ethers.js) til at hente transaktionskvitteringen.
Brug af WebSockets til realtidsopdateringer
WebSockets giver en vedvarende forbindelse mellem klienten og serveren, hvilket muliggør realtids, tovejskommunikation. Dette er ideelt til at levere event-notifikationer til frontenden.
Både Web3.js og ethers.js understøtter WebSockets. For at bruge WebSockets skal du konfigurere din Web3-provider med et WebSocket-endpoint (som vist i opsætningseksemplerne ovenfor).
Sikkerhedsovervejelser
Når du bygger frontend event listeners, er det vigtigt at overveje følgende sikkerhedsaspekter:
- Datavalidering: Valider altid event-data, før du bruger dem i din applikation. Stol ikke blindt på de data, der modtages fra blockchainen.
- Fejlhåndtering: Implementer robust fejlhåndtering for at forhindre uventet adfærd og potentielle sikkerhedssårbarheder.
- Rate Limiting: Implementer rate limiting for at forhindre misbrug og beskytte din applikation mod denial-of-service-angreb.
- Håndtering af afhængigheder: Hold dine afhængigheder opdaterede for at lukke sikkerhedshuller.
- Sanering af brugerinput: Hvis du viser event-data til brugere, skal du sanere dataene for at forhindre cross-site scripting (XSS)-angreb.
Bedste praksis
Følg disse bedste praksisser for at bygge robuste og vedligeholdelsesvenlige frontend event listeners:
- Brug en modulær arkitektur: Opdel din applikation i mindre, genanvendelige komponenter.
- Skriv enhedstests: Test dine event listeners grundigt for at sikre, at de fungerer korrekt.
- Brug et lognings-framework: Log vigtige events og fejl for at hjælpe dig med at fejlfinde din applikation.
- Dokumenter din kode: Dokumenter din kode tydeligt for at gøre den lettere at forstå og vedligeholde.
- Følg kodningskonventioner: Overhold konsistente kodningskonventioner for at forbedre læsbarhed og vedligeholdelse.
- Overvåg din applikation: Overvåg din applikations ydeevne og ressourceforbrug for at identificere potentielle flaskehalse.
Eksempelscenarie: Overvågning af en token-overførsel
Lad os overveje et praktisk eksempel: overvågning af token-overførsler i en simpel ERC-20 token-kontrakt.
ERC-20-standarden inkluderer en `Transfer`-event, der udsendes, hver gang tokens overføres mellem konti. Denne event inkluderer afsenderens adresse, modtagerens adresse og det overførte beløb.
Her er, hvordan du kan lytte efter `Transfer`-events i din frontend-applikation:
Ved brug af Web3.js:
myContract.events.Transfer({
fromBlock: 'latest'
}, function(error, event){
if(!error)
{
console.log("Transfer Event:", event);
const from = event.returnValues.from;
const to = event.returnValues.to;
const value = event.returnValues.value;
// Opdater UI eller udfør andre handlinger
console.log(`Tokens overført fra ${from} til ${to}: ${value}`);
}
else
{console.error(error);}
});
Ved brug af ethers.js:
myContract.on("Transfer", (from, to, value, event) => {
console.log("Transfer Event udsendt!");
console.log("From:", from);
console.log("To:", to);
console.log("Value:", value.toString()); // Value er et BigNumber i ethers.js
console.log("Event Data:", event);
// Opdater UI eller udfør andre handlinger
console.log(`Tokens overført fra ${from} til ${to}: ${value.toString()}`);
});
Dette kodestykke lytter efter `Transfer`-events og logger afsenderens adresse, modtagerens adresse og det overførte beløb til konsollen. Du kan derefter bruge denne information til at opdatere din applikations UI, vise transaktionshistorik eller udføre andre handlinger.
Konklusion
Frontend blockchain smart contract event listeners er et kraftfuldt værktøj til at bygge responsive DApps i realtid. Ved at overvåge events, der udsendes af smart contracts, kan du give brugerne opdateret information og forbedre den samlede brugeroplevelse. Denne guide har dækket de grundlæggende koncepter, værktøjer og teknikker til at bygge event listeners, sammen med avancerede emner som filtrering af events, håndtering af tilbageførte transaktioner og brug af WebSockets til realtidsopdateringer. Ved at følge de bedste praksisser, der er beskrevet i denne guide, kan du bygge robuste og sikre event listeners, der vil forbedre funktionaliteten og brugeroplevelsen af dine DApps.