Honest Protocol v0.1 Implementation

Hi! We’re the HonestNFT Protocol development team.

We’re first working on v1 of the 3 smart contracts relevant in our architecture. Here’s an outline of the contracts written so far.

You can check out the github repo here: GitHub - Honest-Protocol/honest-protocol-v0.1

This is the first version of many, so we appreciate any questions, feedback, and comments!



Label Contract

Label contract is, in essence, the on-chain database of labels for audited NFT collections. It is designed to hold all the NFT collections, the label values of each NFT collection, and the proof of those labels for the NFT collection. For example, it would hold the address of the Vigilante NFT collection, 1 for “Commit-Reveal” Label, and a pointer (ex. an IPFS link) to the proof of commit-reveal for the Vigilante NFT collection.

Filter Factory Contract

Filter Factory contract is designed to create and hold “filters” or selections of labels that a user will deem relevant for their use case. APIs, users, or other contracts can interact directly with this contract to determine if a NFT collection meets their filter criteria.

Filter Contract

Filter Contract is where APIs, users, or contracts interact directly with this contract to determine if a NFT collection meets this particular filter’s criteria.

Overall notes

  1. Throughout these contracts, you will see the label values and filters in the form of a uint256. This is because we are treating the uint256 as simply an array of booleans, where the 0th place bool pertains to label 0 (let’s say, level of gas fees), the first place bool pertains to label 1 (let’s say, uniformity of rarity map distribution), etc. The label ↔ index assignment follows the order in which label types are added to the label contract.

  2. v1 does not include the consensus mechanisms (where auditors and agree/disagree, and validators confirm the audit). That will be added later. Ergo, in order to audit an NFT collection through these contracts, you must be a whitelisted auditor (see Label Contract).

Technical Details

Label Contract

Main variables (excluding helper variables):

  • mapping(address => LabelData) labelInfo: nested map containing label data for all NFT collections
    • LabelData is a struct containing 1) labelValues and 2) the proofs
  • mapping(address => bool) whiteListedAuditors: keeps track of who is allowed to edit label data (for v1 only)
  • mapping(string => uint256) labelIndices and string[] labelIndicesKeys: keeps track of which index of the uint256 refers to which label.

Public methods:

For reading label data:

  • getLabelOfAsset(address asset, uint256 labelIndex) returns (bool): gets label value for a single label type (defined by its index, e.g. 0) of an NFT collection.
  • getLabelOfAsset(address asset, string calldata labelName) returns (bool): gets label value for a single label type (defined by its name, e.g. “COMMIT REVEAL”) of an NFT collection.
  • getLabelData(address asset) returns (uint256): gets data for all labels of an asset, represented as an array of bools (uint256)
  • getProofs(address asset) returns (string[] memory): gets the array of proofs for all labels for a given NFT collection
  • getProof(address asset, string calldata _label) returns (string memory): gets the proof for a specific label of a specific NFT collection.

For editing label data:

  • editLabelData(address asset, string calldata _label, bool _labelValue, string calldata _labelProof): changes the value of a single label for a single NFT collection (and adds the proof of this audit)
  • editMultipleLabelsForAsset(address asset, string[] calldata labelsToChange, bool[] calldata newValues, string[] calldata proofs): changes the values of multiple labels for a single NFT collection (and adds the respective proofs)
  • editLabelForMultipleAssets(string calldata labelName, address[] calldata assets, bool[] calldata newValues, string[] calldata proofs): changes the values of a single label but for multiple NFT collections (and adds the respective proofs)

For adding a new label type/metric in general:

  • addLabel(string calldata _newLabel)


  • addWhitelistAuditor(address newAuditor): whiteLists a new auditor address. (can only be done by the owner of the Label contract)

Filter Factory Contract

Main variables:

  • mapping(uint256 => mapping(uint256 => address)) getFilterAddress: nested map to get the address of existing filters. The key of the outer map is a uint256 representing which labels must be compared in order for an NFT collection to pass that filter (AKA labelsRequired). The key of the inner map is a uint256 representing what those required label values must be (AKA valuesRequired). (E.g. Not all of the booleans in the inner key will be looked at.)

Public Methods:

  • createFilter(uint256 labelsRequired, uint256 valuesRequired) returns (address newFilter): creates a new filter given a novel (labelsRequired, valuesRequired) pair. If the pair already exists as a filter, it will through an error. Returns the address of the new created filter.
  • getMissedCriteria(address asset, uint256 labelsRequired, uint256 valuesRequired) external view returns (uint256 passes): returns the boolean array (uint256) representing which labels of the NFT collection didn’t pass the filter. For example, if the returned value ends in …010, that means that the label corresponding to index 1 didn’t meet the filter criteria.

Filter Contract

Main variables:

  • uint256 labelsRequired: a boolean array representing what labels this filter “cares” about. It will only check these labels when evaluating an NFT collection.
  • uint256 valuesRequired: a boolean array representing what values the filter requires for the labels it cares about. For example, if labelsRequired ends with a 1 (i.e. labelsRequired is odd) and valuesRequired ends with a 1 as well, then the label corresponding to index 0 NFT collection


  • initialize(uint256 _labelsRequired, uint256 _valuesRequired, address _labelContract): initializes the new filter contract with the labelsRequired and valuesRequired (called by filterFactory)
  • getUnknowns(address assetAddress) returns (uint256): returns a boolean array (uint256) of the traits that have not been audited yet.
  • getMissedCriteria(address assetAddress) returns (uint256): returns boolean array (uint256) of the traits that did not pass the filter (either because it was explicitly audited to be a different value, or because it had not been audited yet)
1 Like

Would any of the Vigilante Rarity Specs appear in the Filter Contract Labels? For example, would users be able to pull all “Cityscape Neon Blue” Background categories? I am approaching your explanation (above) from a creator perspective and not a coder, so I need a but more specificity to understand.

It would be cool, if you could express Labels as booleans (if I understand you correctly).

Sorry for the delayed reply. Somehow missed this really great question. It’s something that we’ve been thinking about a lot.

So v0.1 of the protocol, as described here, only labels whole contracts. (e.g. we would label the entire Vigilante contract as True for has_commit_reveal and is_randomly_distributed.) That means it won’t be able to label individual NFT traits.

That being said, something else in the pipeline (which we haven’t announced and I think this is one of the first public mentions) is that we also want to label individual NFTs.

So you or anybody else, could permissionlessly make a Label and Filter contract and add Vigilante specs and yes, you could easily pull the metadata and then label all of the “Cityscape Neon Blue” NFTs as such.

The two use cases we current have in mind for this are 1) labeling stolen NFTs, and 2) labeling “potatoes” which is another way of labeling NFTs that are not in “good standing” within an organization. (e.g. say there was a bored ape DAO and someone embezzled a bunch of money from it. Bored Ape DAO can’t claw back that guy’s Bored Ape. But they can label it as a “potato” which means that holding it is insufficient for membership in Bored Ape DAO.)