0

I'm trying to use the Alchemy API to find specific events thrown by a set of contracts. One of the args that can be passed to the call is a list of topics (I'm using python, but my question is probably language agnostic), and from the docs it appears to be positional:

topics array of strings Array of 32 Bytes DATA topics. Topics are order-dependent. Each topic can also be an array of DATA with "or" options.

So, my questions is, is there a way to pass filters for, say, the 1st and 3rd topic?? The etherscan API avoids this by allowing specific topic references by number in the URL string. for example:

https://api.etherscan.io/api
   ?module=logs
   &action=getLogs
   &fromBlock=12878196
   &toBlock=12879196
   &topic0=0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef
   &topic0_1_opr=and
   &topic1=0x0000000000000000000000000000000000000000000000000000000000000000
   &page=1
   &offset=1000
   &apikey=YourApiKeyToken

...but is there a way to do something like this using the Alchemy API? Thanks!!

1 Answer 1

1

There certainly is.

First, go to Alchemy, create a free account, register a new tool and drop your API key into your code as displayed there. Then, go to the composer.

There, choose your language, find eth_getLogs from the drop down and specify the contract your hoping to listen to, along with a block range (this is limited to around 10K logs, so you’ll need to loop (or other) your function in order to crawl or use WebSockets to monitor.

You’ll then need to create a topicArray, as you’re asking, defining the ‘type’ and ‘name’ for each topic you want to listen to. In JS it looks something like this:

const getLogsAndReadTopicValues = async () => {

let logs = await alchemy.core.getLogs({
<DROP THE FILE CREATED BY THE COMPOSER HERE>
});

//then, create your loop

for (log of logs) {
 
const topicArray = [
{type: ‘address’, name: ‘theNameIWantToGiveThisValueInMyOutput’}
];

const topic0Array = web3.eth.abi.decodeParameters(topicArray, String(log.topics[0]));

try {

let topic0Value = topic0Array.theNameIWantToGiveThisValueInMyOutput;
console.log(topic0Value);

} catch (error) {
console.log(error);
}

getLogsAndReadTopicValues();

You'll then have direct access to the value held within the topic hexes.

EDIT

Now, if you want to listen to more than one topic, just define another topicArray for your other topics, and define your output in your loop accordingly. Something like this works:

const anotherTopicArray = [
{type: ‘address’, name: ‘theOtherInterestingTopicOutput’}
]

const anotherTopicArrayValue = web3.eth.abi.decodeParameters(anotherTopicArray, String(log.topics[2]));

const topic2Value = anotherTopicArrayValue.theOtherInterestingTopicOutput;
    console.log(topic2Value);

It's worth noting some things.

Firstly, that you can supposedly do this with one topic array, but you might run into buffer problems, so this individual deconstruction will yield you what you're looking for, just in more lines of code/with less faf.

Secondly, you need to know what types of value the topics are outputting (so here, we have defined both of our types as address - but these can be uint as well.

Hope that helps

3
  • hello @XaEk, thanks for the response! so, I have that part mostly working, but am wondering if/how it's possible to provide, for example, only filters for topics 0 and 2? accepting any value for topic 1
    – ben
    Commented Dec 15, 2022 at 1:35
  • made an edit above ^ let me know if that suffices
    – immaxkent
    Commented Dec 15, 2022 at 10:51
  • just so you know, you would effectively ignore topic 1 if it weren't included in your topic deconstruction via web3.eth.abi.decodeParameters
    – immaxkent
    Commented Dec 15, 2022 at 10:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.