En omfattande guide för att bygga en frontend-hÀndelselyssnare för smarta kontrakt pÄ blockkedjan, vilket möjliggör realtidsövervakning av Àndringar i kontraktstillstÄnd. LÀr dig integrera Web3.js eller ethers.js, avkoda hÀndelsedata och uppdatera din applikations UI.
Frontend-lyssnare för smarta kontrakthĂ€ndelser pĂ„ blockkedjan: Ăvervakning av kontraktstillstĂ„nd
Decentraliserade applikationer (DApps) krÀver ofta realtidsuppdateringar för att Äterspegla Àndringar i det underliggande smarta kontraktets tillstÄnd. Det Àr hÀr hÀndelselyssnare kommer in i bilden. Genom att övervaka hÀndelser som emitteras av smarta kontrakt kan frontend-applikationer reagera pÄ tillstÄndsövergÄngar och ge anvÀndarna aktuell information. Denna guide ger en omfattande översikt över hur man bygger en frontend-hÀndelselyssnare för smarta kontrakt pÄ blockkedjan, med fokus pÄ praktisk implementering och bÀsta praxis.
Vad Àr hÀndelser i smarta kontrakt?
Smarta kontrakt, skrivna i sprÄk som Solidity, kan emittera hÀndelser nÀr specifika ÄtgÀrder intrÀffar i kontraktet. Dessa hÀndelser fungerar som en aviseringsmekanism som signalerar till externa applikationer att en tillstÄndsförÀndring har Àgt rum. Se dem som loggposter som permanent registreras pÄ blockkedjan. HÀndelser innehÄller information om förÀndringen, vilket gör att applikationer kan reagera dÀrefter.
TÀnk till exempel pÄ ett enkelt token-kontrakt. Det kan emittera en hÀndelse nÀr tokens överförs mellan konton. Denna hÀndelse skulle vanligtvis inkludera avsÀndarens adress, mottagarens adress och det överförda beloppet. En frontend-applikation kan lyssna efter denna hÀndelse och uppdatera anvÀndarens saldo i realtid.
Varför anvÀnda hÀndelselyssnare?
Att "polla" blockkedjan för tillstÄndsförÀndringar Àr ineffektivt och resurskrÀvande. HÀndelselyssnare erbjuder en mer elegant och effektiv lösning genom att lÄta applikationer passivt vÀnta pÄ aviseringar. Detta minskar belastningen pÄ blockkedjan och förbÀttrar DAppens responsivitet.
Viktiga fördelar med att anvÀnda hÀndelselyssnare inkluderar:
- Realtidsuppdateringar: Ge anvÀndarna omedelbar feedback om Àndringar i kontraktstillstÄnd.
- FörbÀttrad effektivitet: Minska behovet av konstant polling av blockkedjan.
- FörbÀttrad anvÀndarupplevelse: Skapa en mer dynamisk och responsiv applikation.
- Minskade gaskostnader: Undvik onödiga lÀsoperationer pÄ blockkedjan.
Verktyg och tekniker
Flera verktyg och bibliotek kan anvÀndas för att bygga frontend-hÀndelselyssnare. De mest populÀra alternativen inkluderar:
- Web3.js: Ett JavaScript-bibliotek som lÄter dig interagera med Ethereum-noder och smarta kontrakt. Det tillhandahÄller ett omfattande API för att komma Ät blockkedjedata, skicka transaktioner och lyssna efter hÀndelser.
- Ethers.js: Ett annat populÀrt JavaScript-bibliotek för att interagera med Ethereum. Det Àr kÀnt för sin enkelhet, sÀkerhet och prestanda.
- Infura/Alchemy: Infrastrukturleverantörer som erbjuder tillförlitlig Ätkomst till Ethereum-nÀtverket. De tillhandahÄller API:er för att lÀsa blockkedjedata och skicka transaktioner, vilket eliminerar behovet av att köra en egen Ethereum-nod.
- WebSockets: Ett kommunikationsprotokoll som möjliggör realtids, dubbelriktad kommunikation mellan en klient och en server. WebSockets anvÀnds ofta för att leverera hÀndelseaviseringar till frontend.
Bygga en frontend-hÀndelselyssnare: En steg-för-steg-guide
Detta avsnitt beskriver stegen för att bygga en frontend-hÀndelselyssnare med Web3.js eller ethers.js.
Steg 1: SÀtta upp din utvecklingsmiljö
Innan du börjar, se till att du har följande installerat:
- Node.js: En JavaScript-runtime-miljö.
- npm (Node Package Manager) eller yarn: En pakethanterare för att installera beroenden.
- En kodredigerare: Visual Studio Code, Sublime Text, eller nÄgon annan redigerare du föredrar.
Skapa en ny projektkatalog och initiera den med npm eller yarn:
mkdir my-dapp
cd my-dapp
npm init -y
Eller med yarn:
mkdir my-dapp
cd my-dapp
yarn init -y
Steg 2: Installera beroenden
Installera Web3.js eller ethers.js, tillsammans med andra nödvÀndiga beroenden. Du kan till exempel behöva ett bibliotek för att hantera miljövariabler.
Med npm:
npm install web3 dotenv
Med yarn:
yarn add web3 dotenv
Eller för ethers.js:
Med npm:
npm install ethers dotenv
Med yarn:
yarn add ethers dotenv
Steg 3: Konfigurera din Web3-provider
Du mÄste konfigurera en Web3-provider för att ansluta till Ethereum-nÀtverket. Detta kan göras med Infura, Alchemy, eller en lokal Ethereum-nod (som Ganache).
Skapa en `.env`-fil i din projektkatalog och lÀgg till din Infura- eller Alchemy-API-nyckel:
INFURA_API_KEY=DIN_INFURA_API_NYCKEL
Konfigurera sedan Web3-providern i din JavaScript-fil:
Med 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}`));
Med 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}`);
Obs: ErsÀtt `mainnet` med lÀmpligt nÀtverk (t.ex. `ropsten`, `rinkeby`, `goerli`) om du anvÀnder ett testnÀtverk.
Steg 4: HĂ€mta kontraktets ABI och adress
För att interagera med ditt smarta kontrakt behöver du dess Application Binary Interface (ABI) och adress. ABI Àr en JSON-fil som beskriver kontraktets funktioner och hÀndelser. Adressen Àr kontraktets plats pÄ blockkedjan.
Du kan fÄ ABI frÄn din Solidity-kompilators output. Adressen visas efter att du har distribuerat kontraktet.
Spara ABI i en JSON-fil (t.ex. `MyContract.json`) och adressen i din `.env`-fil:
CONTRACT_ADDRESS=0xDinKontraktsadress...
Steg 5: Skapa en kontraktinstans
AnvÀnd ABI och adressen för att skapa en kontraktinstans i din JavaScript-fil:
Med Web3.js:
const contractAddress = process.env.CONTRACT_ADDRESS;
const contractABI = require('./MyContract.json').abi;
const myContract = new web3.eth.Contract(contractABI, contractAddress);
Med ethers.js:
const contractAddress = process.env.CONTRACT_ADDRESS;
const contractABI = require('./MyContract.json').abi;
const myContract = new ethers.Contract(contractAddress, contractABI, provider);
Steg 6: Lyssna efter hÀndelser
Nu kan du börja lyssna efter hÀndelser som emitteras av ditt smarta kontrakt. AnvÀnd `events`-egenskapen i din kontraktinstans för att prenumerera pÄ hÀndelser.
Med Web3.js:
myContract.events.MyEvent({
filter: {myIndexedParam: [20,23]}, // Valfritt filter med indexerade parametrar.
fromBlock: 'latest' // Börja lyssna frÄn det senaste blocket.
}, function(error, event){
if(!error)
{console.log(event);}
else
{console.log(error);}
})
.on('data', function(event){
console.log(event);
})
.on('changed', function(event){
// ta bort hÀndelse frÄn lokal databas
})
.on('error', console.error);
Eller, med async/await:
myContract.events.MyEvent({
filter: {myIndexedParam: [20,23]}, // Valfritt filter med indexerade parametrar.
fromBlock: 'latest' // Börja lyssna frÄn det senaste blocket.
})
.on('data', async function(event){
console.log(event);
// Bearbeta hÀndelsedata hÀr, t.ex. uppdatera UI
try {
// Exempel: Interagera med en annan del av din DApp.
// await someOtherFunction(event.returnValues);
} catch (error) {
console.error("Fel vid bearbetning av hÀndelse:", error);
}
})
.on('changed', function(event){
// ta bort hÀndelse frÄn lokal databas
})
.on('error', console.error);
Med ethers.js:
myContract.on("MyEvent", (param1, param2, event) => {
console.log("HĂ€ndelsen MyEvent emitterades!");
console.log("Param1:", param1);
console.log("Param2:", param2);
console.log("HĂ€ndelsedata:", event);
// Bearbeta hÀndelsedata hÀr, t.ex. uppdatera UI
});
I bÄda exemplen, ersÀtt `MyEvent` med namnet pÄ hÀndelsen du vill lyssna pÄ. Callback-funktionen kommer att exekveras varje gÄng hÀndelsen emitteras. Du kan komma Ät hÀndelsedata via `event`-objektet.
Steg 7: Hantera hÀndelsedata
`event`-objektet innehÄller information om hÀndelsen, inklusive argumenten som skickades till den, blocknumret och transaktionshashen. Du kan anvÀnda dessa data för att uppdatera din applikations UI eller utföra andra ÄtgÀrder.
Till exempel, om din hÀndelse inkluderar en anvÀndares saldo, kan du uppdatera saldovisningen pÄ frontend:
// Inuti hÀndelsehanteraren
const balance = event.returnValues.balance; // Web3.js
// Eller
// const balance = param1; // ethers.js, förutsatt att param1 Àr saldot
document.getElementById('balance').textContent = balance;
Avancerade tekniker för hÀndelselyssnare
Detta avsnitt utforskar nÄgra avancerade tekniker för att bygga mer sofistikerade hÀndelselyssnare.
Filtrera hÀndelser
Du kan filtrera hÀndelser baserat pÄ specifika kriterier, sÄsom vÀrdet pÄ en indexerad parameter. Detta kan hjÀlpa dig att begrÀnsa de hÀndelser du Àr intresserad av och minska mÀngden data du behöver bearbeta.
I Web3.js kan du anvÀnda `filter`-alternativet nÀr du prenumererar pÄ hÀndelser:
myContract.events.MyEvent({
filter: {myIndexedParam: [20, 23]}, // Lyssna bara efter hÀndelser dÀr myIndexedParam Àr 20 eller 23.
fromBlock: 'latest'
}, function(error, event){
console.log(event);
})
I ethers.js kan du specificera filter nÀr du skapar kontraktinstansen eller nÀr du kopplar hÀndelselyssnaren:
// Filtrera efter hÀndelsenamn och indexerade argument
const filter = myContract.filters.MyEvent(arg1, arg2);
myContract.on(filter, (arg1, arg2, event) => {
console.log("HĂ€ndelsen MyEvent emitterades med specifika argument!");
console.log("Arg1:", arg1);
console.log("Arg2:", arg2);
console.log("HĂ€ndelsedata:", event);
});
Lyssna efter tidigare hÀndelser
Du kan hÀmta tidigare hÀndelser som intrÀffade innan din hÀndelselyssnare var aktiv. Detta kan vara anvÀndbart för att initiera din applikations tillstÄnd eller för granskningsÀndamÄl.
I Web3.js kan du anvÀnda `getPastEvents`-metoden:
myContract.getPastEvents('MyEvent', {
fromBlock: 0,
toBlock: 'latest'
}, function(error, events){
console.log(events);
});
I ethers.js kan du frÄga hÀndelseloggarna med hjÀlp av providerns `getLogs`-metod:
const blockNumber = await provider.getBlockNumber();
const filter = myContract.filters.MyEvent(arg1, arg2);
const logs = await provider.getLogs({
address: myContract.address,
fromBlock: blockNumber - 1000, // sista 1000 blocken
toBlock: blockNumber,
topics: filter.topics // filterÀmnen
});
for (const log of logs) {
const parsedLog = myContract.interface.parseLog(log);
console.log(parsedLog);
}
Hantera Äterkallade transaktioner
Transaktioner kan ibland Äterkallas pÄ grund av fel eller otillrÀcklig gas. NÀr en transaktion Äterkallas, emitteras inte hÀndelser associerade med den transaktionen. Det Àr viktigt att hantera Äterkallade transaktioner pÄ ett elegant sÀtt för att undvika ovÀntat beteende i din applikation.
Ett sÀtt att hantera Äterkallade transaktioner Àr att övervaka transaktionskvittot. Kvittot innehÄller information om transaktionen, inklusive dess status (lyckad eller misslyckad). Om statusen Àr `0x0` har transaktionen Äterkallats.
Du kan anvÀnda metoden `web3.eth.getTransactionReceipt` (Web3.js) eller `provider.getTransactionReceipt` (ethers.js) för att hÀmta transaktionskvittot.
AnvÀnda WebSockets för realtidsuppdateringar
WebSockets ger en bestÀndig anslutning mellan klienten och servern, vilket möjliggör realtids, dubbelriktad kommunikation. Detta Àr idealiskt för att leverera hÀndelseaviseringar till frontend.
BÄde Web3.js och ethers.js stöder WebSockets. För att anvÀnda WebSockets, konfigurera din Web3-provider med en WebSocket-slutpunkt (som visas i installations exemplen ovan).
SĂ€kerhetsaspekter
NÀr du bygger frontend-hÀndelselyssnare Àr det viktigt att tÀnka pÄ följande sÀkerhetsaspekter:
- Datavalidering: Validera alltid hÀndelsedata innan du anvÀnder den i din applikation. Lita inte blint pÄ data som tas emot frÄn blockkedjan.
- Felhantering: Implementera robust felhantering för att förhindra ovÀntat beteende och potentiella sÀkerhetssÄrbarheter.
- Rate Limiting: Implementera rate limiting för att förhindra missbruk och skydda din applikation frÄn denial-of-service-attacker.
- Beroendehantering: HÄll dina beroenden uppdaterade för att ÄtgÀrda sÀkerhetssÄrbarheter.
- Sanering av anvÀndarinmatning: Om du visar hÀndelsedata för anvÀndare, sanera datan för att förhindra cross-site scripting (XSS)-attacker.
BĂ€sta praxis
Följ dessa bÀsta praxis för att bygga robusta och underhÄllbara frontend-hÀndelselyssnare:
- AnvÀnd en modulÀr arkitektur: Bryt ner din applikation i mindre, ÄteranvÀndbara komponenter.
- Skriv enhetstester: Testa dina hÀndelselyssnare noggrant för att sÀkerstÀlla att de fungerar korrekt.
- AnvÀnd ett loggningsramverk: Logga viktiga hÀndelser och fel för att hjÀlpa dig felsöka din applikation.
- Dokumentera din kod: Dokumentera din kod tydligt för att göra den lÀttare att förstÄ och underhÄlla.
- Följ kodningskonventioner: Följ konsekventa kodningskonventioner för att förbÀttra lÀsbarheten och underhÄllbarheten.
- Ăvervaka din applikation: Ăvervaka din applikations prestanda och resursanvĂ€ndning för att identifiera potentiella flaskhalsar.
Exempelscenario: Ăvervaka en tokenöverföring
LÄt oss titta pÄ ett praktiskt exempel: övervakning av tokenöverföringar i ett enkelt ERC-20-token-kontrakt.
ERC-20-standarden inkluderar en `Transfer`-hÀndelse som emitteras nÀrhelst tokens överförs mellan konton. Denna hÀndelse inkluderar avsÀndarens adress, mottagarens adress och det överförda beloppet.
SÄ hÀr kan du lyssna efter `Transfer`-hÀndelser i din frontend-applikation:
Med Web3.js:
myContract.events.Transfer({
fromBlock: 'latest'
}, function(error, event){
if(!error)
{
console.log("Transfer-hÀndelse:", event);
const from = event.returnValues.from;
const to = event.returnValues.to;
const value = event.returnValues.value;
// Uppdatera UI eller utför andra ÄtgÀrder
console.log(`Tokens överförda frÄn ${from} till ${to}: ${value}`);
}
else
{console.error(error);}
});
Med ethers.js:
myContract.on("Transfer", (from, to, value, event) => {
console.log("Transfer-hÀndelse emitterad!");
console.log("FrÄn:", from);
console.log("Till:", to);
console.log("VÀrde:", value.toString()); // VÀrdet Àr ett BigNumber i ethers.js
console.log("HĂ€ndelsedata:", event);
// Uppdatera UI eller utför andra ÄtgÀrder
console.log(`Tokens överförda frÄn ${from} till ${to}: ${value.toString()}`);
});
Denna kodsnutt lyssnar efter `Transfer`-hÀndelser och loggar avsÀndarens adress, mottagarens adress och det överförda beloppet till konsolen. Du kan sedan anvÀnda denna information för att uppdatera din applikations UI, visa transaktionshistorik eller utföra andra ÄtgÀrder.
Sammanfattning
Frontend-hÀndelselyssnare för smarta kontrakt pÄ blockkedjan Àr ett kraftfullt verktyg för att bygga realtids, responsiva DApps. Genom att övervaka hÀndelser som emitteras av smarta kontrakt kan du ge anvÀndarna aktuell information och förbÀttra den övergripande anvÀndarupplevelsen. Denna guide har tÀckt de grundlÀggande koncepten, verktygen och teknikerna för att bygga hÀndelselyssnare, tillsammans med avancerade Àmnen som att filtrera hÀndelser, hantera Äterkallade transaktioner och anvÀnda WebSockets för realtidsuppdateringar. Genom att följa de bÀsta praxis som beskrivs i denna guide kan du bygga robusta och sÀkra hÀndelselyssnare som kommer att förbÀttra funktionaliteten och anvÀndarupplevelsen i dina DApps.