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

Allow extended metadata for NFTs for easy wallet/client integration #9

Open
ferencdg opened this issue Sep 17, 2021 · 9 comments
Open

Comments

@ferencdg
Copy link

ferencdg commented Sep 17, 2021

Hi, thank you for your high quality standard, I would like to propose and extension to get extended NFT metadata.

Right now, if we have a browser wallet plugin, we are unable to uniformly retrieve the content-type of the NFT that is written based on your standard. That means our wallet plugin would need to know about the actual contract to know the NFT content-type or query some aggregation service. Also based on your specification, someone currently cannot uniformly implement an NFT that might return a jpeg for some TokenId while returning a mpeg for some other TokenId.

The second problem for us is that NFTs based on your standard doesn't provide a uniform location specification where the NFT binary/blob is located. People might store their NFT in the token contract directly, or in an other canister, IPFS, or on web. For clients like a wallet it would be good to be able to uniformly retrieve the NFT binary.

The suggested extension:

type ExtendedMetadata = {
  #fungible : {
    name : Text;
    symbol : Text;
    decimals : Nat8;
    metadata : ?Blob;
  };
  #nonfungible : {
    content-type : Text; // some kind of mime type or any other standard
    location: IPFS|Canister|TokenContract|....
    metadata : ?Blob;
  };
};

for example if the location is IPFS, then the metadata should be an IPFS hash, if it is Canister then maybe a canister Principal.... We can discuss this in details, if people are happy with this in Principal.

type ExtendedMetadata = actor {
  extended_metadata: shared query (token : TokenIdentifier) -> async Result<ExtendedMetadata, CommonError>;

};
@stephenandrews
Copy link
Contributor

Thanks - yeah we are trying to figure out the best way to handle this. We have a few ideas:

  1. The idea you pose is good, but we want go even further and ensure we can handle any type of NFTs that people want to load using EXT
  2. One idea we are looking at is serializing data as JSON and converting to a blob for storage. This means that any client can read it and decide how to handle the data. We could then standardize the JSON format as well. The problem is that currently there is no way to read JSON inside Motoko, making it hard to use inside canisters (e.g. genetics for Cronics requires reading the data in the canister)
  3. We found a library which allows us to convert any motoko value into a blob - this seems to be a good option, but makes it harder for wallets to interpret (but not really). It does require some funky stuff to compile tho (you have to compile using a moc flag to unlock the serde library).
  4. Finally, we are looking to just setup an array with key=>value pairs. This can be read by both canisters and clients, and is a fairly simple (and easy to follow) method. eg:
type MetadataKey = Text;
type MetadataValue = {
  #text : Text;
  #blob : Blob;
  #nat : Nat;
  #nat8: Nat8; //can add more
};
type MetadataElement = {
  #keypair : (MetadataKey , MetadataValue);
  #byte : Nat8;
};
type ExtendedMetadata = {
  #fungible : [MetadataElement ];
  #nonfungible : [MetadataElement];
};

For something like Cronics, we would do something like (to represent 32 bytes):

metadata = #nonfungible([#byte(102), #byte(23)...]);

For something like a fungible token:

metadata = #fungible([#keypair("name", #text("Name of token"))...]);

For something like your example

metadata = #nonfungible([#keypair("content-type", #text("image/png"))...]);

What do you think? I totally agree though, metadata needs to be redone

@ferencdg
Copy link
Author

ferencdg commented Sep 17, 2021

I like the idea! I am thinking about how we should accomodate Json, after someone writes a parser, how about the one below (field names like arrayMetadataElement probably need change)?

type MetadataKey = Text;
type MetadataValue = {
  #text : Text;
  #blob : Blob;
  #nat : Nat;
  #nat8: Nat8; //can add more
};
type MetadataElement = {
  #keypair : (MetadataKey , MetadataValue);
  #byte : Nat8;
};

type MetadataContainer = {
  #arrayMetadataElement : [MetadataElement];
  #json : Text;
};

type ExtendedMetadata = {
  #fungible : MetaContainer;
  #nonfungible : MetadataContainer;
};

I am happy with your original suggestion too. Do you guys have some timeline when it will be in the standard?

@ferencdg
Copy link
Author

I think for us the main thing is, where we should expect the location/content-type fields in the metadata, I suppose that will also be standardized.

@stephenandrews
Copy link
Contributor

Yeah I think that addition makes sense too. We may alter the names of the types a bit more (bundle it in it's own module)

We are uploading the marketplace changes this weekend, and can include this update in the spec. I definitely agree that something more than what we have is required so I'll make changes to the interface over the next week and update the github.

@ferencdg
Copy link
Author

great, thank you!

@stephenandrews
Copy link
Contributor

We are looking at going with the following:

  type Value = {
    #text : Text;
    #blob : Blob;
    #nat : Nat;
    #nat8: Nat8;
  };
  type MetadataValue = (Text , Value);
  type MetadataContainer = {
      #data : [MetadataValue];
      #blob : Blob;
      #json : Text;
  };
  public type Metadata = {
    #fungible : {
      name : Text;
      symbol : Text;
      decimals : Nat8;
      metadata: ?MetadataContainer;
    };
    #nonfungible : ?MetadataContainer;
  };

Rationale - we want to support existing platform that have already adopted part of the standard for their apps. We think this still provides a way to extend metadata for either NFTs of fungible tokens. Let me know your thoughts @ferencdg ?

@ferencdg
Copy link
Author

looks good to me! Can we also put the field names and values for the most important fields like
content-type : Text; // some kind of mime type or any other standard
location: IPFS|Canister|TokenContract|....

@stephenandrews
Copy link
Contributor

Where exactly do you want this added?

@ferencdg
Copy link
Author

ferencdg commented Sep 25, 2021

maybe pairs under non-fungible->data and we could have
contentType key -> #text(let's say Mime type)
locationType -> #nat8 (and we would also specify which integer means IPFS/TokenContract/URI....
location -> #text (URI(for URI type)/IPFS hash(for IPFS type)/empty string(for TokenContract meaning that the image is stored in the token contract)
name -> #text (name of the NFT like ICPunk)
nftBlob -> #blob (the nft binary, if the locationType is TokenContract)

if we standardize those fields, then all wallets can treat them uniformly

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants