Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Individual NFT (SIP-009) token metadata support #743

Closed
zone117x opened this issue Sep 7, 2021 · 12 comments
Closed

Individual NFT (SIP-009) token metadata support #743

zone117x opened this issue Sep 7, 2021 · 12 comments
Labels
P2 Priority 2 Critical functionality not working Impacts one/few customers

Comments

@zone117x
Copy link
Member

zone117x commented Sep 7, 2021

Per leather-io/extension#1028

Note that this issue is distinct from NFT-class metadata support. This issue refers to resolving metadata for every token in every NFT class (e.g. Cryptopunk number 3712, as opposed to the broader Cryptopunk NFT-class).

To give some context to this issue, here's an explanation of how FT and NFT-class metadata resolving works (implemented in #576):

The API watches for contract-deploy transaction types and detecting when a contract ABI matches the ABIs defined by SIP-010 FT or SIP-009 NFT. When a matching contract is found, it's added to a db table that functions as a resolver queue.

The API runs a mostly independent subsystem, the token processor, which observes and drains the db queue. This subsystem must perform relatively expensive readonly contract-calls to the stacks-node in order to grab information like token symbol, name, decimals, and the arbitrary metadata json file URL. Once it has that initial data, it performs another relatively expensive process of fetching from that arbitrary metadata json file URL, extracting additional metadata like description and another URL for the token image/icon.

For security and client-performance purposes, image URLs are processed through a configurable script that is responsible for providing a new URL (e.g. from a CDN fit for client usage) from the given arbitrary URL:
https://github.com/blockstack/stacks-blockchain-api/blob/1914333f669e4ff8d4497e715cb703ca17d14fae/.env#L63-L67

Unknowns

Now moving on to the issues of implementing similar functionality for all NFT tokens:

The implementation described above has received fair criticisms for both not doing enough (arbitrary metadata URLs are not polled for updates) and for doing too much (why does the API have this relatively heavy subsystem to begin with, why is it dealing with off-chain image data?). See the discussion in #576 for more details.

Keeping that in mind, supporting all NFT tokens would involve performing something similar to the above process where NFT minting is detected, queued, and processed via additional contract-calls and arbitrary JSON url fetching. However, rather than processing the tens of compliant FT and NFT contracts currently deployed to mainnet, we'd be doing this for tens of thousands of individual NFTs. For example, an FT like MiamiCoin requires this processing be performed once. An NFT like StacksPunks requires this process be performed ~10,000 times.

We need to iron out feasibility and implementation details like image URL processing, db queuing, contract-call contraints, metadata refreshing, etc.

@agraebe
Copy link
Contributor

agraebe commented Sep 7, 2021

@wileyj @CharlieC3 @rafaelcr to leave some feedback

@agraebe agraebe added the P2 Priority 2 Critical functionality not working Impacts one/few customers label Sep 7, 2021
@wileyj
Copy link
Contributor

wileyj commented Sep 7, 2021

As mentioned in #576 - I don't think this should be a part of the core API functionality.
I don't have any opinion of if the work should be done to process all the FT/NFT tokens, but if it's something we end up doing - I would strongly advocate for a completely separate service that performs this work.

Unclear from the above text is if this is a one time operation for "older" tokens, or would need to be run often.

@zone117x
Copy link
Member Author

zone117x commented Sep 7, 2021

Unclear from the above text is if this is a one time operation for "older" tokens, or would need to be run often.

The operation described above is performed once on every token (all old/existing tokens, and new tokens as they are created), and it's ran on every API deployment including when using event-replay deployments. There was a request to run these more than once (likely on an interval) in order to support metadata updates.

@CharlieC3
Copy link
Member

CharlieC3 commented Sep 7, 2021

Agreed with @wileyj, this is a lot of eggs to put in one basket so to speak. My thoughts are that separating this and #576 out into a dedicated microservice would pay in dividends and reduce the API's complexity. A more thorough recommendation can be found starting here.

There was a request to run these more than once (likely on an interval) in order to support metadata updates.

Instead of an interval to run against all token metadata, can this just be ran when a metadata update event comes through on just the affected token, similar to when a new token event comes through?

@zone117x
Copy link
Member Author

zone117x commented Sep 7, 2021

Instead of an interval to run against all token metadata, can this just be ran when a metadata update event comes through on just the affected token, similar to when a new token event comes through?

Yep, if we do support updating existing metadata, I think it should be done through events like that. There's some previous discussion around that here #576 (comment).

@zone117x
Copy link
Member Author

zone117x commented Sep 7, 2021

One issue that comes to mind is how a server would be able to fetch something like 10k JSON files from a given NFT's metadata server in a short period of time. For example, NFT contracts that do something like the following to return a metadata URL:

# pseudo code
(define-read-only (get-token-uri (token-id uint))
  (ok (some "https://example-nft-site.com/nft_{token-id}.json")))

It seems likely the metadata resolver server would get IP rate limited/blocked while attempting 10k http requests to example-nft-site.com. A workaround could be re-queuing for a scheduled future timestamp when receiving a 429 Too Many Requests. But even with a Retry-After response of 1 minute, it could add 100+ hours to chug through 10k tokens.

@wileyj
Copy link
Contributor

wileyj commented Sep 7, 2021

One issue that comes to mind is how a server would be able to fetch something like 10k JSON files from a given NFT's metadata server in a short period of time. For example, NFT contracts that do something like the following to return a metadata URL:

# pseudo code
(define-read-only (get-token-uri (token-id uint))
  (ok (some "https://example-nft-site.com/nft_{token-id}.json")))

It seems likely the metadata resolver server would get IP rate limited/blocked while attempting 10k http requests to example-nft-site.com. A workaround could be re-queuing for a scheduled future timestamp when receiving a 429 Too Many Requests. But even with a Retry-After response of 1 minute, it could add 100+ hours to chug through 10k tokens.

There are ways around that 429......but it would require a separate service to perform these fetches, and little bit of hack engineering.

@markmhendrickson
Copy link

@andresgalante @kyranjamie I presume we're agonistic client-side as to whether this functionality is provided via the same API or a micro service as long as the metadata is provided reliably in an updated manner?

@dantrevino
Copy link

From an NFT perspective, I'd like to point out that there is currently no metadata standard. SIP009 only specifies to return a metadata uri from get-token-uri ... it does not specify the protocol, format, or properties of metadata

The following still needs to be managed:

  1. metadata protocol. Is this service prepared to handle ipfs (ipfs://)/arweave (ar://) as well as http(s)?
  2. metadata format. CSV? JSON? Excel? Clarity tuple? No standard is specified by sip009.
  3. metadata properties. Are images named "img"? "image"? "imageUrl"? "imagen"? Is the name "name" or "title" or something else?
  4. what metadata properties must be provided?

For reference: stacksgov/sips#17

@zone117x
Copy link
Member Author

zone117x commented Sep 9, 2021

Good point @dantrevino. A requirement for this issue is that an NFT metadata standard SIP needs to be defined and at least in the process of ratification.

@kyranjamie
Copy link
Contributor

I presume we're agonistic client-side as to whether this functionality is provided via the same API or a micro service as long as the metadata is provided reliably in an updated manner?

We'd be happy to consume data from a separate service is necessary. Definitely see the concerns of the API becoming the place to Do everything™️

@zone117x
Copy link
Member Author

zone117x commented Nov 2, 2021

We've decided not to add support for this in the API. We plan to implement additional NFT endpoints related to ownership, but unrelated to metadata.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
P2 Priority 2 Critical functionality not working Impacts one/few customers
Projects
None yet
Development

No branches or pull requests

8 participants