Is there a standard (or commonly used) format for NFT transfer records?


I’m working on an NFT canister and I would like to maintain a history of all transfer activity. I understand there are 3rd party services that can track this activity for me but I would prefer to maintain our own history until more reliable services become available. I would also like to make this data available in a format that can be ingested by existing network scanners and analytics tools.

Is there a standard interface and record type for NFT transfers that is commonly used today? Should I try to reproduce the output from CAP?

cc: @skilesare @bob11 @domwoe


This is what we’ve put together so far for Origyn: origyn_nft/ at 90b5522bcc660f3f3ee4f64e3a766dfd4d6e6481 · ORIGYN-SA/origyn_nft · GitHub

There are likely a few holes in it and we certainly have additional transaction types to add, but it is a starting point.

Thanks Austin. I’ve looked at it a couple times now and I am concerned about the dependencies required to support this format.

For example; why does the “extensible” field of each variant record require a CandyType.CandyValue? I would have thought that a generic transaction record would try to stick with base types as much as possible. Doesn’t this require all services ingesting this data to use the Candy library? Are there any services that support these records today?

Edit: I found a version of the candy library here and I’m not so concerned now. I am still curious if you know of any services that work with these record types.

CandyLibrary is just a formalization of a variant pattern that covers the base types. It helps create document object models. We have more things planned like schemas and other helper functions(converting things to json/xml…and back). The pattern was used with an extensible on each one to allow for new features without having to upgrade all the canisters to new candid types. (Imagine a blackholed canister that can’t be upgraded to add a new transaction record type). So far we’ve put #Empty in all of those because it isn’t used yet.

The first use case I can think of would be a variable type #memo. I spoke with @rckprtr a while back about memos and their limitations and it made sense to me to give a bit of a blank slate so future applications could put the kind of data into to a memo that they needed.

We’d take any pull requests for candy library that make the library better/more standard. We likely need a Rust mirror for the variant types. Hopefully it can be a general-purpose tool for Motoko/Rust when you need a document-type object that can’t be defined before hand.

1 Like


Without a memo field it makes it impossible to extend the token to provide utility for other applications.

So you can insert metadata like an ID or rich data (Imagine a micro protocol) into the memo field for other applications monitoring the transactions to take action.

Even more helpful is a notify pattern, but possible issues with it still.


All of our canisters use EXT transactions for all marketplace transactions, and then we use CAP right now for transfer tracking. So we have 100+ canisters using CAP right now to some degree. It doesn’t do everything we need though, so in the near future we’ll likely improve upon it or build our own solution. Perhaps using something along the lines of EXT txns, but can be flexible.

EXT txns are definitely straightforward but afaik they only track sales via the marketplace and not owner transfers. We manage two of our own EXT canisters and our next canister will provide the standard EXT interface. I have not been a fan of CAP so I’m not really interested in going down that path a third time if I can avoid it.

The Origyn transaction record seems to cover most of our needs. Still open to an alternative though.

I understand there is an NFT WG that recently kicked off. I imagine trying to nail down a NFT standard is going to be even more difficult and controversial than ICRC-1.

Maybe settling on a standard transaction record would be a good place to start.

1 Like

It is on the agenda of the WG. The goal is to start with a very basic bare-bones interface and then annotate extensions that takes advantage of the full power of the IC. It will likely take a bit of time. At Origyn we plan to add any agreed-upon standard to our implementations to the extent that it is possible.