getNFTOwners at specific block?

Hi, I’m trying to make a snapshot of NFT holders of a particular collection, at a specific block.

It’s on fantom. I’m using the ā€œstandard wayā€ (no moralis api):

let result = await instance.getPastEvents('Transfer', { fromBlock: _from, toBlock: _to })

but I’m not getting any transfer strangely (a few months ago, the script I was using was working fine… maybe something changed on fantom?). Using RPC https://rpc.ftm.tools/ (I tried others, same issue).

On Moralias I’ve found 2 interesting endpoints:

getNFTOwners
https://docs.moralis.io/reference/getnftowners-1
this unluckily doesn’t let specify the block number, else it would be perfect… maybe feature request?

The other way would be to use

getNFTContractTransfers
https://docs.moralis.io/reference/getnftcontracttransfers-2
This also does not allow to specify from / to… so basically I’d have to fetch everything in batches of 100 (because of api limit 100 results…)

Advise to achieve this in a smart way?

I tried to setup a stream via admin.moralis.io, chose erc721, entered address but what would I set for tokenId?

Thx

Check that you should be getting some past event data for that contract on ftmscan.com with the parameters you’re using (fromBlock/toBlock). You could also try with another contract.

I tried to setup a stream via admin.moralis.io, chose erc721, entered address but what would I set for tokenId?

Streams API is for live data. But you would put in the NFT tokenId.

Thanks for the answer. In the end I debugged my code, and if curious… specifying ā€œTransferā€ as event name, was returning no results. I modified my code as follows and got all events, then filtered those results by event name… will dig it more and compare with other chains. I swear it was working months ago, so somethng changed.

let result = await instance.getPastEvents({ fromBlock: _from, toBlock: _to });
for (let e of result) {
  if (e.event == 'Transfer') {
    console.log(e);
// rest of my code omitted but that's what I ended up doing...

Specifying tokenId seems really odd. I mean who wants to setup a stream to watch live events just for a singular tokenId? Normally if you have a minting website or so you wanna track an entire collection, not just a single NFT…

… I think I’ll check how to setup a moralis server (self hosted), because I’m getting a bit bored with buggy RPCs, APIs not offering what I need etc etc. as I understand moralis server heart is a parse server and the only thing I need to do is to fill the parse server with the data I need, then querying it will be piece of cake like querying a mongo db, right?

If the moralis server saves data the way I think it does (a useful way) then I should be able to get all transfer events by specifying:

  • collection address
  • event name
  • block nr >= _from and <= _to

And I’d expect to get also the event data I need (for a token transfer it’s tokenId, from and to) or at least the entire returnValues and then parse returnValues to get those properties.

Specifying tokenId seems really odd. I mean who wants to setup a stream to watch live events just for a singular tokenId?

That is a template. You can do all transfer events for a collection. Here is an example which then optionally filters to a specific set of tokenIds.

You can find out more here.

only thing I need to do is to fill the parse server with the data I need, then querying it will be piece of cake like querying a mongo db, right?

Parse Server may do things slightly differently compared to interacting with MongoDB directly so you would need to check their docs for cases like this where the behaviour is different from what you expect.