Vigilante NFT Metadata Verifier

An annotated code walk-through

Barabazs
Honest Protocol
5 min readJun 3, 2022

--

A screenshot describing the last lines of code in the notebook.

Introduction

This article aims to demonstrate how to verify that the Vigilante NFTs are randomly distributed while using a commit-reveal scheme. An initial verification approach was described by the team in the article How to verify that HonestNFT Vigilantes are randomly distributed. However, the described approach would be time consuming and error-prone for this multi phased reveal.

This is a more automated approach, coupled with annotations for each step. You can download the code from https://github.com/Convex-Labs/vigilante-verifier and follow along. You will find detailed installation steps in the repository.

For full disclosure I want to mention that I was not a team member at the time of the mint, but joined later on. (cf. disclosure at the bottom)

Short recap of the commit-reveal process

  1. Original unshuffled metadata is uploaded to IPFS.
  2. When you mint a vigilante, your NFT is unrevealed until the HonestNFT team performs the metadata shuffle + reveal procedure.
  3. Phased reveal every x days.
    1. Call is made from Vigilante contract to Chainlink VRF.
    2. Chainlink VRF stores a random number in the Vigilante contract.
    3. HonestNFT team shuffles the minted and unrevealed metadata with the random number as a seed.
    4. Shuffled metadata is uploaded to IPFS and the baseURI is updated to point to the new file.

Block 1

In the first code block we have to input the last revealed token_id. There are various methods we can use, but for simplicity we will go to OpenSea, sort by “Recently Created” and copy the last (revealed) token_id. At the time of writing it is 1489.

Block 2

In the next code block we import the necessary packages, set up our Web3 provider and declare some constants:

  1. PROVENANCE_HASH is the IPFS CID from the unshuffled metadata. We can verify this hash on the contract or from IPFS
  2. FILE_NAME for the original unshuffled metadata which we will download at the end of this code block
  3. CONTRACT_ADDRESS from the vigilante contract

We will also need to download the transactions which interacted with the contract. This is a simple manual step.

A screenshot of the Etherscan transaction download page.

Block 3
As mentioned earlier, the Vigilante contract relies on Chainlink VRF and has to call a function described as “Request Random Words”. In this code block we iterate over the transactions and extract the transactions where a call to that function was made. These transactions are saved to a list which we will need in the next code block.

Block 4

Now that we know which transaction was a VRF call, we can determine which transactions were the latest unrevealed NFT mint. In this block we simply iterate over the list of VRF events and look at the transactions that happened before that. We’re looking for mint transactions and since we can mint multiple tokens in one transaction, we only look a the last token_id from the mint transaction. All those token_ids are added to a list which we will use in another code block.

Block 5

Here we pull the “random words” that are stored in the Vigilante contract. Each “random word” corresponds to a VRF call we stored in the list from block 3. We will save all these seeds to another list for later.

Block 6

This code block is almost identical to the hermes_partial_shuffler which was used to shuffle the metadata. The only difference is that the hermes_partial_shuffler was designed to be executed manually before each reveal. But we will simulate all the reveals one after the other by iterating over each reveal and shuffling the metadata accordingly. E.g. before the first reveal there was revealed token, so we shuffle the metadata for all token_ids. On the second reveal the last revealed token was 1330, so we will shuffle the metadata from 3777 to 1331. At the end of this block our shuffled metadata file should be identical to the metadata from the Vigilante contract (stored on IPFS). At least if the metadata was not tampered with…

Block 7

Now we need to download the metadata from the contract. We will simply download it with the pulling.py script from the honestnft-shenanigans tools.

Block 8

Now for the actual comparison… We’ll use the pandas function pandas.DataFrame.equals to compare the downloaded metadata and our shuffled metadata. If there is only a tiny difference, it will be detected by this function.

To actually compare data in such a way, we need to make sure that the data is normalised. E.g. we don’t care about lower or upper case differences, our column headers should have the same name and structure, …

  1. We start by sorting the downloaded metadata by token_id
  2. In the shuffled metadata, we rename the column “Masks” to “Mask” and “TOKEN ID” to “TOKEN_ID”
  3. Now we sort the shuffled metadata by token_id
  4. The full trait sheet contains both the feminine and masculine versions of the accessories. But the downloaded metadata only contains the accessory that corresponds to the gender as specified in the full trait sheet.
    We will add a new column named “Accessory” to the shuffled metadata and input the correct Accessory according to the gender.
  5. We still have a few columns that only appear in the unshuffled metadata, so we will remove them. (Accessory_F, Accessory_M, Image_Number)
    And in the downloaded metadata we have a column “TOKEN_NAME” that should also be dropped.
  6. We need to re-index both DataFrames, since we added and removed columns.
  7. We still have more rows in the shuffled metadata than from the actually revealed (and downloaded) metadata. Since we don’t care about the unminted tokens (and obviously don’t know in advance how they will be shuffled), we will remove these rows.
  8. The last part of our data normalisation is making sure both DataFrames use token_id as the index.
  9. Now we can finally check if both sheets are identical. If there is a difference we will use the function pandas.DataFrame.compare to show us where there is a discrepancy.

Conclusion

Trust, but verify!” is a slogan often advertised in the web3 community, but it’s rarely applied. This is why HonestNFT emphasises the need for more provably fair NFT projects. It should be clear by now that a commit-reveal scheme combined with verifiable randomness is achievable and easily verifiable. It’s impossible for the HonestNFT team to tamper with the metadata without being noticed. You can try this for yourself by going through the notebook and modify a few values between block 7 and 8.

Disclosure

  1. I was not part of the HonestNFT team when the Vigilante NFT project was launched. (March 7, 2022)
  2. I was active as a community member when the Vigilante NFT was launched.
  3. I have minted Vigilante NFTs.
  4. I joined the HonestNFT team on April 12, 2022.

--

--