2. Tracking ERC721 transfers
We build APIs for recent Nouns transfers and a leaderboard of most popular NFTs (by transfer counts)
Let's index ERC721s / NFTs, tracking any instance in which one transferred. In this canvas, we'll hook on all contracts that implement the ERC721 standard and track the Transfer log.
The ERC721 standard actually includes three transfer functions: transferFrom, and two variants of safeTransferFrom. The same Transfer event is typically emitted in each of these cases, as well as often for mint and burn ops.
If you want to skip to the end, here's the canvas that already has everything built.
Steps
Set up the Lambda
-
Add an EVM Lambda to the canvas. For the hook, choose ABI > Classification > ERC721 and hit enter. Select the
Transfer
log hook. Leave the default hook position (Post
) and callback name (postTransferLog
). Toggle on theGenerate schema
feature as it'll give us a good template. Then hitAdd
. -
A
TransferLog
schema is automatically generated with a few fields. Hit theTest
button at the top-right of the IDE and then hitRun
. You'll see logs emitted to the console. -
Now let's add more details and re-arrange: click the menu next to the schema and select
Edit
. Add fields and rearrange:Name Type txnHash bytes32 globalCounter uint256 blockNumber uint64 tokenAddress address tokenId uint256 fromAddress address toAddress address -
When you're done editing the schema, hit
Save
. Now we need to update the callback to emit the new data:
function postTransferLog() public {
postTransferLogContext storage ctx = getPostTransferLogContext();
simEmitToSchema_TransferLog(
SchemaTransferLogColumns({
txnHash: ctx.txn.hash(),
globalCounter: simGlobalCounter(),
blockNumber: block.number,
tokenAddress: ctx.txn.to(),
tokenId: ctx.tokenId,
fromAddress: ctx.from,
toAddress: ctx.to
})
);
}
- Test again when you're done and you'll see the extra fields in the emitted logs.
Build the pipeline
- Close the IDE for the EVM Lambda component. You'll see a Schema component was automatically added to your canvas.
- Click on the left handle of the Lambda component to add a
Data source
. In the data source component, set the From in the block range to 1. While the ERC721 standard was formally accepted in early 2018, we'll run from genesis to include contracts that implemented the standard before its acceptance. Leave the To blank to let it keep running at the tip. - Click on the right handle of the Schema component to add a
Persistence
. Name the persistence something likeerc721_transfers
and set the persistence. - Hit the play button on the execution edge. In a few moments, we should see both tip and backfill executions in the execution edge status (mouse over the
i
).
Querying and building APIs
You can prototype queries using the query editor. Let's use some we've prebaked to make APIs.
- Add an API component to the canvas. It doesn't have to be connected to any other components. For the first API, let's do a simple one that shows the N most recent Nouns owner changes. Use the following query:
select * from @org.erc721_owner_changes
where tokenAddress = '0x9c8ff314c9bc7f6e59a9d9225fb22946427edc03'
order by globalCounter desc
limit $limit
- For the
limit
parameter, use typeuint32
(a few others would work too), and set the default value to 1. - Test the query using the test interaction, then set the API, activate it, and try the cURL request available in the actions menu.
- For our second API, let's build a leaderboard of the most popular NFT contracts over a user-defined block range, sorting by the number of transfers. Here's a query for that:
with most_recent_block as (
select max(blockNumber) as most_recent_block from @org.erc721_transfers
)
select
tokenAddress,
count(*) as cnt
from @org.erc721_transfers
where blockNumber >= (select * from most_recent_block) - $block_range
group by tokenAddress
order by cnt desc
limit $limit
- Both
block_range
andlimit
parameters can be typed asuint32
, and1000
and5
would make sense as default parameters. Again, test the query and API using the test feature and the cURL.
Key takeaways
- You can easily hook on all contracts that implement a certain standard, like ERC721, even if they have vastly different implementations.
- You can query and build APIs against all of your persistences as well as sim core tables from any canvas.
Updated about 1 month ago