ATHERXPERIMENT
September 10, 2021
Data Merkle Tree Generation
Why is NFT Data Merkle tree Necessary?
As Genesis Siphers are generative NFTs, several key concerns amongst consumers come into mind:
- The team wants the NFTs to have a flexible use case while remaining entirely decentralized.
- Of the Genesis SIPHER NFTs available, there would be a handful that possesses a combination of rare traits, producing a “rare” NFT in comparison to the rest of the collection. The team is aiming to prevent the leak of such data before the metadata reveal as it serves as an influence on buying decisions.
- This ensures a level playing field as nobody has an advantage over the other.
- The team wants to save gas usage across the board.
In order to address the first concern, the team has decided to host all metadata, including the generated photo files, attributes, and file names on a private server instead of IPFS, setting up a Merkle tree over the metadata to verify the integrity of your NFT. For the other concerns, a sale in the form of a “loot box” drop is efficient as nobody has control over what is purchased. This results in lower gas prices as consumers would not go out of their way to “snipe” a “rare” NFT. These mechanisms would be discussed in further detail under the Sale Mechanism.
Sale mechanism
To better understand how the Merkle tree plays its role in the Sipher sale, let's run through how SIPHER's NFT public sale is conducted.
Firstly, the team will deploy the sales smart contract, where the team is required to submit the Merkle root to the sale smart contract before any sales occur (including internal team sales, whitelisted participants, and the public sale).
Next, once the Merkle root is set and the sale's star time kicks in, the team is allowed to buy up to 500 NFTs at 0 ETH, while the other whitelisted addresses are allowed to buy 1 NFT per wallet at the price of 0.1 ETH.
At the end of a public sale, the team is allowed to push through a transaction in order to roll randomizedStartIndex, a key factor in the random generation of the NFTs. Here, all the "loot boxes" are opened, technically mapped to the purchased NFTs within the SIPHER server in accordance to the following rule:
NFTSipherID = mod((tokenID + randomizedStartIndex − 2), 10000 )+1
However, there are several technical concerns that arise as part of this sales flow, one of which will be addressed below.
- Everyone will be allocated tokenIDs prior to its reveal. This is important for NFT holders as the ID is essential for verification. However, prior to the transaction to push for randomizedStartIndex, the mapping between NFT Sipher ID on Sipher Server and tokenID is left unestablished
- The team will buy 500 NFTs (eg. IDs 1 -500). While the ID numbers are fixed, the team is unaware of the traits behind each ID as the mapping is left unknown prior to the randomizedStartIndex transaction push.
- All NFT data is stored on the SIPHER servers with the exception of the tokenID that is publicly visible. This comes with mutual trust between the team and the consumer as it facilitates future on-chain and off-chain blockchain operations for gameplay. Thus, trust is placed on the SIPHER servers to correctly return data in accordance with the ID of the purchased NFT.
- As it is costly to achieve true decentralization and flexibility for an NFT-based game, the team has chosen to strike a balance between both features:
- Consumers should be able to verify the metadata of the purchased NFT.
- The verification result should be accepted as such.
- The team should be trusted to deliver accurate data.
Here, the Merkle tree will be utilized to facilitate the verification of the metadata. As the Merkle root is required to push before sales begin, the team has to finalize the metadata prior to the start of the sale, where it can no longer be modified after.
How do buyers verify the NFT data?
The Merkle tree comes in to facilitate such verifications. The Merkle root is required to push before the sale can start, this means the team has to finalize the NFT data before the sale and they can't modify the data afterward.
Below is a diagram explaining the Merkle Tree in principle and how to Verify
Merkle Tree Diagram and How to Verify True Randomization
What is this repo?
This repository provides a tool for the team to calculate the NFT data's Merkle root as well as for NFT holders to verify their NFT data.
https://github.com/sipherion/merkle_sipher_inus
Merkle tree construction
The Merkle tree in this repo is constructed in the same way as merkle tree js library with the following hash function:
const leaves = data.tokens.map((token) => {
return hashOneToken(token);
})
const tree = new MerkleTree(leaves, keccak256, {sort: true});
Where hashOneToken
is a function to hash 1 NFT data as the following pseudo-code:
id = Id in Sipher server of the NFT.
attributeNames = All of the NFT's attribute names sorted alphabetically.
attributeValues = All of the attribute values, in the corresponding order to attributeNames.
mainPhotoMD5 = MD5 of the main photo.
emotions = All of the NFT's emotions sorted alphabetically.
emotionMD5s = All of the MD5 of NFT's emotion photos, in corresponding order to emotions.
name = Name of the NFT.
origin = Origin of the NFT.
return hash = keccak256(abiEncode(
id, attributeNames, attributeValues, mainPhotoMD5,
emotions, emotionMD5, name, origin
))
How to run the tool
To Sipher team
In order to calculate Merkle root and proofs for all NFT data.
1. set your current directory to the root directory of the repo.
2. npm install
to install all of the dependencies.
3. node generateMerkleRoot.js -f [path_to_final_data]
to calculate the Merkle tree and write the output to merkle_data_sipher.json
in the current directory. You can find merkleRoot
as well as all of the proofs for each NFT. The merkleRoot
is used to push to Sale
contract.
To NFT holders
In order to verify if your NFT data is correct manually.
1. Query on the NFT contract to get your id
and the randomizedStartIndex
.
2. Download all of the photos related to your NFT including the main photo, and emotion photos, and get MD5 of them.
3. Get all of the necessary NFT data from Sipher servers using your NFT's tokenUri(id)
function. Verify your computed MD5s in step #2 to see if they match with what was returned from Sipher servers. If they don't, the data is not correct, you should ask the team.
4. Get merkleRoot
from Sale
contract.
5. Get proofs
from the Sipher server.
6. Use this const verifyProof = require('./merkleDist/parseData').verifyProof;
function to run Merkle proof verification. If it returns True
, the data is fine, otherwise, it is not.
Note: The Sipher team will work on an automatic tool to do all of those steps just with 1 click in the future to save all of the efforts. However, it is still important for every NFT holder to understand how they can do it without relying fully on the Sipher team.
For step by step to verify your NFT with the code, please visit this article.
SUBSCRIBE
Subscribe to our newsletter today and be the first to receive Sipher news, AtherXplorer weekly issues, and new AtherXperiment posts. Sign up now and get ahead of the game!