dev advocate at Chainstack here.
When you retrieve the logs, you receive an array of different elements. Let's take the Approval event from an ERC-721 contract as an example since it's what you need.
In this case, this is how it looks in the smart contract:
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
As you can see, this event has 3 indexed parameters, which means that those values will be returned into the topics
array in the logs object. You can only mark up to 3 elements as indexed
; the non-indexed parameters will be returned in a separate array named data
.
You ask: Looking at the data and topics I get from the logs, I noticed that data always is just 0x. The topics are the actual value. Looking up the transactions on etherscan I also noticed that the data value is also 0x, so that seems correct?
This is the case because all parameters are indexed in the Approval event, so the data
array is returned empty as 0x
.
A typical topics
array for the approval event looks like this:
topics: [
'0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925', // Event signature
'0x000000000000000000000000f9cc4b93728328ccfce3cfe446d4c52d1571aa20', // Owner address
'0x0000000000000000000000000000000000000000000000000000000000000000', // Approved address
'0x000000000000000000000000000000000000000000000000000000000000043c' // Token ID
],
As you can see, there are 4 elements because the first element is the event signature (like you have in your code). The last 3 elements correspond to what's returned by the event:
- Address owner
- Address approved
- Token ID
These elements are encoded as 32-byte size, and to take the addresses, you have to take the last 20 bytes; in this case, the last 20 bytes equal to the last 40 characters as they are in hex format 2 hex digits make up one byte.
Note that you have to add 0x in front of those 20 bytes to parse a valid address
I'm not very familiar with the Alchemy SDK, but here is a script in web3.js
to retrieve and parse the Approval
event from an ERC-721 contract using the getPastLogs method.
const Web3 = require("web3");
require('dotenv').config();
// Initialize connection to the node.
const node_url = process.env.ETHEREUM_CHAINSTACK;
const web3 = new Web3(new Web3.providers.HttpProvider(node_url))
// Retrieve the logs based on the Transfer event
async function getLogs() {
// Initialize blocks to query
const startBlock = 16599340
const latestBlock = await web3.eth.getBlockNumber()
// Set the parameters for the getPastLogs method
const params = {
fromBlock: startBlock,
toBlock: 'latest',
address: "0x9401518f4EBBA857BAA879D9f76E1Cc8b31ed197", // smart contract address
topics: ["0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"], // Approval event signature
};
// Print some info on the screen.
console.log(`Getting logs starting from block ${startBlock} to ${latestBlock} \n`)
// Retrieve logs
const logs = await web3.eth.getPastLogs(params)
//console.log(logs)
return logs
}
// Parse the logs and extract only the tx hash and topics.
async function parseLogs(logs) {
for (let object of logs) {
const txhash = object.transactionHash
const from = object.topics[1]
const fromAddress = from.slice(-40); // This is how we take the last 20 bytes
const to = object.topics[2]
const toAddress = to.slice(-40);
const tokenId = object.topics[3]
console.log(`Approval tx hash: ${txhash}`)
console.log(`Owner address: 0x${fromAddress}`)
console.log(`Approved address: 0x${toAddress}`)
console.log(`Token ID: ${web3.utils.hexToNumber(tokenId)} \n`) // web3.utils.hexToNumber converts to the decimal token id
}
}
// Main program.
async function main() {
const approvalLogs = await getLogs()
parseLogs(approvalLogs)
}
main();
Everything in the getLogs
function is similar to what you already do. The parseLogs
function extracts the topics, decodes them, and prints them on the screen.
Running it will give you something like this:
Getting logs starting from block 16600272 to 16600472
Approval tx hash: 0x7dee982e52154f0750f58ce77bcc6047c08d38339ade1a060e317eccd17f3b6c
Owner address: 0xf9cc4b93728328ccfce3cfe446d4c52d1571aa20
Approved address: 0x0000000000000000000000000000000000000000
Token ID: 1084
Approval tx hash: 0xfe319b5527fd4f9a240abc0d0676599251e1ce58fa87a45eb674a9e39862ddf3
Owner address: 0x2ed0f4e9769591d8eff038abd884187c8101c7f3
Approved address: 0x0000000000000000000000000000000000000000
Token ID: 828
Topics
array at position 1,2 or 3. At the position 0 goes the event signature hash. So if it is an address, it will be in the lower side (right) of the 32 bytes of the topic.Data
field is used only for event fields that are not indexed