This guide demonstrates how to leverage QuickNode’s Streams and Functions to build a system that monitors Aave V3 borrowers' health factors. The process involves:
- Setting up a Stream to capture real-time borrowing events.
- Creating a Function to process these events, extract borrower addresses and health factors, and store data in QuickNode’s Key-Value Store API.
Designed for developers, this tutorial provides a step-by-step approach to blockchain data processing with serverless infrastructure.
Overview
Managing blockchain infrastructure can be complex. QuickNode’s Functions simplifies this by offering serverless solutions for deploying pre-built or custom logic without self-hosting.
In this guide, you’ll learn to:
- Capture borrowing events from Aave V3 using Streams.
- Extract borrower addresses and health factors via a Function.
- Store data in a Key-Value Store for later retrieval.
Prerequisites
- A QuickNode account.
- Basic knowledge of JavaScript, Ethereum transactions, and events.
- An Ethereum Mainnet RPC endpoint.
- A webhook URL (e.g., from TypedWebhook Tools).
Step 1: Setting Up a Stream
Stream Configuration:
- Chain: Ethereum
- Network: Mainnet
- Dataset: Transactions
- Start Point: Latest block
- Filter Code:
function main(stream) {
try {
const AAVE_V3_POOL_ADDRESS = '0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2'.toLowerCase();
const BORROW_FUNCTION_SIGNATURE = '0xa415bcad'; // borrow() signature
const filteredList = stream.data[0].filter(tx =>
tx.to?.toLowerCase() === AAVE_V3_POOL_ADDRESS &&
tx.input.startsWith(BORROW_FUNCTION_SIGNATURE)
);
return filteredList.length > 0 ? {
borrowers: filteredList.map(tx => ({
block: parseInt(tx.blockNumber, 16),
borrower: tx.from
}))
} : {
block: parseInt(stream.data[0][0].blockNumber, 16),
message: "No borrow transactions found in this block."
};
} catch (e) {
return { error: e.message };
}
}Key Actions:
- Filters transactions for Aave V3 borrow events.
- Extracts borrower addresses and block numbers.
Step 2: Creating the Function
Function Code:
const ethers = require('ethers');
const RPC_URL = "YOUR_RPC_URL";
const WEBHOOK_URL = "YOUR_WEBHOOK_URL";
const AAVE_V3_POOL_ABI = [{
"inputs": [{ "type": "address", "name": "user" }],
"name": "getUserAccountData",
"outputs": [{ "name": "healthFactor", "type": "uint256" }],
"stateMutability": "view",
"type": "function"
}];
let provider, aavePool;
function initializeContract() {
provider = new ethers.JsonRpcProvider(RPC_URL);
aavePool = new ethers.Contract('0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2', AAVE_V3_POOL_ABI, provider);
}
async function convertToHealthFactor(address) {
const data = await aavePool.getUserAccountData(address);
return ethers.formatUnits(data.healthFactor, 18);
}
async function main(params) {
initializeContract();
const borrowers = params.data?.borrowers || [];
const processed = [];
for (const { borrower } of borrowers) {
const healthFactor = await convertToHealthFactor(borrower);
await qnLib.qnAddListItem(`borrowers-AAVE_V3`, borrower);
await qnLib.qnAddSet(`borrower-${borrower}`, healthFactor);
processed.push({ borrower, healthFactor });
}
await sendToWebhook({ borrowers: processed });
return { message: `Processed ${processed.length} borrowers.` };
}Key Features:
- Fetches health factors from Aave V3.
- Stores data in Key-Value Store.
- Sends results to a webhook.
Step 3: Testing the Key-Value Store
Retrieve stored borrower data via REST API:
curl -X GET "https://api.quicknode.com/kv/rest/v1/lists/borrowers-AAVE_V3" \
-H "x-api-key: YOUR_API_KEY"Sample Response:
{
"data": {
"items": ["0x123...", "0x456..."]
}
}Fetch a borrower’s health factor:
curl -X GET "https://api.quicknode.com/kv/rest/v1/sets/borrower-0x123" \
-H "x-api-key: YOUR_API_KEY"Output:
{ "data": { "value": "1.85" } }FAQs
1. What is a health factor in Aave?
The health factor measures a borrower’s collateralization ratio. If it drops below 1, the position can be liquidated.
2. Can I monitor multiple blockchains?
Yes! QuickNode supports Ethereum, Optimism, Base, and more.
3. How often does the Function run?
It triggers only when a borrow event occurs, saving compute costs.
4. Can I extend this system?
Absolutely! Add:
- Historical block tracking.
- Alerts for low health factors.
Conclusion
By combining QuickNode Streams, Functions, and Key-Value Store, you’ve built an automated monitoring system for Aave borrowers. This scalable solution eliminates server management, letting you focus on real-time data logic.
👉 Explore more QuickNode guides
Feedback? Let us know how we can improve!