Skip to content

Token Instance Metadata#787

Open
Jehosephat wants to merge 1 commit into
mainfrom
feat/token-instance-metadata
Open

Token Instance Metadata#787
Jehosephat wants to merge 1 commit into
mainfrom
feat/token-instance-metadata

Conversation

@Jehosephat

Copy link
Copy Markdown
Collaborator

The token instance metadata feature is complete, purely additive, and fully verified -- including the mid-flight change to per-project metadata: each NFT instance can now hold multiple metadata documents (one per project), and the first user to create metadata for a project on a token class owns that project's metadata for the whole class.

How the per-project model works

  • TokenInstanceMetadata (new chain object, index key GCTIM) is keyed by collection/category/type/additionalKey/instance/project, so one document per (instance, project) pair. It carries the OpenSea standard fields (name, description, image, external_url, animation_url, background_color, youtube_url, attributes[] with trait_type/value/display_type) plus a validated customFields key-value list for game-specific data, and bookkeeping (createdBy, lastModifiedBy, created, lastModified).
  • TokenInstanceMetadataProject (new chain object, GCTIMP) is the ownership record, keyed by class + project. It's created automatically on first set with the caller as owner; afterwards only that owner can set or delete that project's metadata anywhere in the class. This is how I implemented your "the user who creates the metadata for that project will own that project's metadata for that class" -- ownership is class-wide per project, and it replaces the earlier token-class-authorities check entirely (so any user can annotate any NFT under their own project name; deleting the last document keeps the ownership claim). If you'd rather authorities retain moderation powers over their classes, that's a small follow-up.
  • Contract methods on GalaChainTokenContract: SetTokenInstanceMetadata (full-document upsert), FetchTokenInstanceMetadata (one project, or all projects for an instance), FetchTokenInstanceMetadataWithPagination (partial-key browse down to project level), DeleteTokenInstanceMetadata. Metadata is NFT-only; fungible instance 0 is rejected with a typed error since class-level metadata already lives on TokenClass.

What changed where

  • chain-api: new TokenInstanceMetadata.ts (chain objects + 4 DTOs), new IsStringOrNumber validator (OpenSea trait values can be string or number), barrel export. One deviation from the plan: DTOs live in the same file as the chain object because the planned tokenInstanceMetadata.ts/TokenInstanceMetadata.ts pair collides on case-insensitive filesystems (Windows/macOS).
  • chaincode: new src/tokenInstanceMetadata/ domain (set/fetch/delete, helpers, typed errors), exported from the package barrel; methods added to the test contract.
  • chain-test: nft.tokenInstance1Metadata() and nft.tokenInstance1MetadataProject() factories.
  • chain-cli/chaincode-template: same four contract methods, a full e2e spec (mint --> set --> ownership rejection --> second project --> fetch-all --> replace --> delete), and both API snapshots regenerated. I validated the snapshot regeneration by running it offline via the fixture -- the two untouched contracts' snapshots passed byte-identical, proving correctness without a network.
  • chain-connect: four TokenApi methods + request types.

name: params.name,
description: params.description,
image: params.image,
external_url: params.external_url,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

by convention we use camelCase - since it's not merged yet, and we don't have actual data on chain, it would be good to align this to our convention

Comment on lines +61 to +63
// the first user to create metadata for a project on a token class becomes
// the owner of that project's metadata for the whole class
const ownership = await fetchTokenInstanceMetadataProject(ctx, tokenInstance, project);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't it mean that any user can create metadata for any instance?

Further in the code we verify only the owner of the metadata => if no metadata, or creator === callingUser; then set().

But there is no validation if the instance is owned by the calling user. (like with TokenInstance.owner field, which is required for NFTs). Is it the expected behavior?

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

Successfully merging this pull request may close these issues.

2 participants