Overview
The Node.js v20 Runtime enables you to build and deploy serverless functions using the Node.js v20 environment. This runtime provides access to the QuickNode SDK, popular packages and web3 libraries, as well as the Node.js core modules. You can also include additional npm packages by uploading a zip file containing your function code and dependencies.
Available Packages
The Node.js 20 runtime includes the following useful packages and web3 libraries which can be used inside your function:
redis@4.6.15
@quicknode/sdk@2.3.0
ethers@6.13.1
web3@4.10.0
@solana/web3.js@1.95.3
axios@1.7.2
date-fns@3.6.0
dotenv@16.4.5
lodash@4.17.21
The Node.js v20 runtime also includes the following core modules:
assert
buffer
child_process
cluster
console
crypto
dgram
dns
events
fs
http
https
net
os
path
process
querystring
readline
stream
string_decoder
tls
tty
url
util
v8
vm
zlib
For more details, you can refer to the Node.js GitHub repository.
Using the Code Editor
Within the code editor, you can write and test your function using the core modules listed above. Here is a simple example of a Node.js function:
function main(params) {
// Extract dataset and network from metadata in params
const dataset = params.metadata.dataset;
const network = params.metadata.network;
return {
message: `This is data from the ${dataset} dataset on the ${network} network.`,
params
};
}
Uploading a Zip File
If you need to include additional npm packages, you can upload your function as a zip file. Follow these steps:
- Step 1: Create your function code in
index.js
. - Step 2: Create a
package.json
file with your dependencies. - Step 3: Run
npm install
to install the dependencies. - Step 4: Zip the contents of your project directory, including index.js, package.json, and the node_modules directory. Note: Make sure that you do not zip the containing folder. Instead, select the files you want to include in your zip, for example the
index.js
,.env
, andpackage.json
files as well as thenode_modules
directory, and compress them into an archive. - Step 5: Upload the zip file in the function editor.
- Step 6: Test the function with the Block with Receipts dataset on Ethereum Mainnet.
Example package.json
:
{
"name": "qn-token-metadata-parser",
"version": "1.0.0",
"description": "A boilerplate to process Ethereum block and receipt data for erc-20 and erc-721 transfer events",
"main": "index.js",
"dependencies": {
"axios": "^0.27.2",
"dotenv": "^16.4.5",
"web3": "^1.10.4"
}
}
Example index.js
:
require('dotenv').config();
const Web3 = require('web3');
const axios = require('axios');
const https = require('https');
const web3 = new Web3(new Web3.providers.HttpProvider(process.env.QUICKNODE_URL));
// Create an HTTPS Agent that specifies the TLS protocol
const httpsAgent = new https.Agent({
secureProtocol: 'TLSv1_2_method' // Using TLS 1.2 as an example; adjust as necessary based on the server's requirements
});
async function getTokenMetadata(contractAddress) {
console.log(`Fetching token metadata for address: ${contractAddress}`); // Log the address being queried
try {
const response = await axios.post(process.env.QUICKNODE_URL, {
id: 67,
jsonrpc: "2.0",
method: "qn_getTokenMetadataByContractAddress",
params: [{
contract: contractAddress
}]
}, {
headers: {
'Content-Type': 'application/json'
},
httpsAgent: httpsAgent // Use the custom HTTPS Agent
});
console.log('Response data:', response.data); // Log response data
return response.data.result;
} catch (error) {
console.error('Error fetching token metadata:', error); // Log errors if the request fails
throw error; // Rethrow error to handle it upstream if necessary
}
}
async function parseLogs(logs) {
const summaries = [];
console.log(`Parsing logs: ${logs.length} entries found`); // Log number of logs to be parsed
for (const log of logs) {
console.log(`Processing log entry:`, log); // Log each log entry
if (log.topics[0] === '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef') {
const from = '0x' + log.topics[1].slice(26);
const to = '0x' + log.topics[2].slice(26);
if (log.topics.length === 4) {
// ERC-721 Transfer event
const tokenId = Web3.utils.hexToNumberString(log.topics[3]);
summaries.push(`Transaction ${log.transactionHash} - Transferred NFT token ID ${tokenId} from ${from} to ${to}`);
} else {
// ERC-20 Transfer event
const metadata = await getTokenMetadata(log.address);
const value = Web3.utils.fromWei(log.data, 'ether');
const readableValue = (parseInt(value) / Math.pow(10, metadata.decimals)).toFixed(metadata.decimals);
summaries.push(`Transaction ${log.transactionHash} - Transferred ${readableValue} ${metadata.symbol} (${metadata.name}) from ${from} to ${to}`);
}
}
}
console.log('Completed parsing logs:', summaries); // Log summaries of all parsed logs
return summaries;
}
async function main(params) {
console.log('Starting main function with params:', params); // Log input params
try {
const { data } = params;
const results = await Promise.all(data.map(async entry => {
const { block, receipts } = entry;
console.log(`Processing block number ${block.number} with receipts`); // Log details of the block being processed
return {
blockNumber: block.number,
transactions: await Promise.all(receipts.map(async receipt => ({
transactionHash: receipt.transactionHash,
logsSummary: await parseLogs(receipt.logs)
})))
};
}));
console.log('Final results:', results); // Log final results
return { results };
} catch (error) {
console.error('Error in main function:', error); // Log any errors encountered in the main function
throw error;
}
}
module.exports = { main };
Example .env
:
# QUICKNODE_URL = https://your-quicknode-url
# If you don't have a QuickNode Endpoint, you can get one here: https://dashboard.quicknode.com/endpoints
QUICKNODE_URL="YOUR_QUICKNODE_URL"