Technical Details

Image Generation

Image generation from the drawn traits is made possible by utilising the open-source library from HashLips. We thank the team at HashLips for open-sourcing the library, saving just about every other team weeks of man-hours.

The trait images form subsets of traits, and from these, images are overlaid in many layers to form the final piece of art. Each trait will have a set of rarity rules, and the generation will prevent duplicates.

NFT Images & Metadata Immutability

This has always been a topic of conflict within the NFT space. From our perspective we agree that that metadata should be sufficiently decentralised and must be immutable. This means the use of IPFS.

However, we also understand that from a practical and project perspective, using IPFS from the start for a new launch project limits the amount of runway for minting. Let us explain.

Brief Overview of NFT Assets & Metadata on IPFS

To use IPFS, all the assets and metadata will have to be uploaded. From there, a base URL will be generated, eg. https://mybaseurl.com/myMetadataFolder/ . And individual metadata file will be stored as files named after the token IDs. For example, for token with an ID of 123, the metadata URL for the token will be https://mybaseurl.com/myMetadataFolder/123.json .

This makes it easy to for people to write scripts to enumerate ALL the token metadata, and determine the rarity of the tokens even before they are being minted. And then they will just either try to front-run to mint the rare ones, or snipe off the rare ones from secondary market post-mint, before reveal.

That is the key reason why many projects do delayed revealing. So essentially all token metadata will be from the same URL, displaying a default image, eg. https://mybaseurl.com/revealing-soon.json . Once the assets are ready to be revealed, the team will interact with the contract to set the actual base URL, and token URLs.

Problems with Using IPFS for New Projects

We have to point out here that IPFS is the way to go, just that for new projects, it makes more sense to go with the usual data storages, and switch to IPFS when the project is at a stage when it is ready.

We think that there are two major problems using IPFS for a new project. While both are not technical related, we think that it is worth mentioning here.

First as we mentioned, using IPFS from the start gives a new project limited runway for minting. All projects want their tokens to be fully minted. When that occurs, only then it will make sense to set the IPFS base URL and token URLs to reveal the assets (for the reason detailed in previous section).

But what happens if the minting is going slowly? Will the community be willing to wait for a week, 2 weeks, a month for the reveal after tokens are fully minted? Likely not. So what other options are left? Mostly closing the mint, and burning off the remaining un-minted ones, so that the reveal can happen.

We think this is not ideal, it creates an immense pressure on the project teams to beef up the hype for the project, at the expense of real substance.

Secondly, the gas fee incurred for a team to set the token URL for each token take a toll on the mint proceeds, that could otherwise be used for other more meaningful purposes. Suppose it costs 0.01 ETH (probably higher) to set base URL for each token, with 7000 tokens, that amounts to 70 ETH! We could have bought a BAYC, a couple of Cool Cats, and fractionalise them to be rewarded to all token holders instead.

Our Approach

We will be storing the token image assets and metadata in a scalable centralised storage, eg. AWS S3, Google Storage, etc. Doing so allows us to reveal the minted tokens, without exposing the metadata of the un-minted ones.

Once the all tokens have been minted, we will migrate everything to IPFS.

To illustrate the process, when a token is minted:

  1. Token URL will be set according to the token ID within the contract. Eg. 1.json, 2.json, 3.json ...

  2. The mint event will trigger an API call to our backend, which will then make the metadata of the minted token available.

  3. Thus with the preset Base URL, the full token URL will be formed, eg. https://storage.com/1.json

  4. When it is time to migrate to IPFS, we just need to make a single interaction with the contract to change the base URL to https://my-ipfs.com/ , and the full token URL for example for token ID 1 will then be https://my-ipfs.com/1.json .

One question that could arise is that for step 2, why not just do it with IPFS? For that, it is not possible.

The way IPFS works is "all the files, or nothing". Meaning if tokens with IDs 1 - 10 are minted, it is not possible to only upload the folder with images and metadata of tokens 1 - 10, because once a folder is uploaded to IPFS, it is impossible to modify the folder contents. I.e if token 11 is minted, we cannot update the folder with image and metadata of token 11. Thus, the images and metadata of ALL tokens have to be uploaded all at once.

Provenance Hash

Provenance according to the dictionary definition from Google search means "the place of origin or earliest known history of something.".

The idea of a provenance hash in the context of NFT is such that we are able track the "beginning and the end" of the entire collection, in the exact order, and the exact metadata assigned to each token. This serves as a prove that what you have minted is exactly what you get, the asset and the associating metadata, and that there is no tempering or manipulation of any kind.

In order to achieve that, the provenance hash must be made know publicly and set within the contract BEFORE the minting starts.

The calculation of the provenance hash for Catto Katsu is described below.

For each token:

  1. Token image will be hashed: SHA256(tokenImage) -> tokenImageHash

  2. Compacted token metadata (JSON with all whitespace stripped, attributes in a specified order) will be hashed: SHA256(tokenMetadata) -> tokenMetadataHash

  3. The two hashes will be combined, then suffixed with the final token hash of previous token, and finally hashed: SHA256(tokenImageHash + tokenMetadataHash + previousFinalTokenHash) -> finalTokenHash

For step 3, in the case of the genesis token, the final token hash calculation will just be SHA256(tokenImageHash + tokenMetadataHash) -> finalTokenHash

The final token hash for the last token will then be the provenance hash that will be made known publicly, and be set in the contract before the mint starts.

Last updated